@datalayer/core 1.0.23 → 1.0.25

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.
Files changed (67) hide show
  1. package/README.md +30 -7
  2. package/lib/api/constants.d.ts +3 -0
  3. package/lib/api/constants.js +3 -0
  4. package/lib/api/index.d.ts +1 -0
  5. package/lib/api/index.js +1 -0
  6. package/lib/api/runtimes/checkpoints.d.ts +4 -4
  7. package/lib/api/runtimes/runtimes.d.ts +3 -3
  8. package/lib/api/scheduler/index.d.ts +6 -0
  9. package/lib/api/scheduler/index.js +10 -0
  10. package/lib/api/scheduler/schedules.d.ts +85 -0
  11. package/lib/api/scheduler/schedules.js +78 -0
  12. package/lib/components/checkout/StripeCheckout.js +48 -2
  13. package/lib/components/display/LiveRelativeTime.d.ts +1 -10
  14. package/lib/components/display/LiveRelativeTime.js +3 -18
  15. package/lib/components/index.d.ts +3 -0
  16. package/lib/components/index.js +3 -0
  17. package/lib/components/runtimes/RuntimePickerBase.js +18 -16
  18. package/lib/components/runtimes/RuntimePickerCell.js +1 -1
  19. package/lib/components/scheduler/ScheduleMenu.d.ts +54 -0
  20. package/lib/components/scheduler/ScheduleMenu.js +154 -0
  21. package/lib/components/scheduler/index.d.ts +1 -0
  22. package/lib/{views/iam-tokens → components/scheduler}/index.js +1 -3
  23. package/lib/components/time/LiveRelativeTime.d.ts +14 -0
  24. package/lib/components/time/LiveRelativeTime.js +39 -0
  25. package/lib/components/time/index.d.ts +1 -0
  26. package/lib/components/time/index.js +5 -0
  27. package/lib/components/timeline/Timeline.d.ts +20 -0
  28. package/lib/components/timeline/Timeline.js +90 -0
  29. package/lib/components/timeline/index.d.ts +1 -0
  30. package/lib/components/timeline/index.js +5 -0
  31. package/lib/hooks/useCache.d.ts +31 -1
  32. package/lib/hooks/useCache.js +221 -17
  33. package/lib/hooks/useProjectStore.d.ts +1 -1
  34. package/lib/hooks/useProjects.d.ts +2 -2
  35. package/lib/models/IAMToken.d.ts +1 -1
  36. package/lib/models/Page.d.ts +3 -0
  37. package/lib/models/ProjectDTO.d.ts +1 -1
  38. package/lib/models/ProjectDTO.js +1 -1
  39. package/lib/state/substates/CoreState.js +2 -2
  40. package/lib/utils/Date.d.ts +7 -0
  41. package/lib/utils/Date.js +43 -10
  42. package/lib/utils/Name.d.ts +1 -0
  43. package/lib/utils/Name.js +8 -0
  44. package/lib/utils/Snapshot.js +2 -2
  45. package/lib/utils/index.d.ts +1 -0
  46. package/lib/utils/index.js +1 -0
  47. package/lib/views/api-keys/APIKeyEdit.d.ts +8 -0
  48. package/lib/views/{iam-tokens/IAMTokenEdit.js → api-keys/APIKeyEdit.js} +31 -31
  49. package/lib/views/api-keys/APIKeyNew.d.ts +8 -0
  50. package/lib/views/api-keys/APIKeyNew.js +143 -0
  51. package/lib/views/api-keys/APIKeys.d.ts +12 -0
  52. package/lib/views/api-keys/APIKeys.js +119 -0
  53. package/lib/views/api-keys/APIKeysStandalone.d.ts +2 -0
  54. package/lib/views/api-keys/APIKeysStandalone.js +117 -0
  55. package/lib/views/api-keys/index.d.ts +3 -0
  56. package/lib/views/api-keys/index.js +7 -0
  57. package/package.json +1 -1
  58. package/lib/views/iam-tokens/IAMTokenEdit.d.ts +0 -6
  59. package/lib/views/iam-tokens/IAMTokenNew.d.ts +0 -8
  60. package/lib/views/iam-tokens/IAMTokenNew.js +0 -118
  61. package/lib/views/iam-tokens/IAMTokens.d.ts +0 -12
  62. package/lib/views/iam-tokens/IAMTokens.js +0 -87
  63. package/lib/views/iam-tokens/Tokens.d.ts +0 -2
  64. package/lib/views/iam-tokens/Tokens.js +0 -85
  65. package/lib/views/iam-tokens/index.d.ts +0 -3
  66. /package/lib/utils/{logger.d.ts → Logger.d.ts} +0 -0
  67. /package/lib/utils/{logger.js → Logger.js} +0 -0
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![Become a Sponsor](https://img.shields.io/static/v1?label=Become%20a%20Sponsor&message=%E2%9D%A4&logo=GitHub&style=flat&color=1ABC9C)](https://github.com/sponsors/datalayer)
4
4
 
5
- # ☰ Datalayer Core
5
+ # ☰ 🌀 Datalayer Core
6
6
 
7
7
  <p align="center">
8
8
  <strong>Python and Typescript libraries for Datalayer</strong>
@@ -12,7 +12,7 @@
12
12
  <a href="https://pypi.org/project/datalayer-core/"><img src="https://img.shields.io/pypi/v/datalayer-core.svg" alt="PyPI version"></img></a>
13
13
  <a href="https://pypi.org/project/datalayer-core/"><img src="https://img.shields.io/pypi/pyversions/datalayer-core.svg" alt="Python versions"></img></a>
14
14
  <a href="https://github.com/datalayer/core/blob/main/LICENSE"><img src="https://img.shields.io/badge/License-BSD%203--Clause-blue.svg" alt="License"></img></a>
15
- <a href="https://docs.datalayer.app/"><img src="https://img.shields.io/badge/docs-datalayer.app-blue" alt="Documentation"></img></a>
15
+ <a href="https://datalayer.ai/docs/"><img src="https://img.shields.io/badge/docs-datalayer.app-blue" alt="Documentation"></img></a>
16
16
  <a href="https://github.com/datalayer/core/actions/workflows/py-tests.yml"><img src="https://github.com/datalayer/core/actions/workflows/py-tests.yml/badge.svg" alt="Units Tests"></img></a><a href="https://github.com/datalayer/core/actions/workflows/ts-tests.yml"><img src="https://github.com/datalayer/core/actions/workflows/ts-tests.yml/badge.svg" alt="Units Tests"></img></a>
17
17
  </p>
18
18
 
@@ -118,7 +118,7 @@ datalayer runtime list
118
118
  datalayer runtime create ai-env --given-name my-runtime-123
119
119
 
120
120
  # Execute a script in a runtime
121
- datalayer runtime exec my-script.py --runtime <runtime-id>
121
+ datalayer runtime exec my-script.py --agent <agent-id>
122
122
 
123
123
  # Create a snapshot from a runtime but do not terminate the runtime
124
124
  datalayer snapshots create <pod-name> my-snapshot 'AI work!' False
@@ -151,6 +151,29 @@ datalayer usage team-allocate-member --team-uid <team_uid> --member-uid <member_
151
151
  datalayer usage team-revoke-member --team-uid <team_uid> --member-uid <member_uid> --amount 5
152
152
  ```
153
153
 
154
+ ### 5. Evals CLI (Multi-Agentspec)
155
+
156
+ Use comma-separated agentspec ids to create one experiment per agentspec variant:
157
+
158
+ ```bash
159
+ # Creates one experiment per agentspec in the list
160
+ datalayer evals experiments create my-exp \
161
+ --evalset-id <evalset_id> \
162
+ --agent-spec-ids example-evals,example-evals-nocodemode,example-custom
163
+ ```
164
+
165
+ Generate a comparison report:
166
+
167
+ ```bash
168
+ datalayer evals report <evalset_id> --run-limit 50 --export
169
+ ```
170
+
171
+ How to interpret grouped comparisons in the report:
172
+
173
+ - `Within-Agentspec Pairwise Latest-Pass Deltas`: compares experiments using the same agentspec id.
174
+ - `Cross-Agentspec Pairwise Latest-Pass Deltas`: compares experiments using different agentspec ids.
175
+ - Pairwise sections compute all combinations for the selected experiments, not just two agentspecs.
176
+
154
177
  ## Examples
155
178
 
156
179
  ### Python Examples
@@ -217,10 +240,10 @@ Key platform features accessible through this Client and CLI:
217
240
 
218
241
  ## Documentation
219
242
 
220
- - **Command Line Interface (CLI)**: [https://docs.datalayer.app/cli/](https://docs.datalayer.app/cli/)
243
+ - **Command Line Interface (CLI)**: [https://datalayer.ai/docs/cli/](https://datalayer.ai/docs/cli/)
221
244
  - **Core Python Client**: [core.datalayer.tech/python/](https://core.datalayer.tech/python/)
222
- - **Platform Documentation**: [docs.datalayer.app](https://docs.datalayer.app/)
223
- - **API Reference**: [API documentation](https://docs.datalayer.app/api/)
245
+ - **Platform Documentation**: [docs.datalayer.app](https://datalayer.ai/docs/)
246
+ - **API Reference**: [API documentation](https://datalayer.ai/docs/api/)
224
247
 
225
248
  ## Development
226
249
 
@@ -317,7 +340,7 @@ This project is licensed under the [BSD 3-Clause License](https://github.com/dat
317
340
 
318
341
  ## Support
319
342
 
320
- - **Documentation**: [Datalayer Platform Documentation](https://docs.datalayer.app/)
343
+ - **Documentation**: [Datalayer Platform Documentation](https://datalayer.ai/docs/)
321
344
  - **Issues**: [GitHub Issues](https://github.com/datalayer/core/issues)
322
345
  - **Community**: [Datalayer Platform](https://datalayer.app/)
323
346
 
@@ -6,6 +6,7 @@ export declare const API_BASE_PATHS: {
6
6
  readonly IAM: "/api/iam/v1";
7
7
  readonly OTEL: "/api/otel/v1";
8
8
  readonly RUNTIMES: "/api/runtimes/v1";
9
+ readonly SCHEDULER: "/api/scheduler/v1";
9
10
  readonly SPACER: "/api/spacer/v1";
10
11
  };
11
12
  /**
@@ -20,6 +21,8 @@ export declare const DEFAULT_SERVICE_URLS: {
20
21
  readonly OTEL: "https://prod1.datalayer.run";
21
22
  /** Default URL for Runtimes service */
22
23
  readonly RUNTIMES: "https://r1.datalayer.run";
24
+ /** Default URL for Scheduler (cron schedules and runs) service */
25
+ readonly SCHEDULER: "https://prod1.datalayer.run";
23
26
  /** Default URL for Spacer (workspaces and collaboration) service */
24
27
  readonly SPACER: "https://prod1.datalayer.run";
25
28
  };
@@ -10,6 +10,7 @@ export const API_BASE_PATHS = {
10
10
  IAM: '/api/iam/v1',
11
11
  OTEL: '/api/otel/v1',
12
12
  RUNTIMES: '/api/runtimes/v1',
13
+ SCHEDULER: '/api/scheduler/v1',
13
14
  SPACER: '/api/spacer/v1',
14
15
  };
15
16
  /**
@@ -24,6 +25,8 @@ export const DEFAULT_SERVICE_URLS = {
24
25
  OTEL: 'https://prod1.datalayer.run',
25
26
  /** Default URL for Runtimes service */
26
27
  RUNTIMES: 'https://r1.datalayer.run',
28
+ /** Default URL for Scheduler (cron schedules and runs) service */
29
+ SCHEDULER: 'https://prod1.datalayer.run',
27
30
  /** Default URL for Spacer (workspaces and collaboration) service */
28
31
  SPACER: 'https://prod1.datalayer.run',
29
32
  };
@@ -11,6 +11,7 @@ export type { IRequestDatalayerAPIOptions } from './DatalayerApi';
11
11
  export * as iam from './iam';
12
12
  export * as otel from './otel';
13
13
  export * as runtimes from './runtimes';
14
+ export * as scheduler from './scheduler';
14
15
  export * as spacer from './spacer';
15
16
  /**
16
17
  * @deprecated Please import directly from '@datalayer/core/stateful' instead.
package/lib/api/index.js CHANGED
@@ -16,6 +16,7 @@ export { requestDatalayerAPI, RunResponseError, NetworkError, } from './Datalaye
16
16
  export * as iam from './iam/index.js';
17
17
  export * as otel from './otel/index.js';
18
18
  export * as runtimes from './runtimes/index.js';
19
+ export * as scheduler from './scheduler/index.js';
19
20
  export * as spacer from './spacer/index.js';
20
21
  /**
21
22
  * @deprecated Please import directly from '@datalayer/core/stateful' instead.
@@ -10,9 +10,9 @@ export interface RuntimeCheckpointData {
10
10
  description: string;
11
11
  /** Runtime that was checkpointed */
12
12
  runtime_uid: string;
13
- /** Agent spec identifier (e.g. "mocks/monitor-sales-kpis") */
13
+ /** Agentspec identifier (e.g. "mocks/monitor-sales-kpis") */
14
14
  agent_spec_id: string;
15
- /** Full agent spec payload */
15
+ /** Full agentspec payload */
16
16
  agentspec: Record<string, any>;
17
17
  /** Additional metadata */
18
18
  metadata: Record<string, any>;
@@ -37,9 +37,9 @@ export interface CreateRuntimeCheckpointRequest {
37
37
  name?: string;
38
38
  /** Checkpoint description */
39
39
  description?: string;
40
- /** Agent spec identifier */
40
+ /** Agentspec identifier */
41
41
  agentspec_id?: string;
42
- /** Full agent spec payload to persist */
42
+ /** Full agentspec payload to persist */
43
43
  agentspec?: Record<string, any>;
44
44
  /** Additional metadata */
45
45
  metadata?: Record<string, any>;
@@ -73,9 +73,9 @@ export interface PauseRuntimeBody {
73
73
  name?: string;
74
74
  /** Checkpoint description */
75
75
  description?: string;
76
- /** Agent spec identifier */
76
+ /** Agentspec identifier */
77
77
  agent_spec_id?: string;
78
- /** Full agent spec payload to persist with the checkpoint */
78
+ /** Full agentspec payload to persist with the checkpoint */
79
79
  agentspec?: Record<string, any>;
80
80
  /** Additional metadata */
81
81
  metadata?: Record<string, any>;
@@ -107,7 +107,7 @@ export interface ResumeRuntimeBody {
107
107
  checkpoint_mode?: 'criu' | 'light';
108
108
  /** Explicit checkpoint identifier */
109
109
  checkpoint_id?: string;
110
- /** Agent spec identifier (required by the operator for restore) */
110
+ /** Agentspec identifier (required by the operator for restore) */
111
111
  agent_spec_id?: string;
112
112
  /** Specific checkpoint timestamp to restore from */
113
113
  checkpoint_timestamp?: string;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Scheduler API module for the Datalayer platform.
3
+ *
4
+ * @module api/scheduler
5
+ */
6
+ export * from './schedules';
@@ -0,0 +1,10 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Scheduler API module for the Datalayer platform.
7
+ *
8
+ * @module api/scheduler
9
+ */
10
+ export * from './schedules.js';
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Raw schedule document as returned by the scheduler service.
3
+ *
4
+ * Fields follow the Solr suffix convention (`_s`, `_b`, `_dt`, `_i`).
5
+ */
6
+ export interface ScheduleDoc {
7
+ uid?: string;
8
+ type_s?: string;
9
+ notebook_uid_s?: string;
10
+ owner_uid_s?: string;
11
+ cron_expression_s?: string;
12
+ preset_s?: string;
13
+ enabled_b?: boolean;
14
+ [key: string]: unknown;
15
+ }
16
+ /**
17
+ * Request payload to create or update a notebook schedule.
18
+ */
19
+ export interface UpsertScheduleRequest {
20
+ /** Target notebook uid. */
21
+ notebookUid: string;
22
+ /** Cron expression (e.g. `* * * * *`). */
23
+ cronExpression: string;
24
+ /** Optional preset identifier (e.g. `every-minute`, `hourly`, `daily`, `custom`). */
25
+ preset?: string;
26
+ /** Whether the schedule is enabled. Defaults to `true`. */
27
+ enabled?: boolean;
28
+ }
29
+ /**
30
+ * Request payload to update an existing schedule by uid.
31
+ */
32
+ export interface UpdateScheduleRequest {
33
+ cronExpression?: string;
34
+ preset?: string;
35
+ enabled?: boolean;
36
+ }
37
+ /**
38
+ * Response shape for listing schedules.
39
+ */
40
+ export interface ListSchedulesResponse {
41
+ success: boolean;
42
+ message: string;
43
+ schedules: ScheduleDoc[];
44
+ }
45
+ /**
46
+ * Response shape for a single schedule mutation.
47
+ */
48
+ export interface ScheduleResponse {
49
+ success: boolean;
50
+ message: string;
51
+ schedule: ScheduleDoc;
52
+ }
53
+ /**
54
+ * List the schedules owned by the authenticated user.
55
+ * @param token - Authentication token
56
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
57
+ * @param includeDisabled - Include disabled schedules in the result
58
+ * @returns Promise resolving to the list of schedules
59
+ */
60
+ export declare const listSchedules: (token: string, baseUrl?: string, includeDisabled?: boolean) => Promise<ListSchedulesResponse>;
61
+ /**
62
+ * Create or update the schedule for a notebook.
63
+ * @param token - Authentication token
64
+ * @param data - Schedule configuration
65
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
66
+ * @returns Promise resolving to the upserted schedule
67
+ */
68
+ export declare const upsertSchedule: (token: string, data: UpsertScheduleRequest, baseUrl?: string) => Promise<ScheduleResponse>;
69
+ /**
70
+ * Update an existing schedule by uid.
71
+ * @param token - Authentication token
72
+ * @param scheduleUid - The schedule uid
73
+ * @param data - Fields to update
74
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
75
+ * @returns Promise resolving to the updated schedule
76
+ */
77
+ export declare const updateSchedule: (token: string, scheduleUid: string, data: UpdateScheduleRequest, baseUrl?: string) => Promise<ScheduleResponse>;
78
+ /**
79
+ * Disable a schedule by uid.
80
+ * @param token - Authentication token
81
+ * @param scheduleUid - The schedule uid
82
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
83
+ * @returns Promise resolving to the disabled schedule
84
+ */
85
+ export declare const disableSchedule: (token: string, scheduleUid: string, baseUrl?: string) => Promise<ScheduleResponse>;
@@ -0,0 +1,78 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * Scheduler schedules API functions for the Datalayer platform.
7
+ *
8
+ * Provides functions for listing, creating, and updating cron schedules that
9
+ * trigger automated notebook executions.
10
+ *
11
+ * @module api/scheduler/schedules
12
+ */
13
+ import { requestDatalayerAPI } from '../DatalayerApi.js';
14
+ import { API_BASE_PATHS, DEFAULT_SERVICE_URLS } from '../constants.js';
15
+ /**
16
+ * List the schedules owned by the authenticated user.
17
+ * @param token - Authentication token
18
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
19
+ * @param includeDisabled - Include disabled schedules in the result
20
+ * @returns Promise resolving to the list of schedules
21
+ */
22
+ export const listSchedules = async (token, baseUrl = DEFAULT_SERVICE_URLS.SCHEDULER, includeDisabled = false) => {
23
+ const query = includeDisabled ? '?includeDisabled=true' : '';
24
+ return requestDatalayerAPI({
25
+ url: `${baseUrl}${API_BASE_PATHS.SCHEDULER}/schedules${query}`,
26
+ method: 'GET',
27
+ token,
28
+ });
29
+ };
30
+ /**
31
+ * Create or update the schedule for a notebook.
32
+ * @param token - Authentication token
33
+ * @param data - Schedule configuration
34
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
35
+ * @returns Promise resolving to the upserted schedule
36
+ */
37
+ export const upsertSchedule = async (token, data, baseUrl = DEFAULT_SERVICE_URLS.SCHEDULER) => {
38
+ return requestDatalayerAPI({
39
+ url: `${baseUrl}${API_BASE_PATHS.SCHEDULER}/schedules`,
40
+ method: 'POST',
41
+ token,
42
+ body: {
43
+ enabled: true,
44
+ preset: 'custom',
45
+ ...data,
46
+ },
47
+ });
48
+ };
49
+ /**
50
+ * Update an existing schedule by uid.
51
+ * @param token - Authentication token
52
+ * @param scheduleUid - The schedule uid
53
+ * @param data - Fields to update
54
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
55
+ * @returns Promise resolving to the updated schedule
56
+ */
57
+ export const updateSchedule = async (token, scheduleUid, data, baseUrl = DEFAULT_SERVICE_URLS.SCHEDULER) => {
58
+ return requestDatalayerAPI({
59
+ url: `${baseUrl}${API_BASE_PATHS.SCHEDULER}/schedules/${scheduleUid}`,
60
+ method: 'PUT',
61
+ token,
62
+ body: data,
63
+ });
64
+ };
65
+ /**
66
+ * Disable a schedule by uid.
67
+ * @param token - Authentication token
68
+ * @param scheduleUid - The schedule uid
69
+ * @param baseUrl - Base URL for the scheduler service (defaults to production)
70
+ * @returns Promise resolving to the disabled schedule
71
+ */
72
+ export const disableSchedule = async (token, scheduleUid, baseUrl = DEFAULT_SERVICE_URLS.SCHEDULER) => {
73
+ return requestDatalayerAPI({
74
+ url: `${baseUrl}${API_BASE_PATHS.SCHEDULER}/schedules/${scheduleUid}/disable`,
75
+ method: 'POST',
76
+ token,
77
+ });
78
+ };
@@ -670,6 +670,37 @@ export function StripeCheckout({ checkoutPortal, appearance, accountUid, showSta
670
670
  }
671
671
  void startSubscriptionCheckout(pendingSubscriptionPlan);
672
672
  }, [pendingSubscriptionPlan, startSubscriptionCheckout]);
673
+ // Auto-open the subscription checkout when the page is opened with
674
+ // `?upgrade` or `?action=upgrade` (e.g. from the Plan Overview
675
+ // "Upgrade to Team Plan" CTA).
676
+ useEffect(() => {
677
+ if (typeof window === 'undefined') {
678
+ return;
679
+ }
680
+ if (autoActionTriggeredRef.current) {
681
+ return;
682
+ }
683
+ if (isPaidSubscription || isCancellationScheduled) {
684
+ return;
685
+ }
686
+ try {
687
+ const params = new URLSearchParams(window.location.search);
688
+ const action = String(params.get('action') || '').toLowerCase();
689
+ const shouldAutoUpgrade = params.has('upgrade') || action === 'upgrade';
690
+ if (shouldAutoUpgrade && pendingSubscriptionPlan) {
691
+ autoActionTriggeredRef.current = true;
692
+ startPendingSubscriptionCheckout();
693
+ }
694
+ }
695
+ catch (_error) {
696
+ // Ignore malformed URLs.
697
+ }
698
+ }, [
699
+ isPaidSubscription,
700
+ isCancellationScheduled,
701
+ pendingSubscriptionPlan,
702
+ startPendingSubscriptionCheckout,
703
+ ]);
673
704
  const openPortal = useCallback((url) => {
674
705
  if (!url) {
675
706
  return;
@@ -825,7 +856,22 @@ export function StripeCheckout({ checkoutPortal, appearance, accountUid, showSta
825
856
  checkout ||
826
857
  !pendingSubscriptionPlan, children: subscriptionPaymentIntentMutation.isPending
827
858
  ? 'Preparing checkout...'
828
- : 'Continue pending payment' }), _jsx(Button, { variant: "danger", onClick: onCancelSubscription, children: "Cancel pending plan change" })] })] })) : !isPaidSubscription ? (_jsxs(_Fragment, { children: [_jsxs(Box, { role: "radiogroup", sx: {
859
+ : 'Continue pending payment' }), _jsx(Button, { variant: "danger", onClick: onCancelSubscription, children: "Cancel pending plan change" })] }), cancelViewOpen && (_jsxs(Box, { sx: {
860
+ marginTop: 'var(--stack-gap-normal)',
861
+ border: '1px solid',
862
+ borderColor: 'border.default',
863
+ borderRadius: 'var(--borderRadius-medium)',
864
+ backgroundColor: 'canvas.subtle',
865
+ padding: 'var(--stack-padding-normal)',
866
+ display: 'grid',
867
+ gap: 'var(--stack-gap-condensed)',
868
+ }, children: [_jsx(Text, { as: "h4", sx: { fontWeight: 'bold' }, children: "Cancel pending plan change" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted' }, children: "This pending plan change will be canceled immediately." }), _jsxs(Box, { sx: {
869
+ display: 'flex',
870
+ gap: 'var(--stack-gap-condensed)',
871
+ flexWrap: 'wrap',
872
+ }, children: [_jsx(Button, { variant: "danger", onClick: () => void onConfirmCancelSubscription(), disabled: isCancelActionPending, leadingVisual: () => isCancelActionPending ? _jsx(Spinner, { size: "small" }) : undefined, children: isCancelActionPending
873
+ ? 'Canceling pending plan change...'
874
+ : 'Confirm cancel pending plan change' }), _jsx(Button, { variant: "default", onClick: onAbortCancelView, disabled: isCancelActionPending, children: "Keep pending plan change" })] })] }))] })) : !isPaidSubscription ? (_jsxs(_Fragment, { children: [_jsxs(Box, { role: "radiogroup", sx: {
829
875
  display: 'grid',
830
876
  gap: 'var(--stack-gap-condensed)',
831
877
  maxHeight: '260px',
@@ -847,7 +893,7 @@ export function StripeCheckout({ checkoutPortal, appearance, accountUid, showSta
847
893
  subscriptionPaymentIntentMutation.isPending ||
848
894
  checkout, children: subscriptionPaymentIntentMutation.isPending
849
895
  ? 'Preparing Team plan checkout...'
850
- : 'Update to Team Plan' })] })) : null] })) : null;
896
+ : 'Upgrade to Team Plan' })] })) : null] })) : null;
851
897
  const topUpSection = (_jsxs(Box, { children: [_jsx(Text, { as: "h3", sx: sectionTitleSx, children: "Topup your wallet with credits" }), _jsx(Box, { role: "radiogroup", sx: {
852
898
  display: 'grid',
853
899
  gap: 'var(--stack-gap-normal)',
@@ -1,10 +1 @@
1
- type ILiveRelativeTimeProps = {
2
- value?: Date | string | number;
3
- refreshIntervalMs?: number;
4
- fallback?: string;
5
- };
6
- /**
7
- * Display a live-updating relative time label (e.g. "5m ago").
8
- */
9
- export declare function LiveRelativeTime({ value, refreshIntervalMs, fallback, }: ILiveRelativeTimeProps): JSX.Element;
10
- export {};
1
+ export { LiveRelativeTime } from '../time/LiveRelativeTime';
@@ -1,21 +1,6 @@
1
- import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
1
  /*
3
- * Copyright (c) 2023-2025 Datalayer, Inc.
2
+ * Copyright (c) 2023-2026 Datalayer, Inc.
4
3
  * Distributed under the terms of the Modified BSD License.
5
4
  */
6
- import { useEffect, useMemo, useState } from 'react';
7
- import { formatRelativeTime } from '../../utils/index.js';
8
- /**
9
- * Display a live-updating relative time label (e.g. "5m ago").
10
- */
11
- export function LiveRelativeTime({ value, refreshIntervalMs = 1000, fallback = '—', }) {
12
- const [now, setNow] = useState(() => new Date());
13
- useEffect(() => {
14
- const timer = window.setInterval(() => {
15
- setNow(new Date());
16
- }, refreshIntervalMs);
17
- return () => window.clearInterval(timer);
18
- }, [refreshIntervalMs]);
19
- const label = useMemo(() => formatRelativeTime(value, now), [value, now]);
20
- return _jsx(_Fragment, { children: label ?? fallback });
21
- }
5
+ // Backward compatibility export. Use ../../components/time/LiveRelativeTime.
6
+ export { LiveRelativeTime } from '../time/LiveRelativeTime.js';
@@ -1,4 +1,7 @@
1
1
  export * from './auth';
2
2
  export * from './billing';
3
+ export * from './scheduler';
3
4
  export * from './sharing';
4
5
  export * from './sparklines';
6
+ export * from './time';
7
+ export * from './timeline';
@@ -4,5 +4,8 @@
4
4
  */
5
5
  export * from './auth/index.js';
6
6
  export * from './billing/index.js';
7
+ export * from './scheduler/index.js';
7
8
  export * from './sharing/index.js';
8
9
  export * from './sparklines/index.js';
10
+ export * from './time/index.js';
11
+ export * from './timeline/index.js';
@@ -85,24 +85,26 @@ export function RuntimePickerBase(props) {
85
85
  // icon={() => <kernelIcon.react className="dla-Cell-runtime-icon" tag={'span'} />}
86
86
  icon: () => (_jsx("span", { className: "dla-Cell-runtime-icon", children: _jsx(CpuIcon, {}) })), "aria-label": trans.__('Assign a Runtime to the Cell.'), title: trans.__('Assign a Runtime to the Cell.'), size: "small", variant: "invisible" }) })) : (_jsxs(ActionMenu.Button, { variant: "default", disabled: disabled || groupedRuntimeDescs === null, children: [_jsx(Text, { fontWeight: 'bold', children: trans.__('Runtime:') }), ' ' + (runtimeDesc?.displayName ?? trans.__('No Runtime'))] })), _jsx(ActionMenu.Overlay, { ...overlayProps, width: "medium", sx: { overflowY: 'auto' }, side: variant === 'cell' ? 'outside-left' : 'outside-right', children: _jsxs(ActionList, { selectionVariant: "single", children: [variant === 'cell' && (_jsxs(ActionList.Item, { selected: runtimeDesc === undefined, onSelect: () => {
87
87
  setRuntimeDesc(undefined);
88
- }, children: [preference?.location && (_jsx(ActionList.LeadingVisual, { children: preference.location === 'local' ? (_jsx(LaptopSimpleIcon, {})) : preference.location === 'browser' ? (_jsx(BrowserIcon, {})) : (_jsx(CloudUploadIcon, {})) })), trans.__('Assign the Notebook Runtime')] }, 'null')), !!preActions && preActions, Object.entries(groupedRuntimeDescs ?? {}).map(([group, runtimeDescs]) => (_jsxs(ActionList.Group, { children: [_jsx(ActionList.GroupHeading, { children: group }), runtimeDescs.map(runtimeDesc => {
89
- const annotation = runtimeDesc.podName
90
- ? ` - ${runtimeDesc.podName.split('-', 2).reverse()[0]}`
91
- : runtimeDesc.kernelId
92
- ? ` - ${runtimeDesc.kernelId}`
88
+ }, children: [preference?.location && (_jsx(ActionList.LeadingVisual, { children: preference.location === 'local' ? (_jsx(LaptopSimpleIcon, {})) : preference.location === 'browser' ? (_jsx(BrowserIcon, {})) : (_jsx(CloudUploadIcon, {})) })), trans.__('Assign the Notebook Runtime')] }, 'null')), !!preActions && preActions, Object.entries(groupedRuntimeDescs ?? {}).map(([group, runtimeDescs]) => (_jsxs(ActionList.Group, { children: [_jsx(ActionList.GroupHeading, { children: group }), runtimeDescs.map(candidateRuntimeDesc => {
89
+ const annotation = candidateRuntimeDesc.podName
90
+ ? ` - ${candidateRuntimeDesc.podName.split('-', 2).reverse()[0]}`
91
+ : candidateRuntimeDesc.kernelId
92
+ ? ` - ${candidateRuntimeDesc.kernelId}`
93
93
  : '';
94
- const fullDisplayName = (runtimeDesc.displayName ?? '') + annotation;
95
- const displayName = (runtimeDesc.displayName?.length ?? 0) >
94
+ const fullDisplayName = (candidateRuntimeDesc.displayName ?? '') + annotation;
95
+ const displayName = (candidateRuntimeDesc.displayName?.length ?? 0) >
96
96
  RUNTIME_DISPLAY_NAME_MAX_LENGTH
97
- ? runtimeDesc.displayName.slice(0, RUNTIME_DISPLAY_NAME_MAX_LENGTH) + '…'
98
- : (runtimeDesc.displayName ?? '');
99
- return (_jsxs(ActionList.Item, { title: fullDisplayName, selected: (runtimeDesc.location === runtimeDesc?.location ||
100
- (isRuntimeRemote(runtimeDesc.location) &&
97
+ ? candidateRuntimeDesc.displayName.slice(0, RUNTIME_DISPLAY_NAME_MAX_LENGTH) + '…'
98
+ : (candidateRuntimeDesc.displayName ?? '');
99
+ return (_jsxs(ActionList.Item, { title: fullDisplayName, selected: (candidateRuntimeDesc.location ===
100
+ runtimeDesc?.location ||
101
+ (isRuntimeRemote(candidateRuntimeDesc.location) &&
101
102
  isRuntimeRemote(runtimeDesc?.location ?? 'local'))) &&
102
- (runtimeDesc.kernelId ?? runtimeDesc.name) ===
103
+ (candidateRuntimeDesc.kernelId ??
104
+ candidateRuntimeDesc.name) ===
103
105
  (runtimeDesc?.kernelId ?? runtimeDesc?.name), onSelect: () => {
104
- setRuntimeDesc(runtimeDesc);
105
- }, children: [_jsx(ActionList.LeadingVisual, { children: runtimeDesc.location === 'local' ? (_jsx(LaptopSimpleIcon, {})) : runtimeDesc.location === 'browser' ? (_jsx(BrowserIcon, {})) : (_jsx(CloudUploadIcon, {})) }), displayName + annotation.slice(0, 10)] }, runtimeDesc.name));
106
+ setRuntimeDesc(candidateRuntimeDesc);
107
+ }, children: [_jsx(ActionList.LeadingVisual, { children: candidateRuntimeDesc.location === 'local' ? (_jsx(LaptopSimpleIcon, {})) : candidateRuntimeDesc.location === 'browser' ? (_jsx(BrowserIcon, {})) : (_jsx(CloudUploadIcon, {})) }), displayName + annotation.slice(0, 10)] }, candidateRuntimeDesc.name));
106
108
  })] }, group))), !!postActions && (_jsxs(_Fragment, { children: [_jsx(ActionList.Divider, {}), postActions] }))] }) })] })) : (
107
109
  /*
108
110
  * Section for Radio display.
@@ -110,9 +112,9 @@ export function RuntimePickerBase(props) {
110
112
  _jsxs(_Fragment, { children: [defaultSet && (_jsx(RadioGroup, { name: "kernel-options", "aria-labelledby": "kernel-options", children: Object.entries(groupedRuntimeDescs ?? {}).map(([group, runtimeDescs]) => (_jsxs(Box, { children: [_jsx(Box, { as: "h4", style: { marginTop: 0 }, children: group }), runtimeDescs.map(k => {
111
113
  return (_jsxs(Box, { title: k.name, children: [_jsxs(FormControl, { children: [_jsx(Radio, { value: k.kernelId, onChange: () => {
112
114
  setRuntimeDesc(k);
113
- }, checked: (k.location === k?.location ||
115
+ }, checked: (k.location === runtimeDesc?.location ||
114
116
  (isRuntimeRemote(k.location) &&
115
- isRuntimeRemote(k?.location ?? 'local'))) &&
117
+ isRuntimeRemote(runtimeDesc?.location ?? 'local'))) &&
116
118
  (k.kernelId ?? k.name) ===
117
119
  (runtimeDesc?.kernelId ?? runtimeDesc?.name) }), _jsx(FormControl.Label, { children: _jsxs(Box, { display: "flex", children: [_jsx(Box, { children: k.displayName }), k.kernelId && k.location === 'remote' && (_jsx(Box, { ml: 3, mt: 1, children: _jsx(CreditsIndicator, { kernelId: k.kernelId, serviceManager: multiServiceManager.remote }, "credits-indicator") }))] }) }), _jsx(FormControl.Caption, { children: _jsxs(LabelGroup, { sx: { marginTop: 1 }, children: [_jsx(Label, { variant: "secondary", children: k.name }), _jsx(Label, { variant: "secondary", sx: { marginLeft: 1 }, children: k.location }), k.burningRate && (_jsxs(Label, { variant: "sponsors", sx: { marginLeft: 1 }, children: [k.burningRate, " credits/second"] })), k.gpu && (_jsx(Label, { variant: "success", sx: { marginLeft: 1 }, children: "GPU" }))] }) })] }), _jsx(ActionList.Divider, {})] }, k.kernelId));
118
120
  })] }, group))) })), !!postActions && _jsx(_Fragment, { children: postActions })] })) }));
@@ -99,6 +99,6 @@ export function RuntimePickerCell(props) {
99
99
  const datalayerMeta = model.getMetadata('datalayer') ?? {};
100
100
  return (_jsxs(_Fragment, { children: [_jsx(RuntimePickerBase, { display: "menu", filterRuntime: filterKernel, preference: preference, multiServiceManager: multiServiceManager, runtimeDesc: datalayerMeta.kernel ? datalayerMeta.kernel : undefined, setRuntimeDesc: setSelectedRuntimeDesc, variant: 'cell', preActions: _jsxs(ActionList.Item, { disabled: !multiServiceManager.remote, onSelect: setCell, selected: hasCellRuntime, title: !multiServiceManager.remote
101
101
  ? 'You are not connected with Datalayer.'
102
- : 'Assign a new temporary Runtime on each Cell execution.', children: [_jsx(ActionList.LeadingVisual, { children: _jsx(CloudUploadIcon, {}) }), trans.__('Assign a Cell Runtime')] }), postActions: token || !logIn ? (_jsxs(_Fragment, { children: [RuntimeSnippetsFacade.supports(preference?.language ?? '') && (_jsx(ActionList.Item, { onSelect: openVariableDialog, disabled: !isForeign, title: trans.__('Define variables to transfer between the document kernel and the cell kernel.'), children: trans.__('Define Cell Variables Transfer') })), !configuration.whiteLabel && (_jsx(ActionList.Item, { onSelect: openSnippetDialog, disabled: snippets.length === 0, title: trans.__('Inject a code snippet at the end of the cell.'), children: trans.__('Inject Code Snippet') }))] })) : (_jsx(ActionList.Item, { onSelect: props.logIn, title: 'Connect to the Runtime provider.', children: _jsx(ExternalTokenSilentLogin, { message: "Connect to the Runtime provider" }) })), translator: translator }), isVariableDialogOpen && (_jsx(RuntimeCellVariablesDialog, { model: model, onClose: closeVariableDialog, preference: preference, sessionContext: sessionContext, translator: translator })), isSnippetDialogOpen && (_jsx(SnippetDialog, { language: language, model: model, snippets: snippets, onClose: closeSnippetDialog, markdownParser: markdownParser, sanitizer: sanitizer })), isKernelDialogOpen && (_jsx(RuntimeLauncherDialog, { manager: multiServiceManager.remote, onSubmit: onStartRemote, startRuntime: true, submitLabel: "Assign", markdownParser: markdownParser, sanitizer: sanitizer }))] }));
102
+ : 'Assign a new temporary Runtime on each Cell execution.', children: [_jsx(ActionList.LeadingVisual, { children: _jsx(CloudUploadIcon, {}) }), trans.__('Assign a Cell Runtime')] }), postActions: token || !logIn ? (_jsxs(_Fragment, { children: [RuntimeSnippetsFacade.supports(preference?.language ?? '') && (_jsx(ActionList.Item, { onSelect: openVariableDialog, disabled: !isForeign, title: trans.__('Define variables to transfer between the document kernel and the cell kernel.'), children: trans.__('Define Cell Variables Transfer') })), !configuration.whiteLabel && (_jsx(ActionList.Item, { onSelect: openSnippetDialog, disabled: snippets.length === 0, title: trans.__('Inject a code snippet at the end of the cell.'), children: trans.__('Inject Code Snippet') }))] })) : (_jsx(ActionList.Item, { onSelect: props.logIn, title: 'Connect to the Runtime provider.', children: _jsx(ExternalTokenSilentLogin, { message: "Connect to the Runtime provider" }) })), translator: translator }), isVariableDialogOpen && (_jsx(RuntimeCellVariablesDialog, { model: model, onClose: closeVariableDialog, preference: preference, sessionContext: sessionContext, translator: translator })), isSnippetDialogOpen && (_jsx(SnippetDialog, { language: language, model: model, snippets: snippets, onClose: closeSnippetDialog, markdownParser: markdownParser, sanitizer: sanitizer })), isKernelDialogOpen && (_jsx(RuntimeLauncherDialog, { manager: multiServiceManager.remote, onSubmit: onStartRemote, startRuntime: 'defer', submitLabel: "Assign", markdownParser: markdownParser, sanitizer: sanitizer }))] }));
103
103
  }
104
104
  export default RuntimePickerCell;
@@ -0,0 +1,54 @@
1
+ import { type Icon } from '@primer/octicons-react';
2
+ import { type ScheduleDoc } from '../../api/scheduler/schedules';
3
+ /**
4
+ * Supported schedule presets.
5
+ */
6
+ export type SchedulePreset = 'every-minute' | 'hourly' | 'daily' | 'custom';
7
+ /**
8
+ * Props for the self-contained {@link ScheduleMenu} component.
9
+ *
10
+ * The component performs the scheduler service calls internally. Provide the
11
+ * `notebookUid`, an authentication `token`, and the scheduler service
12
+ * `baseUrl` (configurable via props) to enable scheduling.
13
+ */
14
+ export type ScheduleMenuProps = {
15
+ /** Target notebook uid to schedule (used to create/update a schedule). */
16
+ notebookUid?: string;
17
+ /**
18
+ * Existing schedule uid to update in place. When provided, changes are
19
+ * persisted with a PUT update instead of a notebook upsert.
20
+ */
21
+ scheduleUid?: string;
22
+ /** Authentication token used for scheduler API calls. */
23
+ token?: string;
24
+ /** Base URL of the scheduler service. Defaults to the production service. */
25
+ baseUrl?: string;
26
+ /** Force-disable the menu. When omitted, the menu is enabled if a token and notebook uid are present. */
27
+ enabled?: boolean;
28
+ /** Icon shown on the anchor button (replaced by a spinner while saving). */
29
+ icon?: Icon;
30
+ /** Optional color for the anchor icon. */
31
+ iconColor?: string;
32
+ /** Accessible label for the anchor button. */
33
+ ariaLabel?: string;
34
+ /** Initial preset selection. */
35
+ initialPreset?: SchedulePreset;
36
+ /** Initial cron expression. */
37
+ initialCronExpression?: string;
38
+ /** Called after a schedule is successfully saved. */
39
+ onSaved?: (schedule: ScheduleDoc) => void;
40
+ /** Called after a schedule is successfully deleted/disabled. */
41
+ onDeleted?: (schedule: ScheduleDoc) => void;
42
+ /** Called when saving a schedule fails. */
43
+ onError?: (error: unknown) => void;
44
+ };
45
+ /**
46
+ * Self-contained schedule menu that lets a user pick a cron schedule for a
47
+ * notebook and persists it to the scheduler service.
48
+ *
49
+ * The component owns its loading state and renders a spinner in place of the
50
+ * anchor icon while a save request is in flight. The scheduler service URL is
51
+ * configurable through the `baseUrl` prop.
52
+ */
53
+ export declare const ScheduleMenu: ({ notebookUid, scheduleUid, token, baseUrl, enabled, icon, iconColor, ariaLabel, initialPreset, initialCronExpression, onSaved, onDeleted, onError, }: ScheduleMenuProps) => import("react/jsx-runtime").JSX.Element;
54
+ export default ScheduleMenu;