@jskit-ai/users-web 0.1.178-oldline.2 → 0.1.178

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 (124) hide show
  1. package/package.json +197 -45
  2. package/patterns/account-settings/PATTERN.md +61 -0
  3. package/src/client/bootstrap/user-bootstrap-handler.js +2 -12
  4. package/src/client/composables/account-settings/accountSettingsAvatarUploadRuntime.js +2 -2
  5. package/src/client/composables/useAccountSettingsRuntime.js +3 -3
  6. package/src/client/index.js +0 -16
  7. package/src/client/providers/UsersWebClientProvider.js +13 -14
  8. package/test/bootstrap.test.js +6 -41
  9. package/test/exportsContract.test.js +3 -29
  10. package/test/packageMetadataOwnership.test.js +19 -0
  11. package/test/settingsPlacementContract.test.js +93 -405
  12. package/fixtures/crud-list-date-filters/App.vue +0 -107
  13. package/fixtures/crud-list-date-filters/index.html +0 -12
  14. package/fixtures/crud-list-date-filters/main.js +0 -24
  15. package/fixtures/crud-list-date-filters/vite.config.mjs +0 -18
  16. package/package.descriptor.mjs +0 -468
  17. package/src/client/bulkActions.js +0 -47
  18. package/src/client/components/CrudAddEditScreen.vue +0 -186
  19. package/src/client/components/CrudListBulkActionSurface.vue +0 -126
  20. package/src/client/components/CrudListDateFilterControl.vue +0 -188
  21. package/src/client/components/CrudListFilterSurface.vue +0 -388
  22. package/src/client/components/CrudListRecordActionMenu.vue +0 -120
  23. package/src/client/components/CrudListScreen.vue +0 -501
  24. package/src/client/components/CrudViewScreen.vue +0 -197
  25. package/src/client/composables/crud/crudBindingSupport.js +0 -75
  26. package/src/client/composables/crud/crudHttpClientSupport.js +0 -57
  27. package/src/client/composables/crud/crudJsonApiTransportSupport.js +0 -145
  28. package/src/client/composables/crud/crudLookupFieldLabelSupport.js +0 -151
  29. package/src/client/composables/crud/crudLookupFieldRuntime.js +0 -251
  30. package/src/client/composables/crud/crudSchemaFormHelpers.js +0 -464
  31. package/src/client/composables/internal/crudListFilterLookupSupport.js +0 -161
  32. package/src/client/composables/internal/crudListParentTitleSupport.js +0 -171
  33. package/src/client/composables/internal/useOperationScope.js +0 -144
  34. package/src/client/composables/records/useAddEdit.js +0 -224
  35. package/src/client/composables/records/useCrudAddEdit.js +0 -227
  36. package/src/client/composables/records/useCrudList.js +0 -101
  37. package/src/client/composables/records/useCrudView.js +0 -47
  38. package/src/client/composables/records/useList.js +0 -500
  39. package/src/client/composables/records/useView.js +0 -164
  40. package/src/client/composables/runtime/addEditUiRuntime.js +0 -130
  41. package/src/client/composables/runtime/listUiRuntime.js +0 -123
  42. package/src/client/composables/runtime/modelStateHelpers.js +0 -90
  43. package/src/client/composables/runtime/operationAdapters.js +0 -34
  44. package/src/client/composables/runtime/operationUiHelpers.js +0 -125
  45. package/src/client/composables/runtime/operationValidationHelpers.js +0 -51
  46. package/src/client/composables/runtime/useAddEditCore.js +0 -112
  47. package/src/client/composables/runtime/useCommandCore.js +0 -123
  48. package/src/client/composables/runtime/useEndpointResource.js +0 -199
  49. package/src/client/composables/runtime/useFieldErrorBag.js +0 -61
  50. package/src/client/composables/runtime/useListCore.js +0 -112
  51. package/src/client/composables/runtime/useUiFeedback.js +0 -98
  52. package/src/client/composables/runtime/useViewCore.js +0 -93
  53. package/src/client/composables/runtime/viewUiRuntime.js +0 -96
  54. package/src/client/composables/support/errorMessageHelpers.js +0 -66
  55. package/src/client/composables/support/listQueryParamSupport.js +0 -473
  56. package/src/client/composables/support/listSearchSupport.js +0 -70
  57. package/src/client/composables/support/refValueHelpers.js +0 -19
  58. package/src/client/composables/support/requestQueryRuntimeSupport.js +0 -141
  59. package/src/client/composables/support/resourceLoadStateHelpers.js +0 -229
  60. package/src/client/composables/support/routeTemplateHelpers.js +0 -285
  61. package/src/client/composables/support/scopeHelpers.js +0 -145
  62. package/src/client/composables/useAccess.js +0 -109
  63. package/src/client/composables/useCommand.js +0 -118
  64. package/src/client/composables/useCrudAddEditScreen.js +0 -88
  65. package/src/client/composables/useCrudDeleteAction.js +0 -160
  66. package/src/client/composables/useCrudListBulkActions.js +0 -147
  67. package/src/client/composables/useCrudListFilterLookups.js +0 -146
  68. package/src/client/composables/useCrudListFilters.js +0 -339
  69. package/src/client/composables/useCrudListParentTitle.js +0 -151
  70. package/src/client/composables/useCrudListRowActions.js +0 -144
  71. package/src/client/composables/useCrudListScreen.js +0 -237
  72. package/src/client/composables/useCrudViewScreen.js +0 -77
  73. package/src/client/composables/usePagedCollection.js +0 -181
  74. package/src/client/composables/usePaths.js +0 -120
  75. package/src/client/composables/useRealtimeQueryInvalidation.js +0 -156
  76. package/src/client/composables/useScopeRuntime.js +0 -135
  77. package/src/client/composables/useSurfaceRouteContext.js +0 -25
  78. package/src/client/filters.js +0 -15
  79. package/src/client/lib/httpClient.js +0 -47
  80. package/src/client/lib/permissions.js +0 -34
  81. package/src/client/rowActions.js +0 -47
  82. package/src/client/support/contractGuards.js +0 -34
  83. package/src/client/support/crudListDateFilterSupport.js +0 -91
  84. package/test/addEditUiRuntime.test.js +0 -110
  85. package/test/crudBindingSupport.test.js +0 -110
  86. package/test/crudHttpClientSupport.test.js +0 -77
  87. package/test/crudJsonApiTransportSupport.test.js +0 -179
  88. package/test/crudListBulkActionSurface.test.js +0 -27
  89. package/test/crudListDateFilterSupport.test.js +0 -92
  90. package/test/crudListDateFilterSurface.browser.test.js +0 -273
  91. package/test/crudListFilterSurface.test.js +0 -90
  92. package/test/crudLookupFieldRuntime.test.js +0 -264
  93. package/test/crudScreenComponents.test.js +0 -108
  94. package/test/errorIntentContract.test.js +0 -31
  95. package/test/errorMessageHelpers.test.js +0 -28
  96. package/test/listQueryParamSupport.test.js +0 -223
  97. package/test/listUiRuntime.test.js +0 -102
  98. package/test/operationValidationHelpers.test.js +0 -64
  99. package/test/packageDescriptorOwnership.test.js +0 -18
  100. package/test/permissions.test.js +0 -35
  101. package/test/refValueHelpers.test.js +0 -14
  102. package/test/requestTransportOptions.test.js +0 -457
  103. package/test/resourceLoadStateHelpers.test.js +0 -189
  104. package/test/routeTemplateHelpers.test.js +0 -85
  105. package/test/scopeHelpers.test.js +0 -57
  106. package/test/useAddEditCore.test.js +0 -124
  107. package/test/useAddEditRequestQueryParams.test.js +0 -190
  108. package/test/useCrudAddEdit.test.js +0 -435
  109. package/test/useCrudDeleteAction.test.js +0 -139
  110. package/test/useCrudListBulkActions.test.js +0 -65
  111. package/test/useCrudListFilterLookups.test.js +0 -114
  112. package/test/useCrudListFilters.test.js +0 -293
  113. package/test/useCrudListParentTitle.test.js +0 -262
  114. package/test/useCrudListRowActions.test.js +0 -77
  115. package/test/useListRouteInitialization.test.js +0 -337
  116. package/test/useListSearchSupport.test.js +0 -61
  117. package/test/usePagedCollection.test.js +0 -53
  118. package/test/useViewRequestQueryParams.test.js +0 -20
  119. package/test/viewCoreLoading.test.js +0 -44
  120. package/test/viewUiRuntime.test.js +0 -95
  121. /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsNotificationsSection.vue +0 -0
  122. /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsPreferencesSection.vue +0 -0
  123. /package/{templates → patterns/account-settings/example}/src/components/account/settings/AccountSettingsProfileSection.vue +0 -0
  124. /package/{templates → patterns/account-settings/example}/src/pages/account/index.vue +0 -0
@@ -1,171 +0,0 @@
1
- import {
2
- normalizeCrudLookupContainerKey,
3
- resolveCrudLookupApiPathFromNamespace,
4
- resolveCrudLookupFieldKeyFromRouteParam
5
- } from "@jskit-ai/kernel/shared/support/crudLookup";
6
- import { buildCrudFieldContractMap } from "@jskit-ai/kernel/shared/support/crudFieldContract";
7
- import { normalizeText } from "@jskit-ai/kernel/shared/support/normalize";
8
- import { resolveLookupFieldDisplayValue, resolveRecordTitle } from "../crud/crudLookupFieldLabelSupport.js";
9
- import { resolveRouteParamNamesInOrder, toRouteParamValue } from "../support/routeTemplateHelpers.js";
10
-
11
- function singularizeLabel(value = "") {
12
- const normalizedValue = normalizeText(value);
13
- if (!normalizedValue) {
14
- return "";
15
- }
16
- if (normalizedValue.endsWith("ies")) {
17
- return `${normalizedValue.slice(0, -3)}y`;
18
- }
19
- if (normalizedValue.endsWith("s") && !normalizedValue.endsWith("ss")) {
20
- return normalizedValue.slice(0, -1);
21
- }
22
- return normalizedValue;
23
- }
24
-
25
- function toTitleLabel(value = "") {
26
- const normalizedValue = normalizeText(value)
27
- .replace(/Id$/u, "")
28
- .replace(/[_-]+/gu, " ")
29
- .replace(/([a-z0-9])([A-Z])/gu, "$1 $2")
30
- .trim();
31
- if (!normalizedValue) {
32
- return "";
33
- }
34
-
35
- return normalizedValue
36
- .split(/\s+/u)
37
- .filter(Boolean)
38
- .map((entry) => entry.charAt(0).toUpperCase() + entry.slice(1))
39
- .join(" ");
40
- }
41
-
42
- function resolveEntityLabel(routeParamKey = "", relationNamespace = "") {
43
- const routeLabel = singularizeLabel(toTitleLabel(routeParamKey));
44
- if (routeLabel) {
45
- return routeLabel;
46
- }
47
-
48
- const namespaceLabel = singularizeLabel(toTitleLabel(relationNamespace));
49
- if (namespaceLabel) {
50
- return namespaceLabel;
51
- }
52
-
53
- return "Record";
54
- }
55
-
56
- function resolveLookupFieldMeta(resource = {}, fieldKey = "") {
57
- const normalizedFieldKey = normalizeText(fieldKey);
58
- if (!normalizedFieldKey) {
59
- return null;
60
- }
61
-
62
- const entry = buildCrudFieldContractMap(resource, {
63
- context: "crud list parent title resource field contract"
64
- })[normalizedFieldKey];
65
- if (!entry) {
66
- return null;
67
- }
68
-
69
- const relation = entry?.relation;
70
- if (!relation || normalizeText(relation.kind).toLowerCase() !== "lookup") {
71
- return null;
72
- }
73
-
74
- return entry;
75
- }
76
-
77
- function resolveCrudListParentDescriptor({ resource = {}, route = null, recordIdParam = "recordId" } = {}) {
78
- const orderedRouteParamNames = resolveRouteParamNamesInOrder(route);
79
- if (orderedRouteParamNames.length < 1) {
80
- return null;
81
- }
82
-
83
- const normalizedRecordIdParam = normalizeText(recordIdParam) || "recordId";
84
- for (const routeParamKey of [...orderedRouteParamNames].reverse()) {
85
- if (routeParamKey === normalizedRecordIdParam) {
86
- continue;
87
- }
88
-
89
- const fieldKey = resolveCrudLookupFieldKeyFromRouteParam(resource, routeParamKey);
90
- if (!fieldKey) {
91
- continue;
92
- }
93
-
94
- const fieldContractEntry = resolveLookupFieldMeta(resource, fieldKey);
95
- if (!fieldContractEntry) {
96
- continue;
97
- }
98
-
99
- const relation = fieldContractEntry.relation || {};
100
- const relationNamespace = normalizeText(relation.namespace);
101
- const containerKey = normalizeCrudLookupContainerKey(relation.containerKey, {
102
- defaultValue: resource?.contract?.lookup?.containerKey || "lookups"
103
- });
104
-
105
- return Object.freeze({
106
- fieldKey,
107
- routeParamKey,
108
- relationNamespace,
109
- entityLabel: resolveEntityLabel(routeParamKey, relationNamespace),
110
- labelKey: normalizeText(relation.labelKey),
111
- fieldDescriptor: Object.freeze({
112
- key: fieldKey,
113
- relation: Object.freeze({
114
- kind: "lookup",
115
- valueKey: normalizeText(relation.valueKey) || "id",
116
- labelKey: normalizeText(relation.labelKey),
117
- containerKey
118
- })
119
- }),
120
- apiUrlTemplate: relationNamespace
121
- ? `${resolveCrudLookupApiPathFromNamespace(relationNamespace)}/:${routeParamKey}`
122
- : ""
123
- });
124
- }
125
-
126
- return null;
127
- }
128
-
129
- function resolveCrudListParentTitleFromItems(items = [], descriptor = null) {
130
- const sourceItems = Array.isArray(items) ? items : [];
131
- if (!descriptor?.fieldDescriptor) {
132
- return "";
133
- }
134
-
135
- for (const item of sourceItems) {
136
- const rawParentValue = toRouteParamValue(item?.[descriptor.fieldKey]);
137
- const resolvedTitle = normalizeText(resolveLookupFieldDisplayValue(item, descriptor.fieldDescriptor));
138
- if (resolvedTitle && rawParentValue && resolvedTitle === rawParentValue) {
139
- continue;
140
- }
141
- if (resolvedTitle) {
142
- return resolvedTitle;
143
- }
144
- }
145
-
146
- return "";
147
- }
148
-
149
- function resolveCrudListParentRecordTitle(record = {}, descriptor = null) {
150
- const resolvedTitle = resolveRecordTitle(record, {
151
- fallbackKey: normalizeText(descriptor?.labelKey),
152
- defaultValue: ""
153
- });
154
- if (resolvedTitle && resolvedTitle !== "-") {
155
- return resolvedTitle;
156
- }
157
-
158
- const entityLabel = normalizeText(descriptor?.entityLabel) || "Record";
159
- const recordId = toRouteParamValue(record?.id);
160
- if (recordId) {
161
- return `${entityLabel} #${recordId}`;
162
- }
163
-
164
- return "";
165
- }
166
-
167
- export {
168
- resolveCrudListParentDescriptor,
169
- resolveCrudListParentRecordTitle,
170
- resolveCrudListParentTitleFromItems
171
- };
@@ -1,144 +0,0 @@
1
- import { computed, unref } from "vue";
2
- import { ROUTE_VISIBILITY_WORKSPACE } from "@jskit-ai/kernel/shared/support/visibility";
3
- import { useScopeRuntime } from "../useScopeRuntime.js";
4
- import { useOperationRealtime } from "../useRealtimeQueryInvalidation.js";
5
- import {
6
- normalizePermissions,
7
- resolvePermissionAccess,
8
- resolveEnabled,
9
- resolveQueryKey
10
- } from "../support/scopeHelpers.js";
11
-
12
- function normalizePermissionSets(permissionSets = {}) {
13
- const source = permissionSets && typeof permissionSets === "object" && !Array.isArray(permissionSets)
14
- ? permissionSets
15
- : {};
16
- const normalized = {};
17
-
18
- for (const [key, value] of Object.entries(source)) {
19
- normalized[key] = normalizePermissions(value);
20
- }
21
-
22
- return normalized;
23
- }
24
-
25
- function hasAnyPermissions(permissionSets = {}) {
26
- for (const list of Object.values(permissionSets)) {
27
- if (Array.isArray(list) && list.length > 0) {
28
- return true;
29
- }
30
- }
31
-
32
- return false;
33
- }
34
-
35
- function useOperationScope({
36
- ownershipFilter = ROUTE_VISIBILITY_WORKSPACE,
37
- surfaceId = "",
38
- access = "auto",
39
- placementSource = "users-web.operation",
40
- apiSuffix = "",
41
- model,
42
- readEnabled = true,
43
- queryKeyFactory = null,
44
- permissionSets = {},
45
- realtime = null
46
- } = {}) {
47
- const normalizedPermissionSets = normalizePermissionSets(permissionSets);
48
- const scopeRuntime = useScopeRuntime({
49
- ownershipFilter,
50
- surfaceId,
51
- accessMode: access,
52
- hasPermissionRequirements: hasAnyPermissions(normalizedPermissionSets),
53
- placementSource
54
- });
55
- const normalizedOwnershipFilter = scopeRuntime.normalizedOwnershipFilter;
56
- const routeContext = scopeRuntime.routeContext;
57
- const scopeParamValue = scopeRuntime.scopeParamValue;
58
- const hasRequiredRouteScope = scopeRuntime.hasRequiredRouteScope;
59
- const accessRuntime = scopeRuntime.access;
60
-
61
- const apiPath = computed(() =>
62
- scopeRuntime.resolveApiPath(apiSuffix, {
63
- model
64
- })
65
- );
66
-
67
- const queryEnabled = computed(() =>
68
- resolveEnabled(readEnabled, {
69
- surfaceId: routeContext.currentSurfaceId.value,
70
- scopeParamValue: scopeParamValue.value,
71
- ownershipFilter: normalizedOwnershipFilter,
72
- model
73
- })
74
- );
75
-
76
- const queryKey = computed(() =>
77
- resolveQueryKey(queryKeyFactory, {
78
- surfaceId: routeContext.currentSurfaceId.value,
79
- scopeParamValue: scopeParamValue.value,
80
- ownershipFilter: normalizedOwnershipFilter
81
- })
82
- );
83
- const realtimeBinding = useOperationRealtime({
84
- realtime,
85
- queryKey: typeof queryKeyFactory === "function" ? queryKey : null,
86
- enabled: computed(() => hasRequiredRouteScope.value && Boolean(apiPath.value))
87
- });
88
-
89
- function queryCanRun(accessGate = true) {
90
- return computed(() =>
91
- queryEnabled.value &&
92
- hasRequiredRouteScope.value &&
93
- Boolean(apiPath.value) &&
94
- Boolean(unref(accessGate))
95
- );
96
- }
97
-
98
- function permissionGate(key = "") {
99
- const list = normalizedPermissionSets[String(key || "")] || [];
100
- return computed(() => resolvePermissionAccess(accessRuntime, list));
101
- }
102
-
103
- function loadError(baseError = "") {
104
- return computed(() => {
105
- if (scopeRuntime.routeScopeError.value) {
106
- return scopeRuntime.routeScopeError.value;
107
- }
108
-
109
- const bootstrapError = String(accessRuntime.bootstrapError.value || "").trim();
110
- if (bootstrapError) {
111
- return bootstrapError;
112
- }
113
-
114
- if (baseError === undefined || baseError === null || baseError === "") {
115
- return "";
116
- }
117
-
118
- return String(unref(baseError) || "").trim();
119
- });
120
- }
121
-
122
- function isLoading(baseLoading = false) {
123
- return computed(() => Boolean(unref(baseLoading)) || accessRuntime.isBootstrapping.value);
124
- }
125
-
126
- return Object.freeze({
127
- scopeRuntime,
128
- routeContext,
129
- normalizedOwnershipFilter,
130
- scopeParamValue,
131
- hasRequiredRouteScope,
132
- access: accessRuntime,
133
- apiPath,
134
- queryEnabled,
135
- queryKey,
136
- queryCanRun,
137
- realtime: realtimeBinding,
138
- permissionGate,
139
- loadError,
140
- isLoading
141
- });
142
- }
143
-
144
- export { useOperationScope };
@@ -1,224 +0,0 @@
1
- import { computed, proxyRefs } from "vue";
2
- import { useRoute } from "vue-router";
3
- import { ROUTE_VISIBILITY_WORKSPACE } from "@jskit-ai/kernel/shared/support/visibility";
4
- import { useAddEditCore } from "../runtime/useAddEditCore.js";
5
- import { useEndpointResource } from "../runtime/useEndpointResource.js";
6
- import { resolveOperationAdapter } from "../runtime/operationAdapters.js";
7
- import { createAddEditUiRuntime } from "../runtime/addEditUiRuntime.js";
8
- import { useUiFeedback } from "../runtime/useUiFeedback.js";
9
- import { useFieldErrorBag } from "../runtime/useFieldErrorBag.js";
10
- import {
11
- setupRouteChangeCleanup,
12
- setupOperationErrorReporting
13
- } from "../runtime/operationUiHelpers.js";
14
- import {
15
- resolveResourceMessages
16
- } from "../support/scopeHelpers.js";
17
- import { createRequestQueryRuntime } from "../support/requestQueryRuntimeSupport.js";
18
- import { resolveRouteParamNamesInOrder } from "../support/routeTemplateHelpers.js";
19
-
20
- function useAddEdit({
21
- ownershipFilter = ROUTE_VISIBILITY_WORKSPACE,
22
- surfaceId = "",
23
- access = "auto",
24
- resource = null,
25
- apiSuffix = "",
26
- queryKeyFactory = null,
27
- viewPermissions = [],
28
- savePermissions = [],
29
- readMethod = "GET",
30
- readEnabled = true,
31
- writeMethod = "PATCH",
32
- client = null,
33
- transport = null,
34
- requestRecovery = null,
35
- requestRecoveryLabel = "Resource",
36
- placementSource = "users-web.add-edit",
37
- fallbackLoadError = "Unable to load resource.",
38
- fallbackSaveError = "Unable to save resource.",
39
- fieldErrorKeys = [],
40
- clearOnRouteChange = true,
41
- model,
42
- input,
43
- mapLoadedToModel,
44
- buildRawPayload,
45
- buildSavePayload,
46
- onSaveSuccess,
47
- requestQueryParams = null,
48
- recordIdParam = "recordId",
49
- routeParams = null,
50
- routeRecordId = null,
51
- apiUrlTemplate = "",
52
- viewUrlTemplate = "",
53
- listUrlTemplate = "",
54
- saveRecordIdSelector = null,
55
- messages = {},
56
- realtime = null,
57
- adapter = null
58
- } = {}) {
59
- const route = useRoute();
60
- const addEditUiRuntime = createAddEditUiRuntime({
61
- recordIdParam,
62
- routeParams: routeParams ?? computed(() => route?.params || {}),
63
- routeParamNames: computed(() => resolveRouteParamNamesInOrder(route)),
64
- routePath: computed(() => route?.path || ""),
65
- routeRecordId,
66
- apiUrlTemplate,
67
- viewUrlTemplate,
68
- listUrlTemplate,
69
- saveRecordIdSelector
70
- });
71
- const normalizedApiUrlTemplate = String(apiUrlTemplate || "").trim();
72
- const effectiveApiSuffix = normalizedApiUrlTemplate ? addEditUiRuntime.apiSuffix : apiSuffix;
73
- const operationAdapter = resolveOperationAdapter(adapter, {
74
- context: "useAddEdit adapter"
75
- });
76
- const operationScope = operationAdapter.useOperationScope({
77
- ownershipFilter,
78
- surfaceId,
79
- access,
80
- placementSource,
81
- apiSuffix: effectiveApiSuffix,
82
- model,
83
- readEnabled,
84
- queryKeyFactory,
85
- permissionSets: {
86
- view: viewPermissions,
87
- save: savePermissions
88
- },
89
- realtime
90
- });
91
- const routeContext = operationScope.routeContext;
92
- const effectiveMessages = {
93
- ...resolveResourceMessages(resource, {
94
- validation: "Fix invalid values and try again.",
95
- saveSuccess: "Saved.",
96
- saveError: "Unable to save."
97
- }),
98
- ...(messages && typeof messages === "object" ? messages : {})
99
- };
100
-
101
- const canView = operationScope.permissionGate("view");
102
- const canSave = operationScope.permissionGate("save");
103
- const queryCanRun = operationScope.queryCanRun(canView);
104
- const queryParamsContext = computed(() => {
105
- return Object.freeze({
106
- surfaceId: operationScope.routeContext.currentSurfaceId.value,
107
- scopeParamValue: operationScope.scopeParamValue.value,
108
- ownershipFilter: operationScope.normalizedOwnershipFilter,
109
- recordId: addEditUiRuntime.recordId.value,
110
- model
111
- });
112
- });
113
- const requestQueryRuntime = createRequestQueryRuntime({
114
- requestQueryParams,
115
- context: queryParamsContext,
116
- sourceQueryKey: operationScope.queryKey
117
- });
118
-
119
- const endpointResource = useEndpointResource({
120
- queryKey: requestQueryRuntime.queryKey,
121
- path: operationScope.apiPath,
122
- enabled: queryCanRun,
123
- client,
124
- readMethod,
125
- writeMethod,
126
- readQuery: requestQueryRuntime.requestQuery,
127
- transport,
128
- requestRecovery,
129
- requestRecoveryLabel,
130
- fallbackLoadError,
131
- fallbackSaveError: String(fallbackSaveError || effectiveMessages.saveError || "Unable to save resource.")
132
- });
133
-
134
- const feedback = useUiFeedback({
135
- source: `${placementSource}.feedback`
136
- });
137
- const fieldBag = useFieldErrorBag(fieldErrorKeys);
138
-
139
- const addEdit = useAddEditCore({
140
- model,
141
- resource: endpointResource,
142
- queryKey: requestQueryRuntime.queryKey,
143
- canSave,
144
- fieldBag,
145
- feedback,
146
- input,
147
- mapLoadedToModel,
148
- buildRawPayload,
149
- buildSavePayload,
150
- onSaveSuccess,
151
- messages: effectiveMessages
152
- });
153
-
154
- setupRouteChangeCleanup({
155
- enabled: clearOnRouteChange,
156
- route: routeContext.route,
157
- feedback,
158
- fieldBag
159
- });
160
-
161
- const isInitialLoading = operationScope.isLoading(endpointResource.isInitialLoading);
162
- const isFetching = operationScope.isLoading(endpointResource.isFetching);
163
- const isRefetching = computed(() => Boolean(isFetching.value && !isInitialLoading.value));
164
- const isFieldLocked = computed(() =>
165
- Boolean(!canSave.value || addEdit.saving.value || isRefetching.value)
166
- );
167
- const isSubmitDisabled = computed(() =>
168
- Boolean(isInitialLoading.value || isRefetching.value || !canSave.value)
169
- );
170
- const loadError = operationScope.loadError(endpointResource.loadError);
171
- const isLoading = operationScope.isLoading(endpointResource.isLoading);
172
- const canRetryLoad = computed(() => Boolean(readEnabled !== false && endpointResource?.reload));
173
-
174
- async function refresh() {
175
- if (!canRetryLoad.value) {
176
- return null;
177
- }
178
-
179
- return endpointResource.reload();
180
- }
181
-
182
- setupOperationErrorReporting({
183
- source: `${placementSource}.load`,
184
- loadError,
185
- dedupeWindowMs: 0,
186
- loadActionFactory: () => canRetryLoad.value
187
- ? {
188
- label: "Retry",
189
- dismissOnRun: true,
190
- handler() {
191
- void refresh();
192
- }
193
- }
194
- : null
195
- });
196
-
197
- return proxyRefs({
198
- canView,
199
- canSave,
200
- loadError,
201
- isInitialLoading,
202
- isFetching,
203
- isRefetching,
204
- isFieldLocked,
205
- isSubmitDisabled,
206
- canRetryLoad,
207
- isLoading,
208
- isSaving: addEdit.saving,
209
- fieldErrors: addEdit.fieldErrors,
210
- message: addEdit.message,
211
- messageType: addEdit.messageType,
212
- submit: addEdit.submit,
213
- refresh,
214
- resource: endpointResource,
215
- recordId: addEditUiRuntime.recordId,
216
- listUrl: addEditUiRuntime.listUrl,
217
- cancelUrl: addEditUiRuntime.cancelUrl,
218
- resolveParams: addEditUiRuntime.resolveParams,
219
- resolveViewUrl: addEditUiRuntime.resolveViewUrl,
220
- resolveSavedViewUrl: addEditUiRuntime.resolveSavedViewUrl
221
- });
222
- }
223
-
224
- export { useAddEdit };