feat: initial dataset review orchestration flow implementation
This commit is contained in:
112
frontend/src/lib/stores/__tests__/test_datasetReviewSession.js
Normal file
112
frontend/src/lib/stores/__tests__/test_datasetReviewSession.js
Normal 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]
|
||||
89
frontend/src/lib/stores/datasetReviewSession.js
Normal file
89
frontend/src/lib/stores/datasetReviewSession.js
Normal 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]
|
||||
Reference in New Issue
Block a user