@datalayer/core 1.1.50 → 1.1.56
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 +19 -42
- package/lib/client/auth/AuthenticationManager.js +6 -4
- package/lib/client/auth/strategies.js +2 -0
- package/lib/components/animation/AnimatedText.d.ts +98 -0
- package/lib/components/animation/AnimatedText.js +220 -0
- package/lib/components/animation/index.d.ts +1 -0
- package/lib/components/animation/index.js +5 -0
- package/lib/components/auth/{LoginToken.d.ts → SigInAPIKey.d.ts} +3 -3
- package/lib/components/auth/{LoginToken.js → SigInAPIKey.js} +5 -5
- package/lib/components/auth/{Login.d.ts → SignIn.d.ts} +3 -3
- package/lib/components/auth/{Login.js → SignIn.js} +12 -12
- package/lib/components/auth/{Login.stories.d.ts → SignIn.stories.d.ts} +2 -2
- package/lib/components/auth/{Login.stories.js → SignIn.stories.js} +4 -4
- package/lib/components/auth/index.d.ts +2 -2
- package/lib/components/auth/index.js +2 -2
- package/lib/components/avatars/UserAvatar.d.ts +3 -1
- package/lib/components/avatars/UserAvatar.js +16 -3
- package/lib/components/avatars/UserProfileAvatar.js +2 -6
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +31 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +107 -0
- package/lib/components/collaboration/index.d.ts +1 -0
- package/lib/components/collaboration/index.js +9 -0
- package/lib/components/display/DatalayerBox.d.ts +3 -1
- package/lib/components/display/DatalayerBox.js +7 -7
- package/lib/components/display/JupyterDialog.d.ts +2 -0
- package/lib/components/display/JupyterDialog.js +10 -4
- package/lib/components/iam/ExternalTokenSilentLogin.js +2 -2
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +2 -0
- package/lib/components/labels/StatusLabels.d.ts +42 -0
- package/lib/components/labels/StatusLabels.js +61 -0
- package/lib/components/labels/index.d.ts +1 -0
- package/lib/components/labels/index.js +1 -0
- package/lib/components/principal/Principal.d.ts +2 -0
- package/lib/components/principal/Principal.js +11 -1
- package/lib/components/principal/PrincipalAppearance.d.ts +136 -0
- package/lib/components/principal/PrincipalAppearance.js +203 -0
- package/lib/components/principal/PrincipalAvatar.d.ts +5 -2
- package/lib/components/principal/PrincipalAvatar.js +16 -3
- package/lib/components/principal/PrincipalBadge.js +7 -0
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +2 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
- package/lib/components/principal/index.d.ts +1 -0
- package/lib/components/principal/index.js +1 -0
- package/lib/components/progress/ConsumptionBar.d.ts +9 -0
- package/lib/components/progress/ConsumptionBar.js +10 -2
- package/lib/components/sharing/ShareAccessComponent.js +6 -1
- package/lib/config/Configuration.d.ts +17 -8
- package/lib/config/Configuration.js +12 -5
- package/lib/hooks/useCache.d.ts +2 -0
- package/lib/hooks/useCache.js +35 -11
- package/lib/hooks/usePrincipalCacheStore.d.ts +2 -0
- package/lib/hooks/usePrincipalCacheStore.js +2 -0
- package/lib/models/IAM.d.ts +10 -0
- package/lib/models/Organization.d.ts +2 -0
- package/lib/models/Organization.js +2 -0
- package/lib/models/Profile.d.ts +2 -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 +4 -0
- package/lib/models/UserDTO.d.ts +6 -0
- package/lib/models/UserDTO.js +8 -0
- package/lib/state/substates/CoreState.js +3 -2
- package/lib/state/substates/IAMState.js +6 -0
- package/lib/state/substates/LayoutState.js +62 -7
- package/lib/state/substates/OrganizationState.d.ts +6 -0
- package/lib/state/substates/OrganizationState.js +5 -0
- package/lib/state/substates/ProfileState.d.ts +34 -0
- package/lib/state/substates/ProfileState.js +68 -0
- package/lib/state/substates/TeamState.d.ts +6 -0
- package/lib/state/substates/TeamState.js +3 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/views/iam/SignInSimple.d.ts +1 -1
- package/lib/views/iam/SignInSimple.js +3 -4
- package/package.json +2 -2
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* Authentication components for Datalayer platform
|
|
7
7
|
*/
|
|
8
|
-
export * from './
|
|
8
|
+
export * from './SignIn.js';
|
|
9
9
|
// LoginCLI is excluded from build - it's meant for CLI apps with full routing.
|
|
10
10
|
// export * from './LoginCLI.js';
|
|
11
|
-
export * from './
|
|
11
|
+
export * from './SigInAPIKey.js';
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export declare function hasRealAvatar(url?: string): boolean;
|
|
6
6
|
export type UserAvatarProps = {
|
|
7
7
|
avatarUrl?: string;
|
|
8
|
+
avatarIcon?: string;
|
|
8
9
|
/** Avatar edge length in pixels. Defaults to 100. */
|
|
9
10
|
size?: number;
|
|
10
11
|
/** Render with rounded square corners instead of a circle. Defaults to true. */
|
|
@@ -15,6 +16,7 @@ export type UserAvatarProps = {
|
|
|
15
16
|
fallbackBackground?: string;
|
|
16
17
|
/** Optional icon foreground color override for the default avatar. */
|
|
17
18
|
fallbackForeground?: string;
|
|
19
|
+
className?: string;
|
|
18
20
|
};
|
|
19
|
-
export declare const UserAvatar: ({ avatarUrl, size, square, iconSize, fallbackBackground, fallbackForeground, }: UserAvatarProps) => JSX.Element;
|
|
21
|
+
export declare const UserAvatar: ({ avatarUrl, avatarIcon, size, square, iconSize, fallbackBackground, fallbackForeground, className, }: UserAvatarProps) => JSX.Element;
|
|
20
22
|
export default UserAvatar;
|
|
@@ -14,6 +14,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
14
14
|
import { AlienIcon } from '@datalayer/icons-react';
|
|
15
15
|
import { Box, useColorPalette } from '@datalayer/primer-addons';
|
|
16
16
|
import { DLAvatar } from './DLAvatar.js';
|
|
17
|
+
import { getPrincipalAvatarIcon } from '../principal/PrincipalAppearance.js';
|
|
17
18
|
/**
|
|
18
19
|
* Returns `true` when the given URL points to a real user avatar (i.e. not a
|
|
19
20
|
* Gravatar default placeholder).
|
|
@@ -27,13 +28,25 @@ export function hasRealAvatar(url) {
|
|
|
27
28
|
}
|
|
28
29
|
return true;
|
|
29
30
|
}
|
|
30
|
-
export const UserAvatar = ({ avatarUrl, size = 100, square = true, iconSize, fallbackBackground, fallbackForeground, }) => {
|
|
31
|
+
export const UserAvatar = ({ avatarUrl, avatarIcon, size = 100, square = true, iconSize, fallbackBackground, fallbackForeground, className, }) => {
|
|
31
32
|
const palette = useColorPalette();
|
|
33
|
+
const SelectedIcon = getPrincipalAvatarIcon(avatarIcon);
|
|
34
|
+
if (SelectedIcon) {
|
|
35
|
+
return (_jsx(Box, { className: className, sx: {
|
|
36
|
+
width: size,
|
|
37
|
+
height: size,
|
|
38
|
+
borderRadius: square ? 2 : '50%',
|
|
39
|
+
overflow: 'hidden',
|
|
40
|
+
display: 'inline-flex',
|
|
41
|
+
alignItems: 'center',
|
|
42
|
+
justifyContent: 'center',
|
|
43
|
+
}, children: _jsx(SelectedIcon, { size: size, colored: true }) }));
|
|
44
|
+
}
|
|
32
45
|
if (hasRealAvatar(avatarUrl)) {
|
|
33
|
-
return _jsx(DLAvatar, { square: square, src: avatarUrl, size: size });
|
|
46
|
+
return _jsx(DLAvatar, { className: className, square: square, src: avatarUrl, size: size });
|
|
34
47
|
}
|
|
35
48
|
const resolvedIconSize = iconSize ?? Math.round(size * 0.48);
|
|
36
|
-
return (_jsx(Box, { sx: {
|
|
49
|
+
return (_jsx(Box, { className: className, sx: {
|
|
37
50
|
width: size,
|
|
38
51
|
height: size,
|
|
39
52
|
borderRadius: square ? 2 : '50%',
|
|
@@ -6,13 +6,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
6
6
|
import { Link } from '@primer/react';
|
|
7
7
|
import { Box } from '@datalayer/primer-addons';
|
|
8
8
|
import { AvatarSkeleton } from '../../components/display/index.js';
|
|
9
|
-
import {
|
|
9
|
+
import { UserAvatar } from './UserAvatar.js';
|
|
10
10
|
const Profile = ({ user, size = 100, onClick }) => {
|
|
11
|
-
return (_jsx(Box, { style: { width: size }, children: _jsx(
|
|
12
|
-
// square
|
|
13
|
-
, {
|
|
14
|
-
// square
|
|
15
|
-
src: user?.avatarUrl, size: size, onClick: onClick }) }));
|
|
11
|
+
return (_jsx(Box, { style: { width: size }, onClick: onClick, children: _jsx(UserAvatar, { avatarUrl: user?.avatarUrl, avatarIcon: user?.avatarIcon, size: size }) }));
|
|
16
12
|
};
|
|
17
13
|
export const UserProfileAvatar = ({ onClick, user, size = 100, }) => {
|
|
18
14
|
return user ? (onClick ? (_jsx(Link, { href: "javascript: return false;", onClick: onClick, children: _jsx(Profile, { user: user, size: size, onClick: onClick }) })) : (_jsx(Profile, { user: user, size: size, onClick: onClick }))) : (_jsx(AvatarSkeleton, { size: size }));
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type LiveCollaborator = {
|
|
2
|
+
/** Stable identity — a user uid, or the awareness client id. */
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
avatarUrl?: string;
|
|
6
|
+
avatarIcon?: string;
|
|
7
|
+
/** Cursor color of the presence, worn by the initials disc. */
|
|
8
|
+
color?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* The slice of a Yjs-style awareness this component reads. Structural, so
|
|
12
|
+
* any provider — Jupyter collaboration, Datalayer spacer — fits without a
|
|
13
|
+
* dependency on its package.
|
|
14
|
+
*/
|
|
15
|
+
export type IAwarenessLike = {
|
|
16
|
+
getStates(): Map<number, Record<string, any>>;
|
|
17
|
+
on(event: 'change', handler: () => void): void;
|
|
18
|
+
off(event: 'change', handler: () => void): void;
|
|
19
|
+
};
|
|
20
|
+
export type LiveEditorCollaboratorsProps = {
|
|
21
|
+
/** The presence of the room, followed live when given. */
|
|
22
|
+
awareness?: IAwarenessLike | null;
|
|
23
|
+
/** The collaborators known without a room — owner and granted. */
|
|
24
|
+
collaborators?: LiveCollaborator[];
|
|
25
|
+
/** Diameter of a face, in pixels. */
|
|
26
|
+
size?: number;
|
|
27
|
+
/** How many faces at most; the stack keeps the first ones. */
|
|
28
|
+
max?: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function LiveEditorCollaborators(props: LiveEditorCollaboratorsProps): JSX.Element | null;
|
|
31
|
+
export default LiveEditorCollaborators;
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/*
|
|
3
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
+
* Distributed under the terms of the Modified BSD License.
|
|
5
|
+
*/
|
|
6
|
+
/*
|
|
7
|
+
* Copyright (c) 2023-2026 Datalayer, Inc.
|
|
8
|
+
* Distributed under the terms of the Modified BSD License.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The faces on a shared document: who is here now, and who belongs here.
|
|
12
|
+
*
|
|
13
|
+
* One avatar stack for every surface that names collaborators — the cards of
|
|
14
|
+
* the home page, the headers of the notebook and document editors, in the
|
|
15
|
+
* web application and in JupyterLab alike. Two sources feed it, both
|
|
16
|
+
* optional and freely combined:
|
|
17
|
+
*
|
|
18
|
+
* - `awareness`: the presence channel of a collaborative editor. The stack
|
|
19
|
+
* follows it live — people appear as they join and leave as they go.
|
|
20
|
+
* - `collaborators`: what is known without a room, the owner and the granted
|
|
21
|
+
* of an item. They fill the stack when there is no presence, and complete
|
|
22
|
+
* it when there is.
|
|
23
|
+
*
|
|
24
|
+
* Every face uses the shared principal avatar rules: a selected icon wins,
|
|
25
|
+
* then a connected-account picture, then the standard personal fallback.
|
|
26
|
+
*
|
|
27
|
+
* @module components/collaboration/LiveEditorCollaborators
|
|
28
|
+
*/
|
|
29
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
30
|
+
import { AvatarStack } from '@primer/react';
|
|
31
|
+
import { PrincipalAvatar } from '../principal/PrincipalAvatar.js';
|
|
32
|
+
/** The `user` field of an awareness state, in its several spellings. */
|
|
33
|
+
function collaboratorOfState(clientId, state) {
|
|
34
|
+
const user = state?.user;
|
|
35
|
+
if (!user) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const name = user.display_name || user.displayName || user.name || user.username || '';
|
|
39
|
+
if (!name) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
id: String(user.uid ?? user.id ?? user.username ?? clientId),
|
|
44
|
+
name,
|
|
45
|
+
avatarUrl: user.avatar_url || user.avatarUrl || undefined,
|
|
46
|
+
avatarIcon: user.avatar_icon_s || user.avatarIcon || undefined,
|
|
47
|
+
color: user.color || undefined
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function LiveEditorCollaborators(props) {
|
|
51
|
+
const { awareness, collaborators = [], max = 5, size = 24 } = props;
|
|
52
|
+
const [present, setPresent] = useState([]);
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!awareness) {
|
|
55
|
+
setPresent([]);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const read = () => {
|
|
59
|
+
const seen = new Map();
|
|
60
|
+
awareness.getStates().forEach((state, clientId) => {
|
|
61
|
+
const collaborator = collaboratorOfState(clientId, state);
|
|
62
|
+
// One face per person, however many tabs they have open.
|
|
63
|
+
if (collaborator && !seen.has(collaborator.id)) {
|
|
64
|
+
seen.set(collaborator.id, collaborator);
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
setPresent(Array.from(seen.values()));
|
|
68
|
+
};
|
|
69
|
+
read();
|
|
70
|
+
awareness.on('change', read);
|
|
71
|
+
return () => {
|
|
72
|
+
awareness.off('change', read);
|
|
73
|
+
};
|
|
74
|
+
}, [awareness]);
|
|
75
|
+
const faces = useMemo(() => {
|
|
76
|
+
// Who is here leads; who merely belongs completes. Folded by id and
|
|
77
|
+
// then by name: the same person often arrives twice — once under their
|
|
78
|
+
// platform uid, once under the identity the room gave them.
|
|
79
|
+
const merged = new Map();
|
|
80
|
+
const byName = new Map();
|
|
81
|
+
for (const collaborator of [...present, ...collaborators]) {
|
|
82
|
+
const nameKey = collaborator.name.trim().toLowerCase();
|
|
83
|
+
const key = merged.has(collaborator.id)
|
|
84
|
+
? collaborator.id
|
|
85
|
+
: (byName.get(nameKey) ?? collaborator.id);
|
|
86
|
+
const known = merged.get(key);
|
|
87
|
+
if (!known) {
|
|
88
|
+
merged.set(key, collaborator);
|
|
89
|
+
byName.set(nameKey, key);
|
|
90
|
+
}
|
|
91
|
+
else if ((!known.avatarIcon && collaborator.avatarIcon) ||
|
|
92
|
+
(!known.avatarUrl && collaborator.avatarUrl)) {
|
|
93
|
+
merged.set(key, {
|
|
94
|
+
...known,
|
|
95
|
+
avatarIcon: known.avatarIcon || collaborator.avatarIcon,
|
|
96
|
+
avatarUrl: known.avatarUrl || collaborator.avatarUrl,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return Array.from(merged.values()).slice(0, max);
|
|
101
|
+
}, [collaborators, max, present]);
|
|
102
|
+
if (!faces.length) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
return (_jsx(AvatarStack, { size: size, children: faces.map(face => (_jsx(PrincipalAvatar, { kind: "personal", size: size, alt: face.name, avatarUrl: face.avatarUrl, avatarIcon: face.avatarIcon, square: false }, face.id))) }));
|
|
106
|
+
}
|
|
107
|
+
export default LiveEditorCollaborators;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './LiveEditorCollaborators';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
/*
|
|
6
|
+
* Copyright (c) 2023-2026 Datalayer, Inc.
|
|
7
|
+
* Distributed under the terms of the Modified BSD License.
|
|
8
|
+
*/
|
|
9
|
+
export * from './LiveEditorCollaborators.js';
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { PropsWithChildren, ReactNode } from 'react';
|
|
1
2
|
type DatalayerBoxProps = {
|
|
2
3
|
id?: string;
|
|
3
4
|
title: string;
|
|
5
|
+
titleAction?: ReactNode;
|
|
4
6
|
linkLabel?: string;
|
|
5
7
|
linkRoute?: string;
|
|
6
8
|
};
|
|
7
|
-
export declare const DatalayerBox: (props:
|
|
9
|
+
export declare const DatalayerBox: (props: PropsWithChildren<DatalayerBoxProps>) => import("react/jsx-runtime").JSX.Element;
|
|
8
10
|
export default DatalayerBox;
|
|
@@ -8,19 +8,19 @@ import { Box } from '@datalayer/primer-addons';
|
|
|
8
8
|
import { ArrowRightIcon } from '@primer/octicons-react';
|
|
9
9
|
import { useNavigate } from '../../hooks/index.js';
|
|
10
10
|
export const DatalayerBox = (props) => {
|
|
11
|
-
const { title, linkLabel, linkRoute, children } = props;
|
|
11
|
+
const { title, titleAction, linkLabel, linkRoute, children } = props;
|
|
12
12
|
const navigate = useNavigate();
|
|
13
13
|
return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
14
14
|
display: 'flex',
|
|
15
15
|
alignItems: 'center',
|
|
16
16
|
justifyContent: 'space-between',
|
|
17
17
|
paddingRight: 4,
|
|
18
|
-
}, children: [_jsx(Text, { as: "h2", sx: { borderLeft: '6px solid #28b899', paddingLeft: 2 }, children: title }), linkRoute && linkLabel && (_jsxs(Link, { href: "javascript: return false;", onClick: e => navigate(linkRoute), sx: {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
}, children: [_jsx(Text, { as: "h2", sx: { borderLeft: '6px solid #28b899', paddingLeft: 2 }, children: title }), (titleAction || (linkRoute && linkLabel)) && (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [titleAction, linkRoute && linkLabel && (_jsxs(Link, { href: "javascript: return false;", onClick: e => navigate(linkRoute), sx: {
|
|
19
|
+
display: 'inline-flex',
|
|
20
|
+
alignItems: 'center',
|
|
21
|
+
gap: 1,
|
|
22
|
+
whiteSpace: 'nowrap',
|
|
23
|
+
}, children: [linkLabel, _jsx(ArrowRightIcon, {})] }))] }))] }), _jsx(Box, { sx: {
|
|
24
24
|
borderColor: 'border.default',
|
|
25
25
|
borderStyle: 'solid',
|
|
26
26
|
borderWidth: '1',
|
|
@@ -45,6 +45,8 @@ export interface IDialogWrapperOptions<T> {
|
|
|
45
45
|
export declare class JupyterDialog<T> extends ReactWidget {
|
|
46
46
|
protected body: JSXElementConstructor<PropsWithChildren<DialogProps & {
|
|
47
47
|
setValue: (v: T | Error) => void;
|
|
48
|
+
/** Whether an accepted answer is being acted on. */
|
|
49
|
+
pending?: boolean;
|
|
48
50
|
}>>;
|
|
49
51
|
protected checkbox: Partial<Dialog.ICheckbox> | null;
|
|
50
52
|
protected buttons: Dialog.IButton[];
|
|
@@ -56,10 +56,16 @@ export class JupyterDialog extends ReactWidget {
|
|
|
56
56
|
this.dialogTitle = options.title;
|
|
57
57
|
this.onWillAccept = options.onWillAccept;
|
|
58
58
|
}
|
|
59
|
-
_renderBody = (props) =>
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
_renderBody = (props) => {
|
|
60
|
+
const pending = this._pendingButtonIndex !== null;
|
|
61
|
+
return (_jsx(PrimerDialog.Body, { children: _jsx("div", { "aria-busy": pending, ...(pending ? { inert: '' } : {}), style: pending
|
|
62
|
+
? { pointerEvents: 'none', opacity: 0.6 }
|
|
63
|
+
: undefined, children: createElement(this.body, {
|
|
64
|
+
...props,
|
|
65
|
+
setValue: this.setValue,
|
|
66
|
+
pending,
|
|
67
|
+
}) }) }));
|
|
68
|
+
};
|
|
63
69
|
_renderFooter = (props) => (_jsx(DialogFooter, { ...props, checkbox: this.checkbox, setChecked: this.setChecked }));
|
|
64
70
|
render() {
|
|
65
71
|
// TODO title color is enforced for JupyterLab.
|
|
@@ -18,8 +18,8 @@ const ExternalTokenSilentLoginRoute = (props) => {
|
|
|
18
18
|
if (externalToken) {
|
|
19
19
|
loginAndNavigate(externalToken, logout, checkIAMToken)
|
|
20
20
|
.catch(error => {
|
|
21
|
-
console.debug('Failed to
|
|
22
|
-
enqueueToast('Failed to
|
|
21
|
+
console.debug('Failed to sign in with the provided token.', error);
|
|
22
|
+
enqueueToast('Failed to sign in with the provided token.', {
|
|
23
23
|
variant: 'error',
|
|
24
24
|
});
|
|
25
25
|
})
|
package/lib/components/index.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
* Distributed under the terms of the Modified BSD License.
|
|
4
4
|
*/
|
|
5
5
|
export * from './auth/index.js';
|
|
6
|
+
export * from './animation/index.js';
|
|
6
7
|
export * from './billing/index.js';
|
|
8
|
+
export * from './collaboration/index.js';
|
|
7
9
|
export * from './sharing/index.js';
|
|
8
10
|
export * from './sparklines/index.js';
|
|
9
11
|
export * from './time/index.js';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The small pills that qualify an entry.
|
|
3
|
+
*
|
|
4
|
+
* A menu entry, a card, a row of a switcher: what qualifies them is always
|
|
5
|
+
* the same mark — one lowercase word in a semantic tone — and it was written
|
|
6
|
+
* out at every place that needed one. These are that mark, named after what
|
|
7
|
+
* they say, so `alpha` looks the same in the user menu, on an integration and
|
|
8
|
+
* wherever it is needed next.
|
|
9
|
+
*
|
|
10
|
+
* @module components/labels/StatusLabels
|
|
11
|
+
*/
|
|
12
|
+
import type { ReactNode } from 'react';
|
|
13
|
+
/** The tones a status pill is read in. */
|
|
14
|
+
export type StatusLabelTone = 'accent' | 'attention' | 'success' | 'neutral';
|
|
15
|
+
export type StatusLabelProps = {
|
|
16
|
+
/** Word of the pill; each label has one of its own. */
|
|
17
|
+
children?: ReactNode;
|
|
18
|
+
size?: 'small' | 'large';
|
|
19
|
+
sx?: Record<string, unknown>;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The pill the named labels below are made of.
|
|
23
|
+
*
|
|
24
|
+
* Exported for a qualification that has no label of its own yet; prefer one of
|
|
25
|
+
* the named ones, so the same thing is said the same way everywhere.
|
|
26
|
+
*/
|
|
27
|
+
export declare function StatusLabel(props: StatusLabelProps & {
|
|
28
|
+
tone: StatusLabelTone;
|
|
29
|
+
}): JSX.Element;
|
|
30
|
+
/**
|
|
31
|
+
* A feature that is being tried out.
|
|
32
|
+
*/
|
|
33
|
+
export declare function AlphaLabel(props?: StatusLabelProps): JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* Something reserved to the administrators of the platform.
|
|
36
|
+
*/
|
|
37
|
+
export declare function AdminLabel(props?: StatusLabelProps): JSX.Element;
|
|
38
|
+
/**
|
|
39
|
+
* The one that is taken when none is chosen — the default space of an account.
|
|
40
|
+
*/
|
|
41
|
+
export declare function DefaultLabel(props?: StatusLabelProps): JSX.Element;
|
|
42
|
+
export default StatusLabel;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Label } from '@primer/react';
|
|
3
|
+
const TONES = {
|
|
4
|
+
accent: {
|
|
5
|
+
bg: 'accent.subtle',
|
|
6
|
+
color: 'accent.fg',
|
|
7
|
+
borderColor: 'accent.muted',
|
|
8
|
+
},
|
|
9
|
+
attention: {
|
|
10
|
+
bg: 'attention.subtle',
|
|
11
|
+
color: 'attention.fg',
|
|
12
|
+
borderColor: 'attention.muted',
|
|
13
|
+
},
|
|
14
|
+
success: {
|
|
15
|
+
bg: 'success.subtle',
|
|
16
|
+
color: 'success.fg',
|
|
17
|
+
borderColor: 'success.muted',
|
|
18
|
+
},
|
|
19
|
+
neutral: {
|
|
20
|
+
bg: 'neutral.subtle',
|
|
21
|
+
color: 'fg.muted',
|
|
22
|
+
borderColor: 'border.default',
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The pill the named labels below are made of.
|
|
27
|
+
*
|
|
28
|
+
* Exported for a qualification that has no label of its own yet; prefer one of
|
|
29
|
+
* the named ones, so the same thing is said the same way everywhere.
|
|
30
|
+
*/
|
|
31
|
+
export function StatusLabel(props) {
|
|
32
|
+
const { children, size = 'small', sx, tone } = props;
|
|
33
|
+
return (_jsx(Label, { variant: "secondary", size: size, sx: {
|
|
34
|
+
textTransform: 'lowercase',
|
|
35
|
+
lineHeight: 1.2,
|
|
36
|
+
...TONES[tone],
|
|
37
|
+
...sx,
|
|
38
|
+
}, children: children }));
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A feature that is being tried out.
|
|
42
|
+
*/
|
|
43
|
+
export function AlphaLabel(props = {}) {
|
|
44
|
+
const { children = 'alpha', ...rest } = props;
|
|
45
|
+
return (_jsx(StatusLabel, { tone: "accent", ...rest, children: children }));
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Something reserved to the administrators of the platform.
|
|
49
|
+
*/
|
|
50
|
+
export function AdminLabel(props = {}) {
|
|
51
|
+
const { children = 'admin', ...rest } = props;
|
|
52
|
+
return (_jsx(StatusLabel, { tone: "attention", ...rest, children: children }));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* The one that is taken when none is chosen — the default space of an account.
|
|
56
|
+
*/
|
|
57
|
+
export function DefaultLabel(props = {}) {
|
|
58
|
+
const { children = 'default', ...rest } = props;
|
|
59
|
+
return (_jsx(StatusLabel, { tone: "accent", ...rest, children: children }));
|
|
60
|
+
}
|
|
61
|
+
export default StatusLabel;
|
|
@@ -114,6 +114,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
|
|
|
114
114
|
lastName: profile.last_name,
|
|
115
115
|
handle: profile.handle,
|
|
116
116
|
avatarUrl: profile.avatar_url,
|
|
117
|
+
avatarIcon: profile.avatar_icon_s || profile.avatar_icon,
|
|
118
|
+
banner: profile.banner_s || profile.banner,
|
|
117
119
|
origin: profile.origin,
|
|
118
120
|
email: profile.email,
|
|
119
121
|
};
|
|
@@ -129,6 +131,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
|
|
|
129
131
|
description: profile.description || profile.description_t,
|
|
130
132
|
handle: profile.handle,
|
|
131
133
|
avatarUrl: profile.avatar_url,
|
|
134
|
+
avatarIcon: profile.avatar_icon_s || profile.avatar_icon,
|
|
135
|
+
banner: profile.banner_s || profile.banner,
|
|
132
136
|
};
|
|
133
137
|
}, [hydratedPublicOrgQuery.data]);
|
|
134
138
|
const hydratedEntity = principal.kind === 'personal'
|
|
@@ -222,6 +226,10 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
|
|
|
222
226
|
hydratedEntity?.avatarUrl ||
|
|
223
227
|
cachedPrincipal?.avatarUrl ||
|
|
224
228
|
undefined,
|
|
229
|
+
avatarIcon: principal.avatarIcon ||
|
|
230
|
+
hydratedEntity?.avatarIcon ||
|
|
231
|
+
undefined,
|
|
232
|
+
banner: principal.banner || hydratedEntity?.banner || undefined,
|
|
225
233
|
firstName: principal.firstName ||
|
|
226
234
|
hydratedEntity?.firstName ||
|
|
227
235
|
cachedPrincipal?.firstName ||
|
|
@@ -263,6 +271,8 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
|
|
|
263
271
|
email: resolvedPrincipal.email,
|
|
264
272
|
origin: resolvedPrincipal.origin,
|
|
265
273
|
avatarUrl: resolvedPrincipal.avatarUrl,
|
|
274
|
+
avatarIcon: resolvedPrincipal.avatarIcon,
|
|
275
|
+
banner: resolvedPrincipal.banner,
|
|
266
276
|
organizationHandle: teamOrganizationHandleResolved,
|
|
267
277
|
organizationName: teamOrganizationNameResolved,
|
|
268
278
|
memberCount: teamMemberCount,
|
|
@@ -286,6 +296,6 @@ export const Principal = ({ principal, isAdmin = false, avatarSize = 20, gap = 2
|
|
|
286
296
|
gap,
|
|
287
297
|
minWidth: 0,
|
|
288
298
|
...sx,
|
|
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 })] }));
|
|
299
|
+
}, children: [_jsx(PrincipalAvatar, { kind: resolvedPrincipal.kind, avatarUrl: resolvedPrincipal.avatarUrl, avatarIcon: resolvedPrincipal.avatarIcon, 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, avatarIcon: resolvedPrincipal.avatarIcon, organizationName: teamOrganizationNameResolved, memberCount: teamMemberCount, isPublic: resolvedIsPublic, isAdmin: isAdmin })] }));
|
|
290
300
|
};
|
|
291
301
|
export default Principal;
|