diff --git a/node.go b/node.go index bac98bf..9738ea0 100644 --- a/node.go +++ b/node.go @@ -84,24 +84,7 @@ func GetNode(nodeID int) (node Node, err error) { // {{{ ) AS res ) , '[]'::jsonb - ) AS ConnectedNodes, - - COALESCE( - ( - SELECT jsonb_agg(res) - FROM ( - SELECT - h.id, - to_jsonb(s) AS script, - ssh - FROM hook h - INNER JOIN public.script s ON h.script_id = s.id - WHERE - h.node_id = n.id - ) AS res - ) - , '[]'::jsonb - ) AS ScriptHooks + ) AS ConnectedNodes FROM public.node n INNER JOIN public.type t ON n.type_id = t.id @@ -128,98 +111,25 @@ func GetNode(nodeID int) (node Node, err error) { // {{{ return } // }}} -func GetNodeTree(startNodeID, maxDepth int, withData bool) (topNode *Node, err error) { // {{{ +func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) { // {{{ nodes := make(map[int]*Node) - - var nodesFromRow []Node - row := db.QueryRow(` - SELECT json_agg(res) FROM ( - WITH RECURSIVE nodes AS ( - SELECT - $1::int AS id, - 0 AS depth - UNION - - SELECT - n.id, - ns.depth+1 AS depth - FROM node n - INNER JOIN nodes ns ON ns.depth < $2 AND n.parent_id = ns.id - ) - - SEARCH DEPTH FIRST BY id SET ordercol - - SELECT - COALESCE(n.parent_id, -1) AS ParentID, - n.id, - n.name, - n.type_id AS TypeID, - t.name AS TypeName, - COALESCE(t.schema->>'icon', '') AS TypeIcon, - n.updated, - n.data AS data, - COUNT(node_children.id) AS NumChildren, - COALESCE( - ( - SELECT jsonb_agg(res) - FROM ( - SELECT - nn.ID, - COALESCE(nn.parent_id, -1) AS ParentID, - nn.Name, - nn.Updated, - nn.data AS Data, - - tt.id AS TypeID, - tt.name AS TypeName, - tt.schema AS TypeSchema, - tt.schema->>'icon' AS TypeIcon, - - c.id AS ConnectionID, - c.data AS ConnectionData - FROM connection c - INNER JOIN public.node nn ON c.child_node_id = nn.id - INNER JOIN public.type tt ON nn.type_id = tt.id - WHERE - c.parent_node_id = n.id - ) AS res - ) - , '[]'::jsonb - ) AS ConnectedNodes - FROM nodes ns - INNER JOIN public.node n ON ns.id = n.id - INNER JOIN public.type t ON n.type_id = t.id - LEFT JOIN node node_children ON node_children.parent_id = n.id - - GROUP BY - ns.depth, - n.parent_id, - n.id, - t.name, - t.schema, - ns.ordercol - ORDER BY ordercol - ) AS res - `, - startNodeID, - maxDepth, - ) - - var body []byte - err = row.Scan(&body) - if err != nil { - err = werr.Wrap(err) - return - } - - err = json.Unmarshal(body, &nodesFromRow) + var rows *sqlx.Rows + rows, err = GetNodeRows(startNodeID, maxDepth) if err != nil { err = werr.Wrap(err) return } + defer rows.Close() first := true - for _, node := range nodesFromRow { + for rows.Next() { + var node Node + err = rows.StructScan(&node) + if err != nil { + err = werr.Wrap(err) + return + } + if first { topNode = &node first = false @@ -230,6 +140,57 @@ func GetNodeTree(startNodeID, maxDepth int, withData bool) (topNode *Node, err e return } // }}} +func GetNodeRows(startNodeID, maxDepth int) (rows *sqlx.Rows, err error) { // {{{ + rows, err = db.Queryx(` + WITH RECURSIVE nodes AS ( + SELECT + $1::int AS id, + 0 AS depth + UNION + + SELECT + n.id, + ns.depth+1 AS depth + FROM node n + INNER JOIN nodes ns ON ns.depth < $2 AND n.parent_id = ns.id + ) + + SEARCH DEPTH FIRST BY id SET ordercol + + SELECT + COALESCE(n.parent_id, -1) AS parent_id, + n.id, + n.name, + n.type_id, + t.name AS type_name, + COALESCE(t.schema->>'icon', '') AS type_icon, + n.updated, + n.data AS data_raw, + COUNT(node_children.id) AS num_children + FROM nodes ns + INNER JOIN public.node n ON ns.id = n.id + INNER JOIN public.type t ON n.type_id = t.id + LEFT JOIN node node_children ON node_children.parent_id = n.id + + GROUP BY + ns.depth, + n.parent_id, + n.id, + t.name, + t.schema, + ns.ordercol + ORDER BY ordercol + `, + startNodeID, + maxDepth, + ) + + if err != nil { + err = werr.Wrap(err) + } + + return +} // }}} func ComposeTree(nodes map[int]*Node, node *Node) { // {{{ if node.Children == nil { node.Children = []*Node{} @@ -360,7 +321,7 @@ func SearchNodes(typeID int, search string, maxResults int) (nodes []Node, err e row := db.QueryRowx(` SELECT - COALESCE(json_agg(res), '[]'::json) AS node + json_agg(res) AS node FROM ( SELECT n.id, diff --git a/static/css/main.css b/static/css/main.css index b87e152..5e62d57 100644 --- a/static/css/main.css +++ b/static/css/main.css @@ -220,7 +220,6 @@ select:focus { } #connected-nodes > .add img { height: 24px; - cursor: pointer; } #connected-nodes .connected-nodes { display: flex; @@ -246,41 +245,6 @@ select:focus { display: block; height: 24px; } -#script-hooks .scripts-grid { - display: grid; - grid-template-columns: repeat(4, min-content); - align-items: center; - grid-gap: 4px 0px; -} -#script-hooks .scripts-grid .header { - font-weight: bold; - margin-right: 8px; -} -#script-hooks .scripts-grid div { - white-space: nowrap; -} -#script-hooks .scripts-grid .script-icon { - margin-right: 4px; -} -#script-hooks .scripts-grid .script-icon img, -#script-hooks .scripts-grid .script-unhook img { - display: block; - height: 24px; -} -#script-hooks .scripts-grid .script-name, -#script-hooks .scripts-grid .script-ssh { - margin-right: 16px; -} -#script-hooks .scripts-grid .script-ssh { - cursor: pointer; -} -#script-hooks > .add { - margin-bottom: 8px; -} -#script-hooks > .add img { - height: 24px; - cursor: pointer; -} #script-hooks > .label { color: var(--section-color); font-weight: bold; diff --git a/static/images/logo.svg b/static/images/logo.svg index 1107d10..22fc538 100644 --- a/static/images/logo.svg +++ b/static/images/logo.svg @@ -2,13 +2,13 @@ JSONJSONDATAGRAPH + inkscape:connection-end="#circle6" /> diff --git a/static/js/app.mjs b/static/js/app.mjs index 503ffc4..06828a0 100644 --- a/static/js/app.mjs +++ b/static/js/app.mjs @@ -973,58 +973,19 @@ class ConnectedNode { } class ScriptHooks extends Component { - constructor(hooks) { + constructor() { super() - this.hooks = hooks } renderComponent() { const div = document.createElement('div') div.innerHTML = `
Script hooks
-
-
-
Script
-
SSH
-
+
hum
` - - div.querySelector('.add').addEventListener('click', ()=>{ - alert('FIXME') - }) - - const scriptsGrid = div.querySelector('.scripts-grid') - for(const hook of this.hooks) { - const h = new ScriptHook(hook) - scriptsGrid.append(h.render()) - } - return div.children } } -class ScriptHook extends Component { - constructor(hook) {// {{{ - super() - this.hook = hook - }// }}} - renderComponent() {// {{{ - const tmpl = document.createElement('template') - tmpl.innerHTML = ` -
-
${this.hook.Script.Name}
-
${this.hook.SSH}
-
- ` - - tmpl.content.querySelector('.script-ssh').addEventListener('click', () => { - prompt('SSH', this.hook.SSH) - //new ConnectionDataDialog(this.hook, () => _app.edit(_app.currentNode.ID)).render() - }) - - return tmpl.content - }// }}} -} - class ScriptsList extends Component { constructor() {// {{{ super() diff --git a/static/less/main.less b/static/less/main.less index c0a303b..2af627a 100644 --- a/static/less/main.less +++ b/static/less/main.less @@ -292,9 +292,9 @@ select:focus { & > .add { margin-bottom: 8px; + img { height: 24px; - cursor: pointer; } } @@ -330,56 +330,12 @@ select:focus { } #script-hooks { - .scripts-grid { - .header { - font-weight: bold; - margin-right: 8px; - } - - display: grid; - grid-template-columns: repeat(4, min-content); - align-items: center; - grid-gap: 4px 0px; - - div { - white-space: nowrap; - } - - .script-icon { - margin-right: 4px; - } - - .script-icon, .script-unhook { - img { - display: block; - height: 24px; - } - } - - .script-name, .script-ssh { - margin-right: 16px; - } - - .script-ssh { - cursor: pointer; - } - } - - & > .add { - margin-bottom: 8px; - img { - height: 24px; - cursor: pointer; - } - } - & > .label { color: var(--section-color); font-weight: bold; font-size: 1.25em; margin-bottom: 8px; } - } #select-node { diff --git a/webserver.go b/webserver.go index cd8d9b3..68ed9cb 100644 --- a/webserver.go +++ b/webserver.go @@ -50,7 +50,6 @@ func initWebserver() (err error) { http.HandleFunc("/scripts/", actionScripts) http.HandleFunc("/scripts/update/{scriptID}", actionScriptUpdate) http.HandleFunc("/scripts/delete/{scriptID}", actionScriptDelete) - http.HandleFunc("/hooks/update/{hookID}", actionHookUpdate) err = http.ListenAndServe(address, nil) return @@ -106,12 +105,7 @@ func actionNodesTree(w http.ResponseWriter, r *http.Request) { // {{{ maxDepth = 3 } - var withData bool - if r.URL.Query().Get("data") == "true" { - withData = true - } - - topNode, err := GetNodeTree(startNode, maxDepth, withData) + topNode, err := GetNodeTree(startNode, maxDepth) if err != nil { err = werr.Wrap(err) httpError(w, err) @@ -622,27 +616,4 @@ func actionScriptDelete(w http.ResponseWriter, r *http.Request) { // {{{ w.Write(j) } // }}} -func actionHookUpdate(w http.ResponseWriter, r *http.Request) { // {{{ - hookID := 0 - hookIDStr := r.PathValue("hookID") - hookID, _ = strconv.Atoi(hookIDStr) - - // XXX - here - - err := UpdateHook(hook) - if err != nil { - err = werr.Wrap(err) - httpError(w, err) - return - } - - out := struct { - OK bool - }{ - true, - } - j, _ := json.Marshal(out) - w.Write(j) -} // }}} - // vim: foldmethod=marker