@datalayer/core 1.0.19 → 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.
- package/README.md +27 -0
- package/lib/api/DatalayerApi.d.ts +5 -1
- package/lib/api/DatalayerApi.js +55 -8
- package/lib/api/iam/oauth2.d.ts +3 -3
- package/lib/api/iam/oauth2.js +2 -2
- package/lib/api/iam/profile.d.ts +9 -1
- package/lib/api/iam/profile.js +15 -0
- package/lib/api/runtimes/checkpoints.js +1 -1
- package/lib/api/runtimes/snapshots.d.ts +7 -7
- package/lib/api/runtimes/snapshots.js +9 -9
- package/lib/client/auth/storage.js +103 -12
- package/lib/client/index.d.ts +7 -7
- package/lib/client/index.js +1 -1
- package/lib/client/mixins/RuntimesMixin.d.ts +6 -6
- package/lib/client/mixins/RuntimesMixin.js +5 -5
- package/lib/client/mixins/SpacerMixin.js +22 -1
- package/lib/collaboration/DatalayerCollaborationProvider.d.ts +4 -3
- package/lib/components/avatars/DLAvatar.d.ts +24 -0
- package/lib/components/avatars/DLAvatar.js +26 -0
- package/lib/components/avatars/UserProfileAvatar.js +4 -4
- package/lib/components/avatars/index.d.ts +1 -0
- package/lib/components/avatars/index.js +1 -0
- package/lib/components/checkout/StripeCheckout.d.ts +24 -3
- package/lib/components/checkout/StripeCheckout.js +1116 -55
- package/lib/components/display/DatalayerBox.js +6 -1
- package/lib/components/runtimes/RuntimeLauncherDialog.d.ts +2 -2
- package/lib/components/snapshots/{RuntimeSnapshotMenu.d.ts → SandboxSnapshotMenu.d.ts} +4 -4
- package/lib/components/snapshots/{RuntimeSnapshotMenu.js → SandboxSnapshotMenu.js} +33 -33
- package/lib/components/snapshots/index.d.ts +1 -1
- package/lib/components/snapshots/index.js +1 -1
- package/lib/components/storage/ContentsBrowser.js +2 -2
- package/lib/components/tokens/SpaceVariantToken.d.ts +1 -1
- package/lib/components/tokens/SpaceVariantToken.js +7 -4
- package/lib/components/users/PeerIndicator.js +5 -4
- package/lib/hooks/useCache.d.ts +125 -18
- package/lib/hooks/useCache.js +893 -120
- package/lib/hooks/useDatalayer.js +31 -3
- package/lib/hooks/useIAM.js +1 -8
- package/lib/hooks/useProjects.d.ts +44 -0
- package/lib/hooks/useProjects.js +26 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js +1 -1
- package/lib/mocks/components/FlashMock.js +8 -2
- package/lib/models/{RuntimeSnapshot.d.ts → CodeSandboxSnapshot.d.ts} +5 -5
- package/lib/models/{RuntimeSnapshot.js → CodeSandboxSnapshot.js} +1 -1
- package/lib/models/{RuntimeSnapshotDTO.d.ts → CodeSandboxSnapshotDTO.d.ts} +30 -30
- package/lib/models/{RuntimeSnapshotDTO.js → CodeSandboxSnapshotDTO.js} +6 -6
- package/lib/models/Environment.d.ts +4 -0
- package/lib/models/IAM.d.ts +66 -0
- package/lib/models/Organization.d.ts +1 -0
- package/lib/models/Organization.js +1 -0
- package/lib/models/Page.d.ts +2 -2
- package/lib/models/Page.js +2 -2
- package/lib/models/Profile.d.ts +1 -1
- package/lib/models/RuntimeDTO.d.ts +2 -2
- package/lib/models/Space.d.ts +1 -0
- package/lib/models/Space.js +29 -5
- package/lib/models/SpaceDTO.d.ts +4 -0
- package/lib/models/SpaceDTO.js +5 -0
- package/lib/models/Usage.d.ts +15 -0
- package/lib/models/Usage.js +9 -0
- package/lib/models/User.d.ts +21 -0
- package/lib/models/User.js +6 -2
- package/lib/models/index.d.ts +2 -2
- package/lib/models/index.js +2 -2
- package/lib/otel/auth.js +0 -4
- package/lib/services/index.d.ts +1 -1
- package/lib/services/index.js +1 -1
- package/lib/state/substates/IAMState.js +0 -7
- package/lib/state/substates/RuntimesState.d.ts +9 -9
- package/lib/state/substates/RuntimesState.js +3 -3
- package/lib/stateful/runtimes/actions.d.ts +17 -17
- package/lib/stateful/runtimes/actions.js +35 -55
- package/lib/stateful/runtimes/apis.d.ts +3 -3
- package/lib/stateful/runtimes/snapshots.d.ts +2 -2
- package/lib/stateful/runtimes/snapshots.js +7 -7
- package/lib/utils/Format.d.ts +6 -0
- package/lib/utils/Format.js +17 -0
- package/lib/utils/Snapshot.d.ts +1 -1
- package/lib/utils/Snapshot.js +1 -1
- package/lib/views/datasources/DatasourceDetail.d.ts +7 -1
- package/lib/views/datasources/DatasourceDetail.js +61 -23
- package/lib/views/datasources/DatasourceNew.d.ts +8 -1
- package/lib/views/datasources/DatasourceNew.js +23 -10
- package/lib/views/datasources/Datasources.d.ts +5 -1
- package/lib/views/datasources/Datasources.js +38 -30
- package/lib/views/iam/SignInSimple.d.ts +1 -1
- package/lib/views/iam/SignInSimple.js +52 -28
- package/lib/views/iam-tokens/IAMTokenNew.d.ts +3 -1
- package/lib/views/iam-tokens/IAMTokenNew.js +2 -2
- package/lib/views/iam-tokens/IAMTokens.d.ts +3 -1
- package/lib/views/iam-tokens/IAMTokens.js +2 -2
- package/lib/views/otel/OtelHeader.d.ts +5 -0
- package/lib/views/otel/OtelHeader.js +3 -3
- package/lib/views/profile/UserBadge.d.ts +21 -0
- package/lib/views/profile/UserBadge.js +100 -8
- package/lib/views/secrets/Secrets.js +21 -21
- package/package.json +8 -7
|
@@ -4,14 +4,15 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
4
4
|
* Distributed under the terms of the Modified BSD License.
|
|
5
5
|
*/
|
|
6
6
|
import { useState, useEffect } from 'react';
|
|
7
|
-
import { PageLayout, Button, IconButton, Text, Label } from '@primer/react';
|
|
8
|
-
import { Blankslate,
|
|
7
|
+
import { PageLayout, Button, IconButton, Text, Label, Heading, } from '@primer/react';
|
|
8
|
+
import { Blankslate, Table, DataTable } from '@primer/react/experimental';
|
|
9
|
+
import { DatabaseIcon } from '@primer/octicons-react';
|
|
9
10
|
import { Box } from '@datalayer/primer-addons';
|
|
10
11
|
import { EditIcon } from '@datalayer/icons-react';
|
|
11
12
|
import { useCache, useNavigate } from '../../hooks/index.js';
|
|
12
|
-
const DatasourcesTable = ({ datasourcesListRoute, }) => {
|
|
13
|
+
const DatasourcesTable = ({ datasourcesListRoute, principalUid, principalKind, }) => {
|
|
13
14
|
const { useDatasources } = useCache();
|
|
14
|
-
const datasourcesQuery = useDatasources();
|
|
15
|
+
const datasourcesQuery = useDatasources({ principalUid, principalKind });
|
|
15
16
|
const navigate = useNavigate();
|
|
16
17
|
const [datasources, setDatasources] = useState([]);
|
|
17
18
|
useEffect(() => {
|
|
@@ -19,33 +20,40 @@ const DatasourcesTable = ({ datasourcesListRoute, }) => {
|
|
|
19
20
|
setDatasources(datasourcesQuery.data || []);
|
|
20
21
|
}
|
|
21
22
|
}, [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." }) })] })) : (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
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." }) })] })) : (_jsx(Table.Container, { children: _jsx(DataTable, { "aria-labelledby": "teams", "aria-describedby": "teams-subtitle", data: datasources, columns: [
|
|
24
|
+
// @ts-ignore
|
|
25
|
+
{
|
|
26
|
+
header: 'Type',
|
|
27
|
+
field: 'variant',
|
|
28
|
+
renderCell: datasource => _jsx(Label, { children: datasource.variant }),
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
header: 'Name',
|
|
32
|
+
field: 'name',
|
|
33
|
+
rowHeader: true,
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
header: 'Description',
|
|
37
|
+
field: 'description',
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
header: '',
|
|
41
|
+
field: 'id',
|
|
42
|
+
renderCell: datasource => (_jsx(IconButton, { icon: EditIcon, "aria-label": "Edit", size: "small", variant: "invisible", onClick: e => navigate(datasourcesListRoute
|
|
43
|
+
? `${datasourcesListRoute}/${datasource.id}`
|
|
44
|
+
: `${datasource.id}`, e) })),
|
|
45
|
+
},
|
|
46
|
+
] }) }));
|
|
46
47
|
};
|
|
47
|
-
export const Datasources = ({ newDatasourceRoute = '/new/datasource', datasourcesListRoute, } = {}) => {
|
|
48
|
+
export const Datasources = ({ newDatasourceRoute = '/new/datasource', datasourcesListRoute, principalUid, principalKind, } = {}) => {
|
|
48
49
|
const navigate = useNavigate();
|
|
49
|
-
return (
|
|
50
|
+
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: {
|
|
51
|
+
display: 'flex',
|
|
52
|
+
alignItems: 'flex-start',
|
|
53
|
+
justifyContent: 'space-between',
|
|
54
|
+
gap: 3,
|
|
55
|
+
flexWrap: 'wrap',
|
|
56
|
+
mb: 4,
|
|
57
|
+
}, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Datasources" }), _jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: "Configure external data providers available to your workspaces and agents." })] }), _jsx(Button, { size: "small", variant: "primary", leadingVisual: DatabaseIcon, onClick: e => navigate(newDatasourceRoute, e), children: "New datasource" })] }), _jsx(DatasourcesTable, { datasourcesListRoute: datasourcesListRoute, principalUid: principalUid, principalKind: principalKind })] }) }) }));
|
|
50
58
|
};
|
|
51
59
|
export default Datasources;
|
|
@@ -16,7 +16,7 @@ export interface SignInSimpleProps {
|
|
|
16
16
|
onSignIn: (token: string, handle: string) => void;
|
|
17
17
|
/**
|
|
18
18
|
* Called when the user authenticates with an API key.
|
|
19
|
-
* If not provided the "Sign
|
|
19
|
+
* If not provided the "Sign In with an API Key" button is hidden.
|
|
20
20
|
*/
|
|
21
21
|
onApiKeySignIn?: (apiKey: string) => void;
|
|
22
22
|
/**
|
|
@@ -12,10 +12,9 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
12
12
|
*
|
|
13
13
|
* @module views/signin
|
|
14
14
|
*/
|
|
15
|
-
import { useState, useCallback, useRef, useMemo } from 'react';
|
|
15
|
+
import { useState, useCallback, useRef, useMemo, useEffect, } from 'react';
|
|
16
16
|
import { Box, Button, FormControl, Heading, Text, Textarea, TextInput, } from '@primer/react';
|
|
17
|
-
import {
|
|
18
|
-
import { EyeIcon, EyeClosedIcon, KeyIcon, TelescopeIcon, } from '@primer/octicons-react';
|
|
17
|
+
import { EyeIcon, EyeClosedIcon, KeyIcon, LinkExternalIcon, TelescopeIcon, } from '@primer/octicons-react';
|
|
19
18
|
import { coreStore } from '../../state/index.js';
|
|
20
19
|
// ── Component ────────────────────────────────────────────────────────
|
|
21
20
|
export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp, title = 'Datalayer OTEL', description = 'Sign in to access the observability dashboard.', leadingIcon = _jsx(TelescopeIcon, { size: 24 }), }) => {
|
|
@@ -34,6 +33,24 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
|
|
|
34
33
|
const [showApiKeyDialog, setShowApiKeyDialog] = useState(false);
|
|
35
34
|
const [apiKey, setApiKey] = useState('');
|
|
36
35
|
const apiKeyRef = useRef(null);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (showApiKeyDialog) {
|
|
38
|
+
apiKeyRef.current?.focus();
|
|
39
|
+
}
|
|
40
|
+
}, [showApiKeyDialog]);
|
|
41
|
+
const closeApiKeyDialog = useCallback(() => {
|
|
42
|
+
setShowApiKeyDialog(false);
|
|
43
|
+
setApiKey('');
|
|
44
|
+
}, []);
|
|
45
|
+
const handleApiKeyAuthenticate = useCallback(() => {
|
|
46
|
+
if (!apiKey.trim() || !onApiKeySignIn)
|
|
47
|
+
return;
|
|
48
|
+
onApiKeySignIn(apiKey.trim());
|
|
49
|
+
closeApiKeyDialog();
|
|
50
|
+
}, [apiKey, onApiKeySignIn, closeApiKeyDialog]);
|
|
51
|
+
const handleSignUp = useCallback(() => {
|
|
52
|
+
window.open('https://datalayer.ai/signup', '_blank', 'noopener,noreferrer');
|
|
53
|
+
}, []);
|
|
37
54
|
const submit = useCallback(async () => {
|
|
38
55
|
if (!handle || !password || loading)
|
|
39
56
|
return;
|
|
@@ -87,34 +104,41 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
|
|
|
87
104
|
gap: 2,
|
|
88
105
|
mb: 4,
|
|
89
106
|
justifyContent: 'center',
|
|
90
|
-
}, children: [leadingIcon, _jsx(Heading, { sx: { fontSize: 3 }, children: title })] }), _jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mb: 3, textAlign: 'center' }, children: description }), _jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Username" }), _jsx(TextInput, { autoFocus: true, block: true, placeholder: "Your username", value: handle, onChange: e => setHandle(e.target.value), onKeyDown: handleKeyDown })] }), _jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Password" }), _jsx(TextInput, { block: true, placeholder: "Your password", type: showPassword ? 'text' : 'password', value: password, onChange: e => setPassword(e.target.value), onKeyDown: handleKeyDown, trailingAction: _jsx(TextInput.Action, { onClick: () => setShowPassword(!showPassword), icon: showPassword ? EyeClosedIcon : EyeIcon, "aria-label": showPassword ? 'Hide password' : 'Show password', sx: { color: 'var(--fgColor-muted)' } }) })] }), error && (_jsx(Text, { sx: { color: 'danger.fg', fontSize: 1, mb: 3, display: 'block' }, children: error })), _jsx(Button, { variant: "primary", block: true, disabled: loading || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign in' }), onApiKeySignIn && (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
107
|
+
}, children: [leadingIcon, _jsx(Heading, { sx: { fontSize: 3 }, children: title })] }), _jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mb: 3, textAlign: 'center' }, children: description }), _jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Username" }), _jsx(TextInput, { autoFocus: true, block: true, placeholder: "Your username", value: handle, onChange: e => setHandle(e.target.value), onKeyDown: handleKeyDown })] }), _jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Password" }), _jsx(TextInput, { block: true, placeholder: "Your password", type: showPassword ? 'text' : 'password', value: password, onChange: e => setPassword(e.target.value), onKeyDown: handleKeyDown, trailingAction: _jsx(TextInput.Action, { onClick: () => setShowPassword(!showPassword), icon: showPassword ? EyeClosedIcon : EyeIcon, "aria-label": showPassword ? 'Hide password' : 'Show password', sx: { color: 'var(--fgColor-muted)' } }) })] }), error && (_jsx(Text, { sx: { color: 'danger.fg', fontSize: 1, mb: 3, display: 'block' }, children: error })), _jsx(Button, { variant: "primary", block: true, disabled: loading || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign in' }), _jsx(Box, { sx: { mt: 2, display: 'flex', justifyContent: 'center' }, children: _jsx(Button, { size: "small", variant: "invisible", leadingVisual: LinkExternalIcon, onClick: handleSignUp, children: "Sign Up" }) }), onApiKeySignIn && (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
91
108
|
display: 'flex',
|
|
92
109
|
alignItems: 'center',
|
|
93
110
|
gap: 2,
|
|
94
111
|
my: 3,
|
|
95
|
-
}, children: [_jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "or" }), _jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } })] }), _jsx(Button, { block: true, leadingVisual: KeyIcon, onClick: () => setShowApiKeyDialog(true), children: "Sign
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
112
|
+
}, children: [_jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "or" }), _jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } })] }), _jsx(Button, { block: true, leadingVisual: KeyIcon, onClick: () => setShowApiKeyDialog(true), children: "Sign In with an API Key" }), showApiKeyDialog && (_jsx(Box, { role: "dialog", "aria-modal": "true", "aria-labelledby": "signin-api-key-title", onKeyDown: event => {
|
|
113
|
+
if (event.key === 'Escape') {
|
|
114
|
+
closeApiKeyDialog();
|
|
115
|
+
}
|
|
116
|
+
}, onClick: closeApiKeyDialog, sx: {
|
|
117
|
+
position: 'fixed',
|
|
118
|
+
inset: 0,
|
|
119
|
+
zIndex: 200,
|
|
120
|
+
p: 3,
|
|
121
|
+
bg: 'canvas.backdrop',
|
|
122
|
+
display: 'flex',
|
|
123
|
+
alignItems: 'center',
|
|
124
|
+
justifyContent: 'center',
|
|
125
|
+
}, children: _jsxs(Box, { as: "form", onClick: event => event.stopPropagation(), onSubmit: event => {
|
|
126
|
+
event.preventDefault();
|
|
127
|
+
handleApiKeyAuthenticate();
|
|
128
|
+
}, sx: {
|
|
129
|
+
width: 'min(560px, 100%)',
|
|
130
|
+
p: 3,
|
|
131
|
+
borderRadius: 2,
|
|
132
|
+
border: '1px solid',
|
|
133
|
+
borderColor: 'border.default',
|
|
134
|
+
bg: 'canvas.overlay',
|
|
135
|
+
color: 'fg.default',
|
|
136
|
+
boxShadow: 'shadow.large',
|
|
137
|
+
}, children: [_jsx(Heading, { id: "signin-api-key-title", sx: { fontSize: 2, mb: 2 }, children: "Enter your API Key" }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "API Key" }), _jsx(Textarea, { block: true, required: true, autoFocus: true, placeholder: "Paste your API key here", value: apiKey, onInput: (e) => setApiKey(e.target.value), ref: apiKeyRef })] }), _jsxs(Box, { sx: {
|
|
138
|
+
mt: 3,
|
|
139
|
+
display: 'flex',
|
|
140
|
+
justifyContent: 'flex-end',
|
|
141
|
+
gap: 2,
|
|
142
|
+
}, children: [_jsx(Button, { type: "button", onClick: closeApiKeyDialog, children: "Cancel" }), _jsx(Button, { type: "submit", variant: "primary", disabled: !apiKey.trim(), children: "Authenticate" })] })] }) }))] }))] }) }));
|
|
119
143
|
};
|
|
120
144
|
export default SignInSimple;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export type IAMTokenNewProps = {
|
|
2
2
|
/** Route to navigate when clicking "List my Tokens". Defaults to '/settings/iam/tokens'. */
|
|
3
3
|
tokensListRoute?: string;
|
|
4
|
+
/** Whether to render the "New API Key" title header in create mode. Defaults to true. */
|
|
5
|
+
showTitle?: boolean;
|
|
4
6
|
};
|
|
5
|
-
export declare const IAMTokenNew: ({ tokensListRoute, }?: IAMTokenNewProps) => import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
export declare const IAMTokenNew: ({ tokensListRoute, showTitle, }?: IAMTokenNewProps) => import("react/jsx-runtime").JSX.Element;
|
|
6
8
|
export default IAMTokenNew;
|
|
@@ -10,7 +10,7 @@ import { CopyIcon } from '@primer/octicons-react';
|
|
|
10
10
|
import { Calendar, defaultCalendarStrings } from '@fluentui/react';
|
|
11
11
|
import { useCache, useNavigate, useToast } from '../../hooks/index.js';
|
|
12
12
|
import { useRunStore } from '../../state/index.js';
|
|
13
|
-
export const IAMTokenNew = ({ tokensListRoute = '/settings/iam/tokens', } = {}) => {
|
|
13
|
+
export const IAMTokenNew = ({ tokensListRoute = '/settings/iam/tokens', showTitle = true, } = {}) => {
|
|
14
14
|
const runStore = useRunStore();
|
|
15
15
|
const { useCreateToken } = useCache();
|
|
16
16
|
const createTokenMutation = useCreateToken();
|
|
@@ -108,7 +108,7 @@ export const IAMTokenNew = ({ tokensListRoute = '/settings/iam/tokens', } = {})
|
|
|
108
108
|
variant: 'success',
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
|
-
} })] })] }), _jsx(Box, { mt: 3, children: _jsx(Button, { onClick: e => navigate(tokensListRoute, e), children: "List my API Keys" }) })] })) : (_jsxs(_Fragment, { children: [_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "New API Key" }) }) }), _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 ||
|
|
111
|
+
} })] })] }), _jsx(Box, { mt: 3, children: _jsx(Button, { onClick: e => navigate(tokensListRoute, e), children: "List my API Keys" }) })] })) : (_jsxs(_Fragment, { children: [showTitle ? (_jsx(PageHeader, { children: _jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "New API Key" }) }) })) : null, _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
112
|
!validationResult.description ||
|
|
113
113
|
!validationResult.expirationDate, sx: { marginTop: 2 }, onClick: e => {
|
|
114
114
|
e.preventDefault();
|
|
@@ -5,6 +5,8 @@ export type IAMTokensProps = {
|
|
|
5
5
|
tokensListRoute?: string;
|
|
6
6
|
/** Whether to display view titles/headings. Defaults to true. */
|
|
7
7
|
showTitle?: boolean;
|
|
8
|
+
/** Whether to render the "New API Key" button in this component header. Defaults to true. */
|
|
9
|
+
showNewButton?: boolean;
|
|
8
10
|
};
|
|
9
|
-
export declare const IAMTokens: ({ newTokenRoute, tokensListRoute, showTitle, }?: IAMTokensProps) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare const IAMTokens: ({ newTokenRoute, tokensListRoute, showTitle, showNewButton, }?: IAMTokensProps) => import("react/jsx-runtime").JSX.Element;
|
|
10
12
|
export default IAMTokens;
|
|
@@ -80,8 +80,8 @@ const TokensTable = ({ tokensListRoute, showTitle = true, }) => {
|
|
|
80
80
|
setDeletingToken(null);
|
|
81
81
|
}, confirmButtonContent: "Delete", confirmButtonType: "danger", children: ["Are you sure you want to delete the token", ' ', _jsx("strong", { children: deletingToken.name }), "? This action cannot be undone."] }))] }));
|
|
82
82
|
};
|
|
83
|
-
export const IAMTokens = ({ newTokenRoute = '/new/token', tokensListRoute, showTitle = true, } = {}) => {
|
|
83
|
+
export const IAMTokens = ({ newTokenRoute = '/new/token', tokensListRoute, showTitle = true, showNewButton = true, } = {}) => {
|
|
84
84
|
const navigate = useNavigate();
|
|
85
|
-
return (_jsxs(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: [_jsx(PageLayout.Header, { children: _jsxs(PageHeader, { children: [showTitle && (_jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "API Keys" }) })), _jsx(PageHeader.Actions, { children: _jsx(Button, { size: "small", variant: "primary", onClick: e => navigate(newTokenRoute, e), children: "New API Key" }) })] }) }), _jsx(PageLayout.Content, { children: _jsx(Box, { children: _jsx(TokensTable, { tokensListRoute: tokensListRoute, showTitle: showTitle }) }) })] }));
|
|
85
|
+
return (_jsxs(PageLayout, { containerWidth: "full", padding: "normal", style: { overflow: 'visible', minHeight: 'calc(100vh - 45px)' }, children: [showTitle || showNewButton ? (_jsx(PageLayout.Header, { children: _jsxs(PageHeader, { children: [showTitle && (_jsx(PageHeader.TitleArea, { variant: "large", children: _jsx(PageHeader.Title, { children: "API Keys" }) })), showNewButton && (_jsx(PageHeader.Actions, { children: _jsx(Button, { size: "small", variant: "primary", onClick: e => navigate(newTokenRoute, e), children: "New API Key" }) }))] }) })) : null, _jsx(PageLayout.Content, { children: _jsx(Box, { children: _jsx(TokensTable, { tokensListRoute: tokensListRoute, showTitle: showTitle }) }) })] }));
|
|
86
86
|
};
|
|
87
87
|
export default IAMTokens;
|
|
@@ -29,5 +29,10 @@ export interface OtelHeaderProps {
|
|
|
29
29
|
* where data is generated by agents, not manually).
|
|
30
30
|
*/
|
|
31
31
|
showGenerateButtons?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Whether to show account controls (token badge + sign out).
|
|
34
|
+
* Defaults to `true`.
|
|
35
|
+
*/
|
|
36
|
+
showAccountControls?: boolean;
|
|
32
37
|
}
|
|
33
38
|
export declare const OtelHeader: React.FC<OtelHeaderProps>;
|
|
@@ -14,7 +14,7 @@ import { useState, useCallback, useRef } from 'react';
|
|
|
14
14
|
import { Box, Text, Button, Dialog } from '@primer/react';
|
|
15
15
|
import { TelescopeIcon, SignOutIcon } from '@primer/octicons-react';
|
|
16
16
|
import { UserBadge } from '../profile/index.js';
|
|
17
|
-
export const OtelHeader = ({ baseUrl = '', token, trailing, onNavigate, onSignOut, showGenerateButtons = true, }) => {
|
|
17
|
+
export const OtelHeader = ({ baseUrl = '', token, trailing, onNavigate, onSignOut, showGenerateButtons = true, showAccountControls = true, }) => {
|
|
18
18
|
const [dialogOpen, setDialogOpen] = useState(false);
|
|
19
19
|
const [dialogTitle, setDialogTitle] = useState('');
|
|
20
20
|
const [dialogRequest, setDialogRequest] = useState('');
|
|
@@ -33,7 +33,7 @@ export const OtelHeader = ({ baseUrl = '', token, trailing, onNavigate, onSignOu
|
|
|
33
33
|
onNavigate(signalMap[kind]);
|
|
34
34
|
}
|
|
35
35
|
setGenerating(true);
|
|
36
|
-
const url = `${baseUrl}/api/generate/${kind}?count=${count}`;
|
|
36
|
+
const url = `${baseUrl}/api/otel/v1/generate/${kind}?count=${count}`;
|
|
37
37
|
setDialogRequest(`POST ${url}`);
|
|
38
38
|
try {
|
|
39
39
|
const headers = {};
|
|
@@ -70,7 +70,7 @@ export const OtelHeader = ({ baseUrl = '', token, trailing, onNavigate, onSignOu
|
|
|
70
70
|
flexShrink: 0,
|
|
71
71
|
// Allow overflow visible so the JWT popover can extend below the header.
|
|
72
72
|
overflow: 'visible',
|
|
73
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(TelescopeIcon, { size: 20 }), _jsx(Text, { sx: { fontWeight: 'bold', fontSize: 2 }, children: "Datalayer OTEL" })] }), _jsx(Box, { sx: { flex: 1 } }), showGenerateButtons && (_jsxs(_Fragment, { children: [_jsx(Button, { ref: returnFocusRef, size: "small", variant: "primary", disabled: generating, onClick: () => generate('traces', 3), children: "+ Traces" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('ai-traces', 3), children: "+ AI Traces" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('logs', 10), children: "+ Logs" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('metrics', 5), children: "+ Metrics" })] })), trailing, token && _jsx(UserBadge, { token: token }), onSignOut && (_jsx(Button, { size: "small", variant: "invisible", onClick: onSignOut, sx: { color: 'fg.muted' }, leadingVisual: SignOutIcon, children: "Sign out" }))] }), dialogOpen && (_jsxs(Dialog, { title: dialogTitle, onClose: () => setDialogOpen(false), footerButtons: [
|
|
73
|
+
}, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(TelescopeIcon, { size: 20 }), _jsx(Text, { sx: { fontWeight: 'bold', fontSize: 2 }, children: "Datalayer OTEL" })] }), _jsx(Box, { sx: { flex: 1 } }), showGenerateButtons && (_jsxs(_Fragment, { children: [_jsx(Button, { ref: returnFocusRef, size: "small", variant: "primary", disabled: generating, onClick: () => generate('traces', 3), children: "+ Traces" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('ai-traces', 3), children: "+ AI Traces" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('logs', 10), children: "+ Logs" }), _jsx(Button, { size: "small", variant: "primary", disabled: generating, onClick: () => generate('metrics', 5), children: "+ Metrics" })] })), trailing, showAccountControls && token && _jsx(UserBadge, { token: token }), showAccountControls && onSignOut && (_jsx(Button, { size: "small", variant: "invisible", onClick: onSignOut, sx: { color: 'fg.muted' }, leadingVisual: SignOutIcon, children: "Sign out" }))] }), dialogOpen && (_jsxs(Dialog, { title: dialogTitle, onClose: () => setDialogOpen(false), footerButtons: [
|
|
74
74
|
{
|
|
75
75
|
content: 'Close',
|
|
76
76
|
onClick: () => setDialogOpen(false),
|
|
@@ -15,6 +15,27 @@ export interface UserBadgeProps {
|
|
|
15
15
|
token: string;
|
|
16
16
|
/** Display variant for the claims overlay. */
|
|
17
17
|
variant?: 'full' | 'small';
|
|
18
|
+
/**
|
|
19
|
+
* When the popover is rendered in the ``small`` variant, show a ``+``
|
|
20
|
+
* affordance in the top-right corner of the header that lets the user
|
|
21
|
+
* expand the overlay to the ``full`` variant (raw JSON claims).
|
|
22
|
+
*
|
|
23
|
+
* Defaults to ``true``. Ignored when ``variant`` is already ``full``.
|
|
24
|
+
*/
|
|
25
|
+
showExpandToggle?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Threshold (in milliseconds) below which the expiration timestamp is
|
|
28
|
+
* rendered in ``attention.fg`` (yellow) to warn that the token is about
|
|
29
|
+
* to expire. Tokens already past ``exp`` render in ``danger.fg`` (red);
|
|
30
|
+
* tokens further out than this threshold render in ``success.fg`` (green).
|
|
31
|
+
* Defaults to ``10_800_000`` (3 hours).
|
|
32
|
+
*/
|
|
33
|
+
expirationWarningMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Optional callback fired when the claims popover is open and the token is
|
|
36
|
+
* already expired.
|
|
37
|
+
*/
|
|
38
|
+
onTokenExpired?: () => void;
|
|
18
39
|
}
|
|
19
40
|
export declare const UserBadge: React.FC<UserBadgeProps>;
|
|
20
41
|
export default UserBadge;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } 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.
|
|
@@ -14,12 +14,14 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
14
14
|
*
|
|
15
15
|
* @module views/profile
|
|
16
16
|
*/
|
|
17
|
-
import { useState, useRef, useCallback } from 'react';
|
|
17
|
+
import { useState, useRef, useCallback, useEffect } from 'react';
|
|
18
18
|
import { Box, Text } from '@primer/react';
|
|
19
19
|
import { parseJwtPayload, getDatalayerJwtUser, getDatalayerDisplayName, } from '../../utils/Jwt.js';
|
|
20
|
+
import { getRelativeTime } from '../../utils/Date.js';
|
|
20
21
|
// ── Component ─────────────────────────────────────────────────────
|
|
21
|
-
export const UserBadge = ({ token, variant = 'full', }) => {
|
|
22
|
+
export const UserBadge = ({ token, variant = 'full', showExpandToggle = true, expirationWarningMs = 3 * 60 * 60 * 1000, onTokenExpired, }) => {
|
|
22
23
|
const [open, setOpen] = useState(false);
|
|
24
|
+
const [expanded, setExpanded] = useState(false);
|
|
23
25
|
const closeTimer = useRef(null);
|
|
24
26
|
const handleEnter = useCallback(() => {
|
|
25
27
|
if (closeTimer.current)
|
|
@@ -34,9 +36,34 @@ export const UserBadge = ({ token, variant = 'full', }) => {
|
|
|
34
36
|
const user = getDatalayerJwtUser(token);
|
|
35
37
|
const displayName = getDatalayerDisplayName(user, user?.handle ?? '');
|
|
36
38
|
const claims = parseJwtPayload(token);
|
|
39
|
+
// Colour the trigger label based on token expiry:
|
|
40
|
+
// - red when already expired,
|
|
41
|
+
// - yellow when expiring within ``expirationWarningMs``,
|
|
42
|
+
// - muted grey otherwise.
|
|
43
|
+
const msUntilExpiry = claims?.exp
|
|
44
|
+
? claims.exp * 1000 - Date.now()
|
|
45
|
+
: undefined;
|
|
46
|
+
const expired = msUntilExpiry !== undefined && msUntilExpiry <= 0;
|
|
47
|
+
const expiringSoon = msUntilExpiry !== undefined &&
|
|
48
|
+
msUntilExpiry > 0 &&
|
|
49
|
+
msUntilExpiry <= expirationWarningMs;
|
|
50
|
+
const triggerColor = expired
|
|
51
|
+
? 'danger.fg'
|
|
52
|
+
: expiringSoon
|
|
53
|
+
? 'attention.fg'
|
|
54
|
+
: 'fg.muted';
|
|
55
|
+
const expiredNotifiedForTokenRef = useRef(null);
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (!onTokenExpired || !open || !expired)
|
|
58
|
+
return;
|
|
59
|
+
if (expiredNotifiedForTokenRef.current === token)
|
|
60
|
+
return;
|
|
61
|
+
expiredNotifiedForTokenRef.current = token;
|
|
62
|
+
onTokenExpired();
|
|
63
|
+
}, [expired, onTokenExpired, open, token]);
|
|
37
64
|
return (_jsxs(Box, { sx: { position: 'relative' }, onMouseEnter: handleEnter, onMouseLeave: handleLeave, children: [_jsx(Text, { sx: {
|
|
38
65
|
fontSize: 1,
|
|
39
|
-
color:
|
|
66
|
+
color: triggerColor,
|
|
40
67
|
cursor: 'default',
|
|
41
68
|
borderBottom: '1px dashed',
|
|
42
69
|
borderColor: 'border.muted',
|
|
@@ -54,13 +81,36 @@ export const UserBadge = ({ token, variant = 'full', }) => {
|
|
|
54
81
|
borderRadius: 2,
|
|
55
82
|
boxShadow: 'shadow.large',
|
|
56
83
|
overflow: 'hidden',
|
|
57
|
-
}, children: [
|
|
84
|
+
}, children: [_jsxs(Box, { sx: {
|
|
58
85
|
px: 3,
|
|
59
86
|
py: 2,
|
|
60
87
|
bg: 'canvas.subtle',
|
|
61
88
|
borderBottom: '1px solid',
|
|
62
89
|
borderColor: 'border.default',
|
|
63
|
-
|
|
90
|
+
display: 'flex',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
justifyContent: 'space-between',
|
|
93
|
+
gap: 2,
|
|
94
|
+
}, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: "JWT Claims" }), variant === 'small' && showExpandToggle && (_jsx(Box, { as: "button", type: "button", onClick: () => setExpanded(v => !v), "aria-label": expanded ? 'Hide full JWT claims' : 'Show full JWT claims', "aria-expanded": expanded, title: expanded ? 'Hide full JWT claims' : 'Show full JWT claims', sx: {
|
|
95
|
+
appearance: 'none',
|
|
96
|
+
border: '1px solid',
|
|
97
|
+
borderColor: 'border.default',
|
|
98
|
+
borderRadius: 1,
|
|
99
|
+
bg: 'canvas.default',
|
|
100
|
+
color: 'fg.default',
|
|
101
|
+
fontSize: 1,
|
|
102
|
+
lineHeight: 1,
|
|
103
|
+
width: '20px',
|
|
104
|
+
height: '20px',
|
|
105
|
+
display: 'inline-flex',
|
|
106
|
+
alignItems: 'center',
|
|
107
|
+
justifyContent: 'center',
|
|
108
|
+
cursor: 'pointer',
|
|
109
|
+
p: 0,
|
|
110
|
+
'&:hover': {
|
|
111
|
+
bg: 'canvas.subtle',
|
|
112
|
+
},
|
|
113
|
+
}, children: expanded ? '−' : '+' }))] }), claims.user && (_jsx(Box, { sx: {
|
|
64
114
|
px: 3,
|
|
65
115
|
py: 2,
|
|
66
116
|
borderBottom: '1px solid',
|
|
@@ -70,7 +120,49 @@ export const UserBadge = ({ token, variant = 'full', }) => {
|
|
|
70
120
|
gridTemplateColumns: '90px 1fr',
|
|
71
121
|
gap: 1,
|
|
72
122
|
fontSize: 0,
|
|
73
|
-
}, children: [claims.user.email && (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.email })] })), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.handle }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontFamily: 'mono', wordBreak: 'break-all' }, children: claims.user.uid }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Issued" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: new Date(claims.iat * 1000).toISOString() }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Expires" }),
|
|
123
|
+
}, children: [claims.user.email && (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.email })] })), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: claims.user.handle }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontFamily: 'mono', wordBreak: 'break-all' }, children: claims.user.uid }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Issued" }), _jsx(Text, { sx: { fontFamily: 'mono' }, children: new Date(claims.iat * 1000).toISOString() }), _jsx(Text, { sx: { color: 'fg.muted' }, children: "Expires" }), _jsxs(Box, { sx: {
|
|
124
|
+
display: 'flex',
|
|
125
|
+
alignItems: 'center',
|
|
126
|
+
gap: 2,
|
|
127
|
+
minWidth: 0,
|
|
128
|
+
}, children: [_jsx(Text, { sx: {
|
|
129
|
+
fontFamily: 'mono',
|
|
130
|
+
overflow: 'hidden',
|
|
131
|
+
textOverflow: 'ellipsis',
|
|
132
|
+
whiteSpace: 'nowrap',
|
|
133
|
+
}, children: new Date(claims.exp * 1000).toISOString() }), (() => {
|
|
134
|
+
const expDate = new Date(claims.exp * 1000);
|
|
135
|
+
const msUntilExpiry = expDate.getTime() - Date.now();
|
|
136
|
+
const expired = msUntilExpiry <= 0;
|
|
137
|
+
const warning = !expired && msUntilExpiry <= expirationWarningMs;
|
|
138
|
+
const bg = expired
|
|
139
|
+
? 'danger.subtle'
|
|
140
|
+
: warning
|
|
141
|
+
? 'attention.subtle'
|
|
142
|
+
: 'success.subtle';
|
|
143
|
+
const fg = expired
|
|
144
|
+
? 'danger.fg'
|
|
145
|
+
: warning
|
|
146
|
+
? 'attention.fg'
|
|
147
|
+
: 'success.fg';
|
|
148
|
+
const border = expired
|
|
149
|
+
? 'danger.muted'
|
|
150
|
+
: warning
|
|
151
|
+
? 'attention.muted'
|
|
152
|
+
: 'success.muted';
|
|
153
|
+
return (_jsx(Box, { sx: {
|
|
154
|
+
flexShrink: 0,
|
|
155
|
+
fontSize: 0,
|
|
156
|
+
px: 1,
|
|
157
|
+
py: '1px',
|
|
158
|
+
bg,
|
|
159
|
+
color: fg,
|
|
160
|
+
borderRadius: 1,
|
|
161
|
+
border: '1px solid',
|
|
162
|
+
borderColor: border,
|
|
163
|
+
whiteSpace: 'nowrap',
|
|
164
|
+
}, children: getRelativeTime(expDate) }));
|
|
165
|
+
})()] })] }) })), (claims.user?.roles ?? claims.roles ?? []).length > 0 && (_jsxs(Box, { sx: {
|
|
74
166
|
px: 3,
|
|
75
167
|
py: 2,
|
|
76
168
|
borderBottom: '1px solid',
|
|
@@ -85,7 +177,7 @@ export const UserBadge = ({ token, variant = 'full', }) => {
|
|
|
85
177
|
borderRadius: 1,
|
|
86
178
|
border: '1px solid',
|
|
87
179
|
borderColor: 'accent.muted',
|
|
88
|
-
}, children: r }, r))) })] })), variant === 'full' && (_jsx(Box, { as: "pre", sx: {
|
|
180
|
+
}, children: r }, r))) })] })), (variant === 'full' || expanded) && (_jsx(Box, { as: "pre", sx: {
|
|
89
181
|
m: 0,
|
|
90
182
|
px: 3,
|
|
91
183
|
py: 2,
|
|
@@ -19,27 +19,27 @@ const SecretsTable = () => {
|
|
|
19
19
|
setSecrets(secretsQuery.data || []);
|
|
20
20
|
}
|
|
21
21
|
}, [secretsQuery.data]);
|
|
22
|
-
return secrets.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Heading, { children: "Secrets" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "No Secrets found." }) })] })) : (
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
22
|
+
return secrets.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Heading, { children: "Secrets" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "No Secrets found." }) })] })) : (_jsx(Table.Container, { children: _jsx(DataTable, { "aria-labelledby": "secrets", "aria-describedby": "secrets-subtitle", data: secrets, columns: [
|
|
23
|
+
{
|
|
24
|
+
header: 'Type',
|
|
25
|
+
field: 'variant',
|
|
26
|
+
renderCell: secret => _jsx(Label, { children: secret.variant }),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
header: 'Name',
|
|
30
|
+
field: 'name',
|
|
31
|
+
rowHeader: true,
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
header: 'Description',
|
|
35
|
+
field: 'description',
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
header: '',
|
|
39
|
+
field: 'id',
|
|
40
|
+
renderCell: secret => (_jsx(IconButton, { icon: EditIcon, "aria-label": "Edit", size: "small", variant: "invisible", onClick: e => navigate(`${secret.id}`, e) })),
|
|
41
|
+
},
|
|
42
|
+
] }) }));
|
|
43
43
|
};
|
|
44
44
|
export const Secrets = () => {
|
|
45
45
|
const navigate = useNavigate();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datalayer/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"workspaces": [
|
|
6
6
|
".",
|
|
@@ -102,11 +102,11 @@
|
|
|
102
102
|
"rebuild:fresh": "npm run create:patches && npm install && npm run build && npm run clean:cache"
|
|
103
103
|
},
|
|
104
104
|
"dependencies": {
|
|
105
|
-
"@datalayer/icons-react": "^1.0.
|
|
105
|
+
"@datalayer/icons-react": "^1.0.7",
|
|
106
106
|
"@datalayer/jupyter-lexical": "^1.0.16",
|
|
107
107
|
"@datalayer/jupyter-react": "^2.0.7",
|
|
108
|
-
"@datalayer/primer-addons": "^1.0.
|
|
109
|
-
"@datalayer/primer-rjsf": "^1.0.
|
|
108
|
+
"@datalayer/primer-addons": "^1.0.15",
|
|
109
|
+
"@datalayer/primer-rjsf": "^1.0.3",
|
|
110
110
|
"@fluentui/react": "^8.125.3",
|
|
111
111
|
"@jupyter-widgets/base-manager": "^1.0.12",
|
|
112
112
|
"@jupyter-widgets/schema": "^0.5.6",
|
|
@@ -133,8 +133,8 @@
|
|
|
133
133
|
"@primer/primitives": "^10.5.0",
|
|
134
134
|
"@primer/react": "^37.19.0",
|
|
135
135
|
"@primer/react-brand": "^0.58.0",
|
|
136
|
-
"@stripe/react-stripe-js": "^
|
|
137
|
-
"@stripe/stripe-js": "^4.0
|
|
136
|
+
"@stripe/react-stripe-js": "^6.3.0",
|
|
137
|
+
"@stripe/stripe-js": "^9.4.0",
|
|
138
138
|
"@styled-system/css": "^5.1.5",
|
|
139
139
|
"@tailwindcss/vite": "^4.1.13",
|
|
140
140
|
"@tanstack/react-query": "^5.90.6",
|
|
@@ -169,6 +169,7 @@
|
|
|
169
169
|
"ulid": "^2.3.0",
|
|
170
170
|
"unique-names-generator": "^4.7.1",
|
|
171
171
|
"usehooks-ts": "^2.9.1",
|
|
172
|
+
"user": "^0.0.0",
|
|
172
173
|
"uuid": "^13.0.0",
|
|
173
174
|
"validator": "^13.7.0",
|
|
174
175
|
"zod": "^4.1.13",
|
|
@@ -257,6 +258,6 @@
|
|
|
257
258
|
]
|
|
258
259
|
},
|
|
259
260
|
"optionalDependencies": {
|
|
260
|
-
"keytar": "^7.
|
|
261
|
+
"@github/keytar": "^7.10.6"
|
|
261
262
|
}
|
|
262
263
|
}
|