@critical-path/svelte 0.14.0 → 0.15.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.
@@ -0,0 +1,26 @@
1
+ import type { CriticalPathClient } from '@critical-path/client';
2
+ import type { WorkloadDistribution, WorkloadDistributionOptions, WorkloadInterval, WorkloadGroupBy, WorkloadMetric, WorkloadBucket } from '@critical-path/core';
3
+ export declare class WorkloadState {
4
+ private client;
5
+ projectId?: string | undefined;
6
+ initialOptions?: WorkloadDistributionOptions | undefined;
7
+ data: WorkloadDistribution | null;
8
+ interval: WorkloadInterval;
9
+ groupBy: WorkloadGroupBy;
10
+ metric: WorkloadMetric;
11
+ loading: boolean;
12
+ error: Error | null;
13
+ buckets: WorkloadBucket[];
14
+ seriesKeys: string[];
15
+ seriesLabels: Record<string, string>;
16
+ totalHours: number;
17
+ totalCapacity: number;
18
+ averageUtilization: number | undefined;
19
+ constructor(client: CriticalPathClient, projectId?: string | undefined, initialOptions?: WorkloadDistributionOptions | undefined);
20
+ setInterval(newInterval: WorkloadInterval): Promise<void>;
21
+ setGroupBy(newGroupBy: WorkloadGroupBy): Promise<void>;
22
+ setMetric(newMetric: WorkloadMetric): Promise<void>;
23
+ fetch(options?: WorkloadDistributionOptions): Promise<void>;
24
+ }
25
+ export declare function createWorkloadState(client: CriticalPathClient, projectId?: string, initialOptions?: WorkloadDistributionOptions): WorkloadState;
26
+ //# sourceMappingURL=workload-state.svelte.d.ts.map
@@ -0,0 +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;AAChE,OAAO,KAAK,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,cAAc,EACf,MAAM,qBAAqB,CAAC;AAE7B,qBAAa,aAAa;IAgBtB,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;CAiBlD;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.14.0",
3
+ "version": "0.15.1",
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/client": "0.11.0",
22
- "@critical-path/mcp": "0.4.0",
23
- "@critical-path/core": "0.17.0"
21
+ "@critical-path/core": "0.19.0",
22
+ "@critical-path/client": "0.12.1",
23
+ "@critical-path/mcp": "0.6.0"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "svelte": "^5.0.0"
package/src/index.test.ts CHANGED
@@ -28,7 +28,9 @@ import {
28
28
  TimelineLadderState,
29
29
  createTimelineLadderState,
30
30
  TaskMetricsState,
31
- createTaskMetricsState
31
+ createTaskMetricsState,
32
+ WorkloadState,
33
+ createWorkloadState
32
34
  } from './index.js';
33
35
  import type { CriticalPathClient } from '@critical-path/client';
34
36
  import type {
@@ -40,7 +42,8 @@ import type {
40
42
  Deliverable,
41
43
  DeliverableSummary,
42
44
  CriticalPathAnalysis,
43
- TimelineLadder
45
+ TimelineLadder,
46
+ WorkloadDistribution
44
47
  } from '@critical-path/core';
45
48
 
46
49
  describe('@critical-path/svelte Svelte 5 Runes Test Suite', () => {
@@ -735,6 +738,86 @@ describe('@critical-path/svelte Svelte 5 Runes Test Suite', () => {
735
738
  expect(state.curveProfile).toBe('linear');
736
739
  });
737
740
  });
741
+
742
+ describe('WorkloadState & createWorkloadState', () => {
743
+ it('initializes with default options and fetches workload distribution', async () => {
744
+ const mockDistribution: WorkloadDistribution = {
745
+ projectId: 'proj_wl',
746
+ startDate: '2026-09-01',
747
+ endDate: '2026-09-14',
748
+ interval: 'week',
749
+ groupBy: 'assignee',
750
+ metric: 'blended',
751
+ seriesKeys: ['u1', 'u2'],
752
+ seriesLabels: { u1: 'Alice', u2: 'Bob' },
753
+ buckets: [
754
+ {
755
+ date: '2026-09-01',
756
+ timestamp: 1788220800000,
757
+ totalHours: 40,
758
+ values: { u1: 25, u2: 15 },
759
+ capacity: { u1: 35, u2: 40 },
760
+ totalCapacity: 75,
761
+ utilizationRatio: 0.533
762
+ }
763
+ ],
764
+ totalHours: 40,
765
+ totalCapacity: 75,
766
+ averageUtilization: 0.533
767
+ };
768
+
769
+ const mockClient = {
770
+ getWorkloadDistribution: vi.fn().mockResolvedValue(mockDistribution)
771
+ } as unknown as CriticalPathClient;
772
+
773
+ const state = createWorkloadState(mockClient, 'proj_wl', {
774
+ interval: 'week',
775
+ groupBy: 'assignee',
776
+ metric: 'blended'
777
+ });
778
+
779
+ expect(state.data).toBeNull();
780
+ expect(state.buckets).toEqual([]);
781
+ expect(state.seriesKeys).toEqual([]);
782
+ expect(state.totalHours).toBe(0);
783
+
784
+ await state.fetch();
785
+
786
+ expect(mockClient.getWorkloadDistribution).toHaveBeenCalledWith('proj_wl', {
787
+ interval: 'week',
788
+ groupBy: 'assignee',
789
+ metric: 'blended'
790
+ });
791
+ expect(state.data).toEqual(mockDistribution);
792
+ expect(state.buckets).toHaveLength(1);
793
+ expect(state.seriesKeys).toEqual(['u1', 'u2']);
794
+ expect(state.totalHours).toBe(40);
795
+ expect(state.totalCapacity).toBe(75);
796
+ expect(state.averageUtilization).toBe(0.533);
797
+ });
798
+
799
+ it('updates interval and re-fetches', async () => {
800
+ const mockClient = {
801
+ getWorkloadDistribution: vi.fn().mockResolvedValue({
802
+ buckets: [],
803
+ seriesKeys: [],
804
+ seriesLabels: {},
805
+ totalHours: 0,
806
+ totalCapacity: 0
807
+ })
808
+ } as unknown as CriticalPathClient;
809
+
810
+ const state = new WorkloadState(mockClient, 'proj_wl');
811
+ expect(state.interval).toBe('week');
812
+
813
+ await state.setInterval('day');
814
+ expect(state.interval).toBe('day');
815
+ expect(mockClient.getWorkloadDistribution).toHaveBeenCalledWith(
816
+ 'proj_wl',
817
+ expect.objectContaining({ interval: 'day' })
818
+ );
819
+ });
820
+ });
738
821
  });
