@datalayer/core 1.1.46 → 1.1.48

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.
@@ -13,6 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
13
13
  import * as React from 'react';
14
14
  import { Box } from '@datalayer/primer-addons';
15
15
  import { useCache } from '../../hooks/index.js';
16
+ import { usePrincipalCacheStore, principalCacheKey, } from '../../hooks/usePrincipalCacheStore.js';
16
17
  import { useIAMStore } from '../../state/index.js';
17
18
  import { PrincipalAvatar } from './PrincipalAvatar.js';
18
19
  import { PrincipalDetailsOverlay } from './PrincipalDetailsOverlay.js';
@@ -53,6 +54,14 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
53
54
  const { user: authenticatedUser } = useIAMStore();
54
55
  const isAnonymous = !authenticatedUser;
55
56
  const normalizedUid = String(principal.uid || '').trim();
57
+ // In-memory principal cache: seed the display from a previously resolved
58
+ // snapshot (keyed by uid) for an instant paint, and write freshly resolved
59
+ // data back so later renders anywhere reuse it. Network hooks below still
60
+ // refresh on demand per their staleTime.
61
+ const cachedPrincipal = usePrincipalCacheStore(state => normalizedUid
62
+ ? state.principals[principalCacheKey(principal.kind, normalizedUid)]
63
+ : undefined);
64
+ const upsertCachedPrincipal = usePrincipalCacheStore(state => state.upsertPrincipal);
56
65
  const normalizedProvidedHandle = String(principal.handle || '').trim();
57
66
  const normalizedProvidedAccountHandle = String(principal.accountHandle || '').trim();
58
67
  const providedHandleIsUidPlaceholder = !!normalizedProvidedHandle &&
@@ -145,9 +154,31 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
145
154
  : String(hydratedEntity?.displayName ||
146
155
  hydratedEntity?.name ||
147
156
  '').trim();
157
+ // Team-specific enrichment: parent organization + membership + visibility,
158
+ // falling back to the in-memory cache when the network data isn't ready yet.
159
+ const hydratedTeam = principal.kind === 'team' ? hydratedTeamQuery.data : undefined;
160
+ const teamMemberCount = hydratedTeam && Array.isArray(hydratedTeam.members)
161
+ ? hydratedTeam.members.length
162
+ : cachedPrincipal?.memberCount;
163
+ const teamOrganizationHandleResolved = principal.kind === 'team'
164
+ ? String(teamOrganizationQuery.data?.handle ||
165
+ teamOrganizationHandle ||
166
+ cachedPrincipal?.organizationHandle ||
167
+ '').trim() || undefined
168
+ : undefined;
169
+ const teamOrganizationNameResolved = principal.kind === 'team'
170
+ ? String(teamOrganizationQuery.data?.displayName ||
171
+ teamOrganizationQuery.data?.name ||
172
+ cachedPrincipal?.organizationName ||
173
+ '').trim() || undefined
174
+ : undefined;
175
+ const resolvedIsPublic = typeof hydratedEntity?.public === 'boolean'
176
+ ? hydratedEntity.public
177
+ : cachedPrincipal?.isPublic;
148
178
  const resolvedPrincipal = {
149
179
  ...principal,
150
180
  displayName: hydratedDisplayName ||
181
+ String(cachedPrincipal?.displayName || '').trim() ||
151
182
  (() => {
152
183
  const providedDisplayName = String(principal.displayName || '').trim();
153
184
  const providedIsGenericPlaceholder = !providedDisplayName ||
@@ -164,30 +195,97 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
164
195
  })(),
165
196
  handle: (!providedHandleIsUidPlaceholder ? principal.handle : undefined) ||
166
197
  String(hydratedEntity?.handle || '').trim() ||
198
+ cachedPrincipal?.handle ||
167
199
  undefined,
168
- accountHandle: (!providedAccountHandleIsUidPlaceholder
169
- ? principal.accountHandle
170
- : undefined) ||
171
- String(hydratedEntity?.handle || '').trim() ||
172
- undefined,
200
+ accountHandle: principal.kind === 'team'
201
+ ? (!providedAccountHandleIsUidPlaceholder
202
+ ? principal.accountHandle
203
+ : undefined) ||
204
+ teamOrganizationHandleResolved ||
205
+ cachedPrincipal?.accountHandle ||
206
+ undefined
207
+ : (!providedAccountHandleIsUidPlaceholder
208
+ ? principal.accountHandle
209
+ : undefined) ||
210
+ String(hydratedEntity?.handle || '').trim() ||
211
+ cachedPrincipal?.accountHandle ||
212
+ undefined,
173
213
  name: principal.name ||
174
214
  String(hydratedEntity?.name || '').trim() ||
215
+ cachedPrincipal?.name ||
175
216
  undefined,
176
217
  description: principal.description ||
177
218
  String(hydratedEntity?.description || '').trim() ||
219
+ cachedPrincipal?.description ||
220
+ undefined,
221
+ avatarUrl: principal.avatarUrl ||
222
+ hydratedEntity?.avatarUrl ||
223
+ cachedPrincipal?.avatarUrl ||
224
+ undefined,
225
+ firstName: principal.firstName ||
226
+ hydratedEntity?.firstName ||
227
+ cachedPrincipal?.firstName ||
228
+ undefined,
229
+ lastName: principal.lastName ||
230
+ hydratedEntity?.lastName ||
231
+ cachedPrincipal?.lastName ||
232
+ undefined,
233
+ email: principal.email ||
234
+ hydratedEntity?.email ||
235
+ cachedPrincipal?.email ||
236
+ undefined,
237
+ origin: principal.origin ||
238
+ hydratedEntity?.origin ||
239
+ cachedPrincipal?.origin ||
178
240
  undefined,
179
- avatarUrl: principal.avatarUrl || hydratedEntity?.avatarUrl || undefined,
180
- firstName: principal.firstName || hydratedEntity?.firstName || undefined,
181
- lastName: principal.lastName || hydratedEntity?.lastName || undefined,
182
- email: principal.email || hydratedEntity?.email || undefined,
183
- origin: principal.origin || hydratedEntity?.origin || undefined,
184
241
  };
