@object-ui/core 17.5.0 → 17.7.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 (157) hide show
  1. package/CHANGELOG.md +7404 -0
  2. package/README.md +127 -26
  3. package/dist/actions/ActionEngine.d.ts +5 -3
  4. package/dist/actions/ActionEngine.js +14 -10
  5. package/dist/actions/ActionRunner.d.ts +363 -30
  6. package/dist/actions/ActionRunner.js +544 -58
  7. package/dist/actions/TransactionManager.d.ts +7 -2
  8. package/dist/actions/actionKeys.d.ts +75 -13
  9. package/dist/actions/actionKeys.js +131 -16
  10. package/dist/actions/actionResponse.js +3 -3
  11. package/dist/actions/index.d.ts +2 -0
  12. package/dist/actions/index.js +2 -0
  13. package/dist/actions/recordDelete.d.ts +118 -0
  14. package/dist/actions/recordDelete.js +112 -0
  15. package/dist/actions/recordIdParam.d.ts +77 -0
  16. package/dist/actions/recordIdParam.js +37 -0
  17. package/dist/actions/serverActionHandler.d.ts +1 -1
  18. package/dist/actions/serverActionHandler.js +1 -1
  19. package/dist/adapters/ValueDataSource.d.ts +6 -1
  20. package/dist/adapters/ValueDataSource.js +1090 -98
  21. package/dist/adapters/batchTransaction.d.ts +1 -1
  22. package/dist/adapters/batchTransaction.js +1 -1
  23. package/dist/builder/schema-builder.d.ts +38 -81
  24. package/dist/builder/schema-builder.js +33 -152
  25. package/dist/data-scope/ViewDataProvider.d.ts +1 -1
  26. package/dist/data-scope/ViewDataProvider.js +21 -1
  27. package/dist/data-scope/element-data-source.d.ts +261 -7
  28. package/dist/data-scope/element-data-source.js +342 -52
  29. package/dist/data-scope/index.d.ts +9 -4
  30. package/dist/data-scope/index.js +9 -4
  31. package/dist/evaluator/ExpressionEvaluator.d.ts +128 -1
  32. package/dist/evaluator/ExpressionEvaluator.js +226 -13
  33. package/dist/evaluator/FormulaFunctions.d.ts +0 -10
  34. package/dist/evaluator/FormulaFunctions.js +166 -27
  35. package/dist/evaluator/SafeExpressionParser.js +0 -4
  36. package/dist/evaluator/declaredPredicate.d.ts +93 -9
  37. package/dist/evaluator/declaredPredicate.js +118 -17
  38. package/dist/evaluator/fieldRules.d.ts +107 -4
  39. package/dist/evaluator/fieldRules.js +231 -35
  40. package/dist/evaluator/index.d.ts +2 -0
  41. package/dist/evaluator/index.js +2 -0
  42. package/dist/evaluator/listConditional.d.ts +125 -9
  43. package/dist/evaluator/listConditional.js +167 -26
  44. package/dist/evaluator/optionRules.d.ts +126 -0
  45. package/dist/evaluator/optionRules.js +141 -4
  46. package/dist/evaluator/predicateInput.d.ts +15 -4
  47. package/dist/evaluator/predicateInput.js +35 -2
  48. package/dist/evaluator/rowPredicateCanon.d.ts +56 -0
  49. package/dist/evaluator/rowPredicateCanon.js +158 -0
  50. package/dist/evaluator/subjectPermissions.d.ts +76 -0
  51. package/dist/evaluator/subjectPermissions.js +44 -0
  52. package/dist/evaluator/unevaluablePredicate.d.ts +57 -0
  53. package/dist/evaluator/unevaluablePredicate.js +70 -0
  54. package/dist/index.d.ts +18 -0
  55. package/dist/index.js +97 -2
  56. package/dist/protocols/index.d.ts +0 -1
  57. package/dist/protocols/index.js +9 -1
  58. package/dist/registry/Registry.d.ts +397 -48
  59. package/dist/registry/Registry.js +263 -11
  60. package/dist/registry/WidgetRegistry.js +7 -3
  61. package/dist/registry/html-tier-intrinsics.d.ts +90 -0
  62. package/dist/registry/html-tier-intrinsics.js +110 -0
  63. package/dist/registry/public-blocks.d.ts +8 -0
  64. package/dist/registry/public-blocks.js +57 -0
  65. package/dist/theme/ThemeEngine.js +1 -1
  66. package/dist/theme/index.d.ts +1 -1
  67. package/dist/theme/index.js +1 -1
  68. package/dist/types/index.d.ts +92 -13
  69. package/dist/utils/chart-category-key.d.ts +82 -0
  70. package/dist/utils/chart-category-key.js +84 -0
  71. package/dist/utils/chart-measure-key.d.ts +64 -0
  72. package/dist/utils/chart-measure-key.js +65 -0
  73. package/dist/utils/chart-presentation.d.ts +188 -0
  74. package/dist/utils/chart-presentation.js +345 -0
  75. package/dist/utils/chart-series.d.ts +271 -31
  76. package/dist/utils/chart-series.js +478 -55
  77. package/dist/utils/column-identity.d.ts +43 -0
  78. package/dist/utils/column-identity.js +47 -1
  79. package/dist/utils/column-sortability.d.ts +157 -0
  80. package/dist/utils/column-sortability.js +217 -0
  81. package/dist/utils/dashboard-filters.d.ts +38 -6
  82. package/dist/utils/dashboard-filters.js +107 -61
  83. package/dist/utils/dataset-format.d.ts +211 -30
  84. package/dist/utils/dataset-format.js +407 -52
  85. package/dist/utils/date-display.d.ts +354 -0
  86. package/dist/utils/date-display.js +463 -0
  87. package/dist/utils/date-macros.js +7 -0
  88. package/dist/utils/debug.js +7 -0
  89. package/dist/utils/drill-down.d.ts +78 -0
  90. package/dist/utils/drill-down.js +93 -0
  91. package/dist/utils/emptiness.d.ts +96 -0
  92. package/dist/utils/emptiness.js +101 -0
  93. package/dist/utils/expand-fields.d.ts +171 -11
  94. package/dist/utils/expand-fields.js +171 -11
  95. package/dist/utils/extract-records.d.ts +65 -5
  96. package/dist/utils/extract-records.js +65 -8
  97. package/dist/utils/filter-converter.d.ts +152 -4
  98. package/dist/utils/filter-converter.js +1092 -22
  99. package/dist/utils/filter-tokens.d.ts +49 -5
  100. package/dist/utils/filter-tokens.js +105 -34
  101. package/dist/utils/freeze-schema.d.ts +38 -1
  102. package/dist/utils/freeze-schema.js +10 -0
  103. package/dist/utils/grouping-fields.d.ts +61 -0
  104. package/dist/utils/grouping-fields.js +84 -0
  105. package/dist/utils/humanize-label.d.ts +60 -0
  106. package/dist/utils/humanize-label.js +62 -0
  107. package/dist/utils/managedBy.d.ts +30 -5
  108. package/dist/utils/managedBy.js +5 -5
  109. package/dist/utils/native-date-value.d.ts +48 -0
  110. package/dist/utils/native-date-value.js +167 -0
  111. package/dist/utils/non-grid-row-ceiling.d.ts +143 -0
  112. package/dist/utils/non-grid-row-ceiling.js +141 -0
  113. package/dist/utils/normalize-list-view.d.ts +131 -1
  114. package/dist/utils/normalize-list-view.js +248 -6
  115. package/dist/utils/number-display.d.ts +70 -17
  116. package/dist/utils/number-display.js +34 -12
  117. package/dist/utils/object-aggregate-query.d.ts +113 -0
  118. package/dist/utils/object-aggregate-query.js +50 -0
  119. package/dist/utils/parent-scope.d.ts +123 -0
  120. package/dist/utils/parent-scope.js +140 -0
  121. package/dist/utils/predicate-fields.d.ts +62 -4
  122. package/dist/utils/predicate-fields.js +169 -4
  123. package/dist/utils/record-color.d.ts +75 -0
  124. package/dist/utils/record-color.js +65 -0
  125. package/dist/utils/record-source.d.ts +298 -0
  126. package/dist/utils/record-source.js +331 -0
  127. package/dist/utils/record-title.d.ts +148 -8
  128. package/dist/utils/record-title.js +220 -26
  129. package/dist/utils/reference-keys.d.ts +21 -22
  130. package/dist/utils/reference-keys.js +532 -29
  131. package/dist/utils/retired-field-types.d.ts +90 -0
  132. package/dist/utils/retired-field-types.js +124 -0
  133. package/dist/utils/sort-query.d.ts +128 -26
  134. package/dist/utils/sort-query.js +240 -13
  135. package/dist/utils/text-comparand.d.ts +92 -0
  136. package/dist/utils/text-comparand.js +99 -0
  137. package/dist/utils/unmaterialized-fields.d.ts +52 -0
  138. package/dist/utils/unmaterialized-fields.js +57 -0
  139. package/dist/utils/without-denied-fields.d.ts +49 -0
  140. package/dist/utils/without-denied-fields.js +52 -0
  141. package/dist/validation/index.d.ts +9 -4
  142. package/dist/validation/index.js +9 -4
  143. package/dist/validation/schema-validator.d.ts +1 -1
  144. package/dist/validation/schema-validator.js +305 -82
  145. package/dist/validation/server-owned-value.d.ts +62 -0
  146. package/dist/validation/server-owned-value.js +99 -0
  147. package/dist/validation/validators/object-validation-engine.d.ts +1 -1
  148. package/dist/validation/validators/object-validation-engine.js +14 -5
  149. package/package.json +8 -9
  150. package/dist/__benchmarks__/core.bench.d.ts +0 -8
  151. package/dist/__benchmarks__/core.bench.js +0 -53
  152. package/dist/data-scope/DataScopeManager.d.ts +0 -127
  153. package/dist/data-scope/DataScopeManager.js +0 -229
  154. package/dist/protocols/ResponsiveProtocol.d.ts +0 -73
  155. package/dist/protocols/ResponsiveProtocol.js +0 -158
  156. package/dist/validation/validation-engine.d.ts +0 -88
  157. package/dist/validation/validation-engine.js +0 -434
@@ -0,0 +1,112 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ const PERMISSION_SET_OBJECT = 'sys_permission_set';
9
+ /** ADR-0094: is this permission-set row owned by an installed package? */
10
+ function isPackageOwned(row) {
11
+ return row?.managed_by === 'package';
12
+ }
13
+ /**
14
+ * The record-delete core: `confirmText` is the question to ask before deleting
15
+ * one record, `run` performs the delete (one record, or several settled
16
+ * together) and reports it. See the module docblock for objectui#10383 and
17
+ * ADR-0094.
18
+ */
19
+ export const recordDelete = Object.freeze({
20
+ /**
21
+ * The question to ask before deleting ONE record: the reset question for a
22
+ * package-owned permission set (ADR-0094), the plain delete question
23
+ * otherwise. Reads only the row it is handed — no lookup.
24
+ */
25
+ confirmText(deps, record) {
26
+ const { objectName, t } = deps;
27
+ return objectName === PERMISSION_SET_OBJECT && isPackageOwned(record)
28
+ ? t('objectActions.resetPackageSetConfirm', {
29
+ defaultValue: 'This permission set ships with an installed package and cannot be removed. ' +
30
+ 'Deleting resets it to the shipped baseline and discards your environment customization. Continue?',
31
+ })
32
+ : t('objectActions.deleteConfirm');
33
+ },
34
+ /**
35
+ * Delete, refresh and report. Several records (`params.records`, more than
36
+ * one with an `id`) are deleted one call each and settled together, then the
37
+ * list refreshes and ONE summary toast reports the batch. Otherwise one
38
+ * record is deleted; on success the list refreshes and a success toast shows
39
+ * (the reset copy for a package-owned permission set), on failure an error
40
+ * toast carries the error message and the list is left as it is.
41
+ */
42
+ async run(deps, request) {
43
+ const { objectName, t, label, dataSource, toast, onRefresh } = deps;
44
+ const params = request.params;
45
+ const records = Array.isArray(params?.records)
46
+ ? params.records.filter((r) => r?.id != null)
47
+ : null;
48
+ // Bulk path — delete every record in parallel and report a summary.
49
+ if (records && records.length > 1) {
50
+ const results = await Promise.allSettled(records.map((r) => dataSource.delete(objectName, r.id)));
51
+ const failed = results.filter((r) => r.status === 'rejected').length;
52
+ const succeeded = results.length - failed;
53
+ onRefresh?.();
54
+ if (failed === 0) {
55
+ toast.success(t('objectActions.bulkDeleteSuccess', {
56
+ count: succeeded,
57
+ label,
58
+ defaultValue: `Deleted ${succeeded} ${label} records`,
59
+ }));
60
+ // `silent`: the summary above is the feedback — without it the runner's
61
+ // post-execution hook adds a second, generic success toast.
62
+ return { success: true, reload: true, silent: true };
63
+ }
64
+ toast.error(t('objectActions.bulkDeletePartial', {
65
+ succeeded,
66
+ failed,
67
+ defaultValue: `${succeeded} deleted, ${failed} failed`,
68
+ }));
69
+ // The summary above is authoritative; returning WITHOUT `error` keeps the
70
+ // runner from toasting the failure a second time.
71
+ return { success: false };
72
+ }
73
+ const recordId = params?.recordId ?? params?.record?.id ?? records?.[0]?.id ?? request.recordId;
74
+ if (!recordId)
75
+ return { success: false, error: t('objectActions.noRecordId') };
76
+ // [ADR-0094] Detect the reset BEFORE the delete (the row still exists), so
77
+ // the success toast tells the truth. A caller that passed the row spares
78
+ // the lookup.
79
+ let packagedSetReset = false;
80
+ if (objectName === PERMISSION_SET_OBJECT) {
81
+ try {
82
+ const row = params?.record?.managed_by !== undefined
83
+ ? params.record
84
+ : await dataSource.findOne(objectName, recordId);
85
+ packagedSetReset = isPackageOwned(row);
86
+ }
87
+ catch { /* best-effort — fall back to the generic delete copy */ }
88
+ }
89
+ try {
90
+ await dataSource.delete(objectName, recordId);
91
+ onRefresh?.();
92
+ toast.success(packagedSetReset
93
+ // No `label` argument, unlike `deleteSuccess` below: this sentence
94
+ // names the permission set by kind rather than by label, so none of
95
+ // the ten packs has a `{{label}}` hole and i18next would drop the
96
+ // argument in silence (objectui#3845).
97
+ ? t('objectActions.resetPackageSetSuccess', {
98
+ defaultValue: 'Permission set reset to its shipped baseline',
99
+ })
100
+ : t('objectActions.deleteSuccess', { label }));
101
+ return { success: true, reload: true, silent: true };
102
+ }
103
+ catch (err) {
104
+ toast.error(t('objectActions.deleteFailed', { label }), {
105
+ description: err.message,
106
+ });
107
+ // The toast above (label + error message) is the feedback; returning
108
+ // WITHOUT `error` keeps the runner from toasting the raw message again.
109
+ return { success: false };
110
+ }
111
+ },
112
+ });
@@ -0,0 +1,77 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Seeding an action's `recordIdParam` from the row — and refusing to dispatch
10
+ * when the row cannot supply it (objectstack#8018).
11
+ *
12
+ * An `api` action declaring `recordIdParam` names the request key that carries
13
+ * the record it acts on; `recordIdField` names the row field whose value seeds
14
+ * it (default `id`). Every call site used to spell the read the same permissive
15
+ * way:
16
+ *
17
+ * ```ts
18
+ * const rowValue = rowRecord[action.recordIdField || 'id'];
19
+ * if (rowValue != null) body[action.recordIdParam] = rowValue; // else: nothing
20
+ * ```
21
+ *
22
+ * The `else` branch is the defect. It cannot distinguish "this row has no such
23
+ * key" from "this row's value is null", and in both cases it drops the parameter
24
+ * and lets the request go out anyway. What reaches the server is a mutation with
25
+ * no record named — and a backend that treats a missing selector as "match
26
+ * nothing" answers `{ status: true }` for having deleted nothing. The user is
27
+ * told the action succeeded. The measured instance was a session-revocation
28
+ * control that revoked nothing, which is the worst shape this can take: a
29
+ * security affordance that reports success while no-op'ing.
30
+ *
31
+ * The absent-key half is reachable from ordinary authoring, not just from bad
32
+ * data: the grid projects `$select` from the listView columns, so until
33
+ * `recordIdField` was harvested into it (see `listViewPredicates`) any action
34
+ * keyed on a non-column field got a row without that key. The harvest closes the
35
+ * common route; this guard closes the class, because a row can still lack the key
36
+ * for reasons projection cannot fix — a server-side read mask that strips the
37
+ * field regardless of projection (`internal: true`), a partial payload handed
38
+ * down from a host, a field the principal cannot read.
39
+ *
40
+ * Contract-first (AGENTS.md #0.1): the answer to an under-specified request is to
41
+ * refuse it at the producer, loudly, not to send it and hope the server objects.
42
+ * The two failures are named separately because they point at different repairs —
43
+ * an absent key is a projection/visibility problem, a null value is a data one.
44
+ */
45
+ /** The minimal action shape this resolution reads. */
46
+ export interface RecordIdParamAction {
47
+ /** Request key that carries the record id. Absent ⇒ no injection is declared. */
48
+ recordIdParam?: string;
49
+ /** Row field whose value seeds it. Defaults to `id`. */
50
+ recordIdField?: string;
51
+ /** Used only to make the refusal message name the action. */
52
+ name?: string;
53
+ label?: string;
54
+ }
55
+ /**
56
+ * Either the value to inject, or the reason the action must not be dispatched.
57
+ * `{}` (neither key) means no injection is declared — carry on unchanged.
58
+ */
59
+ export type RecordIdParamSeed = {
60
+ value: unknown;
61
+ error?: undefined;
62
+ } | {
63
+ value?: undefined;
64
+ error: string;
65
+ } | {
66
+ value?: undefined;
67
+ error?: undefined;
68
+ };
69
+ /**
70
+ * Resolve the value an action's `recordIdParam` should carry, or the refusal.
71
+ *
72
+ * Pure — reads the action and the row, mutates nothing. Returns `{}` when the
73
+ * action declares no `recordIdParam` (nothing to inject) or when there is no row
74
+ * record at all (the caller is on a path where no row context exists; that is not
75
+ * this guard's business).
76
+ */
77
+ export declare function resolveRecordIdParamSeed(action: RecordIdParamAction | null | undefined, rowRecord: Record<string, unknown> | null | undefined): RecordIdParamSeed;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * ObjectUI
3
+ * Copyright (c) 2024-present ObjectStack Inc.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ /**
9
+ * Resolve the value an action's `recordIdParam` should carry, or the refusal.
10
+ *
11
+ * Pure — reads the action and the row, mutates nothing. Returns `{}` when the
12
+ * action declares no `recordIdParam` (nothing to inject) or when there is no row
13
+ * record at all (the caller is on a path where no row context exists; that is not
14
+ * this guard's business).
15
+ */
16
+ export function resolveRecordIdParamSeed(action, rowRecord) {
17
+ const param = action?.recordIdParam;
18
+ if (!param || !rowRecord || typeof rowRecord !== 'object')
19
+ return {};
20
+ const field = action?.recordIdField || 'id';
21
+ const label = action?.label || action?.name || param;
22
+ if (!(field in rowRecord)) {
23
+ return {
24
+ error: `Action "${label}" identifies its record by "${field}", but that field is not ` +
25
+ `present on the row. Add it to the view's columns, or check that it is readable ` +
26
+ `— running without it would send a request that names no record.`,
27
+ };
28
+ }
29
+ const value = rowRecord[field];
30
+ if (value == null) {
31
+ return {
32
+ error: `Action "${label}" identifies its record by "${field}", but this record has no ` +
33
+ `value for it — running without it would send a request that names no record.`,
34
+ };
35
+ }
36
+ return { value };
37
+ }
@@ -52,7 +52,7 @@
52
52
  * // <ActionProvider handlers={{ script }} … /> (or runner.registerHandler('script', script))
53
53
  * ```
54
54
  */
55
- import type { ActionContext, ActionDef, ActionResult } from './ActionRunner';
55
+ import type { ActionContext, ActionDef, ActionResult } from './ActionRunner.js';
56
56
  /** The response surface the dispatcher needs — satisfied by a WHATWG `Response`. */
57
57
  export interface ServerActionFetchResponse {
58
58
  ok: boolean;
@@ -5,7 +5,7 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
- import { interpretActionResponse } from './actionResponse';
8
+ import { interpretActionResponse } from './actionResponse.js';
9
9
  /**
10
10
  * An action that also mounts on list rows (`list_item`) or record pages is
11
11
  * designed to run against a single record. When such an action is launched
@@ -63,6 +63,11 @@ export declare class ValueDataSource<T = any> implements DataSource<T> {
63
63
  onMutation(callback: (event: DataSourceMutationEvent<T>) => void): () => void;
64
64
  /** Get the current number of items */
65
65
  get count(): number;
66
- /** Get a snapshot of all items (cloned) */
66
+ /**
67
+ * Get a snapshot of all items (cloned).
68
+ *
69
+ * Same clone as the constructor and for the same reason — see the note
70
+ * there: `structuredClone`, never a JSON round-trip (objectui#9175).
71
+ */
67
72
  getAll(): T[];
68
73
  }