739
822
 
740
823
 
package/src/index.ts CHANGED
@@ -18,5 +18,6 @@ export * from './webmcp-state.svelte.js';
18
18
  export * from './critical-path-state.svelte.js';
19
19
  export * from './timeline-ladder-state.svelte.js';
20
20
  export * from './task-metrics-state.svelte.js';
21
+ export * from './workload-state.svelte.js';
21
22
 
22
23
 
@@ -0,0 +1,83 @@
1
+ /// <reference types="svelte" />
2
+ import type { CriticalPathClient } from '@critical-path/client';
3
+ import type {
4
+ WorkloadDistribution,
5
+ WorkloadDistributionOptions,
6
+ WorkloadInterval,
7
+ WorkloadGroupBy,
8
+ WorkloadMetric,
9
+ WorkloadBucket
10
+ } from '@critical-path/core';
11
+
12
+ export class WorkloadState {
13
+ data = $state<WorkloadDistribution | null>(null);
14
+ interval = $state<WorkloadInterval>('week');
15
+ groupBy = $state<WorkloadGroupBy>('assignee');
16
+ metric = $state<WorkloadMetric>('blended');
17
+ loading = $state<boolean>(false);
18
+ error = $state<Error | null>(null);
19
+
20
+ buckets = $derived<WorkloadBucket[]>(this.data?.buckets ?? []);
21
+ seriesKeys = $derived<string[]>(this.data?.seriesKeys ?? []);
22
+ seriesLabels = $derived<Record<string, string>>(this.data?.seriesLabels ?? {});
23
+ totalHours = $derived<number>(this.data?.totalHours ?? 0);
24
+ totalCapacity = $derived<number>(this.data?.totalCapacity ?? 0);
25
+ averageUtilization = $derived<number | undefined>(this.data?.averageUtilization);
26
+
27
+ constructor(
28
+ private client: CriticalPathClient,
29
+ public projectId?: string,
30
+ public initialOptions?: WorkloadDistributionOptions
31
+ ) {
32
+ if (initialOptions?.interval) {
33
+ this.interval = initialOptions.interval;
34
+ }
35
+ if (initialOptions?.groupBy) {
36
+ this.groupBy = initialOptions.groupBy;
37
+ }
38
+ if (initialOptions?.metric) {
39
+ this.metric = initialOptions.metric;
40
+ }
41
+ }
42
+
43
+ async setInterval(newInterval: WorkloadInterval) {
44
+ this.interval = newInterval;
45
+ await this.fetch();
46
+ }
47
+
48
+ async setGroupBy(newGroupBy: WorkloadGroupBy) {
49
+ this.groupBy = newGroupBy;
50
+ await this.fetch();
51
+ }
52
+
53
+ async setMetric(newMetric: WorkloadMetric) {
54
+ this.metric = newMetric;
55
+ await this.fetch();
56
+ }
57
+
58
+ async fetch(options?: WorkloadDistributionOptions) {
59
+ this.loading = true;
60
+ this.error = null;
61
+ try {
62
+ this.data = await this.client.getWorkloadDistribution(this.projectId, {
63
+ ...this.initialOptions,
64
+ interval: this.interval,
65
+ groupBy: this.groupBy,
66
+ metric: this.metric,
67
+ ...options
68
+ });
69
+ } catch (err) {
70
+ this.error = err instanceof Error ? err : new Error(String(err));
71
+ } finally {
72
+ this.loading = false;
73
+ }
74
+ }
75
+ }
76
+
77
+ export function createWorkloadState(
78
+ client: CriticalPathClient,
79
+ projectId?: string,
80
+ initialOptions?: WorkloadDistributionOptions
81
+ ): WorkloadState {
82
+ return new WorkloadState(client, projectId, initialOptions);
83
+ }