feat: initial dataset review orchestration flow implementation

This commit is contained in:
2026-03-16 23:43:03 +03:00
parent 9cae07a3b4
commit f4416c3ebb
9 changed files with 1565 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
// [DEF:frontend.src.lib.stores.__tests__.test_datasetReviewSession:Module]
// @COMPLEXITY: 3
// @SEMANTICS: dataset-review, store, session, tests
// @PURPOSE: Unit tests for dataset review session store
// @LAYER: UI
// @RELATION: VERIFIES -> [datasetReviewSession:Store]
import { describe, it, expect, beforeEach, vi } from 'vitest';
describe('datasetReviewSession store', () => {
beforeEach(async () => {
vi.resetModules();
});
it('should have correct initial state', async () => {
const { datasetReviewSessionStore } = await import('../datasetReviewSession.js');
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.session).toBeNull();
expect(state.isLoading).toBe(false);
expect(state.isSaving).toBe(false);
expect(state.error).toBeNull();
expect(state.isDirty).toBe(false);
});
it('should set session data', async () => {
const { datasetReviewSessionStore, setSession } = await import('../datasetReviewSession.js');
const mockSession = { session_id: 's1', user_id: 'u1' };
setSession(mockSession);
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.session).toEqual(mockSession);
expect(state.isLoading).toBe(false);
expect(state.error).toBeNull();
expect(state.lastUpdated).toBeInstanceOf(Date);
expect(state.isDirty).toBe(false);
});
it('should update loading state', async () => {
const { datasetReviewSessionStore, setLoading } = await import('../datasetReviewSession.js');
setLoading(true);
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.isLoading).toBe(true);
});
it('should set error state', async () => {
const { datasetReviewSessionStore, setError } = await import('../datasetReviewSession.js');
setError('Failed to load');
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.error).toBe('Failed to load');
expect(state.isLoading).toBe(false);
});
it('should mark as dirty', async () => {
const { datasetReviewSessionStore, setDirty } = await import('../datasetReviewSession.js');
setDirty(true);
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.isDirty).toBe(true);
});
it('should patch session data and mark as dirty', async () => {
const { datasetReviewSessionStore, setSession, patchSession } = await import('../datasetReviewSession.js');
const mockSession = { session_id: 's1', readiness_state: 'empty' };
setSession(mockSession);
patchSession({ readiness_state: 'ready' });
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.session.readiness_state).toBe('ready');
expect(state.isDirty).toBe(true);
});
it('should reset session', async () => {
const { datasetReviewSessionStore, setSession, resetSession } = await import('../datasetReviewSession.js');
setSession({ id: 's1' });
resetSession();
let state = null;
const unsubscribe = datasetReviewSessionStore.subscribe(s => { state = s; });
unsubscribe();
expect(state.session).toBeNull();
});
});
// [/DEF:frontend.src.lib.stores.__tests__.test_datasetReviewSession:Module]

View File

@@ -0,0 +1,89 @@
// [DEF:datasetReviewSession:Store]
// @COMPLEXITY: 4
// @PURPOSE: Manage active dataset review session state, including loading, updates, and navigation guards.
// @LAYER: UI
// @RELATION: DEPENDS_ON -> api_module (requestApi/fetchApi)
//
// @UX_STATE: Loading -> Session detail is being fetched.
// @UX_STATE: Ready -> Session detail is available for UI binding.
// @UX_STATE: Saving -> Updates are being persisted.
// @UX_STATE: Error -> Failed to load or update session.
// @UX_REACTIVITY: Uses Svelte writable store for session aggregate.
import { writable } from 'svelte/store';
// [SECTION: INITIAL STATE]
const initialState = {
session: null,
isLoading: false,
isSaving: false,
error: null,
lastUpdated: null,
isDirty: false
};
// [/SECTION]
export const datasetReviewSessionStore = writable(initialState);
/**
* Set active session data
* @param {Object} session - Full SessionDetail aggregate
*/
export function setSession(session) {
datasetReviewSessionStore.update(state => ({
...state,
session,
isLoading: false,
error: null,
lastUpdated: new Date(),
isDirty: false
}));
}
/**
* Update session loading state
* @param {boolean} isLoading
*/
export function setLoading(isLoading) {
datasetReviewSessionStore.update(state => ({ ...state, isLoading }));
}
/**
* Set session error state
* @param {string|null} error
*/
export function setError(error) {
datasetReviewSessionStore.update(state => ({ ...state, error, isLoading: false, isSaving: false }));
}
/**
* Mark session as dirty (unsaved changes)
* @param {boolean} isDirty
*/
export function setDirty(isDirty) {
datasetReviewSessionStore.update(state => ({ ...state, isDirty }));
}
/**
* Reset store to initial state
*/
export function resetSession() {
datasetReviewSessionStore.set(initialState);
}
/**
* Patch session data locally
* @param {Object} patch - Partial session data
*/
export function patchSession(patch) {
datasetReviewSessionStore.update(state => {
if (!state.session) return state;
return {
...state,
session: { ...state.session, ...patch },
isDirty: true
};
});
}
// [/DEF:datasetReviewSession:Store]