@datalayer/core 1.0.20 → 1.0.21

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 (96) 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/checkout/StripeCheckout.d.ts +24 -3
  24. package/lib/components/checkout/StripeCheckout.js +1116 -55
  25. package/lib/components/display/DatalayerBox.js +6 -1
  26. package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +2 -2
  27. package/lib/components/snapshots/{RuntimeSnapshotMenu.d.ts → SandboxSnapshotMenu.d.ts} +4 -4
  28. package/lib/components/snapshots/{RuntimeSnapshotMenu.js → SandboxSnapshotMenu.js} +33 -33
  29. package/lib/components/snapshots/index.d.ts +1 -1
  30. package/lib/components/snapshots/index.js +1 -1
  31. package/lib/components/storage/ContentsBrowser.js +2 -2
  32. package/lib/components/tokens/SpaceVariantToken.d.ts +1 -1
  33. package/lib/components/tokens/SpaceVariantToken.js +7 -4
  34. package/lib/components/users/PeerIndicator.js +5 -4
  35. package/lib/hooks/useCache.d.ts +125 -18
  36. package/lib/hooks/useCache.js +893 -120
  37. package/lib/hooks/useDatalayer.js +31 -3
  38. package/lib/hooks/useIAM.js +1 -8
  39. package/lib/hooks/useProjects.d.ts +44 -0
  40. package/lib/hooks/useProjects.js +26 -2
  41. package/lib/index.d.ts +2 -2
  42. package/lib/index.js +1 -1
  43. package/lib/mocks/components/FlashMock.js +8 -2
  44. package/lib/models/{RuntimeSnapshot.d.ts → CodeSandboxSnapshot.d.ts} +5 -5
  45. package/lib/models/{RuntimeSnapshot.js → CodeSandboxSnapshot.js} +1 -1
  46. package/lib/models/{RuntimeSnapshotDTO.d.ts → CodeSandboxSnapshotDTO.d.ts} +30 -30
  47. package/lib/models/{RuntimeSnapshotDTO.js → CodeSandboxSnapshotDTO.js} +6 -6
  48. package/lib/models/Environment.d.ts +4 -0
  49. package/lib/models/IAM.d.ts +66 -0
  50. package/lib/models/Organization.d.ts +1 -0
  51. package/lib/models/Organization.js +1 -0
  52. package/lib/models/Page.d.ts +2 -2
  53. package/lib/models/Page.js +2 -2
  54. package/lib/models/Profile.d.ts +1 -1
  55. package/lib/models/RuntimeDTO.d.ts +2 -2
  56. package/lib/models/Space.d.ts +1 -0
  57. package/lib/models/Space.js +29 -5
  58. package/lib/models/SpaceDTO.d.ts +4 -0
  59. package/lib/models/SpaceDTO.js +5 -0
  60. package/lib/models/Usage.d.ts +15 -0
  61. package/lib/models/Usage.js +9 -0
  62. package/lib/models/User.d.ts +21 -0
  63. package/lib/models/User.js +6 -2
  64. package/lib/models/index.d.ts +2 -2
  65. package/lib/models/index.js +2 -2
  66. package/lib/otel/auth.js +0 -4
  67. package/lib/services/index.d.ts +1 -1
  68. package/lib/services/index.js +1 -1
  69. package/lib/state/substates/IAMState.js +0 -7
  70. package/lib/state/substates/RuntimesState.d.ts +9 -9
  71. package/lib/state/substates/RuntimesState.js +3 -3
  72. package/lib/stateful/runtimes/actions.d.ts +17 -17
  73. package/lib/stateful/runtimes/actions.js +35 -55
  74. package/lib/stateful/runtimes/apis.d.ts +3 -3
  75. package/lib/stateful/runtimes/snapshots.d.ts +2 -2
  76. package/lib/stateful/runtimes/snapshots.js +7 -7
  77. package/lib/utils/Format.d.ts +6 -0
  78. package/lib/utils/Format.js +17 -0
  79. package/lib/utils/Snapshot.d.ts +1 -1
  80. package/lib/utils/Snapshot.js +1 -1
  81. package/lib/views/datasources/DatasourceDetail.d.ts +7 -1
  82. package/lib/views/datasources/DatasourceDetail.js +61 -23
  83. package/lib/views/datasources/DatasourceNew.d.ts +8 -1
  84. package/lib/views/datasources/DatasourceNew.js +23 -10
  85. package/lib/views/datasources/Datasources.d.ts +5 -1
  86. package/lib/views/datasources/Datasources.js +38 -30
  87. package/lib/views/iam-tokens/IAMTokenNew.d.ts +3 -1
  88. package/lib/views/iam-tokens/IAMTokenNew.js +2 -2
  89. package/lib/views/iam-tokens/IAMTokens.d.ts +3 -1
  90. package/lib/views/iam-tokens/IAMTokens.js +2 -2
  91. package/lib/views/otel/OtelHeader.d.ts +5 -0
  92. package/lib/views/otel/OtelHeader.js +3 -3
  93. package/lib/views/profile/UserBadge.d.ts +7 -2
  94. package/lib/views/profile/UserBadge.js +11 -2
  95. package/lib/views/secrets/Secrets.js +21 -21
  96. package/package.json +8 -7
@@ -9,9 +9,8 @@ import { URLExt } from '@jupyterlab/coreutils';
9
9
  import { PromiseDelegate } from '@lumino/coreutils';
10
10
  import { Upload } from 'tus-js-client';
11
11
  import { requestDatalayerAPI, } from '../../api/index.js';
12
- import { asRuntimeSnapshot } from '../../models/index.js';
12
+ import { asCodeSandboxSnapshot } from '../../models/index.js';
13
13
  import { iamStore, runtimesStore } from '../../state/index.js';
