alinea 2.0.0-preview.11 → 2.0.0-preview.13
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/dist/.init/content/pages/welcome.json +1 -1
- package/dist/.mcp/later/dev.json +1 -1
- package/dist/.mcp/online/dev.json +1 -1
- package/dist/adapter/next/cms.js +16 -8
- package/dist/adapter/next/dashboardUrl.d.ts +6 -0
- package/dist/adapter/next/dashboardUrl.js +13 -0
- package/dist/adapter/next/syncCheck.d.ts +15 -2
- package/dist/adapter/next/syncCheck.js +26 -9
- package/dist/backend/Handler.js +5 -1
- package/dist/backend/api/BlobStore.d.ts +21 -0
- package/dist/backend/api/BlobStore.js +63 -0
- package/dist/backend/api/CreateBackend.js +10 -8
- package/dist/backend/api/DatabaseApi.d.ts +4 -1
- package/dist/backend/api/DatabaseApi.js +88 -4
- package/dist/backend/api/GithubApi.js +47 -24
- package/dist/backend/api/database.js +6 -6
- package/dist/bundled.d.ts +687 -248
- package/dist/chunks/{bun-sqlite-5SHXN3AT.js → bun-sqlite-RI6BYU5S.js} +3 -3
- package/dist/chunks/{chunk-YCQR5GRT.js → chunk-3QFSGTGF.js} +2 -3
- package/dist/chunks/{chunk-QJGGYF6E.js → chunk-4ZA6KZHS.js} +5 -5
- package/dist/chunks/{chunk-ASYKC6IE.js → chunk-5H4D5JQL.js} +1 -1
- package/dist/chunks/{chunk-ETWOY4AL.js → chunk-A2I6MCCS.js} +1 -1
- package/dist/chunks/{chunk-W5AXN7GH.js → chunk-CYVOGRSD.js} +1 -2
- package/dist/chunks/{chunk-TIJTT5ZI.js → chunk-G43W7AME.js} +1 -0
- package/dist/chunks/{chunk-RE523BQ7.js → chunk-HOETF6HN.js} +5829 -5830
- package/dist/chunks/{chunk-AIU6CMVT.js → chunk-PTYZMV5G.js} +1 -1
- package/dist/chunks/{chunk-JOF663EG.js → chunk-QHHMKJUO.js} +1 -1
- package/dist/chunks/{chunk-66YZ47TY.js → chunk-RAR44T5O.js} +1 -1
- package/dist/chunks/{chunk-QSN6RH6X.js → chunk-VA6NC3MI.js} +1 -1
- package/dist/chunks/{node-sqlite-XVNTNMCY.js → node-sqlite-C7VJ2NSN.js} +3 -3
- package/dist/cli/Mcp.js +1 -1
- package/dist/cli/Serve.js +1 -1
- package/dist/cli/bin.js +2 -3
- package/dist/cli/generate/GenerateDashboard.js +17 -5
- package/dist/cli/serve/mcp/DevMcp.js +1 -1
- package/dist/cli/serve/mcp/McpTools.js +29 -1
- package/dist/cli/static/dashboard/entry.js +2 -1
- package/dist/cloud/CloudRemote.js +1 -1
- package/dist/components/Alert.js +3 -3
- package/dist/components/AppShell.js +2 -2
- package/dist/components/Badge.d.ts +3 -1
- package/dist/components/Badge.js +5 -3
- package/dist/components/Breadcrumbs.js +6 -6
- package/dist/components/Button.d.ts +6 -1
- package/dist/components/Button.js +14 -5
- package/dist/components/Calendar.js +20 -20
- package/dist/components/Checkbox.js +9 -9
- package/dist/components/CheckboxGroup.js +4 -4
- package/dist/components/Collapsible.js +3 -3
- package/dist/components/ColorSwatch.js +2 -2
- package/dist/components/ColorSwatchPicker.js +2 -2
- package/dist/components/ComboBox.js +7 -7
- package/dist/components/Command.js +10 -9
- package/dist/components/ContentCard.d.ts +3 -1
- package/dist/components/ContentCard.js +39 -17
- package/dist/components/ContentGrid.js +15 -15
- package/dist/components/DataList.js +2 -2
- package/dist/components/DateField.js +2 -2
- package/dist/components/DatePicker.js +2 -2
- package/dist/components/DateRangePicker.js +2 -2
- package/dist/components/Dialog.js +6 -6
- package/dist/components/DropZone.js +4 -4
- package/dist/components/DropdownMenu.js +10 -10
- package/dist/components/Empty.js +4 -4
- package/dist/components/Field.js +8 -8
- package/dist/components/List.js +23 -23
- package/dist/components/MediaPreview.js +5 -5
- package/dist/components/MultipleSelect.js +20 -20
- package/dist/components/NavRail.js +4 -4
- package/dist/components/NumberField.js +5 -5
- package/dist/components/Page.js +5 -5
- package/dist/components/Popover.js +2 -2
- package/dist/components/PreviewFrame.js +5 -5
- package/dist/components/RadioGroup.js +6 -6
- package/dist/components/Resizable.js +5 -5
- package/dist/components/SearchField.d.ts +6 -1
- package/dist/components/SearchField.js +7 -5
- package/dist/components/Select.js +14 -14
- package/dist/components/Sheet.d.ts +50 -0
- package/dist/components/Sheet.js +202 -0
- package/dist/components/Sidebar.js +4 -4
- package/dist/components/SortableList.d.ts +34 -30
- package/dist/components/SortableList.js +162 -265
- package/dist/components/Spinner.js +1 -1
- package/dist/components/Surface.js +2 -2
- package/dist/components/Switch.js +7 -7
- package/dist/components/Table.d.ts +3 -1
- package/dist/components/Table.js +53 -42
- package/dist/components/Tabs.js +5 -5
- package/dist/components/TagGroup.js +9 -9
- package/dist/components/TextField.js +10 -10
- package/dist/components/TimeField.js +8 -8
- package/dist/components/Timestamp.js +1 -1
- package/dist/components/ToggleGroup.js +2 -2
- package/dist/components/Toolbar.js +4 -4
- package/dist/components/Tooltip.js +5 -5
- package/dist/components/Tree.js +29 -29
- package/dist/components/internal/DateControl.js +10 -10
- package/dist/components/internal/ListBoxOption.js +13 -13
- package/dist/components/internal/Locale.js +2 -2
- package/dist/components/internal/PopoverSurface.js +2 -2
- package/dist/components/internal/SelectionCheckbox.js +6 -6
- package/dist/components/internal/Slot.js +1 -1
- package/dist/components/internal/ToggleButton.js +3 -3
- package/dist/components/internal/Trigger.js +2 -2
- package/dist/components/internal/sortableDrag.d.ts +19 -0
- package/dist/components/internal/sortableDrag.js +175 -0
- package/dist/components/internal/useDragDrop.js +2 -2
- package/dist/components.d.ts +1 -0
- package/dist/components.js +1 -0
- package/dist/core/Config.d.ts +6 -1
- package/dist/core/Document.d.ts +9 -1
- package/dist/core/Document.js +31 -6
- package/dist/core/Overview.d.ts +2 -4
- package/dist/core/TextDoc.d.ts +4 -0
- package/dist/core/Validation.d.ts +0 -1
- package/dist/core/Validation.js +0 -6
- package/dist/core/field/RichTextField.js +23 -4
- package/dist/core/media/MediaTypes.js +1 -1
- package/dist/core/source/GithubSource.d.ts +4 -0
- package/dist/core/source/GithubSource.js +127 -25
- package/dist/core/source/GithubUsage.d.ts +21 -0
- package/dist/core/source/GithubUsage.js +47 -0
- package/dist/dashboard/App.d.ts +2 -2
- package/dist/dashboard/App.js +5 -3
- package/dist/dashboard/ViewKeys.d.ts +1 -0
- package/dist/dashboard/ViewKeys.js +1 -0
- package/dist/dashboard/app/ActivityStatus.js +11 -11
- package/dist/dashboard/app/AuthView.js +5 -5
- package/dist/dashboard/app/BlockSheet.d.ts +50 -0
- package/dist/dashboard/app/BlockSheet.js +207 -0
- package/dist/dashboard/app/BlockSheetStoryFrame.d.ts +6 -0
- package/dist/dashboard/app/BlockSheetStoryFrame.js +29 -0
- package/dist/dashboard/app/CompactField.js +15 -15
- package/dist/dashboard/app/CroppedImage.js +2 -2
- package/dist/dashboard/app/DashboardErrorBoundary.js +3 -3
- package/dist/dashboard/app/DashboardLayout.js +3 -1
- package/dist/dashboard/app/EntryHeader.js +32 -33
- package/dist/dashboard/app/EntryReferences.js +5 -5
- package/dist/dashboard/app/EntrySidebar.js +8 -8
- package/dist/dashboard/app/EntrySidebarPreview.js +4 -4
- package/dist/dashboard/app/EntryStatusIcon.d.ts +23 -0
- package/dist/dashboard/app/EntryStatusIcon.js +58 -0
- package/dist/dashboard/app/EntryValidationModal.d.ts +6 -5
- package/dist/dashboard/app/EntryValidationModal.js +18 -18
- package/dist/dashboard/app/Explorer.d.ts +3 -1
- package/dist/dashboard/app/Explorer.js +51 -47
- package/dist/dashboard/app/ExplorerBatchActions.d.ts +3 -1
- package/dist/dashboard/app/ExplorerBatchActions.js +68 -43
- package/dist/dashboard/app/ExplorerCards.js +7 -1
- package/dist/dashboard/app/ExplorerControls.js +6 -6
- package/dist/dashboard/app/ExplorerList.js +5 -5
- package/dist/dashboard/app/ExplorerModal.js +1 -1
- package/dist/dashboard/app/ExplorerTable.js +14 -11
- package/dist/dashboard/app/ImageEditor.js +25 -25
- package/dist/dashboard/app/ImagePicker.js +3 -13
- package/dist/dashboard/app/LinkPicker.js +29 -27
- package/dist/dashboard/app/LocaleMenu.js +7 -7
- package/dist/dashboard/app/MediaPreviewCell.js +2 -2
- package/dist/dashboard/app/MoveConfirmDialog.d.ts +5 -0
- package/dist/dashboard/app/MoveConfirmDialog.js +79 -0
- package/dist/dashboard/app/OverviewCell.js +8 -13
- package/dist/dashboard/app/ReadOnlyBadge.d.ts +1 -1
- package/dist/dashboard/app/RemoveDialog.d.ts +17 -0
- package/dist/dashboard/app/{DeleteDialog.js → RemoveDialog.js} +67 -27
- package/dist/dashboard/app/RemoveRedirect.d.ts +7 -0
- package/dist/dashboard/app/RemoveRedirect.js +123 -0
- package/dist/dashboard/app/SearchBar.d.ts +9 -0
- package/dist/dashboard/app/SearchBar.js +31 -0
- package/dist/dashboard/app/SidebarTree.js +29 -74
- package/dist/dashboard/app/WorkspaceMenu.js +8 -8
- package/dist/dashboard/app/WorkspaceRoots.js +11 -11
- package/dist/dashboard/app/editor/FileEditor.js +16 -16
- package/dist/dashboard/app/modals/CreateEntry.js +5 -5
- package/dist/dashboard/app/pages/EntryPage.d.ts +2 -1
- package/dist/dashboard/app/pages/EntryPage.js +35 -16
- package/dist/dashboard/app/pages/SplashPage.js +35 -35
- package/dist/dashboard/app/pages/UsersPage.js +14 -14
- package/dist/dashboard/app/ui/DashboardModal.js +17 -16
- package/dist/dashboard/atoms/dashboard.js +1 -1
- package/dist/dashboard/atoms/entry.js +1 -14
- package/dist/dashboard/atoms/entryTable.js +1 -0
- package/dist/dashboard/atoms/explorer.d.ts +4 -0
- package/dist/dashboard/atoms/explorer.js +19 -7
- package/dist/dashboard/atoms/graph.js +1 -1
- package/dist/dashboard/atoms/link.js +5 -2
- package/dist/dashboard/atoms/move.d.ts +5 -0
- package/dist/dashboard/atoms/move.js +29 -3
- package/dist/dashboard/atoms/moveConfirmation.d.ts +34 -0
- package/dist/dashboard/atoms/moveConfirmation.js +95 -0
- package/dist/dashboard/atoms/nav.d.ts +9 -5
- package/dist/dashboard/atoms/nav.js +120 -45
- package/dist/dashboard/atoms/overview.d.ts +6 -5
- package/dist/dashboard/atoms/overview.js +2 -16
- package/dist/dashboard/atoms/remove.d.ts +112 -0
- package/dist/dashboard/atoms/remove.js +268 -0
- package/dist/dashboard/atoms/root.d.ts +2 -2
- package/dist/dashboard/atoms/root.js +41 -26
- package/dist/dashboard/atoms/user.js +1 -1
- package/dist/dashboard/atoms/utils.js +1 -1
- package/dist/dashboard/boot/Boot.js +25 -17
- package/dist/dashboard/boot/BootProd.d.ts +6 -1
- package/dist/dashboard/boot/BootProd.js +2 -2
- package/dist/dashboard/boot/DashboardWorker.d.ts +1 -0
- package/dist/dashboard/boot/DashboardWorker.js +18 -18
- package/dist/dashboard/boot/LoadWorker.js +17 -10
- package/dist/dashboard/cms/EntryTable.js +6 -3
- package/dist/database/BrowserEntryStore.d.ts +17 -29
- package/dist/database/BrowserEntryStore.js +116 -144
- package/dist/database/DatabaseTables.js +2 -2
- package/dist/database/EntryDatabase.js +21 -1
- package/dist/database/EntryTransaction.js +0 -35
- package/dist/database/EntryUrlAliases.d.ts +4 -0
- package/dist/database/EntryUrlAliases.js +16 -10
- package/dist/database/driver/RuntimeDatabase.js +3 -3
- package/dist/database/driver/WasmDatabase.d.ts +5 -18
- package/dist/database/driver/WasmDatabase.js +15 -16
- package/dist/database/entry/EntryTable.js +2 -2
- package/dist/database/query/EntryQuery.js +1 -1
- package/dist/database/query/Relation.js +1 -1
- package/dist/database/query/Search.js +2 -2
- package/dist/field/check/CheckField.view.js +2 -2
- package/dist/field/code/CodeField.view.js +14 -14
- package/dist/field/link/EntryLink.d.ts +4 -4
- package/dist/field/link/FileLink.d.ts +4 -4
- package/dist/field/link/ImageLink.d.ts +4 -4
- package/dist/field/link/Link.d.ts +1 -1
- package/dist/field/link/LinkField.d.ts +5 -0
- package/dist/field/link/LinkField.view.js +246 -372
- package/dist/field/link/UrlLink.d.ts +4 -4
- package/dist/field/list/ListField.d.ts +2 -0
- package/dist/field/list/ListField.view.d.ts +15 -0
- package/dist/field/list/ListField.view.js +343 -301
- package/dist/field/metadata/MetadataField.d.ts +17 -7
- package/dist/field/metadata/MetadataField.js +14 -3
- package/dist/field/metadata/MetadataField.view.d.ts +1 -0
- package/dist/field/metadata/MetadataField.view.js +27 -23
- package/dist/field/richtext/RichTextBlock.d.ts +3 -1
- package/dist/field/richtext/RichTextBlock.js +178 -75
- package/dist/field/richtext/RichTextBlockHost.js +1 -1
- package/dist/field/richtext/RichTextExtensions.js +35 -35
- package/dist/field/richtext/RichTextField.view.js +14 -8
- package/dist/field/richtext/RichTextInsertMenu.js +43 -27
- package/dist/field/views.js +2 -0
- package/dist/index.css +490 -309
- package/dist/picker/url/UrlPicker.js +1 -0
- package/docs/components/badge.md +1 -0
- package/docs/components/button.md +1 -0
- package/docs/components/content-card.md +1 -0
- package/docs/components/search-field.md +1 -0
- package/docs/components/sortable-list.md +5 -20
- package/docs/components/table.md +1 -0
- package/docs/configuration.md +1 -1
- package/docs/deploy/self-host.md +1 -1
- package/docs/deploy.md +5 -4
- package/docs/fields.md +1 -1
- package/docs/index.md +1 -1
- package/docs/instant-publishing.md +7 -22
- package/docs/overviews.md +3 -4
- package/docs/upgrading.md +3 -2
- package/llms-full.txt +31 -55
- package/package.json +2 -3
- package/dist/core/db/EntryValidationError.d.ts +0 -13
- package/dist/core/db/EntryValidationError.js +0 -23
- package/dist/dashboard/app/DeleteDialog.d.ts +0 -11
- package/dist/dashboard/atoms/delete.d.ts +0 -68
- package/dist/dashboard/atoms/delete.js +0 -143
- package/dist/chunks/{chunk-MOWR65LM.js → chunk-PYDOMKJZ.js} +71 -71
|
@@ -7,12 +7,12 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
7
7
|
import { Config } from "alinea/core/Config";
|
|
8
8
|
import { MoveOperation } from "alinea/core/db/Operation";
|
|
9
9
|
import { Entry } from "alinea/core/Entry";
|
|
10
|
+
import { getRoot, getWorkspace } from "alinea/core/Internal";
|
|
10
11
|
import { MediaFile } from "alinea/core/media/MediaTypes";
|
|
11
12
|
import { Schema } from "alinea/core/Schema";
|
|
12
13
|
import { Type } from "alinea/core/Type";
|
|
13
14
|
import { entries } from "alinea/core/util/Objects";
|
|
14
15
|
import { configAtom, graphAtom } from "./core.js";
|
|
15
|
-
import { rootAtoms } from "./root.js";
|
|
16
16
|
import { policyAtom } from "./user.js";
|
|
17
17
|
function rootAcceptsType(config, rootData, typeName) {
|
|
18
18
|
const contains = rootData.contains;
|
|
@@ -36,10 +36,34 @@ function moveTargets(config, policy, rootData, selected, translated) {
|
|
|
36
36
|
const containers = entries(config.schema).filter(
|
|
37
37
|
([, parent]) => movable && !Type.isHidden(parent) && types.every((type) => type && Config.typeContains(config, parent, type))
|
|
38
38
|
).map(([name]) => name);
|
|
39
|
+
const canSelect = (item) => !moving.has(item.id) && !item.parents.some((parent) => moving.has(parent)) && (!translated || translated.has(item.id)) && policy.canMove(item);
|
|
39
40
|
return {
|
|
40
41
|
subjects,
|
|
41
42
|
condition: { _type: { in: containers } },
|
|
42
|
-
canSelect
|
|
43
|
+
canSelect,
|
|
44
|
+
refusal(parent) {
|
|
45
|
+
if (!movable) return "These entries can't be moved.";
|
|
46
|
+
const single = subjects.length === 1;
|
|
47
|
+
const these = single ? `"${first.title}"` : "these entries";
|
|
48
|
+
const These = single ? these : "These entries";
|
|
49
|
+
const kinds = typeNames.map((name) => Type.label(config.schema[name])).join(" or ");
|
|
50
|
+
if (!parent) {
|
|
51
|
+
if (!typeNames.every((name) => rootAcceptsType(config, rootData, name)))
|
|
52
|
+
return `${rootData.label} doesn't hold ${kinds} at its top level.`;
|
|
53
|
+
if (!policy.canMove({ workspace: first.workspace, root: first.root }))
|
|
54
|
+
return `You can't move entries to the top level of ${rootData.label}.`;
|
|
55
|
+
return void 0;
|
|
56
|
+
}
|
|
57
|
+
if (moving.has(parent.id) || parent.parents.some((id) => moving.has(id)))
|
|
58
|
+
return `${These} can't be moved into itself.`;
|
|
59
|
+
if (!containers.includes(parent.type))
|
|
60
|
+
return `"${parent.title}" can't hold ${kinds}.`;
|
|
61
|
+
if (translated && !translated.has(parent.id))
|
|
62
|
+
return `"${parent.title}" doesn't exist in every language of ${these}.`;
|
|
63
|
+
if (!policy.canMove(parent))
|
|
64
|
+
return `You can't move entries into "${parent.title}".`;
|
|
65
|
+
return void 0;
|
|
66
|
+
},
|
|
43
67
|
rootAccepts: movable && typeNames.every((name) => rootAcceptsType(config, rootData, name)) && policy.canMove({ workspace: first.workspace, root: first.root })
|
|
44
68
|
};
|
|
45
69
|
}
|
|
@@ -49,7 +73,9 @@ var loadMoveTargetsAtom = atom(
|
|
|
49
73
|
const config = get(configAtom);
|
|
50
74
|
const policy = get(policyAtom);
|
|
51
75
|
const [{ workspace, root }] = subjects;
|
|
52
|
-
const rootData =
|
|
76
|
+
const rootData = getRoot(
|
|
77
|
+
getWorkspace(config.workspaces[workspace]).roots[root]
|
|
78
|
+
);
|
|
53
79
|
const targets = moveTargets(config, policy, rootData, subjects);
|
|
54
80
|
if (!rootData.i18n) return targets;
|
|
55
81
|
const graph = get(graphAtom);
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DropTarget, Key } from 'alinea/components';
|
|
2
|
+
/**
|
|
3
|
+
* A dragged move to confirm: the pages it gives another parent, and so
|
|
4
|
+
* another url, or why it can not move there
|
|
5
|
+
*/
|
|
6
|
+
export interface MoveConfirmation {
|
|
7
|
+
pages: Array<{
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
}>;
|
|
11
|
+
refusal?: string;
|
|
12
|
+
resolve(confirmed: boolean): void;
|
|
13
|
+
}
|
|
14
|
+
/** Whether moving pages asks first, until the editor stops it here */
|
|
15
|
+
export declare const confirmMovesAtom: import("jotai").WritableAtom<boolean, [boolean | typeof import("jotai/utils").RESET | ((prev: boolean) => boolean | typeof import("jotai/utils").RESET)], void>;
|
|
16
|
+
/**
|
|
17
|
+
* The entries being dragged, known from the start of a drag so that drop
|
|
18
|
+
* targets can turn down the ones they can not hold
|
|
19
|
+
*/
|
|
20
|
+
export declare const draggedEntriesAtom: import("jotai").PrimitiveAtom<ReadonlySet<Key>> & {
|
|
21
|
+
init: ReadonlySet<Key>;
|
|
22
|
+
};
|
|
23
|
+
export declare const moveConfirmationAtom: import("jotai").PrimitiveAtom<MoveConfirmation | undefined> & {
|
|
24
|
+
init: MoveConfirmation | undefined;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Whether entries dropped on a target can move there, and the editor agrees:
|
|
28
|
+
* entries that get another parent follow the rules of moving them with the
|
|
29
|
+
* move dialog, and entries of a document type ask first, as their url and
|
|
30
|
+
* those of the pages below them change.
|
|
31
|
+
*/
|
|
32
|
+
export declare const confirmMoveAtom: import("jotai").WritableAtom<null, [ids: Iterable<string>, target: DropTarget], Promise<boolean>> & {
|
|
33
|
+
init: null;
|
|
34
|
+
};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import {
|
|
2
|
+
atomWithStorage
|
|
3
|
+
} from "../../chunks/chunk-G43W7AME.js";
|
|
4
|
+
import {
|
|
5
|
+
atom
|
|
6
|
+
} from "../../chunks/chunk-CFNRVI3Y.js";
|
|
7
|
+
import "../../chunks/chunk-CQ52GEHY.js";
|
|
8
|
+
|
|
9
|
+
// src/dashboard/atoms/moveConfirmation.ts
|
|
10
|
+
import { isDocument } from "alinea/core/Document";
|
|
11
|
+
import { Entry } from "alinea/core/Entry";
|
|
12
|
+
import { configAtom, graphAtom } from "./core.js";
|
|
13
|
+
import { loadMoveTargetsAtom } from "./move.js";
|
|
14
|
+
import { policyAtom } from "./user.js";
|
|
15
|
+
var confirmMovesAtom = atomWithStorage(
|
|
16
|
+
"alinea-dashboard-confirm-moves",
|
|
17
|
+
true,
|
|
18
|
+
void 0,
|
|
19
|
+
{ getOnInit: true }
|
|
20
|
+
);
|
|
21
|
+
var draggedEntriesAtom = atom(/* @__PURE__ */ new Set());
|
|
22
|
+
var moveConfirmationAtom = atom(
|
|
23
|
+
void 0
|
|
24
|
+
);
|
|
25
|
+
var moveItem = {
|
|
26
|
+
id: Entry.id,
|
|
27
|
+
title: Entry.title,
|
|
28
|
+
type: Entry.type,
|
|
29
|
+
workspace: Entry.workspace,
|
|
30
|
+
root: Entry.root,
|
|
31
|
+
locale: Entry.locale,
|
|
32
|
+
parentId: Entry.parentId,
|
|
33
|
+
parents: Entry.parents,
|
|
34
|
+
seeded: Entry.seeded
|
|
35
|
+
};
|
|
36
|
+
var confirmMoveAtom = atom(
|
|
37
|
+
null,
|
|
38
|
+
async (get, set, ids, target) => {
|
|
39
|
+
const graph = get(graphAtom);
|
|
40
|
+
const query = { status: "preferDraft", select: moveItem };
|
|
41
|
+
const [rows, dropped] = await Promise.all([
|
|
42
|
+
graph.find({ ...query, id: { in: [...ids] } }),
|
|
43
|
+
graph.first({ ...query, id: String(target.key) })
|
|
44
|
+
]);
|
|
45
|
+
if (!dropped) return false;
|
|
46
|
+
const subjects = [...new Map(rows.map((row) => [row.id, row])).values()];
|
|
47
|
+
const parentId = target.position === "on" ? dropped.id : dropped.parentId;
|
|
48
|
+
const moved = subjects.filter(
|
|
49
|
+
(subject) => subject.parentId !== parentId || subject.workspace !== dropped.workspace || subject.root !== dropped.root
|
|
50
|
+
);
|
|
51
|
+
if (moved.length === 0) return true;
|
|
52
|
+
const ask = (question) => new Promise(
|
|
53
|
+
(resolve) => set(moveConfirmationAtom, {
|
|
54
|
+
...question,
|
|
55
|
+
resolve(confirmed) {
|
|
56
|
+
set(moveConfirmationAtom, void 0);
|
|
57
|
+
resolve(confirmed);
|
|
58
|
+
}
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
const refusal = await moveRefusal(get, set, moved, dropped, parentId);
|
|
62
|
+
if (refusal) return ask({ pages: [], refusal }).then(() => false);
|
|
63
|
+
const { schema } = get(configAtom);
|
|
64
|
+
const pages = moved.filter((subject) => {
|
|
65
|
+
const type = schema[subject.type];
|
|
66
|
+
return type && isDocument(type);
|
|
67
|
+
});
|
|
68
|
+
if (pages.length === 0 || !get(confirmMovesAtom)) return true;
|
|
69
|
+
return ask({ pages: pages.map(({ id, title }) => ({ id, title })) });
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
async function moveRefusal(get, set, moved, dropped, parentId) {
|
|
73
|
+
const policy = get(policyAtom);
|
|
74
|
+
for (const subject of moved) {
|
|
75
|
+
if (subject.workspace !== dropped.workspace || subject.root !== dropped.root)
|
|
76
|
+
return "Entries can't be moved out of their root.";
|
|
77
|
+
if (subject.seeded)
|
|
78
|
+
return `"${subject.title}" is part of the site setup and can't be moved.`;
|
|
79
|
+
if (!policy.canMove(subject)) return `You can't move "${subject.title}".`;
|
|
80
|
+
}
|
|
81
|
+
const targets = await set(loadMoveTargetsAtom, moved);
|
|
82
|
+
if (parentId === null) return targets.refusal(null);
|
|
83
|
+
const parent = parentId === dropped.id ? dropped : await get(graphAtom).first({
|
|
84
|
+
id: parentId,
|
|
85
|
+
status: "preferDraft",
|
|
86
|
+
select: moveItem
|
|
87
|
+
});
|
|
88
|
+
return parent ? targets.refusal(parent) : "The new parent can't be found.";
|
|
89
|
+
}
|
|
90
|
+
export {
|
|
91
|
+
confirmMoveAtom,
|
|
92
|
+
confirmMovesAtom,
|
|
93
|
+
draggedEntriesAtom,
|
|
94
|
+
moveConfirmationAtom
|
|
95
|
+
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Atom, Getter } from 'jotai';
|
|
1
|
+
import { Atom, type Getter } from 'jotai';
|
|
2
2
|
import type { OverviewSort } from 'alinea/core/Overview';
|
|
3
3
|
import type { EntryDefaultView } from 'alinea/core/Type';
|
|
4
4
|
import { ReactNode } from 'react';
|
|
@@ -12,7 +12,9 @@ export declare const routeBlockAtom: import("jotai").PrimitiveAtom<RouteBlock |
|
|
|
12
12
|
init: RouteBlock | null;
|
|
13
13
|
};
|
|
14
14
|
export interface DashboardRoute {
|
|
15
|
-
|
|
15
|
+
/** An edit link names an entry by its url, until it is looked up */
|
|
16
|
+
page?: 'splash' | 'entry' | 'users' | 'edit';
|
|
17
|
+
url?: string;
|
|
16
18
|
workspace?: string;
|
|
17
19
|
root?: string;
|
|
18
20
|
entry?: string;
|
|
@@ -24,11 +26,13 @@ export interface DashboardRoute {
|
|
|
24
26
|
replace?: boolean;
|
|
25
27
|
}
|
|
26
28
|
interface ResolvedDashboardRoute extends DashboardRoute {
|
|
27
|
-
page: 'splash' | 'entry' | 'users';
|
|
29
|
+
page: 'splash' | 'entry' | 'users' | 'edit';
|
|
28
30
|
}
|
|
29
31
|
export declare const nav: {
|
|
30
32
|
splash(): string;
|
|
31
33
|
users(): string;
|
|
34
|
+
/** The editor of the entry at `url`, as linked from a page of the site */
|
|
35
|
+
edit(url: string, workspace?: string, root?: string): string;
|
|
32
36
|
entry(workspace?: string, root?: string, entryId?: string, locale?: string | null, view?: EntryDefaultView, sort?: string): string;
|
|
33
37
|
};
|
|
34
38
|
/** The url parameter of an overview sort: the column, prefixed with - when descending */
|
|
@@ -40,11 +44,11 @@ interface NavigationRequest {
|
|
|
40
44
|
route: ResolvedDashboardRoute;
|
|
41
45
|
}
|
|
42
46
|
/** @internal */
|
|
43
|
-
export declare const routeAtom: import("jotai").WritableAtom<ResolvedDashboardRoute, [update: DashboardRoute | NavigationRequest], void
|
|
47
|
+
export declare const routeAtom: import("jotai").WritableAtom<ResolvedDashboardRoute, [update: DashboardRoute | NavigationRequest], void | Promise<void>> & {
|
|
44
48
|
onMount(navigate: (request: NavigationRequest) => void): (() => void) | undefined;
|
|
45
49
|
};
|
|
46
50
|
export interface Page {
|
|
47
|
-
type: 'splash' | 'users' | 'entry';
|
|
51
|
+
type: 'splash' | 'users' | 'entry' | 'edit';
|
|
48
52
|
workspace: string | undefined;
|
|
49
53
|
root: string | undefined;
|
|
50
54
|
requestedRoot?: string;
|
|
@@ -58,9 +58,10 @@ function atomWithLocation(options) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
// src/dashboard/atoms/nav.ts
|
|
61
|
+
import { Entry } from "alinea/core/Entry";
|
|
61
62
|
import { getRoot } from "alinea/core/Internal";
|
|
62
63
|
import { workspaceAtom, workspacesAtom } from "./config.js";
|
|
63
|
-
import { configAtom } from "./core.js";
|
|
64
|
+
import { configAtom, graphAtom } from "./core.js";
|
|
64
65
|
import { policyAtom } from "./user.js";
|
|
65
66
|
import { dispense } from "./utils.js";
|
|
66
67
|
var routeGuardAtom = atom(null);
|
|
@@ -72,6 +73,13 @@ var nav = {
|
|
|
72
73
|
users() {
|
|
73
74
|
return "/users";
|
|
74
75
|
},
|
|
76
|
+
/** The editor of the entry at `url`, as linked from a page of the site */
|
|
77
|
+
edit(url, workspace, root) {
|
|
78
|
+
const params = new URLSearchParams({ url });
|
|
79
|
+
if (workspace) params.set("workspace", workspace);
|
|
80
|
+
if (root) params.set("root", root);
|
|
81
|
+
return `/edit?${params}`;
|
|
82
|
+
},
|
|
75
83
|
entry(workspace, root, entryId, locale, view, sort) {
|
|
76
84
|
const rootPart = root ? `${root}${locale ? `:${locale}` : ""}` : "";
|
|
77
85
|
const path = `/entry/${[workspace, rootPart, entryId].filter(Boolean).join("/")}`;
|
|
@@ -100,9 +108,17 @@ var overviewSortMemoryAtom = atom(/* @__PURE__ */ new Map());
|
|
|
100
108
|
function routeFromHash(hash) {
|
|
101
109
|
const [path, search = ""] = hash.slice(1).split("?");
|
|
102
110
|
const [action, workspace, rootPart = "", entry] = path.split("/").slice(1);
|
|
111
|
+
const params = new URLSearchParams(search);
|
|
112
|
+
const url = params.get("url");
|
|
113
|
+
if (action === "edit" && url)
|
|
114
|
+
return {
|
|
115
|
+
page: "edit",
|
|
116
|
+
url,
|
|
117
|
+
workspace: params.get("workspace") ?? void 0,
|
|
118
|
+
root: params.get("root") ?? void 0
|
|
119
|
+
};
|
|
103
120
|
const page2 = action === "users" ? "users" : action === "entry" ? "entry" : "splash";
|
|
104
121
|
const [root, locale] = rootPart.split(":");
|
|
105
|
-
const params = new URLSearchParams(search);
|
|
106
122
|
const view = params.get("view");
|
|
107
123
|
const sort = params.get("sort");
|
|
108
124
|
return {
|
|
@@ -118,6 +134,13 @@ function routeFromHash(hash) {
|
|
|
118
134
|
function routeFromUpdate(update) {
|
|
119
135
|
if (update.page === "users") return { page: "users" };
|
|
120
136
|
if (update.page === "splash") return { page: "splash" };
|
|
137
|
+
if (update.page === "edit")
|
|
138
|
+
return update.url ? {
|
|
139
|
+
page: "edit",
|
|
140
|
+
url: update.url,
|
|
141
|
+
workspace: update.workspace,
|
|
142
|
+
root: update.root
|
|
143
|
+
} : { page: "splash" };
|
|
121
144
|
return {
|
|
122
145
|
page: "entry",
|
|
123
146
|
workspace: update.workspace,
|
|
@@ -129,6 +152,8 @@ function routeFromUpdate(update) {
|
|
|
129
152
|
};
|
|
130
153
|
}
|
|
131
154
|
function hashFromRoute(route) {
|
|
155
|
+
if (route.page === "edit")
|
|
156
|
+
return `#${nav.edit(route.url ?? "/", route.workspace, route.root)}`;
|
|
132
157
|
return route.page === "splash" ? `#${nav.splash()}` : route.page === "users" ? `#${nav.users()}` : `#${nav.entry(
|
|
133
158
|
route.workspace,
|
|
134
159
|
route.root,
|
|
@@ -155,6 +180,7 @@ var initialRoute = routeFromHash(
|
|
|
155
180
|
);
|
|
156
181
|
var currentRouteAtom = atom(initialRoute);
|
|
157
182
|
var ignoredBrowserHash;
|
|
183
|
+
var linkLookups = 0;
|
|
158
184
|
var routeAtom = Object.assign(
|
|
159
185
|
atom(
|
|
160
186
|
(get) => get(currentRouteAtom),
|
|
@@ -163,58 +189,31 @@ var routeAtom = Object.assign(
|
|
|
163
189
|
route: routeFromUpdate(update),
|
|
164
190
|
replace: update.replace
|
|
165
191
|
};
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
if (
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
);
|
|
181
|
-
if (!syncLocation) return;
|
|
182
|
-
set(
|
|
183
|
-
locationAtom,
|
|
184
|
-
(location) => ({ ...location, hash: hashFromRoute(route) }),
|
|
185
|
-
{ replace }
|
|
186
|
-
);
|
|
187
|
-
};
|
|
188
|
-
const guard = get(routeGuardAtom);
|
|
189
|
-
if (guard && get(guard)) {
|
|
190
|
-
if (request.browser) {
|
|
191
|
-
ignoredBrowserHash = hashFromRoute(previous);
|
|
192
|
-
set(
|
|
193
|
-
locationAtom,
|
|
194
|
-
(location) => ({ ...location, hash: hashFromRoute(previous) }),
|
|
195
|
-
{ replace: true }
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
set(routeBlockAtom, {
|
|
199
|
-
confirm() {
|
|
200
|
-
set(routeBlockAtom, null);
|
|
201
|
-
commit(request.browser, true);
|
|
202
|
-
}
|
|
203
|
-
});
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
commit();
|
|
192
|
+
if (request.route.page !== "edit")
|
|
193
|
+
return navigate(get, set, request, "sort" in update);
|
|
194
|
+
const current = get(currentRouteAtom);
|
|
195
|
+
const lookup = ++linkLookups;
|
|
196
|
+
set(
|
|
197
|
+
locationAtom,
|
|
198
|
+
(location) => ({ ...location, hash: hashFromRoute(current) }),
|
|
199
|
+
{ replace: true }
|
|
200
|
+
);
|
|
201
|
+
return linkedRoute(get, request.route).catch(() => ({ page: "splash" })).then((route) => {
|
|
202
|
+
if (lookup !== linkLookups || get(currentRouteAtom) !== current)
|
|
203
|
+
return;
|
|
204
|
+
navigate(get, set, { route, replace: true }, true);
|
|
205
|
+
});
|
|
207
206
|
}
|
|
208
207
|
),
|
|
209
208
|
{
|
|
210
|
-
onMount(
|
|
209
|
+
onMount(navigate2) {
|
|
211
210
|
if (typeof window === "undefined") return;
|
|
212
211
|
const onNavigation = () => {
|
|
213
212
|
if (window.location.hash === ignoredBrowserHash) {
|
|
214
213
|
ignoredBrowserHash = void 0;
|
|
215
214
|
return;
|
|
216
215
|
}
|
|
217
|
-
|
|
216
|
+
navigate2({ browser: true, route: routeFromHash(window.location.hash) });
|
|
218
217
|
};
|
|
219
218
|
window.addEventListener("hashchange", onNavigation);
|
|
220
219
|
window.addEventListener("popstate", onNavigation);
|
|
@@ -226,6 +225,73 @@ var routeAtom = Object.assign(
|
|
|
226
225
|
}
|
|
227
226
|
}
|
|
228
227
|
);
|
|
228
|
+
function navigate(get, set, request, sortGiven) {
|
|
229
|
+
let { route } = request;
|
|
230
|
+
const key = sortKey(get, request);
|
|
231
|
+
const explicit = request.browser || route.sort !== void 0 || sortGiven;
|
|
232
|
+
if (key && !explicit) {
|
|
233
|
+
const sort = get(overviewSortMemoryAtom).get(key);
|
|
234
|
+
if (sort) route = { ...route, sort: formatOverviewSort(sort) };
|
|
235
|
+
}
|
|
236
|
+
const previous = get(currentRouteAtom);
|
|
237
|
+
const commit = (replace = request.replace ?? false, syncLocation = !request.browser) => {
|
|
238
|
+
set(currentRouteAtom, route);
|
|
239
|
+
if (key)
|
|
240
|
+
set(overviewSortMemoryAtom, (memory) => remember(memory, key, route.sort));
|
|
241
|
+
if (!syncLocation) return;
|
|
242
|
+
set(locationAtom, (location) => ({ ...location, hash: hashFromRoute(route) }), {
|
|
243
|
+
replace
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
const guard = get(routeGuardAtom);
|
|
247
|
+
if (guard && get(guard)) {
|
|
248
|
+
if (request.browser) {
|
|
249
|
+
ignoredBrowserHash = hashFromRoute(previous);
|
|
250
|
+
set(
|
|
251
|
+
locationAtom,
|
|
252
|
+
(location) => ({ ...location, hash: hashFromRoute(previous) }),
|
|
253
|
+
{ replace: true }
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
set(routeBlockAtom, {
|
|
257
|
+
confirm() {
|
|
258
|
+
set(routeBlockAtom, null);
|
|
259
|
+
commit(request.browser, true);
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
commit();
|
|
265
|
+
}
|
|
266
|
+
async function linkedRoute(get, { url = "/", workspace, root }) {
|
|
267
|
+
const graph = get(graphAtom);
|
|
268
|
+
const query = {
|
|
269
|
+
workspace,
|
|
270
|
+
root,
|
|
271
|
+
status: "preferDraft",
|
|
272
|
+
select: {
|
|
273
|
+
entry: Entry.id,
|
|
274
|
+
locale: Entry.locale,
|
|
275
|
+
workspace: Entry.workspace,
|
|
276
|
+
root: Entry.root
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
const urls = [.../* @__PURE__ */ new Set([withoutSlash(url), withoutSlash(decoded(url))])];
|
|
280
|
+
const live = { ...query, filter: { _status: { isNot: "archived" } } };
|
|
281
|
+
const found = await graph.first({ ...live, url: { in: urls } }) ?? await graph.first({ ...live, alias: { in: urls } }) ?? await graph.first({ ...query, url: { in: urls } });
|
|
282
|
+
if (!found) return { page: "splash" };
|
|
283
|
+
return { page: "entry", ...found, locale: found.locale ?? void 0 };
|
|
284
|
+
}
|
|
285
|
+
function decoded(url) {
|
|
286
|
+
try {
|
|
287
|
+
return decodeURI(url);
|
|
288
|
+
} catch {
|
|
289
|
+
return url;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
function withoutSlash(url) {
|
|
293
|
+
return url.length > 1 && url.endsWith("/") ? url.slice(0, -1) : url;
|
|
294
|
+
}
|
|
229
295
|
function sortKey(get, { browser, route }) {
|
|
230
296
|
if (route.page !== "entry") return void 0;
|
|
231
297
|
if (route.workspace && route.root)
|
|
@@ -244,6 +310,15 @@ function remember(memory, key, value) {
|
|
|
244
310
|
}
|
|
245
311
|
var pageAtom = atom((get) => resolvePage(get, get(routeAtom)));
|
|
246
312
|
function resolvePage(get, route) {
|
|
313
|
+
if (route.page === "edit")
|
|
314
|
+
return {
|
|
315
|
+
type: "edit",
|
|
316
|
+
workspace: void 0,
|
|
317
|
+
root: void 0,
|
|
318
|
+
entry: void 0,
|
|
319
|
+
locale: null,
|
|
320
|
+
view: void 0
|
|
321
|
+
};
|
|
247
322
|
const config = get(configAtom);
|
|
248
323
|
const policy = get(policyAtom);
|
|
249
324
|
const workspaces = get(workspacesAtom);
|
|
@@ -11,7 +11,7 @@ import { type RootData } from 'alinea/core/Root';
|
|
|
11
11
|
import { Type } from 'alinea/core/Type';
|
|
12
12
|
import type { View } from 'alinea/core/View';
|
|
13
13
|
/** The columns every overview can show next to its configured columns */
|
|
14
|
-
export type OverviewBuiltinColumn = 'type' | '
|
|
14
|
+
export type OverviewBuiltinColumn = 'type' | 'updated' | 'author';
|
|
15
15
|
/** The number of `overview: true` fields shown when a parent has no columns */
|
|
16
16
|
export declare const overviewFieldColumnLimit = 5;
|
|
17
17
|
/** Where a list of entries lives, its overview is configured there */
|
|
@@ -109,7 +109,7 @@ export interface OverviewResolveOptions {
|
|
|
109
109
|
*/
|
|
110
110
|
mixed?: boolean;
|
|
111
111
|
/**
|
|
112
|
-
* The listed children grouped by type
|
|
112
|
+
* The listed children grouped by type, see `summarizeRows`.
|
|
113
113
|
* The columns then follow the children: the types present, and built-in
|
|
114
114
|
* columns only when they tell the children apart.
|
|
115
115
|
*/
|
|
@@ -158,6 +158,8 @@ export interface OverviewRow {
|
|
|
158
158
|
path: string;
|
|
159
159
|
url?: string;
|
|
160
160
|
status?: EntryStatus;
|
|
161
|
+
/** The version is the main one, a draft then was never published */
|
|
162
|
+
main?: boolean;
|
|
161
163
|
locale: string | null;
|
|
162
164
|
workspace: string;
|
|
163
165
|
root: string;
|
|
@@ -186,17 +188,16 @@ export declare function linkedEntryId(value: unknown): string | undefined;
|
|
|
186
188
|
export declare const openEntryAtom: import("jotai").WritableAtom<null, [id: string, locale: string | null], Promise<void>> & {
|
|
187
189
|
init: null;
|
|
188
190
|
};
|
|
189
|
-
/** The listed children that share a type
|
|
191
|
+
/** The listed children that share a type */
|
|
190
192
|
export interface OverviewChildren {
|
|
191
193
|
type: string;
|
|
192
|
-
status: EntryStatus;
|
|
193
194
|
/** Some of these children store when they were last edited */
|
|
194
195
|
updatedAt: boolean;
|
|
195
196
|
/** Some of these children store who last edited them */
|
|
196
197
|
updatedBy: boolean;
|
|
197
198
|
}
|
|
198
199
|
/**
|
|
199
|
-
* Groups rows by type
|
|
200
|
+
* Groups rows by type, noting whether they store audit
|
|
200
201
|
* metadata. Lists load every child of their parent and searches their
|
|
201
202
|
* shown results, so this covers every row and the columns stay put.
|
|
202
203
|
*/
|
|
@@ -23,7 +23,6 @@ import { graphAtom } from "./core.js";
|
|
|
23
23
|
import { routeAtom } from "./nav.js";
|
|
24
24
|
var builtinColumns = [
|
|
25
25
|
"type",
|
|
26
|
-
"status",
|
|
27
26
|
"updated",
|
|
28
27
|
"author"
|
|
29
28
|
];
|
|
@@ -49,15 +48,6 @@ function builtinColumn(key) {
|
|
|
49
48
|
collapsible: true,
|
|
50
49
|
sortBy: Entry.type
|
|
51
50
|
};
|
|
52
|
-
case "status":
|
|
53
|
-
return {
|
|
54
|
-
key,
|
|
55
|
-
builtin: key,
|
|
56
|
-
header: "Status",
|
|
57
|
-
width: 120,
|
|
58
|
-
collapsible: true,
|
|
59
|
-
sortBy: Entry.status
|
|
60
|
-
};
|
|
61
51
|
case "updated":
|
|
62
52
|
return {
|
|
63
53
|
key,
|
|
@@ -129,7 +119,6 @@ function resolveOverviewOptions(config, overview, types, sort, options = {}) {
|
|
|
129
119
|
const audited = childTypes.some(hasAuditMetadata);
|
|
130
120
|
const defaults = {
|
|
131
121
|
type: children ? new Set(children.map((group) => group.type)).size > 1 : Boolean(options.mixed) || listed.length > 1,
|
|
132
|
-
status: children ? new Set(children.map((group) => group.status)).size > 1 : true,
|
|
133
122
|
updated: children ? children.some((group) => group.updatedAt) : audited,
|
|
134
123
|
author: children ? children.some((group) => group.updatedBy) : audited
|
|
135
124
|
};
|
|
@@ -456,17 +445,14 @@ var openEntryAtom = atom(
|
|
|
456
445
|
function summarizeRows(rows) {
|
|
457
446
|
const groups = /* @__PURE__ */ new Map();
|
|
458
447
|
for (const row of rows) {
|
|
459
|
-
const
|
|
460
|
-
const key = `${row.type}\0${status}`;
|
|
461
|
-
const group = groups.get(key) ?? {
|
|
448
|
+
const group = groups.get(row.type) ?? {
|
|
462
449
|
type: row.type,
|
|
463
|
-
status,
|
|
464
450
|
updatedAt: false,
|
|
465
451
|
updatedBy: false
|
|
466
452
|
};
|
|
467
453
|
group.updatedAt ||= hasAuditValue(row, "updatedAt");
|
|
468
454
|
group.updatedBy ||= hasAuditValue(row, "updatedBy");
|
|
469
|
-
groups.set(
|
|
455
|
+
groups.set(row.type, group);
|
|
470
456
|
}
|
|
471
457
|
return [...groups.values()];
|
|
472
458
|
}
|