242
+ // Persist the freshly resolved snapshot so subsequent renders (here or in
243
+ // other views) paint instantly from memory. Refreshes still happen on demand
244
+ // through the underlying query hooks.
245
+ React.useEffect(() => {
246
+ if (!normalizedUid) {
247
+ return;
248
+ }
249
+ upsertCachedPrincipal({
250
+ kind: principal.kind,
251
+ uid: normalizedUid,
252
+ // Only cache a real, resolved display name — never a uid/handle
253
+ // placeholder — so cached names stay authoritative.
254
+ displayName: hydratedDisplayName ||
255
+ String(cachedPrincipal?.displayName || '').trim() ||
256
+ undefined,
257
+ name: resolvedPrincipal.name,
258
+ description: resolvedPrincipal.description,
259
+ handle: resolvedPrincipal.handle,
260
+ accountHandle: resolvedPrincipal.accountHandle,
261
+ firstName: resolvedPrincipal.firstName,
262
+ lastName: resolvedPrincipal.lastName,
263
+ email: resolvedPrincipal.email,
264
+ origin: resolvedPrincipal.origin,
265
+ avatarUrl: resolvedPrincipal.avatarUrl,
266
+ organizationHandle: teamOrganizationHandleResolved,
267
+ organizationName: teamOrganizationNameResolved,
268
+ memberCount: teamMemberCount,
269
+ isPublic: resolvedIsPublic,
270
+ });
271
+ // eslint-disable-next-line react-hooks/exhaustive-deps
272
+ }, [
273
+ normalizedUid,
274
+ principal.kind,
275
+ hydratedEntity,
276
+ hydratedDisplayName,
277
+ teamOrganizationHandleResolved,
278
+ teamOrganizationNameResolved,
279
+ teamMemberCount,
280
+ resolvedIsPublic,
281
+ upsertCachedPrincipal,
282
+ ]);
185
283
  return (_jsxs(Box, { sx: {
186
284
  display: 'inline-flex',
187
285
  alignItems: 'center',
188
286
  gap,
189
287
  minWidth: 0,
190
288
  ...sx,
191
- }, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, alt: resolvedPrincipal.displayName, size: avatarSize, square: square }), _jsx(PrincipalDetailsOverlay, { kind: resolvedPrincipal.kind, uid: resolvedPrincipal.uid, displayName: resolvedPrincipal.displayName, name: resolvedPrincipal.name, description: resolvedPrincipal.description, handle: resolvedPrincipal.handle, accountHandle: resolvedPrincipal.accountHandle, firstName: resolvedPrincipal.firstName, lastName: resolvedPrincipal.lastName, email: resolvedPrincipal.email, origin: resolvedPrincipal.origin, avatarUrl: resolvedPrincipal.avatarUrl, isAdmin: isAdmin })] }));
289
+ }, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, alt: resolvedPrincipal.displayName, size: avatarSize, square: square }), _jsx(PrincipalDetailsOverlay, { kind: resolvedPrincipal.kind, uid: resolvedPrincipal.uid, displayName: resolvedPrincipal.displayName, name: resolvedPrincipal.name, description: resolvedPrincipal.description, handle: resolvedPrincipal.handle, accountHandle: resolvedPrincipal.accountHandle, firstName: resolvedPrincipal.firstName, lastName: resolvedPrincipal.lastName, email: resolvedPrincipal.email, origin: resolvedPrincipal.origin, avatarUrl: resolvedPrincipal.avatarUrl, organizationName: teamOrganizationNameResolved, memberCount: teamMemberCount, isPublic: resolvedIsPublic, isAdmin: isAdmin })] }));
192
290
  };
193
291
  export default Principal;
@@ -12,6 +12,12 @@ export type PrincipalDetailsOverlayProps = {
12
12
  email?: string;
13
13
  origin?: string;
14
14
  avatarUrl?: string;
15
+ /** Team-specific: parent organization display name. */
16
+ organizationName?: string;
17
+ /** Team-specific: number of members. */
18
+ memberCount?: number;
19
+ /** Team/organization visibility. */
20
+ isPublic?: boolean;
15
21
  isAdmin?: boolean;
16
22
  };
