@critical-path/svelte 0.18.0 → 0.18.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +10 -6
- package/CHANGELOG.md +0 -730
- package/dist/cancellation.test.d.ts +0 -2
- package/dist/cancellation.test.d.ts.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/src/activity-state.svelte.ts +0 -203
- package/src/attachment-state.svelte.ts +0 -71
- package/src/cancellation.test.ts +0 -43
- package/src/comment-state.svelte.ts +0 -140
- package/src/critical-path-state.svelte.ts +0 -43
- package/src/deliverable-state.svelte.ts +0 -87
- package/src/deliverable-summary-state.svelte.ts +0 -51
- package/src/index.test.ts +0 -885
- package/src/index.ts +0 -23
- package/src/kanban-state.svelte.ts +0 -113
- package/src/latest-request.ts +0 -24
- package/src/project-state.svelte.ts +0 -64
- package/src/task-metrics-state.svelte.ts +0 -103
- package/src/task-state.svelte.ts +0 -205
- package/src/task-transitions-state.svelte.ts +0 -46
- package/src/timeline-ladder-state.svelte.ts +0 -68
- package/src/webmcp-state.svelte.ts +0 -78
- package/src/workflow-state.svelte.ts +0 -72
- package/src/workload-state.svelte.ts +0 -93
- package/tsconfig.json +0 -8
- package/vite.config.ts +0 -22
- package/vitest.config.ts +0 -6
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cancellation.test.d.ts","sourceRoot":"","sources":["../src/cancellation.test.ts"],"names":[],"mappings":""}
|
package/dist/index.test.d.ts
DELETED
package/dist/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { CreateAttachmentBody, CreateCommentBody } from '@critical-path/core/schemas';
|
|
3
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
|
-
import type { Comment, Attachment } from '@critical-path/core';
|
|
5
|
-
import { LatestRequest } from './latest-request.js';
|
|
6
|
-
|
|
7
|
-
export interface ThreadedCommentWithAttachments extends Comment {
|
|
8
|
-
attachments: Attachment[];
|
|
9
|
-
replies: ThreadedCommentWithAttachments[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class TaskActivityState {
|
|
13
|
-
#fetchRequest = new LatestRequest();
|
|
14
|
-
comments = $state<Comment[]>([]);
|
|
15
|
-
attachments = $state<Attachment[]>([]);
|
|
16
|
-
loading = $state<boolean>(false);
|
|
17
|
-
error = $state<Error | null>(null);
|
|
18
|
-
|
|
19
|
-
threads = $derived.by(() => {
|
|
20
|
-
const map = new Map<string, ThreadedCommentWithAttachments>();
|
|
21
|
-
const roots: ThreadedCommentWithAttachments[] = [];
|
|
22
|
-
|
|
23
|
-
// Group attachments by commentId
|
|
24
|
-
const attachmentsByComment = new Map<string, Attachment[]>();
|
|
25
|
-
for (const a of this.attachments) {
|
|
26
|
-
if (a.commentId) {
|
|
27
|
-
if (!attachmentsByComment.has(a.commentId)) {
|
|
28
|
-
attachmentsByComment.set(a.commentId, []);
|
|
29
|
-
}
|
|
30
|
-
attachmentsByComment.get(a.commentId)!.push(a);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
for (const c of this.comments) {
|
|
35
|
-
map.set(c.id, {
|
|
36
|
-
...c,
|
|
37
|
-
attachments: attachmentsByComment.get(c.id) || [],
|
|
38
|
-
replies: []
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
for (const c of this.comments) {
|
|
43
|
-
const threaded = map.get(c.id)!;
|
|
44
|
-
if (c.parentId && map.has(c.parentId)) {
|
|
45
|
-
map.get(c.parentId)!.replies.push(threaded);
|
|
46
|
-
} else {
|
|
47
|
-
roots.push(threaded);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
return roots;
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
standaloneAttachments = $derived.by(() => {
|
|
55
|
-
return this.attachments.filter((a) => !a.commentId);
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
constructor(private client: CriticalPathClient, public taskId?: string) {}
|
|
59
|
-
|
|
60
|
-
async fetch(taskId?: string) {
|
|
61
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
62
|
-
const targetTaskId = taskId || this.taskId;
|
|
63
|
-
if (!targetTaskId) {
|
|
64
|
-
this.comments = [];
|
|
65
|
-
this.attachments = [];
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
this.taskId = targetTaskId;
|
|
69
|
-
this.loading = true;
|
|
70
|
-
this.error = null;
|
|
71
|
-
try {
|
|
72
|
-
const [comments, attachments] = await Promise.all([
|
|
73
|
-
api.getComments(targetTaskId),
|
|
74
|
-
api.getAttachments({ taskId: targetTaskId })
|
|
75
|
-
]);
|
|
76
|
-
if (signal.aborted) return;
|
|
77
|
-
this.comments = comments;
|
|
78
|
-
this.attachments = attachments;
|
|
79
|
-
} catch (err) {
|
|
80
|
-
if (signal.aborted) return;
|
|
81
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
82
|
-
} finally {
|
|
83
|
-
if (!signal.aborted) this.loading = false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async addComment(
|
|
88
|
-
input: Omit<CreateCommentBody, 'taskId'>,
|
|
89
|
-
attachmentInputs?: Array<Omit<CreateAttachmentBody, 'taskId' | 'commentId'>>
|
|
90
|
-
) {
|
|
91
|
-
if (!this.taskId) {
|
|
92
|
-
throw new Error('TaskActivityState requires a taskId to add comments.');
|
|
93
|
-
}
|
|
94
|
-
try {
|
|
95
|
-
const comment = await this.client.addComment({ ...input, taskId: this.taskId });
|
|
96
|
-
let createdAttachments: Attachment[] = [];
|
|
97
|
-
|
|
98
|
-
if (attachmentInputs && attachmentInputs.length > 0) {
|
|
99
|
-
createdAttachments = await Promise.all(
|
|
100
|
-
attachmentInputs.map((att) =>
|
|
101
|
-
this.client.createAttachment({
|
|
102
|
-
...att,
|
|
103
|
-
taskId: this.taskId,
|
|
104
|
-
commentId: comment.id
|
|
105
|
-
})
|
|
106
|
-
)
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
this.comments = [...this.comments, comment];
|
|
111
|
-
if (createdAttachments.length > 0) {
|
|
112
|
-
this.attachments = [...this.attachments, ...createdAttachments];
|
|
113
|
-
}
|
|
114
|
-
return { comment, attachments: createdAttachments };
|
|
115
|
-
} catch (err) {
|
|
116
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
117
|
-
this.error = errorObj;
|
|
118
|
-
throw errorObj;
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
async addAttachment(input: Omit<Attachment, 'id' | 'taskId' | 'createdAt' | 'updatedAt'>) {
|
|
123
|
-
if (!this.taskId) {
|
|
124
|
-
throw new Error('TaskActivityState requires a taskId to add attachments.');
|
|
125
|
-
}
|
|
126
|
-
try {
|
|
127
|
-
const created = await this.client.createAttachment({ ...input, taskId: this.taskId });
|
|
128
|
-
this.attachments = [created, ...this.attachments];
|
|
129
|
-
return created;
|
|
130
|
-
} catch (err) {
|
|
131
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
132
|
-
this.error = errorObj;
|
|
133
|
-
throw errorObj;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
async deleteComment(id: string) {
|
|
138
|
-
const previous = this.comments;
|
|
139
|
-
this.comments = this.comments.filter((c) => c.id !== id);
|
|
140
|
-
try {
|
|
141
|
-
await this.client.deleteComment(id);
|
|
142
|
-
} catch (err) {
|
|
143
|
-
this.comments = previous;
|
|
144
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
145
|
-
this.error = errorObj;
|
|
146
|
-
throw errorObj;
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
async deleteAttachment(id: string) {
|
|
151
|
-
const previous = this.attachments;
|
|
152
|
-
this.attachments = this.attachments.filter((a) => a.id !== id);
|
|
153
|
-
try {
|
|
154
|
-
await this.client.deleteAttachment(id);
|
|
155
|
-
} catch (err) {
|
|
156
|
-
this.attachments = previous;
|
|
157
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
158
|
-
this.error = errorObj;
|
|
159
|
-
throw errorObj;
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
async addReaction(
|
|
164
|
-
commentId: string,
|
|
165
|
-
emoji: string
|
|
166
|
-
) {
|
|
167
|
-
try {
|
|
168
|
-
const payload = { emoji };
|
|
169
|
-
const updated = await this.client.addCommentReaction(commentId, payload);
|
|
170
|
-
this.comments = this.comments.map((c) => (c.id === commentId ? updated : c));
|
|
171
|
-
return updated;
|
|
172
|
-
} catch (err) {
|
|
173
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
174
|
-
this.error = errorObj;
|
|
175
|
-
throw errorObj;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
async removeReaction(
|
|
180
|
-
commentId: string,
|
|
181
|
-
emoji: string
|
|
182
|
-
) {
|
|
183
|
-
try {
|
|
184
|
-
const payload = { emoji };
|
|
185
|
-
const updated = await this.client.removeCommentReaction(commentId, payload);
|
|
186
|
-
this.comments = this.comments.map((c) => (c.id === commentId ? updated : c));
|
|
187
|
-
return updated;
|
|
188
|
-
} catch (err) {
|
|
189
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
190
|
-
this.error = errorObj;
|
|
191
|
-
throw errorObj;
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
196
|
-
destroy() {
|
|
197
|
-
this.#fetchRequest.cancel();
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export function createTaskActivityState(client: CriticalPathClient, taskId?: string): TaskActivityState {
|
|
202
|
-
return new TaskActivityState(client, taskId);
|
|
203
|
-
}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
|
-
import type { Attachment } from '@critical-path/core';
|
|
4
|
-
import { LatestRequest } from './latest-request.js';
|
|
5
|
-
|
|
6
|
-
export interface AttachmentFilter {
|
|
7
|
-
taskId?: string;
|
|
8
|
-
projectId?: string;
|
|
9
|
-
commentId?: string;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class AttachmentState {
|
|
13
|
-
#fetchRequest = new LatestRequest();
|
|
14
|
-
data = $state<Attachment[]>([]);
|
|
15
|
-
loading = $state<boolean>(false);
|
|
16
|
-
error = $state<Error | null>(null);
|
|
17
|
-
|
|
18
|
-
constructor(private client: CriticalPathClient, public filter?: AttachmentFilter) {}
|
|
19
|
-
|
|
20
|
-
async fetch(filter?: AttachmentFilter) {
|
|
21
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
22
|
-
if (filter) {
|
|
23
|
-
this.filter = filter;
|
|
24
|
-
}
|
|
25
|
-
this.loading = true;
|
|
26
|
-
this.error = null;
|
|
27
|
-
try {
|
|
28
|
-
this.data = await api.getAttachments(this.filter);
|
|
29
|
-
if (signal.aborted) return;
|
|
30
|
-
} catch (err) {
|
|
31
|
-
if (signal.aborted) return;
|
|
32
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
33
|
-
} finally {
|
|
34
|
-
if (!signal.aborted) this.loading = false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async createAttachment(input: Omit<Attachment, 'id' | 'createdAt' | 'updatedAt'>) {
|
|
39
|
-
try {
|
|
40
|
-
const created = await this.client.createAttachment(input);
|
|
41
|
-
this.data = [created, ...this.data];
|
|
42
|
-
return created;
|
|
43
|
-
} catch (err) {
|
|
44
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
45
|
-
this.error = errorObj;
|
|
46
|
-
throw errorObj;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async deleteAttachment(id: string) {
|
|
51
|
-
const previous = this.data;
|
|
52
|
-
this.data = this.data.filter((a) => a.id !== id);
|
|
53
|
-
try {
|
|
54
|
-
await this.client.deleteAttachment(id);
|
|
55
|
-
} catch (err) {
|
|
56
|
-
this.data = previous;
|
|
57
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
58
|
-
this.error = errorObj;
|
|
59
|
-
throw errorObj;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
64
|
-
destroy() {
|
|
65
|
-
this.#fetchRequest.cancel();
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function createAttachmentState(client: CriticalPathClient, initialFilter?: AttachmentFilter): AttachmentState {
|
|
70
|
-
return new AttachmentState(client, initialFilter);
|
|
71
|
-
}
|
package/src/cancellation.test.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { CriticalPathClient } from '@critical-path/client';
|
|
3
|
-
import { TaskState } from './task-state.svelte.js';
|
|
4
|
-
|
|
5
|
-
function controllableFetch() {
|
|
6
|
-
const pending: Array<{ url: string; signal?: AbortSignal | null; resolve: (tasks: unknown[]) => void }> = [];
|
|
7
|
-
const fetchImpl = ((url: string, init: RequestInit) =>
|
|
8
|
-
new Promise<Response>((resolve, reject) => {
|
|
9
|
-
init.signal?.addEventListener('abort', () => reject(init.signal!.reason));
|
|
10
|
-
pending.push({ url, signal: init.signal, resolve: (tasks) => resolve(Response.json({ tasks })) });
|
|
11
|
-
})) as unknown as typeof fetch;
|
|
12
|
-
return { pending, fetchImpl };
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
describe('Svelte state request cancellation', () => {
|
|
16
|
-
it('keeps the newest fetch result when an older request resolves last', async () => {
|
|
17
|
-
const { pending, fetchImpl } = controllableFetch();
|
|
18
|
-
const state = new TaskState(new CriticalPathClient({ baseUrl: 'http://api.test', fetch: fetchImpl }), 'A');
|
|
19
|
-
|
|
20
|
-
const first = state.fetch();
|
|
21
|
-
state.projectId = 'B';
|
|
22
|
-
const second = state.fetch();
|
|
23
|
-
expect(pending[0].signal?.aborted).toBe(true);
|
|
24
|
-
|
|
25
|
-
pending[1].resolve([{ id: 'b1', projectId: 'B', title: 'B task' }]);
|
|
26
|
-
pending[0].resolve([{ id: 'a1', projectId: 'A', title: 'Stale' }]);
|
|
27
|
-
await Promise.all([first, second]);
|
|
28
|
-
|
|
29
|
-
expect(state.data.map((t) => t.id)).toEqual(['b1']);
|
|
30
|
-
expect(state.error).toBeNull();
|
|
31
|
-
expect(state.loading).toBe(false);
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
it('cancels in-flight requests on destroy()', async () => {
|
|
35
|
-
const { pending, fetchImpl } = controllableFetch();
|
|
36
|
-
const state = new TaskState(new CriticalPathClient({ baseUrl: 'http://api.test', fetch: fetchImpl }), 'A');
|
|
37
|
-
const request = state.fetch();
|
|
38
|
-
state.destroy();
|
|
39
|
-
await request;
|
|
40
|
-
expect(pending[0].signal?.aborted).toBe(true);
|
|
41
|
-
expect(state.error).toBeNull();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { CreateCommentBody, UpdateCommentBody } from '@critical-path/core/schemas';
|
|
3
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
|
-
import type { Comment } from '@critical-path/core';
|
|
5
|
-
import { LatestRequest } from './latest-request.js';
|
|
6
|
-
|
|
7
|
-
export interface ThreadedComment extends Comment {
|
|
8
|
-
replies: ThreadedComment[];
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export class CommentState {
|
|
12
|
-
#fetchRequest = new LatestRequest();
|
|
13
|
-
data = $state<Comment[]>([]);
|
|
14
|
-
loading = $state<boolean>(false);
|
|
15
|
-
error = $state<Error | null>(null);
|
|
16
|
-
|
|
17
|
-
threads = $derived.by(() => {
|
|
18
|
-
const map = new Map<string, ThreadedComment>();
|
|
19
|
-
const roots: ThreadedComment[] = [];
|
|
20
|
-
|
|
21
|
-
for (const c of this.data) {
|
|
22
|
-
map.set(c.id, { ...c, replies: [] });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
for (const c of this.data) {
|
|
26
|
-
const threaded = map.get(c.id)!;
|
|
27
|
-
if (c.parentId && map.has(c.parentId)) {
|
|
28
|
-
map.get(c.parentId)!.replies.push(threaded);
|
|
29
|
-
} else {
|
|
30
|
-
roots.push(threaded);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return roots;
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
constructor(private client: CriticalPathClient, public taskId?: string) {}
|
|
38
|
-
|
|
39
|
-
async fetch(taskId?: string) {
|
|
40
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
41
|
-
const targetTaskId = taskId || this.taskId;
|
|
42
|
-
if (!targetTaskId) {
|
|
43
|
-
this.data = [];
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
this.taskId = targetTaskId;
|
|
47
|
-
this.loading = true;
|
|
48
|
-
this.error = null;
|
|
49
|
-
try {
|
|
50
|
-
this.data = await api.getComments(targetTaskId);
|
|
51
|
-
if (signal.aborted) return;
|
|
52
|
-
} catch (err) {
|
|
53
|
-
if (signal.aborted) return;
|
|
54
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
55
|
-
} finally {
|
|
56
|
-
if (!signal.aborted) this.loading = false;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
async addComment(input: Omit<CreateCommentBody, 'taskId'>) {
|
|
61
|
-
if (!this.taskId) {
|
|
62
|
-
throw new Error('CommentState requires a taskId to add comments.');
|
|
63
|
-
}
|
|
64
|
-
try {
|
|
65
|
-
const created = await this.client.addComment({ ...input, taskId: this.taskId });
|
|
66
|
-
this.data = [...this.data, created];
|
|
67
|
-
return created;
|
|
68
|
-
} catch (err) {
|
|
69
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
70
|
-
this.error = errorObj;
|
|
71
|
-
throw errorObj;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async updateComment(id: string, updates: UpdateCommentBody) {
|
|
76
|
-
try {
|
|
77
|
-
const updated = await this.client.updateComment(id, updates);
|
|
78
|
-
this.data = this.data.map((c) => (c.id === id ? updated : c));
|
|
79
|
-
return updated;
|
|
80
|
-
} catch (err) {
|
|
81
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
82
|
-
this.error = errorObj;
|
|
83
|
-
throw errorObj;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async deleteComment(id: string) {
|
|
88
|
-
const previous = this.data;
|
|
89
|
-
this.data = this.data.filter((c) => c.id !== id);
|
|
90
|
-
try {
|
|
91
|
-
await this.client.deleteComment(id);
|
|
92
|
-
} catch (err) {
|
|
93
|
-
this.data = previous;
|
|
94
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
95
|
-
this.error = errorObj;
|
|
96
|
-
throw errorObj;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
async addReaction(
|
|
101
|
-
commentId: string,
|
|
102
|
-
emoji: string
|
|
103
|
-
) {
|
|
104
|
-
try {
|
|
105
|
-
const payload = { emoji };
|
|
106
|
-
const updated = await this.client.addCommentReaction(commentId, payload);
|
|
107
|
-
this.data = this.data.map((c) => (c.id === commentId ? updated : c));
|
|
108
|
-
return updated;
|
|
109
|
-
} catch (err) {
|
|
110
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
111
|
-
this.error = errorObj;
|
|
112
|
-
throw errorObj;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async removeReaction(
|
|
117
|
-
commentId: string,
|
|
118
|
-
emoji: string
|
|
119
|
-
) {
|
|
120
|
-
try {
|
|
121
|
-
const payload = { emoji };
|
|
122
|
-
const updated = await this.client.removeCommentReaction(commentId, payload);
|
|
123
|
-
this.data = this.data.map((c) => (c.id === commentId ? updated : c));
|
|
124
|
-
return updated;
|
|
125
|
-
} catch (err) {
|
|
126
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
127
|
-
this.error = errorObj;
|
|
128
|
-
throw errorObj;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
133
|
-
destroy() {
|
|
134
|
-
this.#fetchRequest.cancel();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export function createCommentState(client: CriticalPathClient, taskId?: string): CommentState {
|
|
139
|
-
return new CommentState(client, taskId);
|
|
140
|
-
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
|
-
import type { CriticalPathAnalysis } from '@critical-path/core';
|
|
4
|
-
import { LatestRequest } from './latest-request.js';
|
|
5
|
-
|
|
6
|
-
export class CriticalPathState {
|
|
7
|
-
#fetchRequest = new LatestRequest();
|
|
8
|
-
data = $state<CriticalPathAnalysis | null>(null);
|
|
9
|
-
loading = $state<boolean>(false);
|
|
10
|
-
error = $state<Error | null>(null);
|
|
11
|
-
|
|
12
|
-
constructor(
|
|
13
|
-
private client: CriticalPathClient,
|
|
14
|
-
public projectId: string
|
|
15
|
-
) {}
|
|
16
|
-
|
|
17
|
-
async fetch() {
|
|
18
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
19
|
-
this.loading = true;
|
|
20
|
-
this.error = null;
|
|
21
|
-
try {
|
|
22
|
-
this.data = await api.calculateCriticalPath(this.projectId);
|
|
23
|
-
if (signal.aborted) return;
|
|
24
|
-
} catch (err) {
|
|
25
|
-
if (signal.aborted) return;
|
|
26
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
27
|
-
} finally {
|
|
28
|
-
if (!signal.aborted) this.loading = false;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
33
|
-
destroy() {
|
|
34
|
-
this.#fetchRequest.cancel();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export function createCriticalPathState(
|
|
39
|
-
client: CriticalPathClient,
|
|
40
|
-
projectId: string
|
|
41
|
-
): CriticalPathState {
|
|
42
|
-
return new CriticalPathState(client, projectId);
|
|
43
|
-
}
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { UpdateDeliverableBody } from '@critical-path/core/schemas';
|
|
3
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
|
-
import type { Deliverable, DeliverableSummary, CreateDeliverableInput } from '@critical-path/core';
|
|
5
|
-
import { LatestRequest } from './latest-request.js';
|
|
6
|
-
|
|
7
|
-
export class DeliverableState {
|
|
8
|
-
#fetchRequest = new LatestRequest();
|
|
9
|
-
data = $state<Deliverable[]>([]);
|
|
10
|
-
loading = $state<boolean>(false);
|
|
11
|
-
error = $state<Error | null>(null);
|
|
12
|
-
|
|
13
|
-
constructor(private client: CriticalPathClient, public projectId?: string) {}
|
|
14
|
-
|
|
15
|
-
async fetch(projectId?: string) {
|
|
16
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
17
|
-
if (projectId) {
|
|
18
|
-
this.projectId = projectId;
|
|
19
|
-
}
|
|
20
|
-
if (!this.projectId) return;
|
|
21
|
-
|
|
22
|
-
this.loading = true;
|
|
23
|
-
this.error = null;
|
|
24
|
-
try {
|
|
25
|
-
this.data = await api.getDeliverables(this.projectId);
|
|
26
|
-
if (signal.aborted) return;
|
|
27
|
-
} catch (err) {
|
|
28
|
-
if (signal.aborted) return;
|
|
29
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
30
|
-
} finally {
|
|
31
|
-
if (!signal.aborted) this.loading = false;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async createDeliverable(input: CreateDeliverableInput) {
|
|
36
|
-
try {
|
|
37
|
-
const created = await this.client.createDeliverable(input);
|
|
38
|
-
this.data = [...this.data, created];
|
|
39
|
-
return created;
|
|
40
|
-
} catch (err) {
|
|
41
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
42
|
-
this.error = errorObj;
|
|
43
|
-
throw errorObj;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async updateDeliverable(id: string, updates: UpdateDeliverableBody) {
|
|
48
|
-
const previous = this.data;
|
|
49
|
-
this.data = this.data.map((d) => (d.id === id ? { ...d, ...updates } : d));
|
|
50
|
-
try {
|
|
51
|
-
const updated = await this.client.updateDeliverable(id, updates);
|
|
52
|
-
this.data = this.data.map((d) => (d.id === id ? updated : d));
|
|
53
|
-
return updated;
|
|
54
|
-
} catch (err) {
|
|
55
|
-
this.data = previous;
|
|
56
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
57
|
-
this.error = errorObj;
|
|
58
|
-
throw errorObj;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async deleteDeliverable(id: string) {
|
|
63
|
-
const previous = this.data;
|
|
64
|
-
this.data = this.data.filter((d) => d.id !== id);
|
|
65
|
-
try {
|
|
66
|
-
await this.client.deleteDeliverable(id);
|
|
67
|
-
} catch (err) {
|
|
68
|
-
this.data = previous;
|
|
69
|
-
const errorObj = err instanceof Error ? err : new Error(String(err));
|
|
70
|
-
this.error = errorObj;
|
|
71
|
-
throw errorObj;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async getSummary(deliverableId: string): Promise<DeliverableSummary> {
|
|
76
|
-
return this.client.getDeliverableSummary(deliverableId);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
80
|
-
destroy() {
|
|
81
|
-
this.#fetchRequest.cancel();
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
export function createDeliverableState(client: CriticalPathClient, initialProjectId?: string): DeliverableState {
|
|
86
|
-
return new DeliverableState(client, initialProjectId);
|
|
87
|
-
}
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
/// <reference types="svelte" />
|
|
2
|
-
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
|
-
import type { DeliverableSummary } from '@critical-path/core';
|
|
4
|
-
import { LatestRequest } from './latest-request.js';
|
|
5
|
-
|
|
6
|
-
export class DeliverableSummaryState {
|
|
7
|
-
#fetchRequest = new LatestRequest();
|
|
8
|
-
summary = $state<DeliverableSummary | null>(null);
|
|
9
|
-
loading = $state<boolean>(false);
|
|
10
|
-
error = $state<Error | null>(null);
|
|
11
|
-
|
|
12
|
-
get data(): DeliverableSummary | null {
|
|
13
|
-
return this.summary;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
constructor(private client: CriticalPathClient, public deliverableId?: string) {}
|
|
17
|
-
|
|
18
|
-
async fetch(deliverableId?: string) {
|
|
19
|
-
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
20
|
-
const targetId = deliverableId || this.deliverableId;
|
|
21
|
-
if (!targetId) {
|
|
22
|
-
this.summary = null;
|
|
23
|
-
this.loading = false;
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
this.deliverableId = targetId;
|
|
27
|
-
this.loading = true;
|
|
28
|
-
this.error = null;
|
|
29
|
-
try {
|
|
30
|
-
this.summary = await api.getDeliverableSummary(targetId);
|
|
31
|
-
if (signal.aborted) return;
|
|
32
|
-
} catch (err) {
|
|
33
|
-
if (signal.aborted) return;
|
|
34
|
-
this.error = err instanceof Error ? err : new Error(String(err));
|
|
35
|
-
} finally {
|
|
36
|
-
if (!signal.aborted) this.loading = false;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
41
|
-
destroy() {
|
|
42
|
-
this.#fetchRequest.cancel();
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export function createDeliverableSummaryState(
|
|
47
|
-
client: CriticalPathClient,
|
|
48
|
-
deliverableId?: string
|
|
49
|
-
): DeliverableSummaryState {
|
|
50
|
-
return new DeliverableSummaryState(client, deliverableId);
|
|
51
|
-
}
|