android/ui: handle NeedsMachineAuth state

Fixes corp#19119

Adds a variation on the ConnectView to render a header and explainer
text for the NeedsMachineAuth state.  A button to take you directly
to the admin page is presented if you are an admin.

Signed-off-by: Jonathan Nobels <jonathan@tailscale.com>
pull/318/head
Jonathan Nobels 2 months ago committed by Percy Wegmann
parent fe3a46e2f0
commit 72b0e365e9
No known key found for this signature in database
GPG Key ID: 29D8CDEB4C13D48B

@ -26,7 +26,6 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.ArrowDropDown
import androidx.compose.material.icons.outlined.Clear
import androidx.compose.material.icons.outlined.Close
import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material.icons.outlined.Search
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.material3.Button
@ -107,6 +106,7 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
val stateVal = viewModel.stateRes.collectAsState(initial = R.string.placeholder).value
val stateStr = stringResource(id = stateVal)
val netmap = viewModel.netmap.collectAsState(initial = null)
val isAdmin = viewModel.isAdmin.collectAsState(initial = false).value
ListItem(
colors = MaterialTheme.colorScheme.surfaceContainerListItem,
@ -163,7 +163,7 @@ fun MainView(navigation: MainViewNavigation, viewModel: MainViewModel = viewMode
Ipn.State.NoState,
Ipn.State.Starting -> StartingView()
else -> {
ConnectView(state, user, { viewModel.toggleVpn() }, { viewModel.login {} })
ConnectView(state, user, { viewModel.toggleVpn() }, { viewModel.login {} }, isAdmin)
}
}
}
@ -257,7 +257,8 @@ fun ConnectView(
state: Ipn.State,
user: IpnLocal.LoginProfile?,
connectAction: () -> Unit,
loginAction: () -> Unit
loginAction: () -> Unit,
isAdmin: Boolean,
) {
val handler = LocalUriHandler.current
@ -269,10 +270,6 @@ fun ConnectView(
horizontalAlignment = Alignment.CenterHorizontally,
) {
if (state == Ipn.State.NeedsMachineAuth) {
Icon(
modifier = Modifier.size(40.dp),
imageVector = Icons.Outlined.Lock,
contentDescription = "Device requires authentication")
Text(
text = stringResource(id = R.string.machine_auth_required),
style = MaterialTheme.typography.titleMedium,
@ -281,11 +278,12 @@ fun ConnectView(
text = stringResource(id = R.string.machine_auth_explainer),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Center)
Spacer(modifier = Modifier.size(1.dp))
PrimaryActionButton(onClick = { handler.openUri(Links.ADMIN_URL) }) {
Text(
text = stringResource(id = R.string.open_admin_console),
fontSize = MaterialTheme.typography.titleMedium.fontSize)
if (isAdmin) {
PrimaryActionButton(onClick = { handler.openUri(Links.ADMIN_URL) }) {
Text(
text = stringResource(id = R.string.open_admin_console),
fontSize = MaterialTheme.typography.titleMedium.fontSize)
}
}
} else if (state != Ipn.State.NeedsLogin && user != null && !user.isEmpty()) {
Icon(

@ -34,6 +34,8 @@ class MainViewModel : IpnViewModel() {
val prefs = Notifier.prefs
val netmap = Notifier.netmap
val isAdmin: StateFlow<Boolean> = MutableStateFlow(false)
// The active search term for filtering peers
val searchTerm: StateFlow<String> = MutableStateFlow("")
@ -53,6 +55,7 @@ class MainViewModel : IpnViewModel() {
it?.let { netmap ->
peerCategorizer.regenerateGroupedPeers(netmap)
peers.set(peerCategorizer.groupedAndFilteredPeers(searchTerm.value))
isAdmin.set(netmap.SelfNode.isAdmin)
}
}
}

Loading…
Cancel
Save