@datalayer/core 1.0.20 → 1.0.22

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 (138) hide show
  1. package/README.md +27 -0
  2. package/lib/api/DatalayerApi.d.ts +5 -1
  3. package/lib/api/DatalayerApi.js +55 -8
  4. package/lib/api/iam/oauth2.d.ts +3 -3
  5. package/lib/api/iam/oauth2.js +2 -2
  6. package/lib/api/iam/profile.d.ts +9 -1
  7. package/lib/api/iam/profile.js +15 -0
  8. package/lib/api/runtimes/checkpoints.js +1 -1
  9. package/lib/api/runtimes/snapshots.d.ts +7 -7
  10. package/lib/api/runtimes/snapshots.js +9 -9
  11. package/lib/client/auth/storage.js +103 -12
  12. package/lib/client/index.d.ts +7 -7
  13. package/lib/client/index.js +1 -1
  14. package/lib/client/mixins/RuntimesMixin.d.ts +6 -6
  15. package/lib/client/mixins/RuntimesMixin.js +5 -5
  16. package/lib/client/mixins/SpacerMixin.js +22 -1
  17. package/lib/collaboration/DatalayerCollaborationProvider.d.ts +4 -3
  18. package/lib/components/avatars/DLAvatar.d.ts +24 -0
  19. package/lib/components/avatars/DLAvatar.js +26 -0
  20. package/lib/components/avatars/UserProfileAvatar.js +4 -4
  21. package/lib/components/avatars/index.d.ts +1 -0
  22. package/lib/components/avatars/index.js +1 -0
  23. package/lib/components/billing/BillableAccountSelect.d.ts +35 -0
  24. package/lib/components/billing/BillableAccountSelect.js +340 -0
  25. package/lib/components/billing/index.d.ts +1 -0
  26. package/lib/components/billing/index.js +5 -0
  27. package/lib/components/checkout/StripeCheckout.d.ts +24 -3
  28. package/lib/components/checkout/StripeCheckout.js +1116 -55
  29. package/lib/components/display/DatalayerBox.js +6 -1
  30. package/lib/components/index.d.ts +2 -0
  31. package/lib/components/index.js +2 -0
  32. package/lib/components/principal/Principal.d.ts +37 -0
  33. package/lib/components/principal/Principal.js +54 -0
  34. package/lib/components/principal/PrincipalAvatar.d.ts +10 -0
  35. package/lib/components/principal/PrincipalAvatar.js +55 -0
  36. package/lib/components/principal/PrincipalBadge.d.ts +20 -0
  37. package/lib/components/principal/PrincipalBadge.js +208 -0
  38. package/lib/components/principal/PrincipalBanner.d.ts +7 -0
  39. package/lib/components/principal/PrincipalBanner.js +84 -0
  40. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +23 -0
  41. package/lib/components/principal/PrincipalDetailsOverlay.js +86 -0
  42. package/lib/components/principal/PrincipalSwitcherMenu.d.ts +14 -0
  43. package/lib/components/principal/PrincipalSwitcherMenu.js +287 -0
  44. package/lib/components/principal/index.d.ts +7 -0
  45. package/lib/components/principal/index.js +10 -0
  46. package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +2 -2
  47. package/lib/components/sharing/ShareAccessComponent.d.ts +18 -0
  48. package/lib/components/sharing/ShareAccessComponent.js +1368 -0
  49. package/lib/components/sharing/SharingEditor.d.ts +20 -0
  50. package/lib/components/sharing/SharingEditor.js +65 -0
  51. package/lib/components/sharing/index.d.ts +9 -0
  52. package/lib/components/sharing/index.js +12 -0
  53. package/lib/components/snapshots/{RuntimeSnapshotMenu.d.ts → SandboxSnapshotMenu.d.ts} +4 -4
  54. package/lib/components/snapshots/{RuntimeSnapshotMenu.js → SandboxSnapshotMenu.js} +33 -33
  55. package/lib/components/snapshots/index.d.ts +1 -1
  56. package/lib/components/snapshots/index.js +1 -1
  57. package/lib/components/storage/ContentsBrowser.js +2 -2
  58. package/lib/components/tokens/SpaceVariantToken.d.ts +1 -1
  59. package/lib/components/tokens/SpaceVariantToken.js +7 -4
  60. package/lib/components/users/PeerIndicator.js +5 -4
  61. package/lib/hooks/index.d.ts +5 -0
  62. package/lib/hooks/index.js +5 -0
  63. package/lib/hooks/useBillableAccountStore.d.ts +31 -0
  64. package/lib/hooks/useBillableAccountStore.js +53 -0
  65. package/lib/hooks/useCache.d.ts +125 -18
  66. package/lib/hooks/useCache.js +893 -120
  67. package/lib/hooks/useDatalayer.js +31 -3
  68. package/lib/hooks/useIAM.js +1 -8
  69. package/lib/hooks/usePrincipalStore.d.ts +41 -0
  70. package/lib/hooks/usePrincipalStore.js +101 -0
  71. package/lib/hooks/useProjects.d.ts +44 -0
  72. package/lib/hooks/useProjects.js +26 -2
  73. package/lib/hooks/useSelectedBillableAccount.d.ts +14 -0
  74. package/lib/hooks/useSelectedBillableAccount.js +36 -0
  75. package/lib/hooks/useSelectedPrincipal.d.ts +17 -0
  76. package/lib/hooks/useSelectedPrincipal.js +29 -0
  77. package/lib/hooks/useUsageRefreshStore.d.ts +8 -0
  78. package/lib/hooks/useUsageRefreshStore.js +16 -0
  79. package/lib/index.d.ts +2 -2
  80. package/lib/index.js +1 -1
  81. package/lib/mocks/components/FlashMock.js +8 -2
  82. package/lib/models/{RuntimeSnapshot.d.ts → CodeSandboxSnapshot.d.ts} +5 -5
  83. package/lib/models/{RuntimeSnapshot.js → CodeSandboxSnapshot.js} +1 -1
  84. package/lib/models/{RuntimeSnapshotDTO.d.ts → CodeSandboxSnapshotDTO.d.ts} +30 -30
  85. package/lib/models/{RuntimeSnapshotDTO.js → CodeSandboxSnapshotDTO.js} +6 -6
  86. package/lib/models/Environment.d.ts +4 -0
  87. package/lib/models/IAM.d.ts +66 -0
  88. package/lib/models/Organization.d.ts +1 -0
  89. package/lib/models/Organization.js +1 -0
  90. package/lib/models/Page.d.ts +2 -2
  91. package/lib/models/Page.js +2 -2
  92. package/lib/models/Profile.d.ts +1 -1
  93. package/lib/models/RuntimeDTO.d.ts +2 -2
  94. package/lib/models/Space.d.ts +1 -0
  95. package/lib/models/Space.js +29 -5
  96. package/lib/models/SpaceDTO.d.ts +4 -0
  97. package/lib/models/SpaceDTO.js +5 -0
  98. package/lib/models/Usage.d.ts +15 -0
  99. package/lib/models/Usage.js +9 -0
  100. package/lib/models/User.d.ts +21 -0
  101. package/lib/models/User.js +6 -2
  102. package/lib/models/index.d.ts +2 -2
  103. package/lib/models/index.js +2 -2
  104. package/lib/otel/auth.js +0 -4
  105. package/lib/services/index.d.ts +1 -1
  106. package/lib/services/index.js +1 -1
  107. package/lib/state/substates/IAMState.js +0 -7
  108. package/lib/state/substates/RuntimesState.d.ts +9 -9
  109. package/lib/state/substates/RuntimesState.js +3 -3
  110. package/lib/stateful/runtimes/actions.d.ts +17 -17
  111. package/lib/stateful/runtimes/actions.js +35 -55
  112. package/lib/stateful/runtimes/apis.d.ts +3 -3
  113. package/lib/stateful/runtimes/snapshots.d.ts +2 -2
  114. package/lib/stateful/runtimes/snapshots.js +7 -7
  115. package/lib/utils/Format.d.ts +6 -0
  116. package/lib/utils/Format.js +17 -0
  117. package/lib/utils/Handles.d.ts +3 -0
  118. package/lib/utils/Handles.js +53 -0
  119. package/lib/utils/Snapshot.d.ts +1 -1
  120. package/lib/utils/Snapshot.js +1 -1
  121. package/lib/utils/index.d.ts +1 -0
  122. package/lib/utils/index.js +1 -0
  123. package/lib/views/datasources/DatasourceDetail.d.ts +7 -1
  124. package/lib/views/datasources/DatasourceDetail.js +61 -23
  125. package/lib/views/datasources/DatasourceNew.d.ts +8 -1
  126. package/lib/views/datasources/DatasourceNew.js +23 -10
  127. package/lib/views/datasources/Datasources.d.ts +5 -1
  128. package/lib/views/datasources/Datasources.js +38 -30
  129. package/lib/views/iam-tokens/IAMTokenNew.d.ts +3 -1
  130. package/lib/views/iam-tokens/IAMTokenNew.js +2 -2
  131. package/lib/views/iam-tokens/IAMTokens.d.ts +3 -1
  132. package/lib/views/iam-tokens/IAMTokens.js +2 -2
  133. package/lib/views/otel/OtelHeader.d.ts +5 -0
  134. package/lib/views/otel/OtelHeader.js +3 -3
  135. package/lib/views/profile/UserBadge.d.ts +7 -2
  136. package/lib/views/profile/UserBadge.js +11 -2
  137. package/lib/views/secrets/Secrets.js +21 -21
  138. package/package.json +7 -8
