Improve Tailscale panel controls
This commit is contained in:
@@ -238,7 +238,7 @@ Panel {
|
|||||||
if (focusSection === "header") {
|
if (focusSection === "header") {
|
||||||
tailscale.toggleTailscale()
|
tailscale.toggleTailscale()
|
||||||
} else if (focusSection === "auth") {
|
} else if (focusSection === "auth") {
|
||||||
tailscale.authorizeProfileSwitching()
|
tailscale.authorizeTailscaleOperator()
|
||||||
} else if (focusSection === "accounts") {
|
} else if (focusSection === "accounts") {
|
||||||
var account = selectedAccount()
|
var account = selectedAccount()
|
||||||
if (account) tailscale.switchAccount(account.id)
|
if (account) tailscale.switchAccount(account.id)
|
||||||
@@ -748,7 +748,7 @@ Panel {
|
|||||||
cursorShape: tailscale.busy ? Qt.ArrowCursor : Qt.PointingHandCursor
|
cursorShape: tailscale.busy ? Qt.ArrowCursor : Qt.PointingHandCursor
|
||||||
enabled: !tailscale.busy
|
enabled: !tailscale.busy
|
||||||
onEntered: root.setAuthCursor()
|
onEntered: root.setAuthCursor()
|
||||||
onClicked: tailscale.authorizeProfileSwitching()
|
onClicked: tailscale.authorizeTailscaleOperator()
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -774,7 +774,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: "Authorize switching"
|
text: "Authorize Tailscale operator"
|
||||||
color: root.foreground
|
color: root.foreground
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: Style.font.body
|
font.pixelSize: Style.font.body
|
||||||
@@ -783,7 +783,7 @@ Panel {
|
|||||||
|
|
||||||
Text {
|
Text {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: "Allow this user to see and switch Tailscale connections"
|
text: "Allow this user to operate this Tailscale profile"
|
||||||
color: root.dim
|
color: root.dim
|
||||||
font.family: root.fontFamily
|
font.family: root.fontFamily
|
||||||
font.pixelSize: Style.font.caption
|
font.pixelSize: Style.font.caption
|
||||||
@@ -791,14 +791,6 @@ Panel {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PanelActionButton {
|
|
||||||
iconText: ""
|
|
||||||
foreground: root.foreground
|
|
||||||
fontFamily: root.fontFamily
|
|
||||||
enabled: !tailscale.busy
|
|
||||||
Layout.alignment: Qt.AlignVCenter
|
|
||||||
onClicked: tailscale.authorizeProfileSwitching()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -994,14 +986,7 @@ Panel {
|
|||||||
modal: false
|
modal: false
|
||||||
focus: true
|
focus: true
|
||||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
onOpenedChanged: {
|
function handleKey(event) {
|
||||||
root.copyMenuOpen = opened
|
|
||||||
if (opened) {
|
|
||||||
peerRow.clampCopyIndex()
|
|
||||||
forceActiveFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Keys.onPressed: function(event) {
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
if (event.key === Qt.Key_Escape) {
|
||||||
close()
|
close()
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
@@ -1022,6 +1007,15 @@ Panel {
|
|||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onOpenedChanged: {
|
||||||
|
root.copyMenuOpen = opened
|
||||||
|
if (opened) {
|
||||||
|
peerRow.clampCopyIndex()
|
||||||
|
Qt.callLater(function() { copyPopupContent.forceActiveFocus() })
|
||||||
|
} else if (root.opened) {
|
||||||
|
Qt.callLater(function() { keyCatcher.forceActiveFocus() })
|
||||||
|
}
|
||||||
|
}
|
||||||
background: BorderSurface {
|
background: BorderSurface {
|
||||||
color: Color.background
|
color: Color.background
|
||||||
borderSpec: Border.flat(root.dim, 1)
|
borderSpec: Border.flat(root.dim, 1)
|
||||||
@@ -1029,7 +1023,11 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
contentItem: Column {
|
contentItem: Column {
|
||||||
|
id: copyPopupContent
|
||||||
width: parent.width
|
width: parent.width
|
||||||
|
focus: true
|
||||||
|
Keys.priority: Keys.BeforeItem
|
||||||
|
Keys.onPressed: function(event) { copyPopup.handleKey(event) }
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: peerRow.copyOptions
|
model: peerRow.copyOptions
|
||||||
@@ -1102,6 +1100,7 @@ Panel {
|
|||||||
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
||||||
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
||||||
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || "Unknown") : "Unknown"
|
readonly property string peerName: peer ? String(peer.DisplayName || peer.HostName || "Unknown") : "Unknown"
|
||||||
|
readonly property string actionTooltip: addMullvad ? "" : (activeExitNode ? "Disconnect" : "Connect")
|
||||||
|
|
||||||
hasCursor: root.cursorActive && root.focusSection === "exitNodes" && root.exitNodeIndex === rowIndex
|
hasCursor: root.cursorActive && root.focusSection === "exitNodes" && root.exitNodeIndex === rowIndex
|
||||||
current: activeExitNode || settingExitNode || (addMullvad && root.mullvadPickerOpen)
|
current: activeExitNode || settingExitNode || (addMullvad && root.mullvadPickerOpen)
|
||||||
@@ -1154,12 +1153,19 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
id: exitNodeMouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onEntered: root.setExitNodeCursor(exitNodeRow.rowIndex)
|
onEntered: root.setExitNodeCursor(exitNodeRow.rowIndex)
|
||||||
onClicked: root.chooseExitNode(exitNodeRow.peer)
|
onClicked: root.chooseExitNode(exitNodeRow.peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PanelToolTip {
|
||||||
|
visible: exitNodeRow.actionTooltip !== "" && exitNodeMouse.containsMouse
|
||||||
|
text: exitNodeRow.actionTooltip
|
||||||
|
fontFamily: root.fontFamily
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
component MullvadRegionRow: CursorSurface {
|
component MullvadRegionRow: CursorSurface {
|
||||||
@@ -1172,6 +1178,7 @@ Panel {
|
|||||||
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
readonly property bool activeExitNode: peer && peer.ExitNode === true
|
||||||
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
readonly property bool settingExitNode: peer && tailscale.settingExitNodeId === String(peer.id || "")
|
||||||
readonly property bool selectedRegion: root.mullvadPickerOpen && root.mullvadRegionIndex === rowIndex
|
readonly property bool selectedRegion: root.mullvadPickerOpen && root.mullvadRegionIndex === rowIndex
|
||||||
|
readonly property string actionTooltip: activeExitNode ? "Disconnect" : "Connect"
|
||||||
|
|
||||||
foreground: root.foreground
|
foreground: root.foreground
|
||||||
fill: root.hoverFill
|
fill: root.hoverFill
|
||||||
@@ -1226,11 +1233,18 @@ Panel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
id: regionMouse
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onEntered: root.mullvadRegionIndex = regionRow.rowIndex
|
onEntered: root.mullvadRegionIndex = regionRow.rowIndex
|
||||||
onClicked: root.chooseExitNode(regionRow.peer)
|
onClicked: root.chooseExitNode(regionRow.peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PanelToolTip {
|
||||||
|
visible: regionMouse.containsMouse
|
||||||
|
text: regionRow.actionTooltip
|
||||||
|
fontFamily: root.fontFamily
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -291,11 +291,11 @@ Item {
|
|||||||
exitNodeProcess.running = true
|
exitNodeProcess.running = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function authorizeProfileSwitching() {
|
function authorizeTailscaleOperator() {
|
||||||
if (!installed || operatorProcess.running || userName === "") return
|
if (!installed || operatorProcess.running || userName === "") return
|
||||||
_operatorOutput = ""
|
_operatorOutput = ""
|
||||||
_operatorError = ""
|
_operatorError = ""
|
||||||
actionStatus = "Authorizing Tailscale profiles…"
|
actionStatus = "Authorizing Tailscale operator..."
|
||||||
operatorProcess.command = ["pkexec", "tailscale", "set", "--operator=" + userName]
|
operatorProcess.command = ["pkexec", "tailscale", "set", "--operator=" + userName]
|
||||||
operatorProcess.running = true
|
operatorProcess.running = true
|
||||||
}
|
}
|
||||||
@@ -414,7 +414,7 @@ Item {
|
|||||||
root.parseAccounts("")
|
root.parseAccounts("")
|
||||||
if (/profiles access denied/i.test(stderr) || /profiles access denied/i.test(stdout)) {
|
if (/profiles access denied/i.test(stderr) || /profiles access denied/i.test(stdout)) {
|
||||||
root.accountsAccessDenied = true
|
root.accountsAccessDenied = true
|
||||||
root.lastError = "Authorize Tailscale profiles to show connections"
|
root.lastError = "Authorize Tailscale operator to show connections"
|
||||||
} else {
|
} else {
|
||||||
root.lastError = elideStatus(stderr || stdout || "Could not list Tailscale connections")
|
root.lastError = elideStatus(stderr || stdout || "Could not list Tailscale connections")
|
||||||
}
|
}
|
||||||
@@ -534,7 +534,7 @@ Item {
|
|||||||
} else {
|
} else {
|
||||||
root.accountsAccessDenied = false
|
root.accountsAccessDenied = false
|
||||||
root.lastError = ""
|
root.lastError = ""
|
||||||
root.actionStatus = "Tailscale profiles authorized"
|
root.actionStatus = "Tailscale operator authorized"
|
||||||
actionStatusTimer.restart()
|
actionStatusTimer.restart()
|
||||||
root._lastAccountsRefreshMs = 0
|
root._lastAccountsRefreshMs = 0
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user