@parallelworks/ui 0.77.0 → 0.79.0
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 +42 -6
- package/dist/access/AccessDrawer.d.ts +49 -7
- package/dist/access/AccessDrawer.js +243 -38
- package/dist/access/AccessList.d.ts +19 -1
- package/dist/access/AccessList.js +220 -9
- package/dist/access/GrantView.d.ts +3 -1
- package/dist/access/GrantView.js +17 -4
- package/dist/access/PrincipalPicker.js +5 -5
- package/dist/access/focus.js +1 -1
- package/dist/access/index.d.ts +2 -2
- package/dist/access/index.js +2 -2
- package/dist/access/strings.d.ts +25 -1
- package/dist/access/strings.js +27 -3
- package/dist/access/types.d.ts +26 -0
- package/dist/ai/components/AllocationSelector.js +1 -1
- package/dist/ai/components/AttachmentManager.js +5 -5
- package/dist/ai/components/AttachmentUpload.js +2 -2
- package/dist/ai/components/BranchNavigator.js +1 -1
- package/dist/ai/components/ChatActivity.js +1 -1
- package/dist/ai/components/ChatEmptyState.js +3 -3
- package/dist/ai/components/ChatInput.js +3 -5
- package/dist/ai/components/ChatLayout.js +1 -1
- package/dist/ai/components/ChatMessage.js +1 -1
- package/dist/ai/components/ChatMessageList.js +23 -8
- package/dist/ai/components/ChatSidebar.js +3 -3
- package/dist/ai/components/ChatThread.js +4 -4
- package/dist/ai/components/ComposerAddMenu.js +9 -20
- package/dist/ai/components/ModelSelector.js +3 -3
- package/dist/ai/components/PastedText.js +5 -5
- package/dist/ai/components/SessionView.js +1 -1
- package/dist/ai/components/ShareDialog.js +3 -3
- package/dist/ai/components/SlashMenu.d.ts +31 -4
- package/dist/ai/components/SlashMenu.js +36 -63
- package/dist/ai/components/agent/ActivityLine.js +1 -1
- package/dist/ai/components/agent/AgentMessageParts.js +13 -13
- package/dist/ai/components/conversationActions.js +3 -3
- package/dist/ai/core/ChatProvider.js +1 -1
- package/dist/ai/core/config.js +1 -1
- package/dist/ai/ui/ConversationSidebar.js +3 -3
- package/dist/ai/ui/sidebar.js +3 -3
- package/dist/assets/yaml.worker-DOBV2lND.js +884 -0
- package/dist/components/ActionMenu.d.ts +38 -9
- package/dist/components/ActionMenu.js +48 -22
- package/dist/components/Avatar.d.ts +66 -6
- package/dist/components/Avatar.js +130 -18
- package/dist/components/Breadcrumbs.d.ts +4 -0
- package/dist/components/Breadcrumbs.js +26 -10
- package/dist/components/Button.d.ts +3 -2
- package/dist/components/Button.js +11 -1
- package/dist/components/Callout.d.ts +3 -2
- package/dist/components/Callout.js +3 -2
- package/dist/components/Card.d.ts +33 -9
- package/dist/components/Card.js +24 -8
- package/dist/components/Checkbox.d.ts +3 -1
- package/dist/components/Checkbox.js +4 -2
- package/dist/components/ColorInput.js +1 -1
- package/dist/components/Combobox.d.ts +23 -0
- package/dist/components/Combobox.js +252 -86
- package/dist/components/ConfirmModal.d.ts +28 -2
- package/dist/components/ConfirmModal.js +100 -15
- package/dist/components/ContextMenu.d.ts +29 -2
- package/dist/components/ContextMenu.js +60 -8
- package/dist/components/CopyButton.d.ts +21 -8
- package/dist/components/CopyButton.js +29 -9
- package/dist/components/CreateModal.d.ts +20 -4
- package/dist/components/CreateModal.js +28 -17
- package/dist/components/DatePicker.d.ts +31 -1
- package/dist/components/DatePicker.js +178 -47
- package/dist/components/DescriptionList.d.ts +13 -3
- package/dist/components/DescriptionList.js +43 -11
- package/dist/components/Disclosure.d.ts +10 -2
- package/dist/components/Disclosure.js +18 -7
- package/dist/components/Drawer.js +5 -5
- package/dist/components/EmptyState.d.ts +12 -4
- package/dist/components/EmptyState.js +18 -10
- package/dist/components/ErrorPage.d.ts +40 -0
- package/dist/components/ErrorPage.js +101 -0
- package/dist/components/ExternalLink.d.ts +4 -1
- package/dist/components/ExternalLink.js +4 -5
- package/dist/components/Field.d.ts +21 -6
- package/dist/components/Field.js +32 -16
- package/dist/components/FileButton.d.ts +19 -0
- package/dist/components/FileButton.js +32 -0
- package/dist/components/HoverCard.d.ts +26 -6
- package/dist/components/HoverCard.js +11 -5
- package/dist/components/IconButton.js +4 -2
- package/dist/components/InfoTip.js +3 -3
- package/dist/components/Input.d.ts +33 -3
- package/dist/components/Input.js +149 -14
- package/dist/components/Kbd.d.ts +40 -0
- package/dist/components/Kbd.js +168 -0
- package/dist/components/Listbox.d.ts +103 -0
- package/dist/components/Listbox.js +190 -0
- package/dist/components/Loader.d.ts +8 -2
- package/dist/components/Loader.js +16 -1
- package/dist/components/Markdown.js +1 -1
- package/dist/components/MarkdownImpl.js +1 -1
- package/dist/components/Menu.d.ts +20 -2
- package/dist/components/Menu.js +48 -19
- package/dist/components/MenuEntries.d.ts +41 -4
- package/dist/components/MenuEntries.js +266 -39
- package/dist/components/Meter.d.ts +50 -11
- package/dist/components/Meter.js +71 -21
- package/dist/components/Modal.d.ts +9 -3
- package/dist/components/Modal.js +68 -29
- package/dist/components/OneTimeCodeInput.js +1 -1
- package/dist/components/PageHeader.js +111 -7
- package/dist/components/PageHeaderAction.d.ts +8 -3
- package/dist/components/PageHeaderAction.js +122 -34
- package/dist/components/Pagination.d.ts +13 -1
- package/dist/components/Pagination.js +90 -19
- package/dist/components/Popover.d.ts +16 -2
- package/dist/components/Popover.js +20 -21
- package/dist/components/Provider.d.ts +172 -5
- package/dist/components/Provider.js +157 -14
- package/dist/components/RefreshButton.d.ts +13 -6
- package/dist/components/RefreshButton.js +17 -9
- package/dist/components/RunStatusIcon.d.ts +16 -7
- package/dist/components/RunStatusIcon.js +21 -8
- package/dist/components/Section.d.ts +11 -4
- package/dist/components/Section.js +33 -22
- package/dist/components/SegmentedControl.d.ts +16 -3
- package/dist/components/SegmentedControl.js +7 -3
- package/dist/components/Select.d.ts +19 -3
- package/dist/components/Select.js +114 -68
- package/dist/components/SelectionCopy.d.ts +10 -0
- package/dist/components/SelectionCopy.js +105 -0
- package/dist/components/SettingModeOption.js +1 -1
- package/dist/components/SettingsCard.js +1 -1
- package/dist/components/Skeleton.js +1 -1
- package/dist/components/StatusBadge.d.ts +55 -10
- package/dist/components/StatusBadge.js +91 -15
- package/dist/components/StickyBar.js +1 -1
- package/dist/components/Table.d.ts +22 -4
- package/dist/components/Table.js +46 -24
- package/dist/components/Tabs.d.ts +9 -4
- package/dist/components/Tabs.js +9 -4
- package/dist/components/Tag.d.ts +49 -0
- package/dist/components/Tag.js +199 -0
- package/dist/components/ThemeEditor.js +1 -1
- package/dist/components/Toast.js +1 -1
- package/dist/components/ToggleGroup.d.ts +4 -1
- package/dist/components/ToggleGroup.js +30 -13
- package/dist/components/Tooltip.d.ts +9 -3
- package/dist/components/Tooltip.js +55 -39
- package/dist/components/buttonClasses.d.ts +5 -2
- package/dist/components/buttonClasses.js +11 -10
- package/dist/components/chart.d.ts +69 -0
- package/dist/components/chart.js +145 -0
- package/dist/components/comboboxItems.d.ts +7 -1
- package/dist/components/comboboxItems.js +6 -2
- package/dist/components/dismiss.d.ts +5 -1
- package/dist/components/dismiss.js +6 -2
- package/dist/components/floating.d.ts +4 -4
- package/dist/components/floating.js +5 -5
- package/dist/components/headerActionsFit.d.ts +37 -0
- package/dist/components/headerActionsFit.js +81 -0
- package/dist/components/pageHeaderStore.d.ts +3 -0
- package/dist/components/pageHeaderStore.js +3 -0
- package/dist/components/pathBreaks.js +2 -2
- package/dist/components/popupContainer.d.ts +17 -0
- package/dist/components/popupContainer.js +69 -0
- package/dist/components/relativeTime.d.ts +21 -10
- package/dist/components/relativeTime.js +50 -22
- package/dist/components/segmented.d.ts +18 -4
- package/dist/components/segmented.js +48 -6
- package/dist/components/typedDate.d.ts +5 -0
- package/dist/components/typedDate.js +50 -0
- package/dist/components/useClosingValue.d.ts +4 -0
- package/dist/components/useClosingValue.js +12 -0
- package/dist/components/useCopy.d.ts +6 -0
- package/dist/components/useCopy.js +3 -3
- package/dist/components/useNarrow.d.ts +2 -0
- package/dist/components/useNarrow.js +16 -0
- package/dist/editor/Editor.js +1 -1
- package/dist/editor/FormCodePanel.js +1 -1
- package/dist/editor/Monaco.js +1 -1
- package/dist/editor/workers.js +1 -1
- package/dist/file-explorer/FileExplorer.js +16 -15
- package/dist/file-explorer/FileExplorerContext.js +2 -2
- package/dist/file-explorer/FilePreview/Viewer.js +3 -3
- package/dist/file-explorer/FilePreview/index.js +2 -2
- package/dist/file-explorer/FileRowsWindow.js +3 -3
- package/dist/file-explorer/FileTable.js +1 -1
- package/dist/file-explorer/LoadMoreRow.js +1 -1
- package/dist/file-explorer/TreeView.js +5 -5
- package/dist/file-explorer/helpers.js +2 -2
- package/dist/file-explorer/toasts.js +2 -2
- package/dist/form/Fields/CheckboxGroupField.js +1 -1
- package/dist/form/Fields/DropdownField.js +1 -1
- package/dist/form/Fields/DurationField.js +2 -2
- package/dist/form/Fields/MultiDropdownField.js +1 -1
- package/dist/form/Fields/NumberField.js +1 -1
- package/dist/form/Fields/ObjectField.js +1 -1
- package/dist/form/Fields/RangeField.js +1 -1
- package/dist/form/Fields/StringField.js +1 -1
- package/dist/form/Form.js +3 -3
- package/dist/form/FormLayout.js +1 -1
- package/dist/form/Wizard/WizardContainer.js +1 -1
- package/dist/form/Wizard/WizardNavigation.js +1 -1
- package/dist/form/Wizard/WizardStepContent.js +1 -1
- package/dist/form/fieldRegistry.js +1 -1
- package/dist/form/formEditing.js +1 -1
- package/dist/format.d.ts +17 -7
- package/dist/format.js +39 -16
- package/dist/graph/AnnotationBanner.js +2 -2
- package/dist/graph/Connectors.js +5 -5
- package/dist/graph/DependencyGraph.js +10 -9
- package/dist/graph/GraphEditor.js +4 -4
- package/dist/graph/GraphEditorDialogs.js +13 -12
- package/dist/graph/GraphNode.js +1 -1
- package/dist/graph/InputDialog.js +5 -5
- package/dist/graph/InputsEditor.js +10 -9
- package/dist/graph/MatrixGroup.js +2 -2
- package/dist/graph/ProblemPageLink.d.ts +9 -0
- package/dist/graph/ProblemPageLink.js +21 -0
- package/dist/graph/ProblemsButton.js +26 -16
- package/dist/graph/Reveal.js +1 -1
- package/dist/graph/RunWarningsList.js +21 -12
- package/dist/graph/ShortcutsButton.js +25 -8
- package/dist/graph/StepSummaries.js +1 -1
- package/dist/graph/TreeView.js +2 -2
- package/dist/graph/WorkflowSettingsDialog.js +3 -3
- package/dist/graph/editorApi.d.ts +10 -0
- package/dist/graph/editorFields.js +3 -3
- package/dist/graph/editorPrimitives.js +1 -1
- package/dist/graph/editorRows.js +8 -6
- package/dist/graph/editorStrings.d.ts +1 -0
- package/dist/graph/editorStrings.js +1 -0
- package/dist/graph/fieldProblems.js +2 -2
- package/dist/graph/inputRefs.js +7 -6
- package/dist/graph/runWarnings.d.ts +12 -1
- package/dist/graph/stepWith.js +2 -2
- package/dist/index.d.ts +30 -21
- package/dist/index.js +20 -12
- package/dist/list/ActionToolbar.d.ts +4 -0
- package/dist/list/ActionToolbar.js +35 -12
- package/dist/list/ListFilterBar.d.ts +42 -0
- package/dist/list/ListFilterBar.js +789 -0
- package/dist/list/ListPage.d.ts +42 -4
- package/dist/list/ListPage.js +56 -22
- package/dist/list/ListTable.d.ts +27 -3
- package/dist/list/ListTable.js +48 -23
- package/dist/list/ListToolbar.d.ts +31 -0
- package/dist/list/ListToolbar.js +43 -0
- package/dist/list/ListViewControls.d.ts +8 -4
- package/dist/list/ListViewControls.js +22 -14
- package/dist/list/UserHoverCard.d.ts +8 -2
- package/dist/list/UserHoverCard.js +26 -13
- package/dist/list/filterModel.d.ts +122 -0
- package/dist/list/filterModel.js +308 -0
- package/dist/list/index.d.ts +6 -2
- package/dist/list/index.js +6 -2
- package/dist/list/listSearch.d.ts +1 -1
- package/dist/list/listSearch.js +8 -4
- package/dist/list/listView.d.ts +24 -2
- package/dist/list/listView.js +47 -45
- package/dist/list/rowMenu.d.ts +10 -5
- package/dist/list/rowMenu.js +17 -7
- package/dist/list/useListFilters.d.ts +68 -0
- package/dist/list/useListFilters.js +252 -0
- package/dist/logviewer/LogViewer.js +4 -4
- package/dist/styles/theme.css +94 -0
- package/dist/styles.css +1 -1
- package/package.json +11 -11
- package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
- package/dist/components/fullscreen.d.ts +0 -4
- package/dist/components/fullscreen.js +0 -18
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type ReactNode } from 'react';
|
|
2
|
+
import type { OpenMenu } from '../components/ContextMenu.js';
|
|
2
3
|
import { type AccessModel } from './model.js';
|
|
3
4
|
import type { AccessStrings } from './strings.js';
|
|
4
|
-
import type { AccessPrincipal } from './types.js';
|
|
5
|
+
import type { AccessPrincipal, AccessRule } from './types.js';
|
|
5
6
|
/** The id the owner's section has among the roles' sections. */
|
|
6
7
|
export declare const OWNER_SECTION = "__owner";
|
|
7
8
|
/** A removal waiting on the reader: one role, or every role a principal holds here. */
|
|
@@ -20,6 +21,12 @@ export interface ListActions {
|
|
|
20
21
|
onCancelRemove: () => void;
|
|
21
22
|
onRemove: (removal: PendingRemoval) => void;
|
|
22
23
|
onGrantMore: (principalId: string) => void;
|
|
24
|
+
/** Gives a principal this one role in place of the ones it holds, where each holds one. */
|
|
25
|
+
onChangeRole: (principalId: string, roleId: string) => void;
|
|
26
|
+
/** Each principal holds one role here. */
|
|
27
|
+
singleRole: boolean;
|
|
28
|
+
/** Opens a row's own menu on a right-click. */
|
|
29
|
+
openMenu: OpenMenu;
|
|
23
30
|
/** The failed save's callout, and where it belongs: under the role or principal it was about. */
|
|
24
31
|
failure: {
|
|
25
32
|
node: ReactNode;
|
|
@@ -56,4 +63,15 @@ interface ViewProps {
|
|
|
56
63
|
export declare function ByRole({ model, shown, order, expanded, onExpandedChange, filtering, actions, t, sectionId, }: ViewProps): (import("react").JSX.Element | null | undefined)[];
|
|
57
64
|
/** Which roles each person and group has, one by one. */
|
|
58
65
|
export declare function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions, t, sectionId, }: ViewProps): (import("react").JSX.Element | null)[];
|
|
66
|
+
/** A reason someone has access that no grant here changes, locked ahead of the grants. */
|
|
67
|
+
export declare function RuleRow({ rule, roleName, lead, t, }: {
|
|
68
|
+
rule: AccessRule;
|
|
69
|
+
roleName: string | undefined;
|
|
70
|
+
/** Lines its title up with the rows below: in a chevron's column, in a tile's, or after both. */
|
|
71
|
+
lead: 'chevron' | 'tile' | 'both';
|
|
72
|
+
t: AccessStrings;
|
|
73
|
+
}): import("react").JSX.Element;
|
|
74
|
+
/** Person and group one by one where each holds one role: a flat row each, its role picked
|
|
75
|
+
* from a list on the row. */
|
|
76
|
+
export declare function ByPrincipalSingle({ model, order, actions, t, sectionId }: ViewProps): (import("react").JSX.Element | null)[];
|
|
59
77
|
export {};
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { cx } from "../cx.js";
|
|
2
|
-
import { AddIcon, ChevronRightIcon, LockIcon, OrganizationIcon, TrashIcon } from "../icons.js";
|
|
2
|
+
import { AddIcon, ChevronRightIcon, KeyIcon, LockIcon, OrganizationIcon, TrashIcon } from "../icons.js";
|
|
3
3
|
import { Loader } from "../components/Loader.js";
|
|
4
|
+
import { menuDivider } from "../components/MenuEntries.js";
|
|
5
|
+
import { Avatar } from "../components/Avatar.js";
|
|
4
6
|
import { Button } from "../components/Button.js";
|
|
5
7
|
import { IconButton } from "../components/IconButton.js";
|
|
6
8
|
import { Callout } from "../components/Callout.js";
|
|
7
9
|
import { collapsePanelClassName } from "../components/Disclosure.js";
|
|
10
|
+
import { Select } from "../components/Select.js";
|
|
8
11
|
import { StatusBadge } from "../components/StatusBadge.js";
|
|
9
12
|
import { alsoHas, firstOfEach, isOwner, key, overlapOf, removalOf } from "./model.js";
|
|
10
13
|
import { PrincipalTile } from "./PrincipalPicker.js";
|
|
11
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
12
14
|
import { useEffect, useId, useRef } from "react";
|
|
15
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
13
16
|
import { Collapsible } from "@base-ui/react/collapsible";
|
|
14
17
|
//#region src/access/AccessList.tsx
|
|
15
18
|
/** The id the owner's section has among the roles' sections. */
|
|
@@ -20,6 +23,21 @@ var aboutOf = (principal, t) => principal.kind === "user" ? principal.detail : p
|
|
|
20
23
|
/** Where a role someone has elsewhere comes from, as "through" reads it. */
|
|
21
24
|
var sourceOf = (holding) => holding.through?.name ?? holding.from ?? "";
|
|
22
25
|
/** Stands where a remove button would, on a row that can't be removed here. */
|
|
26
|
+
/** A role named where a row's role select would sit, so read-only rows line up with
|
|
27
|
+
* editable ones: the select's width, border and padding, without the box. */
|
|
28
|
+
function RoleText({ children }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("span", {
|
|
30
|
+
className: "w-36 shrink-0 wrap-anywhere border border-transparent px-2 text-xs text-(--theme-muted-text-color)",
|
|
31
|
+
children
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
/** Holds the remove button's place on a row that has none. */
|
|
35
|
+
function NoAction() {
|
|
36
|
+
return /* @__PURE__ */ jsx("span", {
|
|
37
|
+
"aria-hidden": "true",
|
|
38
|
+
className: "size-7 shrink-0"
|
|
39
|
+
});
|
|
40
|
+
}
|
|
23
41
|
function Locked() {
|
|
24
42
|
return /* @__PURE__ */ jsx("span", {
|
|
25
43
|
className: "flex size-7 items-center justify-center text-(--theme-muted-text-color)",
|
|
@@ -30,12 +48,13 @@ function Locked() {
|
|
|
30
48
|
});
|
|
31
49
|
}
|
|
32
50
|
/** A role or principal whose rows fold under it. */
|
|
33
|
-
function Section({ id, open, onOpenChange, disabled, lead, title, description, aside, narrowAside, notice, children }) {
|
|
51
|
+
function Section({ id, open, onOpenChange, disabled, lead, title, description, aside, narrowAside, notice, onContextMenu, children }) {
|
|
34
52
|
return /* @__PURE__ */ jsxs(Collapsible.Root, {
|
|
35
53
|
open: open && !disabled,
|
|
36
54
|
onOpenChange,
|
|
37
55
|
disabled,
|
|
38
56
|
className: "border-b border-(--theme-border)",
|
|
57
|
+
onContextMenu,
|
|
39
58
|
children: [
|
|
40
59
|
/* @__PURE__ */ jsxs(Collapsible.Trigger, {
|
|
41
60
|
id,
|
|
@@ -87,9 +106,10 @@ function Section({ id, open, onOpenChange, disabled, lead, title, description, a
|
|
|
87
106
|
});
|
|
88
107
|
}
|
|
89
108
|
/** A line under a section: a principal under a role, or a role under a principal. */
|
|
90
|
-
function Row({ lead, title, meta, action, muted }) {
|
|
109
|
+
function Row({ lead, title, meta, action, muted, onContextMenu }) {
|
|
91
110
|
return /* @__PURE__ */ jsxs("div", {
|
|
92
111
|
className: "flex items-center gap-3 py-1.5 ps-11 pe-4 @min-[30rem]/access:ps-11",
|
|
112
|
+
onContextMenu,
|
|
93
113
|
children: [
|
|
94
114
|
lead,
|
|
95
115
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -173,7 +193,7 @@ function RemoveConfirm({ model, removal, saving, onCancel, onConfirm, t }) {
|
|
|
173
193
|
children: impact.owner ? /* @__PURE__ */ jsx("p", {
|
|
174
194
|
className: "m-0 text-(--theme-muted-text-color)",
|
|
175
195
|
children: t.ownerLosesNothing
|
|
176
|
-
}) : impact.lost.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
196
|
+
}) : impact.lost.length > 0 ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
177
197
|
/* @__PURE__ */ jsx("p", {
|
|
178
198
|
className: "m-0 text-(--theme-muted-text-color)",
|
|
179
199
|
children: t.losesIntro(principal.kind, principal.memberCount)
|
|
@@ -277,7 +297,7 @@ function ByRole({ model, shown, order, expanded, onExpandedChange, filtering, ac
|
|
|
277
297
|
notice: failure,
|
|
278
298
|
title: role.name,
|
|
279
299
|
description: role.description,
|
|
280
|
-
aside: /* @__PURE__ */ jsxs(Fragment, { children: [everyoneTag, count] }),
|
|
300
|
+
aside: /* @__PURE__ */ jsxs(Fragment$1, { children: [everyoneTag, count] }),
|
|
281
301
|
narrowAside: everyoneTag && !count ? /* @__PURE__ */ jsx("span", {
|
|
282
302
|
className: "mt-1 inline-flex",
|
|
283
303
|
children: everyoneTag
|
|
@@ -310,6 +330,11 @@ function ByRole({ model, shown, order, expanded, onExpandedChange, filtering, ac
|
|
|
310
330
|
const hint = overlapHint(overlapOf(model, principalId, role), t);
|
|
311
331
|
const label = t.removeRole(principalLabel(principal, t), role.name);
|
|
312
332
|
return /* @__PURE__ */ jsx(Row, {
|
|
333
|
+
onContextMenu: rowMenu(actions, () => rowEntries(model, principal, actions, t, {
|
|
334
|
+
principalId,
|
|
335
|
+
roleIds: [roleId],
|
|
336
|
+
all: false
|
|
337
|
+
})),
|
|
313
338
|
lead,
|
|
314
339
|
title: principalLabel(principal, t),
|
|
315
340
|
meta: [aboutOf(principal, t), hint].filter(Boolean).join(" · "),
|
|
@@ -349,7 +374,7 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
|
|
|
349
374
|
const room = owner ? 1 : 2;
|
|
350
375
|
const badges = badgeRoles.length <= room ? badgeRoles : badgeRoles.slice(0, room - 1);
|
|
351
376
|
const hidden = badgeRoles.slice(badges.length);
|
|
352
|
-
const roleBadges = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
377
|
+
const roleBadges = /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
353
378
|
owner && /* @__PURE__ */ jsx(StatusBadge, {
|
|
354
379
|
size: "md",
|
|
355
380
|
variant: "info",
|
|
@@ -378,6 +403,11 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
|
|
|
378
403
|
principal,
|
|
379
404
|
className: "hidden @min-[30rem]/access:flex"
|
|
380
405
|
}),
|
|
406
|
+
onContextMenu: held.length > 0 ? rowMenu(actions, () => rowEntries(model, principal, actions, t, {
|
|
407
|
+
principalId,
|
|
408
|
+
roleIds: held.map((role) => role.id),
|
|
409
|
+
all: true
|
|
410
|
+
})) : void 0,
|
|
381
411
|
notice: failure,
|
|
382
412
|
title: principalLabel(principal, t),
|
|
383
413
|
description: everyone ? t.everyoneJoinLater : aboutOf(principal, t),
|
|
@@ -393,7 +423,7 @@ function ByPrincipal({ model, shown, order, expanded, onExpandedChange, actions,
|
|
|
393
423
|
onCancel: actions.onCancelRemove,
|
|
394
424
|
onConfirm: () => actions.removal && actions.onRemove(actions.removal),
|
|
395
425
|
t
|
|
396
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
426
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
397
427
|
owner && /* @__PURE__ */ jsx(Row, {
|
|
398
428
|
title: /* @__PURE__ */ jsx("span", {
|
|
399
429
|
className: "font-medium",
|
|
@@ -482,5 +512,186 @@ function RoleRow({ model, principal, role, actions, t }) {
|
|
|
482
512
|
})
|
|
483
513
|
});
|
|
484
514
|
}
|
|
515
|
+
/** A row's right-click menu, which repeats what its buttons do; none while read-only. */
|
|
516
|
+
function rowMenu(actions, entries) {
|
|
517
|
+
if (actions.readOnly) return;
|
|
518
|
+
return (e) => {
|
|
519
|
+
e.stopPropagation();
|
|
520
|
+
actions.openMenu(e, entries());
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
/** A principal's row menu: its role, where each holds one, more roles otherwise, then removal. */
|
|
524
|
+
function rowEntries(model, principal, actions, t, removal) {
|
|
525
|
+
const held = new Set((model.held.get(principal.id) ?? []).map((role) => role.id));
|
|
526
|
+
const lead = actions.singleRole ? [{
|
|
527
|
+
label: t.roleMenu,
|
|
528
|
+
icon: /* @__PURE__ */ jsx(KeyIcon, {}),
|
|
529
|
+
items: model.grantable.map((role) => ({
|
|
530
|
+
label: role.name,
|
|
531
|
+
description: role.description,
|
|
532
|
+
checked: held.has(role.id),
|
|
533
|
+
onClick: () => {
|
|
534
|
+
if (!held.has(role.id) || held.size > 1) actions.onChangeRole(principal.id, role.id);
|
|
535
|
+
}
|
|
536
|
+
}))
|
|
537
|
+
}] : isOwner(model, principal.id) ? [] : [{
|
|
538
|
+
label: t.grantMoreRoles,
|
|
539
|
+
icon: /* @__PURE__ */ jsx(AddIcon, {}),
|
|
540
|
+
onClick: () => actions.onGrantMore(principal.id)
|
|
541
|
+
}];
|
|
542
|
+
return [
|
|
543
|
+
...lead,
|
|
544
|
+
...lead.length > 0 ? [menuDivider] : [],
|
|
545
|
+
{
|
|
546
|
+
label: removal.all || actions.singleRole ? t.removeAccess : t.confirmRemove(removal.roleIds.map((id) => model.roleById.get(id)?.name ?? id)),
|
|
547
|
+
icon: /* @__PURE__ */ jsx(TrashIcon, {}),
|
|
548
|
+
destructive: true,
|
|
549
|
+
onClick: () => actions.onAskRemove(removal)
|
|
550
|
+
}
|
|
551
|
+
];
|
|
552
|
+
}
|
|
553
|
+
/** A reason someone has access that no grant here changes, locked ahead of the grants. */
|
|
554
|
+
function RuleRow({ rule, roleName, lead, t }) {
|
|
555
|
+
const people = rule.people ?? [];
|
|
556
|
+
const shown = people.slice(0, 4);
|
|
557
|
+
const more = people.length - shown.length;
|
|
558
|
+
const icon = rule.icon ?? /* @__PURE__ */ jsx(LockIcon, {});
|
|
559
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
560
|
+
className: "flex items-center gap-3 border-b border-(--theme-border) px-4 py-2.5",
|
|
561
|
+
children: [
|
|
562
|
+
lead === "chevron" ? /* @__PURE__ */ jsx("span", {
|
|
563
|
+
"aria-hidden": "true",
|
|
564
|
+
className: "flex size-4 shrink-0 items-center justify-center text-(--theme-muted-text-color) [&_svg]:size-4",
|
|
565
|
+
children: icon
|
|
566
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [lead === "both" && /* @__PURE__ */ jsx("span", {
|
|
567
|
+
"aria-hidden": "true",
|
|
568
|
+
className: "size-4 shrink-0"
|
|
569
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
570
|
+
"aria-hidden": "true",
|
|
571
|
+
className: "hidden size-8 shrink-0 items-center justify-center rounded-md bg-(--theme-muted-panel-bg) text-(--theme-muted-text-color) @min-[30rem]/access:flex [&_svg]:size-4",
|
|
572
|
+
children: icon
|
|
573
|
+
})] }),
|
|
574
|
+
/* @__PURE__ */ jsxs("span", {
|
|
575
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
576
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
577
|
+
className: "text-sm font-medium wrap-anywhere",
|
|
578
|
+
children: rule.title
|
|
579
|
+
}), rule.detail && /* @__PURE__ */ jsx("span", {
|
|
580
|
+
className: "text-xs wrap-anywhere text-(--theme-muted-text-color)",
|
|
581
|
+
children: rule.detail
|
|
582
|
+
})]
|
|
583
|
+
}),
|
|
584
|
+
shown.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
585
|
+
className: "sr-only",
|
|
586
|
+
children: t.ruleMembers(shown.map((person) => person.name), more)
|
|
587
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
588
|
+
"aria-hidden": "true",
|
|
589
|
+
className: "hidden shrink-0 items-center gap-1 @min-[30rem]/access:flex",
|
|
590
|
+
children: [shown.map((person, index) => /* @__PURE__ */ jsx(Avatar, {
|
|
591
|
+
name: person.name,
|
|
592
|
+
src: person.avatarUrl,
|
|
593
|
+
size: "md",
|
|
594
|
+
decorative: true
|
|
595
|
+
}, `${person.name}-${index.toString()}`)), more > 0 && /* @__PURE__ */ jsx("span", {
|
|
596
|
+
className: "inline-flex size-7 items-center justify-center rounded-full bg-(--theme-muted-panel-bg) text-[11px] font-medium tabular-nums text-(--theme-muted-text-color)",
|
|
597
|
+
children: t.moreMembers(more)
|
|
598
|
+
})]
|
|
599
|
+
})] }),
|
|
600
|
+
roleName && (lead === "tile" ? /* @__PURE__ */ jsx(RoleText, { children: roleName }) : /* @__PURE__ */ jsx("span", {
|
|
601
|
+
className: "shrink-0 text-xs text-(--theme-muted-text-color)",
|
|
602
|
+
children: roleName
|
|
603
|
+
})),
|
|
604
|
+
/* @__PURE__ */ jsx(Locked, {})
|
|
605
|
+
]
|
|
606
|
+
});
|
|
607
|
+
}
|
|
608
|
+
/** Person and group one by one where each holds one role: a flat row each, its role picked
|
|
609
|
+
* from a list on the row. */
|
|
610
|
+
function ByPrincipalSingle({ model, order, actions, t, sectionId }) {
|
|
611
|
+
return order.map((principalId) => {
|
|
612
|
+
const principal = model.principalById.get(principalId);
|
|
613
|
+
if (!principal) return null;
|
|
614
|
+
const owner = isOwner(model, principalId);
|
|
615
|
+
const held = model.held.get(principalId) ?? [];
|
|
616
|
+
const inheritedRoles = (model.inherited.get(principalId) ?? []).map((holding) => holding.role);
|
|
617
|
+
const role = held[0];
|
|
618
|
+
const name = principalLabel(principal, t);
|
|
619
|
+
const failure = actions.failure?.principalId === principalId ? actions.failure.node : void 0;
|
|
620
|
+
const removal = {
|
|
621
|
+
principalId,
|
|
622
|
+
roleIds: held.map((r) => r.id),
|
|
623
|
+
all: held.length > 1
|
|
624
|
+
};
|
|
625
|
+
if (actions.removal?.principalId === principalId) return /* @__PURE__ */ jsx("div", {
|
|
626
|
+
className: "border-b border-(--theme-border)",
|
|
627
|
+
children: /* @__PURE__ */ jsx(RemoveConfirm, {
|
|
628
|
+
model,
|
|
629
|
+
removal: actions.removal,
|
|
630
|
+
saving: actions.saving.size > 0,
|
|
631
|
+
onCancel: actions.onCancelRemove,
|
|
632
|
+
onConfirm: () => actions.removal && actions.onRemove(actions.removal),
|
|
633
|
+
t
|
|
634
|
+
})
|
|
635
|
+
}, principalId);
|
|
636
|
+
const saving = held.some((r) => actions.saving.has(key({
|
|
637
|
+
principalId,
|
|
638
|
+
roleId: r.id
|
|
639
|
+
})));
|
|
640
|
+
const options = [...model.grantable, ...role && !model.grantable.includes(role) ? [role] : []].map((r) => ({
|
|
641
|
+
value: r.id,
|
|
642
|
+
label: r.name
|
|
643
|
+
}));
|
|
644
|
+
const control = owner ? /* @__PURE__ */ jsx(StatusBadge, {
|
|
645
|
+
size: "md",
|
|
646
|
+
variant: "info",
|
|
647
|
+
children: t.owner
|
|
648
|
+
}) : !role ? /* @__PURE__ */ jsx(RoleText, { children: inheritedRoles.map((r) => r.name).join(", ") }) : actions.readOnly ? /* @__PURE__ */ jsx(RoleText, { children: role.name }) : /* @__PURE__ */ jsx(Select, {
|
|
649
|
+
size: "sm",
|
|
650
|
+
"aria-label": t.roleFor(name),
|
|
651
|
+
items: options,
|
|
652
|
+
value: role.id,
|
|
653
|
+
disabled: saving,
|
|
654
|
+
onValueChange: (next) => {
|
|
655
|
+
if (next !== null && (next !== role.id || held.length > 1)) actions.onChangeRole(principalId, next);
|
|
656
|
+
},
|
|
657
|
+
className: "w-36 shrink-0"
|
|
658
|
+
});
|
|
659
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
660
|
+
id: sectionId(principalId),
|
|
661
|
+
tabIndex: -1,
|
|
662
|
+
className: "border-b border-(--theme-border) outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--theme-focus)",
|
|
663
|
+
onContextMenu: role && !owner ? rowMenu(actions, () => rowEntries(model, principal, actions, t, removal)) : void 0,
|
|
664
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
665
|
+
className: "flex items-center gap-3 px-4 py-2.5",
|
|
666
|
+
children: [
|
|
667
|
+
/* @__PURE__ */ jsx(PrincipalTile, {
|
|
668
|
+
principal,
|
|
669
|
+
className: "hidden @min-[30rem]/access:flex"
|
|
670
|
+
}),
|
|
671
|
+
/* @__PURE__ */ jsxs("span", {
|
|
672
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
673
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
674
|
+
className: "text-sm font-medium wrap-anywhere",
|
|
675
|
+
children: name
|
|
676
|
+
}), aboutOf(principal, t) && /* @__PURE__ */ jsx("span", {
|
|
677
|
+
className: "text-xs wrap-anywhere text-(--theme-muted-text-color)",
|
|
678
|
+
children: aboutOf(principal, t)
|
|
679
|
+
})]
|
|
680
|
+
}),
|
|
681
|
+
control,
|
|
682
|
+
owner || !role ? /* @__PURE__ */ jsx(Locked, {}) : actions.readOnly ? /* @__PURE__ */ jsx(NoAction, {}) : /* @__PURE__ */ jsx(RemoveButton, {
|
|
683
|
+
label: t.removeRole(name, role.name),
|
|
684
|
+
saving,
|
|
685
|
+
removal,
|
|
686
|
+
onAsk: actions.onAskRemove
|
|
687
|
+
})
|
|
688
|
+
]
|
|
689
|
+
}), failure && /* @__PURE__ */ jsx("div", {
|
|
690
|
+
className: "px-4 pb-3",
|
|
691
|
+
children: failure
|
|
692
|
+
})]
|
|
693
|
+
}, principalId);
|
|
694
|
+
});
|
|
695
|
+
}
|
|
485
696
|
//#endregion
|
|
486
|
-
export { ByPrincipal, ByRole, OWNER_SECTION, RemoveConfirm, principalLabel, removeKey };
|
|
697
|
+
export { ByPrincipal, ByPrincipalSingle, ByRole, OWNER_SECTION, RemoveConfirm, RuleRow, principalLabel, removeKey };
|
|
@@ -8,7 +8,7 @@ export interface GrantSelection {
|
|
|
8
8
|
roleIds: string[];
|
|
9
9
|
}
|
|
10
10
|
/** The grant form's body and footer, which the drawer lays out in its own body and footer. */
|
|
11
|
-
export declare function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, t, }: {
|
|
11
|
+
export declare function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, singleRole, t, }: {
|
|
12
12
|
model: AccessModel;
|
|
13
13
|
selection: GrantSelection;
|
|
14
14
|
onSelectionChange: (next: GrantSelection) => void;
|
|
@@ -29,6 +29,8 @@ export declare function useGrantView({ model, selection, onSelectionChange, reso
|
|
|
29
29
|
focusLater: (find: () => HTMLElement | null | undefined) => void;
|
|
30
30
|
/** The drawer's body, above its footer, which the open list fills. */
|
|
31
31
|
boundary: Element | null;
|
|
32
|
+
/** One role each: the form picks one, and granting it takes the role each already holds. */
|
|
33
|
+
singleRole?: boolean;
|
|
32
34
|
t: AccessStrings;
|
|
33
35
|
}): {
|
|
34
36
|
body: ReactNode;
|
package/dist/access/GrantView.js
CHANGED
|
@@ -4,11 +4,11 @@ import { Combobox } from "../components/Combobox.js";
|
|
|
4
4
|
import { StatusBadge } from "../components/StatusBadge.js";
|
|
5
5
|
import { covers, grantPlan, isOwner } from "./model.js";
|
|
6
6
|
import { PrincipalPicker } from "./PrincipalPicker.js";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import { useId, useRef, useState } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
//#region src/access/GrantView.tsx
|
|
10
10
|
/** The grant form's body and footer, which the drawer lays out in its own body and footer. */
|
|
11
|
-
function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, t }) {
|
|
11
|
+
function useGrantView({ model, selection, onSelectionChange, resourceName, describeGroup, searchPrincipals, groupCount, peopleCount, recentPrincipalIds, cache, seen, saving, failure, onGrant, onCancel, focusLater, boundary, singleRole = false, t }) {
|
|
12
12
|
const uid = useId();
|
|
13
13
|
const [confirming, setConfirming] = useState(false);
|
|
14
14
|
const keepButton = useRef(null);
|
|
@@ -61,9 +61,13 @@ function useGrantView({ model, selection, onSelectionChange, resourceName, descr
|
|
|
61
61
|
};
|
|
62
62
|
const grant = () => {
|
|
63
63
|
setConfirming(false);
|
|
64
|
+
const revoke = singleRole ? [...new Set(plan.grant.map((granted) => granted.principalId))].flatMap((principalId) => (model.held.get(principalId) ?? []).filter((held) => !roleIds.includes(held.id)).map((held) => ({
|
|
65
|
+
principalId,
|
|
66
|
+
roleId: held.id
|
|
67
|
+
}))) : [];
|
|
64
68
|
onGrant({
|
|
65
69
|
grant: plan.grant,
|
|
66
|
-
revoke
|
|
70
|
+
revoke
|
|
67
71
|
});
|
|
68
72
|
};
|
|
69
73
|
const statusId = `${uid}status`;
|
|
@@ -98,7 +102,16 @@ function useGrantView({ model, selection, onSelectionChange, resourceName, descr
|
|
|
98
102
|
htmlFor: `${uid}roles`,
|
|
99
103
|
className: "mb-1.5 block text-sm font-medium",
|
|
100
104
|
children: t.rolesLabel
|
|
101
|
-
}), /* @__PURE__ */ jsx(Combobox, {
|
|
105
|
+
}), singleRole ? /* @__PURE__ */ jsx(Combobox, {
|
|
106
|
+
id: `${uid}roles`,
|
|
107
|
+
items: roleItems,
|
|
108
|
+
value: roleIds[0] ?? null,
|
|
109
|
+
onValueChange: (next) => onSelectionChange({
|
|
110
|
+
principalIds,
|
|
111
|
+
roleIds: next === null ? [] : [next]
|
|
112
|
+
}),
|
|
113
|
+
placeholder: t.searchRoles
|
|
114
|
+
}) : /* @__PURE__ */ jsx(Combobox, {
|
|
102
115
|
multiple: true,
|
|
103
116
|
id: `${uid}roles`,
|
|
104
117
|
items: roleItems,
|
|
@@ -9,8 +9,8 @@ import { Combobox } from "../components/Combobox.js";
|
|
|
9
9
|
import { useRelativeTime } from "../components/relativeTime.js";
|
|
10
10
|
import { StatusBadge } from "../components/StatusBadge.js";
|
|
11
11
|
import { covers, isOwner } from "./model.js";
|
|
12
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
12
|
import { useEffect, useMemo, useState } from "react";
|
|
13
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
//#region src/access/PrincipalPicker.tsx
|
|
15
15
|
/** Waits this long on a highlighted group before asking for its details, so arrowing past
|
|
16
16
|
* groups doesn't ask for each one. */
|
|
@@ -124,7 +124,7 @@ function PrincipalPicker({ model, value, onValueChange, granting, describeGroup,
|
|
|
124
124
|
return principal?.kind === "everyone" ? t.everyoneInOrganization : principal?.name ?? principalId;
|
|
125
125
|
};
|
|
126
126
|
const highlightedPrincipal = highlighted === void 0 ? void 0 : seen.get(highlighted);
|
|
127
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Combobox, {
|
|
127
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Combobox, {
|
|
128
128
|
multiple: true,
|
|
129
129
|
id,
|
|
130
130
|
"aria-describedby": describedBy,
|
|
@@ -261,7 +261,7 @@ function Updated({ value, t }) {
|
|
|
261
261
|
});
|
|
262
262
|
}
|
|
263
263
|
function DetailsLine({ details, t }) {
|
|
264
|
-
return /* @__PURE__ */ jsx(Fragment, { children: [details.source === "synced" && t.syncedShort, memberLine(details, 2, t)].filter(Boolean).join(" · ") });
|
|
264
|
+
return /* @__PURE__ */ jsx(Fragment$1, { children: [details.source === "synced" && t.syncedShort, memberLine(details, 2, t)].filter(Boolean).join(" · ") });
|
|
265
265
|
}
|
|
266
266
|
/** What the highlighted one holds here, and what granting the picked roles would change. */
|
|
267
267
|
function OnResource({ principalId, model, granting, t }) {
|
|
@@ -383,7 +383,7 @@ function GroupDetailsPane({ group, state, model, granting, t }) {
|
|
|
383
383
|
className: "rounded-full"
|
|
384
384
|
})
|
|
385
385
|
]
|
|
386
|
-
}) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
386
|
+
}) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
387
387
|
state.failed && /* @__PURE__ */ jsx("p", {
|
|
388
388
|
className: "m-0 text-xs text-(--theme-error-text)",
|
|
389
389
|
children: t.detailsFailed
|
|
@@ -394,7 +394,7 @@ function GroupDetailsPane({ group, state, model, granting, t }) {
|
|
|
394
394
|
}),
|
|
395
395
|
count !== void 0 && /* @__PURE__ */ jsxs("div", { children: [
|
|
396
396
|
/* @__PURE__ */ jsx(PaneHeading, { children: everyone ? t.people(count) : t.members(count) }),
|
|
397
|
-
details && details.members.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Faces, {
|
|
397
|
+
details && details.members.length > 0 && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Faces, {
|
|
398
398
|
details,
|
|
399
399
|
t
|
|
400
400
|
}), /* @__PURE__ */ jsx("p", {
|
package/dist/access/focus.js
CHANGED
|
@@ -5,7 +5,7 @@ import { useCallback, useEffect, useRef } from "react";
|
|
|
5
5
|
* later, which would undo wherever focus is sent next; parked, nothing is lost and it doesn't. */
|
|
6
6
|
function holdFocus() {
|
|
7
7
|
const active = document.activeElement;
|
|
8
|
-
const dialog = active instanceof HTMLElement ? active.closest("[role=\"dialog\"]") : null;
|
|
8
|
+
const dialog = active instanceof HTMLElement ? active.closest("[role=\"dialog\"], [data-access-panel]") : null;
|
|
9
9
|
if (dialog && dialog !== active) dialog.focus({ preventScroll: true });
|
|
10
10
|
}
|
|
11
11
|
/** Returns a function that sends focus to what `find` returns once the change it goes with
|
package/dist/access/index.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { type AccessArrangement, AccessDrawer, type AccessDrawerProps } from './AccessDrawer.js';
|
|
1
|
+
export { type AccessArrangement, AccessDrawer, type AccessDrawerProps, type AccessEditorProps, type AccessManagedElsewhere, AccessPanel, type AccessPanelProps, } from './AccessDrawer.js';
|
|
2
2
|
export { ACCESS_STRINGS, type AccessStrings, type AccessText, useAccessStrings, } from './strings.js';
|
|
3
|
-
export type { AccessChange, AccessGrant, AccessGroupDetails, AccessInheritedGrant, AccessMember, AccessPermission, AccessPrincipal, AccessRole, } from './types.js';
|
|
3
|
+
export type { AccessChange, AccessGrant, AccessGroupDetails, AccessInheritedGrant, AccessMember, AccessPermission, AccessPrincipal, AccessRole, AccessRule, AccessVisibility, } from './types.js';
|
package/dist/access/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ACCESS_STRINGS, useAccessStrings } from "./strings.js";
|
|
2
|
-
import { AccessDrawer } from "./AccessDrawer.js";
|
|
3
|
-
export { ACCESS_STRINGS, AccessDrawer, useAccessStrings };
|
|
2
|
+
import { AccessDrawer, AccessPanel } from "./AccessDrawer.js";
|
|
3
|
+
export { ACCESS_STRINGS, AccessDrawer, AccessPanel, useAccessStrings };
|
package/dist/access/strings.d.ts
CHANGED
|
@@ -66,7 +66,9 @@ export declare const ACCESS_STRINGS: {
|
|
|
66
66
|
removeFailed: (principal: string, roles: readonly string[]) => string;
|
|
67
67
|
grantFailed: (principals: readonly string[], roles: readonly string[]) => string;
|
|
68
68
|
undoFailed: string;
|
|
69
|
-
/**
|
|
69
|
+
/** Why a save failed, when the host gives no `errorMessage`. */
|
|
70
|
+
failedReason: string;
|
|
71
|
+
/** Under a failed save; `reason` is the host's `errorMessage`, or `failedReason`. */
|
|
70
72
|
nothingChanged: (reason: string | undefined) => string;
|
|
71
73
|
/** The toast after a grant. */
|
|
72
74
|
granted: (principals: readonly string[], roles: readonly string[]) => string;
|
|
@@ -74,8 +76,30 @@ export declare const ACCESS_STRINGS: {
|
|
|
74
76
|
removed: (principals: readonly string[], roles: readonly string[]) => string;
|
|
75
77
|
undone: string;
|
|
76
78
|
readOnly: string;
|
|
79
|
+
/** A note atop access set somewhere else, when the host gives no reason. */
|
|
80
|
+
managedElsewhere: string;
|
|
81
|
+
/** The note's link to where access is set, when the host doesn't name it. */
|
|
82
|
+
manageAccess: string;
|
|
77
83
|
/** After `readOnly` when the host gives no reason. */
|
|
78
84
|
readOnlyReason: string;
|
|
85
|
+
/** Names the switch between open to everyone and only those listed. */
|
|
86
|
+
visibility: string;
|
|
87
|
+
/** The switch's choice that limits it to the people and groups listed. */
|
|
88
|
+
restrictedLabel: string;
|
|
89
|
+
/** The toast after the switch saves; `choice` is the label now chosen. */
|
|
90
|
+
visibilityChanged: (choice: string) => string;
|
|
91
|
+
visibilityFailed: (choice: string) => string;
|
|
92
|
+
/** Names the role picker on a row where each person or group holds one role. */
|
|
93
|
+
roleFor: (principal: string) => string;
|
|
94
|
+
/** A row menu's submenu of roles. */
|
|
95
|
+
roleMenu: string;
|
|
96
|
+
/** A row menu's action that takes every role the row holds here. */
|
|
97
|
+
removeAccess: string;
|
|
98
|
+
/** The toast after a row's one role is swapped for another. */
|
|
99
|
+
roleChanged: (principal: string, role: string) => string;
|
|
100
|
+
roleChangeFailed: (principal: string, role: string) => string;
|
|
101
|
+
/** Read with a rule's faces: the first few by name, and how many more. */
|
|
102
|
+
ruleMembers: (names: readonly string[], more: number) => string;
|
|
79
103
|
emptyTitle: string;
|
|
80
104
|
emptyDescription: (resource: string) => string;
|
|
81
105
|
noMatches: string;
|
package/dist/access/strings.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useStrings } from "../components/Provider.js";
|
|
2
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
2
|
import { useMemo } from "react";
|
|
3
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
4
4
|
//#region src/access/strings.tsx
|
|
5
5
|
var plural = new Intl.PluralRules("en");
|
|
6
6
|
var list = new Intl.ListFormat("en", { type: "conjunction" });
|
|
@@ -91,7 +91,9 @@ var ACCESS_STRINGS = {
|
|
|
91
91
|
removeFailed: (principal, roles) => `Couldn’t remove ${principal} from ${and(roles)}`,
|
|
92
92
|
grantFailed: (principals, roles) => `Couldn’t grant ${and(roles)} to ${and(principals)}`,
|
|
93
93
|
undoFailed: "Couldn’t undo the change",
|
|
94
|
-
/**
|
|
94
|
+
/** Why a save failed, when the host gives no `errorMessage`. */
|
|
95
|
+
failedReason: "Something went wrong.",
|
|
96
|
+
/** Under a failed save; `reason` is the host's `errorMessage`, or `failedReason`. */
|
|
95
97
|
nothingChanged: (reason) => reason ? `${reason.replace(/\.?$/, ".")} Nothing changed.` : "Nothing changed.",
|
|
96
98
|
/** The toast after a grant. */
|
|
97
99
|
granted: (principals, roles) => `Granted ${and(roles)} to ${and(principals)}`,
|
|
@@ -99,8 +101,30 @@ var ACCESS_STRINGS = {
|
|
|
99
101
|
removed: (principals, roles) => `Removed ${and(principals)} from ${and(roles)}`,
|
|
100
102
|
undone: "Change undone",
|
|
101
103
|
readOnly: "View only.",
|
|
104
|
+
/** A note atop access set somewhere else, when the host gives no reason. */
|
|
105
|
+
managedElsewhere: "Access here is set somewhere else, so it can’t be changed here.",
|
|
106
|
+
/** The note's link to where access is set, when the host doesn't name it. */
|
|
107
|
+
manageAccess: "Manage access",
|
|
102
108
|
/** After `readOnly` when the host gives no reason. */
|
|
103
109
|
readOnlyReason: "Only people who manage access can make changes.",
|
|
110
|
+
/** Names the switch between open to everyone and only those listed. */
|
|
111
|
+
visibility: "Who can see it",
|
|
112
|
+
/** The switch's choice that limits it to the people and groups listed. */
|
|
113
|
+
restrictedLabel: "Only people with access",
|
|
114
|
+
/** The toast after the switch saves; `choice` is the label now chosen. */
|
|
115
|
+
visibilityChanged: (choice) => `Changed to ${choice}`,
|
|
116
|
+
visibilityFailed: (choice) => `Couldn’t change to ${choice}`,
|
|
117
|
+
/** Names the role picker on a row where each person or group holds one role. */
|
|
118
|
+
roleFor: (principal) => `Role for ${principal}`,
|
|
119
|
+
/** A row menu's submenu of roles. */
|
|
120
|
+
roleMenu: "Role",
|
|
121
|
+
/** A row menu's action that takes every role the row holds here. */
|
|
122
|
+
removeAccess: "Remove access",
|
|
123
|
+
/** The toast after a row's one role is swapped for another. */
|
|
124
|
+
roleChanged: (principal, role) => `Changed ${principal} to ${role}`,
|
|
125
|
+
roleChangeFailed: (principal, role) => `Couldn’t change ${principal} to ${role}`,
|
|
126
|
+
/** Read with a rule's faces: the first few by name, and how many more. */
|
|
127
|
+
ruleMembers: (names, more) => more > 0 ? `Includes ${and([...names, `${more.toLocaleString()} more`])}` : `Includes ${and(names)}`,
|
|
104
128
|
emptyTitle: "No access granted",
|
|
105
129
|
emptyDescription: (resource) => `Grant a role to a person or group to give them access to ${resource}.`,
|
|
106
130
|
noMatches: "No matches",
|
|
@@ -132,7 +156,7 @@ var ACCESS_STRINGS = {
|
|
|
132
156
|
alreadyCovered: (roles) => `Included in ${and(roles)}`,
|
|
133
157
|
everyoneHasIt: "Already granted to Everyone",
|
|
134
158
|
/** The footer's account of what pressing Grant does. */
|
|
135
|
-
grantSummary: (principals, roles) => /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("strong", {
|
|
159
|
+
grantSummary: (principals, roles) => /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("strong", {
|
|
136
160
|
className: "font-medium text-(--theme-app)",
|
|
137
161
|
children: and(roles)
|
|
138
162
|
}), ` for ${and(principals)}`] }),
|
package/dist/access/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
1
2
|
import type { TimeValue } from '../format.js';
|
|
2
3
|
/** A named set of permissions. People and groups are granted roles, never permissions one by
|
|
3
4
|
* one. */
|
|
@@ -72,3 +73,28 @@ export interface AccessGroupDetails {
|
|
|
72
73
|
/** When its membership last changed. */
|
|
73
74
|
updatedAt?: TimeValue;
|
|
74
75
|
}
|
|
76
|
+
/** A reason someone has access that no grant here changes, such as "Workspace admins always
|
|
77
|
+
* have access". It shows, locked, ahead of the grants. */
|
|
78
|
+
export interface AccessRule {
|
|
79
|
+
id: string;
|
|
80
|
+
/** In the leading column, in place of a section's chevron. */
|
|
81
|
+
icon?: ReactNode;
|
|
82
|
+
title: string;
|
|
83
|
+
/** A line under the title, such as who sets it. */
|
|
84
|
+
detail?: string | undefined;
|
|
85
|
+
/** A few of the people it covers, shown as overlapping faces: four, then how many more. */
|
|
86
|
+
people?: readonly AccessMember[] | undefined;
|
|
87
|
+
/** The role it gives, when it gives everyone it covers the same one. */
|
|
88
|
+
roleId?: string | undefined;
|
|
89
|
+
}
|
|
90
|
+
/** Whether a resource is open to everyone who can see what it is in, or only to those listed. */
|
|
91
|
+
export interface AccessVisibility {
|
|
92
|
+
restricted: boolean;
|
|
93
|
+
/** Saves the switch, as `onChange` saves a grant: until the promise settles the switch shows
|
|
94
|
+
* it is saving, and when it rejects the panel says nothing changed and offers to retry. */
|
|
95
|
+
onChange: (restricted: boolean) => void | Promise<unknown>;
|
|
96
|
+
/** The open choice, which names what it is open to: "Everyone in the workspace". */
|
|
97
|
+
openLabel: string;
|
|
98
|
+
/** The restricted choice; defaults to the strings' "Only people with access". */
|
|
99
|
+
restrictedLabel?: string | undefined;
|
|
100
|
+
}
|
|
@@ -4,8 +4,8 @@ import { useChatConfig } from "../core/config.js";
|
|
|
4
4
|
import { useChat } from "../core/ChatProvider.js";
|
|
5
5
|
import { chipClassName } from "../ui/chip.js";
|
|
6
6
|
import { isOrgModel } from "../utils.js";
|
|
7
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
7
|
import { useEffect } from "react";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
9
|
import useSWR from "swr";
|
|
10
10
|
//#region src/ai/components/AllocationSelector.tsx
|
|
11
11
|
var dollars = new Intl.NumberFormat(void 0, {
|