This commit is contained in:
Magnus Åhall 2025-08-07 19:25:05 +02:00
parent 38eef01e34
commit df4cee56af
7 changed files with 292 additions and 74 deletions

View file

@ -29,6 +29,7 @@ export class App {
'NODE_EDIT_NAME',
'NODE_MOVE',
'NODE_SELECTED',
'NODE_HOOKED',
'SCRIPT_CREATED',
'SCRIPT_DELETED',
'SCRIPT_EDIT',
@ -86,6 +87,10 @@ export class App {
this.nodeDelete(this.currentNode.ID)
break
case 'NODE_HOOKED':
this.edit(event.detail)
break
case 'NODE_MOVE':
const nodes = this.tree.markedNodes()
if (!confirm(`Are you sure you want to move ${nodes.length} nodes here?`))
@ -433,6 +438,29 @@ export class App {
return 0
}// }}}
async query(path, data) {// {{{
return new Promise((resolve, reject) => {
let request = {}
if (data !== undefined) {
request.method = 'POST'
request.body = JSON.stringify(data)
}
fetch(path, request)
.then(data => data.json())
.then(json => {
if (!json.OK) {
reject(json.Error)
return
}
resolve(json)
})
.catch(err => {
reject(err)
})
})
}// }}}
}
class NodeCreateDialog {
@ -921,8 +949,10 @@ class ConnectedNodes {
render() {// {{{
const div = document.createElement('template')
div.innerHTML = `
<div class="label">Connected nodes</div>
<div class="add"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/plus-box.svg" /></div>
<div class="label">
<div style="white-space: nowrap">Connected nodes</div>
<img class="add" src="/images/${_VERSION}/node_modules/@mdi/svg/svg/plus-box.svg" />
</div>
<div class="connected-nodes"></div>
`
@ -977,18 +1007,14 @@ class ScriptHooks extends Component {
super()
this.hooks = hooks
this.scriptGrid = null
mbus.subscribe('hook_deleted', event => {
const deletedHook = event.detail
this.hooks = this.hooks.filter(h => h.ID !== deletedHook.ID)
this.renderHooks()
})
}// }}}
renderComponent() {// {{{
const div = document.createElement('div')
div.innerHTML = `
<div class="label">Script hooks</div>
<div class="add"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/plus-box.svg" /></div>
<div class="label">
<div style="white-space: nowrap">Script hooks</div>
<img class="add" src="/images/${_VERSION}/node_modules/@mdi/svg/svg/plus-box.svg" />
</div>
<div class="scripts-grid">
<div class="header" style="grid-column: 1 / 3;">Script</div>
<div class="header" style="grid-column: 3 / 5;">SSH</div>
@ -996,7 +1022,10 @@ class ScriptHooks extends Component {
`
div.querySelector('.add').addEventListener('click', () => {
alert('FIXME')
const dlg = new ScriptSelectDialog(s => {
this.hookScript(s)
})
dlg.render()
})
this.scriptGrid = div.querySelector('.scripts-grid')
@ -1004,31 +1033,53 @@ class ScriptHooks extends Component {
return div.children
}// }}}
hookDeleted(deletedHookID) {// {{{
this.hooks = this.hooks.filter(h => h.ID !== deletedHookID)
this.renderHooks()
}// }}}
renderHooks() {// {{{
this.scriptGrid.innerHTML = ''
let prevGroup = null
for (const hook of this.hooks) {
const h = new ScriptHook(hook)
if (hook.Script.Group !== prevGroup) {
const g = document.createElement('div')
g.classList.add('script-group')
g.innerText = hook.Script.Group
this.scriptGrid.append(g)
prevGroup = hook.Script.Group
}
const h = new ScriptHook(hook, this)
this.scriptGrid.append(h.render())
}
}// }}}
hookScript(script) {// {{{
_app.query(`/nodes/hook`, {
NodeID: _app.currentNode.ID,
ScriptID: script.ID,
})
.then(()=>mbus.dispatch('NODE_HOOKED', _app.currentNode.ID))
.catch(err => showError(err))
}// }}}
}
class ScriptHook extends Component {
constructor(hook) {// {{{
constructor(hook, parentList) {// {{{
super()
this.hook = hook
this.parentList = parentList
this.element_ssh = null
}// }}}
renderComponent() {// {{{
const tmpl = document.createElement('template')
tmpl.innerHTML = `
<div class="script-icon"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/bash.svg" /></div>
<div class="script-name">${this.hook.Script.Name}</div>
<div class="script-ssh">${this.hook.SSH}</div>
<div class="script-ssh"></div>
<div class="script-unhook"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/trash-can.svg" /></div>
`
this.element_ssh = tmpl.content.querySelector('.script-ssh')
this.element_ssh.innerText = this.hook.SSH
tmpl.content.querySelector('.script-ssh').addEventListener('click', () => this.update())
tmpl.content.querySelector('.script-unhook').addEventListener('click', () => this.delete())
@ -1075,7 +1126,7 @@ class ScriptHook extends Component {
showError(json.Error)
return
}
mbus.dispatch('hook_deleted', this.hook)
this.parentList.hookDeleted(this.hook.ID)
})
.catch(err => showError(err))
}// }}}
@ -1294,4 +1345,80 @@ class ScriptEditor extends Component {
}// }}}
}
class ScriptSelectDialog extends Component {
constructor(callback) {// {{{
super()
this.dlg = document.createElement('dialog')
this.dlg.id = 'script-select-dialog'
this.dlg.addEventListener('close', () => this.dlg.remove())
this.searchFor = null
this.scripts = null
this.callback = callback
}// }}}
renderComponent() {// {{{
const div = document.createElement('div')
div.innerHTML = `
<div class="header">Search for script</div>
<div><input class="search-for" type="text" value="%"></div>
<div><button>Search</button></div>
<div class="scripts"></div>
`
this.searchFor = div.querySelector('.search-for')
this.scripts = div.querySelector('.scripts')
const button = div.querySelector('button')
this.searchFor.addEventListener('keydown', event => {
if (event.key == 'Enter')
this.searchScripts()
})
button.addEventListener('click', () => this.searchScripts())
this.dlg.append(...div.children)
document.body.append(this.dlg)
this.dlg.showModal()
return []
}// }}}
searchScripts() {// {{{
fetch('/scripts/search', {
method: 'POST',
body: JSON.stringify({
Search: this.searchFor.value,
}),
})
.then(data => data.json())
.then(json => {
if (!json.OK) {
showError(json.Error)
return
}
this.populateScripts(json.Scripts)
})
.catch(err => showError(err))
}// }}}
populateScripts(scripts) {// {{{
this.scripts.innerHTML = ''
let prevGroup = null
for (const s of scripts) {
if (s.Group !== prevGroup) {
const group = document.createElement('div')
group.classList.add('group')
group.innerText = s.Group
this.scripts.append(group)
prevGroup = s.Group
}
const div = document.createElement('div')
div.innerText = s.Name
div.classList.add('script')
div.addEventListener('click', () => {
this.dlg.close()
this.callback(s)
})
this.scripts.append(div)
}
}// }}}
}
// vim: foldmethod=marker