Connected nodes
This commit is contained in:
parent
dff17cad5b
commit
2b8472bcd1
6 changed files with 280 additions and 84 deletions
|
|
@ -30,6 +30,9 @@ body {
|
|||
[onClick] {
|
||||
cursor: pointer;
|
||||
}
|
||||
button {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
.page {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -199,10 +202,16 @@ select:focus {
|
|||
outline-offset: -2px;
|
||||
}
|
||||
#connected-nodes > .label {
|
||||
margin-bottom: 16px;
|
||||
color: var(--section-color);
|
||||
font-weight: bold;
|
||||
font-size: 1.25em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#connected-nodes > .add {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
#connected-nodes > .add img {
|
||||
height: 24px;
|
||||
}
|
||||
#connected-nodes .connected-nodes {
|
||||
display: flex;
|
||||
|
|
@ -224,3 +233,46 @@ select:focus {
|
|||
display: block;
|
||||
height: 24px;
|
||||
}
|
||||
#select-node {
|
||||
padding: 32px;
|
||||
display: grid;
|
||||
grid-template-columns: min-content;
|
||||
grid-gap: 8px;
|
||||
justify-items: start;
|
||||
}
|
||||
#select-node > * {
|
||||
min-width: 300px;
|
||||
width: 100%;
|
||||
}
|
||||
#select-node button {
|
||||
width: 100px !important;
|
||||
}
|
||||
#select-node .more-exist {
|
||||
color: #a44;
|
||||
}
|
||||
#select-node .search-results .node-table {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
gap: 32px;
|
||||
}
|
||||
#select-node .search-results .node-table .group {
|
||||
margin-top: 16px;
|
||||
}
|
||||
#select-node .search-results .node-table .group .label {
|
||||
font-weight: bold;
|
||||
color: var(--section-color);
|
||||
margin-bottom: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
#select-node .search-results .node-table .group .children {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-gap: 8px;
|
||||
}
|
||||
#select-node .search-results .node-table .group .children .node {
|
||||
cursor: pointer;
|
||||
}
|
||||
#select-node .search-results .node-table .group .children img {
|
||||
cursor: pointer;
|
||||
height: 24px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { Editor } from '@editor'
|
||||
import { MessageBus } from '@mbus'
|
||||
import { SelectType, SelectNode } from '@select_node'
|
||||
|
||||
export class App {
|
||||
constructor() {// {{{
|
||||
|
|
@ -15,6 +16,7 @@ export class App {
|
|||
const events = [
|
||||
'EDITOR_NODE_SAVE',
|
||||
'MENU_ITEM_SELECTED',
|
||||
'NODE_CONNECT',
|
||||
'NODE_CREATE_DIALOG',
|
||||
'NODE_DELETE',
|
||||
'NODE_EDIT_NAME',
|
||||
|
|
@ -38,6 +40,14 @@ export class App {
|
|||
this.page(item, event.detail)
|
||||
break
|
||||
|
||||
case 'NODE_CONNECT':
|
||||
const selectnode = new SelectNode(selectedNode => {
|
||||
this.nodeConnect(this.currentNode, selectedNode)
|
||||
.then(() => this.edit(this.currentNode))
|
||||
})
|
||||
selectnode.render()
|
||||
break
|
||||
|
||||
case 'NODE_SELECTED':
|
||||
for (const n of document.querySelectorAll('#nodes .node.selected'))
|
||||
n.classList.remove('selected')
|
||||
|
|
@ -147,6 +157,7 @@ export class App {
|
|||
case 'type':
|
||||
document.getElementById('types').classList.add('show')
|
||||
document.getElementById('editor-type-schema').classList.add('show')
|
||||
document.getElementById('editor-node').style.display = 'none'
|
||||
|
||||
if (this.typesList === null)
|
||||
this.typesList = new TypesList()
|
||||
|
|
@ -201,7 +212,7 @@ export class App {
|
|||
showError(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
const connectedNodes = new ConnectedNodes(json.Nodes)
|
||||
document.getElementById('connected-nodes').replaceChildren(connectedNodes.render())
|
||||
|
||||
|
|
@ -307,6 +318,27 @@ export class App {
|
|||
})
|
||||
.catch(err => showError(err))
|
||||
}// }}}
|
||||
async nodeConnect(parentNode, nodeToConnect) {
|
||||
return new Promise((resolve, reject)=>{
|
||||
// XXX - here
|
||||
//fetch('/nodes/)
|
||||
})
|
||||
}
|
||||
typeSort(a, b) {// {{{
|
||||
if (a.Schema['x-group'] === undefined)
|
||||
a.Schema['x-group'] = 'No group'
|
||||
|
||||
if (b.Schema['x-group'] === undefined)
|
||||
b.Schema['x-group'] = 'No group'
|
||||
|
||||
if (a.Schema['x-group'] < b.Schema['x-group']) return -1
|
||||
if (a.Schema['x-group'] > b.Schema['x-group']) return 1
|
||||
|
||||
if ((a.Schema.title || a.Name) < (b.Schema.title || b.Name)) return -1
|
||||
if ((a.Schema.title || a.Name) > (b.Schema.title || b.Name)) return 1
|
||||
|
||||
return 0
|
||||
}// }}}
|
||||
}
|
||||
|
||||
class NodeCreateDialog {
|
||||
|
|
@ -319,18 +351,13 @@ class NodeCreateDialog {
|
|||
|
||||
this.createElements()
|
||||
|
||||
this.fetchTypes()
|
||||
.then(() => {
|
||||
const st = new SelectType(this.types)
|
||||
this.select.replaceChildren(st.render())
|
||||
})
|
||||
|
||||
this.dialog.showModal()
|
||||
this.select.focus()
|
||||
//this.select.focus()
|
||||
}// }}}
|
||||
createElements() {// {{{
|
||||
this.dialog = document.createElement('dialog')
|
||||
this.dialog.id = 'create-type'
|
||||
this.dialog.addEventListener('close', () => this.dialog.remove())
|
||||
this.dialog.innerHTML = `
|
||||
<div style="padding: 16px">
|
||||
<select></select>
|
||||
|
|
@ -339,6 +366,13 @@ class NodeCreateDialog {
|
|||
</div>
|
||||
`
|
||||
|
||||
new SelectType().render()
|
||||
.then(select => {
|
||||
this.select = select
|
||||
this.dialog.querySelector('select').replaceWith(this.select)
|
||||
this.select.focus()
|
||||
})
|
||||
|
||||
this.dialog.querySelector('button').addEventListener('click', () => this.commit())
|
||||
this.select = this.dialog.querySelector('select')
|
||||
this.input = this.dialog.querySelector('input')
|
||||
|
|
@ -379,51 +413,6 @@ class NodeCreateDialog {
|
|||
})
|
||||
.catch(err => showError(err))
|
||||
}// }}}
|
||||
async fetchTypes() {// {{{
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch('/types/')
|
||||
.then(data => data.json())
|
||||
.then(json => {
|
||||
if (!json.OK) {
|
||||
showError(json.Error)
|
||||
return
|
||||
}
|
||||
this.types = json.Types
|
||||
resolve()
|
||||
})
|
||||
.catch(err => reject(err))
|
||||
})
|
||||
}// }}}
|
||||
}
|
||||
|
||||
class SelectType {
|
||||
constructor(types) {// {{{
|
||||
this.types = types
|
||||
}// }}}
|
||||
render() {// {{{
|
||||
const tmpl = document.createElement('template')
|
||||
|
||||
this.types.sort(typeSort)
|
||||
let prevGroup = null
|
||||
for (const t of this.types) {
|
||||
if (t.Name == 'root_node')
|
||||
continue
|
||||
|
||||
if (t.Schema['x-group'] != prevGroup) {
|
||||
prevGroup = t.Schema['x-group']
|
||||
const group = document.createElement('optgroup')
|
||||
group.setAttribute('label', t.Schema['x-group'])
|
||||
tmpl.content.appendChild(group)
|
||||
}
|
||||
|
||||
const opt = document.createElement('option')
|
||||
opt.setAttribute('value', t.ID)
|
||||
opt.innerText = t.Schema.title || t.Name
|
||||
tmpl.content.appendChild(opt)
|
||||
}
|
||||
|
||||
return tmpl.content
|
||||
}// }}}
|
||||
}
|
||||
|
||||
export class Tree {
|
||||
|
|
@ -696,7 +685,7 @@ export class TypesList {
|
|||
render() {// {{{
|
||||
const div = document.createElement('div')
|
||||
|
||||
this.types.sort(typeSort)
|
||||
this.types.sort(_app.typeSort)
|
||||
|
||||
let prevGroup = null
|
||||
|
||||
|
|
@ -726,33 +715,20 @@ export class TypesList {
|
|||
}// }}}
|
||||
}
|
||||
|
||||
function typeSort(a, b) {// {{{
|
||||
if (a.Schema['x-group'] === undefined)
|
||||
a.Schema['x-group'] = 'No group'
|
||||
|
||||
if (b.Schema['x-group'] === undefined)
|
||||
b.Schema['x-group'] = 'No group'
|
||||
|
||||
if (a.Schema['x-group'] < b.Schema['x-group']) return -1
|
||||
if (a.Schema['x-group'] > b.Schema['x-group']) return 1
|
||||
|
||||
if ((a.Schema.title || a.Name) < (b.Schema.title || b.Name)) return -1
|
||||
if ((a.Schema.title || a.Name) > (b.Schema.title || b.Name)) return 1
|
||||
|
||||
return 0
|
||||
}// }}}
|
||||
|
||||
class ConnectedNodes {
|
||||
constructor(nodes) {
|
||||
constructor(nodes) {// {{{
|
||||
this.nodes = nodes
|
||||
}
|
||||
render() {
|
||||
}// }}}
|
||||
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="connected-nodes"></div>
|
||||
`
|
||||
|
||||
div.content.querySelector('.add').addEventListener('click', () => mbus.dispatch('NODE_CONNECT'))
|
||||
|
||||
const types = new Map()
|
||||
for (const n of this.nodes) {
|
||||
let typeGroup = types.get(n.TypeSchema.title)
|
||||
|
|
@ -774,23 +750,21 @@ class ConnectedNodes {
|
|||
}
|
||||
|
||||
return div.content
|
||||
}
|
||||
}// }}}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class ConnectedNode {
|
||||
constructor(node) {
|
||||
constructor(node) {// {{{
|
||||
this.node = node
|
||||
}
|
||||
render() {
|
||||
}// }}}
|
||||
render() {// {{{
|
||||
const tmpl = document.createElement('template')
|
||||
tmpl.innerHTML = `
|
||||
<div class="type-icon"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/${this.node.TypeIcon}.svg" /></div>
|
||||
<div class="node-name">${this.node.Name}</div>
|
||||
`
|
||||
return tmpl.content
|
||||
}
|
||||
}// }}}
|
||||
}
|
||||
|
||||
// vim: foldmethod=marker
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ body {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
.page {
|
||||
display: none;
|
||||
|
||||
|
|
@ -270,10 +274,18 @@ select:focus {
|
|||
|
||||
#connected-nodes {
|
||||
& > .label {
|
||||
margin-bottom: 16px;
|
||||
color: var(--section-color);
|
||||
font-weight: bold;
|
||||
font-size: 1.25em;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
& > .add {
|
||||
margin-bottom: 8px;
|
||||
|
||||
img {
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.connected-nodes {
|
||||
|
|
@ -302,3 +314,57 @@ select:focus {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#select-node {
|
||||
padding: 32px;
|
||||
display: grid;
|
||||
grid-template-columns: min-content;
|
||||
grid-gap: 8px;
|
||||
justify-items: start;
|
||||
|
||||
& > * {
|
||||
min-width: 300px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 100px !important;
|
||||
}
|
||||
|
||||
.more-exist {
|
||||
color: #a44;
|
||||
}
|
||||
|
||||
.search-results {
|
||||
.node-table {
|
||||
display: flex;
|
||||
align-items: start;
|
||||
gap: 32px;
|
||||
|
||||
.group {
|
||||
margin-top: 16px;
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: var(--section-color);
|
||||
margin-bottom: 8px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.children {
|
||||
display: grid;
|
||||
grid-template-columns: min-content 1fr;
|
||||
grid-gap: 8px;
|
||||
|
||||
.node {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
cursor: pointer;
|
||||
height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue