@datalayer/core 1.1.59 → 1.1.66
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 +2 -2
- package/lib/api/DatalayerApi.d.ts +42 -1
- package/lib/api/DatalayerApi.js +90 -3
- package/lib/api/constants.d.ts +18 -0
- package/lib/api/constants.js +18 -0
- package/lib/api/contents/attachments.d.ts +9 -0
- package/lib/api/contents/attachments.js +43 -0
- package/lib/api/contents/bridges.d.ts +22 -0
- package/lib/api/contents/bridges.js +79 -0
- package/lib/api/contents/capabilities.d.ts +11 -0
- package/lib/api/contents/capabilities.js +21 -0
- package/lib/api/contents/cloudStorage.d.ts +31 -0
- package/lib/api/contents/cloudStorage.js +89 -0
- package/lib/api/contents/dataservers.d.ts +37 -0
- package/lib/api/contents/dataservers.js +121 -0
- package/lib/api/contents/datasets.d.ts +15 -0
- package/lib/api/contents/datasets.js +45 -0
- package/lib/api/contents/datasources.d.ts +70 -0
- package/lib/api/contents/datasources.js +149 -0
- package/lib/api/contents/generated.d.ts +1070 -0
- package/lib/api/contents/index.d.ts +16 -0
- package/lib/api/contents/index.js +20 -0
- package/lib/api/contents/mcp.d.ts +46 -0
- package/lib/api/contents/mcp.js +157 -0
- package/lib/api/contents/objects.d.ts +31 -0
- package/lib/api/contents/objects.js +88 -0
- package/lib/api/contents/operations.d.ts +3 -0
- package/lib/api/contents/operations.js +19 -0
- package/lib/api/contents/runtimeMounts.d.ts +40 -0
- package/lib/api/contents/runtimeMounts.js +59 -0
- package/lib/api/contents/sandboxUid.d.ts +53 -0
- package/lib/api/contents/sandboxUid.js +78 -0
- package/lib/api/contents/sources.d.ts +19 -0
- package/lib/api/contents/sources.js +119 -0
- package/lib/api/contents/sync.d.ts +18 -0
- package/lib/api/contents/sync.js +69 -0
- package/lib/api/contents/transfers.d.ts +38 -0
- package/lib/api/contents/transfers.js +123 -0
- package/lib/api/iam/connectedAgents.d.ts +39 -0
- package/lib/api/iam/connectedAgents.js +52 -0
- package/lib/api/iam/index.d.ts +2 -1
- package/lib/api/iam/index.js +2 -1
- package/lib/api/iam/mcpAlertRules.d.ts +51 -0
- package/lib/api/iam/mcpAlertRules.js +198 -0
- package/lib/api/iam/mcpAuditSettings.d.ts +46 -0
- package/lib/api/iam/mcpAuditSettings.js +120 -0
- package/lib/api/iam/mcpPolicy.d.ts +80 -0
- package/lib/api/iam/mcpPolicy.js +132 -0
- package/lib/api/iam/organizationTeams.d.ts +13 -0
- package/lib/api/iam/organizationTeams.js +43 -0
- package/lib/api/iam/serviceAgents.d.ts +68 -0
- package/lib/api/iam/serviceAgents.js +119 -0
- package/lib/api/index.d.ts +4 -1
- package/lib/api/index.js +3 -1
- package/lib/api/mcp/activity.d.ts +37 -0
- package/lib/api/mcp/activity.js +26 -0
- package/lib/api/mcp/alerts.d.ts +25 -0
- package/lib/api/mcp/alerts.js +51 -0
- package/lib/api/mcp/audit.d.ts +29 -0
- package/lib/api/mcp/audit.js +55 -0
- package/lib/api/mcp/bindings.d.ts +18 -0
- package/lib/api/mcp/bindings.js +42 -0
- package/lib/api/mcp/forwarding.d.ts +25 -0
- package/lib/api/mcp/forwarding.js +46 -0
- package/lib/api/mcp/gateway.d.ts +16 -0
- package/lib/api/mcp/gateway.js +70 -0
- package/lib/api/mcp/generated.d.ts +22 -0
- package/lib/api/mcp/generated.js +213 -0
- package/lib/api/mcp/index.d.ts +17 -0
- package/lib/api/mcp/index.js +25 -0
- package/lib/api/mcp/observability.d.ts +125 -0
- package/lib/api/mcp/observability.js +254 -0
- package/lib/api/mcp/operations.d.ts +83 -0
- package/lib/api/mcp/operations.js +50 -0
- package/lib/api/mcp/organizations.d.ts +102 -0
- package/lib/api/mcp/organizations.js +46 -0
- package/lib/api/mcp/policy.d.ts +9 -0
- package/lib/api/mcp/policy.js +23 -0
- package/lib/api/mcp/tasks.d.ts +49 -0
- package/lib/api/mcp/tasks.js +147 -0
- package/lib/api/utils/validation.d.ts +1 -1
- package/lib/api/utils/validation.js +1 -1
- package/lib/client/auth/index.js +0 -5
- package/lib/client/auth/storage.js +0 -5
- package/lib/client/auth/strategies.js +0 -5
- package/lib/client/base.d.ts +6 -0
- package/lib/client/base.js +8 -0
- package/lib/client/index.d.ts +0 -10
- package/lib/client/index.js +2 -2
- package/lib/client/mixins/ContentsMixin.d.ts +71 -0
- package/lib/client/mixins/ContentsMixin.js +157 -0
- package/lib/client/mixins/IAMMixin.d.ts +0 -31
- package/lib/client/mixins/IAMMixin.js +0 -58
- package/lib/components/animation/AnimatedText.d.ts +1 -0
- package/lib/components/animation/AnimatedText.js +0 -4
- package/lib/components/auth/SigInAPIKey.d.ts +1 -0
- package/lib/components/auth/SigInAPIKey.js +0 -6
- package/lib/components/auth/SignIn.d.ts +1 -0
- package/lib/components/auth/SignIn.js +0 -4
- package/lib/components/auth/SignIn.stories.d.ts +2 -2
- package/lib/components/avatars/BoringAvatar.d.ts +1 -1
- package/lib/components/avatars/BoringAvatar.stories.d.ts +1 -1
- package/lib/components/avatars/DLAvatar.d.ts +1 -1
- package/lib/components/avatars/DLAvatar.js +0 -4
- package/lib/components/avatars/UserAvatar.d.ts +18 -1
- package/lib/components/avatars/UserAvatar.js +14 -14
- package/lib/components/avatars/UserProfileAvatar.d.ts +1 -1
- package/lib/components/banners/NoAutomationBanner.d.ts +1 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +10 -0
- package/lib/components/billing/BillingEntitySelect.js +0 -17
- package/lib/components/billing/index.js +0 -4
- package/lib/components/buttons/DownloadCSVButton.d.ts +1 -1
- package/lib/components/buttons/DownloadJsonButton.d.ts +1 -1
- package/lib/components/buttons/LongActionButton.d.ts +1 -0
- package/lib/components/buttons/LongActionButton.js +0 -4
- package/lib/components/buttons/UploadButton.d.ts +1 -0
- package/lib/components/buttons/UploadButton.js +0 -4
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +31 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +98 -53
- package/lib/components/collaboration/index.js +0 -4
- package/lib/components/confetti/ConfettiSuccess.d.ts +1 -1
- package/lib/components/contents/ContentSourceCard.d.ts +8 -0
- package/lib/components/contents/ContentSourceCard.js +23 -0
- package/lib/components/contents/HomeFolderObjectsBrowser.d.ts +10 -0
- package/lib/components/contents/HomeFolderObjectsBrowser.js +148 -0
- package/lib/components/contents/index.d.ts +2 -0
- package/lib/components/contents/index.js +6 -0
- package/lib/components/context/OrganizationSelect.d.ts +1 -1
- package/lib/components/display/AvatarSkeleton.d.ts +1 -1
- package/lib/components/display/BusyDots.d.ts +1 -1
- package/lib/components/display/CenteredSpinner.d.ts +1 -1
- package/lib/components/display/CodePreview.d.ts +1 -1
- package/lib/components/display/DatalayerBox.d.ts +7 -2
- package/lib/components/display/DatalayerBox.js +6 -6
- package/lib/components/display/HorizontalCenter.d.ts +1 -1
- package/lib/components/display/JupyterDialog.d.ts +1 -0
- package/lib/components/display/JupyterDialog.js +1 -7
- package/lib/components/display/Markdown.d.ts +1 -0
- package/lib/components/display/NotebookSkeleton.d.ts +1 -1
- package/lib/components/display/Placeholder.d.ts +1 -1
- package/lib/components/display/ToTopBranded.d.ts +1 -1
- package/lib/components/echarts/EChartsReact.d.ts +1 -1
- package/lib/components/flashes/FlashClosable.d.ts +1 -0
- package/lib/components/flashes/FlashClosable.js +0 -4
- package/lib/components/flashes/FlashGuest.d.ts +1 -1
- package/lib/components/flashes/FlashSurveys.d.ts +1 -1
- package/lib/components/flashes/FlashUnauthorized.d.ts +1 -0
- package/lib/components/flashes/FlashUnauthorized.js +0 -6
- package/lib/components/flashes/surveys/Survey2025_1.d.ts +1 -1
- package/lib/components/iam/ExternalTokenSilentLogin.d.ts +1 -1
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +2 -0
- package/lib/components/labels/StatusLabels.d.ts +10 -0
- package/lib/components/labels/StatusLabels.js +30 -1
- package/lib/components/labels/VisibilityLabel.d.ts +1 -1
- package/lib/components/landings/StepBlock.d.ts +1 -1
- package/lib/components/mcp/ClientBadge.d.ts +41 -0
- package/lib/components/mcp/ClientBadge.js +33 -0
- package/lib/components/mcp/McpErrorBlankslate.d.ts +21 -0
- package/lib/components/mcp/McpErrorBlankslate.js +17 -0
- package/lib/components/mcp/ScopeList.d.ts +28 -0
- package/lib/components/mcp/ScopeList.js +14 -0
- package/lib/components/mcp/index.d.ts +10 -0
- package/lib/components/mcp/index.js +18 -0
- package/lib/components/navbar/NavigationVisbilityObserver.d.ts +2 -1
- package/lib/components/navbar/SubdomainNavBar.d.ts +10 -5
- package/lib/components/navbar/SubdomainNavBar.js +2 -1
- package/lib/components/notebooks/JupyterNotebook.d.ts +1 -1
- package/lib/components/notebooks/JupyterNotebookToolbar.d.ts +1 -1
- package/lib/components/principal/PrincipalAppearance.d.ts +1 -0
- package/lib/components/principal/PrincipalAppearance.js +0 -8
- package/lib/components/principal/PrincipalAvatar.d.ts +9 -1
- package/lib/components/principal/PrincipalAvatar.js +25 -10
- package/lib/components/principal/PrincipalBadge.d.ts +1 -1
- package/lib/components/principal/PrincipalBanner.d.ts +1 -1
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +31 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +64 -33
- package/lib/components/principal/PrincipalHoverCard.d.ts +31 -0
- package/lib/components/principal/PrincipalHoverCard.js +52 -0
- package/lib/components/principal/PrincipalSwitcherMenu.d.ts +1 -0
- package/lib/components/principal/PrincipalSwitcherMenu.js +7 -15
- package/lib/components/principal/index.d.ts +2 -1
- package/lib/components/principal/index.js +2 -1
- package/lib/components/progress/ConsumptionBar.d.ts +1 -0
- package/lib/components/progress/ConsumptionBar.js +0 -4
- package/lib/components/progress/ProgressRing.d.ts +1 -0
- package/lib/components/progress/SpinnerBar.d.ts +1 -1
- package/lib/components/progress/Timer.d.ts +1 -0
- package/lib/components/progress/Timer.js +0 -4
- package/lib/components/screencapture/ScreencaptureButton.d.ts +1 -1
- package/lib/components/sharing/ShareAccessComponent.d.ts +15 -1
- package/lib/components/sharing/ShareAccessComponent.js +36 -23
- package/lib/components/sharing/SharingEditor.d.ts +17 -0
- package/lib/components/sharing/SharingEditor.js +0 -24
- package/lib/components/sparklines/Sparklines.js +3 -4
- package/lib/components/sparklines/index.js +0 -4
- package/lib/components/storage/ContentsBrowser.d.ts +25 -1
- package/lib/components/storage/ContentsBrowser.js +145 -52
- package/lib/components/storage/ContentsBrowserMock.d.ts +3 -0
- package/lib/components/storage/ContentsBrowserMock.js +75 -0
- package/lib/components/storage/ContentsItems.d.ts +2 -1
- package/lib/components/storage/ContentsItems.js +0 -4
- package/lib/components/storage/ContentsTable.d.ts +50 -0
- package/lib/components/storage/ContentsTable.js +134 -0
- package/lib/components/storage/HomeFolderDrive.d.ts +71 -0
- package/lib/components/storage/HomeFolderDrive.js +248 -0
- package/lib/components/storage/index.d.ts +2 -0
- package/lib/components/storage/index.js +2 -0
- package/lib/components/students/StudentItemStatus.d.ts +1 -1
- package/lib/components/students/StudentResultCircle.d.ts +1 -1
- package/lib/components/subnav/SubNav.d.ts +5 -5
- package/lib/components/subnav/SubNav.js +11 -9
- package/lib/components/tables/DataTable.d.ts +1 -1
- package/lib/components/text-reveal/TextRevealAnimation.d.ts +2 -2
- package/lib/components/text-reveal/useTextRevealAnimationLines.d.ts +1 -1
- package/lib/components/time/LiveRelativeTime.d.ts +1 -0
- package/lib/components/time/LiveRelativeTime.js +0 -8
- package/lib/components/time/index.js +0 -4
- package/lib/components/timeline/Timeline.d.ts +1 -1
- package/lib/components/timeline/index.js +0 -4
- package/lib/components/users/PeerIndicator.d.ts +1 -0
- package/lib/components/users/PeerIndicator.js +0 -4
- package/lib/config/Configuration.d.ts +15 -17
- package/lib/config/Configuration.js +7 -0
- package/lib/hooks/index.d.ts +2 -0
- package/lib/hooks/index.js +2 -0
- package/lib/hooks/layouts/LayoutBackdrop.d.ts +1 -1
- package/lib/hooks/layouts/LayoutScreencapture.d.ts +1 -1
- package/lib/hooks/useBackdrop.d.ts +1 -1
- package/lib/hooks/useBackdropJupyterLab.d.ts +3 -2
- package/lib/hooks/useBackdropJupyterLab.js +0 -4
- package/lib/hooks/useCache.d.ts +310 -105
- package/lib/hooks/useCache.js +142 -355
- package/lib/hooks/useContainsFocus.d.ts +1 -1
- package/lib/hooks/useContents.d.ts +313 -0
- package/lib/hooks/useContents.js +964 -0
- package/lib/hooks/useFocusTrap.d.ts +4 -4
- package/lib/hooks/useFocusTrap.js +1 -1
- package/lib/hooks/useMcp.d.ts +229 -0
- package/lib/hooks/useMcp.js +656 -0
- package/lib/hooks/useMobile.js +0 -5
- package/lib/hooks/useProjectStore.d.ts +3 -3
- package/lib/hooks/useProjectStore.js +4 -4
- package/lib/hooks/useRef.d.ts +1 -1
- package/lib/hooks/useRef.js +3 -0
- package/lib/hooks/useScreencapture.d.ts +2 -1
- package/lib/hooks/useScreencapture.js +0 -4
- package/lib/hooks/useToast.js +0 -4
- package/lib/hooks/useUser.js +42 -0
- package/lib/hooks/useVisibilityObserver.d.ts +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +3 -1
- package/lib/mocks/components/FlashMock.d.ts +1 -1
- package/lib/mocks/views/ActionMenuMock.d.ts +1 -1
- package/lib/mocks/views/ChartMock.d.ts +1 -1
- package/lib/mocks/views/DashboardMock.d.ts +1 -1
- package/lib/mocks/views/FormMock.d.ts +1 -1
- package/lib/mocks/views/TableMock.d.ts +1 -1
- package/lib/mocks/views/WipMock.d.ts +1 -1
- package/lib/models/Credits.d.ts +16 -0
- package/lib/models/Credits.js +22 -0
- package/lib/models/McpAuditEvent.d.ts +52 -0
- package/lib/models/McpAuditEvent.js +5 -0
- package/lib/models/McpBinding.d.ts +51 -0
- package/lib/models/McpBinding.js +5 -0
- package/lib/models/McpPolicy.d.ts +77 -0
- package/lib/models/McpPolicy.js +5 -0
- package/lib/models/McpTask.d.ts +94 -0
- package/lib/models/McpTask.js +7 -0
- package/lib/models/StartedBy.d.ts +57 -0
- package/lib/models/StartedBy.js +81 -0
- package/lib/models/UserDTO.js +4 -2
- package/lib/models/contents/__fixtures__/solr-codec.json +57 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +66 -0
- package/lib/models/contents/fieldCase.d.ts +8 -0
- package/lib/models/contents/fieldCase.js +37 -0
- package/lib/models/contents/index.d.ts +2 -0
- package/lib/models/contents/index.js +6 -0
- package/lib/models/contents/permissions.d.ts +16 -0
- package/lib/models/contents/permissions.js +34 -0
- package/lib/models/index.d.ts +5 -1
- package/lib/models/index.js +5 -1
- package/lib/state/substates/CoreState.d.ts +15 -7
- package/lib/state/substates/CoreState.js +18 -14
- package/lib/state/substates/IAMState.d.ts +1 -1
- package/lib/state/substates/IAMState.js +5 -5
- package/lib/state/substates/ProfileState.js +0 -4
- package/lib/state/substates/index.d.ts +0 -1
- package/lib/state/substates/index.js +0 -1
- package/lib/utils/Jwt.d.ts +26 -0
- package/lib/utils/Jwt.js +37 -0
- package/lib/utils/WithSuspense.d.ts +1 -1
- package/lib/views/api-keys/APIKeyEdit.d.ts +1 -1
- package/lib/views/api-keys/APIKeyNew.d.ts +1 -1
- package/lib/views/api-keys/APIKeys.d.ts +1 -1
- package/lib/views/api-keys/APIKeys.js +30 -4
- package/lib/views/api-keys/APIKeysStandalone.d.ts +5 -1
- package/lib/views/api-keys/APIKeysStandalone.js +2 -2
- package/lib/views/datasources/DatasourceDetail.d.ts +12 -5
- package/lib/views/datasources/DatasourceDetail.js +80 -110
- package/lib/views/datasources/DatasourceNew.d.ts +14 -8
- package/lib/views/datasources/DatasourceNew.js +129 -118
- package/lib/views/datasources/Datasources.d.ts +39 -7
- package/lib/views/datasources/Datasources.js +95 -40
- package/lib/views/datasources/DatasourcesMock.d.ts +3 -0
- package/lib/views/datasources/DatasourcesMock.js +57 -0
- package/lib/views/iam/SignInSimple.d.ts +12 -0
- package/lib/views/iam/SignInSimple.js +4 -4
- package/lib/views/index.d.ts +1 -0
- package/lib/views/index.js +1 -0
- package/lib/views/mcp/AlertDestinations.d.ts +34 -0
- package/lib/views/mcp/AlertDestinations.js +75 -0
- package/lib/views/mcp/AlertRules.d.ts +32 -0
- package/lib/views/mcp/AlertRules.js +245 -0
- package/lib/views/mcp/AuditLog.d.ts +42 -0
- package/lib/views/mcp/AuditLog.js +144 -0
- package/lib/views/mcp/ConnectedAgents.d.ts +34 -0
- package/lib/views/mcp/ConnectedAgents.js +100 -0
- package/lib/views/mcp/EnterpriseConsole.d.ts +74 -0
- package/lib/views/mcp/EnterpriseConsole.js +173 -0
- package/lib/views/mcp/McpDashboard.d.ts +50 -0
- package/lib/views/mcp/McpDashboard.js +347 -0
- package/lib/views/mcp/McpHome.d.ts +92 -0
- package/lib/views/mcp/McpHome.js +153 -0
- package/lib/views/mcp/McpObservability.d.ts +50 -0
- package/lib/views/mcp/McpObservability.js +150 -0
- package/lib/views/mcp/OrganizationPolicy.d.ts +45 -0
- package/lib/views/mcp/OrganizationPolicy.js +107 -0
- package/lib/views/mcp/OrganizationUsage.d.ts +69 -0
- package/lib/views/mcp/OrganizationUsage.js +113 -0
- package/lib/views/mcp/PersonalPolicy.d.ts +54 -0
- package/lib/views/mcp/PersonalPolicy.js +125 -0
- package/lib/views/mcp/Policies.d.ts +53 -0
- package/lib/views/mcp/Policies.js +210 -0
- package/lib/views/mcp/PolicyForm.d.ts +67 -0
- package/lib/views/mcp/PolicyForm.js +91 -0
- package/lib/views/mcp/PolicyHistory.d.ts +45 -0
- package/lib/views/mcp/PolicyHistory.js +62 -0
- package/lib/views/mcp/ServiceAgents.d.ts +46 -0
- package/lib/views/mcp/ServiceAgents.js +194 -0
- package/lib/views/mcp/TeamPolicies.d.ts +33 -0
- package/lib/views/mcp/TeamPolicies.js +98 -0
- package/lib/views/mcp/format.d.ts +25 -0
- package/lib/views/mcp/format.js +77 -0
- package/lib/views/mcp/index.d.ts +29 -0
- package/lib/views/mcp/index.js +37 -0
- package/lib/views/mcp/types.d.ts +66 -0
- package/lib/views/mcp/types.js +5 -0
- package/lib/views/secrets/SecretEdit.d.ts +5 -1
- package/lib/views/secrets/SecretEdit.js +2 -2
- package/lib/views/secrets/SecretNew.d.ts +11 -1
- package/lib/views/secrets/SecretNew.js +2 -2
- package/lib/views/secrets/Secrets.d.ts +12 -1
- package/lib/views/secrets/Secrets.js +2 -2
- package/package.json +28 -24
- package/scripts/generate-contents-types.py +169 -0
- package/scripts/generate-mcp-types.py +233 -0
- package/lib/api/iam/datasources.d.ts +0 -86
- package/lib/api/iam/datasources.js +0 -185
- package/lib/components/toolbars/index.d.ts +0 -1
- package/lib/models/Datasource.d.ts +0 -181
- package/lib/models/Datasource.js +0 -154
- package/lib/state/substates/DatasourceState.d.ts +0 -11
- package/lib/state/substates/DatasourceState.js +0 -16
- /package/lib/{components/toolbars/index.js → api/contents/generated.js} +0 -0
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
2
|
import { ActionMenu, Box, Button, Label, Text, ThemeProvider, } from '@primer/react';
|
|
7
3
|
import { useNavigate } from '../../hooks/index.js';
|
|
8
4
|
import { PrincipalAvatar } from './PrincipalAvatar.js';
|
|
@@ -80,8 +76,30 @@ export function buildPrincipalProfilePath({ kind, uid, handle, accountHandle, is
|
|
|
80
76
|
}
|
|
81
77
|
return null;
|
|
82
78
|
}
|
|
83
|
-
|
|
79
|
+
/**
|
|
80
|
+
* The card of a principal, on its own — avatar, identity, and the buttons.
|
|
81
|
+
*
|
|
82
|
+
* The body every surface that shows a principal shares: the click overlay
|
|
83
|
+
* anchored on a name ({@link PrincipalDetailsOverlay}) and the hover card
|
|
84
|
+
* anchored on an avatar ({@link PrincipalHoverCard}) both render this, so
|
|
85
|
+
* the two never drift.
|
|
86
|
+
*/
|
|
87
|
+
export function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, organizationName, memberCount, isPublic, isAdmin = false, onNavigate, }) {
|
|
84
88
|
const navigate = useNavigate();
|
|
89
|
+
// Where a profile or organization link goes: the router of this subtree,
|
|
90
|
+
// unless the caller knows of one that can actually serve it — see
|
|
91
|
+
// `onNavigate`. Either way it is a navigation, never a page load.
|
|
92
|
+
const go = (path) => {
|
|
93
|
+
if (!path) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (onNavigate) {
|
|
97
|
+
onNavigate(path);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
navigate(path);
|
|
101
|
+
}
|
|
102
|
+
};
|
|
85
103
|
const normalizedDisplayName = normalize(displayName) ||
|
|
86
104
|
normalize(handle) ||
|
|
87
105
|
normalize(uid) ||
|
|
@@ -117,6 +135,46 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
|
|
|
117
135
|
const organizationPath = teamOrganizationHandle
|
|
118
136
|
? `/${teamOrganizationHandle.replace(/^@+/, '')}`
|
|
119
137
|
: '';
|
|
138
|
+
return (_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, avatarIcon: avatarIcon, alt: normalizedDisplayName, size: 40,
|
|
139
|
+
// The card sets the avatar on its own ground, the same colour
|
|
140
|
+
// the avatar itself is on: without an edge of its own it has
|
|
141
|
+
// no visible shape at all. Round, and ringed.
|
|
142
|
+
square: false, ring: true }), _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
|
|
143
|
+
? ` · @${teamOrganizationHandle.replace(/^@+/, '')}`
|
|
144
|
+
: ''] })) : null) : resolvedHandle ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { sx: {
|
|
145
|
+
display: 'grid',
|
|
146
|
+
gridTemplateColumns: '110px 1fr',
|
|
147
|
+
gap: 1,
|
|
148
|
+
alignItems: 'baseline',
|
|
149
|
+
}, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Kind" }), _jsx(Text, { sx: { fontSize: 1 }, children: kind }), resolvedHandle && kind !== 'team' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontSize: 1 }, children: displayHandleText(resolvedHandle) })] })) : null, normalizedUid ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedUid })] })) : null, kind === 'personal' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "First name" }), _jsx(Text, { sx: { fontSize: 1 }, children: firstName || 'N/A' }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Last name" }), _jsx(Text, { sx: { fontSize: 1 }, children: lastName || 'N/A' }), email ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontSize: 1 }, children: email })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
|
|
150
|
+
justifySelf: 'start',
|
|
151
|
+
width: 'fit-content',
|
|
152
|
+
maxWidth: '100%',
|
|
153
|
+
overflow: 'hidden',
|
|
154
|
+
textOverflow: 'ellipsis',
|
|
155
|
+
whiteSpace: 'nowrap',
|
|
156
|
+
}, 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
|
|
157
|
+
? `${normalizedOrganizationName} (${displayHandleText(teamOrganizationHandle)})`
|
|
158
|
+
: 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: {
|
|
159
|
+
justifySelf: 'start',
|
|
160
|
+
width: 'fit-content',
|
|
161
|
+
maxWidth: '100%',
|
|
162
|
+
overflow: 'hidden',
|
|
163
|
+
textOverflow: 'ellipsis',
|
|
164
|
+
whiteSpace: 'nowrap',
|
|
165
|
+
}, children: normalizedOrigin })] }))] }), _jsxs(Box, { sx: { display: 'flex', justifyContent: 'flex-end', gap: 2 }, children: [kind === 'team' && organizationPath ? (_jsx(Button, { size: "small", variant: "invisible", onClick: () => go(organizationPath), children: "View Organization" })) : null, _jsx(Button, { size: "small", onClick: () => go(targetPath), disabled: !targetPath, children: "View Profile" })] })] }));
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* A principal's details, shown from a click on their name.
|
|
169
|
+
*
|
|
170
|
+
* The name is the anchor; clicking it opens the shared
|
|
171
|
+
* {@link PrincipalDetailsCard}.
|
|
172
|
+
*/
|
|
173
|
+
export function PrincipalDetailsOverlay(props) {
|
|
174
|
+
const normalizedDisplayName = normalize(props.displayName) ||
|
|
175
|
+
normalize(props.handle) ||
|
|
176
|
+
normalize(props.uid) ||
|
|
177
|
+
'Principal';
|
|
120
178
|
return (_jsx(ThemeProvider, { children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Box, { as: "button", type: "button", sx: {
|
|
121
179
|
fontWeight: 'semibold',
|
|
122
180
|
color: 'accent.fg',
|
|
@@ -129,33 +187,6 @@ export function PrincipalDetailsOverlay({ kind, uid, displayName, name, descript
|
|
|
129
187
|
':hover': {
|
|
130
188
|
textDecoration: 'underline',
|
|
131
189
|
},
|
|
132
|
-
}, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children:
|
|
133
|
-
? ` · @${teamOrganizationHandle.replace(/^@+/, '')}`
|
|
134
|
-
: ''] })) : null) : resolvedHandle ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: displayHandleText(resolvedHandle) })) : null] })] }), _jsxs(Box, { sx: {
|
|
135
|
-
display: 'grid',
|
|
136
|
-
gridTemplateColumns: '110px 1fr',
|
|
137
|
-
gap: 1,
|
|
138
|
-
alignItems: 'baseline',
|
|
139
|
-
}, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Kind" }), _jsx(Text, { sx: { fontSize: 1 }, children: kind }), resolvedHandle && kind !== 'team' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Handle" }), _jsx(Text, { sx: { fontSize: 1 }, children: displayHandleText(resolvedHandle) })] })) : null, normalizedUid ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "UID" }), _jsx(Text, { sx: { fontSize: 1 }, children: normalizedUid })] })) : null, kind === 'personal' ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "First name" }), _jsx(Text, { sx: { fontSize: 1 }, children: firstName || 'N/A' }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Last name" }), _jsx(Text, { sx: { fontSize: 1 }, children: lastName || 'N/A' }), email ? (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Email" }), _jsx(Text, { sx: { fontSize: 1 }, children: email })] })) : null, _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Origin" }), _jsx(Label, { size: "small", variant: "secondary", title: normalizedOrigin, sx: {
|
|
140
|
-
justifySelf: 'start',
|
|
141
|
-
width: 'fit-content',
|
|
142
|
-
maxWidth: '100%',
|
|
143
|
-
overflow: 'hidden',
|
|
144
|
-
textOverflow: 'ellipsis',
|
|
145
|
-
whiteSpace: 'nowrap',
|
|
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: {
|
|
149
|
-
justifySelf: 'start',
|
|
150
|
-
width: 'fit-content',
|
|
151
|
-
maxWidth: '100%',
|
|
152
|
-
overflow: 'hidden',
|
|
153
|
-
textOverflow: 'ellipsis',
|
|
154
|
-
whiteSpace: 'nowrap',
|
|
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" })] })] }) })] }) }));
|
|
190
|
+
}, children: normalizedDisplayName }) }), _jsx(ActionMenu.Overlay, { width: "large", children: _jsx(PrincipalDetailsCard, { ...props }) })] }) }));
|
|
160
191
|
}
|
|
161
192
|
export default PrincipalDetailsOverlay;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A principal's details, shown from a hover on their avatar.
|
|
3
|
+
*
|
|
4
|
+
* The same {@link PrincipalDetailsCard} the click overlay uses, anchored on
|
|
5
|
+
* an avatar and opened by pointing at it — for the faces of a shared
|
|
6
|
+
* document, where there is no name to click, only a stack of avatars.
|
|
7
|
+
*
|
|
8
|
+
* The card stays open while the pointer is on the avatar OR on the card, so
|
|
9
|
+
* the "View Profile" button inside it can be reached: leaving the avatar
|
|
10
|
+
* starts a short countdown that entering the card cancels.
|
|
11
|
+
*
|
|
12
|
+
* The anchor forwards the class an `AvatarStack` clones onto its children
|
|
13
|
+
* (`pc-AvatarItem`, which sizes and overlaps the faces) so a hover card can
|
|
14
|
+
* wrap a face without breaking the stack.
|
|
15
|
+
*
|
|
16
|
+
* @module components/principal/PrincipalHoverCard
|
|
17
|
+
*/
|
|
18
|
+
import type { JSX } from 'react';
|
|
19
|
+
import type { ReactNode } from 'react';
|
|
20
|
+
import { type PrincipalDetailsOverlayProps } from './PrincipalDetailsOverlay';
|
|
21
|
+
export type PrincipalHoverCardProps = PrincipalDetailsOverlayProps & {
|
|
22
|
+
/** The avatar the card hangs off — the anchor. */
|
|
23
|
+
children: ReactNode;
|
|
24
|
+
/**
|
|
25
|
+
* Cloned in by `AvatarStack` onto each child; forwarded to the anchor so
|
|
26
|
+
* the face keeps its size, overlap and mask inside the stack.
|
|
27
|
+
*/
|
|
28
|
+
className?: string;
|
|
29
|
+
};
|
|
30
|
+
export declare function PrincipalHoverCard({ children, className, ...principal }: PrincipalHoverCardProps): JSX.Element;
|
|
31
|
+
export default PrincipalHoverCard;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
|
+
import { AnchoredOverlay, Box, ThemeProvider } from '@primer/react';
|
|
4
|
+
import { PrincipalDetailsCard, } from './PrincipalDetailsOverlay.js';
|
|
5
|
+
/** How long the card lingers after the pointer leaves, to let it be entered. */
|
|
6
|
+
const HIDE_DELAY_MS = 200;
|
|
7
|
+
export function PrincipalHoverCard({ children, className, ...principal }) {
|
|
8
|
+
const [open, setOpen] = useState(false);
|
|
9
|
+
const hideTimeout = useRef(undefined);
|
|
10
|
+
const cancelHide = useCallback(() => {
|
|
11
|
+
if (hideTimeout.current !== undefined) {
|
|
12
|
+
window.clearTimeout(hideTimeout.current);
|
|
13
|
+
hideTimeout.current = undefined;
|
|
14
|
+
}
|
|
15
|
+
}, []);
|
|
16
|
+
const show = useCallback(() => {
|
|
17
|
+
cancelHide();
|
|
18
|
+
setOpen(true);
|
|
19
|
+
}, [cancelHide]);
|
|
20
|
+
const hide = useCallback(() => {
|
|
21
|
+
cancelHide();
|
|
22
|
+
hideTimeout.current = window.setTimeout(() => {
|
|
23
|
+
setOpen(false);
|
|
24
|
+
hideTimeout.current = undefined;
|
|
25
|
+
}, HIDE_DELAY_MS);
|
|
26
|
+
}, [cancelHide]);
|
|
27
|
+
useEffect(() => cancelHide, [cancelHide]);
|
|
28
|
+
return (_jsx(AnchoredOverlay, { open: open, onOpen: show, onClose: () => setOpen(false), side: "outside-bottom", align: "center", displayCloseButton: false, focusTrapSettings: { disabled: true }, focusZoneSettings: { disabled: true }, overlayProps: {
|
|
29
|
+
role: 'dialog',
|
|
30
|
+
onMouseEnter: show,
|
|
31
|
+
onMouseLeave: hide,
|
|
32
|
+
preventFocusOnOpen: true,
|
|
33
|
+
}, renderAnchor: anchorProps => (_jsx(Box, { ...anchorProps, className: [className, anchorProps.className]
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
.join(' '), onMouseEnter: show, onMouseLeave: hide, onFocus: show, onBlur: hide, sx: {
|
|
36
|
+
display: 'flex',
|
|
37
|
+
alignItems: 'center',
|
|
38
|
+
justifyContent: 'center',
|
|
39
|
+
cursor: 'pointer',
|
|
40
|
+
/*
|
|
41
|
+
* Round, like the face it holds.
|
|
42
|
+
*
|
|
43
|
+
* This box stands between the stack and the avatar — it is the
|
|
44
|
+
* element `AvatarStack` sizes and clips as one of its items — so a
|
|
45
|
+
* square one clipped a round avatar into a square. It takes the
|
|
46
|
+
* shape of what it wraps.
|
|
47
|
+
*/
|
|
48
|
+
borderRadius: '50%',
|
|
49
|
+
overflow: 'hidden',
|
|
50
|
+
}, children: children })), children: _jsx(ThemeProvider, { children: _jsx(PrincipalDetailsCard, { ...principal }) }) }));
|
|
51
|
+
}
|
|
52
|
+
export default PrincipalHoverCard;
|
|
@@ -1,19 +1,17 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
7
|
-
import { ActionList, ActionMenu, Box, Button,
|
|
3
|
+
import { ActionList, ActionMenu, Box, Button, Text, ThemeProvider, } from '@primer/react';
|
|
8
4
|
import { OrganizationIcon, PeopleIcon, PersonIcon, TriangleDownIcon, } from '@primer/octicons-react';
|
|
9
5
|
import { useCache, useAuthorization } from '../../hooks/index.js';
|
|
10
6
|
import { useCoreStore } from '../../state/index.js';
|
|
11
7
|
import { useIAMStore } from '../../state/substates/index.js';
|
|
8
|
+
import { UserAvatar } from '../avatars/index.js';
|
|
12
9
|
import { memberships as fetchMemberships } from '../../api/iam/profile.js';
|
|
13
10
|
import { usePrincipalStore } from '../../hooks/usePrincipalStore.js';
|
|
14
11
|
import { useBillingEntityStore } from '../../hooks/useBillingEntityStore.js';
|
|
15
12
|
import { useSelectedPrincipal } from '../../hooks/useSelectedPrincipal.js';
|
|
16
13
|
import { DisplayHandle, displayHandleText } from '../display/DisplayHandle.js';
|
|
14
|
+
import { AdminLabel } from '../labels/StatusLabels.js';
|
|
17
15
|
function truncatePrincipalLabel(label, maxChars) {
|
|
18
16
|
const trimmed = (label || '').trim();
|
|
19
17
|
if (!trimmed) {
|
|
@@ -200,12 +198,6 @@ export function PrincipalSwitcherMenu({ maxLabelChars = 48, fullWidth = true, sh
|
|
|
200
198
|
color: 'accent.fg',
|
|
201
199
|
fontWeight: 'semibold',
|
|
202
200
|
};
|
|
203
|
-
const adminBadgeSx = {
|
|
204
|
-
bg: 'attention.subtle',
|
|
205
|
-
color: 'attention.fg',
|
|
206
|
-
textTransform: 'lowercase',
|
|
207
|
-
lineHeight: 1.2,
|
|
208
|
-
};
|
|
209
201
|
return (_jsx(ThemeProvider, { children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: showClosedBorder ? (_jsxs(Box, { as: "button", type: "button", "aria-label": "Switch principal", sx: {
|
|
210
202
|
width: fullWidth ? '100%' : 'auto',
|
|
211
203
|
boxSizing: 'border-box',
|
|
@@ -250,7 +242,7 @@ export function PrincipalSwitcherMenu({ maxLabelChars = 48, fullWidth = true, sh
|
|
|
250
242
|
flexShrink: 0,
|
|
251
243
|
display: 'inline-flex',
|
|
252
244
|
alignItems: 'center',
|
|
253
|
-
}, children: _jsx(
|
|
245
|
+
}, children: _jsx(AdminLabel, {}) })) : null, _jsx(Box, { sx: {
|
|
254
246
|
display: 'inline-flex',
|
|
255
247
|
alignItems: 'center',
|
|
256
248
|
color: 'fg.muted',
|
|
@@ -277,14 +269,14 @@ export function PrincipalSwitcherMenu({ maxLabelChars = 48, fullWidth = true, sh
|
|
|
277
269
|
}, children: _jsx(Text, { sx: {
|
|
278
270
|
color: 'accent.fg',
|
|
279
271
|
fontWeight: 'semibold',
|
|
280
|
-
}, children: selectedPrincipalLabelClosed }) }), isPlatformAdmin && isCurrentUserPrincipal ? (_jsx(
|
|
272
|
+
}, children: selectedPrincipalLabelClosed }) }), isPlatformAdmin && isCurrentUserPrincipal ? (_jsx(AdminLabel, {})) : 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
273
|
if (isCurrentUserPrincipal) {
|
|
282
274
|
return;
|
|
283
275
|
}
|
|
284
276
|
if (personalUid && personalHandle) {
|
|
285
277
|
selectUser(personalUid, personalHandle);
|
|
286
278
|
}
|
|
287
|
-
}, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(
|
|
279
|
+
}, children: [_jsx(ActionList.LeadingVisual, { children: _jsx(UserAvatar, { avatarUrl: user?.avatarUrl, avatarIcon: user?.avatarIcon, size: 16, square: false, ring: true }) }), _jsxs(Box, { as: "span", sx: {
|
|
288
280
|
display: 'block',
|
|
289
281
|
minWidth: 0,
|
|
290
282
|
overflow: 'hidden',
|
|
@@ -293,7 +285,7 @@ export function PrincipalSwitcherMenu({ maxLabelChars = 48, fullWidth = true, sh
|
|
|
293
285
|
}, children: [String(user?.friendlyName ||
|
|
294
286
|
user?.displayName ||
|
|
295
287
|
personalHandle ||
|
|
296
|
-
'Me').trim(), _jsxs(Box, { as: "span", sx: { color: 'fg.muted' }, children: [' ', "\u00B7 ", _jsx(DisplayHandle, { handle: personalHandle || 'me' })] })] }), isPlatformAdmin ? (_jsx(ActionList.TrailingVisual, { children: _jsx(
|
|
288
|
+
'Me').trim(), _jsxs(Box, { as: "span", sx: { color: 'fg.muted' }, children: [' ', "\u00B7 ", _jsx(DisplayHandle, { handle: personalHandle || 'me' })] })] }), isPlatformAdmin ? (_jsx(ActionList.TrailingVisual, { children: _jsx(AdminLabel, {}) })) : null] })] }), _jsxs(ActionList.Group, { children: [_jsx(ActionList.GroupHeading, { children: "Organizations" }), organizations.length === 0 ? (_jsx(ActionList.Item, { disabled: true, children: "No organizations" })) : (organizations.map((organization) => {
|
|
297
289
|
const organizationUid = getOrganizationUid(organization);
|
|
298
290
|
const isCurrentOrganizationPrincipal = selectedPrincipalKind === 'organization' &&
|
|
299
291
|
selectedPrincipalUid === organizationUid;
|
|
@@ -3,6 +3,7 @@ export * from './PrincipalAvatar';
|
|
|
3
3
|
export * from './PrincipalAppearance';
|
|
4
4
|
export * from './PrincipalBadge';
|
|
5
5
|
export * from './PrincipalBanner';
|
|
6
|
-
export { buildPrincipalProfilePath, PrincipalDetailsOverlay, } from './PrincipalDetailsOverlay';
|
|
6
|
+
export { buildPrincipalProfilePath, PrincipalDetailsCard, PrincipalDetailsOverlay, } from './PrincipalDetailsOverlay';
|
|
7
7
|
export type { PrincipalDetailsOverlayProps } from './PrincipalDetailsOverlay';
|
|
8
|
+
export { PrincipalHoverCard, type PrincipalHoverCardProps, } from './PrincipalHoverCard';
|
|
8
9
|
export * from './PrincipalSwitcherMenu';
|
|
@@ -7,5 +7,6 @@ export * from './PrincipalAvatar.js';
|
|
|
7
7
|
export * from './PrincipalAppearance.js';
|
|
8
8
|
export * from './PrincipalBadge.js';
|
|
9
9
|
export * from './PrincipalBanner.js';
|
|
10
|
-
export { buildPrincipalProfilePath, PrincipalDetailsOverlay, } from './PrincipalDetailsOverlay.js';
|
|
10
|
+
export { buildPrincipalProfilePath, PrincipalDetailsCard, PrincipalDetailsOverlay, } from './PrincipalDetailsOverlay.js';
|
|
11
|
+
export { PrincipalHoverCard, } from './PrincipalHoverCard.js';
|
|
11
12
|
export * from './PrincipalSwitcherMenu.js';
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
7
3
|
import { useInterval } from 'usehooks-ts';
|
|
8
4
|
import { ProgressBar, Tooltip, Button } from '@primer/react';
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const SpinnerBar: () => import("react
|
|
1
|
+
export declare const SpinnerBar: () => import("react").JSX.Element;
|
|
2
2
|
export default SpinnerBar;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { PropsWithChildren } from 'react';
|
|
2
|
-
export declare const ScreencaptureButton: (props: PropsWithChildren) => import("react
|
|
2
|
+
export declare const ScreencaptureButton: (props: PropsWithChildren) => import("react").JSX.Element;
|
|
3
3
|
export default ScreencaptureButton;
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
1
2
|
export type ItemAccessLevel = 'view' | 'update' | 'execute';
|
|
2
3
|
type PrincipalKind = 'personal' | 'team' | 'organization';
|
|
4
|
+
type SharingLevelPayload = {
|
|
5
|
+
userUids?: string[];
|
|
6
|
+
teamUids?: string[];
|
|
7
|
+
organizationUids?: string[];
|
|
8
|
+
};
|
|
9
|
+
type SharingPayload = {
|
|
10
|
+
access?: Partial<Record<ItemAccessLevel, SharingLevelPayload>>;
|
|
11
|
+
};
|
|
12
|
+
export type ShareAccessTransport = {
|
|
13
|
+
load: () => Promise<Record<string, any>>;
|
|
14
|
+
save: (sharing: SharingPayload) => Promise<void>;
|
|
15
|
+
};
|
|
3
16
|
export type ShareAccessComponentProps = {
|
|
4
17
|
isOpen: boolean;
|
|
5
18
|
requestUrl?: string;
|
|
19
|
+
transport?: ShareAccessTransport;
|
|
6
20
|
resourceLabel: string;
|
|
7
21
|
resourceName?: string;
|
|
8
22
|
resourceDescription?: string;
|
|
@@ -13,7 +27,7 @@ export type ShareAccessComponentProps = {
|
|
|
13
27
|
displayMode?: 'dialog' | 'inline';
|
|
14
28
|
onClose: () => void;
|
|
15
29
|
};
|
|
16
|
-
export declare function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded, onSharingAccessRestrictedChange, defaultAccessLevel, principalKinds, displayMode, onClose, }: ShareAccessComponentProps): JSX.Element | null;
|
|
30
|
+
export declare function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded, onSharingAccessRestrictedChange, defaultAccessLevel, principalKinds, displayMode, onClose, }: ShareAccessComponentProps): JSX.Element | null;
|
|
17
31
|
export default ShareAccessComponent;
|
|
18
32
|
export declare const ShareAccessDialog: typeof ShareAccessComponent;
|
|
19
33
|
export type ShareAccessDialogProps = ShareAccessComponentProps;
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
7
3
|
import { ChevronDownIcon, ChevronUpIcon, KeyIcon, PersonIcon, OrganizationIcon, PeopleIcon, } from '@primer/octicons-react';
|
|
8
4
|
import { Box } from '@datalayer/primer-addons';
|
|
@@ -382,7 +378,7 @@ function AccessPrincipalRow({ entry, cache, showAvatarSkeleton = false, isPlatfo
|
|
|
382
378
|
// ---------------------------------------------------------------------------
|
|
383
379
|
// Main component.
|
|
384
380
|
// ---------------------------------------------------------------------------
|
|
385
|
-
export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded = false, onSharingAccessRestrictedChange, defaultAccessLevel = 'view', principalKinds = DEFAULT_PRINCIPAL_KINDS, displayMode = 'dialog', onClose, }) {
|
|
381
|
+
export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded = false, onSharingAccessRestrictedChange, defaultAccessLevel = 'view', principalKinds = DEFAULT_PRINCIPAL_KINDS, displayMode = 'dialog', onClose, }) {
|
|
386
382
|
void _resourceDescription;
|
|
387
383
|
const { token, user } = useIAMStore();
|
|
388
384
|
const { configuration } = useCoreStore();
|
|
@@ -432,7 +428,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
432
428
|
onSharingAccessRestrictedChange,
|
|
433
429
|
]);
|
|
434
430
|
// ----- Derived -----
|
|
435
|
-
const canRequest = Boolean(
|
|
431
|
+
const canRequest = Boolean(token && (requestUrl || transport));
|
|
436
432
|
const canSearchPrincipals = Boolean(configuration?.iamUrl && token);
|
|
437
433
|
const iamUrl = configuration?.iamUrl;
|
|
438
434
|
const principalKindsSet = useMemo(() => new Set(principalKinds), [principalKinds]);
|
|
@@ -492,7 +488,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
492
488
|
userHydrationMissesRef.current = new Set();
|
|
493
489
|
return;
|
|
494
490
|
}
|
|
495
|
-
if (!canRequest
|
|
491
|
+
if (!canRequest) {
|
|
496
492
|
setIsLoading(false);
|
|
497
493
|
setIsSharingAccessConfirmed(false);
|
|
498
494
|
return;
|
|
@@ -507,14 +503,18 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
507
503
|
setIsSharingAccessConfirmed(false);
|
|
508
504
|
setSharingAccessMessage(null);
|
|
509
505
|
try {
|
|
510
|
-
const response =
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
506
|
+
const response = transport
|
|
507
|
+
? null
|
|
508
|
+
: await fetch(requestUrl, {
|
|
509
|
+
method: 'GET',
|
|
510
|
+
headers: {
|
|
511
|
+
'Content-Type': 'application/json',
|
|
512
|
+
Authorization: `Bearer ${token}`,
|
|
513
|
+
},
|
|
514
|
+
});
|
|
515
|
+
const payload = transport
|
|
516
|
+
? await transport.load()
|
|
517
|
+
: await response.json();
|
|
518
518
|
const message = payload?.detail ||
|
|
519
519
|
payload?.message ||
|
|
520
520
|
`Unable to load ${resourceLabel.toLowerCase()} sharing.`;
|
|
@@ -528,7 +528,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
528
528
|
}
|
|
529
529
|
throw new Error(message);
|
|
530
530
|
}
|
|
531
|
-
if (!response.ok) {
|
|
531
|
+
if (response && !response.ok) {
|
|
532
532
|
if (response.status === 403 ||
|
|
533
533
|
isSharingAuthorizationMessage(message)) {
|
|
534
534
|
if (!cancelled) {
|
|
@@ -585,6 +585,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
585
585
|
isOpen,
|
|
586
586
|
canRequest,
|
|
587
587
|
requestUrl,
|
|
588
|
+
transport,
|
|
588
589
|
token,
|
|
589
590
|
resourceLabel,
|
|
590
591
|
resourceName,
|
|
@@ -1009,7 +1010,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1009
1010
|
]);
|
|
1010
1011
|
// ----- Auto-save on access change after hydration -----
|
|
1011
1012
|
const saveAccess = useCallback(async (snapshot) => {
|
|
1012
|
-
if (!canRequest
|
|
1013
|
+
if (!canRequest) {
|
|
1013
1014
|
return;
|
|
1014
1015
|
}
|
|
1015
1016
|
setIsSaving(true);
|
|
@@ -1033,6 +1034,13 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1033
1034
|
},
|
|
1034
1035
|
},
|
|
1035
1036
|
};
|
|
1037
|
+
if (transport) {
|
|
1038
|
+
await transport.save(body);
|
|
1039
|
+
enqueueToastRef.current(`${resourceLabel} sharing updated.`, {
|
|
1040
|
+
variant: 'success',
|
|
1041
|
+
});
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1036
1044
|
const response = await fetch(requestUrl, {
|
|
1037
1045
|
method: 'PUT',
|
|
1038
1046
|
headers: {
|
|
@@ -1073,7 +1081,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1073
1081
|
finally {
|
|
1074
1082
|
setIsSaving(false);
|
|
1075
1083
|
}
|
|
1076
|
-
}, [canRequest, requestUrl, token, resourceLabel]);
|
|
1084
|
+
}, [canRequest, requestUrl, token, resourceLabel, transport]);
|
|
1077
1085
|
useEffect(() => {
|
|
1078
1086
|
if (!hasHydratedSharingRef.current) {
|
|
1079
1087
|
return;
|
|
@@ -1262,7 +1270,9 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1262
1270
|
alignItems: 'flex-start',
|
|
1263
1271
|
justifyContent: 'space-between',
|
|
1264
1272
|
gap: 2,
|
|
1265
|
-
}, children: [_jsx(Box, { sx: { display: 'grid', gap: 1 }, children: _jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Share ", resourceName || `this ${resourceLabel.toLowerCase()}`, ". Pick a principal below \u2014 they will be granted the selected access level."] }) }), _jsxs(ActionMenu, { children: [_jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(ActionMenu.Anchor, { children: _jsxs(Button, { variant: "default", size: "small", leadingVisual: KeyIcon, disabled: isSaving || isReadOnly, children: ["Access: ", ACCESS_LEVEL_LABELS[selectedAccessLevel]] }) }), _jsx(Button, { variant: "invisible", size: "small", leadingVisual: isExpanded ? ChevronUpIcon : ChevronDownIcon, onClick: () => setIsExpanded(previous => !previous), "aria-label": isExpanded
|
|
1273
|
+
}, children: [_jsx(Box, { sx: { display: 'grid', gap: 1 }, children: _jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Share ", resourceName || `this ${resourceLabel.toLowerCase()}`, ". Pick a principal below \u2014 they will be granted the selected access level."] }) }), _jsxs(ActionMenu, { children: [_jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(ActionMenu.Anchor, { children: _jsxs(Button, { variant: "default", size: "small", leadingVisual: KeyIcon, disabled: isSaving || isReadOnly, children: ["Access: ", ACCESS_LEVEL_LABELS[selectedAccessLevel]] }) }), _jsx(Button, { variant: "invisible", size: "small", leadingVisual: isExpanded ? ChevronUpIcon : ChevronDownIcon, onClick: () => setIsExpanded(previous => !previous), "aria-label": isExpanded
|
|
1274
|
+
? 'Shrink sharing details'
|
|
1275
|
+
: 'Expand sharing details', children: isExpanded ? 'Shrink details' : 'Expand details' })] }), _jsx(ActionMenu.Overlay, { width: "small", children: _jsx(ActionList, { selectionVariant: "single", children: ACCESS_LEVELS.map(level => (_jsx(ActionList.Item, { selected: selectedAccessLevel === level, onSelect: () => setSelectedAccessLevel(level), children: ACCESS_LEVEL_LABELS[level] }, level))) }) })] })] }), !isExpanded && (_jsxs(Box, { sx: {
|
|
1266
1276
|
px: 3,
|
|
1267
1277
|
py: 2,
|
|
1268
1278
|
borderRadius: 2,
|
|
@@ -1272,7 +1282,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1272
1282
|
bg: 'canvas.default',
|
|
1273
1283
|
display: 'grid',
|
|
1274
1284
|
gap: 1,
|
|
1275
|
-
}, children: [_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Sharing details are collapsed." }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [aclEntries.length, " principal", aclEntries.length === 1 ? '' : 's', "
|
|
1285
|
+
}, children: [_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Sharing details are collapsed." }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [aclEntries.length, " principal", aclEntries.length === 1 ? '' : 's', ' ', "currently granted access."] })] })), isExpanded && (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
1276
1286
|
px: 3,
|
|
1277
1287
|
py: 2,
|
|
1278
1288
|
borderRadius: 2,
|
|
@@ -1303,7 +1313,11 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1303
1313
|
alignItems: 'center',
|
|
1304
1314
|
justifyContent: 'space-between',
|
|
1305
1315
|
gap: 2,
|
|
1306
|
-
}, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 600 }, children: "Share with\u2026" }), isLoadingShareable && (_jsxs(Box, { sx: {
|
|
1316
|
+
}, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 600 }, children: "Share with\u2026" }), isLoadingShareable && (_jsxs(Box, { sx: {
|
|
1317
|
+
display: 'inline-flex',
|
|
1318
|
+
alignItems: 'center',
|
|
1319
|
+
gap: 1,
|
|
1320
|
+
}, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Loading\u2026" })] }))] }), !isLoadingShareable &&
|
|
1307
1321
|
groupedShareable.self.length === 0 &&
|
|
1308
1322
|
groupedShareable.otherUsers.length === 0 &&
|
|
1309
1323
|
groupedShareable.orgs.length === 0 &&
|
|
@@ -1356,8 +1370,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, resourceLabel, resour
|
|
|
1356
1370
|
gap: 1,
|
|
1357
1371
|
flexWrap: 'wrap',
|
|
1358
1372
|
}, children: [_jsx(Text, { children: result.displayName }), result.kind === 'personal' && (_jsx(Label, { size: "small", variant: "secondary", children: result.origin ||
|
|
1359
|
-
principalCache[principalKey('personal', result.uid)]
|
|
1360
|
-
?.origin ||
|
|
1373
|
+
principalCache[principalKey('personal', result.uid)]?.origin ||
|
|
1361
1374
|
'Datalayer' }))] }), _jsxs(ActionList.Description, { variant: "block", children: ["@", result.handle] })] }, principalKey(result.kind, result.uid)))) })) }))] })] }), _jsxs(Box, { sx: {
|
|
1362
1375
|
px: 3,
|
|
1363
1376
|
py: 2,
|
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SharingEditor — inline editor for the sharing payload shape used by
|
|
3
|
+
* `ShareAccessComponent` ACL endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Unlike `ShareAccessComponent` (which is bound to a server-side resource
|
|
6
|
+
* via `requestUrl`), this component edits a free-form
|
|
7
|
+
* `{ access: { view/update/execute: { userUids, teamUids, organizationUids } } }`
|
|
8
|
+
* blob in memory. It is intended for "create" flows where the resource does
|
|
9
|
+
* not yet exist and the sharing payload must be POSTed alongside the rest of
|
|
10
|
+
* the configuration.
|
|
11
|
+
*
|
|
12
|
+
* This is a scaffold: it currently exposes a structured JSON editor with
|
|
13
|
+
* validation and the canonical default shape. Future iterations can replace
|
|
14
|
+
* the textarea with the same principal-picker UI used by
|
|
15
|
+
* `ShareAccessComponent`.
|
|
16
|
+
*/
|
|
17
|
+
import type { JSX } from 'react';
|
|
1
18
|
export type SharingAccessLevel = 'view' | 'update' | 'execute';
|
|
2
19
|
export type SharingLevelPayload = {
|
|
3
20
|
userUids?: string[];
|
|
@@ -1,28 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } 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
|
-
* SharingEditor — inline editor for the sharing payload shape used by
|
|
12
|
-
* `ShareAccessComponent` ACL endpoints.
|
|
13
|
-
*
|
|
14
|
-
* Unlike `ShareAccessComponent` (which is bound to a server-side resource
|
|
15
|
-
* via `requestUrl`), this component edits a free-form
|
|
16
|
-
* `{ access: { view/update/execute: { userUids, teamUids, organizationUids } } }`
|
|
17
|
-
* blob in memory. It is intended for "create" flows where the resource does
|
|
18
|
-
* not yet exist and the sharing payload must be POSTed alongside the rest of
|
|
19
|
-
* the configuration.
|
|
20
|
-
*
|
|
21
|
-
* This is a scaffold: it currently exposes a structured JSON editor with
|
|
22
|
-
* validation and the canonical default shape. Future iterations can replace
|
|
23
|
-
* the textarea with the same principal-picker UI used by
|
|
24
|
-
* `ShareAccessComponent`.
|
|
25
|
-
*/
|
|
26
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
27
3
|
import { Box } from '@datalayer/primer-addons';
|
|
28
4
|
import { FormControl, Text, Textarea } from '@primer/react';
|