alinea 2.0.0-preview.13 → 2.0.0-preview.14
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 +6 -2
- package/dist/adapter/next/context.js +1 -4
- package/dist/adapter/next/handler.js +12 -1
- package/dist/backend/CommitEntries.d.ts +17 -0
- package/dist/backend/CommitEntries.js +39 -0
- package/dist/backend/Handler.d.ts +9 -0
- package/dist/backend/Handler.js +80 -20
- package/dist/backend/api/BasicAuth.js +5 -1
- package/dist/backend/api/CreateBackend.js +2 -2
- package/dist/backend/api/DatabaseApi.js +18 -5
- package/dist/backend/api/GithubApi.d.ts +13 -0
- package/dist/backend/api/GithubApi.js +170 -30
- package/dist/backend/api/database.js +2 -2
- package/dist/backend/util/Syncable.d.ts +6 -0
- package/dist/backend/util/Syncable.js +3 -1
- package/dist/bundled.d.ts +911 -151
- package/dist/chunks/{chunk-5H4D5JQL.js → chunk-2PP7WJUJ.js} +1 -11
- package/dist/chunks/{chunk-QHHMKJUO.js → chunk-7DDPSWRY.js} +465 -2
- package/dist/chunks/{chunk-HOETF6HN.js → chunk-PMGIIYDD.js} +1 -0
- package/dist/chunks/{chunk-3QFSGTGF.js → chunk-SCV3TEXM.js} +1 -1
- package/dist/chunks/{chunk-UPY2RUZF.js → chunk-TWBREZWC.js} +30 -0
- package/dist/cli/Generate.js +20 -7
- package/dist/cli/Mcp.js +1 -1
- package/dist/cli/Serve.js +1 -1
- package/dist/cli/bin.js +1 -1
- package/dist/cli/build/BuildEmitter.d.ts +5 -1
- package/dist/cli/build/BuildEmitter.js +8 -3
- package/dist/cli/generate/CompileConfig.js +10 -6
- package/dist/cli/generate/DevDB.d.ts +4 -1
- package/dist/cli/generate/DevDB.js +15 -7
- package/dist/cli/generate/GenerateDashboard.js +1 -0
- package/dist/cli/generate/MediaLocations.d.ts +18 -0
- package/dist/cli/generate/MediaLocations.js +69 -0
- package/dist/cli/serve/CreateLocalServer.js +1 -0
- package/dist/cli/serve/mcp/DevMcp.js +1 -1
- package/dist/cloud/CloudRemote.js +21 -7
- package/dist/cms.d.ts +4 -2
- package/dist/components/Alert.js +2 -2
- package/dist/components/AppShell.js +2 -2
- package/dist/components/AsyncList.d.ts +52 -0
- package/dist/components/AsyncList.js +69 -0
- package/dist/components/Breadcrumbs.js +6 -6
- package/dist/components/Button.js +4 -4
- package/dist/components/Calendar.js +18 -18
- package/dist/components/Checkbox.js +10 -10
- package/dist/components/CheckboxGroup.js +2 -2
- package/dist/components/Collapsible.js +5 -5
- package/dist/components/ColorSwatch.js +2 -2
- package/dist/components/ColorSwatchPicker.js +4 -4
- package/dist/components/ComboBox.d.ts +27 -9
- package/dist/components/ComboBox.js +40 -9
- package/dist/components/Command.js +13 -13
- package/dist/components/ContentCard.js +28 -28
- package/dist/components/ContentGrid.js +11 -11
- package/dist/components/DataList.js +1 -1
- package/dist/components/DateField.d.ts +4 -0
- 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.d.ts +14 -3
- package/dist/components/Dialog.js +38 -11
- package/dist/components/DropZone.js +6 -6
- package/dist/components/DropdownMenu.js +8 -8
- package/dist/components/Empty.js +4 -4
- package/dist/components/Field.d.ts +1 -1
- package/dist/components/Field.js +18 -12
- package/dist/components/Form.d.ts +23 -0
- package/dist/components/Form.js +64 -0
- package/dist/components/Link.d.ts +8 -1
- package/dist/components/List.js +27 -27
- package/dist/components/MediaPreview.js +5 -5
- package/dist/components/MultipleSelect.d.ts +13 -8
- package/dist/components/MultipleSelect.js +25 -25
- package/dist/components/NavRail.js +7 -7
- package/dist/components/NumberField.d.ts +5 -1
- package/dist/components/NumberField.js +6 -4
- package/dist/components/Page.js +6 -6
- package/dist/components/Popover.js +2 -2
- package/dist/components/PreviewFrame.js +8 -8
- package/dist/components/RadioGroup.js +10 -10
- package/dist/components/Resizable.js +1 -1
- package/dist/components/SearchField.js +8 -8
- package/dist/components/Select.d.ts +13 -10
- package/dist/components/Select.js +18 -32
- package/dist/components/Sheet.js +6 -6
- package/dist/components/Sidebar.js +5 -5
- package/dist/components/SortableList.js +12 -12
- package/dist/components/Spinner.js +4 -4
- package/dist/components/Stack.d.ts +20 -0
- package/dist/components/Stack.js +45 -0
- package/dist/components/Surface.js +1 -1
- package/dist/components/Switch.js +5 -5
- package/dist/components/Table.d.ts +11 -1
- package/dist/components/Table.js +81 -53
- package/dist/components/Tabs.js +6 -6
- package/dist/components/TagGroup.js +10 -10
- package/dist/components/TextField.d.ts +7 -1
- package/dist/components/TextField.js +20 -11
- package/dist/components/TimeField.d.ts +6 -1
- package/dist/components/TimeField.js +51 -26
- package/dist/components/Timestamp.js +1 -1
- package/dist/components/ToggleGroup.js +2 -2
- package/dist/components/Toolbar.js +3 -3
- package/dist/components/Tooltip.js +5 -4
- package/dist/components/Tree.js +27 -27
- package/dist/components/internal/DateControl.js +11 -11
- package/dist/components/internal/FormScope.d.ts +2 -0
- package/dist/components/internal/FormScope.js +8 -0
- package/dist/components/internal/ListBoxGroup.d.ts +12 -0
- package/dist/components/internal/ListBoxGroup.js +46 -0
- package/dist/components/internal/ListBoxOption.d.ts +2 -2
- package/dist/components/internal/ListBoxOption.js +5 -5
- package/dist/components/internal/Locale.js +2 -2
- package/dist/components/internal/PopoverSurface.js +5 -4
- package/dist/components/internal/SelectionCheckbox.js +5 -5
- package/dist/components/internal/Slot.js +1 -1
- package/dist/components/internal/ToggleButton.js +4 -4
- package/dist/components/internal/Trigger.js +2 -2
- package/dist/components/internal/useDragDrop.js +2 -2
- package/dist/components/types.d.ts +4 -0
- package/dist/components.d.ts +3 -0
- package/dist/components.js +3 -0
- package/dist/core/Client.js +12 -1
- package/dist/core/Config.d.ts +6 -0
- package/dist/core/Config.js +12 -0
- package/dist/core/DashboardEntry.d.ts +19 -0
- package/dist/core/DashboardEntry.js +0 -0
- package/dist/core/Document.d.ts +2 -2
- package/dist/core/Document.js +10 -3
- package/dist/core/EntryFields.d.ts +8 -2
- package/dist/core/Field.d.ts +5 -0
- package/dist/core/Filter.d.ts +19 -2
- package/dist/core/Filter.js +5 -0
- package/dist/core/Graph.d.ts +10 -2
- package/dist/core/Overview.d.ts +74 -5
- package/dist/core/Overview.js +1 -0
- package/dist/core/Root.js +1 -1
- package/dist/core/Scope.d.ts +5 -0
- package/dist/core/Scope.js +22 -5
- package/dist/core/Type.d.ts +25 -6
- package/dist/core/Type.js +25 -7
- package/dist/core/db/LocalStore.d.ts +7 -0
- package/dist/core/field/CreateField.d.ts +1 -2
- package/dist/core/source/Source.d.ts +2 -0
- package/dist/core/source/Source.js +11 -0
- package/dist/core/util/Async.d.ts +2 -0
- package/dist/core/util/Async.js +12 -1
- package/dist/core/util/Checks.js +1 -1
- package/dist/core/util/Slugs.js +4 -3
- package/dist/dashboard/App.css +13 -11
- package/dist/dashboard/App.d.ts +1 -0
- package/dist/dashboard/App.js +22 -6
- package/dist/dashboard/Href.d.ts +37 -0
- package/dist/dashboard/Href.js +46 -0
- package/dist/dashboard/app/ActivityStatus.js +34 -12
- package/dist/dashboard/app/AuthView.js +2 -2
- package/dist/dashboard/app/BlockSettings.d.ts +9 -0
- package/dist/dashboard/app/BlockSettings.js +16 -0
- package/dist/dashboard/app/BlockSheet.js +3 -3
- package/dist/dashboard/app/BlockSheetStoryFrame.js +2 -2
- package/dist/dashboard/app/CompactField.js +15 -15
- package/dist/dashboard/app/CroppedImage.js +2 -2
- package/dist/dashboard/app/DashboardLayout.d.ts +1 -1
- package/dist/dashboard/app/DashboardLayout.js +12 -0
- package/dist/dashboard/app/EntryActions.d.ts +11 -0
- package/dist/dashboard/app/EntryActions.js +30 -0
- package/dist/dashboard/app/EntryFields.d.ts +15 -2
- package/dist/dashboard/app/EntryFields.js +26 -5
- package/dist/dashboard/app/EntryHeader.js +17 -7
- package/dist/dashboard/app/EntryReferences.js +2 -2
- package/dist/dashboard/app/EntrySidebar.js +25 -23
- package/dist/dashboard/app/EntrySidebarPreview.js +2 -2
- package/dist/dashboard/app/EntryValidationModal.js +3 -3
- package/dist/dashboard/app/Explorer.js +84 -45
- package/dist/dashboard/app/ExplorerBatchActions.js +4 -4
- package/dist/dashboard/app/ExplorerControls.js +5 -5
- package/dist/dashboard/app/ExplorerList.js +2 -2
- package/dist/dashboard/app/ExplorerModal.js +3 -3
- package/dist/dashboard/app/ExplorerOverviewHeader.d.ts +6 -0
- package/dist/dashboard/app/ExplorerOverviewHeader.js +28 -0
- package/dist/dashboard/app/ExplorerTable.js +7 -7
- package/dist/dashboard/app/ExplorerTabs.d.ts +12 -0
- package/dist/dashboard/app/ExplorerTabs.js +42 -0
- package/dist/dashboard/app/ImageEditor.js +31 -31
- package/dist/dashboard/app/LinkPicker.js +3 -3
- package/dist/dashboard/app/LocaleMenu.js +9 -9
- package/dist/dashboard/app/MediaPreviewCell.js +5 -5
- package/dist/dashboard/app/OverviewCell.js +12 -10
- package/dist/dashboard/app/RemoveDialog.js +5 -0
- package/dist/dashboard/app/SearchBar.js +4 -4
- package/dist/dashboard/app/SettingsTab.d.ts +6 -0
- package/dist/dashboard/app/SettingsTab.js +27 -0
- package/dist/dashboard/app/SidebarTree.js +19 -19
- package/dist/dashboard/app/WorkspaceMenu.js +6 -6
- package/dist/dashboard/app/WorkspaceRoots.js +102 -98
- package/dist/dashboard/app/editor/FileEditor.js +18 -18
- package/dist/dashboard/app/pages/EntryPage.js +42 -39
- package/dist/dashboard/app/pages/RootPage.js +3 -3
- package/dist/dashboard/app/pages/SplashPage.js +94 -79
- package/dist/dashboard/app/pages/UsersPage.js +9 -9
- package/dist/dashboard/app/ui/DashboardModal.js +14 -14
- package/dist/dashboard/atoms/activity.d.ts +1 -0
- package/dist/dashboard/atoms/activity.js +8 -5
- package/dist/dashboard/atoms/config.d.ts +2 -0
- package/dist/dashboard/atoms/dashboard.d.ts +11 -0
- package/dist/dashboard/atoms/dashboard.js +8 -0
- package/dist/dashboard/atoms/editor.d.ts +7 -1
- package/dist/dashboard/atoms/editor.js +14 -2
- package/dist/dashboard/atoms/explorer.d.ts +15 -0
- package/dist/dashboard/atoms/explorer.js +43 -14
- package/dist/dashboard/atoms/graph.d.ts +5 -0
- package/dist/dashboard/atoms/graph.js +26 -1
- package/dist/dashboard/atoms/nav.d.ts +16 -10
- package/dist/dashboard/atoms/nav.js +96 -36
- package/dist/dashboard/atoms/overview.d.ts +26 -4
- package/dist/dashboard/atoms/overview.js +41 -12
- package/dist/dashboard/atoms/root.js +7 -1
- package/dist/dashboard/boot/ActivityEvent.d.ts +1 -1
- package/dist/dashboard/boot/Boot.js +6 -0
- package/dist/dashboard/boot/DashboardWorker.d.ts +6 -0
- package/dist/dashboard/boot/DashboardWorker.js +89 -8
- package/dist/dashboard/boot/LoadWorker.js +3 -0
- package/dist/dashboard/boot/SyncEvent.d.ts +7 -0
- package/dist/dashboard/boot/SyncEvent.js +14 -0
- package/dist/dashboard/boot/WorkerDB.d.ts +1 -0
- package/dist/dashboard/boot/WorkerDB.js +3 -0
- package/dist/dashboard/cms/EntryTable.d.ts +4 -3
- package/dist/dashboard/cms/EntryTable.js +2 -2
- package/dist/dashboard/cms/ViewProps.d.ts +3 -2
- package/dist/dashboard/cms/hooks.d.ts +34 -18
- package/dist/dashboard/cms/hooks.js +43 -18
- package/dist/dashboard/contexts.d.ts +3 -2
- package/dist/dashboard/contexts.js +3 -2
- package/dist/dashboard/hook/UseEntryEditor.d.ts +1 -1
- package/dist/dashboard/hook/UseEntryEditor.js +7 -3
- package/dist/dashboard/icons.d.ts +1 -0
- package/dist/dashboard/icons.js +15 -0
- package/dist/database/BrowserEntryStore.js +35 -13
- package/dist/database/DatabaseTables.js +1 -1
- package/dist/database/EntryDatabase.d.ts +10 -1
- package/dist/database/EntryDatabase.js +31 -10
- package/dist/database/EntryStore.js +1 -11
- package/dist/database/entry/EntryTable.d.ts +5 -3
- package/dist/database/entry/EntryTable.js +25 -8
- package/dist/database/query/Condition.d.ts +4 -1
- package/dist/database/query/Condition.js +16 -5
- package/dist/database/query/EntryQuery.js +59 -7
- package/dist/database/query/Relation.d.ts +13 -1
- package/dist/database/query/Relation.js +19 -1
- package/dist/database/query/Search.d.ts +7 -1
- package/dist/database/query/Search.js +54 -9
- package/dist/database/sync/EntrySyncer.d.ts +2 -0
- package/dist/database/sync/EntrySyncer.js +4 -2
- package/dist/database/sync/Ingest.d.ts +2 -1
- package/dist/database/sync/Ingest.js +20 -6
- package/dist/field/code/CodeField.view.js +12 -12
- package/dist/field/link/EntryLink.d.ts +4 -5
- package/dist/field/link/FileLink.d.ts +2 -2
- package/dist/field/link/ImageLink.d.ts +2 -5
- package/dist/field/link/ImageLink.js +0 -1
- package/dist/field/link/LinkField.view.js +18 -15
- package/dist/field/list/ListField.view.js +50 -35
- package/dist/field/metadata/MetadataField.view.js +14 -14
- package/dist/field/richtext/RichTextBlock.js +39 -35
- package/dist/field/richtext/RichTextExtensions.js +23 -23
- package/dist/field/richtext/RichTextField.view.js +6 -6
- package/dist/field/richtext/RichTextInsertMenu.js +5 -5
- package/dist/field/richtext/RichTextToolbar.js +26 -1
- package/dist/field/richtext/Toolbar.d.ts +9 -1
- package/dist/field/richtext/Toolbar.js +12 -2
- package/dist/field/select/SelectField.view.js +1 -0
- package/dist/index.css +174 -23
- package/dist/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/next.d.ts +2 -0
- package/dist/next.edge.d.ts +2 -0
- package/dist/picker/entry/EntryPicker.d.ts +3 -1
- package/dist/picker/entry/EntryPicker.js +15 -1
- package/dist/preview/react.js +3 -0
- package/dist/query.d.ts +26 -14
- package/dist/query.js +4 -0
- package/dist/types.d.ts +8 -5
- package/dist/ui/Stack.d.ts +4 -2
- package/docs/ai-setup.md +3 -3
- package/docs/cli.md +4 -2
- package/docs/components/combo-box.md +105 -16
- package/docs/components/date-field.md +1 -1
- package/docs/components/dialog.md +51 -0
- package/docs/components/form.md +67 -0
- package/docs/components/link.md +10 -0
- package/docs/components/multiple-select.md +9 -17
- package/docs/components/number-field.md +5 -1
- package/docs/components/select.md +9 -20
- package/docs/components/stack.md +42 -0
- package/docs/components/table.md +83 -0
- package/docs/components/text-field.md +9 -1
- package/docs/components/time-field.md +5 -1
- package/docs/components.md +39 -1
- package/docs/configuration.md +3 -1
- package/docs/custom-fields.md +135 -7
- package/docs/deploy/self-host.md +2 -0
- package/docs/deploy.md +7 -4
- package/docs/fields/image.md +0 -1
- package/docs/fields/list.md +19 -0
- package/docs/fields/object.md +5 -3
- package/docs/fields/rich-text.md +31 -0
- package/docs/index.md +8 -6
- package/docs/instant-publishing.md +23 -2
- package/docs/overviews.md +128 -4
- package/docs/query/filtering.md +2 -0
- package/docs/query/related.md +58 -9
- package/docs/query.md +52 -1
- package/docs/quickstart.md +5 -5
- package/docs/schema/document.md +2 -0
- package/docs/schema/type.md +3 -1
- package/docs/upgrading.md +100 -19
- package/llms-full.txt +1022 -125
- package/package.json +1 -1
- package/readme.md +2 -2
- package/dist/chunks/{chunk-4ZA6KZHS.js → chunk-6FQ5IMNA.js} +3 -3
|
@@ -148,10 +148,16 @@ function resolveOverviewOptions(config, overview, types, sort, options = {}) {
|
|
|
148
148
|
filters: Object.entries(overview?.filters ?? {}).map(
|
|
149
149
|
([key, filter]) => filterState(key, filter)
|
|
150
150
|
),
|
|
151
|
+
tabs: Object.entries(overview?.tabs ?? {}).map(([key, tab]) => ({
|
|
152
|
+
key,
|
|
153
|
+
label: tab.label,
|
|
154
|
+
filter: tab.filter
|
|
155
|
+
})),
|
|
151
156
|
sort,
|
|
152
157
|
layout: overview?.layout,
|
|
153
158
|
thumbnail: overview?.thumbnail ? selection(overview.thumbnail, typeNames) : void 0,
|
|
154
159
|
actions: overview?.actions ?? [],
|
|
160
|
+
header: overview?.header,
|
|
155
161
|
types: listed
|
|
156
162
|
};
|
|
157
163
|
}
|
|
@@ -181,17 +187,31 @@ function columnSorts(columns) {
|
|
|
181
187
|
] : []
|
|
182
188
|
);
|
|
183
189
|
}
|
|
184
|
-
function
|
|
185
|
-
return {
|
|
190
|
+
function filterOptions(options) {
|
|
191
|
+
return Object.entries(options).map(([key, option]) => ({
|
|
186
192
|
key,
|
|
187
|
-
label:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
label: option.label,
|
|
194
|
+
filter: option.filter
|
|
195
|
+
}));
|
|
196
|
+
}
|
|
197
|
+
function filterState(key, filter) {
|
|
198
|
+
const base = { key, label: filter.label, multiple: filter.multiple ?? false };
|
|
199
|
+
const { options } = filter;
|
|
200
|
+
if (typeof options === "function")
|
|
201
|
+
return { ...base, options: [], load: options };
|
|
202
|
+
return { ...base, options: filterOptions(options) };
|
|
203
|
+
}
|
|
204
|
+
function hasFilterLoaders(overview) {
|
|
205
|
+
return overview.filters.some((filter) => filter.load);
|
|
206
|
+
}
|
|
207
|
+
async function loadFilterOptions(overview, context) {
|
|
208
|
+
if (!hasFilterLoaders(overview)) return overview;
|
|
209
|
+
const filters = await Promise.all(
|
|
210
|
+
overview.filters.map(
|
|
211
|
+
async ({ load, ...filter }) => load ? { ...filter, options: filterOptions(await load(context)) } : filter
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
return { ...overview, filters };
|
|
195
215
|
}
|
|
196
216
|
function customColumn(key, column, typeNames) {
|
|
197
217
|
const select = column.select === void 0 ? void 0 : selection(column.select, typeNames);
|
|
@@ -209,6 +229,7 @@ function customColumn(key, column, typeNames) {
|
|
|
209
229
|
};
|
|
210
230
|
}
|
|
211
231
|
function isSortable(value) {
|
|
232
|
+
if (isRecord(value) && "edge" in value) return value.count === true;
|
|
212
233
|
if (!Overview.isPlainExpr(value)) return false;
|
|
213
234
|
if (!hasField(value)) return true;
|
|
214
235
|
const field = value;
|
|
@@ -219,7 +240,7 @@ function columnSortBy(column, select) {
|
|
|
219
240
|
if (column.sortBy) return Overview.sortExpr(column.sortBy);
|
|
220
241
|
if (!select) return void 0;
|
|
221
242
|
if (select.all !== void 0)
|
|
222
|
-
return isSortable(select.all) ? select.all : void 0;
|
|
243
|
+
return isSortable(select.all) ? Overview.sortExpr(select.all) : void 0;
|
|
223
244
|
const cases = Object.entries(select.byType ?? {});
|
|
224
245
|
if (!cases.every(([, value]) => isSortable(value))) return void 0;
|
|
225
246
|
return Overview.sortExpr(Object.fromEntries(cases));
|
|
@@ -321,8 +342,12 @@ function pickedFilters(overview, selection2) {
|
|
|
321
342
|
}
|
|
322
343
|
return picked;
|
|
323
344
|
}
|
|
324
|
-
function
|
|
345
|
+
function pickedTab(overview, tab) {
|
|
346
|
+
return overview.tabs.find((option) => option.key === tab) ?? overview.tabs[0];
|
|
347
|
+
}
|
|
348
|
+
function overviewFilter(overview, selection2, tab) {
|
|
325
349
|
const picked = pickedFilters(overview, selection2);
|
|
350
|
+
const tabFilter = pickedTab(overview, tab)?.filter;
|
|
326
351
|
const conditions = overview.filters.flatMap((filter) => {
|
|
327
352
|
const options = filter.options.filter(
|
|
328
353
|
(option) => picked[filter.key]?.includes(option.key)
|
|
@@ -331,6 +356,7 @@ function overviewFilter(overview, selection2) {
|
|
|
331
356
|
if (options.length === 1) return [options[0].filter];
|
|
332
357
|
return [{ or: options.map((option) => option.filter) }];
|
|
333
358
|
});
|
|
359
|
+
if (tabFilter) conditions.unshift(tabFilter);
|
|
334
360
|
if (conditions.length === 0) return void 0;
|
|
335
361
|
if (conditions.length === 1) return conditions[0];
|
|
336
362
|
return { and: conditions };
|
|
@@ -467,8 +493,10 @@ export {
|
|
|
467
493
|
columnField,
|
|
468
494
|
columnLinkIds,
|
|
469
495
|
columnProjection,
|
|
496
|
+
hasFilterLoaders,
|
|
470
497
|
linkedEntryId,
|
|
471
498
|
loadColumnValues,
|
|
499
|
+
loadFilterOptions,
|
|
472
500
|
loadOverviewParent,
|
|
473
501
|
openEntryAtom,
|
|
474
502
|
overviewEntry,
|
|
@@ -480,6 +508,7 @@ export {
|
|
|
480
508
|
parentTypes,
|
|
481
509
|
pickedFilters,
|
|
482
510
|
pickedSort,
|
|
511
|
+
pickedTab,
|
|
483
512
|
resolveOverview,
|
|
484
513
|
resolveOverviewOptions,
|
|
485
514
|
sortedColumn,
|
|
@@ -28,7 +28,12 @@ import {
|
|
|
28
28
|
treeEntryAtoms
|
|
29
29
|
} from "./entry.js";
|
|
30
30
|
import { shaAtom } from "./graph.js";
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
overviewSortAtom,
|
|
33
|
+
overviewTabAtom,
|
|
34
|
+
pageAtom,
|
|
35
|
+
routeAtom
|
|
36
|
+
} from "./nav.js";
|
|
32
37
|
import { policyAtom } from "./user.js";
|
|
33
38
|
import {
|
|
34
39
|
dashboardEntryDragItem,
|
|
@@ -409,6 +414,7 @@ var RootAtoms = class {
|
|
|
409
414
|
{
|
|
410
415
|
enableNavigation: true,
|
|
411
416
|
sortState: overviewSortAtom(this.workspace, this.key, parentId),
|
|
417
|
+
tabState: overviewTabAtom(this.workspace, this.key, parentId),
|
|
412
418
|
rootData: this.data,
|
|
413
419
|
// The filters picked in this list, kept when the editor comes back to
|
|
414
420
|
// it, like its sort, but not applied to the lists of other entries
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ActivityType = 'mutation' | 'upload';
|
|
1
|
+
export type ActivityType = 'mutation' | 'upload' | 'sync';
|
|
2
2
|
export type ActivityStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'blocked' | 'discarded' | 'cancelled';
|
|
3
3
|
export interface Activity {
|
|
4
4
|
id: string;
|
|
@@ -10,6 +10,7 @@ import { App } from "../App.js";
|
|
|
10
10
|
import { ActivityEvent } from "./ActivityEvent.js";
|
|
11
11
|
import { DashboardWorker } from "./DashboardWorker.js";
|
|
12
12
|
import { loadWorker } from "./LoadWorker.js";
|
|
13
|
+
import { SyncEvent } from "./SyncEvent.js";
|
|
13
14
|
import { WorkerDB } from "./WorkerDB.js";
|
|
14
15
|
import { jsx } from "react/jsx-runtime";
|
|
15
16
|
async function boot(gen) {
|
|
@@ -24,6 +25,9 @@ async function boot(gen) {
|
|
|
24
25
|
into.id = "root";
|
|
25
26
|
if (element.parentElement === document.head) document.body.append(into);
|
|
26
27
|
else element.parentElement.replaceChild(into, element);
|
|
28
|
+
const html = document.documentElement;
|
|
29
|
+
if (!html.hasAttribute("data-alinea-theme"))
|
|
30
|
+
html.setAttribute("data-alinea-theme", "");
|
|
27
31
|
const root = createRoot(into);
|
|
28
32
|
let lastRevision;
|
|
29
33
|
for await (const batch of gen) {
|
|
@@ -75,6 +79,8 @@ function listen(source) {
|
|
|
75
79
|
events.dispatchEvent(new IndexEvent(data.data));
|
|
76
80
|
} else if (data.type === ActivityEvent.type) {
|
|
77
81
|
events.dispatchEvent(new ActivityEvent(data.activities));
|
|
82
|
+
} else if (data.type === SyncEvent.type) {
|
|
83
|
+
events.dispatchEvent(new SyncEvent(data.progress));
|
|
78
84
|
}
|
|
79
85
|
});
|
|
80
86
|
return events;
|
|
@@ -11,6 +11,12 @@ export declare class DashboardWorker extends EventTarget {
|
|
|
11
11
|
constructor(source?: Source);
|
|
12
12
|
get db(): EntryStore | Promise<EntryStore>;
|
|
13
13
|
sync(): Promise<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Resolve once the dashboard can show content. Stored content shows right
|
|
16
|
+
* away and catches up with the remote as an activity; an empty store, or
|
|
17
|
+
* one whose cached content failed, waits for its first sync.
|
|
18
|
+
*/
|
|
19
|
+
ready(): Promise<void>;
|
|
14
20
|
sha(): Promise<string>;
|
|
15
21
|
queue(id: string, mutations: Array<Mutation>): Promise<string>;
|
|
16
22
|
retryActivity(): Promise<void>;
|
|
@@ -5,6 +5,7 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
5
5
|
|
|
6
6
|
// src/dashboard/boot/DashboardWorker.ts
|
|
7
7
|
import { Entry } from "alinea/core/Entry";
|
|
8
|
+
import { createId } from "alinea/core/Id";
|
|
8
9
|
import { getScope } from "alinea/core/Scope";
|
|
9
10
|
import { trigger } from "alinea/core/Trigger";
|
|
10
11
|
import { IndexEvent } from "alinea/core/db/IndexEvent";
|
|
@@ -17,9 +18,11 @@ import { EntryStore } from "alinea/database/EntryStore";
|
|
|
17
18
|
import {
|
|
18
19
|
ActivityEvent
|
|
19
20
|
} from "./ActivityEvent.js";
|
|
21
|
+
import { SyncEvent } from "./SyncEvent.js";
|
|
20
22
|
var remote = pLimit(1);
|
|
21
23
|
var cacheName = "alinea-entry-database";
|
|
22
24
|
var syncInterval = 12e4;
|
|
25
|
+
var progressInterval = 100;
|
|
23
26
|
var activityHistoryLimit = 100;
|
|
24
27
|
var DashboardWorker = class extends EventTarget {
|
|
25
28
|
#source;
|
|
@@ -57,6 +60,57 @@ var DashboardWorker = class extends EventTarget {
|
|
|
57
60
|
throw error;
|
|
58
61
|
}
|
|
59
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolve once the dashboard can show content. Stored content shows right
|
|
65
|
+
* away and catches up with the remote as an activity; an empty store, or
|
|
66
|
+
* one whose cached content failed, waits for its first sync.
|
|
67
|
+
*/
|
|
68
|
+
async ready() {
|
|
69
|
+
const loaded = await this.#nextLoad;
|
|
70
|
+
if (!loaded.stored) return void await this.sync();
|
|
71
|
+
loaded.caughtUp ??= this.#catchUp();
|
|
72
|
+
}
|
|
73
|
+
#catchUp() {
|
|
74
|
+
const activity = {
|
|
75
|
+
id: createId(),
|
|
76
|
+
type: "sync",
|
|
77
|
+
status: "running",
|
|
78
|
+
operations: [{ op: "sync" }],
|
|
79
|
+
startedAt: Date.now()
|
|
80
|
+
};
|
|
81
|
+
this.#activities.unshift(activity);
|
|
82
|
+
return this.#syncActivities([activity]);
|
|
83
|
+
}
|
|
84
|
+
async #syncActivities(activities) {
|
|
85
|
+
for (const activity of activities) {
|
|
86
|
+
activity.status = "running";
|
|
87
|
+
activity.finishedAt = void 0;
|
|
88
|
+
activity.error = void 0;
|
|
89
|
+
}
|
|
90
|
+
this.#emitActivity();
|
|
91
|
+
try {
|
|
92
|
+
await this.sync();
|
|
93
|
+
} catch (error) {
|
|
94
|
+
for (const activity of activities)
|
|
95
|
+
if (activity.status === "running") this.#failActivity(activity, error);
|
|
96
|
+
this.#startSyncing();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/** Content that synced is caught up: settle the catch-up activities. */
|
|
100
|
+
#settleSyncs() {
|
|
101
|
+
const syncs = this.#activities.filter(
|
|
102
|
+
(activity) => activity.type === "sync" && (activity.status === "running" || activity.status === "failed")
|
|
103
|
+
);
|
|
104
|
+
if (syncs.length === 0) return;
|
|
105
|
+
const finishedAt = Date.now();
|
|
106
|
+
for (const activity of syncs) {
|
|
107
|
+
activity.status = "succeeded";
|
|
108
|
+
activity.finishedAt = finishedAt;
|
|
109
|
+
activity.error = void 0;
|
|
110
|
+
}
|
|
111
|
+
this.#trimActivities();
|
|
112
|
+
this.#emitActivity();
|
|
113
|
+
}
|
|
60
114
|
async #syncLoaded(load) {
|
|
61
115
|
const loaded = await load;
|
|
62
116
|
const { db, client } = loaded;
|
|
@@ -127,6 +181,10 @@ Remote updates: ${remote2}`
|
|
|
127
181
|
});
|
|
128
182
|
}
|
|
129
183
|
async retryActivity() {
|
|
184
|
+
const syncs = this.#activities.filter(
|
|
185
|
+
(activity) => activity.type === "sync" && activity.status === "failed"
|
|
186
|
+
);
|
|
187
|
+
if (syncs.length > 0) await this.#syncActivities(syncs);
|
|
130
188
|
if (this.#blocked) await this.#retryMutations();
|
|
131
189
|
}
|
|
132
190
|
async #retryMutations() {
|
|
@@ -191,13 +249,16 @@ Remote updates: ${remote2}`
|
|
|
191
249
|
await this.#syncWithClient(db, client);
|
|
192
250
|
this.#completeMutation(item);
|
|
193
251
|
} catch (error) {
|
|
194
|
-
|
|
195
|
-
this.#failActivity(item.activity, error);
|
|
252
|
+
let revision;
|
|
196
253
|
try {
|
|
197
|
-
await this.#syncWithClient(db, client);
|
|
198
|
-
item.sha = void 0;
|
|
254
|
+
revision = await this.#syncWithClient(db, client);
|
|
199
255
|
} catch {
|
|
200
256
|
}
|
|
257
|
+
if (revision && revision === item.sha)
|
|
258
|
+
return this.#completeMutation(item);
|
|
259
|
+
this.#blocked = true;
|
|
260
|
+
this.#failActivity(item.activity, error);
|
|
261
|
+
if (revision) item.sha = void 0;
|
|
201
262
|
}
|
|
202
263
|
});
|
|
203
264
|
}
|
|
@@ -228,7 +289,21 @@ Remote updates: ${remote2}`
|
|
|
228
289
|
this.dispatchEvent(new ActivityEvent(this.activities()));
|
|
229
290
|
}
|
|
230
291
|
async #syncWithClient(db, client) {
|
|
231
|
-
|
|
292
|
+
let reported = 0;
|
|
293
|
+
const onProgress = (progress) => {
|
|
294
|
+
const now = Date.now();
|
|
295
|
+
const done = progress.loaded >= progress.total;
|
|
296
|
+
if (!done && now - reported < progressInterval) return;
|
|
297
|
+
reported = now;
|
|
298
|
+
this.dispatchEvent(new SyncEvent(progress));
|
|
299
|
+
};
|
|
300
|
+
try {
|
|
301
|
+
const revision = await db.syncWith(client, { validate: false, onProgress });
|
|
302
|
+
this.#settleSyncs();
|
|
303
|
+
return revision;
|
|
304
|
+
} finally {
|
|
305
|
+
if (reported) this.dispatchEvent(new SyncEvent());
|
|
306
|
+
}
|
|
232
307
|
}
|
|
233
308
|
#failActivity(activity, error) {
|
|
234
309
|
activity.status = "failed";
|
|
@@ -241,7 +316,7 @@ Remote updates: ${remote2}`
|
|
|
241
316
|
for (let index = this.#activities.length - 1; excess > 0; index--) {
|
|
242
317
|
if (index < 0) break;
|
|
243
318
|
const activity = this.#activities[index];
|
|
244
|
-
if (activity.status === "pending" || activity.status === "running" || activity.status === "blocked" || activity.
|
|
319
|
+
if (activity.status === "pending" || activity.status === "running" || activity.status === "blocked" || activity.status === "failed")
|
|
245
320
|
continue;
|
|
246
321
|
this.#activities.splice(index, 1);
|
|
247
322
|
excess -= 1;
|
|
@@ -291,12 +366,18 @@ Remote updates: ${remote2}`
|
|
|
291
366
|
db = await this.#open(config, revision, true);
|
|
292
367
|
cacheFailure = await this.#syncLocalIndex(db);
|
|
293
368
|
}
|
|
294
|
-
|
|
369
|
+
const empty = (await db.source.getTree()).isEmpty;
|
|
370
|
+
if (hadPrevious && empty)
|
|
295
371
|
await this.#syncWithClient(db, client).catch(() => {
|
|
296
372
|
});
|
|
297
373
|
this.#localDB = db;
|
|
298
374
|
this.#localClient = client;
|
|
299
|
-
nextLoad.resolve({
|
|
375
|
+
nextLoad.resolve({
|
|
376
|
+
db,
|
|
377
|
+
client,
|
|
378
|
+
cacheFailure,
|
|
379
|
+
stored: !cacheFailure && !empty
|
|
380
|
+
});
|
|
300
381
|
const unsubscribe = db.onChange((change) => {
|
|
301
382
|
this.dispatchEvent(
|
|
302
383
|
new IndexEvent({
|
|
@@ -7,6 +7,7 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
7
7
|
import { IndexEvent } from "alinea/core/db/IndexEvent";
|
|
8
8
|
import { ActivityEvent } from "./ActivityEvent.js";
|
|
9
9
|
import { DashboardWorker } from "./DashboardWorker.js";
|
|
10
|
+
import { SyncEvent } from "./SyncEvent.js";
|
|
10
11
|
async function loadWorker(gen) {
|
|
11
12
|
const worker = new DashboardWorker();
|
|
12
13
|
function forward(target) {
|
|
@@ -16,10 +17,12 @@ async function loadWorker(gen) {
|
|
|
16
17
|
} catch {
|
|
17
18
|
worker.removeEventListener(IndexEvent.type, listen);
|
|
18
19
|
worker.removeEventListener(ActivityEvent.type, listen);
|
|
20
|
+
worker.removeEventListener(SyncEvent.type, listen);
|
|
19
21
|
}
|
|
20
22
|
};
|
|
21
23
|
worker.addEventListener(IndexEvent.type, listen);
|
|
22
24
|
worker.addEventListener(ActivityEvent.type, listen);
|
|
25
|
+
worker.addEventListener(SyncEvent.type, listen);
|
|
23
26
|
}
|
|
24
27
|
if ("onconnect" in globalThis) {
|
|
25
28
|
addEventListener("connect", (event) => {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SyncProgress } from 'alinea/core/db/LocalStore';
|
|
2
|
+
/** Progress of a sync from the remote, without progress once it finished. */
|
|
3
|
+
export declare class SyncEvent extends Event {
|
|
4
|
+
progress?: SyncProgress | undefined;
|
|
5
|
+
static readonly type = "sync";
|
|
6
|
+
constructor(progress?: SyncProgress | undefined);
|
|
7
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "../../chunks/chunk-CQ52GEHY.js";
|
|
2
|
+
|
|
3
|
+
// src/dashboard/boot/SyncEvent.ts
|
|
4
|
+
var SyncEvent = class _SyncEvent extends Event {
|
|
5
|
+
constructor(progress) {
|
|
6
|
+
super(_SyncEvent.type);
|
|
7
|
+
this.progress = progress;
|
|
8
|
+
}
|
|
9
|
+
progress;
|
|
10
|
+
static type = "sync";
|
|
11
|
+
};
|
|
12
|
+
export {
|
|
13
|
+
SyncEvent
|
|
14
|
+
};
|
|
@@ -16,6 +16,7 @@ export declare class WorkerDB extends WriteableGraph {
|
|
|
16
16
|
sha: string;
|
|
17
17
|
}>;
|
|
18
18
|
resolve<Query extends GraphQuery>(query: Query): Promise<AnyQueryResult<Query>>;
|
|
19
|
+
ready(): Promise<void>;
|
|
19
20
|
sync(): Promise<string>;
|
|
20
21
|
get sha(): Promise<string>;
|
|
21
22
|
referencesTo(query: EntryReferenceQuery): Promise<EntryReferenceResult>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EntryFilterFields } from 'alinea/core/EntryFields';
|
|
2
2
|
import type { OpenFilter } from 'alinea/core/Filter';
|
|
3
3
|
import type { OrderBy } from 'alinea/core/OrderBy';
|
|
4
4
|
import type { OverviewColumn, OverviewOptions } from 'alinea/core/Overview';
|
|
@@ -11,9 +11,10 @@ export interface EntryTableProps {
|
|
|
11
11
|
type?: Type | Array<Type>;
|
|
12
12
|
/**
|
|
13
13
|
* Only list entries matching this filter, like the `filter` of a query,
|
|
14
|
-
* eg. `{brand: {has: {_entry: entryId}}}`
|
|
14
|
+
* eg. `{brand: {has: {_entry: entryId}}}` or
|
|
15
|
+
* `{_referenced: Query.referencedBy({type: Product})}`
|
|
15
16
|
*/
|
|
16
|
-
filter?: OpenFilter<
|
|
17
|
+
filter?: OpenFilter<EntryFilterFields>;
|
|
17
18
|
/** Only list entries of this workspace */
|
|
18
19
|
workspace?: string;
|
|
19
20
|
/** Only list entries of this root */
|
|
@@ -66,9 +66,9 @@ import {
|
|
|
66
66
|
var EntryTable_default = {
|
|
67
67
|
"EntryTable-loading": "alinea-EntryTable-loading",
|
|
68
68
|
"EntryTableLoading": "alinea-EntryTable-loading",
|
|
69
|
-
"EntryTable": "alinea-EntryTable",
|
|
70
69
|
"EntryTable-table": "alinea-EntryTable-table",
|
|
71
|
-
"EntryTableTable": "alinea-EntryTable-table"
|
|
70
|
+
"EntryTableTable": "alinea-EntryTable-table",
|
|
71
|
+
"EntryTable": "alinea-EntryTable"
|
|
72
72
|
};
|
|
73
73
|
|
|
74
74
|
// src/dashboard/cms/EntryTable.tsx
|
|
@@ -24,8 +24,9 @@ export interface SectionViewProps {
|
|
|
24
24
|
section: Section;
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
27
|
-
* Props of the component a type points to with `view`. It replaces the
|
|
28
|
-
*
|
|
27
|
+
* Props of the component a type points to with `view`. It replaces the form
|
|
28
|
+
* of entries of that type below the entry header, the field hooks edit the
|
|
29
|
+
* fields of the entry.
|
|
29
30
|
*/
|
|
30
31
|
export interface TypeViewProps {
|
|
31
32
|
/** The type of the entry being shown */
|
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* The hooks of custom field and dashboard views, exported from `alinea/cms`.
|
|
3
3
|
* Their types do not expose the internal state of the dashboard.
|
|
4
4
|
*/
|
|
5
|
+
import type { DashboardEntry } from 'alinea/core/DashboardEntry';
|
|
5
6
|
import type { WriteableGraph } from 'alinea/core/db/WriteableGraph';
|
|
6
|
-
import type { Entry
|
|
7
|
+
import type { Entry } from 'alinea/core/Entry';
|
|
7
8
|
import type { Field } from 'alinea/core/Field';
|
|
8
9
|
import type { PreviewMetadata } from 'alinea/core/Preview';
|
|
9
10
|
import type { Policy } from 'alinea/core/Role';
|
|
10
11
|
import type { User } from 'alinea/core/User';
|
|
11
12
|
import { type Dispatch, type SetStateAction } from 'react';
|
|
13
|
+
import type { DashboardLocation } from '../Href.js';
|
|
12
14
|
/**
|
|
13
15
|
* Returns the permissions of the signed-in user. Check access with
|
|
14
16
|
* `policy.get({workspace, root, id, ...})`, which returns flags such as
|
|
@@ -32,8 +34,24 @@ export declare function usePreviewMetadata(): PreviewMetadata | undefined;
|
|
|
32
34
|
/**
|
|
33
35
|
* Returns the stored value of a field in the entry, list row or object being
|
|
34
36
|
* edited. Use it in a view that only reads the value.
|
|
37
|
+
*
|
|
38
|
+
* The field-based hooks (`useFieldValue`, `useField`, `useFieldSetter`, ...)
|
|
39
|
+
* also read the fields around a custom field: pass a field of the same row,
|
|
40
|
+
* of a parent row or of the entry, and it resolves in the nearest scope that
|
|
41
|
+
* holds it. Import the type from your schema or pass the field through the
|
|
42
|
+
* options of your field.
|
|
43
|
+
*
|
|
44
|
+
* A view shared by types that each define their own field can pass its key
|
|
45
|
+
* instead, which reads the field of the same row, untyped.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // In the view of a field inside a list row of `BlogPost`
|
|
49
|
+
* const title = useFieldValue(BlogPost.title) // a field of the entry
|
|
50
|
+
* const price = useFieldValue(options.price) // a field passed as option
|
|
51
|
+
* const path = useFieldValue('path') // the path field of this type
|
|
35
52
|
*/
|
|
36
53
|
export declare function useFieldValue<StoredValue, QueryValue, Mutator, Options>(field: Field<StoredValue, QueryValue, Mutator, Options>): StoredValue;
|
|
54
|
+
export declare function useFieldValue(key: string): unknown;
|
|
37
55
|
/**
|
|
38
56
|
* Returns the stored value of a field and a setter, like `useState`. The
|
|
39
57
|
* setter also accepts an updater function that receives the current value.
|
|
@@ -66,39 +84,37 @@ export declare function useFieldError<StoredValue, QueryValue, Mutator, Options>
|
|
|
66
84
|
/**
|
|
67
85
|
* Returns the stored value of another field in the same entry, list row or
|
|
68
86
|
* object, by its key.
|
|
87
|
+
*
|
|
88
|
+
* @deprecated Use `useFieldValue`: pass the field, which is typed and also
|
|
89
|
+
* reads fields of a parent row or the entry (`useFieldValue(BlogPost.title)`),
|
|
90
|
+
* or its key (`useFieldValue('title')`).
|
|
69
91
|
*/
|
|
70
92
|
export declare function useSiblingFieldValue(key: string): unknown;
|
|
71
93
|
/**
|
|
72
|
-
* Returns the
|
|
94
|
+
* Returns the entry being edited, in the selected locale and version.
|
|
95
|
+
* `entry.data` holds the field values as saved: use `useFieldValue(field)`
|
|
96
|
+
* for the live value while the editor changes it.
|
|
73
97
|
*
|
|
74
|
-
* Returns null outside an entry
|
|
75
|
-
* resolved. The returned value follows locale/status selection and does not
|
|
76
|
-
* expose internal atoms.
|
|
98
|
+
* Returns null outside an entry, eg. in a root view.
|
|
77
99
|
*/
|
|
78
|
-
export declare function useEntry():
|
|
100
|
+
export declare function useEntry(): DashboardEntry | null;
|
|
101
|
+
/** @internal */
|
|
102
|
+
export declare function dashboardEntry(entry: Entry): DashboardEntry;
|
|
79
103
|
/**
|
|
80
104
|
* Returns the current locale of the dashboard: the locale of the entry being
|
|
81
105
|
* edited, or the selected locale of the current root. `null` for content
|
|
82
106
|
* without translations or outside the dashboard layout.
|
|
83
107
|
*/
|
|
84
108
|
export declare function useLocale(): string | null;
|
|
85
|
-
/** A place in the dashboard to navigate to */
|
|
86
|
-
export interface DashboardLocation {
|
|
87
|
-
/** Name of the workspace */
|
|
88
|
-
workspace: string;
|
|
89
|
-
/** Name of the root */
|
|
90
|
-
root: string;
|
|
91
|
-
/** Id of the entry to open, leave out to open the root */
|
|
92
|
-
entryId?: string;
|
|
93
|
-
/** Locale to open, for roots with translations */
|
|
94
|
-
locale?: string | null;
|
|
95
|
-
}
|
|
96
109
|
/**
|
|
97
110
|
* Returns a function that navigates the dashboard to an entry or root. The
|
|
98
111
|
* user is asked to confirm first when the current entry has unsaved changes.
|
|
112
|
+
* An entry can be opened by its id alone, its workspace and root are looked
|
|
113
|
+
* up.
|
|
99
114
|
*
|
|
100
115
|
* @example
|
|
101
116
|
* const navigate = useNavigate()
|
|
102
|
-
* navigate({
|
|
117
|
+
* navigate({entryId: post.id, locale: 'en'})
|
|
118
|
+
* navigate({workspace: 'main', root: 'pages'})
|
|
103
119
|
*/
|
|
104
120
|
export declare function useNavigate(): (location: DashboardLocation) => void;
|
|
@@ -9,7 +9,8 @@ import "../../chunks/chunk-CQ52GEHY.js";
|
|
|
9
9
|
import { assert } from "alinea/core/util/Assert";
|
|
10
10
|
import {
|
|
11
11
|
useCallback,
|
|
12
|
-
useContext
|
|
12
|
+
useContext,
|
|
13
|
+
useMemo
|
|
13
14
|
} from "react";
|
|
14
15
|
import { graphAtom } from "../atoms/core.js";
|
|
15
16
|
import { routeAtom } from "../atoms/nav.js";
|
|
@@ -19,8 +20,7 @@ import {
|
|
|
19
20
|
dashboardContext,
|
|
20
21
|
entryContext,
|
|
21
22
|
useEditor,
|
|
22
|
-
useFieldInfo
|
|
23
|
-
useFieldNode
|
|
23
|
+
useFieldInfo
|
|
24
24
|
} from "../contexts.js";
|
|
25
25
|
function usePolicy() {
|
|
26
26
|
return useAtomValueRaw(policyAtom);
|
|
@@ -35,8 +35,13 @@ function usePreviewMetadata() {
|
|
|
35
35
|
return useAtomValueRaw(previewMetadataAtom);
|
|
36
36
|
}
|
|
37
37
|
function useFieldValue(field) {
|
|
38
|
-
const
|
|
39
|
-
|
|
38
|
+
const editor = useEditor();
|
|
39
|
+
const info = typeof field === "string" ? editor.field(field) : editor.get(field);
|
|
40
|
+
assert(
|
|
41
|
+
info,
|
|
42
|
+
`Field not found: ${typeof field === "string" ? field : "field"}`
|
|
43
|
+
);
|
|
44
|
+
return useAtomValueRaw(info.value);
|
|
40
45
|
}
|
|
41
46
|
function useField(field) {
|
|
42
47
|
const info = useFieldInfo(field);
|
|
@@ -61,14 +66,26 @@ function useFieldError(field) {
|
|
|
61
66
|
return useAtomValueRaw(info.error);
|
|
62
67
|
}
|
|
63
68
|
function useSiblingFieldValue(key) {
|
|
64
|
-
|
|
65
|
-
const info = editor.field(key);
|
|
66
|
-
assert(info, `Field not found: ${key}`);
|
|
67
|
-
return useAtomValueRaw(info.value);
|
|
69
|
+
return useFieldValue(key);
|
|
68
70
|
}
|
|
69
71
|
function useEntry() {
|
|
70
|
-
const
|
|
71
|
-
return
|
|
72
|
+
const selected = useContext(entryContext)?.selectedEntry;
|
|
73
|
+
return useMemo(() => selected ? dashboardEntry(selected) : null, [selected]);
|
|
74
|
+
}
|
|
75
|
+
function dashboardEntry(entry) {
|
|
76
|
+
return {
|
|
77
|
+
id: entry.id,
|
|
78
|
+
type: entry.type,
|
|
79
|
+
title: entry.title,
|
|
80
|
+
path: entry.path,
|
|
81
|
+
url: entry.url,
|
|
82
|
+
locale: entry.locale,
|
|
83
|
+
status: entry.status,
|
|
84
|
+
workspace: entry.workspace,
|
|
85
|
+
root: entry.root,
|
|
86
|
+
parentId: entry.parentId,
|
|
87
|
+
data: entry.data
|
|
88
|
+
};
|
|
72
89
|
}
|
|
73
90
|
function useLocale() {
|
|
74
91
|
const entry = useContext(entryContext);
|
|
@@ -76,20 +93,28 @@ function useLocale() {
|
|
|
76
93
|
if (entry) return entry.localeData.requestedLocale;
|
|
77
94
|
return dashboard?.page.locale ?? null;
|
|
78
95
|
}
|
|
96
|
+
function dashboardRoute(location) {
|
|
97
|
+
const locale = location.locale ?? void 0;
|
|
98
|
+
if (location.entryId && !location.workspace && !location.root)
|
|
99
|
+
return { page: "edit", entry: location.entryId, locale, view: location.view };
|
|
100
|
+
return {
|
|
101
|
+
page: "entry",
|
|
102
|
+
workspace: location.workspace,
|
|
103
|
+
root: location.root,
|
|
104
|
+
entry: location.entryId,
|
|
105
|
+
locale,
|
|
106
|
+
view: location.view
|
|
107
|
+
};
|
|
108
|
+
}
|
|
79
109
|
function useNavigate() {
|
|
80
110
|
const setRoute = useSetAtom(routeAtom);
|
|
81
111
|
return useCallback(
|
|
82
|
-
(location) => setRoute(
|
|
83
|
-
page: "entry",
|
|
84
|
-
workspace: location.workspace,
|
|
85
|
-
root: location.root,
|
|
86
|
-
entry: location.entryId,
|
|
87
|
-
locale: location.locale ?? void 0
|
|
88
|
-
}),
|
|
112
|
+
(location) => setRoute(dashboardRoute(location)),
|
|
89
113
|
[setRoute]
|
|
90
114
|
);
|
|
91
115
|
}
|
|
92
116
|
export {
|
|
117
|
+
dashboardEntry,
|
|
93
118
|
useEntry,
|
|
94
119
|
useField,
|
|
95
120
|
useFieldError,
|
|
@@ -49,10 +49,11 @@ export declare const editorContext: import("react").Context<EditorModel | null>;
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function useEditor(): EditorModel;
|
|
51
51
|
/**
|
|
52
|
-
* Returns the editor metadata for a field in the active editor scope
|
|
52
|
+
* Returns the editor metadata for a field in the active editor scope, or in
|
|
53
|
+
* the scope of a parent row or the entry when the field belongs there.
|
|
53
54
|
*/
|
|
54
55
|
export declare function useFieldInfo(field: Field): import("./atoms/editor.js").EditorField;
|
|
55
56
|
/**
|
|
56
|
-
* Returns the reactive node backing a field in the
|
|
57
|
+
* Returns the reactive node backing a field in the editor it belongs to.
|
|
57
58
|
*/
|
|
58
59
|
export declare function useFieldNode<Value>(field: Field): ReactiveNode<Value>;
|