@datalayer/core 0.0.19 → 0.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.
- package/lib/App.js +0 -5
- package/lib/api/iam/datasources.d.ts +86 -0
- package/lib/api/iam/datasources.js +185 -0
- package/lib/api/iam/index.d.ts +2 -0
- package/lib/api/iam/index.js +2 -0
- package/lib/api/iam/secrets.d.ts +85 -0
- package/lib/api/iam/secrets.js +196 -0
- package/lib/client/auth/storage.js +17 -62
- package/lib/client/base.d.ts +3 -0
- package/lib/client/base.js +2 -2
- package/lib/client/index.d.ts +82 -3
- package/lib/client/index.js +5 -1
- package/lib/client/mixins/IAMMixin.d.ts +62 -0
- package/lib/client/mixins/IAMMixin.js +116 -0
- package/lib/collaboration/DatalayerCollaboration.d.ts +1 -2
- package/lib/collaboration/DatalayerCollaborationProvider.d.ts +1 -1
- package/lib/collaboration/DatalayerCollaborationProvider.js +1 -1
- package/lib/components/auth/Login.js +0 -5
- package/lib/components/auth/index.js +1 -6
- package/lib/components/index.d.ts +0 -1
- package/lib/components/index.js +0 -1
- package/lib/components/toolbars/AssignmentEditorToolbar.js +9 -7
- package/lib/examples/CellExample.js +4 -3
- package/lib/examples/NotebookExample.js +2 -7
- package/lib/hooks/index.d.ts +0 -2
- package/lib/hooks/index.js +0 -2
- package/lib/hooks/useBackdrop.d.ts +2 -3
- package/lib/hooks/useBackdropJupyterLab.d.ts +2 -2
- package/lib/hooks/useCache.d.ts +18 -4
- package/lib/hooks/useCache.js +87 -69
- package/lib/hooks/useScreenshot.d.ts +2 -3
- package/lib/hooks/useWindowSize.d.ts +1 -2
- package/lib/index.d.ts +2 -1
- package/lib/index.js +6 -2
- package/lib/main.js +4 -1
- package/lib/models/Datasource.d.ts +170 -0
- package/lib/models/Datasource.js +140 -0
- package/lib/models/Runtime.d.ts +1 -1
- package/lib/models/RuntimeSnapshotDTO.d.ts +1 -1
- package/lib/models/RuntimeSnapshotDTO.js +1 -1
- package/lib/models/Secret.d.ts +159 -0
- package/lib/models/Secret.js +135 -0
- package/lib/models/SpaceDTO.d.ts +0 -11
- package/lib/models/index.d.ts +0 -1
- package/lib/models/index.js +0 -1
- package/lib/state/substates/IAMState.d.ts +1 -1
- package/lib/state/substates/LayoutState.d.ts +2 -2
- package/lib/state/substates/NbformatState.d.ts +1 -1
- package/lib/state/substates/index.d.ts +0 -1
- package/lib/state/substates/index.js +0 -1
- package/lib/utils/File.d.ts +1 -1
- package/lib/utils/File.js +1 -1
- package/lib/utils/Notebook.d.ts +5 -3
- package/lib/utils/Notebook.js +5 -3
- package/lib/utils/cli/index.js +0 -5
- package/lib/utils/cli/query.js +0 -5
- package/lib/views/datasources/DatasourceDetail.d.ts +2 -0
- package/lib/views/datasources/DatasourceDetail.js +91 -0
- package/lib/views/datasources/DatasourceNew.d.ts +2 -0
- package/lib/views/datasources/DatasourceNew.js +118 -0
- package/lib/views/datasources/Datasources.d.ts +2 -0
- package/lib/views/datasources/Datasources.js +49 -0
- package/lib/views/datasources/index.d.ts +3 -0
- package/lib/views/datasources/index.js +7 -0
- package/lib/views/iam-tokens/IAMTokenEdit.d.ts +2 -0
- package/lib/views/iam-tokens/IAMTokenEdit.js +86 -0
- package/lib/views/iam-tokens/IAMTokenNew.d.ts +2 -0
- package/lib/views/iam-tokens/IAMTokenNew.js +118 -0
- package/lib/views/iam-tokens/IAMTokens.d.ts +2 -0
- package/lib/views/iam-tokens/IAMTokens.js +53 -0
- package/lib/views/iam-tokens/Tokens.d.ts +2 -0
- package/lib/views/iam-tokens/Tokens.js +53 -0
- package/lib/views/iam-tokens/index.d.ts +3 -0
- package/lib/views/iam-tokens/index.js +7 -0
- package/lib/views/index.d.ts +1 -0
- package/lib/views/secrets/SecretEdit.d.ts +2 -0
- package/lib/views/secrets/SecretEdit.js +149 -0
- package/lib/views/secrets/SecretNew.d.ts +2 -0
- package/lib/views/secrets/SecretNew.js +99 -0
- package/lib/views/secrets/Secrets.d.ts +2 -0
- package/lib/views/secrets/Secrets.js +48 -0
- package/lib/views/secrets/index.d.ts +3 -0
- package/lib/views/secrets/index.js +7 -0
- package/package.json +15 -16
- package/patches/.gitkeep +1 -0
- package/patches/@datalayer+jupyter-lexical+1.0.7.patch +5491 -0
- package/patches/@datalayer+jupyter-react+2.0.1.patch +2674 -0
- package/scripts/apply-patches.sh +44 -0
- package/scripts/create-patches.sh +40 -0
- package/scripts/fix-esm-imports.cjs +124 -0
- package/scripts/sync-jupyter.sh +121 -0
- package/lib/components/chat/ChatComponent.d.ts +0 -4
- package/lib/components/chat/ChatComponent.js +0 -143
- package/lib/components/chat/MessagePart.d.ts +0 -11
- package/lib/components/chat/MessagePart.js +0 -23
- package/lib/components/chat/display/DynamicToolPart.d.ts +0 -6
- package/lib/components/chat/display/DynamicToolPart.js +0 -5
- package/lib/components/chat/display/ReasoningPart.d.ts +0 -6
- package/lib/components/chat/display/ReasoningPart.js +0 -58
- package/lib/components/chat/display/TextPart.d.ts +0 -9
- package/lib/components/chat/display/TextPart.js +0 -93
- package/lib/components/chat/display/ToolPart.d.ts +0 -6
- package/lib/components/chat/display/ToolPart.js +0 -148
- package/lib/components/chat/display/index.d.ts +0 -4
- package/lib/components/chat/display/index.js +0 -13
- package/lib/components/chat/handler.d.ts +0 -8
- package/lib/components/chat/handler.js +0 -43
- package/lib/components/chat/index.d.ts +0 -4
- package/lib/components/chat/index.js +0 -13
- package/lib/hooks/useAIAgents.d.ts +0 -13
- package/lib/hooks/useAIAgents.js +0 -72
- package/lib/hooks/useAIJupyterChat.d.ts +0 -36
- package/lib/hooks/useAIJupyterChat.js +0 -53
- package/lib/hooks/useNotebookAIAgent.d.ts +0 -8
- package/lib/hooks/useNotebookAIAgent.js +0 -56
- package/lib/models/AIAgent.d.ts +0 -17
- package/lib/state/substates/AIAgentState.d.ts +0 -11
- package/lib/state/substates/AIAgentState.js +0 -42
- package/lib/tools/adapters/agui/AgUIToolAdapter.d.ts +0 -75
- package/lib/tools/adapters/agui/AgUIToolAdapter.js +0 -244
- package/lib/tools/adapters/agui/index.d.ts +0 -10
- package/lib/tools/adapters/agui/index.js +0 -19
- package/lib/tools/adapters/agui/lexicalHooks.d.ts +0 -27
- package/lib/tools/adapters/agui/lexicalHooks.js +0 -64
- package/lib/tools/adapters/agui/notebookHooks.d.ts +0 -27
- package/lib/tools/adapters/agui/notebookHooks.js +0 -61
- package/lib/tools/index.d.ts +0 -6
- package/lib/tools/index.js +0 -18
- package/lib/{models/AIAgent.js → views/index.js} +1 -1
|
@@ -6,12 +6,12 @@ export type BackdropDisplay = {
|
|
|
6
6
|
open: boolean;
|
|
7
7
|
message?: string | void;
|
|
8
8
|
};
|
|
9
|
-
type BannerDisplay = {
|
|
9
|
+
export type BannerDisplay = {
|
|
10
10
|
message: string;
|
|
11
11
|
variant: BannerDisplayVariant;
|
|
12
12
|
timestamp?: Date;
|
|
13
13
|
};
|
|
14
|
-
type PortalDisplay = {
|
|
14
|
+
export type PortalDisplay = {
|
|
15
15
|
portal: ReactPortal;
|
|
16
16
|
pinned: boolean;
|
|
17
17
|
};
|
package/lib/utils/File.d.ts
CHANGED
package/lib/utils/File.js
CHANGED
package/lib/utils/Notebook.d.ts
CHANGED
|
@@ -2,9 +2,11 @@ import { JupyterLab } from '@jupyterlab/application';
|
|
|
2
2
|
/**
|
|
3
3
|
* Create a notebook
|
|
4
4
|
*
|
|
5
|
-
* @param
|
|
6
|
-
* @param
|
|
7
|
-
* @param
|
|
5
|
+
* @param params Configuration object
|
|
6
|
+
* @param params.app JupyterLab application
|
|
7
|
+
* @param params.name Notebook name
|
|
8
|
+
* @param params.url Notebook content URL
|
|
9
|
+
* @param params.options Additional options for notebook creation
|
|
8
10
|
*/
|
|
9
11
|
export declare const createNotebook: ({ app, name, url, options, }: {
|
|
10
12
|
app: JupyterLab;
|
package/lib/utils/Notebook.js
CHANGED
|
@@ -5,9 +5,11 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Create a notebook
|
|
7
7
|
*
|
|
8
|
-
* @param
|
|
9
|
-
* @param
|
|
10
|
-
* @param
|
|
8
|
+
* @param params Configuration object
|
|
9
|
+
* @param params.app JupyterLab application
|
|
10
|
+
* @param params.name Notebook name
|
|
11
|
+
* @param params.url Notebook content URL
|
|
12
|
+
* @param params.options Additional options for notebook creation
|
|
11
13
|
*/
|
|
12
14
|
export const createNotebook = async ({ app, name, url, options, }) => {
|
|
13
15
|
const notebook = await app.commands.execute('notebook:create-new', options);
|
package/lib/utils/cli/index.js
CHANGED
package/lib/utils/cli/query.js
CHANGED
|
@@ -2,11 +2,6 @@
|
|
|
2
2
|
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
|
-
/*
|
|
6
|
-
* Copyright (c) 2021-2024 Datalayer, Inc.
|
|
7
|
-
*
|
|
8
|
-
* Datalayer License
|
|
9
|
-
*/
|
|
10
5
|
import { QueryClient } from '@tanstack/react-query';
|
|
11
6
|
/**
|
|
12
7
|
* Shared QueryClient instance for TanStack Query
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect } from 'react';
|
|
7
|
+
import { useParams } from 'react-router-dom';
|
|
8
|
+
import { PageHeader, Heading, Text, Button, TextInput, FormControl, Textarea, Label, } from '@primer/react';
|
|
9
|
+
import { Box } from '@datalayer/primer-addons';
|
|
10
|
+
import { EyeIcon, EyeClosedIcon } from '@primer/octicons-react';
|
|
11
|
+
import { BoringAvatar } from '../../components/avatars';
|
|
12
|
+
import { useCache, useToast } from '../../hooks';
|
|
13
|
+
import { useRunStore } from '../../state';
|
|
14
|
+
export const DatasourceDetail = () => {
|
|
15
|
+
const { datasourceId } = useParams();
|
|
16
|
+
const runStore = useRunStore();
|
|
17
|
+
const { enqueueToast } = useToast();
|
|
18
|
+
const { useUpdateDatasource, useDatasource } = useCache();
|
|
19
|
+
const updateDatasourceMutation = useUpdateDatasource();
|
|
20
|
+
const datasourceQuery = useDatasource(datasourceId);
|
|
21
|
+
const [datasource, setDatasource] = useState();
|
|
22
|
+
const [formValues, setFormValues] = useState({
|
|
23
|
+
name: datasource?.name,
|
|
24
|
+
description: datasource?.description,
|
|
25
|
+
});
|
|
26
|
+
const [validationResult, setValidationResult] = useState({
|
|
27
|
+
name: undefined,
|
|
28
|
+
description: undefined,
|
|
29
|
+
});
|
|
30
|
+
const [passwordVisibility, setPasswordVisibility] = useState(false);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (datasourceQuery.data) {
|
|
33
|
+
const datasource = datasourceQuery.data;
|
|
34
|
+
setDatasource(datasource);
|
|
35
|
+
setFormValues({ ...datasource });
|
|
36
|
+
}
|
|
37
|
+
}, [datasourceQuery.data]);
|
|
38
|
+
const nameNameChange = (event) => {
|
|
39
|
+
setFormValues(prevFormValues => ({
|
|
40
|
+
...prevFormValues,
|
|
41
|
+
name: event.target.value,
|
|
42
|
+
}));
|
|
43
|
+
};
|
|
44
|
+
const nameDescriptionChange = (event) => {
|
|
45
|
+
setFormValues(prevFormValues => ({
|
|
46
|
+
...prevFormValues,
|
|
47
|
+
description: event.target.value,
|
|
48
|
+
}));
|
|
49
|
+
};
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
setValidationResult({
|
|
52
|
+
...validationResult,
|
|
53
|
+
name: formValues.name === undefined
|
|
54
|
+
? undefined
|
|
55
|
+
: formValues.name.length > 2
|
|
56
|
+
? true
|
|
57
|
+
: false,
|
|
58
|
+
description: formValues.description === undefined
|
|
59
|
+
? undefined
|
|
60
|
+
: formValues.description.length > 2
|
|
61
|
+
? true
|
|
62
|
+
: false,
|
|
63
|
+
});
|
|
64
|
+
}, [formValues]);
|
|
65
|
+
const nameSubmit = async () => {
|
|
66
|
+
runStore.layout().showBackdrop();
|
|
67
|
+
datasource.name = formValues.name;
|
|
68
|
+
datasource.description = formValues.description;
|
|
69
|
+
updateDatasourceMutation.mutate(datasource, {
|
|
70
|
+
onSuccess: (resp) => {
|
|
71
|
+
if (resp.success) {
|
|
72
|
+
enqueueToast('The datasource is successfully updated.', {
|
|
73
|
+
variant: 'success',
|
|
74
|
+
});
|
|
75
|
+
setDatasource(datasource);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
onSettled: () => {
|
|
79
|
+
runStore.layout().hideBackdrop();
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
};
|
|
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" })] }) })] })] }));
|
|
90
|
+
};
|
|
91
|
+
export default DatasourceDetail;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import { PageHeader, FormControl, Button, TextInput, Text, Textarea, Select, Flash, Link, } from '@primer/react';
|
|
8
|
+
import { Box } from '@datalayer/primer-addons';
|
|
9
|
+
import { useCache, useNavigate, useToast } from '../../hooks';
|
|
10
|
+
import { useRunStore } from '../../state';
|
|
11
|
+
export const DatasourceNew = () => {
|
|
12
|
+
const runStore = useRunStore();
|
|
13
|
+
const { useCreateDatasource } = useCache();
|
|
14
|
+
const createDatasourceMutation = useCreateDatasource();
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
const { enqueueToast } = useToast();
|
|
17
|
+
const [formValues, setFormValues] = useState({
|
|
18
|
+
variant: 'athena',
|
|
19
|
+
database: undefined,
|
|
20
|
+
outputBucket: undefined,
|
|
21
|
+
name: undefined,
|
|
22
|
+
description: undefined,
|
|
23
|
+
});
|
|
24
|
+
const [validationResult, setValidationResult] = useState({
|
|
25
|
+
variant: undefined,
|
|
26
|
+
database: undefined,
|
|
27
|
+
outputBucket: undefined,
|
|
28
|
+
name: undefined,
|
|
29
|
+
description: undefined,
|
|
30
|
+
});
|
|
31
|
+
const valueVariantChange = (event) => {
|
|
32
|
+
setFormValues(prevFormValues => ({
|
|
33
|
+
...prevFormValues,
|
|
34
|
+
variant: event.target.value,
|
|
35
|
+
}));
|
|
36
|
+
};
|
|
37
|
+
const valueDatabaseChange = (event) => {
|
|
38
|
+
setFormValues(prevFormValues => ({
|
|
39
|
+
...prevFormValues,
|
|
40
|
+
database: event.target.value,
|
|
41
|
+
}));
|
|
42
|
+
};
|
|
43
|
+
const valueOutputBucketChange = (event) => {
|
|
44
|
+
setFormValues(prevFormValues => ({
|
|
45
|
+
...prevFormValues,
|
|
46
|
+
outputBucket: event.target.value,
|
|
47
|
+
}));
|
|
48
|
+
};
|
|
49
|
+
const valueNameChange = (event) => {
|
|
50
|
+
setFormValues(prevFormValues => ({
|
|
51
|
+
...prevFormValues,
|
|
52
|
+
name: event.target.value,
|
|
53
|
+
}));
|
|
54
|
+
};
|
|
55
|
+
const valueDescriptionChange = (event) => {
|
|
56
|
+
setFormValues(prevFormValues => ({
|
|
57
|
+
...prevFormValues,
|
|
58
|
+
description: event.target.value,
|
|
59
|
+
}));
|
|
60
|
+
};
|
|
61
|
+
useEffect(() => {
|
|
62
|
+
setValidationResult({
|
|
63
|
+
...validationResult,
|
|
64
|
+
name: formValues.name === undefined
|
|
65
|
+
? undefined
|
|
66
|
+
: formValues.name.length > 2
|
|
67
|
+
? true
|
|
68
|
+
: false,
|
|
69
|
+
description: formValues.description === undefined
|
|
70
|
+
? undefined
|
|
71
|
+
: formValues.description.length > 2
|
|
72
|
+
? true
|
|
73
|
+
: false,
|
|
74
|
+
database: formValues.variant !== 'athena'
|
|
75
|
+
? true
|
|
76
|
+
: formValues.database === undefined
|
|
77
|
+
? undefined
|
|
78
|
+
: formValues.database.length > 0
|
|
79
|
+
? true
|
|
80
|
+
: false,
|
|
81
|
+
outputBucket: formValues.variant !== 'athena'
|
|
82
|
+
? true
|
|
83
|
+
: formValues.outputBucket === undefined
|
|
84
|
+
? undefined
|
|
85
|
+
: formValues.outputBucket.length > 0
|
|
86
|
+
? true
|
|
87
|
+
: false,
|
|
88
|
+
});
|
|
89
|
+
}, [formValues]);
|
|
90
|
+
const submitCreate = () => {
|
|
91
|
+
runStore.layout().showBackdrop('Creating an datasource...');
|
|
92
|
+
createDatasourceMutation.mutate({
|
|
93
|
+
name: formValues.name,
|
|
94
|
+
variant: formValues.variant,
|
|
95
|
+
database: formValues.database ?? '',
|
|
96
|
+
outputBucket: formValues.outputBucket ?? '',
|
|
97
|
+
description: formValues.description,
|
|
98
|
+
}, {
|
|
99
|
+
onSuccess: (resp) => {
|
|
100
|
+
if (resp.success) {
|
|
101
|
+
enqueueToast(resp.message, { variant: 'success' });
|
|
102
|
+
navigate(`/settings/integrations/datasources`);
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
onSettled: () => {
|
|
106
|
+
runStore.layout().hideBackdrop();
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
};
|
|
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('/settings/iam/secrets', 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('/settings/iam/secrets', 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('/settings/iam/secrets', 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('/settings/iam/secrets', 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 ||
|
|
111
|
+
!validationResult.outputBucket ||
|
|
112
|
+
!validationResult.name ||
|
|
113
|
+
!validationResult.description, sx: { marginTop: 2 }, onClick: e => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
submitCreate();
|
|
116
|
+
}, children: "Create a datasource" })] }) }) })] }));
|
|
117
|
+
};
|
|
118
|
+
export default DatasourceNew;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect } from 'react';
|
|
7
|
+
import { PageLayout, Button, IconButton, Text, Label } from '@primer/react';
|
|
8
|
+
import { Blankslate, PageHeader, Table, DataTable, } from '@primer/react/experimental';
|
|
9
|
+
import { Box } from '@datalayer/primer-addons';
|
|
10
|
+
import { EditIcon } from '@datalayer/icons-react';
|
|
11
|
+
import { useCache, useNavigate } from '../../hooks';
|
|
12
|
+
const DatasourcesTable = () => {
|
|
13
|
+
const { useDatasources } = useCache();
|
|
14
|
+
const datasourcesQuery = useDatasources();
|
|
15
|
+
const navigate = useNavigate();
|
|
16
|
+
const [datasources, setDatasources] = useState([]);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
if (datasourcesQuery.data) {
|
|
19
|
+
setDatasources(datasourcesQuery.data || []);
|
|
20
|
+
}
|
|
21
|
+
}, [datasourcesQuery.data]);
|
|
22
|
+
return datasources.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Heading, { children: "Datasources" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "No Datasources found." }) })] })) : (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h2", id: "datasources", children: "Datasources" }), _jsx(Table.Subtitle, { as: "p", id: "datasources-subtitle", children: "Your datasources." }), _jsx(DataTable, { "aria-labelledby": "teams", "aria-describedby": "teams-subtitle", data: datasources, columns: [
|
|
23
|
+
// @ts-ignore
|
|
24
|
+
{
|
|
25
|
+
header: 'Type',
|
|
26
|
+
field: 'variant',
|
|
27
|
+
renderCell: datasource => _jsx(Label, { children: datasource.variant }),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
header: 'Name',
|
|
31
|
+
field: 'name',
|
|
32
|
+
rowHeader: true,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
header: 'Description',
|
|
36
|
+
field: 'description',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
header: '',
|
|
40
|
+
field: 'id',
|
|
41
|
+
renderCell: datasource => (_jsx(IconButton, { icon: EditIcon, "aria-label": "Edit", size: "small", variant: "invisible", onClick: e => navigate(`${datasource.id}`, e) })),
|
|
42
|
+
},
|
|
43
|
+
] })] }));
|
|
44
|
+
};
|
|
45
|
+
export const Datasources = () => {
|
|
46
|
+
const navigate = useNavigate();
|
|
47
|
+
return (_jsxs(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: [_jsx(PageLayout.Header, { children: _jsxs(PageHeader, { children: [_jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "Datasources" }) }), _jsx(PageHeader.Actions, { children: _jsx(Button, { size: "small", variant: "primary", onClick: e => navigate('/new/datasource', e), children: "New datasource" }) })] }) }), _jsx(PageLayout.Content, { children: _jsx(Box, { children: _jsx(DatasourcesTable, {}) }) })] }));
|
|
48
|
+
};
|
|
49
|
+
export default Datasources;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import { useState, useEffect } from 'react';
|
|
7
|
+
import { useParams } from 'react-router-dom';
|
|
8
|
+
import { PageHeader, Heading, Text, Button, TextInput, FormControl, Textarea, Label, } from '@primer/react';
|
|
9
|
+
import { Box } from '@datalayer/primer-addons';
|
|
10
|
+
import { BoringAvatar } from '../../components/avatars';
|
|
11
|
+
import { useCache, useToast } from '../../hooks';
|
|
12
|
+
import { useRunStore } from '../../state';
|
|
13
|
+
export const IAMTokenEdit = () => {
|
|
14
|
+
const { tokenId } = useParams();
|
|
15
|
+
const runStore = useRunStore();
|
|
16
|
+
const { enqueueToast } = useToast();
|
|
17
|
+
const { useUpdateToken, useToken } = useCache();
|
|
18
|
+
const getTokenQuery = useToken(tokenId);
|
|
19
|
+
const updateTokenMutation = useUpdateToken();
|
|
20
|
+
const [token, setToken] = useState();
|
|
21
|
+
const [formValues, setFormValues] = useState({
|
|
22
|
+
name: token?.name,
|
|
23
|
+
description: token?.description,
|
|
24
|
+
});
|
|
25
|
+
const [validationResult, setValidationResult] = useState({
|
|
26
|
+
name: undefined,
|
|
27
|
+
description: undefined,
|
|
28
|
+
});
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
if (getTokenQuery.data) {
|
|
31
|
+
const token = getTokenQuery.data;
|
|
32
|
+
setToken(token);
|
|
33
|
+
setFormValues({ ...token });
|
|
34
|
+
}
|
|
35
|
+
}, [getTokenQuery.data]);
|
|
36
|
+
const nameNameChange = (event) => {
|
|
37
|
+
setFormValues(prevFormValues => ({
|
|
38
|
+
...prevFormValues,
|
|
39
|
+
name: event.target.value,
|
|
40
|
+
}));
|
|
41
|
+
};
|
|
42
|
+
const nameDescriptionChange = (event) => {
|
|
43
|
+
setFormValues(prevFormValues => ({
|
|
44
|
+
...prevFormValues,
|
|
45
|
+
description: event.target.value,
|
|
46
|
+
}));
|
|
47
|
+
};
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
setValidationResult({
|
|
50
|
+
...validationResult,
|
|
51
|
+
name: formValues.name === undefined
|
|
52
|
+
? undefined
|
|
53
|
+
: formValues.name.length > 2
|
|
54
|
+
? true
|
|
55
|
+
: false,
|
|
56
|
+
description: formValues.description === undefined
|
|
57
|
+
? undefined
|
|
58
|
+
: formValues.description.length > 2
|
|
59
|
+
? true
|
|
60
|
+
: false,
|
|
61
|
+
});
|
|
62
|
+
}, [formValues]);
|
|
63
|
+
const nameSubmit = async () => {
|
|
64
|
+
runStore.layout().showBackdrop();
|
|
65
|
+
const updatedToken = {
|
|
66
|
+
...token,
|
|
67
|
+
name: formValues.name,
|
|
68
|
+
description: formValues.description,
|
|
69
|
+
};
|
|
70
|
+
updateTokenMutation.mutate(updatedToken, {
|
|
71
|
+
onSuccess: (resp) => {
|
|
72
|
+
if (resp.success) {
|
|
73
|
+
enqueueToast('The token is successfully updated.', {
|
|
74
|
+
variant: 'success',
|
|
75
|
+
});
|
|
76
|
+
setToken(updatedToken);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onSettled: () => {
|
|
80
|
+
runStore.layout().hideBackdrop();
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
return (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(Heading, { sx: { fontSize: 3 }, children: "IAM Token" }) }), _jsxs(Box, { display: "flex", children: [_jsxs(Box, { children: [_jsx(BoringAvatar, { displayName: token?.name, size: 100, style: { paddingRight: 10 } }), _jsx(Text, { as: "h2", sx: { paddingTop: 3 }, children: token?.name }), _jsx(Box, { mt: 3, children: _jsx(Label, { size: "large", children: token?.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: "Expiration date" }), _jsx(TextInput, { block: true, value: token?.expirationDate.toLocaleDateString(), onChange: nameNameChange, disabled: true })] }), _jsx(Button, { variant: "primary", disabled: !validationResult.name || !validationResult.description, sx: { marginTop: 3 }, onClick: nameSubmit, children: "Update token" })] }) })] })] }));
|
|
85
|
+
};
|
|
86
|
+
export default IAMTokenEdit;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
import { useEffect, useState } from 'react';
|
|
7
|
+
import { PageHeader, FormControl, Button, TextInput, Textarea, Select, Text, IconButton, } from '@primer/react';
|
|
8
|
+
import { Box } from '@datalayer/primer-addons';
|
|
9
|
+
import { CopyIcon } from '@primer/octicons-react';
|
|
10
|
+
import { Calendar, defaultCalendarStrings } from '@fluentui/react';
|
|
11
|
+
import { useCache, useNavigate, useToast } from '../../hooks';
|
|
12
|
+
import { useRunStore } from '../../state';
|
|
13
|
+
export const IAMTokenNew = () => {
|
|
14
|
+
const runStore = useRunStore();
|
|
15
|
+
const { useCreateToken } = useCache();
|
|
16
|
+
const createTokenMutation = useCreateToken();
|
|
17
|
+
const navigate = useNavigate();
|
|
18
|
+
const { enqueueToast } = useToast();
|
|
19
|
+
const [today, _] = useState(new Date());
|
|
20
|
+
const [showToken, setShowToken] = useState(false);
|
|
21
|
+
const [token, setToken] = useState();
|
|
22
|
+
const [formValues, setFormValues] = useState({
|
|
23
|
+
variant: 'user_token',
|
|
24
|
+
name: undefined,
|
|
25
|
+
description: undefined,
|
|
26
|
+
expirationDate: undefined,
|
|
27
|
+
});
|
|
28
|
+
const [validationResult, setValidationResult] = useState({
|
|
29
|
+
variant: undefined,
|
|
30
|
+
name: undefined,
|
|
31
|
+
description: undefined,
|
|
32
|
+
expirationDate: undefined,
|
|
33
|
+
});
|
|
34
|
+
const valueVariantChange = (event) => {
|
|
35
|
+
setFormValues(prevFormValues => ({
|
|
36
|
+
...prevFormValues,
|
|
37
|
+
variant: event.target.value,
|
|
38
|
+
}));
|
|
39
|
+
};
|
|
40
|
+
const valueNameChange = (event) => {
|
|
41
|
+
setFormValues(prevFormValues => ({
|
|
42
|
+
...prevFormValues,
|
|
43
|
+
name: event.target.value,
|
|
44
|
+
}));
|
|
45
|
+
};
|
|
46
|
+
const valueDescriptionChange = (event) => {
|
|
47
|
+
setFormValues(prevFormValues => ({
|
|
48
|
+
...prevFormValues,
|
|
49
|
+
description: event.target.value,
|
|
50
|
+
}));
|
|
51
|
+
};
|
|
52
|
+
const expirationDateChange = (expirationDate) => {
|
|
53
|
+
setFormValues(prevFormValues => ({
|
|
54
|
+
...prevFormValues,
|
|
55
|
+
expirationDate,
|
|
56
|
+
}));
|
|
57
|
+
};
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
setValidationResult({
|
|
60
|
+
...validationResult,
|
|
61
|
+
name: formValues.name === undefined
|
|
62
|
+
? undefined
|
|
63
|
+
: formValues.name.length > 2
|
|
64
|
+
? true
|
|
65
|
+
: false,
|
|
66
|
+
description: formValues.description === undefined
|
|
67
|
+
? undefined
|
|
68
|
+
: formValues.description.length > 2
|
|
69
|
+
? true
|
|
70
|
+
: false,
|
|
71
|
+
expirationDate: formValues.expirationDate === undefined
|
|
72
|
+
? undefined
|
|
73
|
+
: formValues.expirationDate.getTime() > today.getTime()
|
|
74
|
+
? true
|
|
75
|
+
: false,
|
|
76
|
+
});
|
|
77
|
+
}, [formValues]);
|
|
78
|
+
const valueSubmit = () => {
|
|
79
|
+
runStore.layout().showBackdrop('Creating an token...');
|
|
80
|
+
createTokenMutation.mutate({
|
|
81
|
+
name: formValues.name,
|
|
82
|
+
variant: formValues.variant,
|
|
83
|
+
description: formValues.description,
|
|
84
|
+
expirationDate: formValues.expirationDate,
|
|
85
|
+
}, {
|
|
86
|
+
onSuccess: (resp) => {
|
|
87
|
+
if (resp.success && resp.token) {
|
|
88
|
+
enqueueToast(resp.message, { variant: 'success' });
|
|
89
|
+
setToken(resp.token);
|
|
90
|
+
setShowToken(true);
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
onSettled: () => {
|
|
94
|
+
runStore.layout().hideBackdrop();
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
return (_jsx(Box, { children: showToken ? (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "Your Token is created" }) }) }), _jsx(Box, { children: _jsx(Text, { children: "Take note of the Token value, you won't be able to see it after." }) }), _jsx(Box, { children: _jsxs(Text, { children: ["Name: ", token?.name] }) }), _jsx(Box, { children: _jsxs(Text, { children: ["Description: ", token?.description] }) }), _jsx(Box, { children: _jsxs(Text, { children: ["Expiration date: ", token?.expirationDate.toISOString()] }) }), _jsxs(Box, { children: [_jsx(Text, { mb: 2, children: "Value: " }), _jsxs(Box, { display: "flex", sx: { alignItems: 'center', gap: 2 }, children: [_jsx(Text, { as: "code", sx: {
|
|
99
|
+
color: 'fg.onEmphasis',
|
|
100
|
+
bg: 'neutral.emphasis',
|
|
101
|
+
p: 2,
|
|
102
|
+
overflowWrap: 'anywhere',
|
|
103
|
+
flex: 1,
|
|
104
|
+
}, children: token?.value }), _jsx(IconButton, { "aria-label": "Copy token to clipboard", icon: CopyIcon, size: "small", onClick: () => {
|
|
105
|
+
if (token?.value) {
|
|
106
|
+
navigator.clipboard.writeText(token.value);
|
|
107
|
+
enqueueToast('Token copied to clipboard', {
|
|
108
|
+
variant: 'success',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
} })] })] }), _jsx(Box, { mt: 3, children: _jsx(Button, { onClick: e => navigate('/settings/iam/tokens', e), children: "List my Tokens" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "New IAM Token" }) }) }), _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: "Token type" }), _jsx(Select, { name: "type", value: formValues.variant, onChange: valueVariantChange, children: _jsx(Select.Option, { value: "user_token", children: "User Token" }) }), _jsx(FormControl.Caption, { children: "Pick the most appropriate token 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 token name is a short name that identifies in a unique way your token." }), validationResult.name === false && (_jsx(FormControl.Validation, { variant: "error", children: "Name length must be between 2 and 32 characters." }))] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Expiration day" }), _jsx(Calendar, { showGoToToday: true, onSelectDate: expirationDateChange, value: formValues.expirationDate, strings: defaultCalendarStrings }), validationResult.expirationDate !== true ? (_jsx(FormControl.Validation, { variant: "error", children: "Pick an expiration date in the future." })) : (_jsxs(FormControl.Validation, { variant: "success", children: ["Expiration date:", ' ', formValues.expirationDate?.toLocaleDateString(), "."] }))] }), _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.name ||
|
|
112
|
+
!validationResult.description ||
|
|
113
|
+
!validationResult.expirationDate, sx: { marginTop: 2 }, onClick: e => {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
valueSubmit();
|
|
116
|
+
}, children: "Create a token" })] }) }) })] })) }));
|
|
117
|
+
};
|
|
118
|
+
export default IAMTokenNew;
|