@datalayer/core 1.0.23 → 1.0.24

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/README.md CHANGED
@@ -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
 
@@ -217,10 +217,10 @@ Key platform features accessible through this Client and CLI:
217
217
 
218
218
  ## Documentation
219
219
 
220
- - **Command Line Interface (CLI)**: [https://docs.datalayer.app/cli/](https://docs.datalayer.app/cli/)
220
+ - **Command Line Interface (CLI)**: [https://datalayer.ai/docs/cli/](https://datalayer.ai/docs/cli/)
221
221
  - **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/)
222
+ - **Platform Documentation**: [docs.datalayer.app](https://datalayer.ai/docs/)
223
+ - **API Reference**: [API documentation](https://datalayer.ai/docs/api/)
224
224
 
225
225
  ## Development
226
226
 
@@ -317,7 +317,7 @@ This project is licensed under the [BSD 3-Clause License](https://github.com/dat
317
317
 
318
318
  ## Support
319
319
 
320
- - **Documentation**: [Datalayer Platform Documentation](https://docs.datalayer.app/)
320
+ - **Documentation**: [Datalayer Platform Documentation](https://datalayer.ai/docs/)
321
321
  - **Issues**: [GitHub Issues](https://github.com/datalayer/core/issues)
322
322
  - **Community**: [Datalayer Platform](https://datalayer.app/)
323
323
 
@@ -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;
@@ -233,6 +233,14 @@ export declare const queryKeys: {
233
233
  readonly growth: {
234
234
  readonly kpi: () => readonly ["growth", "kpi"];
235
235
  };
236
+ readonly ray: {
237
+ readonly all: () => readonly ["ray"];
238
+ readonly clusters: () => readonly ["ray", "clusters"];
239
+ readonly cluster: (namespace: string, clusterName: string) => readonly ["ray", "cluster", string, string];
240
+ readonly jobs: (namespace: string, clusterName?: string) => readonly ["ray", "jobs", string, string];
241
+ readonly job: (namespace: string, jobName: string) => readonly ["ray", "job", string, string];
242
+ readonly logs: (namespace: string, jobName: string) => readonly ["ray", "job", string, string, "logs"];
243
+ };
236
244
  readonly oauth2: {
237
245
  readonly authorizationUrl: (queryArgs: Record<string, string>) => readonly ["oauth2", "authz", "url", Record<string, string>];
238
246
  readonly authorizationLinkUrl: (queryArgs: Record<string, string>) => readonly ["oauth2", "authz", "url", "link", Record<string, string>];
@@ -899,6 +907,20 @@ export declare const useCache: ({ loginRoute }?: CacheProps) => {
899
907
  useUserSurveys: (userId: string, options?: Omit<UseQueryOptions<unknown>, "queryKey" | "queryFn">) => import("@tanstack/react-query").UseQueryResult<unknown, Error>;
900
908
  useGrowthKPI: (options?: Omit<UseQueryOptions<unknown>, "queryKey" | "queryFn">) => import("@tanstack/react-query").UseQueryResult<unknown, Error>;
901
909
  useGrowthContactsKPI: (options?: Omit<UseQueryOptions<unknown>, "queryKey" | "queryFn">) => import("@tanstack/react-query").UseQueryResult<unknown, Error>;
910
+ useRayClusters: () => import("@tanstack/react-query").UseQueryResult<{
911
+ clusters: any[];
912
+ namespaces: string[];
913
+ }, Error>;
914
+ useRayCluster: (namespace?: string, clusterName?: string) => import("@tanstack/react-query").UseQueryResult<any, Error>;
915
+ useCreateRayCluster: () => import("@tanstack/react-query").UseMutationResult<any, Error, Record<string, unknown>, unknown>;
916
+ useDeleteRayCluster: (namespace?: string) => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
917
+ useRayJobs: (namespace?: string, clusterName?: string) => import("@tanstack/react-query").UseQueryResult<any[], Error>;
918
+ useSubmitRayJob: (clusterName: string) => import("@tanstack/react-query").UseMutationResult<any, Error, Record<string, unknown>, unknown>;
919
+ useDeleteRayJob: (namespace?: string) => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
920
+ useRayJobLogs: (jobName: string, namespace?: string, tailLines?: number, enabled?: boolean) => import("@tanstack/react-query").UseQueryResult<{
921
+ logs: string;
922
+ status: string;
923
+ }, Error>;
902
924
  queryKeys: {
903
925
  readonly auth: {
904
926
  readonly me: () => readonly ["auth", "me"];
@@ -1084,6 +1106,14 @@ export declare const useCache: ({ loginRoute }?: CacheProps) => {
1084
1106
  readonly growth: {
1085
1107
  readonly kpi: () => readonly ["growth", "kpi"];
1086
1108
  };
1109
+ readonly ray: {
1110
+ readonly all: () => readonly ["ray"];
1111
+ readonly clusters: () => readonly ["ray", "clusters"];
1112
+ readonly cluster: (namespace: string, clusterName: string) => readonly ["ray", "cluster", string, string];
1113
+ readonly jobs: (namespace: string, clusterName?: string) => readonly ["ray", "jobs", string, string];
1114
+ readonly job: (namespace: string, jobName: string) => readonly ["ray", "job", string, string];
1115
+ readonly logs: (namespace: string, jobName: string) => readonly ["ray", "job", string, string, "logs"];
1116
+ };
1087
1117
  readonly oauth2: {
1088
1118
  readonly authorizationUrl: (queryArgs: Record<string, string>) => readonly ["oauth2", "authz", "url", Record<string, string>];
1089
1119
  readonly authorizationLinkUrl: (queryArgs: Record<string, string>) => readonly ["oauth2", "authz", "url", "link", Record<string, string>];
@@ -305,6 +305,20 @@ export const queryKeys = {
305
305
  growth: {
306
306
  kpi: () => ['growth', 'kpi'],
307
307
  },
308
+ // Ray (Runtimes)
309
+ ray: {
310
+ all: () => ['ray'],
311
+ clusters: () => [...queryKeys.ray.all(), 'clusters'],
312
+ cluster: (namespace, clusterName) => [...queryKeys.ray.all(), 'cluster', namespace, clusterName],
313
+ jobs: (namespace, clusterName) => [
314
+ ...queryKeys.ray.all(),
315
+ 'jobs',
316
+ namespace,
317
+ clusterName || 'all',
318
+ ],
319
+ job: (namespace, jobName) => [...queryKeys.ray.all(), 'job', namespace, jobName],
320
+ logs: (namespace, jobName) => [...queryKeys.ray.job(namespace, jobName), 'logs'],
321
+ },
308
322
  // OAuth2
309
323
  oauth2: {
310
324
  authorizationUrl: (queryArgs) => ['oauth2', 'authz', 'url', queryArgs],
@@ -2011,7 +2025,11 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
2011
2025
  const principalUid = options?.principalUid;
2012
2026
  const principalKind = options?.principalKind;
2013
2027
  return useQuery({
2014
- queryKey: [...queryKeys.datasources.all(), principalUid || 'self', principalKind || ''],
2028
+ queryKey: [
2029
+ ...queryKeys.datasources.all(),
2030
+ principalUid || 'self',
2031
+ principalKind || '',
2032
+ ],
2015
2033
  queryFn: async () => {
2016
2034
  const resp = await requestDatalayer({
2017
2035
  url: withAccountUidQuery(`${configuration.iamRunUrl}/api/iam/v1/datasources`, principalUid, principalKind),
@@ -2072,7 +2090,11 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
2072
2090
  const principalUid = options?.principalUid;
2073
2091
  const principalKind = options?.principalKind;
2074
2092
  return useQuery({
2075
- queryKey: [...queryKeys.secrets.all(), principalUid || 'self', principalKind || ''],
2093
+ queryKey: [
2094
+ ...queryKeys.secrets.all(),
2095
+ principalUid || 'self',
2096
+ principalKind || '',
2097
+ ],
2076
2098
  queryFn: async () => {
2077
2099
  const resp = await requestDatalayer({
2078
2100
  url: withAccountUidQuery(`${configuration.iamRunUrl}/api/iam/v1/secrets`, principalUid, principalKind),
@@ -2385,7 +2407,11 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
2385
2407
  const principalUid = options?.principalUid;
2386
2408
  const principalKind = options?.principalKind;
2387
2409
  return useQuery({
2388
- queryKey: [...queryKeys.datasources.detail(datasourceId), principalUid || 'self', principalKind || ''],
2410
+ queryKey: [
2411
+ ...queryKeys.datasources.detail(datasourceId),
2412
+ principalUid || 'self',
2413
+ principalKind || '',
2414
+ ],
2389
2415
  queryFn: async () => {
2390
2416
  const resp = await requestDatalayer({
2391
2417
  url: withAccountUidQuery(`${configuration.iamRunUrl}/api/iam/v1/datasources/${datasourceId}`, principalUid, principalKind),
@@ -2434,7 +2460,11 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
2434
2460
  const principalUid = options?.principalUid;
2435
2461
  const principalKind = options?.principalKind;
2436
2462
  return useQuery({
2437
- queryKey: [...queryKeys.secrets.detail(secretId), principalUid || 'self', principalKind || ''],
2463
+ queryKey: [
2464
+ ...queryKeys.secrets.detail(secretId),
2465
+ principalUid || 'self',
2466
+ principalKind || '',
2467
+ ],
2438
2468
  queryFn: async () => {
2439
2469
  const resp = await requestDatalayer({
2440
2470
  url: withAccountUidQuery(`${configuration.iamRunUrl}/api/iam/v1/secrets/${secretId}`, principalUid, principalKind),
@@ -6805,6 +6835,167 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
6805
6835
  });
6806
6836
  };
6807
6837
  // ============================================================================
6838
+ // Ray (Runtimes) Hooks
6839
+ // ============================================================================
6840
+ const useRayClusters = () => {
6841
+ return useQuery({
6842
+ queryKey: queryKeys.ray.clusters(),
6843
+ queryFn: async () => {
6844
+ const resp = await requestDatalayer({
6845
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/clusters`,
6846
+ method: 'GET',
6847
+ });
6848
+ if (!resp.success) {
6849
+ throw new Error(resp.message || 'Failed to fetch Ray clusters');
6850
+ }
6851
+ return {
6852
+ clusters: asArray(resp.clusters),
6853
+ namespaces: asArray(resp.namespaces)
6854
+ .map(value => String(value))
6855
+ .filter(Boolean),
6856
+ };
6857
+ },
6858
+ ...DEFAULT_QUERY_OPTIONS,
6859
+ refetchOnMount: true,
6860
+ enabled: Boolean(configuration.runtimesRunUrl),
6861
+ });
6862
+ };
6863
+ const useRayCluster = (namespace = 'default', clusterName = '') => {
6864
+ return useQuery({
6865
+ queryKey: queryKeys.ray.cluster(namespace, clusterName),
6866
+ queryFn: async () => {
6867
+ const resp = await requestDatalayer({
6868
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/clusters/${encodeURIComponent(clusterName)}?namespace=${encodeURIComponent(namespace)}`,
6869
+ method: 'GET',
6870
+ });
6871
+ if (!resp.success) {
6872
+ throw new Error(resp.message || 'Failed to fetch Ray cluster');
6873
+ }
6874
+ return resp.cluster || null;
6875
+ },
6876
+ ...DEFAULT_QUERY_OPTIONS,
6877
+ enabled: Boolean(configuration.runtimesRunUrl) &&
6878
+ Boolean(namespace) &&
6879
+ Boolean(clusterName),
6880
+ });
6881
+ };
6882
+ const useCreateRayCluster = () => {
6883
+ return useMutation({
6884
+ mutationFn: async (payload) => {
6885
+ const resp = await requestDatalayer({
6886
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/clusters`,
6887
+ method: 'POST',
6888
+ body: payload,
6889
+ });
6890
+ if (resp?.success === false) {
6891
+ throw new Error(resp?.message || resp?.reason || 'Failed to create Ray cluster');
6892
+ }
6893
+ return resp;
6894
+ },
6895
+ onSuccess: () => {
6896
+ queryClient.invalidateQueries({ queryKey: queryKeys.ray.all() });
6897
+ },
6898
+ });
6899
+ };
6900
+ const useDeleteRayCluster = (namespace = 'default') => {
6901
+ return useMutation({
6902
+ mutationFn: async (clusterName) => {
6903
+ return requestDatalayer({
6904
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/clusters/${encodeURIComponent(clusterName)}?namespace=${encodeURIComponent(namespace)}`,
6905
+ method: 'DELETE',
6906
+ });
6907
+ },
6908
+ onSuccess: () => {
6909
+ queryClient.invalidateQueries({ queryKey: queryKeys.ray.all() });
6910
+ },
6911
+ });
6912
+ };
6913
+ const useRayJobs = (namespace = 'default', clusterName) => {
6914
+ return useQuery({
6915
+ queryKey: queryKeys.ray.jobs(namespace, clusterName),
6916
+ queryFn: async () => {
6917
+ const params = new URLSearchParams();
6918
+ params.set('namespace', namespace);
6919
+ if (clusterName) {
6920
+ params.set('cluster_name', clusterName);
6921
+ }
6922
+ const resp = await requestDatalayer({
6923
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/jobs?${params.toString()}`,
6924
+ method: 'GET',
6925
+ });
6926
+ if (!resp.success) {
6927
+ throw new Error(resp.message || 'Failed to fetch Ray jobs');
6928
+ }
6929
+ return asArray(resp.jobs);
6930
+ },
6931
+ ...DEFAULT_QUERY_OPTIONS,
6932
+ enabled: Boolean(configuration.runtimesRunUrl),
6933
+ });
6934
+ };
6935
+ const useSubmitRayJob = (clusterName) => {
6936
+ return useMutation({
6937
+ mutationFn: async (payload) => {
6938
+ return requestDatalayer({
6939
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/clusters/${encodeURIComponent(clusterName)}/jobs`,
6940
+ method: 'POST',
6941
+ body: payload,
6942
+ });
6943
+ },
6944
+ onSuccess: () => {
6945
+ queryClient.invalidateQueries({ queryKey: queryKeys.ray.all() });
6946
+ },
6947
+ });
6948
+ };
6949
+ const useDeleteRayJob = (namespace = 'default') => {
6950
+ return useMutation({
6951
+ mutationFn: async (jobName) => {
6952
+ return requestDatalayer({
6953
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/jobs/${encodeURIComponent(jobName)}?namespace=${encodeURIComponent(namespace)}`,
6954
+ method: 'DELETE',
6955
+ });
6956
+ },
6957
+ onSuccess: () => {
6958
+ queryClient.invalidateQueries({ queryKey: queryKeys.ray.all() });
6959
+ },
6960
+ });
6961
+ };
6962
+ const useRayJobLogs = (jobName, namespace = 'default', tailLines = 200, enabled = true) => {
6963
+ return useQuery({
6964
+ queryKey: queryKeys.ray.logs(namespace, jobName),
6965
+ queryFn: async () => {
6966
+ const params = new URLSearchParams();
6967
+ params.set('namespace', namespace);
6968
+ params.set('tail_lines', String(tailLines));
6969
+ const resp = await requestDatalayer({
6970
+ url: `${configuration.runtimesRunUrl}/api/runtimes/v1/ray/jobs/${encodeURIComponent(jobName)}/logs?${params.toString()}`,
6971
+ method: 'GET',
6972
+ // Logs naturally 404 once a job is deleted; never surface a toast.
6973
+ notifyOnError: false,
6974
+ });
6975
+ if (!resp.success) {
6976
+ throw new Error(resp.message || 'Failed to fetch Ray job logs');
6977
+ }
6978
+ return {
6979
+ logs: String(resp.logs || ''),
6980
+ status: String(resp.status || ''),
6981
+ };
6982
+ },
6983
+ ...DEFAULT_QUERY_OPTIONS,
6984
+ enabled: Boolean(configuration.runtimesRunUrl) && Boolean(jobName) && enabled,
6985
+ refetchOnMount: 'always',
6986
+ refetchInterval: query => {
6987
+ const status = String(query.state.data?.status || '').toLowerCase();
6988
+ const terminal = [
6989
+ 'succeeded',
6990
+ 'failed',
6991
+ 'stopped',
6992
+ 'completed',
6993
+ ].includes(status);
6994
+ return terminal ? false : 3000;
6995
+ },
6996
+ });
6997
+ };
6998
+ // ============================================================================
6808
6999
  // Return all methods grouped by category
6809
7000
  // ============================================================================
6810
7001
  return {
@@ -7093,6 +7284,15 @@ export const useCache = ({ loginRoute = '/login' } = {}) => {
7093
7284
  useUserSurveys,
7094
7285
  useGrowthKPI,
7095
7286
  useGrowthContactsKPI,
7287
+ // Ray (Runtimes)
7288
+ useRayClusters,
7289
+ useRayCluster,
7290
+ useCreateRayCluster,
7291
+ useDeleteRayCluster,
7292
+ useRayJobs,
7293
+ useSubmitRayJob,
7294
+ useDeleteRayJob,
7295
+ useRayJobLogs,
7096
7296
  // Query keys for manual operations
7097
7297
  queryKeys,
7098
7298
  // Upload
@@ -29,6 +29,9 @@ export type IPage = {
29
29
  screenCapture?: string;
30
30
  creator?: IUser;
31
31
  creatorId?: string;
32
+ selectedPrincipalUid?: string;
33
+ selectedPrincipalKind?: 'user' | 'organization' | 'team';
34
+ selectedOrganizationUid?: string;
32
35
  kernelSnapshot?: ICodeSandboxSnapshot;
33
36
  kernelSnapshotId?: string;
34
37
  createdAt?: string;
@@ -40,7 +40,7 @@ let initialConfiguration = {
40
40
  logoUrl: 'https://assets.datalayer.tech/datalayer-25.svg',
41
41
  logoSquareUrl: 'https://assets.datalayer.tech/datalayer-square.png',
42
42
  copyright: '© 2025 Datalayer, Inc',
43
- docsUrl: 'https://docs.datalayer.ai',
43
+ docsUrl: 'https://datalayer.ai/docs',
44
44
  supportUrl: 'https://datalayer.ai/support',
45
45
  termsUrl: 'https://datalayer.ai/terms',
46
46
  pricingUrl: 'https://datalayer.ai/pricing',
@@ -5,3 +5,4 @@ export declare const namesAsInitials: (firstName: string, lastName: string) => s
5
5
  * Convert first and last names to a friendly name.
6
6
  */
7
7
  export declare const toFriendlyName: (firstName?: string, lastName?: string) => string;
8
+ export declare const createRandomTimestampName: () => string;
package/lib/utils/Name.js CHANGED
@@ -2,6 +2,11 @@
2
2
  * Copyright (c) 2023-2025 Datalayer, Inc.
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
+ import { adjectives, animals, uniqueNamesGenerator, } from 'unique-names-generator';
6
+ const RANDOM_TIMESTAMP_NAME_CONFIGURATION = {
7
+ dictionaries: [adjectives, animals],
8
+ separator: '-',
9
+ };
5
10
  export const asDisplayName = (givenName, familyName) => {
6
11
  return givenName
7
12
  ? familyName
@@ -34,3 +39,6 @@ export const toFriendlyName = (firstName, lastName) => {
34
39
  }
35
40
  return '';
36
41
  };
42
+ export const createRandomTimestampName = () => {
43
+ return `${uniqueNamesGenerator(RANDOM_TIMESTAMP_NAME_CONFIGURATION)}-${Date.now()}`;
44
+ };
@@ -6,7 +6,7 @@ import { adjectives, animals, uniqueNamesGenerator, } from 'unique-names-generat
6
6
  /**
7
7
  * Kernel snapshot description configuration.
8
8
  */
9
- const KERNEL_SNAPSHOT_DESCRIPTION_CONFIGURATION = {
9
+ const CODE_SANDBOX_SNAPSHOT_DESCRIPTION_CONFIGURATION = {
10
10
  dictionaries: [adjectives, animals],
11
11
  separator: '-',
12
12
  };
@@ -17,5 +17,5 @@ const KERNEL_SNAPSHOT_DESCRIPTION_CONFIGURATION = {
17
17
  * @returns The kernel snapshot name
18
18
  */
19
19
  export function createSandboxSnapshotName(suffix) {
20
- return `${uniqueNamesGenerator(KERNEL_SNAPSHOT_DESCRIPTION_CONFIGURATION)}-${suffix}`;
20
+ return `${uniqueNamesGenerator(CODE_SANDBOX_SNAPSHOT_DESCRIPTION_CONFIGURATION)}-${suffix}`;
21
21
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/core",
3
- "version": "1.0.23",
3
+ "version": "1.0.24",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",