ui rework

This commit is contained in:
Mikaël Cluseau
2026-06-17 22:40:44 +02:00
parent f6b301c9a0
commit 38ad620759
20 changed files with 1016 additions and 553 deletions
+50 -14
View File
@@ -21,11 +21,17 @@ createApp({
uiHash: null,
watchingState: false,
state: null,
toasts: [],
toastId: 0,
}
},
mounted() {
this.session = JSON.parse(sessionStorage.state || "{}")
this.watchPublicState()
document.addEventListener('keydown', (e) => this.onKeydown(e))
},
unmounted() {
document.removeEventListener('keydown', (e) => this.onKeydown(e))
},
watch: {
session: {
@@ -56,13 +62,16 @@ createApp({
},
computed: {
views() {
var views = [{type: "actions", name: "admin", title: "Admin actions"}];
(this.state.Clusters||[]).forEach((c) => views.push({type: "cluster", name: c.Name, title: `Cluster ${c.Name}`}));
(this.state.Hosts ||[]).forEach((c) => views.push({type: "host", name: c.Name, title: `Host ${c.Name}`}));
return views.filter((v) => v.type != "host" || v.name.includes(this.viewFilter));
adminViews() {
return [{type: "actions", name: "admin", title: "Admin actions"}];
},
clusterViews() {
return (this.state.Clusters||[]).map((c) => ({type: "cluster", name: c.Name, title: c.Name}));
},
hostViews() {
return (this.state.Hosts||[])
.filter((h) => h.Name.includes(this.viewFilter))
.map((h) => ({type: "host", name: h.Name, title: h.Name}));
},
viewObj() {
if (this.view) {
@@ -84,9 +93,32 @@ createApp({
any(array) {
return array && array.length != 0;
},
isActive(v) {
return this.view && this.view.type == v.type && this.view.name == v.name
},
onKeydown(e) {
if ((e.ctrlKey || e.metaKey) && e.key == 'k') {
e.preventDefault()
this.$nextTick(() => {
const el = document.querySelector('.sidebar input[type="search"]')
if (el) el.focus()
})
return
}
if (e.key == 'Escape') {
this.viewFilter = ''
return
}
},
copyText(text) {
event.preventDefault()
window.navigator.clipboard.writeText(text)
try {
window.navigator.clipboard.writeText(text)
this.toast('copied!', 'info')
} catch (e) {
this.toast('copy failed: ' + e, 'error')
}
},
setToken() {
event.preventDefault()
@@ -177,16 +209,12 @@ createApp({
var xhr = new XMLHttpRequest()
xhr.responseType = 'json'
// TODO spinner, pending action notification, or something
xhr.onerror = () => {
// this.actionResults.splice(idx, 1, {...item, done: true, failed: true })
}
xhr.onerror = () => {}
xhr.onload = (r) => {
if (xhr.status != 200) {
this.error = xhr.response
this.toast((xhr.response && xhr.response.message) || 'request failed', 'error')
return
}
// this.actionResults.splice(idx, 1, {...item, done: true, resp: xhr.responseText})
this.error = null
if (onload) {
onload(xhr.response)
@@ -235,6 +263,14 @@ createApp({
// TODO once-shot download link
return url + '?token=' + this.session.token
},
toast(message, kind) {
const id = ++this.toastId
this.toasts.push({id, message, kind: kind || 'info'})
setTimeout(() => this.dismissToast(id), 4000)
},
dismissToast(id) {
this.toasts = this.toasts.filter(t => t.id != id)
},
watchPublicState() {
this.watchStream('publicState', '/public-state')
},