feat(web): add knowledge entry editor page (KNOW-006)
This commit is contained in:
@@ -4,12 +4,14 @@
|
||||
*/
|
||||
|
||||
import type { KnowledgeEntryWithTags, KnowledgeTag } from "@mosaic/shared";
|
||||
import { EntryStatus } from "@mosaic/shared";
|
||||
import { apiGet, type ApiResponse } from "./client";
|
||||
import { EntryStatus, Visibility } from "@mosaic/shared";
|
||||
import { apiGet, apiPost, apiPatch, apiDelete, type ApiResponse } from "./client";
|
||||
|
||||
export interface EntryFilters {
|
||||
status?: EntryStatus;
|
||||
visibility?: Visibility;
|
||||
tag?: string;
|
||||
tags?: string[];
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
@@ -26,6 +28,24 @@ export interface EntriesResponse {
|
||||
};
|
||||
}
|
||||
|
||||
export interface CreateEntryData {
|
||||
title: string;
|
||||
content: string;
|
||||
summary?: string;
|
||||
status?: EntryStatus;
|
||||
visibility?: Visibility;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface UpdateEntryData {
|
||||
title?: string;
|
||||
content?: string;
|
||||
summary?: string;
|
||||
status?: EntryStatus;
|
||||
visibility?: Visibility;
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch knowledge entries with optional filters
|
||||
*/
|
||||
@@ -35,23 +55,71 @@ export async function fetchEntries(filters?: EntryFilters): Promise<EntriesRespo
|
||||
if (filters?.status) {
|
||||
params.append("status", filters.status);
|
||||
}
|
||||
if (filters?.visibility) {
|
||||
params.append("visibility", filters.visibility);
|
||||
}
|
||||
if (filters?.tag) {
|
||||
params.append("tag", filters.tag);
|
||||
}
|
||||
if (filters?.tags && filters.tags.length > 0) {
|
||||
filters.tags.forEach((tag) => params.append("tags", tag));
|
||||
}
|
||||
if (filters?.page) {
|
||||
params.append("page", filters.page.toString());
|
||||
}
|
||||
if (filters?.limit) {
|
||||
params.append("limit", filters.limit.toString());
|
||||
}
|
||||
if (filters?.search) {
|
||||
params.append("search", filters.search);
|
||||
}
|
||||
if (filters?.sortBy) {
|
||||
params.append("sortBy", filters.sortBy);
|
||||
}
|
||||
if (filters?.sortOrder) {
|
||||
params.append("sortOrder", filters.sortOrder);
|
||||
}
|
||||
|
||||
const queryString = params.toString();
|
||||
const endpoint = queryString ? `/api/knowledge/entries?${queryString}` : "/api/knowledge/entries";
|
||||
const endpoint = queryString
|
||||
? `/api/knowledge/entries?${queryString}`
|
||||
: "/api/knowledge/entries";
|
||||
|
||||
const response = await apiGet<EntriesResponse>(endpoint);
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a single knowledge entry by slug
|
||||
*/
|
||||
export async function fetchEntry(slug: string): Promise<KnowledgeEntryWithTags> {
|
||||
return apiGet<KnowledgeEntryWithTags>(`/api/knowledge/entries/${slug}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new knowledge entry
|
||||
*/
|
||||
export async function createEntry(data: CreateEntryData): Promise<KnowledgeEntryWithTags> {
|
||||
return apiPost<KnowledgeEntryWithTags>("/api/knowledge/entries", data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing knowledge entry
|
||||
*/
|
||||
export async function updateEntry(
|
||||
slug: string,
|
||||
data: UpdateEntryData
|
||||
): Promise<KnowledgeEntryWithTags> {
|
||||
return apiPatch<KnowledgeEntryWithTags>(`/api/knowledge/entries/${slug}`, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete (archive) a knowledge entry
|
||||
*/
|
||||
export async function deleteEntry(slug: string): Promise<void> {
|
||||
await apiDelete(`/api/knowledge/entries/${slug}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all knowledge tags
|
||||
*/
|
||||
@@ -73,14 +141,30 @@ export const mockEntries: KnowledgeEntryWithTags[] = [
|
||||
contentHtml: "<h1>Getting Started</h1><p>Welcome to Mosaic Stack...</p>",
|
||||
summary: "A comprehensive guide to getting started with the Mosaic Stack platform.",
|
||||
status: EntryStatus.PUBLISHED,
|
||||
visibility: "PUBLIC" as const,
|
||||
visibility: Visibility.PUBLIC,
|
||||
createdBy: "user-1",
|
||||
updatedBy: "user-1",
|
||||
createdAt: new Date("2026-01-20"),
|
||||
updatedAt: new Date("2026-01-28"),
|
||||
tags: [
|
||||
{ id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-2", workspaceId: "workspace-1", name: "Onboarding", slug: "onboarding", color: "#10B981", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-1",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Tutorial",
|
||||
slug: "tutorial",
|
||||
color: "#3B82F6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-2",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Onboarding",
|
||||
slug: "onboarding",
|
||||
color: "#10B981",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -92,14 +176,30 @@ export const mockEntries: KnowledgeEntryWithTags[] = [
|
||||
contentHtml: "<h1>Architecture</h1><p>The Mosaic Stack architecture...</p>",
|
||||
summary: "Overview of the system architecture and design patterns used in Mosaic Stack.",
|
||||
status: EntryStatus.PUBLISHED,
|
||||
visibility: "WORKSPACE" as const,
|
||||
visibility: Visibility.WORKSPACE,
|
||||
createdBy: "user-1",
|
||||
updatedBy: "user-1",
|
||||
createdAt: new Date("2026-01-15"),
|
||||
updatedAt: new Date("2026-01-27"),
|
||||
tags: [
|
||||
{ id: "tag-3", workspaceId: "workspace-1", name: "Architecture", slug: "architecture", color: "#8B5CF6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-3",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Architecture",
|
||||
slug: "architecture",
|
||||
color: "#8B5CF6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-4",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Technical",
|
||||
slug: "technical",
|
||||
color: "#F59E0B",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -111,14 +211,30 @@ export const mockEntries: KnowledgeEntryWithTags[] = [
|
||||
contentHtml: "<h1>API Docs</h1><p>Work in progress...</p>",
|
||||
summary: "Comprehensive API documentation for developers.",
|
||||
status: EntryStatus.DRAFT,
|
||||
visibility: "PRIVATE" as const,
|
||||
visibility: Visibility.PRIVATE,
|
||||
createdBy: "user-1",
|
||||
updatedBy: "user-1",
|
||||
createdAt: new Date("2026-01-29"),
|
||||
updatedAt: new Date("2026-01-29"),
|
||||
tags: [
|
||||
{ id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-5", workspaceId: "workspace-1", name: "API", slug: "api", color: "#EF4444", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-4",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Technical",
|
||||
slug: "technical",
|
||||
color: "#F59E0B",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-5",
|
||||
workspaceId: "workspace-1",
|
||||
name: "API",
|
||||
slug: "api",
|
||||
color: "#EF4444",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -130,14 +246,30 @@ export const mockEntries: KnowledgeEntryWithTags[] = [
|
||||
contentHtml: "<h1>Deployment</h1><p>How to deploy Mosaic Stack...</p>",
|
||||
summary: "Step-by-step guide for deploying Mosaic Stack to production.",
|
||||
status: EntryStatus.PUBLISHED,
|
||||
visibility: "WORKSPACE" as const,
|
||||
visibility: Visibility.WORKSPACE,
|
||||
createdBy: "user-1",
|
||||
updatedBy: "user-1",
|
||||
createdAt: new Date("2026-01-18"),
|
||||
updatedAt: new Date("2026-01-25"),
|
||||
tags: [
|
||||
{ id: "tag-6", workspaceId: "workspace-1", name: "DevOps", slug: "devops", color: "#14B8A6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-6",
|
||||
workspaceId: "workspace-1",
|
||||
name: "DevOps",
|
||||
slug: "devops",
|
||||
color: "#14B8A6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-1",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Tutorial",
|
||||
slug: "tutorial",
|
||||
color: "#3B82F6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -149,23 +281,87 @@ export const mockEntries: KnowledgeEntryWithTags[] = [
|
||||
contentHtml: "<h1>Meeting Notes</h1><p>Old archived notes...</p>",
|
||||
summary: "Meeting notes from Q4 2025 - archived for reference.",
|
||||
status: EntryStatus.ARCHIVED,
|
||||
visibility: "PRIVATE" as const,
|
||||
visibility: Visibility.PRIVATE,
|
||||
createdBy: "user-1",
|
||||
updatedBy: "user-1",
|
||||
createdAt: new Date("2025-12-15"),
|
||||
updatedAt: new Date("2026-01-05"),
|
||||
tags: [
|
||||
{ id: "tag-7", workspaceId: "workspace-1", name: "Meetings", slug: "meetings", color: "#6B7280", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-7",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Meetings",
|
||||
slug: "meetings",
|
||||
color: "#6B7280",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export const mockTags: KnowledgeTag[] = [
|
||||
{ id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-2", workspaceId: "workspace-1", name: "Onboarding", slug: "onboarding", color: "#10B981", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-3", workspaceId: "workspace-1", name: "Architecture", slug: "architecture", color: "#8B5CF6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-5", workspaceId: "workspace-1", name: "API", slug: "api", color: "#EF4444", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-6", workspaceId: "workspace-1", name: "DevOps", slug: "devops", color: "#14B8A6", createdAt: new Date(), updatedAt: new Date() },
|
||||
{ id: "tag-7", workspaceId: "workspace-1", name: "Meetings", slug: "meetings", color: "#6B7280", createdAt: new Date(), updatedAt: new Date() },
|
||||
{
|
||||
id: "tag-1",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Tutorial",
|
||||
slug: "tutorial",
|
||||
color: "#3B82F6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-2",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Onboarding",
|
||||
slug: "onboarding",
|
||||
color: "#10B981",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-3",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Architecture",
|
||||
slug: "architecture",
|
||||
color: "#8B5CF6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-4",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Technical",
|
||||
slug: "technical",
|
||||
color: "#F59E0B",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-5",
|
||||
workspaceId: "workspace-1",
|
||||
name: "API",
|
||||
slug: "api",
|
||||
color: "#EF4444",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-6",
|
||||
workspaceId: "workspace-1",
|
||||
name: "DevOps",
|
||||
slug: "devops",
|
||||
color: "#14B8A6",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
{
|
||||
id: "tag-7",
|
||||
workspaceId: "workspace-1",
|
||||
name: "Meetings",
|
||||
slug: "meetings",
|
||||
color: "#6B7280",
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user