14
- import { sleep } from '../../utils/index.js';
15
14
  /**
16
15
  * Get available Environments.
17
16
  */
@@ -100,7 +99,7 @@ export async function deleteRuntime(options) {
100
99
  */
101
100
  export async function snapshotRuntime(options) {
102
101
  const data = await requestDatalayerAPI({
103
- url: URLExt.join(runtimesStore.getState().runtimesRunUrl, 'api/runtimes/v1/runtime-snapshots'),
102
+ url: URLExt.join(runtimesStore.getState().runtimesRunUrl, 'api/runtimes/v1/sandbox-snapshots'),
104
103
  method: 'POST',
105
104
  body: {
106
105
  pod_name: options.id,
@@ -110,29 +109,34 @@ export async function snapshotRuntime(options) {
110
109
  },
111
110
  token: iamStore.getState().token,
112
111
  });
113
- if (!data.success || !data.snapshot) {
114
- throw new Error(`Failed to take the runtime snapshot ${options.id} - ${data}`);
112
+ if (!data.success) {
113
+ throw new Error(`Failed to take the code sandbox snapshot ${options.id} - ${data}`);
114
+ }
115
+ // Runtimes service can return 202 Accepted without inline snapshot payload
116
+ // while the snapshot lifecycle completes asynchronously via pub-sub events.
117
+ if (!data.snapshot) {
118
+ return undefined;
115
119
  }
116
- return asRuntimeSnapshot(data.snapshot);
120
+ return asCodeSandboxSnapshot(data.snapshot);
117
121
  }
118
122
  /**
119
- * Get Runtime Snapshots.
123
+ * Get Code Sandbox Snapshots.
120
124
  */
121
- export async function getRuntimeSnapshots() {
125
+ export async function getSandboxSnapshots() {
122
126
  const data = await requestDatalayerAPI({
123
- url: URLExt.join(runtimesStore.getState().runtimesRunUrl, 'api/runtimes/v1/runtime-snapshots'),
127
+ url: URLExt.join(runtimesStore.getState().runtimesRunUrl, 'api/runtimes/v1/sandbox-snapshots'),
124
128
  token: iamStore.getState().token,
125
129
  });
126
130
  if (!data.success) {
127
- console.error('Failed to fetch runtime snapshots.', data);
131
+ console.error('Failed to fetch code sandbox snapshots.', data);
128
132
  return [];
129
133
  }
130
- return (data.snapshots ?? []).map(asRuntimeSnapshot);
134
+ return (data.snapshots ?? []).map(asCodeSandboxSnapshot);
131
135
  }
132
136
  /**
133
- * Load a Runtime Snapshot within a Runtime.
137
+ * Load a Code Sandbox Snapshot within a Runtime.
134
138
  */
135
- export async function loadRuntimeSnapshot(options) {
139
+ export async function loadSandboxSnapshot(options) {
136
140
  const data = await requestDatalayerAPI({
137
141
  url: URLExt.join(runtimesStore.getState().runtimesRunUrl, 'api/runtimes/v1/runtimes', options.id),
138
142
  method: 'PUT',
@@ -142,29 +146,29 @@ export async function loadRuntimeSnapshot(options) {
142
146
  token: iamStore.getState().token,
143
147
  });
144
148
  if (!data.success) {
145
- throw new Error(`Failed to load the runtime snapshot; ${data.message}`);
149
+ throw new Error(`Failed to load the code sandbox snapshot; ${data.message}`);
146
150
  }
147
151
  }
148
152
  /**
149
- * Returns the Runtime Snapshot download URL.
153
+ * Returns the Code Sandbox Snapshot download URL.
150
154
  *
151
155
  * @param id Snapshot UID to download
152
156
  * @returns The download URL
153
157
  */
154
- export function createRuntimeSnapshotDownloadURL(id) {
155
- return (URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/runtime-snapshots/${id}`) +
158
+ export function createSandboxSnapshotDownloadURL(id) {
159
+ return (URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/sandbox-snapshots/${id}`) +
156
160
  URLExt.objectToQueryString({
157
161
  download: '1',
158
162
  token: iamStore.getState().token ?? '',
159
163
  }));
160
164
  }
161
165
  /**
162
- * Export a Runtime Snapshot.
166
+ * Export a Code Sandbox Snapshot.
163
167
  *
164
- * @param id Runtime snapshot UID to download
168
+ * @param id Code Sandbox snapshot UID to download
165
169
  */
166
- export function exportRuntimeSnapshot(id) {
167
- const url = createRuntimeSnapshotDownloadURL(id);
170
+ export function exportCodeSandboxSnapshot(id) {
171
+ const url = createSandboxSnapshotDownloadURL(id);
168
172
  const element = document.createElement('a');
169
173
  element.href = url;
170
174
  element.download = '';
@@ -173,46 +177,22 @@ export function exportRuntimeSnapshot(id) {
173
177
  document.body.removeChild(element);
174
178
  }
175
179
  /**
176
- * Delete a Runtime Snapshot.
180
+ * Delete a Code Sandbox Snapshot.
177
181
  */
178
- export async function deleteRuntimeSnapshot(id) {
182
+ export async function deleteCodeSandboxSnapshot(id) {
179
183
  await requestDatalayerAPI({
180
- url: URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/runtime-snapshots/${id}`),
184
+ url: URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/sandbox-snapshots/${id}`),
181
185
  method: 'DELETE',
182
186
  token: iamStore.getState().token,
183
187
  });
184
- // Poll Runtime Snapshot state up-to its deletion.
185
- try {
186
- let sleepTimeout = 1000;
187
- while (true) {
188
- await sleep(sleepTimeout);
189
- sleepTimeout *= 2;
190
- const response = await requestDatalayerAPI({
191
- url: URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/runtime-snapshots/${id}`),
192
- token: iamStore.getState().token,
193
- });
194
- if (response.success === false) {
195
- throw new Error(response.message);
196
- }
197
- }
198
- }
199
- catch (error) {
200
- if (error.name === 'RunResponseError' &&
201
- error.response.status === 404) {
202
- // Expected not found
203
- }
204
- else {
205
- throw error;
206
- }
207
- }
208
188
  }
209
189
  /**
210
- * Update Runtime Snapshot metadata.
190
+ * Update Code Sandbox Snapshot metadata.
211
191
  */
212
- export async function updateRuntimeSnapshot(id, metadata) {
192
+ export async function updateCodeSandboxSnapshot(id, metadata) {
213
193
  if (metadata.name || metadata.description) {
214
194
  await requestDatalayerAPI({
215
- url: URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/runtime-snapshots/${id}`),
195
+ url: URLExt.join(runtimesStore.getState().runtimesRunUrl, `api/runtimes/v1/sandbox-snapshots/${id}`),
216
196
  method: 'PATCH',
217
197
  body: { ...metadata },
218
198
  token: iamStore.getState().token,
@@ -220,19 +200,19 @@ export async function updateRuntimeSnapshot(id, metadata) {
220
200
  }
221
201
  }
222
202
  /**
223
- * Upload a Runtime Snapshot.
203
+ * Upload a Code Sandbox Snapshot.
224
204
  *
225
205
  * Note: The promise will be rejected if the runtime state is empty.
226
206
  */
227
- export async function uploadRuntimeSnapshot(options) {
207
+ export async function uploadCodeSandboxSnapshot(options) {
228
208
  if (options.file.size === 0) {
229
- return Promise.reject('Empty Runtime Snapshot.');
209
+ return Promise.reject('Empty Code Sandbox Snapshot.');
230
210
  }
231
211
  const tracker = new PromiseDelegate();
232
212
  // Create a new tus upload.
233
213
  const upload = new Upload(options.file, {
234
214
  // Endpoint is the upload creation URL from your tus server.
235
- endpoint: `${runtimesStore.getState().runtimesRunUrl}/api/runtimes/v1/runtime-snapshots/upload`,
215
+ endpoint: `${runtimesStore.getState().runtimesRunUrl}/api/runtimes/v1/sandbox-snapshots/upload`,
236
216
  headers: { Authorization: `Bearer ${iamStore.getState().token}` },
237
217
  // Retry delays will enable tus-js-client to automatically retry on errors.
238
218
  // retryDelays: [0, 3000, 5000, 10000, 20000],
@@ -5,7 +5,7 @@ import { ISessionContext } from '@jupyterlab/apputils';
5
5
  import { ServiceManager, Kernel, ServerConnection } from '@jupyterlab/services';
6
6
  import { IDisposable } from '@lumino/disposable';
7
7
  import { ISignal } from '@lumino/signaling';
8
- import type { IRuntimeSnapshot, IRuntimeCapabilities, IRuntimeModel, IDatalayerEnvironment, IRuntimeType, IRuntimeLocation } from '../../models';
8
+ import type { ICodeSandboxSnapshot, IRuntimeCapabilities, IRuntimeModel, IDatalayerEnvironment, IRuntimeType, IRuntimeLocation } from '../../models';
9
9
  /**
10
10
  * Abstract interface for the Datalayer session context.
11
11
  * It extends the JupyterLab session context
@@ -188,13 +188,13 @@ export interface IRemoteRuntimesManager extends IDisposable {
188
188
  * Whether to stop the kernel after the snapshot completion or not.
189
189
  */
190
190
  stop?: boolean;
191
- }): Promise<IRuntimeSnapshot | undefined>;
191
+ }): Promise<ICodeSandboxSnapshot | undefined>;
192
192
  /**
193
193
  * Load a snapshot within a runtim
194
194
  *
195
195
  * The runtime may be given by its `id` or `podName`.
196
196
  */
197
- loadRuntimeSnapshot(options: {
197
+ loadSandboxSnapshot(options: {
198
198
  /**
199
199
  * The kernel id
200
200
  */
@@ -12,13 +12,13 @@ type Props = {
12
12
  *
13
13
  * Note: You should use this only for browser runtimes.
14
14
  */
15
- export declare function createRuntimeSnapshot(props: Props): Promise<void>;
15
+ export declare function createSandboxSnapshot(props: Props): Promise<void>;
16
16
  /**
17
17
  * Load a snapshot within a browser kernel.
18
18
  *
19
19
  * Note: You should use this only for browser kernels.
20
20
  */
21
- export declare function loadBrowserRuntimeSnapshot({ connection, id, }: {
21
+ export declare function loadBrowserSandboxSnapshot({ connection, id, }: {
22
22
  connection: Kernel.IKernelConnection;
23
23
  id: string;
24
24
  }): Promise<void>;
@@ -3,13 +3,13 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  import { KernelExecutor } from '@datalayer/jupyter-react';
6
- import { createRuntimeSnapshotDownloadURL, uploadRuntimeSnapshot } from './index.js';
6
+ import { createSandboxSnapshotDownloadURL, uploadCodeSandboxSnapshot } from './index.js';
7
7
  /**
8
8
  * Snapshot a runtime through the frontend and upload it to the cloud.
9
9
  *
10
10
  * Note: You should use this only for browser runtimes.
11
11
  */
12
- export async function createRuntimeSnapshot(props) {
12
+ export async function createSandboxSnapshot(props) {
13
13
  const { connection, metadata, onUploadProgress } = props;
14
14
  const dump = await new KernelExecutor({ connection }).execute(GET_RUNTIME_SNAPSHOT_SNIPPET, {
15
15
  storeHistory: false,
@@ -19,7 +19,7 @@ export async function createRuntimeSnapshot(props) {
19
19
  // Convert the data to blob.
20
20
  const bytes = base64ToBytes(serializedData);
21
21
  const file = new Blob([bytes.buffer]);
22
- return uploadRuntimeSnapshot({
22
+ return uploadCodeSandboxSnapshot({
23
23
  file,
24
24
  metadata,
25
25
  onProgress: onUploadProgress,
@@ -36,14 +36,14 @@ function base64ToBytes(base64) {
36
36
  *
37
37
  * Note: You should use this only for browser kernels.
38
38
  */
39
- export async function loadBrowserRuntimeSnapshot({ connection, id, }) {
40
- const downloadURL = createRuntimeSnapshotDownloadURL(id);
39
+ export async function loadBrowserSandboxSnapshot({ connection, id, }) {
40
+ const downloadURL = createSandboxSnapshotDownloadURL(id);
41
41
  const response = await fetch(downloadURL);
42
42
  const buffer = await response.arrayBuffer();
43
43
  const base64 = bytesToBase64(new Uint8Array(buffer));
44
44
  await new KernelExecutor({
45
45
  connection,
46
- }).execute(getLoadRuntimeSnapshotSnippet(base64), {
46
+ }).execute(getLoadSandboxSnapshotSnippet(base64), {
47
47
  storeHistory: false,
48
48
  silent: true,
49
49
  });
@@ -104,7 +104,7 @@ const GET_RUNTIME_SNAPSHOT_SNIPPET = `def _create_snapshot():
104
104
  _create_snapshot()
105
105
  del _create_snapshot
106
106
  `;
107
- function getLoadRuntimeSnapshotSnippet(content) {
107
+ function getLoadSandboxSnapshotSnippet(content) {
108
108
  return `async def _load_snapshot():
109
109
  import os
110
110
  import logging
@@ -9,6 +9,12 @@ export declare const MEMORY_UNIT_LIMITS: {
9
9
  readonly [U in MemoryUnit]: number;
10
10
  };
11
11
  export declare function formatForDisplay(numBytes: number | undefined, units?: MemoryUnit | undefined): string;
12
+ /**
13
+ * Format a byte size value using a human-friendly unit.
14
+ *
15
+ * Examples: 0 B, 532 B, 1.2 KB, 24 MB, 1.45 GB
16
+ */
17
+ export declare function formatByteSize(numBytes: number | string | null | undefined): string;
12
18
  /**
13
19
  * Given a number of bytes, convert to the most human-readable
14
20
  * format, (GB, TB, etc).
@@ -17,6 +17,23 @@ export function formatForDisplay(numBytes, units) {
17
17
  const lu = convertToLargestUnit(numBytes, units);
18
18
  return lu[0].toFixed(2) + ' ' + lu[1];
19
19
  }
20
+ /**
21
+ * Format a byte size value using a human-friendly unit.
22
+ *
23
+ * Examples: 0 B, 532 B, 1.2 KB, 24 MB, 1.45 GB
24
+ */
25
+ export function formatByteSize(numBytes) {
26
+ const normalizedNumBytes = typeof numBytes === 'string' ? Number(numBytes) : numBytes;
27
+ if (!Number.isFinite(normalizedNumBytes) || !normalizedNumBytes || normalizedNumBytes < 0) {
28
+ return '0 B';
29
+ }
30
+ const [value, unit] = convertToLargestUnit(normalizedNumBytes);
31
+ const decimals = value >= 100 ? 0 : value >= 10 ? 1 : 2;
32
+ const formattedValue = value
33
+ .toFixed(decimals)
34
+ .replace(/\.0+$|(\.[0-9]*[1-9])0+$/, '$1');
35
+ return `${formattedValue} ${unit}`;
36
+ }
20
37
  /**
21
38
  * Given a number of bytes, convert to the most human-readable
22
39
  * format, (GB, TB, etc).
@@ -4,4 +4,4 @@
4
4
  * @param suffix Name prefix
5
5
  * @returns The kernel snapshot name
6
6
  */
7
- export declare function createRuntimeSnapshotName(suffix: string): string;
7
+ export declare function createSandboxSnapshotName(suffix: string): string;
@@ -16,6 +16,6 @@ const KERNEL_SNAPSHOT_DESCRIPTION_CONFIGURATION = {
16
16
  * @param suffix Name prefix
17
17
  * @returns The kernel snapshot name
18
18
  */
19
- export function createRuntimeSnapshotName(suffix) {
19
+ export function createSandboxSnapshotName(suffix) {
20
20
  return `${uniqueNamesGenerator(KERNEL_SNAPSHOT_DESCRIPTION_CONFIGURATION)}-${suffix}`;
21
21
  }
@@ -1,2 +1,8 @@
1
- export declare const DatasourceDetail: () => import("react/jsx-runtime").JSX.Element;
1
+ export type DatasourceDetailProps = {
2
+ /** Optional principal uid used to scope datasource reads/updates. */
3
+ principalUid?: string;
4
+ /** Optional principal kind used to scope datasource reads/updates. */
5
+ principalKind?: 'user' | 'organization' | 'team';
6
+ };
7
+ export declare const DatasourceDetail: ({ principalUid, principalKind, }?: DatasourceDetailProps) => import("react/jsx-runtime").JSX.Element;
2
8
  export default DatasourceDetail;
@@ -1,27 +1,33 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } 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.
5
5
  */
6
6
  import { useState, useEffect } from 'react';
7
7
  import { useParams } from 'react-router-dom';
8
- import { PageHeader, Heading, Text, Button, TextInput, FormControl, Textarea, Label, } from '@primer/react';
8
+ import { PageLayout, Text, Button, TextInput, FormControl, Textarea, Label, Spinner, Heading, } from '@primer/react';
9
9
  import { Box } from '@datalayer/primer-addons';
10
10
  import { EyeIcon, EyeClosedIcon } from '@primer/octicons-react';
11
11
  import { BoringAvatar } from '../../components/avatars/index.js';
12
12
  import { useCache, useToast } from '../../hooks/index.js';
13
13
  import { useRunStore } from '../../state/index.js';
14
- export const DatasourceDetail = () => {
14
+ export const DatasourceDetail = ({ principalUid, principalKind, } = {}) => {
15
15
  const { datasourceId } = useParams();
16
16
  const runStore = useRunStore();
17
17
  const { enqueueToast } = useToast();
18
18
  const { useUpdateDatasource, useDatasource } = useCache();
19
- const updateDatasourceMutation = useUpdateDatasource();
20
- const datasourceQuery = useDatasource(datasourceId);
19
+ const updateDatasourceMutation = useUpdateDatasource({
20
+ principalUid,
21
+ principalKind,
22
+ });
23
+ const datasourceQuery = useDatasource(datasourceId ?? '', {
24
+ principalUid,
25
+ principalKind,
26
+ });
21
27
  const [datasource, setDatasource] = useState();
22
28
  const [formValues, setFormValues] = useState({
23
- name: datasource?.name,
24
- description: datasource?.description,
29
+ name: '',
30
+ description: '',
25
31
  });
26
32
  const [validationResult, setValidationResult] = useState({
27
33
  name: undefined,
@@ -32,7 +38,10 @@ export const DatasourceDetail = () => {
32
38
  if (datasourceQuery.data) {
33
39
  const datasource = datasourceQuery.data;
34
40
  setDatasource(datasource);
35
- setFormValues({ ...datasource });
41
+ setFormValues({
42
+ name: datasource.name || '',
43
+ description: datasource.description || '',
44
+ });
36
45
  }
37
46
  }, [datasourceQuery.data]);
38
47
  const nameNameChange = (event) => {
@@ -48,8 +57,8 @@ export const DatasourceDetail = () => {
48
57
  }));
49
58
  };
50
59
  useEffect(() => {
51
- setValidationResult({
52
- ...validationResult,
60
+ setValidationResult(prev => ({
61
+ ...prev,
53
62
  name: formValues.name === undefined
54
63
  ? undefined
55
64
  : formValues.name.length > 2
@@ -60,19 +69,28 @@ export const DatasourceDetail = () => {
60
69
  : formValues.description.length > 2
61
70
  ? true
62
71
  : false,
63
- });
72
+ }));
64
73
  }, [formValues]);
65
74
  const nameSubmit = async () => {
75
+ if (!datasource) {
76
+ return;
77
+ }
66
78
  runStore.layout().showBackdrop();
67
- datasource.name = formValues.name;
68
- datasource.description = formValues.description;
69
- updateDatasourceMutation.mutate(datasource, {
79
+ const updatedDatasource = {
80
+ ...datasource,
81
+ name: formValues.name,
82
+ description: formValues.description,
83
+ };
84
+ updateDatasourceMutation.mutate(updatedDatasource, {
70
85
  onSuccess: (resp) => {
71
- if (resp.success) {
86
+ if (typeof resp === 'object' &&
87
+ resp !== null &&
88
+ 'success' in resp &&
89
+ resp.success) {
72
90
  enqueueToast('The datasource is successfully updated.', {
73
91
  variant: 'success',
74
92
  });
75
- setDatasource(datasource);
93
+ setDatasource(updatedDatasource);
76
94
  }
77
95
  },
78
96
  onSettled: () => {
@@ -80,12 +98,32 @@ export const DatasourceDetail = () => {
80
98
  },
81
99
  });
82
100
  };
83
- return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(Heading, { sx: { fontSize: 3 }, children: "Datasource" }) }), _jsxs(Box, { display: "flex", children: [_jsxs(Box, { children: [_jsx(BoringAvatar, { displayName: datasource?.name, size: 100, style: { paddingRight: 10 } }), _jsx(Text, { as: "h2", sx: { paddingTop: 3 }, children: datasource?.name }), _jsx(Box, { mt: 3, children: _jsx(Label, { size: "large", children: datasource?.variant }) })] }), _jsx(Box, { ml: 10, children: _jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: nameNameChange }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: nameDescriptionChange, rows: 5 }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Database" }), _jsx(TextInput, { placeholder: "Database", monospace: true, contrast: true, size: "large", type: passwordVisibility ? 'text' : 'password', value: datasource?.database, trailingAction: _jsx(TextInput.Action, { onClick: () => {
84
- setPasswordVisibility(!passwordVisibility);
85
- }, icon: passwordVisibility ? EyeClosedIcon : EyeIcon, "aria-label": passwordVisibility ? 'Hide database' : 'Reveal database', sx: { color: 'var(--fgColor-muted)' } }), sx: { overflow: 'visible' } })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Output bucket" }), _jsx(TextInput, { placeholder: "Output bucket", monospace: true, contrast: true, size: "large", type: passwordVisibility ? 'text' : 'password', value: datasource?.outputBucket, trailingAction: _jsx(TextInput.Action, { onClick: () => {
86
- setPasswordVisibility(!passwordVisibility);
87
- }, icon: passwordVisibility ? EyeClosedIcon : EyeIcon, "aria-label": passwordVisibility
88
- ? 'Hide output bucket'
89
- : 'Reveal output bucket', sx: { color: 'var(--fgColor-muted)' } }), sx: { overflow: 'visible' } })] }), _jsx(Button, { variant: "primary", disabled: !validationResult.name || !validationResult.description, sx: { marginTop: 3 }, onClick: nameSubmit, children: "Update datasource" })] }) })] })] }));
101
+ if (!datasourceId) {
102
+ return _jsx(_Fragment, {});
103
+ }
104
+ if (datasourceQuery.isLoading) {
105
+ return (_jsx(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: _jsx(PageLayout.Content, { children: _jsx(Box, { sx: { maxWidth: 960, mx: 'auto', width: '100%' }, children: _jsx(Box, { sx: {
106
+ display: 'flex',
107
+ justifyContent: 'center',
108
+ alignItems: 'center',
109
+ py: 6,
110
+ }, children: _jsx(Spinner, { size: "large" }) }) }) }) }));
111
+ }
112
+ if (datasourceQuery.isError || (!datasourceQuery.isLoading && !datasource)) {
113
+ return (_jsx(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: _jsx(PageLayout.Content, { children: _jsx(Box, { sx: { maxWidth: 960, mx: 'auto', width: '100%' }, children: _jsx(Box, { sx: { p: 4 }, children: _jsx(Text, { sx: { color: 'danger.fg' }, children: "Datasource not found or failed to load." }) }) }) }) }));
114
+ }
115
+ return (_jsx(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: _jsx(PageLayout.Content, { children: _jsxs(Box, { sx: { maxWidth: 960, mx: 'auto', width: '100%' }, children: [_jsxs(Box, { sx: { mb: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Datasource" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Update datasource connection metadata and review configured credentials." })] }), _jsx(Box, { sx: {
116
+ border: '1px solid',
117
+ borderColor: 'border.default',
118
+ borderRadius: 2,
119
+ bg: 'canvas.default',
120
+ p: 3,
121
+ }, children: _jsxs(Box, { sx: { display: 'grid', gridTemplateColumns: ['1fr', '180px 1fr'], gap: 4 }, children: [_jsxs(Box, { children: [_jsx(BoringAvatar, { displayName: datasource?.name, size: 100, style: { paddingRight: 10 } }), _jsx(Box, { mt: 3, children: _jsx(Label, { size: "large", children: datasource?.variant }) })] }), _jsx(Box, { children: _jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: nameNameChange }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: nameDescriptionChange, rows: 5 }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Database" }), _jsx(TextInput, { placeholder: "Database", monospace: true, size: "large", contrast: !passwordVisibility, disabled: !passwordVisibility, type: passwordVisibility ? 'text' : 'password', value: datasource?.database || '', readOnly: true, trailingAction: _jsx(TextInput.Action, { onClick: () => {
122
+ setPasswordVisibility(!passwordVisibility);
123
+ }, icon: passwordVisibility ? EyeClosedIcon : EyeIcon, "aria-label": passwordVisibility ? 'Hide database' : 'Reveal database', sx: { color: 'var(--fgColor-muted)' } }), sx: { overflow: 'visible' } })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Output bucket" }), _jsx(TextInput, { placeholder: "Output bucket", monospace: true, size: "large", contrast: !passwordVisibility, disabled: !passwordVisibility, type: passwordVisibility ? 'text' : 'password', value: datasource?.outputBucket || '', readOnly: true, trailingAction: _jsx(TextInput.Action, { onClick: () => {
124
+ setPasswordVisibility(!passwordVisibility);
125
+ }, icon: passwordVisibility ? EyeClosedIcon : EyeIcon, "aria-label": passwordVisibility
126
+ ? 'Hide output bucket'
127
+ : 'Reveal output bucket', sx: { color: 'var(--fgColor-muted)' } }), sx: { overflow: 'visible' } })] }), _jsx(Box, { sx: { marginTop: 3 }, children: _jsx(Button, { variant: "primary", disabled: !validationResult.name || !validationResult.description, onClick: nameSubmit, children: "Update datasource" }) })] }) })] }) })] }) }) }));
90
128
  };
91
129
  export default DatasourceDetail;
@@ -1,8 +1,15 @@
1
+ import { ReactNode } from 'react';
1
2
  export type DatasourceNewProps = {
2
3
  /** Route to navigate after creating a datasource. Defaults to '/settings/integrations/datasources'. */
3
4
  datasourcesListRoute?: string;
4
5
  /** Route to navigate to the secrets page. Defaults to '/settings/iam/secrets'. */
5
6
  secretsRoute?: string;
7
+ /** Optional principal uid used to scope datasource creation. */
8
+ principalUid?: string;
9
+ /** Optional principal kind used to scope datasource creation. */
10
+ principalKind?: 'user' | 'organization' | 'team';
11
+ /** Optional contextual principal summary rendered below the page intro. */
12
+ accountPrincipal?: ReactNode;
6
13
  };
7
- export declare const DatasourceNew: ({ datasourcesListRoute, secretsRoute, }?: DatasourceNewProps) => import("react/jsx-runtime").JSX.Element;
14
+ export declare const DatasourceNew: ({ datasourcesListRoute, secretsRoute, principalUid, principalKind, accountPrincipal, }?: DatasourceNewProps) => import("react/jsx-runtime").JSX.Element;
8
15
  export default DatasourceNew;
@@ -4,14 +4,17 @@ 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 { useEffect, useState } from 'react';
7
- import { PageHeader, FormControl, Button, TextInput, Text, Textarea, Select, Flash, Link, } from '@primer/react';
7
+ import { PageLayout, FormControl, Button, TextInput, Text, Heading, Textarea, Select, Flash, Link, } from '@primer/react';
8
8
  import { Box } from '@datalayer/primer-addons';
9
9
  import { useCache, useNavigate, useToast } from '../../hooks/index.js';
10
10
  import { useRunStore } from '../../state/index.js';
11
- export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/datasources', secretsRoute = '/settings/iam/secrets', } = {}) => {
11
+ export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/datasources', secretsRoute = '/settings/iam/secrets', principalUid, principalKind, accountPrincipal, } = {}) => {
12
12
  const runStore = useRunStore();
13
13
  const { useCreateDatasource } = useCache();
14
- const createDatasourceMutation = useCreateDatasource();
14
+ const createDatasourceMutation = useCreateDatasource({
15
+ principalUid,
16
+ principalKind,
17
+ });
15
18
  const navigate = useNavigate();
16
19
  const { enqueueToast } = useToast();
17
20
  const [formValues, setFormValues] = useState({
@@ -59,8 +62,8 @@ export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/d
59
62
  }));
60
63
  };
61
64
  useEffect(() => {
62
- setValidationResult({
63
- ...validationResult,
65
+ setValidationResult(prev => ({
66
+ ...prev,
64
67
  name: formValues.name === undefined
65
68
  ? undefined
66
69
  : formValues.name.length > 2
@@ -85,9 +88,12 @@ export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/d
85
88
  : formValues.outputBucket.length > 0
86
89
  ? true
87
90
  : false,
88
- });
91
+ }));
89
92
  }, [formValues]);
90
93
  const submitCreate = () => {
94
+ if (!formValues.name || !formValues.description) {
95
+ return;
96
+ }
91
97
  runStore.layout().showBackdrop('Creating an datasource...');
92
98
  createDatasourceMutation.mutate({
93
99
  name: formValues.name,
@@ -97,8 +103,15 @@ export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/d
97
103
  description: formValues.description,
98
104
  }, {
99
105
  onSuccess: (resp) => {
100
- if (resp.success) {
101
- enqueueToast(resp.message, { variant: 'success' });
106
+ if (typeof resp === 'object' &&
107
+ resp !== null &&
108
+ 'success' in resp &&
109
+ resp.success) {
110
+ const message = 'message' in resp &&
111
+ typeof resp.message === 'string'
112
+ ? resp.message
113
+ : 'Datasource created.';
114
+ enqueueToast(message, { variant: 'success' });
102
115
  navigate(datasourcesListRoute);
103
116
  }
104
117
  },
@@ -107,12 +120,12 @@ export const DatasourceNew = ({ datasourcesListRoute = '/settings/integrations/d
107
120
  },
108
121
  });
109
122
  };
110
- return (_jsxs(Box, { children: [_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "New Datasource" }) }) }), _jsxs(Flash, { variant: "warning", children: [formValues.variant === 'athena' && (_jsxs(Text, { children: ["For ", _jsx(Link, { href: "https://aws.amazon.com/athena", children: "Amazon Athena" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secrets" }), ' ', "are available:", ' ', _jsx(Text, { as: "code", children: "AWS_SECRET_ACCESS_KEY" }), ' ', _jsx(Text, { as: "code", children: "AWS_ACCESS_KEY_ID" }), ' ', _jsx(Text, { as: "code", children: "AWS_DEFAULT_REGION" })] })), formValues.variant === 'bigquery' && (_jsxs(Text, { children: ["For", ' ', _jsx(Link, { href: "https://cloud.google.com/bigquery", children: "Google Big Query" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "GOOGLE_APPLICATION_CREDENTIALS" })] })), formValues.variant === 'mssentinel' && (_jsxs(Text, { children: ["For", ' ', _jsx(Link, { href: "https://learn.microsoft.com/en-us/azure/sentinel/overview?tabs=defender-portaly", children: "Microsoft Sentinel" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "AZURE_TENANT_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_CLIENT_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_CLIENT_SECRET" }), ` `, _jsx(Text, { as: "code", children: "AZURE_SUBSCRIPTION_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_RESOURCE_GROUP" }), ` `, _jsx(Text, { as: "code", children: "MSSENTINEL_WORKSPACE_ID" }), ` `, _jsx(Text, { as: "code", children: "MSSENTINEL_WORKSPACE_NAME" })] })), formValues.variant === 'splunk' && (_jsxs(Text, { children: ["For ", _jsx(Link, { href: "https://www.splunk.com/", children: "Splunk" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "SPLUNK_HOST" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_PORT" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_USERNAME" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_PASSWORD" })] }))] }), _jsx(Box, { display: "grid", gridTemplateColumns: "1fr 1fr", sx: { gap: 3 }, children: _jsx(Box, { children: _jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Datasource type" }), _jsxs(Select, { name: "type", value: formValues.variant, onChange: valueVariantChange, children: [_jsx(Select.Option, { value: "athena", children: "Amazon Athena" }), _jsx(Select.Option, { value: "bigquery", children: "Google BigQuery" }), _jsx(Select.Option, { value: "mssentinel", children: "Microsoft Sentinel" }), _jsx(Select.Option, { value: "splunk", children: "Splunk" })] }), _jsx(FormControl.Caption, { children: "Pick the most appropriate datasource type." })] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: valueNameChange, autoFocus: true }), _jsx(FormControl.Caption, { children: "Hint: The datasource name is a short name that identifies in a unique way your datasource." }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name length must be between 2 and 32 characters." }))] }), formValues.variant === 'athena' && (_jsxs(_Fragment, { children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Database" }), _jsx(TextInput, { block: true, value: formValues.database, onChange: valueDatabaseChange }), validationResult.database === false && (_jsx(FormControl.Validation, { variant: "error", children: "Database must have more than 1." }))] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Output Bucket" }), _jsx(TextInput, { block: true, value: formValues.outputBucket, onChange: valueOutputBucketChange }), validationResult.database === false && (_jsx(FormControl.Validation, { variant: "error", children: "Output bucket must have more than 1." }))] })] })), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: valueDescriptionChange }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsx(Button, { variant: "primary", disabled: !validationResult.database ||
123
+ return (_jsx(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: _jsx(PageLayout.Content, { children: _jsxs(Box, { sx: { maxWidth: 960, mx: 'auto', width: '100%' }, children: [_jsxs(Box, { sx: { mb: 4 }, children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "New Datasource" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Create a datasource and configure required secrets for the selected provider." }), accountPrincipal && _jsx(Box, { sx: { mt: 2 }, children: accountPrincipal })] }), _jsxs(Flash, { variant: "warning", sx: { mb: 3 }, children: [formValues.variant === 'athena' && (_jsxs(Text, { children: ["For", ' ', _jsx(Link, { href: "https://aws.amazon.com/athena", children: "Amazon Athena" }), ",", ' ', "ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secrets" }), ' ', "are available:", ' ', _jsx(Text, { as: "code", children: "AWS_SECRET_ACCESS_KEY" }), ' ', _jsx(Text, { as: "code", children: "AWS_ACCESS_KEY_ID" }), ' ', _jsx(Text, { as: "code", children: "AWS_DEFAULT_REGION" })] })), formValues.variant === 'bigquery' && (_jsxs(Text, { children: ["For", ' ', _jsx(Link, { href: "https://cloud.google.com/bigquery", children: "Google Big Query" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "GOOGLE_APPLICATION_CREDENTIALS" })] })), formValues.variant === 'mssentinel' && (_jsxs(Text, { children: ["For", ' ', _jsx(Link, { href: "https://learn.microsoft.com/en-us/azure/sentinel/overview?tabs=defender-portaly", children: "Microsoft Sentinel" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "AZURE_TENANT_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_CLIENT_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_CLIENT_SECRET" }), ` `, _jsx(Text, { as: "code", children: "AZURE_SUBSCRIPTION_ID" }), ` `, _jsx(Text, { as: "code", children: "AZURE_RESOURCE_GROUP" }), ` `, _jsx(Text, { as: "code", children: "MSSENTINEL_WORKSPACE_ID" }), ` `, _jsx(Text, { as: "code", children: "MSSENTINEL_WORKSPACE_NAME" })] })), formValues.variant === 'splunk' && (_jsxs(Text, { children: ["For ", _jsx(Link, { href: "https://www.splunk.com/", children: "Splunk" }), ", ensure the following", ' ', _jsx(Link, { href: "javascript: return false;", onClick: e => navigate(secretsRoute, e), children: "Secret" }), ' ', "is available:", ' ', _jsx(Text, { as: "code", children: "SPLUNK_HOST" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_PORT" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_USERNAME" }), ` `, _jsx(Text, { as: "code", children: "SPLUNK_PASSWORD" })] }))] }), _jsxs(Box, { sx: { label: { marginTop: 2 } }, children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Datasource type" }), _jsxs(Select, { name: "type", value: formValues.variant, onChange: valueVariantChange, children: [_jsx(Select.Option, { value: "athena", children: "Amazon Athena" }), _jsx(Select.Option, { value: "bigquery", children: "Google BigQuery" }), _jsx(Select.Option, { value: "mssentinel", children: "Microsoft Sentinel" }), _jsx(Select.Option, { value: "splunk", children: "Splunk" })] }), _jsx(FormControl.Caption, { children: "Pick the most appropriate datasource type." })] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: formValues.name, onChange: valueNameChange, autoFocus: true }), _jsx(FormControl.Caption, { children: "Hint: The datasource name is a short name that identifies in a unique way your datasource." }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name length must be between 2 and 32 characters." }))] }), formValues.variant === 'athena' && (_jsxs(_Fragment, { children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Database" }), _jsx(TextInput, { block: true, value: formValues.database, onChange: valueDatabaseChange }), validationResult.database === false && (_jsx(FormControl.Validation, { variant: "error", children: "Database must have more than 1." }))] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Output Bucket" }), _jsx(TextInput, { block: true, value: formValues.outputBucket, onChange: valueOutputBucketChange }), validationResult.database === false && (_jsx(FormControl.Validation, { variant: "error", children: "Output bucket must have more than 1." }))] })] })), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Description" }), _jsx(Textarea, { block: true, value: formValues.description, onChange: valueDescriptionChange }), validationResult.description === false && (_jsx(FormControl.Validation, { variant: "error", children: "Description must have more than 2 characters." }))] }), _jsx(Button, { variant: "primary", disabled: !validationResult.database ||
111
124
  !validationResult.outputBucket ||
112
125
  !validationResult.name ||
113
126
  !validationResult.description, sx: { marginTop: 2 }, onClick: e => {
114
127
  e.preventDefault();
115
128
  submitCreate();
116
- }, children: "Create a datasource" })] }) }) })] }));
129
+ }, children: "Create a datasource" })] })] }) }) }));
117
130
  };
118
131
  export default DatasourceNew;
@@ -3,6 +3,10 @@ export type DatasourcesProps = {
3
3
  newDatasourceRoute?: string;
4
4
  /** Base route for the datasources list (used for edit navigation). Defaults to current relative path. */
5
5
  datasourcesListRoute?: string;
6
+ /** Optional principal uid used to scope datasource reads. */
7
+ principalUid?: string;
8
+ /** Optional principal kind used to scope datasource reads. */
9
+ principalKind?: 'user' | 'organization' | 'team';
6
10
  };
7
- export declare const Datasources: ({ newDatasourceRoute, datasourcesListRoute, }?: DatasourcesProps) => import("react/jsx-runtime").JSX.Element;
11
+ export declare const Datasources: ({ newDatasourceRoute, datasourcesListRoute, principalUid, principalKind, }?: DatasourcesProps) => import("react/jsx-runtime").JSX.Element;
8
12
  export default Datasources;