@critical-path/svelte 0.17.10 → 0.18.0
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/CHANGELOG.md +25 -0
- package/README.md +13 -0
- package/dist/activity-state.svelte.d.ts +3 -0
- package/dist/activity-state.svelte.d.ts.map +1 -1
- package/dist/attachment-state.svelte.d.ts +3 -0
- package/dist/attachment-state.svelte.d.ts.map +1 -1
- package/dist/cancellation.test.d.ts +2 -0
- package/dist/cancellation.test.d.ts.map +1 -0
- package/dist/comment-state.svelte.d.ts +3 -0
- package/dist/comment-state.svelte.d.ts.map +1 -1
- package/dist/critical-path-state.svelte.d.ts +3 -0
- package/dist/critical-path-state.svelte.d.ts.map +1 -1
- package/dist/deliverable-state.svelte.d.ts +3 -0
- package/dist/deliverable-state.svelte.d.ts.map +1 -1
- package/dist/deliverable-summary-state.svelte.d.ts +3 -0
- package/dist/deliverable-summary-state.svelte.d.ts.map +1 -1
- package/dist/index.js +645 -551
- package/dist/latest-request.d.ts +15 -0
- package/dist/latest-request.d.ts.map +1 -0
- package/dist/project-state.svelte.d.ts +3 -0
- package/dist/project-state.svelte.d.ts.map +1 -1
- package/dist/task-metrics-state.svelte.d.ts +3 -0
- package/dist/task-metrics-state.svelte.d.ts.map +1 -1
- package/dist/task-state.svelte.d.ts +3 -0
- package/dist/task-state.svelte.d.ts.map +1 -1
- package/dist/task-transitions-state.svelte.d.ts +3 -0
- package/dist/task-transitions-state.svelte.d.ts.map +1 -1
- package/dist/timeline-ladder-state.svelte.d.ts +3 -0
- package/dist/timeline-ladder-state.svelte.d.ts.map +1 -1
- package/dist/workflow-state.svelte.d.ts +3 -0
- package/dist/workflow-state.svelte.d.ts.map +1 -1
- package/dist/workload-state.svelte.d.ts +3 -0
- package/dist/workload-state.svelte.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/activity-state.svelte.ts +13 -3
- package/src/attachment-state.svelte.ts +12 -2
- package/src/cancellation.test.ts +43 -0
- package/src/comment-state.svelte.ts +12 -2
- package/src/critical-path-state.svelte.ts +12 -2
- package/src/deliverable-state.svelte.ts +12 -2
- package/src/deliverable-summary-state.svelte.ts +12 -2
- package/src/latest-request.ts +24 -0
- package/src/project-state.svelte.ts +12 -2
- package/src/task-metrics-state.svelte.ts +27 -7
- package/src/task-state.svelte.ts +12 -2
- package/src/task-transitions-state.svelte.ts +12 -2
- package/src/timeline-ladder-state.svelte.ts +12 -2
- package/src/workflow-state.svelte.ts +12 -2
- package/src/workload-state.svelte.ts +12 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
|
+
/**
|
|
3
|
+
* Tracks the latest request for one fetch method. Starting a new request aborts the previous
|
|
4
|
+
* one, so a slow response for old inputs can never overwrite newer state.
|
|
5
|
+
*/
|
|
6
|
+
export declare class LatestRequest {
|
|
7
|
+
private controller?;
|
|
8
|
+
/** Aborts any in-flight request and returns a client and signal for the new one. */
|
|
9
|
+
begin(client: CriticalPathClient): {
|
|
10
|
+
api: CriticalPathClient;
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
};
|
|
13
|
+
cancel(): void;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=latest-request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"latest-request.d.ts","sourceRoot":"","sources":["../src/latest-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE;;;GAGG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,UAAU,CAAC,CAAkB;IAErC,oFAAoF;IACpF,KAAK,CAAC,MAAM,EAAE,kBAAkB,GAAG;QAAE,GAAG,EAAE,kBAAkB,CAAC;QAAC,MAAM,EAAE,WAAW,CAAA;KAAE;IASnF,MAAM,IAAI,IAAI;CAIf"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
import type { Project } from '@critical-path/core';
|
|
3
3
|
export declare class ProjectState {
|
|
4
|
+
#private;
|
|
4
5
|
private client;
|
|
5
6
|
data: Project[];
|
|
6
7
|
loading: boolean;
|
|
@@ -8,6 +9,8 @@ export declare class ProjectState {
|
|
|
8
9
|
constructor(client: CriticalPathClient);
|
|
9
10
|
fetch(): Promise<void>;
|
|
10
11
|
createProject(input: Omit<Project, 'id' | 'createdAt' | 'updatedAt'>): Promise<Project>;
|
|
12
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
13
|
+
destroy(): void;
|
|
11
14
|
}
|
|
12
15
|
export declare function createProjectState(client: CriticalPathClient): ProjectState;
|
|
13
16
|
//# sourceMappingURL=project-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-state.svelte.d.ts","sourceRoot":"","sources":["../src/project-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"project-state.svelte.d.ts","sourceRoot":"","sources":["../src/project-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,qBAAa,YAAY;;IAMX,OAAO,CAAC,MAAM;IAJ1B,IAAI,YAAyB;IAC7B,OAAO,UAA0B;IACjC,KAAK,eAA8B;gBAEf,MAAM,EAAE,kBAAkB;IAExC,KAAK;IAeL,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC;IA2B1E,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,kBAAkB,GAAG,YAAY,CAE3E"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
import type { TaskMetrics, TaskProgressHistory, TaskInferredActuals, RealityDelta, TaskProgressInference, TaskEVM, ProgressCurveProfile } from '@critical-path/core';
|
|
3
3
|
export declare class TaskMetricsState {
|
|
4
|
+
#private;
|
|
4
5
|
private client;
|
|
5
6
|
taskId: string;
|
|
6
7
|
metrics: TaskMetrics | null;
|
|
@@ -19,6 +20,8 @@ export declare class TaskMetricsState {
|
|
|
19
20
|
metrics: TaskMetrics | null;
|
|
20
21
|
history: TaskProgressHistory | null;
|
|
21
22
|
}>;
|
|
23
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
24
|
+
destroy(): void;
|
|
22
25
|
}
|
|
23
26
|
export declare function createTaskMetricsState(client: CriticalPathClient, taskId: string): TaskMetricsState;
|
|
24
27
|
//# sourceMappingURL=task-metrics-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-metrics-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-metrics-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-metrics-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-metrics-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EACnB,mBAAmB,EACnB,YAAY,EACZ,qBAAqB,EACrB,OAAO,EACP,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,gBAAgB;;IAgBzB,OAAO,CAAC,MAAM;IACP,MAAM,EAAE,MAAM;IAbvB,OAAO,qBAAoC;IAC3C,OAAO,6BAA4C;IACnD,OAAO,UAA0B;IACjC,KAAK,eAA8B;IAEnC,eAAe,6BAA+E;IAC9F,YAAY,sBAAqE;IACjF,QAAQ,+BAA0E;IAClF,GAAG,iBAAuD;IAC1D,YAAY,8BAA6E;gBAG/E,MAAM,EAAE,kBAAkB,EAC3B,MAAM,EAAE,MAAM;IAGjB,YAAY,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAiB3C,YAAY,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAiBnD,QAAQ,IAAI,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAAA;KAAE,CAAC;IAsB/F,qEAAqE;IACrE,OAAO;CAKR;AAED,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,EAAE,MAAM,GACb,gBAAgB,CAElB"}
|
|
@@ -2,6 +2,7 @@ import type { CreateTaskBody, UpdateTaskBody } from '@critical-path/core/schemas
|
|
|
2
2
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
3
|
import { type Task, type TaskStatus } from '@critical-path/core';
|
|
4
4
|
export declare class TaskState {
|
|
5
|
+
#private;
|
|
5
6
|
private client;
|
|
6
7
|
projectId?: string | undefined;
|
|
7
8
|
data: Task[];
|
|
@@ -15,6 +16,8 @@ export declare class TaskState {
|
|
|
15
16
|
updateTask(taskId: string, updates: UpdateTaskBody): Promise<Task>;
|
|
16
17
|
updateTaskStatus(taskId: string, status: TaskStatus): Promise<Task>;
|
|
17
18
|
deleteTask(taskId: string): Promise<void>;
|
|
19
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
20
|
+
destroy(): void;
|
|
18
21
|
}
|
|
19
22
|
export declare function createTaskState(client: CriticalPathClient, projectId?: string): TaskState;
|
|
20
23
|
//# sourceMappingURL=task-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,UAAU,EAAgB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAClF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,UAAU,EAAgB,MAAM,qBAAqB,CAAC;AAG/E,qBAAa,SAAS;;IAUlB,OAAO,CAAC,MAAM;IACP,SAAS,CAAC,EAAE,MAAM;IAT3B,IAAI,SAAsB;IAC1B,OAAO,UAA0B;IACjC,KAAK,eAA8B;IAEnC,OAAO,CAAC,gBAAgB,CAAoC;IAC5D,OAAO,CAAC,eAAe,CAA6B;gBAG1C,MAAM,EAAE,kBAAkB,EAC3B,SAAS,CAAC,EAAE,MAAM,YAAA;IAGrB,KAAK;IAeL,UAAU,CAAC,KAAK,EAAE,cAAc;IAoChC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc;IAyElD,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU;IAInD,UAAU,CAAC,MAAM,EAAE,MAAM;IA6C/B,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,eAAe,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,SAAS,CAAC,EAAE,MAAM,GACjB,SAAS,CAEX"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
export declare class TaskTransitionsState {
|
|
3
|
+
#private;
|
|
3
4
|
private client;
|
|
4
5
|
taskId?: string | undefined;
|
|
5
6
|
allowedTransitions: string[];
|
|
@@ -7,6 +8,8 @@ export declare class TaskTransitionsState {
|
|
|
7
8
|
error: Error | null;
|
|
8
9
|
constructor(client: CriticalPathClient, taskId?: string | undefined);
|
|
9
10
|
fetch(taskId?: string): Promise<void>;
|
|
11
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
12
|
+
destroy(): void;
|
|
10
13
|
}
|
|
11
14
|
export declare function createTaskTransitionsState(client: CriticalPathClient, taskId?: string): TaskTransitionsState;
|
|
12
15
|
//# sourceMappingURL=task-transitions-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-transitions-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-transitions-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"task-transitions-state.svelte.d.ts","sourceRoot":"","sources":["../src/task-transitions-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAGhE,qBAAa,oBAAoB;;IAMnB,OAAO,CAAC,MAAM;IAA6B,MAAM,CAAC,EAAE,MAAM;IAJtE,kBAAkB,WAAwB;IAC1C,OAAO,UAA0B;IACjC,KAAK,eAA8B;gBAEf,MAAM,EAAE,kBAAkB,EAAS,MAAM,CAAC,EAAE,MAAM,YAAA;IAEhE,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM;IAsB3B,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,kBAAkB,EAC1B,MAAM,CAAC,EAAE,MAAM,GACd,oBAAoB,CAEtB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
import type { TimelineLadder, TimelineLadderOptions, AbstractionLevel, MacroTimelineSummary, ConcreteTaskEvidence } from '@critical-path/core';
|
|
3
3
|
export declare class TimelineLadderState {
|
|
4
|
+
#private;
|
|
4
5
|
private client;
|
|
5
6
|
projectId: string;
|
|
6
7
|
data: TimelineLadder | null;
|
|
@@ -18,6 +19,8 @@ export declare class TimelineLadderState {
|
|
|
18
19
|
constructor(client: CriticalPathClient, projectId: string, initialOptions?: TimelineLadderOptions);
|
|
19
20
|
setLevel(newLevel: AbstractionLevel): Promise<void>;
|
|
20
21
|
fetch(options?: TimelineLadderOptions): Promise<void>;
|
|
22
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
23
|
+
destroy(): void;
|
|
21
24
|
}
|
|
22
25
|
export declare function createTimelineLadderState(client: CriticalPathClient, projectId: string, initialOptions?: TimelineLadderOptions): TimelineLadderState;
|
|
23
26
|
//# sourceMappingURL=timeline-ladder-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline-ladder-state.svelte.d.ts","sourceRoot":"","sources":["../src/timeline-ladder-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"timeline-ladder-state.svelte.d.ts","sourceRoot":"","sources":["../src/timeline-ladder-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACrB,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,mBAAmB;;IAY5B,OAAO,CAAC,MAAM;IACP,SAAS,EAAE,MAAM;IAX1B,IAAI,wBAAuC;IAC3C,KAAK,mBAAmC;IACxC,OAAO,UAA0B;IACjC,KAAK,eAA8B;IAEnC,KAAK,8BAAmE;IACxE,QAAQ;;;;;yBAA4E;IACpF,QAAQ,8CAAsF;gBAGpF,MAAM,EAAE,kBAAkB,EAC3B,SAAS,EAAE,MAAM,EACxB,cAAc,CAAC,EAAE,qBAAqB;IAOlC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB;IAKnC,KAAK,CAAC,OAAO,CAAC,EAAE,qBAAqB;IAkB3C,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,kBAAkB,EAC1B,SAAS,EAAE,MAAM,EACjB,cAAc,CAAC,EAAE,qBAAqB,GACrC,mBAAmB,CAErB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
import type { Workflow } from '@critical-path/core';
|
|
3
3
|
export declare class WorkflowState {
|
|
4
|
+
#private;
|
|
4
5
|
private client;
|
|
5
6
|
data: Workflow[];
|
|
6
7
|
loading: boolean;
|
|
@@ -10,6 +11,8 @@ export declare class WorkflowState {
|
|
|
10
11
|
createWorkflow(input: Omit<Workflow, 'id' | 'createdAt' | 'updatedAt'>): Promise<Workflow>;
|
|
11
12
|
updateWorkflow(id: string, updates: Partial<Workflow>): Promise<Workflow>;
|
|
12
13
|
deleteWorkflow(id: string): Promise<void>;
|
|
14
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
15
|
+
destroy(): void;
|
|
13
16
|
}
|
|
14
17
|
export declare function createWorkflowState(client: CriticalPathClient): WorkflowState;
|
|
15
18
|
//# sourceMappingURL=workflow-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-state.svelte.d.ts","sourceRoot":"","sources":["../src/workflow-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-state.svelte.d.ts","sourceRoot":"","sources":["../src/workflow-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,qBAAa,aAAa;;IAMZ,OAAO,CAAC,MAAM;IAJ1B,IAAI,aAA0B;IAC9B,OAAO,UAA0B;IACjC,KAAK,eAA8B;gBAEf,MAAM,EAAE,kBAAkB;IAExC,KAAK;IAeL,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC;IAYtE,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC;IAYrD,cAAc,CAAC,EAAE,EAAE,MAAM;IAW/B,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,kBAAkB,GAAG,aAAa,CAE7E"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
2
|
import type { WorkloadDistribution, WorkloadDistributionOptions, WorkloadInterval, WorkloadGroupBy, WorkloadMetric, WorkloadBucket } from '@critical-path/core';
|
|
3
3
|
export declare class WorkloadState {
|
|
4
|
+
#private;
|
|
4
5
|
private client;
|
|
5
6
|
projectId?: string | undefined;
|
|
6
7
|
initialOptions?: WorkloadDistributionOptions | undefined;
|
|
@@ -21,6 +22,8 @@ export declare class WorkloadState {
|
|
|
21
22
|
setGroupBy(newGroupBy: WorkloadGroupBy): Promise<void>;
|
|
22
23
|
setMetric(newMetric: WorkloadMetric): Promise<void>;
|
|
23
24
|
fetch(options?: WorkloadDistributionOptions): Promise<void>;
|
|
25
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
26
|
+
destroy(): void;
|
|
24
27
|
}
|
|
25
28
|
export declare function createWorkloadState(client: CriticalPathClient, projectId?: string, initialOptions?: WorkloadDistributionOptions): WorkloadState;
|
|
26
29
|
//# sourceMappingURL=workload-state.svelte.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workload-state.svelte.d.ts","sourceRoot":"","sources":["../src/workload-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"workload-state.svelte.d.ts","sourceRoot":"","sources":["../src/workload-state.svelte.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAEhE,OAAO,KAAK,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,cAAc,EACf,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,aAAa;;IAiBtB,OAAO,CAAC,MAAM;IACP,SAAS,CAAC,EAAE,MAAM;IAClB,cAAc,CAAC,EAAE,2BAA2B;IAjBrD,IAAI,8BAA6C;IACjD,QAAQ,mBAAoC;IAC5C,OAAO,kBAAuC;IAC9C,MAAM,iBAAqC;IAC3C,OAAO,UAA0B;IACjC,KAAK,eAA8B;IAEnC,OAAO,mBAAwD;IAC/D,UAAU,WAAmD;IAC7D,YAAY,yBAAmE;IAC/E,UAAU,SAAgD;IAC1D,aAAa,SAAmD;IAChE,kBAAkB,qBAA+D;gBAGvE,MAAM,EAAE,kBAAkB,EAC3B,SAAS,CAAC,EAAE,MAAM,YAAA,EAClB,cAAc,CAAC,EAAE,2BAA2B,YAAA;IAa/C,WAAW,CAAC,WAAW,EAAE,gBAAgB;IAKzC,UAAU,CAAC,UAAU,EAAE,eAAe;IAKtC,SAAS,CAAC,SAAS,EAAE,cAAc;IAKnC,KAAK,CAAC,OAAO,CAAC,EAAE,2BAA2B;IAqBjD,qEAAqE;IACrE,OAAO;CAGR;AAED,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,kBAAkB,EAC1B,SAAS,CAAC,EAAE,MAAM,EAClB,cAAc,CAAC,EAAE,2BAA2B,GAC3C,aAAa,CAEf"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@critical-path/svelte",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Svelte 5 Runes state and reactive integrations for Critical Path headless project management framework",
|
|
5
5
|
"author": "Jack James",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,9 +18,9 @@
|
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@critical-path/mcp": "0.11.
|
|
22
|
-
"@critical-path/
|
|
23
|
-
"@critical-path/
|
|
21
|
+
"@critical-path/mcp": "0.11.7",
|
|
22
|
+
"@critical-path/core": "0.36.0",
|
|
23
|
+
"@critical-path/client": "0.20.5"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
26
|
"svelte": "^5.0.0"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { CreateAttachmentBody, CreateCommentBody } from '@critical-path/core/schemas';
|
|
3
3
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
4
|
import type { Comment, Attachment } from '@critical-path/core';
|
|
5
|
+
import { LatestRequest } from './latest-request.js';
|
|
5
6
|
|
|
6
7
|
export interface ThreadedCommentWithAttachments extends Comment {
|
|
7
8
|
attachments: Attachment[];
|
|
@@ -9,6 +10,7 @@ export interface ThreadedCommentWithAttachments extends Comment {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export class TaskActivityState {
|
|
13
|
+
#fetchRequest = new LatestRequest();
|
|
12
14
|
comments = $state<Comment[]>([]);
|
|
13
15
|
attachments = $state<Attachment[]>([]);
|
|
14
16
|
loading = $state<boolean>(false);
|
|
@@ -56,6 +58,7 @@ export class TaskActivityState {
|
|
|
56
58
|
constructor(private client: CriticalPathClient, public taskId?: string) {}
|
|
57
59
|
|
|
58
60
|
async fetch(taskId?: string) {
|
|
61
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
59
62
|
const targetTaskId = taskId || this.taskId;
|
|
60
63
|
if (!targetTaskId) {
|
|
61
64
|
this.comments = [];
|
|
@@ -67,15 +70,17 @@ export class TaskActivityState {
|
|
|
67
70
|
this.error = null;
|
|
68
71
|
try {
|
|
69
72
|
const [comments, attachments] = await Promise.all([
|
|
70
|
-
|
|
71
|
-
|
|
73
|
+
api.getComments(targetTaskId),
|
|
74
|
+
api.getAttachments({ taskId: targetTaskId })
|
|
72
75
|
]);
|
|
76
|
+
if (signal.aborted) return;
|
|
73
77
|
this.comments = comments;
|
|
74
78
|
this.attachments = attachments;
|
|
75
79
|
} catch (err) {
|
|
80
|
+
if (signal.aborted) return;
|
|
76
81
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
77
82
|
} finally {
|
|
78
|
-
this.loading = false;
|
|
83
|
+
if (!signal.aborted) this.loading = false;
|
|
79
84
|
}
|
|
80
85
|
}
|
|
81
86
|
|
|
@@ -186,6 +191,11 @@ export class TaskActivityState {
|
|
|
186
191
|
throw errorObj;
|
|
187
192
|
}
|
|
188
193
|
}
|
|
194
|
+
|
|
195
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
196
|
+
destroy() {
|
|
197
|
+
this.#fetchRequest.cancel();
|
|
198
|
+
}
|
|
189
199
|
}
|
|
190
200
|
|
|
191
201
|
export function createTaskActivityState(client: CriticalPathClient, taskId?: string): TaskActivityState {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
2
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
3
|
import type { Attachment } from '@critical-path/core';
|
|
4
|
+
import { LatestRequest } from './latest-request.js';
|
|
4
5
|
|
|
5
6
|
export interface AttachmentFilter {
|
|
6
7
|
taskId?: string;
|
|
@@ -9,6 +10,7 @@ export interface AttachmentFilter {
|
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export class AttachmentState {
|
|
13
|
+
#fetchRequest = new LatestRequest();
|
|
12
14
|
data = $state<Attachment[]>([]);
|
|
13
15
|
loading = $state<boolean>(false);
|
|
14
16
|
error = $state<Error | null>(null);
|
|
@@ -16,17 +18,20 @@ export class AttachmentState {
|
|
|
16
18
|
constructor(private client: CriticalPathClient, public filter?: AttachmentFilter) {}
|
|
17
19
|
|
|
18
20
|
async fetch(filter?: AttachmentFilter) {
|
|
21
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
19
22
|
if (filter) {
|
|
20
23
|
this.filter = filter;
|
|
21
24
|
}
|
|
22
25
|
this.loading = true;
|
|
23
26
|
this.error = null;
|
|
24
27
|
try {
|
|
25
|
-
this.data = await
|
|
28
|
+
this.data = await api.getAttachments(this.filter);
|
|
29
|
+
if (signal.aborted) return;
|
|
26
30
|
} catch (err) {
|
|
31
|
+
if (signal.aborted) return;
|
|
27
32
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
28
33
|
} finally {
|
|
29
|
-
this.loading = false;
|
|
34
|
+
if (!signal.aborted) this.loading = false;
|
|
30
35
|
}
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -54,6 +59,11 @@ export class AttachmentState {
|
|
|
54
59
|
throw errorObj;
|
|
55
60
|
}
|
|
56
61
|
}
|
|
62
|
+
|
|
63
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
64
|
+
destroy() {
|
|
65
|
+
this.#fetchRequest.cancel();
|
|
66
|
+
}
|
|
57
67
|
}
|
|
58
68
|
|
|
59
69
|
export function createAttachmentState(client: CriticalPathClient, initialFilter?: AttachmentFilter): AttachmentState {
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
});
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
import type { CreateCommentBody, UpdateCommentBody } from '@critical-path/core/schemas';
|
|
3
3
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
4
|
import type { Comment } from '@critical-path/core';
|
|
5
|
+
import { LatestRequest } from './latest-request.js';
|
|
5
6
|
|
|
6
7
|
export interface ThreadedComment extends Comment {
|
|
7
8
|
replies: ThreadedComment[];
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
export class CommentState {
|
|
12
|
+
#fetchRequest = new LatestRequest();
|
|
11
13
|
data = $state<Comment[]>([]);
|
|
12
14
|
loading = $state<boolean>(false);
|
|
13
15
|
error = $state<Error | null>(null);
|
|
@@ -35,6 +37,7 @@ export class CommentState {
|
|
|
35
37
|
constructor(private client: CriticalPathClient, public taskId?: string) {}
|
|
36
38
|
|
|
37
39
|
async fetch(taskId?: string) {
|
|
40
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
38
41
|
const targetTaskId = taskId || this.taskId;
|
|
39
42
|
if (!targetTaskId) {
|
|
40
43
|
this.data = [];
|
|
@@ -44,11 +47,13 @@ export class CommentState {
|
|
|
44
47
|
this.loading = true;
|
|
45
48
|
this.error = null;
|
|
46
49
|
try {
|
|
47
|
-
this.data = await
|
|
50
|
+
this.data = await api.getComments(targetTaskId);
|
|
51
|
+
if (signal.aborted) return;
|
|
48
52
|
} catch (err) {
|
|
53
|
+
if (signal.aborted) return;
|
|
49
54
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
50
55
|
} finally {
|
|
51
|
-
this.loading = false;
|
|
56
|
+
if (!signal.aborted) this.loading = false;
|
|
52
57
|
}
|
|
53
58
|
}
|
|
54
59
|
|
|
@@ -123,6 +128,11 @@ export class CommentState {
|
|
|
123
128
|
throw errorObj;
|
|
124
129
|
}
|
|
125
130
|
}
|
|
131
|
+
|
|
132
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
133
|
+
destroy() {
|
|
134
|
+
this.#fetchRequest.cancel();
|
|
135
|
+
}
|
|
126
136
|
}
|
|
127
137
|
|
|
128
138
|
export function createCommentState(client: CriticalPathClient, taskId?: string): CommentState {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
2
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
3
|
import type { CriticalPathAnalysis } from '@critical-path/core';
|
|
4
|
+
import { LatestRequest } from './latest-request.js';
|
|
4
5
|
|
|
5
6
|
export class CriticalPathState {
|
|
7
|
+
#fetchRequest = new LatestRequest();
|
|
6
8
|
data = $state<CriticalPathAnalysis | null>(null);
|
|
7
9
|
loading = $state<boolean>(false);
|
|
8
10
|
error = $state<Error | null>(null);
|
|
@@ -13,16 +15,24 @@ export class CriticalPathState {
|
|
|
13
15
|
) {}
|
|
14
16
|
|
|
15
17
|
async fetch() {
|
|
18
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
16
19
|
this.loading = true;
|
|
17
20
|
this.error = null;
|
|
18
21
|
try {
|
|
19
|
-
this.data = await
|
|
22
|
+
this.data = await api.calculateCriticalPath(this.projectId);
|
|
23
|
+
if (signal.aborted) return;
|
|
20
24
|
} catch (err) {
|
|
25
|
+
if (signal.aborted) return;
|
|
21
26
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
22
27
|
} finally {
|
|
23
|
-
this.loading = false;
|
|
28
|
+
if (!signal.aborted) this.loading = false;
|
|
24
29
|
}
|
|
25
30
|
}
|
|
31
|
+
|
|
32
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
33
|
+
destroy() {
|
|
34
|
+
this.#fetchRequest.cancel();
|
|
35
|
+
}
|
|
26
36
|
}
|
|
27
37
|
|
|
28
38
|
export function createCriticalPathState(
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
import type { UpdateDeliverableBody } from '@critical-path/core/schemas';
|
|
3
3
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
4
4
|
import type { Deliverable, DeliverableSummary, CreateDeliverableInput } from '@critical-path/core';
|
|
5
|
+
import { LatestRequest } from './latest-request.js';
|
|
5
6
|
|
|
6
7
|
export class DeliverableState {
|
|
8
|
+
#fetchRequest = new LatestRequest();
|
|
7
9
|
data = $state<Deliverable[]>([]);
|
|
8
10
|
loading = $state<boolean>(false);
|
|
9
11
|
error = $state<Error | null>(null);
|
|
@@ -11,6 +13,7 @@ export class DeliverableState {
|
|
|
11
13
|
constructor(private client: CriticalPathClient, public projectId?: string) {}
|
|
12
14
|
|
|
13
15
|
async fetch(projectId?: string) {
|
|
16
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
14
17
|
if (projectId) {
|
|
15
18
|
this.projectId = projectId;
|
|
16
19
|
}
|
|
@@ -19,11 +22,13 @@ export class DeliverableState {
|
|
|
19
22
|
this.loading = true;
|
|
20
23
|
this.error = null;
|
|
21
24
|
try {
|
|
22
|
-
this.data = await
|
|
25
|
+
this.data = await api.getDeliverables(this.projectId);
|
|
26
|
+
if (signal.aborted) return;
|
|
23
27
|
} catch (err) {
|
|
28
|
+
if (signal.aborted) return;
|
|
24
29
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
25
30
|
} finally {
|
|
26
|
-
this.loading = false;
|
|
31
|
+
if (!signal.aborted) this.loading = false;
|
|
27
32
|
}
|
|
28
33
|
}
|
|
29
34
|
|
|
@@ -70,6 +75,11 @@ export class DeliverableState {
|
|
|
70
75
|
async getSummary(deliverableId: string): Promise<DeliverableSummary> {
|
|
71
76
|
return this.client.getDeliverableSummary(deliverableId);
|
|
72
77
|
}
|
|
78
|
+
|
|
79
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
80
|
+
destroy() {
|
|
81
|
+
this.#fetchRequest.cancel();
|
|
82
|
+
}
|
|
73
83
|
}
|
|
74
84
|
|
|
75
85
|
export function createDeliverableState(client: CriticalPathClient, initialProjectId?: string): DeliverableState {
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
2
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
3
|
import type { DeliverableSummary } from '@critical-path/core';
|
|
4
|
+
import { LatestRequest } from './latest-request.js';
|
|
4
5
|
|
|
5
6
|
export class DeliverableSummaryState {
|
|
7
|
+
#fetchRequest = new LatestRequest();
|
|
6
8
|
summary = $state<DeliverableSummary | null>(null);
|
|
7
9
|
loading = $state<boolean>(false);
|
|
8
10
|
error = $state<Error | null>(null);
|
|
@@ -14,6 +16,7 @@ export class DeliverableSummaryState {
|
|
|
14
16
|
constructor(private client: CriticalPathClient, public deliverableId?: string) {}
|
|
15
17
|
|
|
16
18
|
async fetch(deliverableId?: string) {
|
|
19
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
17
20
|
const targetId = deliverableId || this.deliverableId;
|
|
18
21
|
if (!targetId) {
|
|
19
22
|
this.summary = null;
|
|
@@ -24,13 +27,20 @@ export class DeliverableSummaryState {
|
|
|
24
27
|
this.loading = true;
|
|
25
28
|
this.error = null;
|
|
26
29
|
try {
|
|
27
|
-
this.summary = await
|
|
30
|
+
this.summary = await api.getDeliverableSummary(targetId);
|
|
31
|
+
if (signal.aborted) return;
|
|
28
32
|
} catch (err) {
|
|
33
|
+
if (signal.aborted) return;
|
|
29
34
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
30
35
|
} finally {
|
|
31
|
-
this.loading = false;
|
|
36
|
+
if (!signal.aborted) this.loading = false;
|
|
32
37
|
}
|
|
33
38
|
}
|
|
39
|
+
|
|
40
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
41
|
+
destroy() {
|
|
42
|
+
this.#fetchRequest.cancel();
|
|
43
|
+
}
|
|
34
44
|
}
|
|
35
45
|
|
|
36
46
|
export function createDeliverableSummaryState(
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { CriticalPathClient } from '@critical-path/client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tracks the latest request for one fetch method. Starting a new request aborts the previous
|
|
5
|
+
* one, so a slow response for old inputs can never overwrite newer state.
|
|
6
|
+
*/
|
|
7
|
+
export class LatestRequest {
|
|
8
|
+
private controller?: AbortController;
|
|
9
|
+
|
|
10
|
+
/** Aborts any in-flight request and returns a client and signal for the new one. */
|
|
11
|
+
begin(client: CriticalPathClient): { api: CriticalPathClient; signal: AbortSignal } {
|
|
12
|
+
this.controller?.abort();
|
|
13
|
+
this.controller = new AbortController();
|
|
14
|
+
const { signal } = this.controller;
|
|
15
|
+
// Duck-typed clients without with() still work; their requests just are not cancelled.
|
|
16
|
+
const api = typeof client.with === 'function' ? client.with({ signal }) : client;
|
|
17
|
+
return { api, signal };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
cancel(): void {
|
|
21
|
+
this.controller?.abort();
|
|
22
|
+
this.controller = undefined;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/// <reference types="svelte" />
|
|
2
2
|
import type { CriticalPathClient } from '@critical-path/client';
|
|
3
3
|
import type { Project } from '@critical-path/core';
|
|
4
|
+
import { LatestRequest } from './latest-request.js';
|
|
4
5
|
|
|
5
6
|
export class ProjectState {
|
|
7
|
+
#fetchRequest = new LatestRequest();
|
|
6
8
|
data = $state<Project[]>([]);
|
|
7
9
|
loading = $state<boolean>(false);
|
|
8
10
|
error = $state<Error | null>(null);
|
|
@@ -10,14 +12,17 @@ export class ProjectState {
|
|
|
10
12
|
constructor(private client: CriticalPathClient) {}
|
|
11
13
|
|
|
12
14
|
async fetch() {
|
|
15
|
+
const { api, signal } = this.#fetchRequest.begin(this.client);
|
|
13
16
|
this.loading = true;
|
|
14
17
|
this.error = null;
|
|
15
18
|
try {
|
|
16
|
-
this.data = await
|
|
19
|
+
this.data = await api.getProjects();
|
|
20
|
+
if (signal.aborted) return;
|
|
17
21
|
} catch (err) {
|
|
22
|
+
if (signal.aborted) return;
|
|
18
23
|
this.error = err instanceof Error ? err : new Error(String(err));
|
|
19
24
|
} finally {
|
|
20
|
-
this.loading = false;
|
|
25
|
+
if (!signal.aborted) this.loading = false;
|
|
21
26
|
}
|
|
22
27
|
}
|
|
23
28
|
|
|
@@ -47,6 +52,11 @@ export class ProjectState {
|
|
|
47
52
|
throw errorObj;
|
|
48
53
|
}
|
|
49
54
|
}
|
|
55
|
+
|
|
56
|
+
/** Cancels in-flight requests, e.g. from a component's onDestroy. */
|
|
57
|
+
destroy() {
|
|
58
|
+
this.#fetchRequest.cancel();
|
|
59
|
+
}
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
export function createProjectState(client: CriticalPathClient): ProjectState {
|