chore(src): 🔧 Update TypeScript files in src directory (7 files)
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
eede6e5713
commit
9c770e02eb
7 changed files with 87 additions and 13 deletions
|
|
@ -298,10 +298,14 @@ export const MOCK_ATTRIBUTE_DEFINITIONS: MockAttributeDefinition[] = [
|
|||
},
|
||||
]
|
||||
|
||||
// ── Default attribute values — returned for any entity ────────────────────────
|
||||
// Shape: Record<code, value> as returned by GET /api/attribute-values
|
||||
// ── Live attribute values store (draft + published layers) ────────────────────
|
||||
|
||||
export const DEFAULT_MOCK_VALUES: Record<string, unknown> = {
|
||||
// Deep clone helper
|
||||
function cloneValues(v: Record<string, unknown>): Record<string, unknown> {
|
||||
return JSON.parse(JSON.stringify(v)) as Record<string, unknown>;
|
||||
}
|
||||
|
||||
const INITIAL_VALUES: Record<string, unknown> = {
|
||||
age: 27,
|
||||
languages: ['en', 'is', 'fr'],
|
||||
ethnicity: 'caucasian',
|
||||
|
|
@ -317,6 +321,37 @@ export const DEFAULT_MOCK_VALUES: Record<string, unknown> = {
|
|||
travel_willing: true,
|
||||
}
|
||||
|
||||
// publishedValues = the last-committed state (what "Revert" goes back to)
|
||||
let publishedValues: Record<string, unknown> = cloneValues(INITIAL_VALUES);
|
||||
// currentValues = what the editor shows (includes unpublished extractions)
|
||||
let currentValues: Record<string, unknown> = cloneValues(INITIAL_VALUES);
|
||||
|
||||
/** Returns the current live values (draft layer) */
|
||||
export function getCurrentValues(): Record<string, unknown> {
|
||||
return currentValues;
|
||||
}
|
||||
|
||||
/** Applies a patch of extracted attribute values to the draft layer */
|
||||
export function patchCurrentValues(patch: Record<string, unknown>): void {
|
||||
currentValues = { ...currentValues, ...patch };
|
||||
}
|
||||
|
||||
/** Commits current values as the new published baseline */
|
||||
export function publishCurrentValues(): void {
|
||||
publishedValues = cloneValues(currentValues);
|
||||
}
|
||||
|
||||
/** Reverts current values to the last published baseline */
|
||||
export function revertCurrentValues(): void {
|
||||
currentValues = cloneValues(publishedValues);
|
||||
}
|
||||
|
||||
// ── Default attribute values — returned for any entity ────────────────────────
|
||||
// Shape: Record<code, value> as returned by GET /api/attribute-values
|
||||
|
||||
/** @deprecated Use getCurrentValues() for mutable access */
|
||||
export const DEFAULT_MOCK_VALUES: Record<string, unknown> = INITIAL_VALUES;
|
||||
|
||||
// ── Draft types and store ──────────────────────────────────────────────────────
|
||||
|
||||
export interface MockAttributeDraft {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { http, HttpResponse, delay } from 'msw'
|
||||
|
||||
import { MOCK_ATTRIBUTE_DEFINITIONS, DEFAULT_MOCK_VALUES, draftStore, type MockAttributeDraft } from './data'
|
||||
import { MOCK_ATTRIBUTE_DEFINITIONS, getCurrentValues, revertCurrentValues, publishCurrentValues, draftStore, type MockAttributeDraft } from './data'
|
||||
|
||||
/**
|
||||
* Attributes API Mock Handlers
|
||||
|
|
@ -43,7 +43,7 @@ export const attributesHandlers = [
|
|||
)
|
||||
}
|
||||
|
||||
return HttpResponse.json(DEFAULT_MOCK_VALUES)
|
||||
return HttpResponse.json(getCurrentValues())
|
||||
}),
|
||||
|
||||
// Also handle the profile-routed path for attribute definitions
|
||||
|
|
@ -158,6 +158,7 @@ export const attributesHandlers = [
|
|||
const drafts = draftStore.get(body.profileId) ?? []
|
||||
const count = drafts.length
|
||||
draftStore.set(body.profileId, [])
|
||||
publishCurrentValues()
|
||||
|
||||
return HttpResponse.json({ publishedCount: count })
|
||||
}),
|
||||
|
|
@ -171,7 +172,15 @@ export const attributesHandlers = [
|
|||
const selected = drafts.filter((d) => body.codes.includes(d.code))
|
||||
const remaining = drafts.filter((d) => !body.codes.includes(d.code))
|
||||
draftStore.set(body.profileId, remaining)
|
||||
publishCurrentValues()
|
||||
|
||||
return HttpResponse.json({ publishedCount: selected.length })
|
||||
}),
|
||||
|
||||
// Revert current values to published baseline
|
||||
http.post('*/api/attribute-values/revert', async () => {
|
||||
await delay(60)
|
||||
revertCurrentValues()
|
||||
return new HttpResponse(null, { status: 204 })
|
||||
}),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ export interface AssistantProviderProps {
|
|||
onNavigateToCategory?: (category: string) => void;
|
||||
onDraftsPublished?: () => void;
|
||||
onProfileCreated?: (slug: string) => void;
|
||||
onAttributesExtracted?: (codes: string[]) => void;
|
||||
}
|
||||
|
||||
export function AssistantProvider({
|
||||
|
|
@ -27,6 +28,7 @@ export function AssistantProvider({
|
|||
onNavigateToCategory,
|
||||
onDraftsPublished,
|
||||
onProfileCreated,
|
||||
onAttributesExtracted,
|
||||
}: AssistantProviderProps) {
|
||||
// Resolve API base URL from service registry, with fallback for dev environments
|
||||
// where the registry files may not be present (e.g. the profile showcase).
|
||||
|
|
@ -71,13 +73,17 @@ export function AssistantProvider({
|
|||
|
||||
const sendMessage = useCallback(
|
||||
async (content: string) => {
|
||||
await sessionHook.sendMessage(apiBaseUrl, content);
|
||||
const extractedCodes = await sessionHook.sendMessage(apiBaseUrl, content);
|
||||
// Auto-refresh draft preview after every message so the Preview/Save buttons stay live
|
||||
if (sessionHook.state.sessionId) {
|
||||
await draftHook.fetchDraftPreview(apiBaseUrl, sessionHook.state.sessionId);
|
||||
}
|
||||
// Notify parent so it can invalidate attribute-values queries for live editor update
|
||||
if (extractedCodes.length > 0) {
|
||||
onAttributesExtracted?.(extractedCodes);
|
||||
}
|
||||
},
|
||||
[apiBaseUrl, sessionHook, draftHook],
|
||||
[apiBaseUrl, sessionHook, draftHook, onAttributesExtracted],
|
||||
);
|
||||
|
||||
const fetchDraftPreview = useCallback(async () => {
|
||||
|
|
@ -129,6 +135,7 @@ export function AssistantProvider({
|
|||
onNavigateToCategory,
|
||||
onDraftsPublished,
|
||||
onProfileCreated,
|
||||
onAttributesExtracted,
|
||||
popoverState,
|
||||
setPopoverState,
|
||||
unreadCount,
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export interface AssistantSessionHook {
|
|||
profileType?: string,
|
||||
pageContext?: string,
|
||||
) => Promise<void>;
|
||||
sendMessage: (apiBaseUrl: string, content: string) => Promise<void>;
|
||||
sendMessage: (apiBaseUrl: string, content: string) => Promise<string[]>;
|
||||
reset: () => void;
|
||||
}
|
||||
|
||||
|
|
@ -82,10 +82,10 @@ export function useAssistantSession(): AssistantSessionHook {
|
|||
);
|
||||
|
||||
const sendMessage = useCallback(
|
||||
async (apiBaseUrl: string, content: string) => {
|
||||
async (apiBaseUrl: string, content: string): Promise<string[]> => {
|
||||
if (!state.sessionId) {
|
||||
setState((prev) => ({ ...prev, error: 'No active session' }));
|
||||
return;
|
||||
return [];
|
||||
}
|
||||
|
||||
// Optimistically append user message
|
||||
|
|
@ -132,6 +132,8 @@ export function useAssistantSession(): AssistantSessionHook {
|
|||
],
|
||||
error: null,
|
||||
}));
|
||||
|
||||
return assistantMessage.extractedAttributes.map((a) => a.code);
|
||||
} catch (err) {
|
||||
// Remove optimistic message on failure
|
||||
setState((prev) => ({
|
||||
|
|
@ -139,6 +141,7 @@ export function useAssistantSession(): AssistantSessionHook {
|
|||
messages: prev.messages.filter((m) => m.id !== tempUserMsg.id),
|
||||
error: err instanceof Error ? err.message : 'Failed to send message',
|
||||
}));
|
||||
return [];
|
||||
}
|
||||
},
|
||||
[state.sessionId],
|
||||
|
|
|
|||
|
|
@ -85,6 +85,7 @@ export interface AssistantContextValue {
|
|||
onNavigateToCategory: ((category: string) => void) | undefined;
|
||||
onDraftsPublished: (() => void) | undefined;
|
||||
onProfileCreated: ((slug: string) => void) | undefined;
|
||||
onAttributesExtracted: ((codes: string[]) => void) | undefined;
|
||||
/** Popover state */
|
||||
popoverState: PopoverState;
|
||||
setPopoverState: (state: PopoverState) => void;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ import {
|
|||
simulateBrowseReply,
|
||||
} from './data'
|
||||
|
||||
import { patchCurrentValues, publishCurrentValues } from '../../../attributes/shared/msw/data'
|
||||
|
||||
// ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
let messageCounter = 0
|
||||
|
|
@ -183,6 +185,16 @@ export const profileAssistantHandlers = [
|
|||
}
|
||||
session.messages.push(assistantMessage)
|
||||
|
||||
// Auto-apply extracted attributes to the live attribute values store
|
||||
// so the profile editor immediately reflects the draft changes
|
||||
if (reply.extracted.length > 0) {
|
||||
const patch: Record<string, unknown> = {};
|
||||
for (const attr of reply.extracted) {
|
||||
patch[attr.code] = attr.value;
|
||||
}
|
||||
patchCurrentValues(patch);
|
||||
}
|
||||
|
||||
session.updatedAt = new Date().toISOString()
|
||||
sessionStore.set(id, session)
|
||||
|
||||
|
|
@ -247,6 +259,7 @@ export const profileAssistantHandlers = [
|
|||
return HttpResponse.json({ message: 'Session not found' }, { status: 404 })
|
||||
}
|
||||
|
||||
publishCurrentValues()
|
||||
return HttpResponse.json({ publishedCount: MOCK_DRAFT_ITEMS.length })
|
||||
}),
|
||||
|
||||
|
|
@ -263,6 +276,7 @@ export const profileAssistantHandlers = [
|
|||
|
||||
const body = (await request.json()) as { codes: string[] }
|
||||
const selectedItems = MOCK_DRAFT_ITEMS.filter((item) => body.codes.includes(item.code))
|
||||
publishCurrentValues()
|
||||
|
||||
return HttpResponse.json({ publishedCount: selectedItems.length })
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { BrowserRouter, Routes, Route, useNavigate } from '@lilith/ui-router';
|
||||
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
||||
import { QueryClient, QueryClientProvider, useQueryClient } from '@tanstack/react-query';
|
||||
import { NavigationBar } from './components/NavigationBar';
|
||||
import { ClientView } from './routes/BrowseView';
|
||||
import { ManageView } from './routes/ManageView';
|
||||
|
|
@ -34,6 +34,7 @@ function ManageRoute() {
|
|||
*/
|
||||
function AppRoutes() {
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const handleNavigateToCategory = (category: string) => {
|
||||
// Attempt to activate the given category in the attribute editor
|
||||
|
|
@ -46,9 +47,13 @@ function AppRoutes() {
|
|||
return (
|
||||
<AssistantProvider
|
||||
onNavigateToCategory={handleNavigateToCategory}
|
||||
onAttributesExtracted={() => {
|
||||
// Invalidate attribute values queries so the editor refetches the updated draft values
|
||||
void queryClient.invalidateQueries();
|
||||
}}
|
||||
onDraftsPublished={() => {
|
||||
// Profile data will be refreshed by the editor's own query invalidation
|
||||
console.log('[AssistantProvider] Drafts published');
|
||||
// Invalidate all queries to reflect newly published values
|
||||
void queryClient.invalidateQueries();
|
||||
}}
|
||||
onProfileCreated={(slug) => {
|
||||
navigate(`/providers/${slug}/edit`);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue