Compare commits

...

3 commits

Author SHA1 Message Date
Magnus Åhall
2a04cba42a More work on hooks 2025-08-07 15:51:15 +02:00
Magnus Åhall
392aa0d11f Logo update 2025-08-07 14:04:37 +02:00
Magnus Åhall
0138f72b83 JSON-based SQL query for node tree 2025-08-07 14:04:37 +02:00
6 changed files with 337 additions and 150 deletions

169
node.go
View file

@ -84,7 +84,24 @@ func GetNode(nodeID int) (node Node, err error) { // {{{
) AS res
)
, '[]'::jsonb
) AS ConnectedNodes
) 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
FROM public.node n
INNER JOIN public.type t ON n.type_id = t.id
@ -111,25 +128,98 @@ func GetNode(nodeID int) (node Node, err error) { // {{{
return
} // }}}
func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) { // {{{
func GetNodeTree(startNodeID, maxDepth int, withData bool) (topNode *Node, err error) { // {{{
nodes := make(map[int]*Node)
var rows *sqlx.Rows
rows, err = GetNodeRows(startNodeID, maxDepth)
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)
if err != nil {
err = werr.Wrap(err)
return
}
defer rows.Close()
first := true
for rows.Next() {
var node Node
err = rows.StructScan(&node)
if err != nil {
err = werr.Wrap(err)
return
}
for _, node := range nodesFromRow {
if first {
topNode = &node
first = false
@ -140,57 +230,6 @@ func GetNodeTree(startNodeID, maxDepth int) (topNode *Node, err error) { // {{{
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{}
@ -321,7 +360,7 @@ func SearchNodes(typeID int, search string, maxResults int) (nodes []Node, err e
row := db.QueryRowx(`
SELECT
json_agg(res) AS node
COALESCE(json_agg(res), '[]'::json) AS node
FROM (
SELECT
n.id,

View file

@ -220,6 +220,7 @@ select:focus {
}
#connected-nodes > .add img {
height: 24px;
cursor: pointer;
}
#connected-nodes .connected-nodes {
display: flex;
@ -245,6 +246,41 @@ 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;

View file

@ -2,13 +2,13 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="79.624962mm"
height="78.647499mm"
viewBox="0 0 79.624962 78.647499"
width="109.69499mm"
height="47.615765mm"
viewBox="0 0 109.695 47.615764"
version="1.1"
id="svg1"
xml:space="preserve"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
inkscape:version="1.4 (e7c3feb, 2024-10-09)"
sodipodi:docname="logo.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
@ -23,120 +23,120 @@
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.60258984"
inkscape:cx="66.380144"
inkscape:cy="193.33217"
inkscape:window-width="1916"
inkscape:window-height="1161"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" /><defs
inkscape:zoom="1.6985744"
inkscape:cx="278.17446"
inkscape:cy="101.85012"
inkscape:window-width="2190"
inkscape:window-height="1404"
inkscape:window-x="1463"
inkscape:window-y="16"
inkscape:window-maximized="0"
inkscape:current-layer="layer1"
showgrid="false" /><defs
id="defs1" /><g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-38.185371,-67.683764)"><path
d="m 51.45301,114.65074 v -1.98318 h 4.210436 q 1.55603,0 2.379811,-0.82378 0.823781,-0.82378 0.823781,-2.50185 V 98.632775 h -3.081551 v -1.983178 h 4.881664 v 12.051613 q 0,5.94953 -5.247789,5.94953 z M 72.535691,98.632775 h -4.942685 q -1.311947,0 -2.074707,0.67123 -0.76276,0.67123 -0.76276,2.135735 0,1.58654 0.610208,2.3493 0.610208,0.73225 1.708582,0.73225 h 1.861134 q 2.379812,0 3.417165,1.34245 1.037354,1.34246 1.037354,3.90533 0,2.41033 -1.342458,3.66125 -1.311947,1.22042 -3.874821,1.22042 h -5.308809 v -1.98318 h 5.827486 q 1.281437,0 1.983176,-0.70174 0.73225,-0.70174 0.73225,-2.16624 0,-1.55603 -0.579698,-2.41032 -0.579697,-0.8848 -1.861134,-0.8848 h -2.013687 q -2.166238,0 -3.142571,-1.25092 -0.976333,-1.28144 -0.976333,-3.84432 0,-2.349305 1.281437,-3.539205 1.281437,-1.220418 3.966352,-1.220418 h 4.454519 z m 10.922694,-1.983178 q 1.372968,0 2.074708,0.671228 0.732249,0.67123 0.732249,2.22726 v 12.021105 q 0,3.08155 -2.959509,3.08155 H 78.45468 q -2.867978,0 -2.867978,-2.86798 V 99.548085 q 0,-2.898488 2.837467,-2.898488 z m -4.362987,1.983178 q -1.617051,0 -1.617051,1.464505 v 10.83119 q 0,0.91531 0.427145,1.34246 0.427146,0.39663 1.006844,0.39663 h 4.088393 q 0.549187,0 0.945823,-0.51867 0.427145,-0.51868 0.427145,-1.22042 v -10.83119 q 0,-0.793275 -0.427145,-1.128895 -0.427146,-0.33561 -1.159396,-0.33561 z M 98.835602,114.65074 H 96.089666 L 90.628304,100.4634 v 14.18734 H 88.858701 V 96.649597 h 2.257769 l 5.919018,15.377243 V 96.649597 h 1.800114 z"
id="text1"
style="font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';text-align:center;text-anchor:middle;fill:#262626;stroke-width:1.71737"
aria-label="JSON" /><circle
transform="translate(-44.705332,-99.606546)"><circle
style="fill:#27a698;fill-opacity:1;stroke-width:0.477313;-inkscape-stroke:none"
id="path1"
cx="46.627323"
cy="90.933174"
cx="88.605194"
cy="113.66309"
r="4.6399903" /><circle
style="fill:#1e6380;fill-opacity:1;stroke-width:0.452723;-inkscape-stroke:none"
id="circle1"
cx="96.612923"
cy="72.084717"
r="4.4009533" /><circle
style="fill:#21818c;fill-opacity:1;stroke-width:0.529167;-inkscape-stroke:none"
id="circle2"
cx="43.329437"
cy="121.67689"
r="5.1440659" /><circle
style="fill:#2988af;fill-opacity:1;stroke-width:0.355205;-inkscape-stroke:none"
id="circle3"
cx="78.708733"
cy="125.57096"
r="3.4529741" /><circle
style="fill:#1e4c80;fill-opacity:1;stroke-width:0.70227;-inkscape-stroke:none"
id="circle4"
cx="102.07027"
cy="124.97508"
r="6.8268108" /><text
cx="149.99937"
cy="115.46115"
r="4.4009533" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;line-height:normal;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#262626;stroke-width:1.71737;-inkscape-stroke:none"
x="73.981911"
y="186.11093"
x="62.183887"
y="178.34908"
id="text4"><tspan
sodipodi:role="line"
id="tspan4"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.71737"
x="73.981911"
y="186.11093">JSON</tspan></text><circle
style="fill:#1e8071;fill-opacity:1;stroke-width:0.529167;-inkscape-stroke:none"
x="62.183887"
y="178.34908">JSON</tspan></text><circle
style="fill:#1e8071;fill-opacity:1;stroke-width:0.529166;-inkscape-stroke:none"
id="circle5"
cx="80.797234"
cy="85.280693"
r="5.1440659" /><circle
cx="113.69239"
cy="105.83727"
r="6.2307262" /><circle
style="fill:#248d9a;fill-opacity:1;stroke-width:0.529167;-inkscape-stroke:none"
id="circle6"
cx="112.66627"
cy="94.749619"
cx="120.87872"
cy="127.25946"
r="5.1440659" /><path
style="fill:none;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 51.205022,90.175919 75.722226,86.120215"
d="M 93.034595,112.28137 107.74445,107.6927"
id="path6"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#path1"
inkscape:connection-end="#circle5" /><path
style="fill:none;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 84.746953,81.985206 93.23378,74.904138"
d="m 119.71508,107.4337 26.03029,6.89984"
id="path7"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle5"
inkscape:connection-end="#circle1" /><path
style="fill:#1e6380;fill-opacity:1;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 85.728154,86.745768 22.007196,6.538776"
d="m 115.674,111.74437 3.56871,10.63821"
id="path8"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle5"
inkscape:connection-end="#circle6" /><path
style="display:inline;fill:#1e6380;fill-opacity:1;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 48.4426,122.23968 26.833902,2.95351"
id="path9"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle2"
inkscape:connection-end="#circle3" /><path
style="fill:none;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 82.160565,125.48292 13.085148,-0.33376"
id="path10"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-end="#circle4"
inkscape:connection-start="#circle3" /><circle
style="fill:#267ea2;fill-opacity:1;stroke-width:0.653982;-inkscape-stroke:none"
id="circle10"
cx="62.795177"
cy="139.97386"
r="6.3574047" /><path
inkscape:connection-end="#circle6"
inkscape:connection-start="#circle5" /><circle
style="fill:#21608c;fill-opacity:1;stroke-width:0.529167;-inkscape-stroke:none"
id="circle2"
cx="107.89297"
cy="142.85443"
r="4.3678799" /><path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1e6380;fill-opacity:1;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
d="m 67.508676,135.70781 8.639957,-7.81978"
id="path11"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle10"
inkscape:connection-end="#circle3" /><path
style="font-variation-settings:normal;opacity:1;vector-effect:none;fill:#1e6380;fill-opacity:1;fill-rule:evenodd;stroke:#205d7b;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;-inkscape-stroke:none;stop-color:#000000;stop-opacity:1"
d="M 99.156616,75.676028 109.69306,90.551905"
d="m 145.92055,117.1137 -20.27428,8.21418"
id="path12"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle1"
inkscape:connection-end="#circle6" /></g></svg>
inkscape:connection-end="#circle6" /><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;line-height:normal;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#666666;stroke-width:1.71737;-inkscape-stroke:none"
x="175.50702"
y="180.21191"
id="text2"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;fill:#666666;stroke-width:1.71737"
x="175.50702"
y="180.21191"
id="tspan3"
dx="0 0 0 -1.5523715">DATA</tspan></text><text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;line-height:normal;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;text-align:center;text-decoration-color:#000000;text-anchor:middle;fill:#262626;stroke-width:1.71737;-inkscape-stroke:none"
x="185.68044"
y="200.32968"
id="text5"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';font-variant-ligatures:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-east-asian:normal;stroke-width:1.71737"
x="185.68044"
y="200.32968"
id="tspan5">GRAPH</tspan></text><g
id="g7"
transform="matrix(0.80394165,0,0,0.80394165,-58.792934,51.253772)"
style="stroke-width:1.24387"><path
d="m 134.23041,75.898918 q 2.37981,0 3.50869,1.250927 1.1594,1.250926 1.1594,3.691758 v 8.085257 q 0,2.501852 -1.31195,3.752779 -1.28144,1.220416 -3.75278,1.220416 h -5.09523 V 75.898918 Z m -3.75278,1.983177 v 14.034784 h 3.69176 q 2.83746,0 2.83746,-2.776447 v -8.695464 q 0,-1.281437 -0.67122,-1.922155 -0.64072,-0.640718 -2.10522,-0.640718 z m 20.13675,16.01796 h -1.95266 l -0.67123,-2.898488 h -5.91902 l -0.61021,2.898488 h -1.95266 l 4.24094,-18.001137 h 2.89849 z m -8.05474,-4.881664 h 5.03421 l -2.41032,-11.166807 z m 16.13997,-11.136296 h -3.96636 v 16.01796 h -1.80011 v -16.01796 h -3.53921 v -1.983177 h 9.30568 z m 10.59074,16.01796 h -1.95266 l -0.67123,-2.898488 h -5.91902 l -0.61021,2.898488 h -1.95266 l 4.24094,-18.001137 h 2.89849 z m -8.05474,-4.881664 h 5.03421 L 163.8595,77.851584 Z"
id="text6"
style="font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';text-align:center;text-anchor:middle;fill:#666666;stroke-width:2.13619"
aria-label="DATA" /><path
d="m 139.02054,114.01782 h -5.98004 q -2.28828,0 -3.29512,-1.15939 -1.00685,-1.1594 -1.00685,-3.53921 v -8.81751 q 0,-2.288275 1.22042,-3.38665 1.25092,-1.098374 3.66125,-1.098374 h 5.52238 v 1.983176 h -6.13259 q -2.41032,0 -2.41032,2.379808 v 9.18363 q 0,1.37297 0.54918,1.92216 0.5797,0.54919 1.52552,0.54919 h 4.45452 v -6.04106 h -3.84431 v -2.01369 h 5.73596 z m 8.66492,-18.001134 q 2.25777,0 3.20359,1.372968 0.97634,1.372968 0.97634,4.057886 0,2.16624 -0.76276,3.29512 -0.76276,1.12889 -1.76961,1.25093 0.70174,0.21357 1.1594,0.6102 0.45765,0.39664 0.70174,0.91532 0.27459,0.48816 0.36612,1.09837 0.12204,0.5797 0.12204,1.1594 v 4.24094 h -1.86113 v -3.99686 q 0,-1.55603 -0.54919,-2.25777 -0.51868,-0.73225 -1.83062,-0.73225 h -4.11891 v 6.98688 h -1.80011 V 96.016686 Z m -4.33248,1.983176 v 7.047898 h 4.11891 q 1.15939,0 1.83062,-0.94582 0.67123,-0.94582 0.67123,-2.59338 0,-1.617053 -0.48817,-2.562876 -0.45765,-0.945822 -1.64756,-0.945822 z m 21.05213,16.017958 h -1.95266 l -0.67123,-2.89849 h -5.91902 l -0.61021,2.89849 h -1.95266 l 4.24094,-18.001134 h 2.89849 z m -8.05474,-4.88166 h 5.03421 l -2.41032,-11.166809 z m 11.56342,-2.10522 v 6.98688 h -1.7696 V 96.016686 h 6.1631 q 4.1189,0 4.1189,4.362984 v 2.01369 q 0,4.63758 -4.21043,4.63758 z m 0.0305,-9.031078 v 7.047898 h 4.21044 q 2.3493,0 2.3493,-2.56287 v -2.0442 q 0,-2.440828 -2.28828,-2.440828 z m 10.40404,16.017958 V 96.016686 h 1.86113 v 7.993724 h 6.49872 v -7.993724 h 1.80011 v 18.001134 h -1.80011 v -8.02423 h -6.49872 v 8.02423 z"
id="text7"
style="font-size:30.5104px;font-family:'Forgotten Futurist';-inkscape-font-specification:'Forgotten Futurist, Normal';text-align:center;text-anchor:middle;fill:#262626;stroke-width:2.13619"
aria-label="GRAPH" /></g><path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="m 117.58714,131.21242 -6.89925,8.28551"
id="path13"
inkscape:connector-type="polyline"
inkscape:connector-curvature="0"
inkscape:connection-start="#circle6"
inkscape:connection-end="#circle2" /></g></svg>

Before

Width:  |  Height:  |  Size: 8.6 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Before After
Before After

View file

@ -973,19 +973,58 @@ class ConnectedNode {
}
class ScriptHooks extends Component {
constructor() {
constructor(hooks) {
super()
this.hooks = hooks
}
renderComponent() {
const div = document.createElement('div')
div.innerHTML = `
<div class="label">Script hooks</div>
<div>hum</div>
<div class="add"><img 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>
</div>
`
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 = `
<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-unhook"><img src="/images/${_VERSION}/node_modules/@mdi/svg/svg/trash-can.svg" /></div>
`
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()

View file

@ -292,9 +292,9 @@ select:focus {
& > .add {
margin-bottom: 8px;
img {
height: 24px;
cursor: pointer;
}
}
@ -330,12 +330,56 @@ 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 {

View file

@ -50,6 +50,7 @@ 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
@ -105,7 +106,12 @@ func actionNodesTree(w http.ResponseWriter, r *http.Request) { // {{{
maxDepth = 3
}
topNode, err := GetNodeTree(startNode, maxDepth)
var withData bool
if r.URL.Query().Get("data") == "true" {
withData = true
}
topNode, err := GetNodeTree(startNode, maxDepth, withData)
if err != nil {
err = werr.Wrap(err)
httpError(w, err)
@ -616,4 +622,27 @@ 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