Fullfør oppgave 3.5: TipTap-editor med create_node + owner-edge

Legger til owner-edge etter node-opprettelse slik at noden dukker opp
i brukerens mottak. Gjør API-klienten konfigurerbar via VITE_API_URL
for fremtidig produksjonsbruk. Legger til createEdge i API-klienten.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-17 14:26:59 +01:00
parent daaafd34ab
commit 0756e17069
3 changed files with 42 additions and 13 deletions

View file

@ -1,10 +1,10 @@
/** /**
* Client for maskinrommet intentions API. * Client for maskinrommet intentions API.
* Uses the Vite dev proxy (/api api.sidelinja.org) in development, * Uses the Vite dev proxy (/api api.sidelinja.org) in development.
* and direct URL in production. * In production, set VITE_API_URL to the maskinrommet URL.
*/ */
const BASE_URL = '/api'; const BASE_URL = import.meta.env.VITE_API_URL ?? '/api';
export interface CreateNodeRequest { export interface CreateNodeRequest {
node_kind?: string; node_kind?: string;
@ -18,11 +18,20 @@ export interface CreateNodeResponse {
node_id: string; node_id: string;
} }
export async function createNode( export interface CreateEdgeRequest {
accessToken: string, source_id: string;
data: CreateNodeRequest target_id: string;
): Promise<CreateNodeResponse> { edge_type: string;
const res = await fetch(`${BASE_URL}/intentions/create_node`, { metadata?: Record<string, unknown>;
system?: boolean;
}
export interface CreateEdgeResponse {
edge_id: string;
}
async function post<T>(accessToken: string, path: string, data: unknown): Promise<T> {
const res = await fetch(`${BASE_URL}${path}`, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
@ -33,8 +42,22 @@ export async function createNode(
if (!res.ok) { if (!res.ok) {
const body = await res.text(); const body = await res.text();
throw new Error(`create_node failed (${res.status}): ${body}`); throw new Error(`${path} failed (${res.status}): ${body}`);
} }
return res.json(); return res.json();
} }
export function createNode(
accessToken: string,
data: CreateNodeRequest
): Promise<CreateNodeResponse> {
return post(accessToken, '/intentions/create_node', data);
}
export function createEdge(
accessToken: string,
data: CreateEdgeRequest
): Promise<CreateEdgeResponse> {
return post(accessToken, '/intentions/create_edge', data);
}

View file

@ -4,7 +4,7 @@
import { connectionState, nodeStore, edgeStore } from '$lib/spacetime'; import { connectionState, nodeStore, edgeStore } from '$lib/spacetime';
import type { Node } from '$lib/spacetime'; import type { Node } from '$lib/spacetime';
import NodeEditor from '$lib/components/NodeEditor.svelte'; import NodeEditor from '$lib/components/NodeEditor.svelte';
import { createNode } from '$lib/api'; import { createNode, createEdge } from '$lib/api';
const session = $derived($page.data.session as Record<string, unknown> | undefined); const session = $derived($page.data.session as Record<string, unknown> | undefined);
const nodeId = $derived(session?.nodeId as string | undefined); const nodeId = $derived(session?.nodeId as string | undefined);
@ -87,13 +87,20 @@
metadata.document = data.html; metadata.document = data.html;
} }
await createNode(accessToken, { const { node_id } = await createNode(accessToken, {
node_kind: 'content', node_kind: 'content',
title: data.title, title: data.title,
content: data.content, content: data.content,
visibility: 'hidden', visibility: 'hidden',
metadata metadata
}); });
// Create owner edge so the node appears in the user's mottak
await createEdge(accessToken, {
source_id: nodeId!,
target_id: node_id,
edge_type: 'owner'
});
} }
</script> </script>

View file

@ -64,8 +64,7 @@ Uavhengige faser kan fortsatt plukkes.
- [x] 3.2 Authentik login: OIDC-flow (authorization code + PKCE). Session-håndtering. Redirect til login ved 401. - [x] 3.2 Authentik login: OIDC-flow (authorization code + PKCE). Session-håndtering. Redirect til login ved 401.
- [x] 3.3 STDB WebSocket-klient: abonner på noder og edges. Reaktiv Svelte-store som oppdateres ved endringer. - [x] 3.3 STDB WebSocket-klient: abonner på noder og edges. Reaktiv Svelte-store som oppdateres ved endringer.
- [x] 3.4 Mottaksflaten v0: vis noder med edge til innlogget bruker, sortert på `created_at`. Enkel liste med tittel og utdrag. - [x] 3.4 Mottaksflaten v0: vis noder med edge til innlogget bruker, sortert på `created_at`. Enkel liste med tittel og utdrag.
- [~] 3.5 TipTap-editor: enkel preset (tekst, markdown, lenker). Send `create_node`-intensjon til maskinrommet ved submit. - [x] 3.5 TipTap-editor: enkel preset (tekst, markdown, lenker). Send `create_node`-intensjon til maskinrommet ved submit.
> Påbegynt: 2026-03-17T14:19
- [ ] 3.6 Sanntidstest: åpne to faner, skriv i én, se noden dukke opp i den andre via STDB. - [ ] 3.6 Sanntidstest: åpne to faner, skriv i én, se noden dukke opp i den andre via STDB.
## Fase 4: Tilgangskontroll ## Fase 4: Tilgangskontroll