Brukeren kan nå dra eller lime inn bilder i TipTap-editoren. Bildet lastes opp til CAS via upload_media-endepunktet, og settes inn som <img> med CAS-URL i metadata.document (HTML). Endringer: - Ny uploadMedia() og casUrl() i api.ts for multipart upload - @tiptap/extension-image med CasImage-utvidelse (data-node-id attr) - handleDrop/handlePaste i editor intercepter bildefiler - Upload-status vises i editoren mens bilder lastes opp - accessToken sendes ned til NodeEditor fra +page.svelte Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
130 lines
3.1 KiB
TypeScript
130 lines
3.1 KiB
TypeScript
/**
|
|
* Client for maskinrommet intentions API.
|
|
* Uses the Vite dev proxy (/api → api.sidelinja.org) in development.
|
|
* In production, set VITE_API_URL to the maskinrommet URL.
|
|
*/
|
|
|
|
const BASE_URL = import.meta.env.VITE_API_URL ?? '/api';
|
|
|
|
export interface CreateNodeRequest {
|
|
node_kind?: string;
|
|
title?: string;
|
|
content?: string;
|
|
visibility?: string;
|
|
metadata?: Record<string, unknown>;
|
|
/** Kontekst-node (kommunikasjonsnode). Gir automatisk belongs_to-edge. */
|
|
context_id?: string;
|
|
}
|
|
|
|
export interface CreateNodeResponse {
|
|
node_id: string;
|
|
/** Edge-ID for automatisk belongs_to-edge (kun ved context_id). */
|
|
belongs_to_edge_id?: string;
|
|
}
|
|
|
|
export interface CreateEdgeRequest {
|
|
source_id: string;
|
|
target_id: string;
|
|
edge_type: string;
|
|
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',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
Authorization: `Bearer ${accessToken}`
|
|
},
|
|
body: JSON.stringify(data)
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const body = await res.text();
|
|
throw new Error(`${path} failed (${res.status}): ${body}`);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
export interface CreateCommunicationRequest {
|
|
title?: string;
|
|
participants?: string[];
|
|
visibility?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
export interface CreateCommunicationResponse {
|
|
node_id: string;
|
|
edge_ids: string[];
|
|
}
|
|
|
|
export function createCommunication(
|
|
accessToken: string,
|
|
data: CreateCommunicationRequest
|
|
): Promise<CreateCommunicationResponse> {
|
|
return post(accessToken, '/intentions/create_communication', data);
|
|
}
|
|
|
|
export interface UploadMediaRequest {
|
|
file: File;
|
|
source_id?: string;
|
|
visibility?: string;
|
|
title?: string;
|
|
}
|
|
|
|
export interface UploadMediaResponse {
|
|
media_node_id: string;
|
|
cas_hash: string;
|
|
size_bytes: number;
|
|
already_existed: boolean;
|
|
has_media_edge_id?: string;
|
|
}
|
|
|
|
export async function uploadMedia(
|
|
accessToken: string,
|
|
data: UploadMediaRequest
|
|
): Promise<UploadMediaResponse> {
|
|
const form = new FormData();
|
|
form.append('file', data.file);
|
|
if (data.source_id) form.append('source_id', data.source_id);
|
|
if (data.visibility) form.append('visibility', data.visibility);
|
|
if (data.title) form.append('title', data.title);
|
|
|
|
const res = await fetch(`${BASE_URL}/intentions/upload_media`, {
|
|
method: 'POST',
|
|
headers: { Authorization: `Bearer ${accessToken}` },
|
|
body: form
|
|
});
|
|
|
|
if (!res.ok) {
|
|
const body = await res.text();
|
|
throw new Error(`upload_media failed (${res.status}): ${body}`);
|
|
}
|
|
|
|
return res.json();
|
|
}
|
|
|
|
/** Build the CAS URL for a given hash. */
|
|
export function casUrl(hash: string): string {
|
|
return `${BASE_URL}/cas/${hash}`;
|
|
}
|