@datalayer/core 1.1.50 → 1.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/README.md +19 -42
  2. package/lib/client/auth/AuthenticationManager.js +6 -4
  3. package/lib/client/auth/strategies.js +2 -0
  4. package/lib/components/animation/AnimatedText.d.ts +98 -0
  5. package/lib/components/animation/AnimatedText.js +220 -0
  6. package/lib/components/animation/index.d.ts +1 -0
  7. package/lib/components/animation/index.js +5 -0
  8. package/lib/components/auth/{LoginToken.d.ts → SigInAPIKey.d.ts} +3 -3
  9. package/lib/components/auth/{LoginToken.js → SigInAPIKey.js} +5 -5
  10. package/lib/components/auth/{Login.d.ts → SignIn.d.ts} +3 -3
  11. package/lib/components/auth/{Login.js → SignIn.js} +12 -12
  12. package/lib/components/auth/{Login.stories.d.ts → SignIn.stories.d.ts} +2 -2
  13. package/lib/components/auth/{Login.stories.js → SignIn.stories.js} +4 -4
  14. package/lib/components/auth/index.d.ts +2 -2
  15. package/lib/components/auth/index.js +2 -2
  16. package/lib/components/avatars/UserAvatar.d.ts +3 -1
  17. package/lib/components/avatars/UserAvatar.js +16 -3
  18. package/lib/components/avatars/UserProfileAvatar.js +2 -6
  19. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +31 -0
  20. package/lib/components/collaboration/LiveEditorCollaborators.js +107 -0
  21. package/lib/components/collaboration/index.d.ts +1 -0
  22. package/lib/components/collaboration/index.js +9 -0
  23. package/lib/components/display/DatalayerBox.d.ts +3 -1
  24. package/lib/components/display/DatalayerBox.js +7 -7
  25. package/lib/components/display/JupyterDialog.d.ts +2 -0
  26. package/lib/components/display/JupyterDialog.js +10 -4
  27. package/lib/components/iam/ExternalTokenSilentLogin.js +2 -2
  28. package/lib/components/index.d.ts +2 -0
  29. package/lib/components/index.js +2 -0
  30. package/lib/components/labels/StatusLabels.d.ts +42 -0
  31. package/lib/components/labels/StatusLabels.js +61 -0
  32. package/lib/components/labels/index.d.ts +1 -0
  33. package/lib/components/labels/index.js +1 -0
  34. package/lib/components/principal/Principal.d.ts +2 -0
  35. package/lib/components/principal/Principal.js +11 -1
  36. package/lib/components/principal/PrincipalAppearance.d.ts +136 -0
  37. package/lib/components/principal/PrincipalAppearance.js +203 -0
  38. package/lib/components/principal/PrincipalAvatar.d.ts +5 -2
  39. package/lib/components/principal/PrincipalAvatar.js +16 -3
  40. package/lib/components/principal/PrincipalBadge.js +7 -0
  41. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +2 -1
  42. package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
  43. package/lib/components/principal/index.d.ts +1 -0
  44. package/lib/components/principal/index.js +1 -0
  45. package/lib/components/progress/ConsumptionBar.d.ts +9 -0
  46. package/lib/components/progress/ConsumptionBar.js +10 -2
  47. package/lib/components/sharing/ShareAccessComponent.js +6 -1
  48. package/lib/components/students/StudentItemStatus.d.ts +33 -0
  49. package/lib/components/students/StudentItemStatus.js +68 -0
  50. package/lib/components/students/index.d.ts +1 -0
  51. package/lib/components/students/index.js +1 -0
  52. package/lib/config/Configuration.d.ts +17 -8
  53. package/lib/config/Configuration.js +12 -5
  54. package/lib/hooks/useCache.d.ts +2 -0
  55. package/lib/hooks/useCache.js +35 -11
  56. package/lib/hooks/usePrincipalCacheStore.d.ts +2 -0
  57. package/lib/hooks/usePrincipalCacheStore.js +2 -0
  58. package/lib/models/IAM.d.ts +10 -0
  59. package/lib/models/Organization.d.ts +2 -0
  60. package/lib/models/Organization.js +2 -0
  61. package/lib/models/Profile.d.ts +2 -0
  62. package/lib/models/Team.d.ts +2 -0
  63. package/lib/models/Team.js +2 -0
  64. package/lib/models/User.d.ts +4 -0
  65. package/lib/models/User.js +4 -0
  66. package/lib/models/UserDTO.d.ts +6 -0
  67. package/lib/models/UserDTO.js +8 -0
  68. package/lib/state/substates/CoreState.js +3 -2
  69. package/lib/state/substates/IAMState.js +6 -0
  70. package/lib/state/substates/LayoutState.js +62 -7
  71. package/lib/state/substates/OrganizationState.d.ts +6 -0
  72. package/lib/state/substates/OrganizationState.js +5 -0
  73. package/lib/state/substates/ProfileState.d.ts +34 -0
  74. package/lib/state/substates/ProfileState.js +68 -0
  75. package/lib/state/substates/TeamState.d.ts +6 -0
  76. package/lib/state/substates/TeamState.js +3 -0
  77. package/lib/state/substates/index.d.ts +1 -0
  78. package/lib/state/substates/index.js +1 -0
  79. package/lib/views/iam/SignInSimple.d.ts +1 -1
  80. package/lib/views/iam/SignInSimple.js +3 -4
  81. package/package.json +2 -2