17
23
  export declare function buildPrincipalProfilePath({ kind, uid, handle, accountHandle, isAdmin, }: {
@@ -21,5 +27,5 @@ export declare function buildPrincipalProfilePath({ kind, uid, handle, accountHa
21
27
  accountHandle?: string;
22
28
  isAdmin?: boolean;
23
29
  }): string | null;
24
- export declare function PrincipalDetailsOverlay({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, isAdmin, }: PrincipalDetailsOverlayProps): JSX.Element;
30
+ export declare function PrincipalDetailsOverlay({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, organizationName, memberCount, isPublic, isAdmin, }: PrincipalDetailsOverlayProps): JSX.Element;
25
31
  export default PrincipalDetailsOverlay;
@@ -80,7 +80,7 @@ export function buildPrincipalProfilePath({ kind, uid, handle, accountHandle, is
80
80
  }
81
81
  return null;
82
82
  }
83
- export function PrincipalDetailsOverlay({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, isAdmin = false, }) {
83
+ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, organizationName, memberCount, isPublic, isAdmin = false, }) {
84
84
  const navigate = useNavigate();
85
85
  const normalizedDisplayName = normalize(displayName) ||
86
86
  normalize(handle) ||
@@ -91,6 +91,8 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
91
91
  const normalizedName = normalize(name);
92
92
  const normalizedDescription = normalize(description);
93
93
  const normalizedOrigin = normalizeOriginLabel(origin);
94
+ const normalizedAccountHandle = normalize(accountHandle);
95
+ const normalizedOrganizationName = normalize(organizationName);
94
96
  const resolvedHandle = normalizedHandle && normalizedHandle !== normalizedUid
95
97
  ? normalizedHandle
96
98
  : '';
@@ -101,6 +103,20 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
101
103
  accountHandle,
102
104
  isAdmin,
103
105
  });
106
+ // For a team, extract the bare team handle (the last path segment) and the
107
+ // parent organization handle so we can present them separately.
108
+ const teamHandleOnly = kind === 'team' && resolvedHandle.includes('/')
109
+ ? normalize(resolvedHandle.split('/').pop())
110
+ : resolvedHandle;
111
+ const teamOrganizationHandle = kind === 'team'
112
+ ? normalizedAccountHandle ||
113
+ (resolvedHandle.includes('/')
114
+ ? normalize(resolvedHandle.split('/')[0])
115
+ : '')
116
+ : '';
117
+ const organizationPath = teamOrganizationHandle
118
+ ? `/${teamOrganizationHandle.replace(/^@+/, '')}`
119
+ : '';
104
120
  return (_jsx(ThemeProvider, { children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Box, { as: "button", type: "button", sx: {
105
121
  fontWeight: 'semibold',
106
122
  color: 'accent.fg',
@@ -113,7 +129,9 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
113
129
  ':hover': {
114
130
  textDecoration: 'underline',
115
131
  },
116
- }, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsxs(Box, { sx: { display: 'grid', gap: 3, p: 4, minWidth: 420 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, alt: normalizedDisplayName, size: 40 }), _jsxs(Box, { sx: { display: 'grid', gap: 0.5 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: normalizedDisplayName }), resolvedHandle && kind !== 'team' ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { sx: {
132
+ }, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsxs(Box, { sx: { display: 'grid', gap: 3, p: 4, minWidth: 420 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, alt: normalizedDisplayName, size: 40 }), _jsxs(Box, { sx: { display: 'grid', gap: 0.5 }, children: [_jsx(Text, { sx: { fontWeight: 'semibold' }, children: normalizedDisplayName }), kind === 'team' ? (teamHandleOnly ? (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [displayHandleText(teamHandleOnly), teamOrganizationHandle
133
+ ? ` · @${teamOrganizationHandle.replace(/^@+/, '')}`
134
+ : ''] })) : null) : resolvedHandle ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { sx: {
117
135
  display: 'grid',
118
136
  gridTemplateColumns: '110px 1fr',
119
137
  gap: 1,
@@ -125,17 +143,19 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
125
143
  overflow: 'hidden',
126
144
  textOverflow: 'ellipsis',
127
145
  whiteSpace: 'nowrap',
128
- }, children: normalizedOrigin })] })) : (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Name" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedName || normalizedDisplayName }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Description" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedDescription || 'N/A' }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
146
+ }, children: normalizedOrigin })] })) : (_jsxs(_Fragment, { children: [kind === 'team' && teamHandleOnly ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontSize: 1 }, children: displayHandleText(teamHandleOnly) })] })) : null, kind === 'team' && teamOrganizationHandle ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Organization" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedOrganizationName
147
+ ? `${normalizedOrganizationName} (${displayHandleText(teamOrganizationHandle)})`
148
+ : displayHandleText(teamOrganizationHandle) })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Name" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedName || normalizedDisplayName }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Description" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedDescription || 'N/A' }), kind === 'team' && typeof memberCount === 'number' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Members" }), _jsxs(Text, { sx: { fontSize: 1 }, children: [memberCount, " ", memberCount === 1 ? 'member' : 'members'] })] })) : null, typeof isPublic === 'boolean' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Visibility" }), _jsx(Label, { size: "small", variant: isPublic ? 'success' : 'secondary', sx: { justifySelf: 'start', width: 'fit-content' }, children: isPublic ? 'Public' : 'Private' })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
129
149
  justifySelf: 'start',
130
150
  width: 'fit-content',
131
151
  maxWidth: '100%',
132
152
  overflow: 'hidden',
133
153
  textOverflow: 'ellipsis',
134
154
  whiteSpace: 'nowrap',
135
- }, children: normalizedOrigin })] }))] }), _jsx(Box, { sx: { display: 'flex', justifyContent: 'flex-end' }, children: _jsx(Button, { size: "small", onClick: () => {
136
- if (targetPath) {
137
- navigate(targetPath);
138
- }
139
- }, disabled: !targetPath, children: "View Profile" }) })] }) })] }) }));
155
+ }, children: normalizedOrigin })] }))] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', gap: 2 }, children: [kind === 'team' && organizationPath ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => navigate(organizationPath), children: "View Organization" })) : null, _jsx(Button, { size: "small", onClick: () => {
156
+ if (targetPath) {
157
+ navigate(targetPath);
158
+ }
159
+ }, disabled: !targetPath, children: "View Profile" })] })] }) })] }) }));
140
160
  }
141
161
  export default PrincipalDetailsOverlay;
@@ -277,7 +277,7 @@ export function PrincipalSwitcherMenu({ maxLabelChars = 48, fullWidth = true, sh
277
277
  }, children: _jsx(Text, { sx: {
278
278
  color: 'accent.fg',
279
279
  fontWeight: 'semibold',
280
- }, children: selectedPrincipalLabelClosed }) }), isPlatformAdmin && isCurrentUserPrincipal ? (_jsx(Label, { variant: "secondary", size: "small", sx: adminBadgeSx, children: "admin" })) : null] }) })) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsxs(ActionList, { children: [_jsxs(ActionList.Group, { children: [_jsx(ActionList.GroupHeading, { children: "Personal" }), _jsxs(ActionList.Item, { disabled: isCurrentUserPrincipal, selected: isCurrentUserPrincipal, sx: isCurrentUserPrincipal ? selectedItemSx : undefined, onSelect: () => {
280
+ }, children: selectedPrincipalLabelClosed }) }), isPlatformAdmin && isCurrentUserPrincipal ? (_jsx(Label, { variant: "secondary", size: "small", sx: adminBadgeSx, children: "admin" })) : null] }) })) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsxs(ActionList, { selectionVariant: "single", children: [_jsxs(ActionList.Group, { children: [_jsx(ActionList.GroupHeading, { children: "Personal" }), _jsxs(ActionList.Item, { disabled: isCurrentUserPrincipal, selected: isCurrentUserPrincipal, sx: isCurrentUserPrincipal ? selectedItemSx : undefined, onSelect: () => {
281
281
  if (isCurrentUserPrincipal) {
282
282
  return;
283
283
  }
@@ -0,0 +1,2 @@
1
+ export declare const SpinnerBar: () => import("react/jsx-runtime").JSX.Element;
2
+ export default SpinnerBar;
@@ -5,8 +5,8 @@ import { jsx as _jsx } from "react/jsx-runtime";
5
5
  */
6
6
  import { useState } from 'react';
7
7
  import { useInterval } from 'usehooks-ts';
8
- import { ProgressBar as PrimerProgressBar } from '@primer/react';
9
- export const ProgressBar = () => {
8
+ import { ProgressBar } from '@primer/react';
9
+ export const SpinnerBar = () => {
10
10
  const [progress, setProgress] = useState(0);
11
11
  useInterval(() => {
12
12
  if (progress >= 100) {
@@ -16,6 +16,6 @@ export const ProgressBar = () => {
16
16
  setProgress(progress + 1);
17
17
  }
18
18
  }, 100);
19
- return _jsx(PrimerProgressBar, { progress: progress, "aria-label": "" });
19
+ return _jsx(ProgressBar, { progress: progress, "aria-label": "" });
20
20
  };
21
- export default ProgressBar;
21
+ export default SpinnerBar;
@@ -1,5 +1,5 @@
1
1
  export * from './ConsumptionBar';
2
- export * from './ProgressBar';
2
+ export * from './SpinnerBar';
3
3
  export * from './ProgressRing';
4
4
  export * from './Timer';
5
5
  export * from './consumption';
@@ -3,7 +3,7 @@
3
3
  * Distributed under the terms of the Modified BSD License.
4
4
  */
5
5
  export * from './ConsumptionBar.js';
6
- export * from './ProgressBar.js';
6
+ export * from './SpinnerBar.js';
7
7
  export * from './ProgressRing.js';
8
8
  export * from './Timer.js';
9
9
  export * from './consumption.js';
@@ -68,7 +68,7 @@ export declare const SubNav: React.NamedExoticComponent<{
68
68
  readonly type: ({ id, children, className, "data-testid": testId, fullWidth, hasShadow, }: SubNavProps) => import("react/jsx-runtime").JSX.Element;
69
69
  } & {
70
70
  Heading: ({ href, children, className, "data-testid": testID, ...props }: SubNavHeadingProps) => import("react/jsx-runtime").JSX.Element;
71
- Link: React.ForwardRefExoticComponent<Omit<SubNavLinkProps, "ref"> & React.RefAttributes<HTMLDivElement | HTMLAnchorElement>>;
71
+ Link: React.ForwardRefExoticComponent<Omit<SubNavLinkProps, "ref"> & React.RefAttributes<HTMLAnchorElement | HTMLDivElement>>;
72
72
  Action: typeof _SubNavAction;
73
73
  SubMenu: typeof SubMenu;
74
74
  testIds: {
@@ -26,7 +26,7 @@ export class DatalayerConfiguration {
26
26
  * Default configuration values for Datalayer
27
27
  */
28
28
  export const DEFAULT_DATALAYER_CONFIG = {
29
- datalayerUrl: 'https://oss.datalayer.run',
29
+ datalayerUrl: 'https://prod1.datalayer.run',
30
30
  credits: 100,
31
31
  cpuEnvironment: 'ai-agents-env',
32
32
  gpuEnvironment: 'ai-env',
@@ -28,6 +28,7 @@ export * from './useProjectStore';
28
28
  export * from './useMobile';
29
29
  export * from './useUsageRefreshStore';
30
30
  export * from './usePrincipalStore';
31
+ export * from './usePrincipalCacheStore';
31
32
  export * from './useBillingEntityStore';
32
33
  export * from './useSelectedPrincipal';
33
34
  export * from './useSelectedBillingEntity';
@@ -33,6 +33,7 @@ export * from './useProjectStore.js';
33
33
  export * from './useMobile.js';
34
34
  export * from './useUsageRefreshStore.js';
35
35
  export * from './usePrincipalStore.js';
36
+ export * from './usePrincipalCacheStore.js';
36
37
  export * from './useBillingEntityStore.js';
37
38
  export * from './useSelectedPrincipal.js';
38
39
  export * from './useSelectedBillingEntity.js';
@@ -744,7 +744,7 @@ export declare const useCache: ({ loginRoute }?: CacheProps) => {
744
744
  selectedPrincipalKind?: "personal" | "organization" | "team";
745
745
  }) => import("@tanstack/react-query").UseQueryResult<any, Error>;
746
746
  useCreatePage: () => import("@tanstack/react-query").UseMutationResult<any, Error, Omit<any, "id">, unknown>;
747
- useUpdatePage: () => import("@tanstack/react-query").UseMutationResult<any, Error, Pick<any, "name" | "description" | "id" | "tags">, unknown>;
747
+ useUpdatePage: () => import("@tanstack/react-query").UseMutationResult<any, Error, Pick<any, "name" | "id" | "tags" | "description">, unknown>;
748
748
  useDeletePage: () => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
749
749
  useDatasource: (datasourceId: string, options?: {
750
750
  principalUid?: string;
@@ -788,7 +788,7 @@ export declare const useCache: ({ loginRoute }?: CacheProps) => {
788
788
  }) => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
789
789
  useToken: (tokenId: string) => import("@tanstack/react-query").UseQueryResult<NoInfer<IIAMToken | null | undefined>, Error>;
790
790
  useTokens: () => import("@tanstack/react-query").UseQueryResult<NoInfer<(IIAMToken | undefined)[]>, Error>;
791
- useCreateToken: () => import("@tanstack/react-query").UseMutationResult<any, Error, Omit<IIAMToken, "id" | "value">, unknown>;
791
+ useCreateToken: () => import("@tanstack/react-query").UseMutationResult<any, Error, Omit<IIAMToken, "value" | "id">, unknown>;
792
792
  useUpdateToken: () => import("@tanstack/react-query").UseMutationResult<any, Error, IIAMToken, unknown>;
793
793
  useDeleteToken: () => import("@tanstack/react-query").UseMutationResult<any, Error, string, unknown>;
794
794
  useInvite: (token: string) => import("@tanstack/react-query").UseQueryResult<NoInfer<import("..").IInvite | undefined>, Error>;
@@ -0,0 +1,54 @@
1
+ export type PrincipalCacheKind = 'personal' | 'team' | 'organization';
2
+ /**
3
+ * A resolved principal snapshot kept in memory so repeated renders (across
4
+ * views) can paint instantly instead of waiting for a network round trip.
5
+ *
6
+ * Only meaningful fields are stored; partial snapshots are merged over time so
7
+ * the cache accumulates as much information as possible for a given principal.
8
+ */
9
+ export type CachedPrincipal = {
10
+ kind: PrincipalCacheKind;
11
+ uid: string;
12
+ displayName?: string;
13
+ name?: string;
14
+ description?: string;
15
+ handle?: string;
16
+ accountHandle?: string;
17
+ firstName?: string;
18
+ lastName?: string;
19
+ email?: string;
20
+ origin?: string;
21
+ avatarUrl?: string;
22
+ /** Team-specific: parent organization handle. */
23
+ organizationHandle?: string;
24
+ /** Team-specific: parent organization display name. */
25
+ organizationName?: string;
26
+ /** Team-specific: number of members. */
27
+ memberCount?: number;
28
+ /** Whether the principal (team/org) is public. */
29
+ isPublic?: boolean;
30
+ /** Timestamp (ms) of the last time this entry was updated. */
31
+ updatedAt?: number;
32
+ };
33
+ /** Build the cache key for a principal. */
34
+ export declare function principalCacheKey(kind: PrincipalCacheKind, uid: string): string;
35
+ type PrincipalCacheState = {
36
+ /** Cached principals keyed by `${kind}:${uid}`. */
37
+ principals: Record<string, CachedPrincipal>;
38
+ /**
39
+ * Read a cached principal snapshot, if present.
40
+ */
41
+ getPrincipal: (kind: PrincipalCacheKind, uid: string) => CachedPrincipal | undefined;
42
+ /**
43
+ * Merge a (possibly partial) principal snapshot into the cache. Existing
44
+ * meaningful values are preserved when the incoming snapshot omits them, so
45
+ * information accumulates rather than being overwritten with blanks.
46
+ */
47
+ upsertPrincipal: (entry: CachedPrincipal) => void;
48
+ /** Remove a single cached principal (e.g. to force a fresh resolution). */
49
+ clearPrincipal: (kind: PrincipalCacheKind, uid: string) => void;
50
+ /** Clear the entire cache. */
51
+ reset: () => void;
52
+ };
53
+ export declare const usePrincipalCacheStore: import("zustand").UseBoundStore<import("zustand").StoreApi<PrincipalCacheState>>;
54
+ export default usePrincipalCacheStore;
@@ -0,0 +1,94 @@
1
+ /*
2
+ * Copyright (c) 2023-2025 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { create } from 'zustand';
6
+ /** Build the cache key for a principal. */
7
+ export function principalCacheKey(kind, uid) {
8
+ return `${kind}:${String(uid || '').trim()}`;
9
+ }
10
+ const MERGEABLE_KEYS = [
11
+ 'displayName',
12
+ 'name',
13
+ 'description',
14
+ 'handle',
15
+ 'accountHandle',
16
+ 'firstName',
17
+ 'lastName',
18
+ 'email',
19
+ 'origin',
20
+ 'avatarUrl',
21
+ 'organizationHandle',
22
+ 'organizationName',
23
+ 'memberCount',
24
+ 'isPublic',
25
+ ];
26
+ function hasMeaningfulValue(value) {
27
+ if (value === undefined || value === null) {
28
+ return false;
29
+ }
30
+ if (typeof value === 'string') {
31
+ return value.trim().length > 0;
32
+ }
33
+ return true;
34
+ }
35
+ export const usePrincipalCacheStore = create((set, get) => ({
36
+ principals: {},
37
+ getPrincipal: (kind, uid) => {
38
+ const normalizedUid = String(uid || '').trim();
39
+ if (!normalizedUid) {
40
+ return undefined;
41
+ }
42
+ return get().principals[principalCacheKey(kind, normalizedUid)];
43
+ },
44
+ upsertPrincipal: entry => {
45
+ const normalizedUid = String(entry.uid || '').trim();
46
+ if (!normalizedUid) {
47
+ return;
48
+ }
49
+ const key = principalCacheKey(entry.kind, normalizedUid);
50
+ const existing = get().principals[key];
51
+ const merged = {
52
+ ...existing,
53
+ kind: entry.kind,
54
+ uid: normalizedUid,
55
+ };
56
+ for (const field of MERGEABLE_KEYS) {
57
+ const incoming = entry[field];
58
+ if (hasMeaningfulValue(incoming)) {
59
+ merged[field] = incoming;
60
+ }
61
+ }
62
+ merged.updatedAt = Date.now();
63
+ // Skip the state update when no meaningful field changed to avoid
64
+ // needless re-renders of every mounted Principal.
65
+ if (existing) {
66
+ let changed = false;
67
+ for (const field of MERGEABLE_KEYS) {
68
+ if (merged[field] !== existing[field]) {
69
+ changed = true;
70
+ break;
71
+ }
72
+ }
73
+ if (!changed) {
74
+ return;
75
+ }
76
+ }
77
+ set(state => ({
78
+ principals: { ...state.principals, [key]: merged },
79
+ }));
80
+ },
81
+ clearPrincipal: (kind, uid) => {
82
+ const key = principalCacheKey(kind, String(uid || '').trim());
83
+ set(state => {
84
+ if (!state.principals[key]) {
85
+ return state;
86
+ }
87
+ const next = { ...state.principals };
88
+ delete next[key];
89
+ return { principals: next };
90
+ });
91
+ },
92
+ reset: () => set({ principals: {} }),
93
+ }));
94
+ export default usePrincipalCacheStore;
@@ -26,11 +26,15 @@ export interface FetchMetricsOptions {
26
26
  serviceName?: string;
27
27
  metricName?: string;
28
28
  limit?: number;
29
+ /** Optional billing/account scope for account-scoped OTEL queries. */
30
+ accountUid?: string;
29
31
  }
30
32
  export interface FetchMetricTotalOptions {
31
33
  serviceName?: string;
32
34
  limit?: number;
33
35
  fallbackWithoutService?: boolean;
36
+ /** Optional billing/account scope for account-scoped OTEL queries. */
37
+ accountUid?: string;
34
38
  }
35
39
  /**
36
40
  * Typed HTTP client for all OTEL service endpoints.
@@ -168,6 +168,8 @@ export class OtelClient {
168
168
  params.set('service_name', options.serviceName);
169
169
  if (options.metricName)
170
170
  params.set('metric_name', options.metricName);
171
+ if (options.accountUid)
172
+ params.set('account_uid', options.accountUid);
171
173
  const resp = await otelFetch(`${this.baseUrl}/api/otel/v1/metrics/?${params}`, this.token, this.userUid);
172
174
  const rows = (Array.isArray(resp) ? resp : resp.data) ?? [];
173
175
  const normalized = Array.isArray(rows)
@@ -177,17 +179,22 @@ export class OtelClient {
177
179
  }
178
180
  /** Sum all values for one metric name, with optional service filter. */
179
181
  async fetchMetricTotal(metricName, options = {}) {
180
- const { serviceName, limit = 500, fallbackWithoutService = true } = options;
182
+ const { serviceName, limit = 500, fallbackWithoutService = true, accountUid, } = options;
181
183
  const filtered = await this.fetchMetrics({
182
184
  metricName,
183
185
  serviceName,
184
186
  limit,
187
+ accountUid,
185
188
  });
186
189
  const filteredTotal = filtered.data.reduce((sum, row) => sum + Number(row.value || 0), 0);
187
190
  if (filteredTotal > 0 || !serviceName || !fallbackWithoutService) {
188
191
  return filteredTotal;
189
192
  }
190
- const unfiltered = await this.fetchMetrics({ metricName, limit });
193
+ const unfiltered = await this.fetchMetrics({
194
+ metricName,
195
+ limit,
196
+ accountUid,
197
+ });
191
198
  return unfiltered.data.reduce((sum, row) => sum + Number(row.value || 0), 0);
192
199
  }
193
200
  // ── Services ──────────────────────────────────────────────────────────────
@@ -26,6 +26,7 @@ export const PUBLIC_PATH_PREFIXES = [
26
26
  '/docs',
27
27
  '/events',
28
28
  '/features',
29
+ '/gallery',
29
30
  '/integrations',
30
31
  '/join/confirm/user',
31
32
  '/library',
package/lib/utils/Date.js CHANGED
@@ -99,7 +99,10 @@ export const formatRelativeTime = (value, now = new Date()) => {
99
99
  if (weeks < 52)
100
100
  return withDirection(weeks, 'w');
101
101
  const years = Math.floor(days / 365);
102
- return withDirection(years, 'y');
102
+ if (years >= 1)
103
+ return withDirection(years, 'y');
104
+ // Around the year boundary (e.g. 364 days), prefer weeks over "0y".
105
+ return withDirection(weeks, 'w');
103
106
  };
104
107
  /**
105
108
  * Build a detailed datetime string suitable for tooltips.
@@ -7,6 +7,8 @@ export type DatasourcesProps = {
7
7
  principalUid?: string;
8
8
  /** Optional principal kind used to scope datasource reads. */
9
9
  principalKind?: 'personal' | 'organization' | 'team';
10
+ /** Show local inline spinner in empty state while loading. */
11
+ showInlineLoadingIndicator?: boolean;
10
12
  };
11
- export declare const Datasources: ({ newDatasourceRoute, datasourcesListRoute, principalUid, principalKind, }?: DatasourcesProps) => import("react/jsx-runtime").JSX.Element;
13
+ export declare const Datasources: ({ newDatasourceRoute, datasourcesListRoute, principalUid, principalKind, showInlineLoadingIndicator, }?: DatasourcesProps) => import("react/jsx-runtime").JSX.Element;
12
14
  export default Datasources;
@@ -10,26 +10,26 @@ import { DatabaseIcon } from '@primer/octicons-react';
10
10
  import { Box } from '@datalayer/primer-addons';
11
11
  import { EditIcon } from '@datalayer/icons-react';
12
12
  import { useCache, useNavigate } from '../../hooks/index.js';
13
- const DatasourcesTable = ({ datasourcesListRoute, principalUid, principalKind, }) => {
13
+ const DatasourcesTable = ({ datasourcesListRoute, principalUid, principalKind, showInlineLoadingIndicator = true, }) => {
14
14
  const { useDatasources } = useCache();
15
15
  const datasourcesQuery = useDatasources({ principalUid, principalKind });
16
16
  const navigate = useNavigate();
17
17
  const [datasources, setDatasources] = useState([]);
18
- const showInitialSpinner = datasources.length === 0
19
- && (datasourcesQuery.isLoading
20
- || datasourcesQuery.isFetching
21
- || !Array.isArray(datasourcesQuery.data));
18
+ const showInitialSpinner = datasources.length === 0 &&
19
+ (datasourcesQuery.isLoading ||
20
+ datasourcesQuery.isFetching ||
21
+ !Array.isArray(datasourcesQuery.data));
22
22
  useEffect(() => {
23
23
  if (datasourcesQuery.data) {
24
24
  setDatasources(datasourcesQuery.data || []);
25
25
  }
26
26
  }, [datasourcesQuery.data]);
27
- return datasources.length === 0 ? (_jsx(Blankslate, { border: true, spacious: true, children: showInitialSpinner ? (_jsx(Box, { sx: {
27
+ return datasources.length === 0 ? (_jsx(Blankslate, { border: true, spacious: true, children: showInitialSpinner && showInlineLoadingIndicator ? (_jsx(Box, { sx: {
28
28
  display: 'flex',
29
29
  alignItems: 'center',
30
30
  justifyContent: 'center',
31
31
  minHeight: '40px',
32
- }, children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { 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: [
32
+ }, children: _jsx(Spinner, {}) })) : showInitialSpinner ? (_jsxs(_Fragment, { children: [_jsx(Blankslate.Heading, { children: "Datasources" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Loading datasources..." }) })] })) : (_jsxs(_Fragment, { 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: [
33
33
  // @ts-ignore
34
34
  {
35
35
  header: 'Type',
@@ -54,7 +54,7 @@ const DatasourcesTable = ({ datasourcesListRoute, principalUid, principalKind, }
54
54
  },
55
55
  ] }) }));
56
56
  };
57
- export const Datasources = ({ newDatasourceRoute = '/new/datasource', datasourcesListRoute, principalUid, principalKind, } = {}) => {
57
+ export const Datasources = ({ newDatasourceRoute = '/new/datasource', datasourcesListRoute, principalUid, principalKind, showInlineLoadingIndicator = true, } = {}) => {
58
58
  const navigate = useNavigate();
59
59
  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: {
60
60
  display: 'flex',
@@ -63,6 +63,6 @@ export const Datasources = ({ newDatasourceRoute = '/new/datasource', datasource
63
63
  gap: 3,
64
64
  flexWrap: 'wrap',
65
65
  mb: 4,
66
- }, 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 })] }) }) }));
66
+ }, 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, showInlineLoadingIndicator: showInlineLoadingIndicator })] }) }) }));
67
67
  };
68
68
  export default Datasources;
@@ -17,6 +17,7 @@ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
17
17
  import { Box, Button, FormControl, Heading, Text, Textarea, TextInput, } from '@primer/react';
18
18
  import { EyeIcon, EyeClosedIcon, KeyIcon, LinkExternalIcon, TelescopeIcon, } from '@primer/octicons-react';
19
19
  import { GithubMarkIcon, LinkedInGreyIcon } from '@datalayer/icons-react';
20
+ import { useToast } from '../../hooks/index.js';
20
21
  import { isInsideJupyterLab } from '../../utils/Jupyter.js';
21
22
  const GoogleIcon = () => (_jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", preserveAspectRatio: "xMidYMid", viewBox: "0 0 256 262", height: "16px", fill: "currentColor", "aria-hidden": "true", children: [_jsx("path", { fill: "currentColor", d: "M255.878 133.451c0-10.734-.871-18.567-2.756-26.69H130.55v48.448h71.947c-1.45 12.04-9.283 30.172-26.69 42.356l-.244 1.622 38.755 30.023 2.685.268c24.659-22.774 38.875-56.282 38.875-96.027" }), _jsx("path", { fill: "currentColor", d: "M130.55 261.1c35.248 0 64.839-11.605 86.453-31.622l-41.196-31.913c-11.024 7.688-25.82 13.055-45.257 13.055-34.523 0-63.824-22.773-74.269-54.25l-1.531.13-40.298 31.187-.527 1.465C35.393 231.798 79.49 261.1 130.55 261.1" }), _jsx("path", { fill: "currentColor", d: "M56.281 156.37c-2.756-8.123-4.351-16.827-4.351-25.82 0-8.994 1.595-17.697 4.206-25.82l-.073-1.73L15.26 71.312l-1.335.635C5.077 89.644 0 109.517 0 130.55s5.077 40.905 13.925 58.602l42.356-32.782" }), _jsx("path", { fill: "currentColor", d: "M130.55 50.479c24.514 0 41.05 10.589 50.479 19.438l36.844-35.974C195.245 12.91 165.798 0 130.55 0 79.49 0 35.393 29.301 13.925 71.947l42.211 32.783c10.59-31.477 39.891-54.251 74.414-54.251" })] }));
22
23
  const OAUTH2_PROVIDERS = {
@@ -52,6 +53,21 @@ const getIAMUrlFromDocumentConfig = () => {
52
53
  return '';
53
54
  }
54
55
  };
56
+ const getErrorMessage = (error, fallback = 'Unable to start social sign-in.') => {
57
+ if (error instanceof Error && error.message) {
58
+ return error.message;
59
+ }
60
+ if (typeof error === 'string' && error.trim()) {
61
+ return error;
62
+ }
63
+ if (error && typeof error === 'object' && 'message' in error) {
64
+ const message = error.message;
65
+ if (typeof message === 'string' && message.trim()) {
66
+ return message;
67
+ }
68
+ }
69
+ return fallback;
70
+ };
55
71
  // ── Component ────────────────────────────────────────────────────────
56
72
  export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp, name, title = 'Datalayer OTEL', description = 'Sign in to access the observability dashboard.', icon, leadingIcon = _jsx(TelescopeIcon, { size: 24 }), github = false, google = false, linkedin = false, apiKey = false, signUp = true, socialSignInNavigationTarget, }) => {
57
73
  const headingText = name ?? title;
@@ -68,6 +84,7 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
68
84
  const [loading, setLoading] = useState(false);
69
85
  const [socialLoading, setSocialLoading] = useState(false);
70
86
  const [error, setError] = useState(null);
87
+ const { enqueueToast } = useToast();
71
88
  // API Key dialog state
72
89
  const [showApiKeyDialog, setShowApiKeyDialog] = useState(false);
73
90
  const [apiKeyValue, setApiKeyValue] = useState('');
@@ -86,6 +103,9 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
86
103
  return route.startsWith('/') ? route : '/';
87
104
  }, []);
88
105
  const startOAuthSignIn = useCallback(async (providerSpec) => {
106
+ if (socialLoading) {
107
+ return;
108
+ }
89
109
  setError(null);
90
110
  setSocialLoading(true);
91
111
  try {
@@ -120,12 +140,18 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
120
140
  window.location.assign(authorizationURL);
121
141
  }
122
142
  catch (err) {
123
- setError(err instanceof Error ? err.message : 'Unable to start social sign-in.');
124
- }
125
- finally {
143
+ const message = getErrorMessage(err);
144
+ setError(message);
145
+ enqueueToast(message, { variant: 'error' });
126
146
  setSocialLoading(false);
127
147
  }
128
- }, [buildCallbackURI, currentRelativeRoute, socialSignInNavigationTarget]);
148
+ }, [
149
+ buildCallbackURI,
150
+ currentRelativeRoute,
151
+ enqueueToast,
152
+ socialLoading,
153
+ socialSignInNavigationTarget,
154
+ ]);
129
155
  useEffect(() => {
130
156
  if (showApiKeyDialog) {
131
157
  apiKeyRef.current?.focus();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/core",
3
- "version": "1.1.46",
3
+ "version": "1.1.48",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -1,2 +0,0 @@
1
- export declare const ProgressBar: () => import("react/jsx-runtime").JSX.Element;
2
- export default ProgressBar;