Skip to content

Commit 492e186

Browse files
committed
Add core timeline domain models and timeline store
1 parent 9ba9b47 commit 492e186

4 files changed

Lines changed: 1415 additions & 0 deletions

File tree

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
/**
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import {
18+
TimelineStore,
19+
TimelineDTO,
20+
RevisionDTO,
21+
EventDTO,
22+
} from 'src/app/store/domain/timeline-store';
23+
import { InternPoolStore } from 'src/app/store/domain/intern-pool-store';
24+
import { StyleStore } from 'src/app/store/domain/style-store';
25+
import { LogStore } from 'src/app/store/domain/log-store';
26+
27+
describe('TimelineStore', () => {
28+
let internPool: InternPoolStore;
29+
let styleStore: StyleStore;
30+
let logStore: LogStore;
31+
let store: TimelineStore;
32+
33+
const mockColor = { r: 0, g: 0, b: 0, a: 1 };
34+
35+
beforeEach(() => {
36+
internPool = new InternPoolStore();
37+
styleStore = new StyleStore();
38+
logStore = new LogStore(internPool, styleStore);
39+
store = new TimelineStore(internPool, styleStore, logStore);
40+
41+
styleStore.addTimelineTypes([
42+
{
43+
id: 1,
44+
label: 'type-a',
45+
description: 'desc',
46+
backgroundColor: mockColor,
47+
foregroundColor: mockColor,
48+
visible: true,
49+
sortPriority: 0,
50+
},
51+
]);
52+
53+
styleStore.addSeverities([
54+
{
55+
id: 1,
56+
label: 'S1',
57+
shortLabel: 'S1',
58+
backgroundColor: mockColor,
59+
foregroundColor: mockColor,
60+
order: 0,
61+
},
62+
]);
63+
64+
styleStore.addLogTypes([
65+
{
66+
id: 1,
67+
label: 'L1',
68+
description: '',
69+
backgroundColor: mockColor,
70+
foregroundColor: mockColor,
71+
},
72+
]);
73+
74+
styleStore.addVerbs([
75+
{
76+
id: 1,
77+
label: 'V1',
78+
backgroundColor: mockColor,
79+
foregroundColor: mockColor,
80+
visible: true,
81+
},
82+
]);
83+
84+
styleStore.addRevisionStates([
85+
{
86+
id: 1,
87+
label: 'normal',
88+
icon: '',
89+
description: '',
90+
backgroundColor: mockColor,
91+
style: 0,
92+
},
93+
]);
94+
});
95+
96+
it('should successfully populate internal states on initialize', () => {
97+
internPool.addStrings([
98+
{ id: 1, value: 'timeline-x' },
99+
{ id: 2, value: 'principal-y' },
100+
]);
101+
102+
const rawTimelines: TimelineDTO[] = [
103+
{
104+
id: 10,
105+
timelineTypeId: 1,
106+
nameStringId: 1,
107+
parentTimelineId: 0,
108+
revisionIds: [100],
109+
eventIds: [200],
110+
},
111+
];
112+
113+
const rawRevisions: RevisionDTO[] = [
114+
{
115+
id: 100,
116+
logId: 1,
117+
changedTime: 123456n,
118+
principalStringId: 2,
119+
verbTypeId: 1,
120+
stateTypeId: 1,
121+
},
122+
];
123+
124+
const rawEvents: EventDTO[] = [
125+
{
126+
id: 200,
127+
logId: 1,
128+
},
129+
];
130+
131+
expect(() =>
132+
store.initialize(rawTimelines, 1, rawRevisions, 1, rawEvents, 1),
133+
).not.toThrow();
134+
135+
const t = store.getTimeline(10);
136+
expect(t.id).toBe(10);
137+
expect(t.name).toBe('timeline-x');
138+
139+
const all = store.getAllTimelines();
140+
expect(all.length).toBe(1);
141+
expect(all[0].id).toBe(10);
142+
});
143+
144+
it('should correctly decode timeline traversal path', () => {
145+
internPool.addStrings([
146+
{ id: 1, value: 'root' },
147+
{ id: 2, value: 'child' },
148+
]);
149+
150+
const rawTimelines: TimelineDTO[] = [
151+
{
152+
id: 1,
153+
timelineTypeId: 1,
154+
nameStringId: 1,
155+
parentTimelineId: 0,
156+
revisionIds: [],
157+
eventIds: [],
158+
},
159+
{
160+
id: 2,
161+
timelineTypeId: 1,
162+
nameStringId: 2,
163+
parentTimelineId: 1,
164+
revisionIds: [],
165+
eventIds: [],
166+
},
167+
];
168+
169+
store.initialize(rawTimelines, 2, [], 0, [], 0);
170+
171+
const timeline = store.getTimeline(2);
172+
const computedPath = timeline.path;
173+
174+
expect(computedPath.length).toBe(2);
175+
expect(computedPath[0].label).toBe('root');
176+
expect(computedPath[1].label).toBe('child');
177+
});
178+
179+
it('should error when reading invalid timeline ID', () => {
180+
expect(() => store.getTimeline(999)).toThrowError(
181+
'Timeline ID 999 not found',
182+
);
183+
});
184+
});

0 commit comments

Comments
 (0)