@@ -9,6 +9,11 @@ export const organizationStore = createStore((set, get) => ({
9
9
  updateOrganizations: (organizations) => set((state) => ({
10
10
  organizations,
11
11
  })),
12
+ updateOrganization: organization => set((state) => ({
13
+ organizations: state.organizations.map(known => known.id === organization.id
14
+ ? { ...known, ...organization }
15
+ : known),
16
+ })),
12
17
  }));
13
18
  export function useOrganizationStore(selector) {
14
19
  return useStore(organizationStore, selector);
@@ -0,0 +1,34 @@
1
+ import type { IUser } from '../../models';
2
+ /** The profile of the authenticated user, as the surfaces show it. */
3
+ export type IProfile = {
4
+ id?: string;
5
+ uid?: string;
6
+ handle?: string;
7
+ email?: string;
8
+ firstName?: string;
9
+ lastName?: string;
10
+ displayName?: string;
11
+ initials?: string;
12
+ avatarUrl?: string;
13
+ avatarIcon?: string;
14
+ banner?: string;
15
+ origin?: string;
16
+ roles?: string[];
17
+ };
18
+ export type ProfileState = {
19
+ profile?: IProfile;
20
+ /** Replace the profile wholesale. */
21
+ setProfile: (profile?: IProfile) => void;
22
+ /** Merge what a flow just learned into the profile. */
23
+ updateProfile: (partial: Partial<IProfile>) => void;
24
+ /** The IAM user as the profile — login and refresh feed through this. */
25
+ setProfileFromUser: (user?: IUser) => void;
26
+ /** Logout. */
27
+ clearProfile: () => void;
28
+ };
29
+ export declare const profileStore: import("zustand").StoreApi<ProfileState>;
30
+ export declare function useProfileStore(): ProfileState;
31
+ export declare function useProfileStore<T>(selector: (state: ProfileState) => T): T;
32
+ /** The profile, for surfaces that show it. */
33
+ export declare const useProfile: () => IProfile | undefined;
34
+ export default useProfileStore;
@@ -0,0 +1,68 @@
1
+ /*
2
+ * Copyright (c) 2023-2026 Datalayer, Inc.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ /**
6
+ * ProfileState — the one place the authenticated user's profile lives.
7
+ *
8
+ * The avatar and the banner used to be read from whatever carried them at
9
+ * each call site — the IAM user, a whoami response, a form snapshot — and
10
+ * the surfaces drifted: a banner updated on the profile page did not reach
11
+ * the user menu until the page reloaded. Every surface showing the profile
12
+ * (user menu, sidebars, profile views) reads this store instead, and every
13
+ * flow that learns something about the profile (login, `GET /me`, a profile
14
+ * update) writes it here.
15
+ *
16
+ * The store is fed automatically by {@link IAMState} on login, profile
17
+ * update and logout, and by the `useMe` query with the full profile — the
18
+ * consumers only ever read.
19
+ *
20
+ * @module state/substates/ProfileState
21
+ */
22
+ import { useStore } from 'zustand';
23
+ import { createStore } from 'zustand/vanilla';
24
+ const userToProfile = (user) => user
25
+ ? {
26
+ id: user.id,
27
+ uid: user.uid,
28
+ handle: user.handle,
29
+ email: user.email,
30
+ firstName: user.firstName,
31
+ lastName: user.lastName,
32
+ displayName: user.displayName,
33
+ initials: user.initials,
34
+ avatarUrl: user.avatarUrl,
35
+ avatarIcon: user.avatarIcon,
36
+ banner: user.banner,
37
+ origin: user.origin,
38
+ roles: user.roles,
39
+ }
40
+ : undefined;
41
+ export const profileStore = createStore(set => ({
42
+ profile: undefined,
43
+ setProfile: profile => set({ profile }),
44
+ updateProfile: partial => set(state => ({ profile: { ...state.profile, ...partial } })),
45
+ setProfileFromUser: user => set(state => {
46
+ const profile = userToProfile(user);
47
+ if (!profile) {
48
+ return state;
49
+ }
50
+ // A login refresh may know less than a profile update that already
51
+ // landed (the anonymous whoami has no banner): merge, newest wins,
52
+ // but never erase a field with undefined.
53
+ const merged = { ...state.profile };
54
+ for (const [key, value] of Object.entries(profile)) {
55
+ if (value !== undefined) {
56
+ merged[key] = value;
57
+ }
58
+ }
59
+ return { profile: merged };
60
+ }),
61
+ clearProfile: () => set({ profile: undefined }),
62
+ }));
63
+ export function useProfileStore(selector) {
64
+ return useStore(profileStore, selector);
65
+ }
66
+ /** The profile, for surfaces that show it. */
67
+ export const useProfile = () => useProfileStore(state => state.profile);
68
+ export default useProfileStore;
@@ -4,6 +4,12 @@ export type ITeamState = {
4
4
  };
5
5
  export type TeamState = ITeamState & {
6
6
  update: (teams: IBaseTeam[]) => void;
7
+ /**
8
+ * Merge what just changed into the team of the list — the way a settings
9
+ * save keeps every surface reading this store current (avatar, banner,
10
+ * name…) without refetching the list.
11
+ */
12
+ updateTeam: (team: Partial<IBaseTeam> & Pick<IBaseTeam, 'id'>) => void;
7
13
  };
8
14
  export declare const teamStore: import("zustand").StoreApi<TeamState>;
9
15
  export declare function useTeamStore(): TeamState;
@@ -10,6 +10,9 @@ export const teamStore = createStore((set, get) => ({
10
10
  update: (teams) => set((state) => ({
11
11
  teams,
12
12
  })),
13
+ updateTeam: team => set((state) => ({
14
+ teams: state.teams.map(known => known.id === team.id ? { ...known, ...team } : known),
15
+ })),
13
16
  }));
14
17
  export function useTeamStore(selector) {
15
18
  return useStore(teamStore, selector);
@@ -2,6 +2,7 @@ export * from './CoreState';
2
2
  export * from './DatasourceState';
3
3
  export * from './IAMState';
4
4
  export * from './LayoutState';
5
+ export * from './ProfileState';
5
6
  export * from './OrganizationState';
6
7
  export * from './SurveysState';
7
8
  export * from './TeamState';
@@ -6,6 +6,7 @@ export * from './CoreState.js';
6
6
  export * from './DatasourceState.js';
7
7
  export * from './IAMState.js';
8
8
  export * from './LayoutState.js';
9
+ export * from './ProfileState.js';
9
10
  export * from './OrganizationState.js';
10
11
  export * from './SurveysState.js';
11
12
  export * from './TeamState.js';
@@ -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 In with an API Key" button is hidden.
19
+ * If not provided the "Sign in with an API Key" button is hidden.
20
20
  */
21
21
  onApiKeySignIn?: (apiKey: string) => void;
22
22
  /**
@@ -103,8 +103,7 @@ const SignInInputGlobalStyle = createGlobalStyle `
103
103
  // ── Component ────────────────────────────────────────────────────────
104
104
  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, asDoc = false, hideHero = false, calloutTitle, calloutDescription, passwordToggleLabel = 'Sign in with a password', signUpTitle = "Don't have an account?", signUpDescription = 'Create a free Datalayer account with your email address.', signUpLabel = 'Sign up with email', signUpHref = 'https://datalayer.ai/signup', forgotPasswordHref = '/password', forgotPasswordLabel = 'Forgot password?', showForgotPassword = true, socialButtonMarginTop = 3, actionButtonMaxWidth = 320, }) => {
105
105
  const compactDocMode = asDoc && !hideHero;
106
- const headingText = name ??
107
- (asDoc && title === 'Datalayer OTEL' ? 'Datalayer Sign In' : title);
106
+ const headingText = name ?? (asDoc && title === 'Datalayer OTEL' ? 'Datalayer Sign In' : title);
108
107
  const headingIcon = icon ?? (asDoc ? _jsx(SignInIcon, { size: 24 }) : leadingIcon);
109
108
  const loginUrl = useMemo(() => {
110
109
  if (loginUrlProp)
@@ -361,7 +360,7 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
361
360
  alignItems: 'center',
362
361
  justifyContent: 'space-between',
363
362
  mt: 3,
364
- }, children: [_jsx(Button, { variant: "primary", disabled: loading || asDoc || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign in' }), showForgotPassword && (_jsx(Link, { as: "button", sx: {
363
+ }, children: [_jsx(Button, { variant: "primary", disabled: loading || asDoc || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign In' }), showForgotPassword && (_jsx(Link, { as: "button", sx: {
365
364
  fontSize: 1,
366
365
  cursor: asDoc ? 'not-allowed' : 'pointer',
367
366
  background: 'none',
@@ -383,7 +382,7 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
383
382
  alignItems: 'center',
384
383
  gap: 2,
385
384
  my: 3,
386
- }, 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, disabled: asDoc || loading || socialLoading, onClick: () => setShowApiKeyDialog(true), sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: "Sign In with an API Key" }), showApiKeyDialog && (_jsx(Box, { role: "dialog", "aria-modal": "true", "aria-labelledby": "signin-api-key-title", onKeyDown: event => {
385
+ }, 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, disabled: asDoc || loading || socialLoading, onClick: () => setShowApiKeyDialog(true), sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: "Sign in with an API Key" }), showApiKeyDialog && (_jsx(Box, { role: "dialog", "aria-modal": "true", "aria-labelledby": "signin-api-key-title", onKeyDown: event => {
387
386
  if (event.key === 'Escape') {
388
387
  closeApiKeyDialog();
389
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/core",
3
- "version": "1.1.50",
3
+ "version": "1.1.57",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",
@@ -90,7 +90,7 @@
90
90
  "watch:lib:src": "tsc -b -w",
91
91
  "type-check:watch": "tsc -b -w --noEmit",
92
92
  "examples": "run-p jupyter:start examples:vite",
93
- "examples:vite": "VITE_DATALAYER_URL=http://localhost:8888 vite --config vite.examples.config.ts",
93
+ "examples:vite": "VITE_DATALAYER_IAM_URL=http://localhost:8888 vite --config vite.examples.config.ts",
94
94
  "examples:nextjs": "npm run dev --workspace=nextjj-example",
95
95
  "jupyter:start": "./dev/sh/start-jupyter-server.sh",
96
96
  "prepare": "husky || true",