Compare commits
3 commits
f1f0f499dd
...
2a04cba42a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a04cba42a | ||
|
|
392aa0d11f | ||
|
|
0138f72b83 |
6 changed files with 337 additions and 150 deletions
169
node.go
169
node.go
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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 |
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
31
webserver.go
31
webserver.go
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue