Compare commits
No commits in common. "658733b1d879cd2eb137c2954aa655e438972d14" and "53d8d16086d8941b35b348ab4008a08513535171" have entirely different histories.
658733b1d8
...
53d8d16086
4 changed files with 14 additions and 180 deletions
119
sql/00007.sql
119
sql/00007.sql
|
|
@ -1,119 +0,0 @@
|
||||||
CREATE OR REPLACE PROCEDURE public.add_nodes(IN p_user_id integer, IN p_client_uuid uuid, IN p_nodes jsonb)
|
|
||||||
LANGUAGE plpgsql
|
|
||||||
AS $procedure$
|
|
||||||
|
|
||||||
DECLARE
|
|
||||||
node_data jsonb;
|
|
||||||
node_updated timestamptz;
|
|
||||||
db_updated timestamptz;
|
|
||||||
db_uuid uuid;
|
|
||||||
db_client uuid;
|
|
||||||
db_history_uuid uuid;
|
|
||||||
node_uuid uuid;
|
|
||||||
node_parent_uuid uuid;
|
|
||||||
node_history_uuid uuid;
|
|
||||||
|
|
||||||
BEGIN
|
|
||||||
FOR node_data IN SELECT * FROM jsonb_array_elements(p_nodes)
|
|
||||||
LOOP
|
|
||||||
node_uuid = (node_data->>'UUID')::uuid;
|
|
||||||
node_history_uuid = (node_data->>'HistoryUUID')::uuid;
|
|
||||||
node_updated = (node_data->>'Updated')::timestamptz;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Frontend is using an all-zero UUID to define the root node.
|
|
||||||
-- Database is using NULL.
|
|
||||||
IF node_data->>'ParentUUID' = '00000000-0000-0000-0000-000000000000' OR node_data->>'ParentUUID' = '' THEN
|
|
||||||
node_parent_uuid = NULL;
|
|
||||||
ELSE
|
|
||||||
node_parent_uuid = (node_data->>'ParentUUID')::uuid;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Every jode has a new history UUID to keep the history entry uniquely identifiable
|
|
||||||
-- across clients. A history entry could potentially be sent again, but should be
|
|
||||||
-- safe to ignore as every change to a node should have a new history UUID.
|
|
||||||
--
|
|
||||||
-- The current node is also stored as history.
|
|
||||||
INSERT INTO node_history(
|
|
||||||
user_id, "uuid", "history_uuid", parents, created, updated,
|
|
||||||
"name", "content", "content_encrypted",
|
|
||||||
client
|
|
||||||
)
|
|
||||||
VALUES(
|
|
||||||
p_user_id, -- combined key
|
|
||||||
node_uuid, -- combined key
|
|
||||||
node_history_uuid, -- combined key
|
|
||||||
(jsonb_populate_record(null::json_ancestor_array, node_data))."Ancestors",
|
|
||||||
COALESCE((node_data->>'Created')::timestamptz, NOW()),
|
|
||||||
COALESCE((node_data->>'Updated')::timestamptz, NOW()),
|
|
||||||
(node_data->>'Name')::varchar,
|
|
||||||
(node_data->>'Content')::text,
|
|
||||||
'', /* content_encrypted */
|
|
||||||
p_client_uuid
|
|
||||||
)
|
|
||||||
ON CONFLICT ("user_id", "uuid", "history_uuid")
|
|
||||||
DO NOTHING;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Retrieve the current modified timestamp for this node from the database.
|
|
||||||
SELECT
|
|
||||||
uuid, updated, client
|
|
||||||
INTO
|
|
||||||
db_uuid, db_updated, db_client
|
|
||||||
FROM public."node"
|
|
||||||
WHERE
|
|
||||||
user_id = p_user_id AND
|
|
||||||
uuid::uuid = node_uuid::uuid;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Is the node not in database? It needs to be created.
|
|
||||||
IF db_uuid IS NULL THEN
|
|
||||||
RAISE NOTICE '01 New node %', node_uuid;
|
|
||||||
|
|
||||||
INSERT INTO public."node" (
|
|
||||||
user_id, "uuid", parent_uuid, created, updated,
|
|
||||||
"name", "content", "content_encrypted",
|
|
||||||
client
|
|
||||||
)
|
|
||||||
VALUES(
|
|
||||||
p_user_id,
|
|
||||||
node_uuid,
|
|
||||||
node_parent_uuid,
|
|
||||||
COALESCE((node_data->>'Created')::timestamptz, NOW()),
|
|
||||||
COALESCE((node_data->>'Updated')::timestamptz, NOW()),
|
|
||||||
(node_data->>'Name')::varchar,
|
|
||||||
(node_data->>'Content')::text,
|
|
||||||
'', /* content_encrypted */
|
|
||||||
p_client_uuid
|
|
||||||
);
|
|
||||||
|
|
||||||
CONTINUE;
|
|
||||||
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-- Update the public node as well if it was older than incoming node.
|
|
||||||
IF node_updated > db_updated THEN
|
|
||||||
UPDATE public."node"
|
|
||||||
SET
|
|
||||||
updated = (node_data->>'Updated')::timestamptz,
|
|
||||||
updated_seq = nextval('node_updates'),
|
|
||||||
parent_uuid = node_parent_uuid,
|
|
||||||
name = (node_data->>'Name')::varchar,
|
|
||||||
content = (node_data->>'Content')::text,
|
|
||||||
client = p_client_uuid
|
|
||||||
WHERE
|
|
||||||
user_id = p_user_id AND
|
|
||||||
uuid::uuid = node_uuid::uuid;
|
|
||||||
END IF;
|
|
||||||
|
|
||||||
END LOOP;
|
|
||||||
END
|
|
||||||
$procedure$
|
|
||||||
;
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="26.666645"
|
|
||||||
height="24"
|
|
||||||
viewBox="0 0 7.0555498 6.35"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.4.2 (ebf0e94, 2025-05-08)"
|
|
||||||
sodipodi:docname="icon_menu.svg"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#000000"
|
|
||||||
borderopacity="0.25"
|
|
||||||
inkscape:showpageshadow="2"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pagecheckerboard="0"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:zoom="2.096401"
|
|
||||||
inkscape:cx="10.255672"
|
|
||||||
inkscape:cy="9.0631517"
|
|
||||||
inkscape:window-width="1916"
|
|
||||||
inkscape:window-height="1041"
|
|
||||||
inkscape:window-x="1920"
|
|
||||||
inkscape:window-y="1080"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
inkscape:current-layer="layer1" />
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-146.57917,-92.339583)">
|
|
||||||
<title
|
|
||||||
id="title1">menu</title>
|
|
||||||
<title
|
|
||||||
id="title1-6">hamburger</title>
|
|
||||||
<path
|
|
||||||
d="m 153.63472,95.867362 c 0,0.391582 -0.31398,0.705554 -0.70555,0.705554 h -5.64445 c -0.38806,0 -0.70555,-0.313972 -0.70555,-0.705554 0,-0.391584 0.31749,-0.705556 0.70555,-0.705556 h 3.175 l 0.88194,0.705556 0.88195,-0.705556 h 0.70556 c 0.39157,0 0.70555,0.3175 0.70555,0.705556 m -3.52778,-3.527779 c -3.175,0 -3.175,2.116667 -3.175,2.116667 h 6.35 c 0,0 0,-2.116667 -3.175,-2.116667 m -3.175,5.291667 c 0,0.585612 0.47272,1.058333 1.05834,1.058333 h 4.23333 c 0.58561,0 1.05833,-0.472721 1.05833,-1.058333 v -0.352778 h -6.35 z"
|
|
||||||
id="path1-2"
|
|
||||||
style="stroke-width:0.352777" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
|
@ -370,7 +370,7 @@ class N2DragIcon extends CustomHTMLElement {
|
||||||
this.style.top = `${e.clientY}px`
|
this.style.top = `${e.clientY}px`
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dragSource = null
|
this.dragTarget = null
|
||||||
}// }}}
|
}// }}}
|
||||||
start() {// {{{
|
start() {// {{{
|
||||||
this.style.display = 'block'
|
this.style.display = 'block'
|
||||||
|
|
@ -383,11 +383,11 @@ class N2DragIcon extends CustomHTMLElement {
|
||||||
name = '_' + name
|
name = '_' + name
|
||||||
this.elIcon.setAttribute('src', `/images/${_VERSION}/icon_drag${name}.svg`)
|
this.elIcon.setAttribute('src', `/images/${_VERSION}/icon_drag${name}.svg`)
|
||||||
}// }}}
|
}// }}}
|
||||||
setSource(s) {// {{{
|
setTarget(t) {// {{{
|
||||||
this.dragSource = s
|
this.dragTarget = t
|
||||||
}// }}}
|
}// }}}
|
||||||
getSource() {// {{{
|
getTarget() {// {{{
|
||||||
return this.dragSource
|
return this.dragTarget
|
||||||
}// }}}
|
}// }}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -585,7 +585,6 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
e.dataTransfer.setDragImage(blankPixel, 0, 0)
|
e.dataTransfer.setDragImage(blankPixel, 0, 0)
|
||||||
e.dataTransfer.allowedEffects = 'none'
|
e.dataTransfer.allowedEffects = 'none'
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
_app.dragIcon.setSource(this)
|
|
||||||
_app.dragIcon.start()
|
_app.dragIcon.start()
|
||||||
}// }}}
|
}// }}}
|
||||||
dragEnd(e) {// {{{
|
dragEnd(e) {// {{{
|
||||||
|
|
@ -599,12 +598,13 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
}// }}}
|
}// }}}
|
||||||
async dragDrop(e) {// {{{
|
async dragDrop(e) {// {{{
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
const sourceNode = _app.dragIcon.getSource()
|
const moveToNode = _app.dragIcon.getTarget()
|
||||||
await _app.moveNode(sourceNode.node, this.node.UUID)
|
await _app.moveNode(this.node, moveToNode.node.UUID)
|
||||||
|
return
|
||||||
|
|
||||||
_app.sidebar.setNodeExpanded(this, true)
|
_app.sidebar.setNodeExpanded(moveToNode, true)
|
||||||
await this.render(true, true)
|
await this.render(true, true)
|
||||||
await sourceNode.render(true, true)
|
await moveToNode.render(true, true)
|
||||||
|
|
||||||
this.dragLeave(e)
|
this.dragLeave(e)
|
||||||
}// }}}
|
}// }}}
|
||||||
|
|
@ -615,6 +615,8 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
_app.dragIcon.icon('ok')
|
_app.dragIcon.icon('ok')
|
||||||
this.classList.add('drag-target')
|
this.classList.add('drag-target')
|
||||||
|
|
||||||
|
_app.dragIcon.setTarget(this)
|
||||||
}// }}}
|
}// }}}
|
||||||
dragLeave(e) {// {{{
|
dragLeave(e) {// {{{
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
@ -622,6 +624,8 @@ export class N2TreeNode extends CustomHTMLElement {
|
||||||
e.dataTransfer.setDragImage(N2TreeNode.DRAG_ICON, -16, 8)
|
e.dataTransfer.setDragImage(N2TreeNode.DRAG_ICON, -16, 8)
|
||||||
_app.dragIcon.icon('')
|
_app.dragIcon.icon('')
|
||||||
this.classList.remove('drag-target')
|
this.classList.remove('drag-target')
|
||||||
|
|
||||||
|
_app.dragIcon.setTarget(null)
|
||||||
}// }}}
|
}// }}}
|
||||||
async fetchChildren(force_fetch) {//{{{
|
async fetchChildren(force_fetch) {//{{{
|
||||||
if (this.children_populated && !force_fetch)
|
if (this.children_populated && !force_fetch)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue