@rebasepro/cms 0.20.0 → 0.21.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.
Files changed (43) hide show
  1. package/dist/{CollectionEditorDialog-DQjLtp1W.js → CollectionEditorDialog-C-A_NCKB.js} +15 -14
  2. package/dist/CollectionEditorDialog-C-A_NCKB.js.map +1 -0
  3. package/dist/JsonPreviewBinding-v0w3H0fp.js +35 -0
  4. package/dist/JsonPreviewBinding-v0w3H0fp.js.map +1 -0
  5. package/dist/{PropertyEditView-BMCCD2OI.js → PropertyEditView-Dv7496fx.js} +2 -57
  6. package/dist/{PropertyEditView-BMCCD2OI.js.map → PropertyEditView-Dv7496fx.js.map} +1 -1
  7. package/dist/{RouterCollectionsStudioView-DwsbIAqr.js → RouterCollectionsStudioView-DuDFEYuL.js} +4 -4
  8. package/dist/{RouterCollectionsStudioView-DwsbIAqr.js.map → RouterCollectionsStudioView-DuDFEYuL.js.map} +1 -1
  9. package/dist/collection_editor/ui/collection_editor/templates/blog_template.d.ts +126 -2
  10. package/dist/collection_editor/ui/collection_editor/templates/pages_template.d.ts +201 -2
  11. package/dist/collection_editor/ui/collection_editor/templates/products_template.d.ts +92 -2
  12. package/dist/collection_editor/ui/collection_editor/templates/users_template.d.ts +43 -2
  13. package/dist/collection_editor_ui.js +4 -4
  14. package/dist/components/CollectionViewBinding/CollectionViewStartActions.d.ts +6 -2
  15. package/dist/components/CollectionViewBinding/EntityCardBinding.d.ts +11 -1
  16. package/dist/components/DeleteEntityDialog.d.ts +11 -3
  17. package/dist/data_export/export/ExportCollectionAction.d.ts +1 -1
  18. package/dist/data_export/export/fetch_export_data.d.ts +10 -16
  19. package/dist/editor/editor.d.ts +1 -6
  20. package/dist/editor.js +1 -1
  21. package/dist/editor.js.map +1 -1
  22. package/dist/{export-DJoGYb89.js → export-DtSmLT6u.js} +54 -42
  23. package/dist/export-DtSmLT6u.js.map +1 -0
  24. package/dist/form/EntityForm.d.ts +1 -1
  25. package/dist/{history-BBpsdTrJ.js → history-C6kUDQ3f.js} +2 -2
  26. package/dist/{history-BBpsdTrJ.js.map → history-C6kUDQ3f.js.map} +1 -1
  27. package/dist/{import-C4VQ0rwO.js → import-BciQBH5t.js} +2 -2
  28. package/dist/{import-C4VQ0rwO.js.map → import-BciQBH5t.js.map} +1 -1
  29. package/dist/index.d.ts +1 -0
  30. package/dist/index.js +12 -12
  31. package/dist/index.js.map +1 -1
  32. package/dist/selection/SelectionMenu.d.ts +27 -0
  33. package/dist/selection/index.d.ts +2 -0
  34. package/dist/selection/resolve_selection.d.ts +62 -0
  35. package/dist/types/components/EntityFormProps.d.ts +13 -0
  36. package/dist/util/entity_pages.d.ts +36 -0
  37. package/dist/util/map_with_concurrency.d.ts +16 -0
  38. package/dist/{util-4oPxPkbp.js → util-h6jhiiBE.js} +674 -195
  39. package/dist/util-h6jhiiBE.js.map +1 -0
  40. package/package.json +9 -9
  41. package/dist/CollectionEditorDialog-DQjLtp1W.js.map +0 -1
  42. package/dist/export-DJoGYb89.js.map +0 -1
  43. package/dist/util-4oPxPkbp.js.map +0 -1
@@ -0,0 +1,27 @@
1
+ import React from "react";
2
+ import { Entity } from "@rebasepro/types";
3
+ import { SelectionController, SelectionQuery } from "@rebasepro/cms-types";
4
+ export interface SelectionMenuProps<M extends Record<string, unknown>> {
5
+ selectionController: SelectionController<M>;
6
+ /** The rows the view is holding right now. */
7
+ loadedEntities: Entity<M>[];
8
+ /** The view's live query — what "all matching" stands for. */
9
+ query: SelectionQuery<M>;
10
+ /** The view's filtered count. `undefined` while loading, or where the accessor has none. */
11
+ collectionEntitiesCount?: number;
12
+ collectionName: string;
13
+ }
14
+ /**
15
+ * The whole of selecting rows, in one control: a checkbox for the common case
16
+ * and a caret for everything else.
17
+ *
18
+ * The escalation from "the rows on screen" to "every row that matches" lived in
19
+ * a strip under the toolbar, which was wrong in a way that only shows up in
20
+ * use: it appears the moment you tick a single checkbox, and the list you were
21
+ * reading jumps down by its height. A control that punishes the first click is
22
+ * not worth whatever the strip was explaining.
23
+ *
24
+ * So the escalation is a menu item — clicked deliberately, costing no layout,
25
+ * and in the place you already go to select everything.
26
+ */
27
+ export declare function SelectionMenu<M extends Record<string, unknown>>({ selectionController, loadedEntities, query, collectionEntitiesCount, collectionName }: SelectionMenuProps<M>): React.JSX.Element;
@@ -0,0 +1,2 @@
1
+ export * from "./resolve_selection.js";
2
+ export * from "./SelectionMenu.js";
@@ -0,0 +1,62 @@
1
+ import { Entity, FindParams } from "@rebasepro/types";
2
+ import { EntitySelection, SelectionQuery } from "@rebasepro/cms-types";
3
+ import { EntityPageAccessor } from "../util/entity_pages.js";
4
+ /**
5
+ * Rows asked for per request while resolving a query selection.
6
+ *
7
+ * Same ceiling as the export walk, and for the same reason: the server refuses
8
+ * a `limit` above its `MAX_LIST_LIMIT` rather than clamping it.
9
+ */
10
+ export declare const SELECTION_PAGE_SIZE = 500;
11
+ /**
12
+ * Most rows one query selection will resolve to ids for.
13
+ *
14
+ * The write path is per-row — `deleteMany` loops the single-row delete server
15
+ * side so hooks and row-level security still run for each — so this is a
16
+ * genuine ceiling on the work, not just on memory. Going over it **throws**
17
+ * rather than acting on a prefix, which is the failure that cannot be seen:
18
+ * "deleted 12,480 rows" reads identically whether it was all of them or the
19
+ * first page.
20
+ */
21
+ export declare const MAX_SELECTION_ROWS = 20000;
22
+ /**
23
+ * A stable string for a selection query, for comparing the query a selection
24
+ * was made against with the one the view is showing now.
25
+ *
26
+ * Filter keys are sorted: `filterValues` is rebuilt on most renders and its key
27
+ * order follows whatever order the user touched the columns in, so a plain
28
+ * `JSON.stringify` would report the same filter as a different one and drop a
29
+ * selection the moment anything re-rendered.
30
+ */
31
+ export declare function serializeSelectionQuery<M extends Record<string, unknown>>(query: SelectionQuery<M>): string;
32
+ /** Turn a captured selection query into the `find` params that reproduce it. */
33
+ export declare function selectionQueryToFindParams<M extends Record<string, unknown>>(query: SelectionQuery<M>): Omit<FindParams<M>, "limit" | "offset" | "page">;
34
+ export interface ResolveSelectionParams<M extends Record<string, unknown>> {
35
+ selection: EntitySelection<M>;
36
+ /**
37
+ * Reads the rows a query selection stands for. Only consulted in query
38
+ * mode — an entities selection is already resolved and never hits the
39
+ * network.
40
+ */
41
+ accessor: EntityPageAccessor<M>;
42
+ pageSize?: number;
43
+ maxRows?: number;
44
+ /** Called after every page, so a long resolve can show where it is. */
45
+ onProgress?: (loaded: number, total: number | undefined) => void;
46
+ /** Checked between pages; aborting returns the rows read so far. */
47
+ signal?: {
48
+ aborted: boolean;
49
+ };
50
+ }
51
+ /**
52
+ * The rows a selection covers.
53
+ *
54
+ * This is the *only* way to get rows out of a query selection, and it is why
55
+ * {@link EntitySelection} is a union: a bulk action has to call it, which means
56
+ * it has to deal with the wait, the ceiling and the failure. The array this
57
+ * replaced let the same code path read whatever the view had scrolled — 50 rows
58
+ * of 12,480 — and report success.
59
+ *
60
+ * @throws When the query matches more than `maxRows` rows.
61
+ */
62
+ export declare function resolveSelection<M extends Record<string, unknown>>({ selection, accessor, pageSize, maxRows, onProgress, signal }: ResolveSelectionParams<M>): Promise<Entity<M>[]>;
@@ -36,7 +36,20 @@ export type EntityFormProps<M extends Record<string, unknown>> = {
36
36
  showDefaultActions?: boolean;
37
37
  EntityFormActionsComponent?: React.FC<EntityFormActionsProps>;
38
38
  navigateBack?: () => void;
39
+ /**
40
+ * Rendered in place of the generated fields, inside this form — so it is
41
+ * handed this form's live {@link FormContext}, and Save, validation and the
42
+ * unsaved-changes guard all see what it writes. A collection's
43
+ * `formView.Builder` and an entity view declared with `includeActions` both
44
+ * arrive here.
45
+ */
39
46
  Builder?: React.ComponentType<EntityCustomViewParams<M>>;
47
+ /**
48
+ * Passed through to {@link Builder}: the path of parents above this record,
49
+ * which every entity view receives. The form itself does not read them.
50
+ */
51
+ parentCollectionSlugs?: string[];
52
+ parentEntityIds?: string[];
40
53
  children?: React.ReactNode;
41
54
  /**
42
55
  * Called on form submit with the values to save.
@@ -0,0 +1,36 @@
1
+ import { Entity, FindParams, FindResponse } from "@rebasepro/types";
2
+ /** The slice of a collection accessor a page walk needs. */
3
+ export interface EntityPageAccessor<M extends Record<string, unknown>> {
4
+ find(params?: FindParams<M>): Promise<FindResponse<M>>;
5
+ }
6
+ export interface WalkEntityPagesParams<M extends Record<string, unknown>> {
7
+ accessor: EntityPageAccessor<M>;
8
+ /** Query to walk. The window (`limit` / `offset` / `page`) is owned by the walk. */
9
+ params?: Omit<FindParams<M>, "limit" | "offset" | "page">;
10
+ pageSize: number;
11
+ /** Walking past this many rows throws, with `onCeiling`'s message. */
12
+ maxRows: number;
13
+ onCeiling: (maxRows: number) => string;
14
+ /** Called after every page with the rows so far, and the total when the server reports one. */
15
+ onProgress?: (loaded: number, total: number | undefined) => void;
16
+ /** Checked between pages. When it aborts, what has been read so far is returned. */
17
+ signal?: {
18
+ aborted: boolean;
19
+ };
20
+ }
21
+ /**
22
+ * Read **every** row matching a query, one page at a time.
23
+ *
24
+ * `find({})` sends no `limit`, and an absent limit is resolved server-side to
25
+ * `DEFAULT_LIST_LIMIT` — 50 rows. Anything that means "all of them" and asks
26
+ * once gets 50 back, with nothing to say that is what happened.
27
+ *
28
+ * Termination is driven by the server's `meta.hasMore` where it is reported and
29
+ * by an empty page otherwise — never by comparing a page's length against the
30
+ * requested limit, since a final page that happens to be exactly full is
31
+ * indistinguishable that way and a walk that stops there drops rows.
32
+ *
33
+ * @throws When more than `maxRows` rows match. A truncated answer is worse than
34
+ * no answer: it is indistinguishable from a complete one.
35
+ */
36
+ export declare function walkEntityPages<M extends Record<string, unknown>>({ accessor, params, pageSize, maxRows, onCeiling, onProgress, signal }: WalkEntityPagesParams<M>): Promise<Entity<M>[]>;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Run `task` over every item, at most `concurrency` at a time, and return the
3
+ * results in the order the items were given.
4
+ *
5
+ * The bulk delete used to be `Promise.all(entities.map(performDelete))`. That is
6
+ * fine for the handful of rows anyone could tick by hand, and it is the reason
7
+ * a "select all matching" over a real collection could not simply be poured
8
+ * into the existing dialog: twelve thousand entries in that array is twelve
9
+ * thousand simultaneous requests, which the browser queues and the server takes
10
+ * as a burst.
11
+ *
12
+ * Rejections are not swallowed and do not cancel: every task is run, and the
13
+ * first rejection is thrown once they have all settled, so a bulk action cannot
14
+ * half-apply and then report the failure as if nothing had happened.
15
+ */
16
+ export declare function mapWithConcurrency<T, R>(items: readonly T[], concurrency: number, task: (item: T, index: number) => Promise<R>, onSettled?: (completed: number, total: number) => void): Promise<R[]>;