@@ -0,0 +1,20 @@
1
+ export type SharingAccessLevel = 'view' | 'update' | 'execute';
2
+ export type SharingLevelPayload = {
3
+ userUids?: string[];
4
+ teamUids?: string[];
5
+ organizationUids?: string[];
6
+ };
7
+ export type SharingPayload = {
8
+ access?: Partial<Record<SharingAccessLevel, SharingLevelPayload>>;
9
+ };
10
+ export declare const EMPTY_SHARING_PAYLOAD: SharingPayload;
11
+ export type SharingEditorProps = {
12
+ value: SharingPayload;
13
+ onChange: (next: SharingPayload) => void;
14
+ label?: string;
15
+ caption?: string;
16
+ rows?: number;
17
+ disabled?: boolean;
18
+ };
19
+ export declare function SharingEditor({ value, onChange, label, caption, rows, disabled, }: SharingEditorProps): JSX.Element;
20
+ export default SharingEditor;
@@ -0,0 +1,65 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /*
3
+ * Copyright (c) 2023-2026 Datalayer, Inc.
4
+ * Distributed under the terms of the Modified BSD License.
5
+ */
6
+ /**
7
+ * SharingEditor — inline editor for the sharing payload shape used by
8
+ * `ShareAccessComponent` ACL endpoints.
9
+ *
10
+ * Unlike `ShareAccessComponent` (which is bound to a server-side resource
11
+ * via `requestUrl`), this component edits a free-form
12
+ * `{ access: { view/update/execute: { userUids, teamUids, organizationUids } } }`
13
+ * blob in memory. It is intended for "create" flows where the resource does
14
+ * not yet exist and the sharing payload must be POSTed alongside the rest of
15
+ * the configuration.
16
+ *
17
+ * This is a scaffold: it currently exposes a structured JSON editor with
18
+ * validation and the canonical default shape. Future iterations can replace
19
+ * the textarea with the same principal-picker UI used by
20
+ * `ShareAccessComponent`.
21
+ */
22
+ import { useEffect, useMemo, useState } from 'react';
23
+ import { Box } from '@datalayer/primer-addons';
24
+ import { FormControl, Text, Textarea } from '@primer/react';
25
+ export const EMPTY_SHARING_PAYLOAD = {
26
+ access: {
27
+ view: { userUids: [], teamUids: [], organizationUids: [] },
28
+ update: { userUids: [], teamUids: [], organizationUids: [] },
29
+ execute: { userUids: [], teamUids: [], organizationUids: [] },
30
+ },
31
+ };
32
+ const stringify = (value) => {
33
+ try {
34
+ return JSON.stringify(value ?? {}, null, 2);
35
+ }
36
+ catch {
37
+ return '{}';
38
+ }
39
+ };
40
+ export function SharingEditor({ value, onChange, label = 'Sharing', caption = 'Edit the sharing payload. Each access level (view/update/execute) can grant access to user, team, and organization UIDs.', rows = 10, disabled = false, }) {
41
+ const initial = useMemo(() => stringify(value), [value]);
42
+ const [raw, setRaw] = useState(initial);
43
+ const [error, setError] = useState(null);
44
+ useEffect(() => {
45
+ setRaw(stringify(value));
46
+ }, [value]);
47
+ return (_jsxs(FormControl, { disabled: disabled, children: [_jsx(FormControl.Label, { children: label }), _jsx(Textarea, { rows: rows, value: raw, onChange: event => {
48
+ const next = event.target.value;
49
+ setRaw(next);
50
+ if (!next.trim()) {
51
+ setError(null);
52
+ onChange({});
53
+ return;
54
+ }
55
+ try {
56
+ const parsed = JSON.parse(next);
57
+ setError(null);
58
+ onChange(parsed);
59
+ }
60
+ catch (reason) {
61
+ setError(reason?.message || 'Invalid JSON');
62
+ }
63
+ }, sx: { width: '100%', fontFamily: 'mono' } }), _jsx(FormControl.Caption, { children: caption }), error && (_jsx(Box, { sx: { mt: 1 }, children: _jsx(Text, { sx: { color: 'danger.fg', fontSize: 1 }, children: error }) }))] }));
64
+ }
65
+ export default SharingEditor;
@@ -0,0 +1,9 @@
1
+ export * from '../principal/Principal';
2
+ export * from '../principal/PrincipalAvatar';
3
+ export * from '../principal/PrincipalBadge';
4
+ export * from '../principal/PrincipalBanner';
5
+ export { buildPrincipalProfilePath, PrincipalDetailsOverlay, } from '../principal/PrincipalDetailsOverlay';
6
+ export type { PrincipalDetailsOverlayProps } from '../principal/PrincipalDetailsOverlay';
7
+ export * from '../principal/PrincipalSwitcherMenu';
8
+ export * from './ShareAccessComponent';
9
+ export * from './SharingEditor';
@@ -0,0 +1,12 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export * from '../principal/Principal.js';
6
+ export * from '../principal/PrincipalAvatar.js';
7
+ export * from '../principal/PrincipalBadge.js';
8
+ export * from '../principal/PrincipalBanner.js';
9
+ export { buildPrincipalProfilePath, PrincipalDetailsOverlay, } from '../principal/PrincipalDetailsOverlay.js';
10
+ export * from '../principal/PrincipalSwitcherMenu.js';
11
+ export * from './ShareAccessComponent.js';
12
+ export * from './SharingEditor.js';
@@ -2,9 +2,9 @@ import { type PropsWithChildren } from 'react';
2
2
  import { Kernel } from '@jupyterlab/services';
