feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
/**
|
|
|
|
|
* Generic undo stack with clone-on-push semantics.
|
|
|
|
|
*
|
|
|
|
|
* Stores deep clones of state snapshots. Popped snapshots are returned
|
|
|
|
|
* directly (no re-cloning) since they are already detached.
|
|
|
|
|
*/
|
|
|
|
|
export class UndoStack<S> {
|
|
|
|
|
private stack: S[] = [];
|
2026-05-10 12:41:47 +02:00
|
|
|
private redoStack: S[] = [];
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
|
2026-05-10 12:41:47 +02:00
|
|
|
/** Push a deep clone of the given state onto the undo stack. Clears redo history. */
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
push(state: S): void {
|
|
|
|
|
this.stack.push(structuredClone(state));
|
2026-05-10 12:41:47 +02:00
|
|
|
this.redoStack.length = 0;
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
2026-05-10 12:41:47 +02:00
|
|
|
/** Pop and return the most recent undo snapshot, or undefined if empty. */
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
pop(): S | undefined {
|
|
|
|
|
return this.stack.pop();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-10 12:41:47 +02:00
|
|
|
/**
|
|
|
|
|
* Push a deep clone of the given state onto the redo stack.
|
|
|
|
|
* Called by the editor before applying an undo so the state can be redone.
|
|
|
|
|
*/
|
|
|
|
|
pushRedo(state: S): void {
|
|
|
|
|
this.redoStack.push(structuredClone(state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Push a deep clone of the given state onto the undo stack without clearing
|
|
|
|
|
* the redo stack. Called by the editor before applying a redo so the state
|
|
|
|
|
* remains undoable.
|
|
|
|
|
*/
|
|
|
|
|
pushUndo(state: S): void {
|
|
|
|
|
this.stack.push(structuredClone(state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Pop and return the most recent redo snapshot, or undefined if empty. */
|
|
|
|
|
redo(): S | undefined {
|
|
|
|
|
return this.redoStack.pop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
canRedo(): boolean {
|
|
|
|
|
return this.redoStack.length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Remove all snapshots from both undo and redo stacks. */
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
clear(): void {
|
|
|
|
|
this.stack.length = 0;
|
2026-05-10 12:41:47 +02:00
|
|
|
this.redoStack.length = 0;
|
feat(web): add error boundaries, expand test coverage, add README
- Add class-based ErrorBoundary component wrapping all 7 main views
inside WorkspaceChrome; fallback shows view name, error, reload button
- Add 30 new unit tests (boot null-project path × 9, onboarding
pure-function logic × 21); all 43 web/lib tests pass
- Add web/README.md: architecture, auth flow, 7 views, dev setup,
API route pattern, test instructions
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-10 11:24:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
get length(): number {
|
|
|
|
|
return this.stack.length;
|
|
|
|
|
}
|
|
|
|
|
}
|