From 714d316d7de7b41c5f564c66fc4d77d64c64b00c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Tue, 2 Jun 2026 07:30:55 +0200 Subject: [PATCH 1/4] Update to table formatting --- static/css/markdown.css | 2 ++ static/js/page_node.mjs | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/static/css/markdown.css b/static/css/markdown.css index cf80c34..631f578 100644 --- a/static/css/markdown.css +++ b/static/css/markdown.css @@ -1,4 +1,6 @@ .el-node-markdown { + padding-top: 16px; + h1 { border-bottom: 1px solid #ccc; margin-top: 32px; diff --git a/static/js/page_node.mjs b/static/js/page_node.mjs index 6291c8f..d151f77 100644 --- a/static/js/page_node.mjs +++ b/static/js/page_node.mjs @@ -86,6 +86,8 @@ export class N2PageNodeUI extends CustomHTMLElement { const formatted = this.formatAllTables(text) this.elNodeContent.setRangeText(formatted, from, to, 'select'); } + + this.node.setContent(this.elNodeContent.value) }) this.showMarkdown(true) @@ -245,7 +247,7 @@ export class N2PageNodeUI extends CustomHTMLElement { } } - lines[i] = '│ ' + cols.join(' │ ') + ' │' + lines[i] = '| ' + cols.join(' | ') + ' |' } return lines From bcd9d8df2d3eb43321a920168d07eab136ba21f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Tue, 2 Jun 2026 07:31:05 +0200 Subject: [PATCH 2/4] Bumped to v6 --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index 8edd01c..96e26ca 100644 --- a/main.go +++ b/main.go @@ -23,7 +23,7 @@ import ( "text/template" ) -const VERSION = "v5" +const VERSION = "v6" const CONTEXT_USER = 1 const SYNC_PAGINATION = 200 From b3652e48afaaa94cc9b38b329388ed56df984248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Tue, 2 Jun 2026 07:32:20 +0200 Subject: [PATCH 3/4] Remove debugging --- static/js/sync.mjs | 3 --- 1 file changed, 3 deletions(-) diff --git a/static/js/sync.mjs b/static/js/sync.mjs index e432f15..291e0b9 100644 --- a/static/js/sync.mjs +++ b/static/js/sync.mjs @@ -9,9 +9,6 @@ export class Sync { }//}}} async run() {//{{{ - // XXX - Delete me - return - try { let duration = 0 // in ms From 2f27aeffb362ba74cd7030621d3aa3cc398df88b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Magnus=20=C3=85hall?= Date: Tue, 2 Jun 2026 17:11:36 +0200 Subject: [PATCH 4/4] Fixed add_nodes function in database when adding a new top-level node --- sql/00002.sql | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 sql/00002.sql diff --git a/sql/00002.sql b/sql/00002.sql new file mode 100644 index 0000000..1775dc3 --- /dev/null +++ b/sql/00002.sql @@ -0,0 +1,168 @@ +CREATE OR REPLACE PROCEDURE public.add_nodes(IN p_user_id integer, IN p_client_uuid character varying, IN p_nodes jsonb) + LANGUAGE plpgsql +AS $procedure$ + +DECLARE + node_data jsonb; + node_updated timestamptz; + db_updated timestamptz; + db_uuid bpchar; + db_client bpchar; + db_client_seq int; + node_uuid bpchar; + parent_uuid bpchar; + +BEGIN + RAISE NOTICE '--------------------------'; + FOR node_data IN SELECT * FROM jsonb_array_elements(p_nodes) + LOOP + node_uuid = (node_data->>'UUID')::bpchar; + node_updated = (node_data->>'Updated')::timestamptz; + + IF node_data->>'ParentUUID' = '00000000-0000-0000-0000-000000000000' THEN + parent_uuid = NULL; + ELSE + parent_uuid = node_data->>'ParentUUID'; + END IF; + + /* Retrieve the current modified timestamp for this node from the database. */ + SELECT + uuid, updated, client, client_sequence + INTO + db_uuid, db_updated, db_client, db_client_seq + FROM public."node" + WHERE + user_id = p_user_id AND + uuid = node_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", markdown, "content_encrypted", + client, client_sequence + ) + VALUES( + p_user_id, + node_uuid, + parent_uuid, + (node_data->>'Created')::timestamptz, + (node_data->>'Updated')::timestamptz, + (node_data->>'Name')::varchar, + (node_data->>'Content')::text, + (node_data->>'Markdown')::bool, + '', /* content_encrypted */ + p_client_uuid, + (node_data->>'ClientSequence')::int + ); + CONTINUE; + END IF; + + + /* The client could send a specific node again if it didn't receive the OK from this procedure before. */ + IF db_updated = node_updated AND db_client = p_client_uuid AND db_client_seq = (node_data->>'ClientSequence')::int THEN + RAISE NOTICE '04, already recorded, %, %', db_client, db_client_seq; + CONTINUE; + END IF; + + /* Determine if the incoming node data is to go into history or replace the current node. */ + IF db_updated > node_updated THEN + RAISE NOTICE '02 DB newer, % > % (%))', db_updated, node_updated, node_uuid; + /* Incoming node is going straight to history since it is older than the current node. */ + INSERT INTO node_history( + user_id, "uuid", parents, created, updated, + "name", "content", markdown, "content_encrypted", + client, client_sequence + ) + VALUES( + p_user_id, + node_uuid, + (jsonb_populate_record(null::json_ancestor_array, node_data))."Ancestors", + (node_data->>'Created')::timestamptz, + (node_data->>'Updated')::timestamptz, + (node_data->>'Name')::varchar, + (node_data->>'Content')::text, + (node_data->>'Markdown')::bool, + '', /* content_encrypted */ + p_client_uuid, + (node_data->>'ClientSequence')::int + ) + ON CONFLICT (client, client_sequence) + DO NOTHING; + ELSE + RAISE NOTICE '03 Client newer, % > % (%, %)', node_updated, db_updated, node_uuid, (node_data->>'ClientSequence'); + /* Incoming node is newer and will replace the current node. + * + * The current node is copied to the node_history table and then modified in place + * with the incoming data. */ + INSERT INTO node_history( + user_id, "uuid", parents, + created, updated, "name", "content", markdown, "content_encrypted", + client, client_sequence + ) + SELECT + user_id, + "uuid", + ( + WITH RECURSIVE nodes AS ( + SELECT + uuid, + COALESCE(node.parent_uuid, '') AS parent_uuid, + name, + 0 AS depth + FROM node + WHERE + uuid = node_uuid + + UNION + + SELECT + n.uuid, + COALESCE(n.parent_uuid, '') AS parent_uuid, + n.name, + nr.depth+1 AS depth + FROM node n + INNER JOIN nodes nr ON n.uuid = nr.parent_uuid + ) + SELECT ARRAY ( + SELECT name + FROM nodes + ORDER BY depth DESC + OFFSET 1 /* discard itself */ + ) + ), + created, + updated, + name, + content, + markdown, + content_encrypted, + client, + client_sequence + FROM public."node" + WHERE + user_id = p_user_id AND + uuid = node_uuid + ON CONFLICT (client, client_sequence) + DO NOTHING; + + /* Current node in database is updated with incoming data. */ + UPDATE public."node" + SET + updated = (node_data->>'Updated')::timestamptz, + updated_seq = nextval('node_updates'), + name = (node_data->>'Name')::varchar, + content = (node_data->>'Content')::text, + markdown = (node_data->>'Markdown')::bool, + client = p_client_uuid, + client_sequence = (node_data->>'ClientSequence')::int + WHERE + user_id = p_user_id AND + uuid = node_uuid; + END IF; + + END LOOP; +END +$procedure$ +;