@jsenv/navi 0.0.1 → 0.1.1
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/jsenv_navi.js +22959 -0
- package/index.js +66 -16
- package/package.json +23 -11
- package/src/actions.js +50 -26
- package/src/browser_integration/browser_integration.js +31 -6
- package/src/browser_integration/via_history.js +42 -9
- package/src/components/action_execution/render_actionable_component.jsx +6 -4
- package/src/components/action_execution/use_action.js +51 -282
- package/src/components/action_execution/use_execute_action.js +106 -92
- package/src/components/action_execution/use_run_on_mount.js +9 -0
- package/src/components/action_renderer.jsx +21 -32
- package/src/components/demos/0_button_demo.html +574 -103
- package/src/components/demos/10_column_reordering_debug.html +277 -0
- package/src/components/demos/11_table_selection_debug.html +432 -0
- package/src/components/demos/1_checkbox_demo.html +579 -202
- package/src/components/demos/2_input_textual_demo.html +81 -138
- package/src/components/demos/3_radio_demo.html +0 -2
- package/src/components/demos/4_select_demo.html +19 -23
- package/src/components/demos/6_tablist_demo.html +77 -0
- package/src/components/demos/7_table_selection_demo.html +176 -0
- package/src/components/demos/8_table_fixed_headers_demo.html +584 -0
- package/src/components/demos/9_table_column_drag_demo.html +325 -0
- package/src/components/demos/action/0_button_demo.html +2 -4
- package/src/components/demos/action/1_input_text_demo.html +643 -222
- package/src/components/demos/action/3_details_demo.html +146 -115
- package/src/components/demos/action/4_input_checkbox_demo.html +442 -322
- package/src/components/demos/action/5_input_checkbox_state_demo.html +270 -0
- package/src/components/demos/action/6_checkbox_list_demo.html +304 -72
- package/src/components/demos/action/7_radio_list_demo.html +310 -170
- package/src/components/demos/action/{8_editable_text_demo.html → 8_editable_demo.html} +65 -76
- package/src/components/demos/action/9_link_demo.html +84 -62
- package/src/components/demos/ui_transition/0_action_renderer_ui_transition_demo.html +695 -0
- package/src/components/demos/ui_transition/1_nested_ui_transition_demo.html +429 -0
- package/src/components/demos/ui_transition/2_height_transition_test.html +295 -0
- package/src/components/details/details.jsx +62 -64
- package/src/components/edition/editable.jsx +186 -0
- package/src/components/field/README.md +247 -0
- package/src/components/{input → field}/button.jsx +151 -130
- package/src/components/field/checkbox_list.jsx +184 -0
- package/src/components/{collect_form_element_values.js → field/collect_form_element_values.js} +7 -4
- package/src/components/{input → field}/field_css.js +4 -1
- package/src/components/field/form.jsx +211 -0
- package/src/components/{input → field}/input.jsx +1 -0
- package/src/components/{input → field}/input_checkbox.jsx +132 -155
- package/src/components/{input → field}/input_radio.jsx +135 -46
- package/src/components/field/input_textual.jsx +418 -0
- package/src/components/field/label.jsx +32 -0
- package/src/components/field/radio_list.jsx +182 -0
- package/src/components/{input → field}/select.jsx +17 -32
- package/src/components/field/use_action_events.js +132 -0
- package/src/components/field/use_form_events.js +55 -0
- package/src/components/field/use_ui_state_controller.js +506 -0
- package/src/components/item_tracker/README.md +461 -0
- package/src/components/item_tracker/use_isolated_item_tracker.jsx +209 -0
- package/src/components/item_tracker/use_isolated_item_tracker_demo.html +148 -0
- package/src/components/item_tracker/use_isolated_item_tracker_demo.jsx +460 -0
- package/src/components/item_tracker/use_item_tracker.jsx +143 -0
- package/src/components/item_tracker/use_item_tracker_demo.html +207 -0
- package/src/components/item_tracker/use_item_tracker_demo.jsx +216 -0
- package/src/components/keyboard_shortcuts/active_keyboard_shortcuts.jsx +87 -0
- package/src/components/keyboard_shortcuts/aria_key_shortcuts.js +61 -0
- package/src/components/keyboard_shortcuts/keyboard_key_meta.js +17 -0
- package/src/components/keyboard_shortcuts/keyboard_shortcuts.js +371 -0
- package/src/components/link/link.jsx +65 -102
- package/src/components/link/link_with_icon.jsx +52 -0
- package/src/components/loader/loader_background.jsx +85 -64
- package/src/components/loader/rectangle_loading.jsx +38 -19
- package/src/components/route.jsx +8 -4
- package/src/components/selection/selection.jsx +1583 -0
- package/src/components/svg/font_sized_svg.jsx +45 -0
- package/src/components/svg/icon_and_text.jsx +21 -0
- package/src/components/svg/svg_mask_overlay.jsx +105 -0
- package/src/components/table/drag/table_drag.jsx +506 -0
- package/src/components/table/resize/table_resize.jsx +650 -0
- package/src/components/table/resize/table_size.js +43 -0
- package/src/components/table/selection/table_selection.js +106 -0
- package/src/components/table/selection/table_selection.jsx +203 -0
- package/src/components/table/sticky/sticky_group.js +354 -0
- package/src/components/table/sticky/table_sticky.js +25 -0
- package/src/components/table/sticky/table_sticky.jsx +501 -0
- package/src/components/table/table.jsx +721 -0
- package/src/components/table/table_css.js +211 -0
- package/src/components/table/table_ui.jsx +49 -0
- package/src/components/table/use_cells_and_columns.js +90 -0
- package/src/components/table/use_object_array_to_cells.js +46 -0
- package/src/components/table/z_indexes.js +23 -0
- package/src/components/tablist/tablist.jsx +99 -0
- package/src/components/text/overflow.jsx +15 -0
- package/src/components/text/text_and_count.jsx +28 -0
- package/src/components/ui_transition.jsx +128 -0
- package/src/components/use_auto_focus.js +58 -7
- package/src/components/use_batch_during_render.js +33 -0
- package/src/components/use_debounce_true.js +7 -7
- package/src/components/use_dependencies_diff.js +35 -0
- package/src/components/use_focus_group.js +4 -3
- package/src/components/use_initial_value.js +8 -34
- package/src/components/use_signal_sync.js +1 -1
- package/src/components/use_stable_callback.js +68 -0
- package/src/components/use_state_array.js +16 -9
- package/src/docs/actions.md +22 -0
- package/src/notes.md +33 -12
- package/src/route/route.js +97 -47
- package/src/store/resource_graph.js +2 -1
- package/src/store/tests/{resource_graph_dependencies.test.js → resource_graph_dependencies.test_manual.js} +13 -13
- package/src/utils/is_signal.js +20 -0
- package/src/utils/stringify_for_display.js +4 -23
- package/src/validation/constraints/confirm_constraint.js +14 -0
- package/src/validation/constraints/create_unique_value_constraint.js +27 -0
- package/src/validation/constraints/native_constraints.js +313 -0
- package/src/validation/constraints/readonly_constraint.js +36 -0
- package/src/validation/constraints/single_space_constraint.js +13 -0
- package/src/validation/custom_constraint_validation.js +599 -0
- package/src/validation/custom_message.js +18 -0
- package/src/validation/demos/browser_style.png +0 -0
- package/src/validation/demos/form_validation_demo.html +142 -0
- package/src/validation/demos/form_validation_demo_preact.html +87 -0
- package/src/validation/demos/form_validation_native_popover_demo.html +168 -0
- package/src/validation/demos/form_validation_vs_native_demo.html +172 -0
- package/src/validation/demos/validation_message_demo.html +203 -0
- package/src/validation/hooks/use_constraints.js +23 -0
- package/src/validation/hooks/use_custom_validation_ref.js +73 -0
- package/src/validation/hooks/use_validation_message.js +19 -0
- package/src/validation/validation_message.js +741 -0
- package/src/components/editable_text/editable_text.jsx +0 -96
- package/src/components/form.jsx +0 -144
- package/src/components/input/checkbox_list.jsx +0 -294
- package/src/components/input/field.jsx +0 -61
- package/src/components/input/input_textual.jsx +0 -338
- package/src/components/input/radio_list.jsx +0 -283
- package/src/components/input/use_form_event.js +0 -20
- package/src/components/input/use_on_change.js +0 -12
- package/src/components/selection/selection.js +0 -5
- package/src/components/selection/selection_context.jsx +0 -262
- package/src/components/shortcut/shortcut_context.jsx +0 -390
- package/src/components/use_action_events.js +0 -37
- package/src/utils/iterable_weak_set.js +0 -62
- /package/src/components/demos/action/{11_nested_shortcuts_demo.html → 11_nested_shortcuts_demo.xhtml} +0 -0
- /package/src/components/{shortcut → keyboard_shortcuts}/os.js +0 -0
- /package/src/route/{route.test.html → route.xtest.html} +0 -0
package/src/route/route.js
CHANGED
|
@@ -54,7 +54,12 @@ export const updateRoutes = (
|
|
|
54
54
|
const newActive = Boolean(match);
|
|
55
55
|
let newParams;
|
|
56
56
|
if (match) {
|
|
57
|
-
const
|
|
57
|
+
const { optionalParamKeySet } = routePrivateProperties;
|
|
58
|
+
const extractedParams = extractParams(
|
|
59
|
+
urlPattern,
|
|
60
|
+
url,
|
|
61
|
+
optionalParamKeySet,
|
|
62
|
+
);
|
|
58
63
|
if (compareTwoJsValues(oldParams, extractedParams)) {
|
|
59
64
|
// No change in parameters, keep the old params
|
|
60
65
|
newParams = oldParams;
|
|
@@ -112,6 +117,43 @@ export const updateRoutes = (
|
|
|
112
117
|
const abortSignalMap = new Map();
|
|
113
118
|
const routeLoadRequestedMap = new Map();
|
|
114
119
|
|
|
120
|
+
const shouldLoadOrReload = (route, shouldLoad) => {
|
|
121
|
+
const routeAction = route.action;
|
|
122
|
+
const currentAction = routeAction.getCurrentAction();
|
|
123
|
+
if (shouldLoad) {
|
|
124
|
+
if (replace || currentAction.aborted || currentAction.error) {
|
|
125
|
+
shouldLoad = false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (shouldLoad) {
|
|
129
|
+
toLoadSet.add(currentAction);
|
|
130
|
+
} else {
|
|
131
|
+
toReloadSet.add(currentAction);
|
|
132
|
+
}
|
|
133
|
+
routeLoadRequestedMap.set(route, currentAction);
|
|
134
|
+
// Create a new abort controller for this action
|
|
135
|
+
const actionAbortController = new AbortController();
|
|
136
|
+
actionAbortControllerWeakMap.set(currentAction, actionAbortController);
|
|
137
|
+
abortSignalMap.set(currentAction, actionAbortController.signal);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
const shouldLoad = (route) => {
|
|
141
|
+
shouldLoadOrReload(route, true);
|
|
142
|
+
};
|
|
143
|
+
const shouldReload = (route) => {
|
|
144
|
+
shouldLoadOrReload(route, false);
|
|
145
|
+
};
|
|
146
|
+
const shouldAbort = (route) => {
|
|
147
|
+
const routeAction = route.action;
|
|
148
|
+
const currentAction = routeAction.getCurrentAction();
|
|
149
|
+
const actionAbortController =
|
|
150
|
+
actionAbortControllerWeakMap.get(currentAction);
|
|
151
|
+
if (actionAbortController) {
|
|
152
|
+
actionAbortController.abort(`route no longer matching`);
|
|
153
|
+
actionAbortControllerWeakMap.delete(currentAction);
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
|
|
115
157
|
for (const {
|
|
116
158
|
route,
|
|
117
159
|
routePrivateProperties,
|
|
@@ -138,31 +180,13 @@ export const updateRoutes = (
|
|
|
138
180
|
newParams,
|
|
139
181
|
);
|
|
140
182
|
}
|
|
141
|
-
|
|
142
|
-
if (replace) {
|
|
143
|
-
toLoadSet.add(currentAction);
|
|
144
|
-
} else {
|
|
145
|
-
toReloadSet.add(currentAction);
|
|
146
|
-
}
|
|
147
|
-
routeLoadRequestedMap.set(route, currentAction);
|
|
148
|
-
|
|
149
|
-
// Create a new abort controller for this action
|
|
150
|
-
const actionAbortController = new AbortController();
|
|
151
|
-
actionAbortControllerWeakMap.set(currentAction, actionAbortController);
|
|
152
|
-
abortSignalMap.set(currentAction, actionAbortController.signal);
|
|
153
|
-
|
|
183
|
+
shouldLoad(route);
|
|
154
184
|
continue;
|
|
155
185
|
}
|
|
156
186
|
|
|
157
187
|
// Handle actions for routes that become inactive - abort them
|
|
158
188
|
if (becomesInactive && ROUTE_DEACTIVATION_STRATEGY === "abort") {
|
|
159
|
-
|
|
160
|
-
const actionAbortController =
|
|
161
|
-
actionAbortControllerWeakMap.get(currentAction);
|
|
162
|
-
if (actionAbortController) {
|
|
163
|
-
actionAbortController.abort(`route no longer matching`);
|
|
164
|
-
actionAbortControllerWeakMap.delete(currentAction);
|
|
165
|
-
}
|
|
189
|
+
shouldAbort(route);
|
|
166
190
|
continue;
|
|
167
191
|
}
|
|
168
192
|
|
|
@@ -174,16 +198,7 @@ export const updateRoutes = (
|
|
|
174
198
|
newParams,
|
|
175
199
|
);
|
|
176
200
|
}
|
|
177
|
-
|
|
178
|
-
if (!replace || currentAction.aborted || currentAction.error) {
|
|
179
|
-
toReloadSet.add(currentAction);
|
|
180
|
-
routeLoadRequestedMap.set(route, currentAction);
|
|
181
|
-
// Create a new abort controller for the reload
|
|
182
|
-
const actionAbortController = new AbortController();
|
|
183
|
-
actionAbortControllerWeakMap.set(currentAction, actionAbortController);
|
|
184
|
-
abortSignalMap.set(currentAction, actionAbortController.signal);
|
|
185
|
-
}
|
|
186
|
-
continue;
|
|
201
|
+
shouldReload(route);
|
|
187
202
|
}
|
|
188
203
|
}
|
|
189
204
|
|
|
@@ -195,7 +210,7 @@ export const updateRoutes = (
|
|
|
195
210
|
activeRouteSet,
|
|
196
211
|
};
|
|
197
212
|
};
|
|
198
|
-
const extractParams = (urlPattern, url) => {
|
|
213
|
+
const extractParams = (urlPattern, url, ignoreSet = new Set()) => {
|
|
199
214
|
const match = urlPattern.exec(url);
|
|
200
215
|
if (!match) {
|
|
201
216
|
return NO_PARAMS;
|
|
@@ -213,12 +228,15 @@ const extractParams = (urlPattern, url) => {
|
|
|
213
228
|
const keyAsNumber = parseInt(key, 10);
|
|
214
229
|
if (!isNaN(keyAsNumber)) {
|
|
215
230
|
if (value) {
|
|
216
|
-
// Only include non-empty values
|
|
217
|
-
|
|
231
|
+
// Only include non-empty values and non-ignored wildcard indices
|
|
232
|
+
const wildcardKey = String(wildcardOffset + keyAsNumber);
|
|
233
|
+
if (!ignoreSet.has(wildcardKey)) {
|
|
234
|
+
params[wildcardKey] = decodeURIComponent(value);
|
|
235
|
+
}
|
|
218
236
|
localWildcardCount++;
|
|
219
237
|
}
|
|
220
|
-
} else {
|
|
221
|
-
// Named group (:param or {param})
|
|
238
|
+
} else if (!ignoreSet.has(key)) {
|
|
239
|
+
// Named group (:param or {param}) - only include if not ignored
|
|
222
240
|
params[key] = decodeURIComponent(value);
|
|
223
241
|
}
|
|
224
242
|
}
|
|
@@ -252,6 +270,7 @@ const createRoute = (urlPatternInput) => {
|
|
|
252
270
|
};
|
|
253
271
|
|
|
254
272
|
const route = {
|
|
273
|
+
urlPattern: urlPatternInput,
|
|
255
274
|
isRoute: true,
|
|
256
275
|
active: false,
|
|
257
276
|
params: NO_PARAMS,
|
|
@@ -275,11 +294,13 @@ const createRoute = (urlPatternInput) => {
|
|
|
275
294
|
visitedSignal: null,
|
|
276
295
|
relativeUrlSignal: null,
|
|
277
296
|
urlSignal: null,
|
|
297
|
+
optionalParamKeySet: null,
|
|
278
298
|
};
|
|
279
299
|
routePrivatePropertiesMap.set(route, routePrivateProperties);
|
|
280
300
|
|
|
281
301
|
const buildRelativeUrl = (params = {}) => {
|
|
282
302
|
let relativeUrl = urlPatternInput;
|
|
303
|
+
|
|
283
304
|
// Replace named parameters (:param and {param})
|
|
284
305
|
for (const key of Object.keys(params)) {
|
|
285
306
|
const value = params[key];
|
|
@@ -287,16 +308,25 @@ const createRoute = (urlPatternInput) => {
|
|
|
287
308
|
relativeUrl = relativeUrl.replace(`:${key}`, encodedValue);
|
|
288
309
|
relativeUrl = relativeUrl.replace(`{${key}}`, encodedValue);
|
|
289
310
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
311
|
+
|
|
312
|
+
// Handle wildcards: if the pattern ends with /*? (optional wildcard)
|
|
313
|
+
// always remove the wildcard part for URL building since it's optional
|
|
314
|
+
if (relativeUrl.endsWith("/*?")) {
|
|
315
|
+
// Always remove the optional wildcard part for URL building
|
|
316
|
+
relativeUrl = relativeUrl.replace(/\/\*\?$/, "");
|
|
317
|
+
} else {
|
|
318
|
+
// For required wildcards (/*) or other patterns, replace normally
|
|
319
|
+
let wildcardIndex = 0;
|
|
320
|
+
relativeUrl = relativeUrl.replace(/\*/g, () => {
|
|
321
|
+
const paramKey = wildcardIndex.toString();
|
|
322
|
+
const replacement = params[paramKey]
|
|
323
|
+
? encodeURIComponent(params[paramKey])
|
|
324
|
+
: "*";
|
|
325
|
+
wildcardIndex++;
|
|
326
|
+
return replacement;
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
300
330
|
return relativeUrl;
|
|
301
331
|
};
|
|
302
332
|
const buildUrl = (params = {}) => {
|
|
@@ -429,6 +459,23 @@ const createRoute = (urlPatternInput) => {
|
|
|
429
459
|
routePrivateProperties.relativeUrlSignal = relativeUrlSignal;
|
|
430
460
|
routePrivateProperties.urlSignal = urlSignal;
|
|
431
461
|
routePrivateProperties.cleanupCallbackSet = cleanupCallbackSet;
|
|
462
|
+
|
|
463
|
+
// Analyze pattern once to detect optional params (named and wildcard indices)
|
|
464
|
+
// Note: Wildcard indices are stored as strings ("0", "1", ...) to match keys from extractParams
|
|
465
|
+
const optionalParamKeySet = new Set();
|
|
466
|
+
normalizedUrlPattern.replace(/:([A-Za-z0-9_]+)\?/g, (_m, name) => {
|
|
467
|
+
optionalParamKeySet.add(name);
|
|
468
|
+
return "";
|
|
469
|
+
});
|
|
470
|
+
let wildcardIndex = 0;
|
|
471
|
+
normalizedUrlPattern.replace(/\*(\?)?/g, (_m, opt) => {
|
|
472
|
+
if (opt === "?") {
|
|
473
|
+
optionalParamKeySet.add(String(wildcardIndex));
|
|
474
|
+
}
|
|
475
|
+
wildcardIndex++;
|
|
476
|
+
return "";
|
|
477
|
+
});
|
|
478
|
+
routePrivateProperties.optionalParamKeySet = optionalParamKeySet;
|
|
432
479
|
}
|
|
433
480
|
|
|
434
481
|
return route;
|
|
@@ -450,13 +497,16 @@ export const useRouteStatus = (route) => {
|
|
|
450
497
|
throw new Error(`Cannot find route private properties for ${route}`);
|
|
451
498
|
}
|
|
452
499
|
|
|
453
|
-
const { activeSignal, paramsSignal, visitedSignal } =
|
|
500
|
+
const { urlSignal, activeSignal, paramsSignal, visitedSignal } =
|
|
501
|
+
routePrivateProperties;
|
|
454
502
|
|
|
503
|
+
const url = urlSignal.value;
|
|
455
504
|
const active = activeSignal.value;
|
|
456
505
|
const params = paramsSignal.value;
|
|
457
506
|
const visited = visitedSignal.value;
|
|
458
507
|
|
|
459
508
|
return {
|
|
509
|
+
url,
|
|
460
510
|
active,
|
|
461
511
|
params,
|
|
462
512
|
visited,
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { createIterableWeakSet } from "@jsenv/dom";
|
|
1
2
|
import { computed, signal } from "@preact/signals";
|
|
3
|
+
|
|
2
4
|
import { getActionPrivateProperties } from "../action_private_properties.js";
|
|
3
5
|
import { createAction, getActionDispatcher } from "../actions.js";
|
|
4
6
|
import { SYMBOL_OBJECT_SIGNAL } from "../symbol_object_signal.js";
|
|
@@ -7,7 +9,6 @@ import {
|
|
|
7
9
|
compareTwoJsValues,
|
|
8
10
|
} from "../utils/compare_two_js_values.js";
|
|
9
11
|
import { getCallerInfo } from "../utils/get_caller_info.js";
|
|
10
|
-
import { createIterableWeakSet } from "../utils/iterable_weak_set.js";
|
|
11
12
|
import { arraySignalStore, primitiveCanBeId } from "./array_signal_store.js";
|
|
12
13
|
|
|
13
14
|
let DEBUG = false;
|
|
@@ -51,45 +51,45 @@ console.log(
|
|
|
51
51
|
);
|
|
52
52
|
|
|
53
53
|
// Test the autoreload mechanism
|
|
54
|
-
async function
|
|
55
|
-
console.log("\n🧪 Testing
|
|
54
|
+
async function testAutorerun() {
|
|
55
|
+
console.log("\n🧪 Testing autorerun mechanism...");
|
|
56
56
|
|
|
57
57
|
try {
|
|
58
58
|
// Load the parameterized resource
|
|
59
|
-
const ownershipData = await ROLE_WITH_OWNERSHIP.GET_MANY.
|
|
59
|
+
const ownershipData = await ROLE_WITH_OWNERSHIP.GET_MANY.run();
|
|
60
60
|
console.log(
|
|
61
|
-
"✅ ROLE_WITH_OWNERSHIP.GET_MANY.
|
|
61
|
+
"✅ ROLE_WITH_OWNERSHIP.GET_MANY.run() executed:",
|
|
62
62
|
ownershipData.length,
|
|
63
63
|
"items",
|
|
64
64
|
);
|
|
65
65
|
|
|
66
|
-
// Trigger dependency changes that should cause
|
|
66
|
+
// Trigger dependency changes that should cause autorerun
|
|
67
67
|
console.log("\n📝 Triggering dependency changes...");
|
|
68
68
|
|
|
69
|
-
await tables.POST.
|
|
69
|
+
await tables.POST.run({ name: "new_table", database_id: 1 });
|
|
70
70
|
console.log(
|
|
71
|
-
"✅ tables.POST.
|
|
71
|
+
"✅ tables.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
|
|
72
72
|
);
|
|
73
73
|
|
|
74
|
-
await database.POST.
|
|
74
|
+
await database.POST.run({ name: "new_database" });
|
|
75
75
|
console.log(
|
|
76
|
-
"✅ database.POST.
|
|
76
|
+
"✅ database.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
|
|
77
77
|
);
|
|
78
78
|
|
|
79
|
-
await role.POST.
|
|
79
|
+
await role.POST.run({ name: "new_role" });
|
|
80
80
|
console.log(
|
|
81
|
-
"✅ role.POST.
|
|
81
|
+
"✅ role.POST.run() - should trigger ROLE_WITH_OWNERSHIP autorerun",
|
|
82
82
|
);
|
|
83
83
|
|
|
84
84
|
console.log("\n✅ Dependency system test completed successfully!");
|
|
85
85
|
console.log(
|
|
86
|
-
"💡 In a real application, these would automatically
|
|
86
|
+
"💡 In a real application, these would automatically rerun ROLE_WITH_OWNERSHIP.GET_MANY",
|
|
87
87
|
);
|
|
88
88
|
} catch (error) {
|
|
89
89
|
console.error("❌ Test failed:", error);
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
|
|
93
|
+
testAutorerun();
|
|
94
94
|
|
|
95
95
|
export { database, role, ROLE_WITH_OWNERSHIP, tables };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const isSignal = (value) => {
|
|
2
|
+
return getSignalType(value) !== null;
|
|
3
|
+
};
|
|
4
|
+
|
|
5
|
+
const BRAND_SYMBOL = Symbol.for("preact-signals");
|
|
6
|
+
export const getSignalType = (value) => {
|
|
7
|
+
if (!value || typeof value !== "object") {
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (value.brand !== BRAND_SYMBOL) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (typeof value._fn === "function") {
|
|
16
|
+
return "computed";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return "signal";
|
|
20
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { getSignalType } from "./is_signal.js";
|
|
2
|
+
|
|
3
|
+
const MAX_ENTRIES = 5;
|
|
4
|
+
|
|
1
5
|
export const stringifyForDisplay = (
|
|
2
6
|
value,
|
|
3
7
|
maxDepth = 2,
|
|
@@ -125,26 +129,3 @@ export const stringifyForDisplay = (
|
|
|
125
129
|
|
|
126
130
|
return String(value);
|
|
127
131
|
};
|
|
128
|
-
|
|
129
|
-
export const isSignal = (value) => {
|
|
130
|
-
return getSignalType(value) !== null;
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
const BRAND_SYMBOL = Symbol.for("preact-signals");
|
|
134
|
-
export const getSignalType = (value) => {
|
|
135
|
-
if (!value || typeof value !== "object") {
|
|
136
|
-
return null;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
if (value.brand !== BRAND_SYMBOL) {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (typeof value._fn === "function") {
|
|
144
|
-
return "computed";
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return "signal";
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const MAX_ENTRIES = 5;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const CONFIRM_CONSTRAINT = {
|
|
2
|
+
name: "confirm",
|
|
3
|
+
check: (element) => {
|
|
4
|
+
const confirmMessage = element.getAttribute("data-confirm");
|
|
5
|
+
if (!confirmMessage) {
|
|
6
|
+
return "";
|
|
7
|
+
}
|
|
8
|
+
// eslint-disable-next-line no-alert
|
|
9
|
+
if (window.confirm(confirmMessage)) {
|
|
10
|
+
return "";
|
|
11
|
+
}
|
|
12
|
+
return "";
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export const createUniqueValueConstraint = (
|
|
2
|
+
// the set might be incomplete (the front usually don't have the full copy of all the items from the backend)
|
|
3
|
+
// but this is already nice to help user with what we know
|
|
4
|
+
// it's also possible that front is unsync with backend, preventing user to choose a value
|
|
5
|
+
// that is actually free.
|
|
6
|
+
// But this is unlikely to happen and user could reload the page to be able to choose that name
|
|
7
|
+
// that suddenly became available
|
|
8
|
+
existingValueSet,
|
|
9
|
+
message = `"{value}" already exists. Please choose another value.`,
|
|
10
|
+
) => {
|
|
11
|
+
return {
|
|
12
|
+
name: "unique_value",
|
|
13
|
+
check: (input) => {
|
|
14
|
+
const inputValue = input.value;
|
|
15
|
+
const hasConflict = existingValueSet.has(inputValue);
|
|
16
|
+
// console.log({
|
|
17
|
+
// inputValue,
|
|
18
|
+
// names: Array.from(otherNameSet.values()),
|
|
19
|
+
// hasConflict,
|
|
20
|
+
// });
|
|
21
|
+
if (hasConflict) {
|
|
22
|
+
return message.replace("{value}", inputValue);
|
|
23
|
+
}
|
|
24
|
+
return "";
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
};
|