@datalayer/core 1.1.66 → 1.2.12
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 +43 -20
- package/lib/api/constants.d.ts +1 -1
- package/lib/api/constants.js +1 -1
- package/lib/api/contents/attachments.js +3 -7
- package/lib/api/contents/datasets.d.ts +48 -0
- package/lib/api/contents/datasets.js +44 -7
- package/lib/api/contents/runtimeMounts.js +1 -1
- package/lib/api/contents/sandboxUid.d.ts +13 -45
- package/lib/api/contents/sandboxUid.js +14 -65
- package/lib/api/evals/client.d.ts +402 -0
- package/lib/api/evals/client.js +359 -0
- package/lib/api/evals/index.d.ts +10 -0
- package/lib/api/evals/index.js +18 -0
- package/lib/api/evals/request.d.ts +43 -0
- package/lib/api/evals/request.js +67 -0
- package/lib/api/evals/status.d.ts +27 -0
- package/lib/api/evals/status.js +122 -0
- package/lib/api/evals/types.d.ts +1335 -0
- package/lib/api/evals/types.js +5 -0
- package/lib/api/iam/authentication.js +6 -4
- package/lib/api/iam/connectedAgents.d.ts +29 -0
- package/lib/api/iam/connectedAgents.js +35 -0
- package/lib/api/iam/healthz.js +2 -2
- package/lib/api/iam/identityProviders.d.ts +76 -0
- package/lib/api/iam/identityProviders.js +187 -0
- package/lib/api/iam/index.d.ts +1 -0
- package/lib/api/iam/index.js +1 -0
- package/lib/api/iam/mcpPolicy.d.ts +102 -1
- package/lib/api/iam/mcpPolicy.js +38 -2
- package/lib/api/iam/oauth2.js +18 -12
- package/lib/api/iam/profile.d.ts +17 -1
- package/lib/api/iam/profile.js +27 -0
- package/lib/api/iam/scimTokens.d.ts +79 -0
- package/lib/api/iam/scimTokens.js +141 -0
- package/lib/api/iam/secrets.js +10 -23
- package/lib/api/iam/trials.d.ts +38 -0
- package/lib/api/iam/trials.js +66 -0
- package/lib/api/index.d.ts +4 -0
- package/lib/api/index.js +4 -0
- package/lib/api/mcp/observability.d.ts +34 -11
- package/lib/api/mcp/observability.js +97 -59
- package/lib/api/orchestration/client.d.ts +53 -0
- package/lib/api/orchestration/client.js +105 -0
- package/lib/api/orchestration/events.d.ts +88 -0
- package/lib/api/orchestration/events.js +245 -0
- package/lib/api/orchestration/generated.d.ts +693 -0
- package/lib/api/orchestration/generated.js +687 -0
- package/lib/api/orchestration/index.d.ts +30 -0
- package/lib/api/orchestration/index.js +34 -0
- package/lib/api/orchestration/lifecycle.d.ts +39 -0
- package/lib/api/orchestration/lifecycle.js +57 -0
- package/lib/api/orchestration/measures.d.ts +55 -0
- package/lib/api/orchestration/measures.js +99 -0
- package/lib/api/otel/dashboards.d.ts +56 -0
- package/lib/api/otel/dashboards.js +50 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/api/otel/metrics.d.ts +16 -0
- package/lib/api/otel/metrics.js +15 -0
- package/lib/api/scheduler/client.d.ts +32 -0
- package/lib/api/scheduler/client.js +42 -0
- package/lib/api/scheduler/index.d.ts +8 -0
- package/lib/api/scheduler/index.js +16 -0
- package/lib/api/scheduler/request.d.ts +28 -0
- package/lib/api/scheduler/request.js +50 -0
- package/lib/api/scheduler/types.d.ts +88 -0
- package/lib/api/scheduler/types.js +5 -0
- package/lib/api/spacer/comments.d.ts +97 -0
- package/lib/api/spacer/comments.js +45 -0
- package/lib/api/spacer/index.d.ts +9 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/notebooks.d.ts +33 -0
- package/lib/api/spacer/notebooks.js +39 -0
- package/lib/api/spacer/request.d.ts +25 -0
- package/lib/api/spacer/request.js +46 -0
- package/lib/api/spacer/spaces.d.ts +68 -0
- package/lib/api/spacer/spaces.js +45 -0
- package/lib/api/utils/validation.d.ts +4 -4
- package/lib/api/utils/validation.js +10 -7
- package/lib/client/auth/strategies.js +1 -1
- package/lib/client/constants.d.ts +1 -0
- package/lib/client/constants.js +1 -0
- package/lib/client/mixins/IAMMixin.js +2 -2
- package/lib/components/animation/AnimatedText.d.ts +1 -44
- package/lib/components/animation/AnimatedText.js +6 -122
- package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
- package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
- package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
- package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
- package/lib/components/anonymous/index.d.ts +7 -0
- package/lib/components/anonymous/index.js +15 -0
- package/lib/components/avatars/UserAvatar.d.ts +7 -1
- package/lib/components/avatars/UserAvatar.js +15 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
- package/lib/components/billing/BillingEntitySelect.js +49 -10
- package/lib/components/billing/eligibility.d.ts +22 -0
- package/lib/components/billing/eligibility.js +27 -0
- package/lib/components/billing/index.d.ts +1 -0
- package/lib/components/billing/index.js +1 -0
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/checkout/StripeCheckout.js +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
- package/lib/components/display/DatalayerBox.d.ts +2 -3
- package/lib/components/display/DatalayerBox.js +1 -1
- package/lib/components/display/NavLink.js +3 -2
- package/lib/components/display/VisuallyHidden.d.ts +1 -2
- package/lib/components/labels/StatusLabels.d.ts +2 -10
- package/lib/components/labels/StatusLabels.js +2 -26
- package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
- package/lib/components/principal/PrincipalAppearance.js +232 -174
- package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
- package/lib/components/principal/PrincipalAvatar.js +2 -2
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
- package/lib/components/screencapture/Screencapture.js +46 -3
- package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
- package/lib/components/sharing/ShareAccessComponent.js +110 -78
- package/lib/components/sharing/SharingEditor.d.ts +5 -1
- package/lib/components/sharing/SharingEditor.js +9 -4
- package/lib/components/sharing/index.d.ts +1 -0
- package/lib/components/sharing/index.js +1 -0
- package/lib/components/sharing/sandboxSharing.d.ts +26 -0
- package/lib/components/sharing/sandboxSharing.js +47 -0
- package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
- package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
- package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
- package/lib/components/spaces/SpaceDisplay.js +92 -0
- package/lib/components/spaces/index.d.ts +4 -0
- package/lib/components/spaces/index.js +7 -0
- package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
- package/lib/components/spaces/spaceDisplayModel.js +170 -0
- package/lib/config/Configuration.d.ts +4 -4
- package/lib/config/Configuration.js +7 -7
- package/lib/config/index.d.ts +1 -0
- package/lib/config/index.js +1 -0
- package/lib/config/planes.d.ts +45 -0
- package/lib/config/planes.js +53 -0
- package/lib/hooks/cacheConverters.d.ts +0 -7
- package/lib/hooks/cacheConverters.js +0 -25
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useBackdrop.d.ts +4 -5
- package/lib/hooks/useBillingEntityStore.js +3 -0
- package/lib/hooks/useCache.d.ts +197 -44
- package/lib/hooks/useCache.js +1586 -494
- package/lib/hooks/useContents.d.ts +22 -1
- package/lib/hooks/useContents.js +90 -21
- package/lib/hooks/useMcp.d.ts +87 -1
- package/lib/hooks/useMcp.js +248 -13
- package/lib/hooks/useNavigate.d.ts +41 -3
- package/lib/hooks/useNavigate.js +116 -52
- package/lib/hooks/usePrincipalCacheStore.js +3 -0
- package/lib/hooks/usePrincipalStore.js +3 -0
- package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
- package/lib/hooks/useSpaceCacheStore.js +85 -0
- package/lib/hooks/useWindowSize.js +1 -1
- package/lib/models/CreditsDTO.d.ts +6 -5
- package/lib/models/CreditsDTO.js +7 -5
- package/lib/models/IAMProvidersSpecs.d.ts +10 -5
- package/lib/models/IAMProvidersSpecs.js +0 -23
- package/lib/models/McpBinding.d.ts +6 -0
- package/lib/models/Organization.d.ts +69 -0
- package/lib/models/Organization.js +96 -0
- package/lib/models/Secret.d.ts +1 -2
- package/lib/models/Secret.js +2 -18
- package/lib/models/StartedBy.d.ts +34 -0
- package/lib/models/StartedBy.js +36 -0
- package/lib/models/Team.d.ts +2 -0
- package/lib/models/Team.js +2 -0
- package/lib/models/User.d.ts +4 -0
- package/lib/models/User.js +3 -0
- package/lib/models/UserSettings.d.ts +13 -0
- package/lib/models/UserSettings.js +9 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
- package/lib/navigation/adapters/react-router.d.ts +1 -1
- package/lib/navigation/adapters/react-router.js +3 -0
- package/lib/navigation/components.js +2 -3
- package/lib/routes/publicPaths.js +4 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +1 -0
- package/lib/state/sessionEnd.d.ts +55 -0
- package/lib/state/sessionEnd.js +162 -0
- package/lib/state/substates/CoreState.js +3 -16
- package/lib/state/substates/IAMState.d.ts +3 -3
- package/lib/state/substates/IAMState.js +7 -0
- package/lib/state/substates/LayoutState.js +12 -0
- package/lib/state/substates/NavigationState.d.ts +82 -0
- package/lib/state/substates/NavigationState.js +255 -0
- package/lib/state/substates/ProfileState.d.ts +1 -0
- package/lib/state/substates/ProfileState.js +1 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/utils/Lazy.d.ts +20 -0
- package/lib/utils/Lazy.js +32 -6
- package/lib/utils/Screencapture.d.ts +15 -0
- package/lib/utils/Screencapture.js +26 -20
- package/lib/utils/WithSuspense.d.ts +11 -1
- package/lib/utils/WithSuspense.js +11 -1
- package/lib/views/mcp/AdmittedClients.d.ts +44 -0
- package/lib/views/mcp/AdmittedClients.js +59 -0
- package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
- package/lib/views/mcp/ApprovalQueue.js +95 -0
- package/lib/views/mcp/ConnectedAgents.js +38 -3
- package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
- package/lib/views/mcp/EnterpriseConsole.js +23 -1
- package/lib/views/mcp/IdentityProviders.d.ts +33 -0
- package/lib/views/mcp/IdentityProviders.js +299 -0
- package/lib/views/mcp/McpDashboard.js +90 -7
- package/lib/views/mcp/McpHome.js +1 -1
- package/lib/views/mcp/McpObservability.d.ts +30 -1
- package/lib/views/mcp/McpObservability.js +105 -19
- package/lib/views/mcp/NotebookRuns.d.ts +39 -0
- package/lib/views/mcp/NotebookRuns.js +44 -0
- package/lib/views/mcp/OrganizationPolicy.js +2 -1
- package/lib/views/mcp/PersonalPolicy.js +2 -1
- package/lib/views/mcp/PolicyForm.d.ts +17 -1
- package/lib/views/mcp/PolicyForm.js +25 -3
- package/lib/views/mcp/PolicyHistory.d.ts +13 -0
- package/lib/views/mcp/PolicyHistory.js +14 -1
- package/lib/views/mcp/RunDetail.d.ts +87 -0
- package/lib/views/mcp/RunDetail.js +186 -0
- package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
- package/lib/views/mcp/ScimProvisioning.js +173 -0
- package/lib/views/mcp/TeamPolicies.js +66 -5
- package/lib/views/mcp/ToolAccess.d.ts +60 -0
- package/lib/views/mcp/ToolAccess.js +101 -0
- package/lib/views/mcp/TraceTimeline.d.ts +81 -0
- package/lib/views/mcp/TraceTimeline.js +132 -0
- package/lib/views/mcp/index.d.ts +5 -0
- package/lib/views/mcp/index.js +5 -0
- package/lib/views/otel/simpleAuthStore.js +3 -0
- package/lib/views/secrets/SecretEdit.js +3 -2
- package/lib/views/secrets/SecretNew.js +5 -1
- package/package.json +271 -264
- package/scripts/generate-mcp-types.py +16 -10
- package/scripts/generate-orchestration-types.py +920 -0
package/lib/client/constants.js
CHANGED
|
@@ -75,7 +75,7 @@ export function IAMMixin(Base) {
|
|
|
75
75
|
catch (error) {
|
|
76
76
|
// Clear the invalid token
|
|
77
77
|
await this.setToken('');
|
|
78
|
-
throw new Error(`Invalid token: ${error instanceof Error ? error.message : 'Unknown error'}
|
|
78
|
+
throw new Error(`Invalid token: ${error instanceof Error ? error.message : 'Unknown error'}`, { cause: error });
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
81
|
/** Log out the current user. */
|
|
@@ -144,7 +144,7 @@ export function IAMMixin(Base) {
|
|
|
144
144
|
async checkIAMHealth() {
|
|
145
145
|
const startTime = Date.now();
|
|
146
146
|
const errors = [];
|
|
147
|
-
let status
|
|
147
|
+
let status;
|
|
148
148
|
let healthy = false;
|
|
149
149
|
try {
|
|
150
150
|
// Test basic connectivity and authentication by getting user profile
|
|
@@ -18,8 +18,6 @@ export type AnimatedTextWords = {
|
|
|
18
18
|
* it resolves to the CSS variable Primer sets.
|
|
19
19
|
*/
|
|
20
20
|
color?: AnimatedTextColor;
|
|
21
|
-
/** Overrides the background of this piece alone. */
|
|
22
|
-
background?: string;
|
|
23
21
|
};
|
|
24
22
|
export type AnimatedTextColor = 'accent' | 'success' | 'attention' | 'severe' | 'done' | 'muted' | 'default' | (string & {});
|
|
25
23
|
export interface AnimatedTextProps extends Omit<React.HTMLAttributes<HTMLSpanElement>, 'children' | 'color'> {
|
|
@@ -36,39 +34,6 @@ export interface AnimatedTextProps extends Omit<React.HTMLAttributes<HTMLSpanEle
|
|
|
36
34
|
parts?: AnimatedTextPart[];
|
|
37
35
|
/** Colour applied to cycling pieces that do not name their own. */
|
|
38
36
|
color?: AnimatedTextColor;
|
|
39
|
-
/**
|
|
40
|
-
* The colours to draw cycling words in when neither the piece nor `color`
|
|
41
|
-
* names one. Each word takes a different colour, and changes colour as it
|
|
42
|
-
* changes word.
|
|
43
|
-
*/
|
|
44
|
-
palette?: string[];
|
|
45
|
-
/**
|
|
46
|
-
* What sits behind the cycling words. White by default so a coloured word
|
|
47
|
-
* stays readable over artwork; pass `'transparent'` for a plain background
|
|
48
|
-
* where the plate is not wanted.
|
|
49
|
-
*/
|
|
50
|
-
background?: string;
|
|
51
|
-
/**
|
|
52
|
-
* Hold every cycling piece at the width of the longest word it can show,
|
|
53
|
-
* instead of letting it size itself to whichever word is currently up.
|
|
54
|
-
*
|
|
55
|
-
* Off by default, because it changes the look: a piece is then as wide as
|
|
56
|
-
* its longest word even when a short one is showing, which is right for a
|
|
57
|
-
* line that reads as a slot being filled and wrong for one meant to read as
|
|
58
|
-
* an ordinary sentence.
|
|
59
|
-
*
|
|
60
|
-
* Turn it on when the line is set large, or is close to the width it has.
|
|
61
|
-
* Words of different lengths otherwise shove the rest of the sentence
|
|
62
|
-
* sideways on every tick, and the longest combination can take a line that
|
|
63
|
-
* fits on one row and drop it onto two — which, since a theme may set any
|
|
64
|
-
* typeface, is not something a caller can rule out by measuring.
|
|
65
|
-
*
|
|
66
|
-
* The reservation is made by the browser, not by a measurement: all of the
|
|
67
|
-
* words are laid into one grid cell and the ones not showing are hidden, so
|
|
68
|
-
* the piece is exactly as wide as the widest of them in the font and size it
|
|
69
|
-
* actually ends up with.
|
|
70
|
-
*/
|
|
71
|
-
reserveWidth?: boolean;
|
|
72
37
|
intervalMs?: number;
|
|
73
38
|
transitionMs?: number;
|
|
74
39
|
}
|
|
@@ -86,14 +51,6 @@ export interface AnimatedTextProps extends Omit<React.HTMLAttributes<HTMLSpanEle
|
|
|
86
51
|
* ]}
|
|
87
52
|
* />
|
|
88
53
|
* ```
|
|
89
|
-
*
|
|
90
|
-
* Set large, or set close to the width available, pass `reserveWidth` so the
|
|
91
|
-
* cycling pieces hold the width of their longest word and the line neither
|
|
92
|
-
* shifts on each tick nor wraps on its longest combination:
|
|
93
|
-
*
|
|
94
|
-
* ```tsx
|
|
95
|
-
* <AnimatedText reserveWidth parts={[...]} background="transparent" />
|
|
96
|
-
* ```
|
|
97
54
|
*/
|
|
98
|
-
export declare function AnimatedText({ prefix, words, suffix, parts, color,
|
|
55
|
+
export declare function AnimatedText({ prefix, words, suffix, parts, color, intervalMs, transitionMs, style, ...rest }: AnimatedTextProps): JSX.Element;
|
|
99
56
|
export default AnimatedText;
|
|
@@ -10,33 +10,6 @@ const THEME_COLORS = {
|
|
|
10
10
|
muted: 'var(--fgColor-muted, var(--color-fg-muted))',
|
|
11
11
|
default: 'inherit',
|
|
12
12
|
};
|
|
13
|
-
/**
|
|
14
|
-
* The colours the cycling words are drawn in when none is named.
|
|
15
|
-
*
|
|
16
|
-
* Fixed values rather than Primer's theme tokens, because the plate behind
|
|
17
|
-
* the words is white in either theme: a token would resolve to its light-mode
|
|
18
|
-
* variant in the dark and wash out. Every one of these sits between 4.8 and
|
|
19
|
-
* 5.4 contrast on white — comfortably readable, and none of them the pale or
|
|
20
|
-
* near-black ends of the palette.
|
|
21
|
-
*/
|
|
22
|
-
const MEDIUM_PALETTE = [
|
|
23
|
-
'#0969da', // blue
|
|
24
|
-
'#1a7f37', // green
|
|
25
|
-
'#8250df', // purple
|
|
26
|
-
'#bc4c00', // orange
|
|
27
|
-
'#cf222e', // red
|
|
28
|
-
'#1b7c83', // teal
|
|
29
|
-
'#bf3989', // pink
|
|
30
|
-
];
|
|
31
|
-
/**
|
|
32
|
-
* What sits behind the cycling words.
|
|
33
|
-
*
|
|
34
|
-
* A coloured word over a photograph or an illustrated hero is legible only by
|
|
35
|
-
* luck: the contrast changes with whatever the artwork happens to be doing
|
|
36
|
-
* behind that glyph. A solid plate underneath makes it legible by
|
|
37
|
-
* construction, whatever it is laid over.
|
|
38
|
-
*/
|
|
39
|
-
const DEFAULT_BACKGROUND = '#ffffff';
|
|
40
13
|
/**
|
|
41
14
|
* Resolve a colour: a known token becomes the themed CSS variable, anything
|
|
42
15
|
* else is passed through so a caller can still give a literal colour.
|
|
@@ -47,21 +20,6 @@ function resolveColor(color) {
|
|
|
47
20
|
}
|
|
48
21
|
return THEME_COLORS[color] ?? color;
|
|
49
22
|
}
|
|
50
|
-
/** Whether this reader has asked for less movement. */
|
|
51
|
-
function usePrefersReducedMotion() {
|
|
52
|
-
const [reduced, setReduced] = useState(false);
|
|
53
|
-
useEffect(() => {
|
|
54
|
-
if (typeof window === 'undefined' || !window.matchMedia) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const query = window.matchMedia('(prefers-reduced-motion: reduce)');
|
|
58
|
-
const update = () => setReduced(query.matches);
|
|
59
|
-
update();
|
|
60
|
-
query.addEventListener('change', update);
|
|
61
|
-
return () => query.removeEventListener('change', update);
|
|
62
|
-
}, []);
|
|
63
|
-
return reduced;
|
|
64
|
-
}
|
|
65
23
|
/**
|
|
66
24
|
* A line of text in which one or more words change, in step.
|
|
67
25
|
*
|
|
@@ -76,20 +34,8 @@ function usePrefersReducedMotion() {
|
|
|
76
34
|
* ]}
|
|
77
35
|
* />
|
|
78
36
|
* ```
|
|
79
|
-
*
|
|
80
|
-
* Set large, or set close to the width available, pass `reserveWidth` so the
|
|
81
|
-
* cycling pieces hold the width of their longest word and the line neither
|
|
82
|
-
* shifts on each tick nor wraps on its longest combination:
|
|
83
|
-
*
|
|
84
|
-
* ```tsx
|
|
85
|
-
* <AnimatedText reserveWidth parts={[...]} background="transparent" />
|
|
86
|
-
* ```
|
|
87
37
|
*/
|
|
88
|
-
export function AnimatedText({ prefix, words, suffix, parts, color,
|
|
89
|
-
// The words still change for a reader who asked for less movement — that is
|
|
90
|
-
// what this component is for — but they do it without travelling, and the
|
|
91
|
-
// fade is dropped rather than merely shortened.
|
|
92
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
38
|
+
export function AnimatedText({ prefix, words, suffix, parts, color, intervalMs = 1800, transitionMs = 240, style, ...rest }) {
|
|
93
39
|
// The older three-prop form is the same thing with one cycling piece.
|
|
94
40
|
const resolvedParts = useMemo(() => {
|
|
95
41
|
if (parts && parts.length > 0) {
|
|
@@ -124,70 +70,12 @@ export function AnimatedText({ prefix, words, suffix, parts, color, palette = ME
|
|
|
124
70
|
clearInterval(timer);
|
|
125
71
|
};
|
|
126
72
|
}, [cycleLength, intervalMs, transitionMs]);
|
|
127
|
-
|
|
128
|
-
* The colour of the cycling piece at `ordinal`, for the current step.
|
|
129
|
-
*
|
|
130
|
-
* Derived rather than random so a re-render does not repaint the line, and
|
|
131
|
-
* offset by the ordinal so two words showing at once never take the same
|
|
132
|
-
* colour. The palette length being prime keeps the pairing from settling
|
|
133
|
-
* into a short repeating pattern.
|
|
134
|
-
*/
|
|
135
|
-
const paletteColor = (ordinal) => {
|
|
136
|
-
if (palette.length === 0) {
|
|
137
|
-
return undefined;
|
|
138
|
-
}
|
|
139
|
-
return palette[(step * 2 + ordinal * 3) % palette.length];
|
|
140
|
-
};
|
|
141
|
-
/** How a word arrives and leaves, and how far it travels doing it. */
|
|
142
|
-
const motion = reducedMotion
|
|
143
|
-
? { transition: undefined }
|
|
144
|
-
: {
|
|
145
|
-
transition: `opacity ${transitionMs}ms ease, transform ${transitionMs}ms ease`,
|
|
146
|
-
};
|
|
147
|
-
const offset = reducedMotion ? 'translateY(0)' : 'translateY(0.25em)';
|
|
148
|
-
/** The plate the words of a piece are drawn on, and the colour they take. */
|
|
149
|
-
const pieceStyle = (part, ordinal) => {
|
|
150
|
-
const plate = part.background ?? background;
|
|
151
|
-
const hasPlate = plate !== 'transparent' && plate !== 'none';
|
|
152
|
-
return {
|
|
153
|
-
// An explicitly named colour always wins; otherwise the palette.
|
|
154
|
-
color: resolveColor(part.color ?? color) ?? paletteColor(ordinal),
|
|
155
|
-
backgroundColor: hasPlate ? plate : undefined,
|
|
156
|
-
// Enough to keep the plate clear of the glyphs without the words
|
|
157
|
-
// drifting apart from the fixed text around them.
|
|
158
|
-
padding: hasPlate ? '0 0.25em' : undefined,
|
|
159
|
-
borderRadius: hasPlate ? '0.25em' : undefined,
|
|
160
|
-
};
|
|
161
|
-
};
|
|
162
|
-
const wordStyle = (part, ordinal) => ({
|
|
163
|
-
...pieceStyle(part, ordinal),
|
|
73
|
+
const wordStyle = (part) => ({
|
|
164
74
|
display: 'inline-block',
|
|
165
|
-
|
|
75
|
+
color: resolveColor(part.color ?? color),
|
|
76
|
+
transition: `opacity ${transitionMs}ms ease, transform ${transitionMs}ms ease`,
|
|
166
77
|
opacity: visible ? 1 : 0,
|
|
167
|
-
transform: visible ? 'translateY(0)' :
|
|
168
|
-
});
|
|
169
|
-
/**
|
|
170
|
-
* The piece as a slot: a grid of one cell, holding every word it can show.
|
|
171
|
-
*
|
|
172
|
-
* The cell takes the width of its widest occupant, so the slot is the same
|
|
173
|
-
* width whichever word is up — which is the whole point of `reserveWidth`,
|
|
174
|
-
* and why the words have to be in the document rather than measured.
|
|
175
|
-
*/
|
|
176
|
-
const slotStyle = (part, ordinal) => ({
|
|
177
|
-
...pieceStyle(part, ordinal),
|
|
178
|
-
display: 'inline-grid',
|
|
179
|
-
justifyItems: 'center',
|
|
180
|
-
});
|
|
181
|
-
const wordInSlotStyle = (showing) => ({
|
|
182
|
-
gridArea: '1 / 1',
|
|
183
|
-
whiteSpace: 'nowrap',
|
|
184
|
-
// Hidden rather than merely transparent: the words not showing should be
|
|
185
|
-
// out of the accessibility tree and out of the way of the pointer, while
|
|
186
|
-
// still holding the cell open.
|
|
187
|
-
visibility: showing ? 'visible' : 'hidden',
|
|
188
|
-
...motion,
|
|
189
|
-
opacity: showing && visible ? 1 : 0,
|
|
190
|
-
transform: showing && visible ? 'translateY(0)' : offset,
|
|
78
|
+
transform: visible ? 'translateY(0)' : 'translateY(0.25em)',
|
|
191
79
|
});
|
|
192
80
|
return (_jsx("span", { ...rest, style: style, children: resolvedParts.map((part, index) => {
|
|
193
81
|
if (typeof part === 'string') {
|
|
@@ -197,11 +85,7 @@ export function AnimatedText({ prefix, words, suffix, parts, color, palette = ME
|
|
|
197
85
|
if (available.length === 0) {
|
|
198
86
|
return null;
|
|
199
87
|
}
|
|
200
|
-
|
|
201
|
-
const current = step % available.length;
|
|
202
|
-
return (_jsx("span", { "aria-live": "polite", style: reserveWidth ? slotStyle(part, ordinal) : wordStyle(part, ordinal), children: reserveWidth
|
|
203
|
-
? available.map((word, wordIndex) => (_jsx("span", { "aria-hidden": wordIndex === current ? undefined : true, style: wordInSlotStyle(wordIndex === current), children: word }, word)))
|
|
204
|
-
: available[current] }, `words-${index}`));
|
|
88
|
+
return (_jsx("span", { "aria-live": "polite", style: wordStyle(part), children: available[step % available.length] }, `words-${index}`));
|
|
205
89
|
}) }));
|
|
206
90
|
}
|
|
207
91
|
function greatestCommonDivisor(a, b) {
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the workspace says when the visitor's trial key runs out.
|
|
3
|
+
*
|
|
4
|
+
* The end of a trial of anonymous inference is a fact worth stating plainly.
|
|
5
|
+
* Left unsaid it arrives as an agent that has stopped answering, and a reader
|
|
6
|
+
* with no account has no way to tell that apart from a broken one — so this
|
|
7
|
+
* takes the workspace's place and says which of the two happened, and what to
|
|
8
|
+
* do about it. The workspace, not the conversation: on a layout whose
|
|
9
|
+
* transcript is a panel the reader has not opened, a message inside the chat
|
|
10
|
+
* is a message nobody sees.
|
|
11
|
+
*
|
|
12
|
+
* The form is `SignInSimple`, the same one the examples and the landing use,
|
|
13
|
+
* rather than a second sign-in written for this panel: a person who signs in
|
|
14
|
+
* here should end up in exactly the state they would have been in had they
|
|
15
|
+
* signed in first.
|
|
16
|
+
*
|
|
17
|
+
* Signing in is enough. The key is read from the IAM store on every render of
|
|
18
|
+
* the chat, so a member's token replaces the dead trial one where it stands —
|
|
19
|
+
* no reload, and the conversation is still underneath.
|
|
20
|
+
*
|
|
21
|
+
* @module components/anonymous/AnonymousKeyExpired
|
|
22
|
+
*/
|
|
23
|
+
import type { JSX } from 'react';
|
|
24
|
+
export type AnonymousKeyExpiredProps = {
|
|
25
|
+
/**
|
|
26
|
+
* What the visitor was talking to, named so the panel is about their
|
|
27
|
+
* conversation rather than about authentication in general.
|
|
28
|
+
*/
|
|
29
|
+
agentName?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Whether anything else on the page still works without a key.
|
|
32
|
+
*
|
|
33
|
+
* True where the code runs in the browser: the kernel owes nothing to the
|
|
34
|
+
* inference service, so the notebook beside the chat is unaffected and
|
|
35
|
+
* saying so is the difference between "the agent stopped" and "the page
|
|
36
|
+
* broke".
|
|
37
|
+
*/
|
|
38
|
+
sandboxStillRuns?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether the credential that ran out was the anonymous trial key.
|
|
41
|
+
*
|
|
42
|
+
* It decides the wording, and the difference is not cosmetic. "This demo
|
|
43
|
+
* runs on a shared key" is true of a visitor who never signed in and simply
|
|
44
|
+
* wrong for a member whose own session ran out — that reader would go
|
|
45
|
+
* looking for a demo key they never had, and conclude the page had confused
|
|
46
|
+
* them with somebody else.
|
|
47
|
+
*
|
|
48
|
+
* Defaults to the trial, because that is the only credential this panel
|
|
49
|
+
* could describe when it was written and every existing caller means it.
|
|
50
|
+
*/
|
|
51
|
+
temporary?: boolean;
|
|
52
|
+
/** Called after a successful sign-in, once the token is stored. */
|
|
53
|
+
onSignedIn?: () => void;
|
|
54
|
+
};
|
|
55
|
+
export declare function AnonymousKeyExpired({ agentName, sandboxStillRuns, temporary, onSignedIn, }: AnonymousKeyExpiredProps): JSX.Element;
|
|
56
|
+
export default AnonymousKeyExpired;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { Text } from '@primer/react';
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
|
+
import { KeyIcon } from '@primer/octicons-react';
|
|
6
|
+
import { SignInSimple } from '../../views/iam/SignInSimple.js';
|
|
7
|
+
import { useCoreStore, iamStore } from '../../state/substates/index.js';
|
|
8
|
+
export function AnonymousKeyExpired({ agentName, sandboxStillRuns = false, temporary = true, onSignedIn, }) {
|
|
9
|
+
const { configuration } = useCoreStore();
|
|
10
|
+
const handleSignIn = useCallback((token) => {
|
|
11
|
+
/*
|
|
12
|
+
* Through the store's own check, not by writing the token into it.
|
|
13
|
+
*
|
|
14
|
+
* `checkIAMToken` fetches the user the token belongs to and stores both,
|
|
15
|
+
* which is what every other sign-in in the product does — setting the
|
|
16
|
+
* token alone would have left the rest of the page believing nobody was
|
|
17
|
+
* signed in, since what it looks at is the user. The agent works either
|
|
18
|
+
* way; the header above it would not have noticed.
|
|
19
|
+
*/
|
|
20
|
+
void iamStore.getState().checkIAMToken(token);
|
|
21
|
+
// And the host lets the trial key go: it is spent, and a session left
|
|
22
|
+
// sitting in `expired` would keep this panel on screen over a working
|
|
23
|
+
// chat. The session is the host's — the in-page runtime that minted
|
|
24
|
+
// the key — so clearing it is `onSignedIn`'s job, not this panel's.
|
|
25
|
+
onSignedIn?.();
|
|
26
|
+
}, [onSignedIn]);
|
|
27
|
+
return (_jsx(Box, { sx: {
|
|
28
|
+
height: '100%',
|
|
29
|
+
minHeight: 0,
|
|
30
|
+
overflowY: 'auto',
|
|
31
|
+
bg: 'canvas.default',
|
|
32
|
+
px: 4,
|
|
33
|
+
py: 4,
|
|
34
|
+
}, children: _jsxs(Box, { sx: { maxWidth: 440, mx: 'auto' }, children: [_jsxs(Box, { sx: {
|
|
35
|
+
display: 'flex',
|
|
36
|
+
alignItems: 'center',
|
|
37
|
+
justifyContent: 'center',
|
|
38
|
+
gap: 2,
|
|
39
|
+
color: 'attention.fg',
|
|
40
|
+
mb: 2,
|
|
41
|
+
}, children: [_jsx(KeyIcon, { size: 20 }), _jsx(Text, { sx: { fontSize: 2, fontWeight: 'semibold', color: 'fg.default' }, children: temporary
|
|
42
|
+
? 'This demo runs on a shared key'
|
|
43
|
+
: 'Your key has expired' })] }), _jsxs(Text, { as: "p", sx: {
|
|
44
|
+
fontSize: 1,
|
|
45
|
+
color: 'fg.muted',
|
|
46
|
+
textAlign: 'center',
|
|
47
|
+
mb: 3,
|
|
48
|
+
}, children: [temporary
|
|
49
|
+
? `${agentName ?? 'The agent'} has used the time this key allows. Sign in to point your own agent at it, use your own data, and drop the time limit.`
|
|
50
|
+
: `${agentName ?? 'The agent'} stopped because your session ran out.`, sandboxStillRuns
|
|
51
|
+
? ' Your notebook is still running in this page.'
|
|
52
|
+
: ''] }), _jsx(SignInSimple
|
|
53
|
+
// The panel above has already said what happened and why; the form's
|
|
54
|
+
// own hero would say it a second time, in a bigger font.
|
|
55
|
+
, {
|
|
56
|
+
// The panel above has already said what happened and why; the form's
|
|
57
|
+
// own hero would say it a second time, in a bigger font.
|
|
58
|
+
hideHero: true, fillHeight: false, calloutTitle: "Sign in to keep going",
|
|
59
|
+
/*
|
|
60
|
+
The social providers, which is how most people will do this.
|
|
61
|
+
|
|
62
|
+
Somebody whose trial just ran out mid-question is not going to
|
|
63
|
+
invent a password: the fastest door is the only one worth putting
|
|
64
|
+
first, and the form puts these above the handle-and-password
|
|
65
|
+
fields. All three, because which one a person has is not something
|
|
66
|
+
this panel can know.
|
|
67
|
+
|
|
68
|
+
The flow leaves the page and comes back to the host's own
|
|
69
|
+
`/iam/oauth2/<provider>/callback`. Both hosts that mount this
|
|
70
|
+
workspace answer that route — the landing has it in its router and
|
|
71
|
+
the examples shell handles it in `main.tsx` — so the buttons are on
|
|
72
|
+
rather than configurable. A host that adds neither would strand
|
|
73
|
+
somebody who clicked, and that is the thing to check before
|
|
74
|
+
embedding this somewhere new.
|
|
75
|
+
*/
|
|
76
|
+
github: true, google: true, linkedin: true,
|
|
77
|
+
/*
|
|
78
|
+
And back to the page they were reading.
|
|
79
|
+
|
|
80
|
+
The form only forwards the current route when it is not `/`, which
|
|
81
|
+
is exactly the landing page this workspace sits on — so without
|
|
82
|
+
saying it explicitly, a visitor who signed in from the home page
|
|
83
|
+
would have been returned to the home page by accident rather than
|
|
84
|
+
on purpose, and from anywhere else would have lost their place.
|
|
85
|
+
*/
|
|
86
|
+
socialSignInNavigationTarget: typeof window === 'undefined'
|
|
87
|
+
? undefined
|
|
88
|
+
: `${window.location.pathname}${window.location.search}`,
|
|
89
|
+
// Where this deployment's IAM is. Left to the form when nothing says
|
|
90
|
+
// — it reads the page's own config, which is right for a host that
|
|
91
|
+
// has one and harmless for one that does not.
|
|
92
|
+
loginUrl: configuration?.iamUrl
|
|
93
|
+
? `${configuration.iamUrl}/api/iam/v1/login`
|
|
94
|
+
: undefined, onSignIn: handleSignIn })] }) }));
|
|
95
|
+
}
|
|
96
|
+
export default AnonymousKeyExpired;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How long a visitor's trial key has left, burning down as they use it.
|
|
3
|
+
*
|
|
4
|
+
* An anonymous visitor reaches the model on a key the inference service mints
|
|
5
|
+
* for exactly this, and it does not last. Without a clock on screen the end of
|
|
6
|
+
* it arrives as an agent that suddenly stops answering — indistinguishable,
|
|
7
|
+
* from the reader's chair, from an agent that is broken. A ring that empties
|
|
8
|
+
* says the same thing in advance, and turns a failure into a deadline.
|
|
9
|
+
*
|
|
10
|
+
* Every number it draws comes from the key: when it dies and how long it was
|
|
11
|
+
* given are both read out of the JWT by whoever minted it, so this assumes no
|
|
12
|
+
* particular generosity from the service. The points at which it changes
|
|
13
|
+
* colour are shares of that, for the same reason — see `warnAt`.
|
|
14
|
+
*
|
|
15
|
+
* Purely a display: it is handed a moment in the future and counts to it. What
|
|
16
|
+
* to do when it arrives is the caller's business — the ring reports it once,
|
|
17
|
+
* through `onExpire`, and stops.
|
|
18
|
+
*
|
|
19
|
+
* @module components/anonymous/AnonymousKeyTimer
|
|
20
|
+
*/
|
|
21
|
+
import type { JSX } from 'react';
|
|
22
|
+
export type AnonymousKeyTimerProps = {
|
|
23
|
+
/** Epoch milliseconds at which the trial ends. */
|
|
24
|
+
expiresAt: number;
|
|
25
|
+
/**
|
|
26
|
+
* How long the key was signed for, in milliseconds.
|
|
27
|
+
*
|
|
28
|
+
* Read off the token by whoever minted it. The ring draws what is left *of
|
|
29
|
+
* this*, and the colours below turn at a share of it — so a service that
|
|
30
|
+
* signs keys for ten minutes gets a timer that behaves like a ten-minute
|
|
31
|
+
* one without anything here changing. Without it the ring has no
|
|
32
|
+
* denominator, so it falls back to the time remaining when it first
|
|
33
|
+
* rendered.
|
|
34
|
+
*/
|
|
35
|
+
grantedMs?: number;
|
|
36
|
+
/** What the clock is counting, said beside it. */
|
|
37
|
+
label?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The share of the key still left when the clock starts warning, 0–1.
|
|
40
|
+
*
|
|
41
|
+
* A proportion rather than a number of seconds, because the service decides
|
|
42
|
+
* how long it signs a key for and this component must not have an opinion
|
|
43
|
+
* about that. A sixty-second key and a ten-minute one both turn amber with a
|
|
44
|
+
* quarter of themselves to go, and both are saying the same thing: you have
|
|
45
|
+
* about as long again as you have already used.
|
|
46
|
+
*/
|
|
47
|
+
warnAt?: number;
|
|
48
|
+
/** The share left when it turns to danger, 0–1. */
|
|
49
|
+
dangerAt?: number;
|
|
50
|
+
/**
|
|
51
|
+
* The share left when it starts fading in and out, 0–1.
|
|
52
|
+
*
|
|
53
|
+
* The last resort of a control that has already changed colour twice and is
|
|
54
|
+
* still being ignored. Movement is what the eye catches in peripheral
|
|
55
|
+
* vision, which is where a header sits while somebody is typing — so this is
|
|
56
|
+
* the only point at which the clock is allowed to move.
|
|
57
|
+
*/
|
|
58
|
+
pulseAt?: number;
|
|
59
|
+
/** Called once, when the clock reaches zero. */
|
|
60
|
+
onExpire?: () => void;
|
|
61
|
+
};
|
|
62
|
+
export declare function AnonymousKeyTimer({ expiresAt, grantedMs, label, warnAt, dangerAt, pulseAt, onExpire, }: AnonymousKeyTimerProps): JSX.Element;
|
|
63
|
+
export default AnonymousKeyTimer;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { Text } from '@primer/react';
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
|
+
import { KeyIcon } from '@primer/octicons-react';
|
|
6
|
+
/** Diameter of the ring, in pixels. Sized to sit level with a line of text. */
|
|
7
|
+
const RING = 14;
|
|
8
|
+
const STROKE = 2.5;
|
|
9
|
+
const RADIUS = (RING - STROKE) / 2;
|
|
10
|
+
const CIRCUMFERENCE = 2 * Math.PI * RADIUS;
|
|
11
|
+
/**
|
|
12
|
+
* The three points at which the clock changes its mind, as shares of the key.
|
|
13
|
+
*
|
|
14
|
+
* Proportions rather than seconds. The service decides how long it signs a key
|
|
15
|
+
* for — a minute today, five after a deployment changes one line — and a
|
|
16
|
+
* component with absolute thresholds either shouts for the whole life of a
|
|
17
|
+
* short key or says nothing until the last moment of a long one. A quarter
|
|
18
|
+
* left means the same thing at every length.
|
|
19
|
+
*/
|
|
20
|
+
const DEFAULT_WARN_AT = 0.25;
|
|
21
|
+
const DEFAULT_DANGER_AT = 0.1;
|
|
22
|
+
const DEFAULT_PULSE_AT = 0.05;
|
|
23
|
+
/** How long one breath of the fade takes. Slow enough to read through. */
|
|
24
|
+
const PULSE_MS = 1200;
|
|
25
|
+
/** `m:ss`, or `0:07` — short enough to read at a glance in a header. */
|
|
26
|
+
function format(ms) {
|
|
27
|
+
const total = Math.max(0, Math.ceil(ms / 1000));
|
|
28
|
+
const minutes = Math.floor(total / 60);
|
|
29
|
+
const seconds = total % 60;
|
|
30
|
+
return `${minutes}:${String(seconds).padStart(2, '0')}`;
|
|
31
|
+
}
|
|
32
|
+
export function AnonymousKeyTimer({ expiresAt, grantedMs, label = 'Trial key', warnAt = DEFAULT_WARN_AT, dangerAt = DEFAULT_DANGER_AT, pulseAt = DEFAULT_PULSE_AT, onExpire, }) {
|
|
33
|
+
const [now, setNow] = useState(() => Date.now());
|
|
34
|
+
/* The denominator, fixed at the first render for want of a better one. A
|
|
35
|
+
ring whose full mark moved would read as time being added. */
|
|
36
|
+
const spanRef = useRef(grantedMs ?? Math.max(1, expiresAt - Date.now()));
|
|
37
|
+
const reported = useRef(false);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
/*
|
|
40
|
+
* Polled four times a second, re-rendered once.
|
|
41
|
+
*
|
|
42
|
+
* A one-second interval lands off the beat and lets the displayed number
|
|
43
|
+
* sit still for nearly two seconds, which reads as a stopped clock — so it
|
|
44
|
+
* looks often. But it only takes the new time when the second a reader
|
|
45
|
+
* would see has actually changed: everything downstream of this state is
|
|
46
|
+
* DOM, and rewriting it on a tick that changes nothing is what made the
|
|
47
|
+
* native tooltip flash while somebody was trying to read it.
|
|
48
|
+
*/
|
|
49
|
+
const timer = window.setInterval(() => {
|
|
50
|
+
setNow(current => {
|
|
51
|
+
const next = Date.now();
|
|
52
|
+
const displayed = (at) => Math.ceil((expiresAt - at) / 1000);
|
|
53
|
+
return displayed(next) === displayed(current) ? current : next;
|
|
54
|
+
});
|
|
55
|
+
}, 250);
|
|
56
|
+
return () => window.clearInterval(timer);
|
|
57
|
+
}, [expiresAt]);
|
|
58
|
+
const left = Math.max(0, expiresAt - now);
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (left > 0 || reported.current) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
// Once. The interval keeps running until unmount, and a caller that
|
|
64
|
+
// re-renders on expiry must not be told again on every tick after it.
|
|
65
|
+
reported.current = true;
|
|
66
|
+
onExpire?.();
|
|
67
|
+
}, [left, onExpire]);
|
|
68
|
+
const fraction = Math.min(1, Math.max(0, left / spanRef.current));
|
|
69
|
+
/*
|
|
70
|
+
* Three steps, each louder than the last, and the loudest one moves.
|
|
71
|
+
*
|
|
72
|
+
* Colour, then a stronger colour, then a fade — because a reader mid-sentence
|
|
73
|
+
* is not looking at the header, and the header has to get louder without
|
|
74
|
+
* getting in the way. Movement is last on purpose: it is the only one of the
|
|
75
|
+
* three that costs the reader anything, so it is spent only when the other
|
|
76
|
+
* two have plainly not worked.
|
|
77
|
+
*/
|
|
78
|
+
const pulsing = fraction <= pulseAt;
|
|
79
|
+
const tone = fraction <= dangerAt
|
|
80
|
+
? 'danger.fg'
|
|
81
|
+
: fraction <= warnAt
|
|
82
|
+
? 'attention.fg'
|
|
83
|
+
: 'fg.muted';
|
|
84
|
+
return (_jsxs(Box, { sx: {
|
|
85
|
+
display: 'inline-flex',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
gap: 1,
|
|
88
|
+
px: 2,
|
|
89
|
+
py: '2px',
|
|
90
|
+
borderRadius: '999px',
|
|
91
|
+
border: '1px solid',
|
|
92
|
+
borderColor: 'border.muted',
|
|
93
|
+
bg: 'canvas.subtle',
|
|
94
|
+
color: tone,
|
|
95
|
+
// The clock is the point; the row it sits in must not resize as the
|
|
96
|
+
// digits change width.
|
|
97
|
+
fontVariantNumeric: 'tabular-nums',
|
|
98
|
+
/*
|
|
99
|
+
The last few percent, breathing.
|
|
100
|
+
|
|
101
|
+
Opacity only: nothing moves, nothing resizes, and the row it sits in
|
|
102
|
+
is unaffected — a pill that grew and shrank would push the controls
|
|
103
|
+
beside it about at exactly the moment somebody is reaching for one.
|
|
104
|
+
It never fades to nothing, because a clock that disappears is a clock
|
|
105
|
+
that has stopped rather than one that is running out.
|
|
106
|
+
|
|
107
|
+
Off for a reader who asked the machine to hold still. They have the
|
|
108
|
+
colour and the number, which is the information; the movement is
|
|
109
|
+
only how hard it knocks.
|
|
110
|
+
*/
|
|
111
|
+
...(pulsing
|
|
112
|
+
? {
|
|
113
|
+
'@keyframes dla-key-pulse': {
|
|
114
|
+
'0%, 100%': { opacity: 1 },
|
|
115
|
+
'50%': { opacity: 0.45 },
|
|
116
|
+
},
|
|
117
|
+
animation: `dla-key-pulse ${PULSE_MS}ms ease-in-out infinite`,
|
|
118
|
+
'@media (prefers-reduced-motion: reduce)': {
|
|
119
|
+
animation: 'none',
|
|
120
|
+
},
|
|
121
|
+
}
|
|
122
|
+
: null),
|
|
123
|
+
},
|
|
124
|
+
/*
|
|
125
|
+
The whole story, for anyone who wonders what the ring is counting.
|
|
126
|
+
|
|
127
|
+
Deliberately without the number in it. The countdown re-renders twice
|
|
128
|
+
a second, and a native tooltip is torn down and rebuilt every time its
|
|
129
|
+
`title` changes — so a title carrying the remaining time flashed once
|
|
130
|
+
per tick for as long as the pointer rested on it, which is the one
|
|
131
|
+
place a reader is trying to read something. React writes the attribute
|
|
132
|
+
only when the string differs, so a constant one stays put and the
|
|
133
|
+
seconds are read off the pill beside it.
|
|
134
|
+
|
|
135
|
+
A status readout rather than a control, so the hint rides on the native
|
|
136
|
+
attribute: Primer's `Tooltip` requires an interactive child.
|
|
137
|
+
*/
|
|
138
|
+
title: `${label}: this workspace is talking to the agent on a temporary key issued to nobody in particular. When it runs out the chat asks you to sign in. Sign in now for an account of your own.`, children: [_jsx(Box, { sx: { display: 'flex', alignItems: 'center', color: tone }, children: _jsx(KeyIcon, { size: 12 }) }), _jsxs(Box, { as: "svg", "aria-hidden": "true", focusable: "false", width: RING, height: RING, viewBox: `0 0 ${RING} ${RING}`, sx: { display: 'block', flexShrink: 0 }, children: [_jsx("circle", { cx: RING / 2, cy: RING / 2, r: RADIUS, fill: "none", stroke: "currentColor", strokeWidth: STROKE, opacity: 0.2 }), _jsx("circle", { cx: RING / 2, cy: RING / 2, r: RADIUS, fill: "none", stroke: "currentColor", strokeWidth: STROKE, strokeLinecap: "round", strokeDasharray: CIRCUMFERENCE, strokeDashoffset: CIRCUMFERENCE * (1 - fraction), transform: `rotate(-90 ${RING / 2} ${RING / 2})`, style: { transition: 'stroke-dashoffset 0.5s linear' } })] }), _jsx(Text, { sx: { fontSize: 0, color: tone, fontWeight: 'semibold' }, children: format(left) })] }));
|
|
139
|
+
}
|
|
140
|
+
export default AnonymousKeyTimer;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (c) 2025-2026 Datalayer, Inc.
|
|
7
|
+
* Distributed under the terms of the Modified BSD License.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* What a visitor with no account sees while they are on a trial key.
|
|
11
|
+
*
|
|
12
|
+
* @module components/anonymous
|
|
13
|
+
*/
|
|
14
|
+
export * from './AnonymousKeyTimer.js';
|
|
15
|
+
export * from './AnonymousKeyExpired.js';
|
|
@@ -15,6 +15,12 @@ export declare function hasRealAvatar(url?: string): boolean;
|
|
|
15
15
|
export type UserAvatarProps = {
|
|
16
16
|
avatarUrl?: string;
|
|
17
17
|
avatarIcon?: string;
|
|
18
|
+
/**
|
|
19
|
+
* A literal emoji, checked before `avatarIcon`/`avatarUrl` — an agent's
|
|
20
|
+
* face is its emoji, not a photograph or a chosen icon standing in for
|
|
21
|
+
* one.
|
|
22
|
+
*/
|
|
23
|
+
avatarEmoji?: string;
|
|
18
24
|
/** Avatar edge length in pixels. Defaults to 100. */
|
|
19
25
|
size?: number;
|
|
20
26
|
/** Render with rounded square corners instead of a circle. Defaults to true. */
|
|
@@ -35,5 +41,5 @@ export type UserAvatarProps = {
|
|
|
35
41
|
ring?: boolean;
|
|
36
42
|
className?: string;
|
|
37
43
|
};
|
|
38
|
-
export declare const UserAvatar: ({ avatarUrl, avatarIcon, size, square, iconSize, fallbackBackground, fallbackForeground, ring, className, }: UserAvatarProps) => JSX.Element;
|
|
44
|
+
export declare const UserAvatar: ({ avatarUrl, avatarIcon, avatarEmoji, size, square, iconSize, fallbackBackground, fallbackForeground, ring, className, }: UserAvatarProps) => JSX.Element;
|
|
39
45
|
export default UserAvatar;
|