3
3
  import { IMultiServiceManager } from '../../stateful/runtimes';
4
4
  /**
5
- * Runtime snapshot menu component properties
5
+ * Code Sandbox snapshot menu component properties
6
6
  */
7
- type IRuntimeSnapshotMenu = {
7
+ type ICodeSandboxSnapshotMenu = {
8
8
  /**
9
9
  * Application multi service manager.
10
10
  */
@@ -27,7 +27,7 @@ type IRuntimeSnapshotMenu = {
27
27
  disabled: boolean;
28
28
  };
29
29
  /**
30
- * Runtime Snapshot menu component.
30
+ * Code Sandbox Snapshot menu component.
31
31
  */
32
- export declare function RuntimeSnapshotMenu({ children, connection, podName, multiServiceManager, disabled, }: PropsWithChildren<IRuntimeSnapshotMenu>): JSX.Element;
32
+ export declare function SandboxSnapshotMenu({ children, connection, podName, multiServiceManager, disabled, }: PropsWithChildren<ICodeSandboxSnapshotMenu>): JSX.Element;
33
33
  export {};
@@ -4,29 +4,29 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useCallback, useEffect, useState, } from 'react';
7
- import { CameraIcon } from '@datalayer/icons-react';
7
+ import { DeviceCameraIcon } from '@primer/octicons-react';
8
8
  import { ActionList, ActionMenu, Flash, FormControl, Select, Spinner, } from '@primer/react';
9
9
  import { Dialog } from '@primer/react/experimental';
10
10
  import { Box } from '@datalayer/primer-addons';
11
11
  import { useToast } from '../../hooks/index.js';
12
- import { createRuntimeSnapshot, getRuntimeSnapshots, loadBrowserRuntimeSnapshot, loadRuntimeSnapshot, } from '../../stateful/runtimes/index.js';
12
+ import { createSandboxSnapshot, getSandboxSnapshots, loadBrowserSandboxSnapshot, loadSandboxSnapshot, } from '../../stateful/runtimes/index.js';
13
13
  import { useRuntimesStore } from '../../state/index.js';
14
- import { createRuntimeSnapshotName } from '../../utils/index.js';
14
+ import { createSandboxSnapshotName } from '../../utils/index.js';
15
15
  /**
16
- * Runtime Snapshot menu component.
16
+ * Code Sandbox Snapshot menu component.
17
17
  */
18
- export function RuntimeSnapshotMenu({ children, connection, podName, multiServiceManager, disabled = false, }) {
19
- const { addRuntimeSnapshot, runtimesRunUrl, runtimeSnapshots, setRuntimeSnapshots, } = useRuntimesStore();
18
+ export function SandboxSnapshotMenu({ children, connection, podName, multiServiceManager, disabled = false, }) {
19
+ const { addSandboxSnapshot, runtimesRunUrl, runtimeSnapshots, setSandboxSnapshots, } = useRuntimesStore();
20
20
  const { enqueueToast, trackAsyncTask } = useToast();
21
21
  const [openLoadDialog, setOpenLoadDialog] = useState(false);
22
- const [loadingRuntimeSnapshot, setLoadingRuntimeSnapshot] = useState(false);
23
- const [takingRuntimeSnapshot, setTakingRuntimeSnapshot] = useState(false);
22
+ const [loadingSandboxSnapshot, setLoadingSandboxSnapshot] = useState(false);
23
+ const [takingSandboxSnapshot, setTakingSandboxSnapshot] = useState(false);
24
24
  const [selection, setSelection] = useState(runtimeSnapshots[0]?.id ?? '');
25
25
  const [error, setError] = useState();
26
26
  useEffect(() => {
27
- getRuntimeSnapshots()
27
+ getSandboxSnapshots()
28
28
  .then(snapshots => {
29
- setRuntimeSnapshots(snapshots);
29
+ setSandboxSnapshots(snapshots);
30
30
  if (!selection && snapshots.length > 0) {
31
31
  setSelection(snapshots[0].id);
32
32
  }
@@ -35,36 +35,36 @@ export function RuntimeSnapshotMenu({ children, connection, podName, multiServic
35
35
  console.error(`Failed to fetch remote kernel snapshots; ${reason}`);
36
36
  });
37
37
  }, [runtimesRunUrl]);
38
- const onLoadRuntimeSnapshot = useCallback(() => {
38
+ const onLoadSandboxSnapshot = useCallback(() => {
39
39
  setError(undefined);
40
40
  setOpenLoadDialog(true);
41
41
  }, []);
42
- const onRuntimeSnapshotChanged = useCallback(event => {
42
+ const onSandboxSnapshotChanged = useCallback(event => {
43
43
  setSelection(event.target.value);
44
44
  }, []);
45
- const onLoadRuntimeSnapshotSubmit = useCallback(async ({ id, connection, podName, }) => {
45
+ const onLoadSandboxSnapshotSubmit = useCallback(async ({ id, connection, podName, }) => {
46
46
  if (podName) {
47
- await loadRuntimeSnapshot({ id: podName, from: id });
48
- enqueueToast(`Runtime snapshot ${podName} is loaded.`, {
47
+ await loadSandboxSnapshot({ id: podName, from: id });
48
+ enqueueToast(`Code Sandbox snapshot ${podName} is loaded.`, {
49
49
  variant: 'success',
50
50
  });
51
51
  }
52
52
  else if (connection) {
53
- await loadBrowserRuntimeSnapshot({ connection, id });
54
- enqueueToast(`Runtime snapshot ${id} is loaded.`, {
53
+ await loadBrowserSandboxSnapshot({ connection, id });
54
+ enqueueToast(`Code Sandbox snapshot ${id} is loaded.`, {
55
55
  variant: 'success',
56
56
  });
57
57
  }
58
58
  }, []);
59
- const onTakeRuntimeSnapshot = useCallback(async () => {
59
+ const onTakeSandboxSnapshot = useCallback(async () => {
60
60
  try {
61
- setTakingRuntimeSnapshot(true);
61
+ setTakingSandboxSnapshot(true);
62
62
  let snapshot;
63
63
  let task;
64
64
  let ref = '';
65
65
  let snapshotName = '';
66
66
  if (podName && multiServiceManager?.remote) {
67
- snapshotName = createRuntimeSnapshotName('cloud');
67
+ snapshotName = createSandboxSnapshotName('cloud');
68
68
  task = multiServiceManager.remote.runtimesManager.snapshotRuntime({
69
69
  podName,
70
70
  name: snapshotName,
@@ -79,9 +79,9 @@ export function RuntimeSnapshotMenu({ children, connection, podName, multiServic
79
79
  else if (connection && multiServiceManager?.browser) {
80
80
  const model = connection.model;
81
81
  ref = model.id;
82
- snapshotName = createRuntimeSnapshotName('browser');
82
+ snapshotName = createSandboxSnapshotName('browser');
83
83
  let isPending = true;
84
- task = createRuntimeSnapshot({
84
+ task = createSandboxSnapshot({
85
85
  connection: multiServiceManager.browser.kernels.connectTo({
86
86
  model,
87
87
  }),
@@ -90,7 +90,7 @@ export function RuntimeSnapshotMenu({ children, connection, podName, multiServic
90
90
  if (isPending) {
91
91
  isPending = false;
92
92
  // Get the kernel snapshot uid.
93
- getRuntimeSnapshots().then(snapshots => {
93
+ getSandboxSnapshots().then(snapshots => {
94
94
  snapshot = snapshots.find(s => s.name === snapshotName);
95
95
  });
96
96
  }
@@ -114,15 +114,15 @@ export function RuntimeSnapshotMenu({ children, connection, podName, multiServic
114
114
  });
115
115
  await task;
116
116
  if (snapshot) {
117
- addRuntimeSnapshot(snapshot);
117
+ addSandboxSnapshot(snapshot);
118
118
  }
119
119
  }
120
120
  }
121
121
  finally {
122
- setTakingRuntimeSnapshot(false);
122
+ setTakingSandboxSnapshot(false);
123
123
  }
124
124
  }, [connection, podName, multiServiceManager]);
125
- return (_jsxs(_Fragment, { children: [_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { leadingVisual: CameraIcon, variant: "invisible", size: "small", disabled: loadingRuntimeSnapshot || takingRuntimeSnapshot || disabled, children: children }), _jsx(ActionMenu.Overlay, { children: _jsxs(ActionList, { children: [_jsx(ActionList.Item, { onSelect: onLoadRuntimeSnapshot, disabled: loadingRuntimeSnapshot || runtimeSnapshots.length === 0, children: "Load a runtime snapshot\u2026" }), _jsx(ActionList.Item, { onSelect: onTakeRuntimeSnapshot, disabled: takingRuntimeSnapshot, children: "Take a runtime snapshot" })] }) })] }), openLoadDialog && (_jsx(Dialog, { title: _jsx("span", { style: { color: 'var(--fgColor-default)' }, children: "Choose a runtime snapshot to load" }), onClose: () => {
125
+ return (_jsxs(_Fragment, { children: [_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { leadingVisual: DeviceCameraIcon, variant: "invisible", size: "small", disabled: loadingSandboxSnapshot || takingSandboxSnapshot || disabled, children: children }), _jsx(ActionMenu.Overlay, { children: _jsxs(ActionList, { children: [_jsx(ActionList.Item, { onSelect: onLoadSandboxSnapshot, disabled: loadingSandboxSnapshot || runtimeSnapshots.length === 0, children: "Load a code sandbox snapshot\u2026" }), _jsx(ActionList.Item, { onSelect: onTakeSandboxSnapshot, disabled: takingSandboxSnapshot, children: "Take a code sandbox snapshot" })] }) })] }), openLoadDialog && (_jsx(Dialog, { title: _jsx("span", { style: { color: 'var(--fgColor-default)' }, children: "Choose a code sandbox snapshot to load" }), onClose: () => {
126
126
  setOpenLoadDialog(false);
127
127
  }, footerButtons: [
128
128
  {
@@ -137,33 +137,33 @@ export function RuntimeSnapshotMenu({ children, connection, podName, multiServic
137
137
  },
138
138
  {
139
139
  buttonType: 'primary',
140
- content: loadingRuntimeSnapshot ? (_jsx(Spinner, { size: "small" })) : ('Load'),
141
- disabled: loadingRuntimeSnapshot,
140
+ content: loadingSandboxSnapshot ? (_jsx(Spinner, { size: "small" })) : ('Load'),
141
+ disabled: loadingSandboxSnapshot,
142
142
  onClick: async (event) => {
143
143
  if (!event.defaultPrevented) {
144
144
  event.preventDefault();
145
- setLoadingRuntimeSnapshot(true);
145
+ setLoadingSandboxSnapshot(true);
146
146
  try {
147
147
  setError(undefined);
148
148
  const snapshot = runtimeSnapshots.find(s => s.id === selection);
149
149
  if (snapshot && (connection || podName)) {
150
- await onLoadRuntimeSnapshotSubmit({
150
+ await onLoadSandboxSnapshotSubmit({
151
151
  connection,
152
152
  id: snapshot.id,
153
153
  podName,
154
154
  });
155
155
  }
156
156
  else {
157
- setError('No runtime snapshot found.');
157
+ setError('No code sandbox snapshot found.');
158
158
  }
159
159
  }
160
160
  finally {
161
- setLoadingRuntimeSnapshot(false);
161
+ setLoadingSandboxSnapshot(false);
162
162
  setOpenLoadDialog(false);
163
163
  }
164
164
  }
165
165
  },
166
166
  autoFocus: true,
167
167
  },
168
- ], children: _jsxs(Box, { as: "form", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Snapshot" }), _jsx(Select, { name: "snapshot", value: selection, onChange: onRuntimeSnapshotChanged, block: true, children: runtimeSnapshots.map(s => (_jsx(Select.Option, { value: s.id, children: s.name ? `${s.name} (${s.id})` : s.id }, s.id))) })] }), error && _jsx(Flash, { variant: "danger", children: error })] }) }))] }));
168
+ ], children: _jsxs(Box, { as: "form", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Snapshot" }), _jsx(Select, { name: "snapshot", value: selection, onChange: onSandboxSnapshotChanged, block: true, children: runtimeSnapshots.map(s => (_jsx(Select.Option, { value: s.id, children: s.name ? `${s.name} (${s.id})` : s.id }, s.id))) })] }), error && _jsx(Flash, { variant: "danger", children: error })] }) }))] }));
169
169
  }
@@ -1 +1 @@
1
- export * from './RuntimeSnapshotMenu';
1
+ export * from './SandboxSnapshotMenu';
@@ -2,4 +2,4 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
- export * from './RuntimeSnapshotMenu.js';
5
+ export * from './SandboxSnapshotMenu.js';
@@ -9,7 +9,7 @@ import { PromiseDelegate } from '@lumino/coreutils';
9
9
  import { ActionList, ActionMenu, Heading, IconButton, Spinner, TreeView, } from '@primer/react';
10
10
  import { Box } from '@datalayer/primer-addons';
11
11
  import { Blankslate, Dialog } from '@primer/react/experimental';
12
- import { CounterClockWiseIcon } from '@datalayer/icons-react';
12
+ import { SyncIcon } from '@primer/octicons-react';
13
13
  import { useIsMounted } from 'usehooks-ts';
14
14
  import { useToast } from '../../hooks/index.js';
15
15
  import { UploadIconButton } from '../buttons/index.js';
@@ -225,7 +225,7 @@ export function ContentsBrowser(props) {
225
225
  alignItems: 'center',
226
226
  flexWrap: 'nowrap',
227
227
  flexShrink: 0,
228
- }, children: [_jsx(IconButton, { variant: "invisible", "aria-label": 'Refresh contents browser.', title: 'Refresh contents browser.', icon: CounterClockWiseIcon, onClick: refresh }), _jsx(UploadIconButton, { label: 'Upload a file', multiple: true, upload: upload })] })] }), isLoading ? (_jsx(Box, { sx: {
228
+ }, children: [_jsx(IconButton, { variant: "invisible", "aria-label": 'Refresh contents browser.', title: 'Refresh contents browser.', icon: SyncIcon, onClick: refresh }), _jsx(UploadIconButton, { label: 'Upload a file', multiple: true, upload: upload })] })] }), isLoading ? (_jsx(Box, { sx: {
229
229
  gridArea: 'content',
230
230
  display: 'flex',
231
231
  alignItems: 'center',
@@ -1,5 +1,5 @@
1
1
  import { ISpaceVariant } from '../../models';
2
2
  export declare const SpaceVariantToken: (props: {
3
- variant: ISpaceVariant;
3
+ variant: ISpaceVariant | string;
4
4
  }) => import("react/jsx-runtime").JSX.Element;
5
5
  export default SpaceVariantToken;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  /*
3
3
  * Copyright (c) 2023-2025 Datalayer, Inc.
4
4
  * Distributed under the terms of the Modified BSD License.
@@ -7,14 +7,17 @@ import { Token } from '@primer/react';
7
7
  import { ProjectIcon } from '@primer/octicons-react';
8
8
  import { StudentIcon } from '@datalayer/icons-react';
9
9
  export const SpaceVariantToken = (props) => {
10
- const { variant } = props;
10
+ const variant = String(props.variant || 'default').toLowerCase();
11
+ if (variant.includes('project')) {
12
+ return _jsx(Token, { text: "project", leadingVisual: ProjectIcon });
13
+ }
11
14
  switch (variant) {
12
15
  case 'default':
13
- return _jsx(Token, { text: "default", leadingVisual: ProjectIcon });
16
+ return _jsx(Token, { text: "default" });
14
17
  case 'course':
15
18
  return _jsx(Token, { text: "course", leadingVisual: StudentIcon });
16
19
  default:
17
- return _jsx(_Fragment, {});
20
+ return _jsx(Token, { text: String(variant || 'default') });
18
21
  }
19
22
  };
20
23
  export default SpaceVariantToken;
@@ -4,8 +4,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
4
4
  * Distributed under the terms of the Modified BSD License.
5
5
  */
6
6
  import { useEffect, useState } from 'react';
7
- import { Avatar, AvatarStack } from '@primer/react';
8
- import { getAvatarURL, getRelativeTime } from '../../utils/index.js';
7
+ import { AvatarStack } from '@primer/react';
8
+ import { getRelativeTime } from '../../utils/index.js';
9
+ import { DLAvatar } from '../avatars/index.js';
9
10
  const AVATAR_SIZE = 28;
10
11
  const SPACER_USER_AGENT = 'DatalayerSpacer';
11
12
  const AWARENESS_NOTIFICATION_TIMEOUT_MS = 30_000;
@@ -89,12 +90,12 @@ export function PeersIndicator({ awareness, currentUserHandle, }) {
89
90
  if (peer.notification) {
90
91
  title += `\n${peer.notification}`;
91
92
  }
92
- return (_jsx(Avatar, { sx: {
93
+ return (_jsx(DLAvatar, { sx: {
93
94
  border: peer.notificationType
94
95
  ? `var(--borderWidth-thick) solid ${peer.notificationType}`
95
96
  : 'none',
96
97
  }, title: title, src: peer.avatarUrl
97
- ? getAvatarURL(peer.avatarUrl)
98
+ ? peer.avatarUrl
98
99
  : defaultAvatarSrc(peer.color, peer.initials), size: AVATAR_SIZE }, peer.displayName));
99
100
  }) }));
100
101
  }
@@ -28,5 +28,10 @@ export * from './useUser';
28
28
  export * from './useProjects';
29
29
  export * from './useProjectStore';
30
30
  export * from './useMobile';
31
+ export * from './useUsageRefreshStore';
32
+ export * from './usePrincipalStore';
33
+ export * from './useBillableAccountStore';
34
+ export * from './useSelectedPrincipal';
35
+ export * from './useSelectedBillableAccount';
31
36
  export * from './useVisibilityObserver';
32
37
  export * from './useWindowSize';
@@ -33,5 +33,10 @@ export * from './useUser.js';
33
33
  export * from './useProjects.js';
34
34
  export * from './useProjectStore.js';
35
35
  export * from './useMobile.js';
36
+ export * from './useUsageRefreshStore.js';
37
+ export * from './usePrincipalStore.js';
38
+ export * from './useBillableAccountStore.js';
39
+ export * from './useSelectedPrincipal.js';
40
+ export * from './useSelectedBillableAccount.js';
36
41
  export * from './useVisibilityObserver.js';
37
42
  export * from './useWindowSize.js';
@@ -0,0 +1,31 @@
1
+ /**
2
+ * The kind of billable account currently in scope.
3
+ *
4
+ * An account is the *billable* principal — only users and organizations
5
+ * are accounts. Teams are NOT accounts; when a team is the selected
6
+ * principal, the billable account is the team's parent organization.
7
+ */
8
+ export type BillableAccountKind = 'user' | 'organization';
9
+ export type BillableAccountState = {
10
+ billableAccountKind: BillableAccountKind;
11
+ billableAccountUid?: string;
12
+ billableAccountHandle?: string;
13
+ setBillableAccount: (args: {
14
+ kind: BillableAccountKind;
15
+ uid: string;
16
+ handle: string;
17
+ }) => void;
18
+ resetBillableAccount: () => void;
19
+ };
20
+ export declare const useBillableAccountStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<BillableAccountState>, "persist"> & {
21
+ persist: {
22
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<BillableAccountState, unknown>>) => void;
23
+ clearStorage: () => void;
24
+ rehydrate: () => Promise<void> | void;
25
+ hasHydrated: () => boolean;
26
+ onHydrate: (fn: (state: BillableAccountState) => void) => () => void;
27
+ onFinishHydration: (fn: (state: BillableAccountState) => void) => () => void;
28
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<BillableAccountState, unknown>>;
29
+ };
30
+ }>;
31
+ export default useBillableAccountStore;
@@ -0,0 +1,53 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { create } from 'zustand';
6
+ import { createJSONStorage, persist } from 'zustand/middleware';
7
+ import { useUsageRefreshStore } from './useUsageRefreshStore.js';
8
+ export const useBillableAccountStore = create()(persist(set => ({
9
+ billableAccountKind: 'user',
10
+ billableAccountUid: undefined,
11
+ billableAccountHandle: undefined,
12
+ setBillableAccount: ({ kind, uid, handle }) => set(state => {
13
+ const unchanged = state.billableAccountKind === kind &&
14
+ state.billableAccountUid === uid &&
15
+ state.billableAccountHandle === handle;
16
+ if (unchanged) {
17
+ return state;
18
+ }
19
+ useUsageRefreshStore
20
+ .getState()
21
+ .requestUsageRefresh('billable-account-changed');
22
+ return {
23
+ billableAccountKind: kind,
24
+ billableAccountUid: uid,
25
+ billableAccountHandle: handle,
26
+ };
27
+ }),
28
+ resetBillableAccount: () => set(state => {
29
+ const unchanged = state.billableAccountKind === 'user' &&
30
+ state.billableAccountUid === undefined &&
31
+ state.billableAccountHandle === undefined;
32
+ if (unchanged) {
33
+ return state;
34
+ }
35
+ useUsageRefreshStore
36
+ .getState()
37
+ .requestUsageRefresh('billable-account-reset');
38
+ return {
39
+ billableAccountKind: 'user',
40
+ billableAccountUid: undefined,
41
+ billableAccountHandle: undefined,
42
+ };
43
+ }),
44
+ }), {
45
+ name: 'datalayer-billable-account',
46
+ storage: createJSONStorage(() => localStorage),
47
+ partialize: state => ({
48
+ billableAccountKind: state.billableAccountKind,
49
+ billableAccountUid: state.billableAccountUid,
50
+ billableAccountHandle: state.billableAccountHandle,
51
+ }),
52
+ }));
53
+ export default useBillableAccountStore;