nexus-shared 3.2.0 → 4.0.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.
- package/CHANGELOG.md +1564 -0
- package/README.md +1705 -1123
- package/dist/Client.Index.d.ts +14 -0
- package/dist/Client.Index.js +14 -0
- package/dist/Components/Documents/DocumentFrame.d.ts +50 -0
- package/dist/Components/Documents/DocumentFrame.js +83 -0
- package/dist/Components/Documents/Menu.d.ts +4 -0
- package/dist/Components/Documents/Menu.js +40 -24
- package/dist/Components/Documents/PrintDocument.d.ts +95 -0
- package/dist/Components/Documents/PrintDocument.js +62 -0
- package/dist/Components/Documents/Tabs.d.ts +59 -0
- package/dist/Components/Documents/Tabs.js +70 -0
- package/dist/Components/Forms/ApiForm.js +19 -2
- package/dist/Components/Forms/Crud.d.ts +2 -2
- package/dist/Components/Forms/Crud.js +576 -243
- package/dist/Components/Forms/CrudActions.d.ts +136 -0
- package/dist/Components/Forms/CrudActions.js +184 -0
- package/dist/Components/Forms/CrudNarrowPicker.d.ts +31 -0
- package/dist/Components/Forms/CrudNarrowPicker.js +180 -0
- package/dist/Components/Forms/CrudParts.d.ts +30 -2
- package/dist/Components/Forms/CrudParts.js +55 -5
- package/dist/Components/Forms/CrudRowForms.d.ts +26 -0
- package/dist/Components/Forms/CrudRowForms.js +114 -0
- package/dist/Components/Forms/CrudScopes.d.ts +28 -0
- package/dist/Components/Forms/CrudScopes.js +76 -0
- package/dist/Components/Forms/CrudTree.d.ts +90 -0
- package/dist/Components/Forms/CrudTree.js +363 -0
- package/dist/Components/Forms/CrudWorkspace.d.ts +63 -0
- package/dist/Components/Forms/CrudWorkspace.js +169 -0
- package/dist/Components/Forms/ExcelImport.js +3 -3
- package/dist/Components/Forms/Form.d.ts +4 -4
- package/dist/Components/Forms/Form.js +123 -17
- package/dist/Components/Forms/FormLeaveGuard.d.ts +44 -0
- package/dist/Components/Forms/FormLeaveGuard.js +65 -0
- package/dist/Components/Forms/RecordFlows.d.ts +50 -0
- package/dist/Components/Forms/RecordFlows.js +282 -0
- package/dist/Components/Forms/SubmitForm.d.ts +37 -2
- package/dist/Components/Forms/SubmitForm.js +195 -10
- package/dist/Components/Inputs/CheckBox.js +1 -1
- package/dist/Components/Inputs/ChoiceField.d.ts +21 -1
- package/dist/Components/Inputs/ChoiceField.js +28 -2
- package/dist/Components/Inputs/Dropdown.d.ts +13 -0
- package/dist/Components/Inputs/Dropdown.js +5 -5
- package/dist/Components/Inputs/DropdownParts.d.ts +3 -1
- package/dist/Components/Inputs/DropdownParts.js +16 -4
- package/dist/Components/Inputs/Field.d.ts +7 -1
- package/dist/Components/Inputs/Field.js +2 -2
- package/dist/Components/Inputs/GroupForm.d.ts +6 -6
- package/dist/Components/Inputs/GroupForm.js +10 -11
- package/dist/Components/Inputs/InputRenderer.d.ts +9 -6
- package/dist/Components/Inputs/InputRenderer.js +37 -32
- package/dist/Components/Inputs/PictureInput.d.ts +41 -0
- package/dist/Components/Inputs/PictureInput.js +70 -0
- package/dist/Components/Inputs/RadioGroup.d.ts +16 -3
- package/dist/Components/Inputs/RadioGroup.js +8 -3
- package/dist/Components/Inputs/RowsInput.d.ts +1 -1
- package/dist/Components/Inputs/RowsInput.js +18 -3
- package/dist/Components/Inputs/TabularForm.d.ts +5 -5
- package/dist/Components/Inputs/TabularForm.js +29 -29
- package/dist/Components/Inputs/TextArea.d.ts +6 -0
- package/dist/Components/Inputs/TextArea.js +11 -2
- package/dist/Components/Inputs/TextBoxTypes.d.ts +6 -0
- package/dist/Components/Inputs/TextBoxTypes.js +17 -0
- package/dist/Components/Inputs/TreeView.d.ts +53 -2
- package/dist/Components/Inputs/TreeView.js +147 -13
- package/dist/Components/Layouts/MessageBox.d.ts +15 -2
- package/dist/Components/Layouts/MessageBox.js +56 -7
- package/dist/Components/Layouts/Popup.d.ts +13 -6
- package/dist/Components/Layouts/Popup.js +37 -9
- package/dist/Components/Layouts/PopupDock.d.ts +3 -1
- package/dist/Components/Layouts/PopupDock.js +2 -1
- package/dist/Components/Layouts/PopupHost.js +5 -4
- package/dist/Components/Viewers/DataTable.js +150 -48
- package/dist/Components/Viewers/DataTableFilters.d.ts +1 -1
- package/dist/Components/Viewers/DataTableFilters.js +17 -2
- package/dist/Components/Viewers/DataTableParts.d.ts +21 -5
- package/dist/Components/Viewers/DataTableParts.js +26 -14
- package/dist/Components/Viewers/OwnerFiles.d.ts +175 -0
- package/dist/Components/Viewers/OwnerFiles.js +589 -0
- package/dist/Components/Viewers/QrCodeImage.d.ts +22 -0
- package/dist/Components/Viewers/QrCodeImage.js +15 -0
- package/dist/Components/Viewers/RecordCards.d.ts +16 -0
- package/dist/Components/Viewers/RecordCards.js +509 -0
- package/dist/Helpers/BusyHooks.d.ts +6 -0
- package/dist/Helpers/BusyHooks.js +39 -0
- package/dist/Helpers/CrudBackend.d.ts +20 -2
- package/dist/Helpers/CrudBackend.js +46 -2
- package/dist/Helpers/CrudColumns.d.ts +53 -6
- package/dist/Helpers/CrudColumns.js +98 -7
- package/dist/Helpers/CrudDetailsTabs.d.ts +58 -0
- package/dist/Helpers/CrudDetailsTabs.js +126 -0
- package/dist/Helpers/CrudHelpers.d.ts +81 -2
- package/dist/Helpers/CrudHelpers.js +195 -0
- package/dist/Helpers/CrudNarrowPick.d.ts +83 -0
- package/dist/Helpers/CrudNarrowPick.js +157 -0
- package/dist/Helpers/CrudRowForms.d.ts +15 -0
- package/dist/Helpers/CrudRowForms.js +43 -0
- package/dist/Helpers/CrudScopes.d.ts +32 -0
- package/dist/Helpers/CrudScopes.js +79 -0
- package/dist/Helpers/DropdownHelpers.d.ts +3 -1
- package/dist/Helpers/DropdownHelpers.js +6 -2
- package/dist/Helpers/ExcelHelpers.d.ts +1 -1
- package/dist/Helpers/ExcelHelpers.js +12 -11
- package/dist/Helpers/FileAdapter.d.ts +78 -0
- package/dist/Helpers/FileAdapter.js +102 -0
- package/dist/Helpers/FilePrimaries.d.ts +48 -0
- package/dist/Helpers/FilePrimaries.js +138 -0
- package/dist/Helpers/FormConfirm.d.ts +32 -0
- package/dist/Helpers/FormConfirm.js +40 -0
- package/dist/Helpers/FormStore.d.ts +90 -5
- package/dist/Helpers/FormStore.js +318 -22
- package/dist/Helpers/InputConditions.d.ts +50 -0
- package/dist/Helpers/InputConditions.js +168 -0
- package/dist/Helpers/InputMemory.d.ts +106 -0
- package/dist/Helpers/InputMemory.js +385 -0
- package/dist/Helpers/InputNarrowing.d.ts +18 -0
- package/dist/Helpers/InputNarrowing.js +67 -0
- package/dist/Helpers/InputParamsHelpers.d.ts +44 -1
- package/dist/Helpers/InputParamsHelpers.js +157 -74
- package/dist/Helpers/NexusDriveAdapter.d.ts +55 -0
- package/dist/Helpers/NexusDriveAdapter.js +207 -0
- package/dist/Helpers/NumberHelpers.d.ts +95 -0
- package/dist/Helpers/NumberHelpers.js +126 -0
- package/dist/Helpers/Permissions.js +2 -1
- package/dist/Helpers/QrCode.d.ts +26 -0
- package/dist/Helpers/QrCode.js +463 -0
- package/dist/Helpers/RecordCards.d.ts +205 -0
- package/dist/Helpers/RecordCards.js +378 -0
- package/dist/Helpers/RequestCache.d.ts +14 -2
- package/dist/Helpers/RequestCache.js +22 -3
- package/dist/Helpers/RowsStore.d.ts +37 -2
- package/dist/Helpers/RowsStore.js +128 -10
- package/dist/Helpers/ServerPreview.d.ts +69 -0
- package/dist/Helpers/ServerPreview.js +99 -0
- package/dist/Helpers/TableColumns.js +4 -3
- package/dist/Helpers/TableExport.d.ts +7 -1
- package/dist/Helpers/TableExport.js +9 -3
- package/dist/Helpers/TableFilters.d.ts +1 -1
- package/dist/Helpers/TableFilters.js +24 -23
- package/dist/Helpers/TableHelpers.d.ts +23 -2
- package/dist/Helpers/TableHelpers.js +51 -10
- package/dist/Helpers/TableJoins.d.ts +13 -0
- package/dist/Helpers/TableJoins.js +34 -0
- package/dist/Helpers/TableStore.d.ts +21 -1
- package/dist/Helpers/TableStore.js +64 -7
- package/dist/Helpers/TreeStore.d.ts +81 -0
- package/dist/Helpers/TreeStore.js +365 -0
- package/dist/Interfaces/CrudInterfaces.d.ts +465 -5
- package/dist/Interfaces/FileInterfaces.d.ts +162 -0
- package/dist/Interfaces/FileInterfaces.js +4 -0
- package/dist/Interfaces/FormInterfaces.d.ts +391 -30
- package/dist/Interfaces/FormInterfaces.js +79 -1
- package/dist/Interfaces/InputInterfaces.d.ts +15 -3
- package/dist/Interfaces/RecordInterfaces.d.ts +367 -0
- package/dist/Interfaces/RecordInterfaces.js +1 -0
- package/dist/Interfaces/TableInterfaces.d.ts +74 -1
- package/dist/Services/ExcelApi.js +5 -0
- package/dist/Services/FileApi.d.ts +13 -0
- package/dist/Services/FileApi.js +29 -0
- package/dist/Services/ImageEditorLoader.d.ts +14 -0
- package/dist/Services/ImageEditorLoader.js +51 -0
- package/dist/Services/JoinSources.d.ts +37 -5
- package/dist/Services/JoinSources.js +90 -14
- package/dist/Services/ModuleImport.d.ts +7 -0
- package/dist/Services/ModuleImport.js +22 -0
- package/dist/Shared.Index.d.ts +16 -0
- package/dist/Shared.Index.js +16 -0
- package/package.json +7 -2
- package/src/Styles/Nexus.Avatar.css +6 -5
- package/src/Styles/Nexus.Button.css +10 -4
- package/src/Styles/Nexus.Choice.css +16 -0
- package/src/Styles/Nexus.Crud.css +383 -9
- package/src/Styles/Nexus.Dropdown.css +8 -0
- package/src/Styles/Nexus.Files.css +410 -0
- package/src/Styles/Nexus.Form.css +5 -2
- package/src/Styles/Nexus.Index.css +4 -0
- package/src/Styles/Nexus.Input.css +42 -0
- package/src/Styles/Nexus.Menu.css +10 -1
- package/src/Styles/Nexus.Popup.css +77 -1
- package/src/Styles/Nexus.Print.css +288 -0
- package/src/Styles/Nexus.QrCode.css +12 -0
- package/src/Styles/Nexus.Record.css +430 -0
- package/src/Styles/Nexus.Tab.Buttons.css +87 -22
- package/src/Styles/Nexus.Table.css +67 -5
- package/src/Styles/Nexus.Themes.css +12 -6
- package/src/Styles/Nexus.Tokens.css +8 -3
- package/src/Styles/Nexus.Tree.css +31 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { InputNarrowing, InputParams } from "../Interfaces/FormInterfaces.ts";
|
|
2
|
+
import type { OptionValue } from "../Interfaces/InputInterfaces.ts";
|
|
3
|
+
/** The value that narrows, or null while the other input has none: an empty text, an empty list and `false` count as none. */
|
|
4
|
+
export declare function narrowingValue(value: unknown): OptionValue | null;
|
|
5
|
+
/** What a narrowed box says while the other input is empty: "Pick a group first". */
|
|
6
|
+
export declare function narrowingPlaceholder(narrowing: InputNarrowing, otherLabel: unknown): string;
|
|
7
|
+
/** A narrowing by a fixed value (`{ key, value }`), not by another input. */
|
|
8
|
+
export declare function isFixedNarrowing(narrowing: InputNarrowing): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* An input's params narrowed by the other input's value as it is now (or by the fixed `value` the narrowing gives): static `options` filtered to the records whose
|
|
11
|
+
* `key` field holds it; `loadOptions` asked with `request.narrow` (crudPicker reads it: from the server when its
|
|
12
|
+
* endpoint takes the parent, else from the list it keeps, narrowed in the browser), and a `loadKey` of its own per
|
|
13
|
+
* value, so the list loads afresh when the other value changes. While the other input is empty, no option is offered
|
|
14
|
+
* and the box says what to pick first. Params without `narrowedBy` are answered as they are.
|
|
15
|
+
*
|
|
16
|
+
* @example narrowInputParams(packageParams, form.get("subscriptionGroupId"), "Group")
|
|
17
|
+
*/
|
|
18
|
+
export declare function narrowInputParams(params: InputParams, otherValue: unknown, otherLabel?: unknown): InputParams;
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Options narrowed by another input's value (`narrowedBy`): a Package list of the Group picked, a Sub-region list of the
|
|
3
|
+
* Country picked. The form reads the other value as it draws and hands the input its params narrowed by it (this file,
|
|
4
|
+
* pure, so Node tests run it); the form's store clears the input's value when the other one changes (FormStore).
|
|
5
|
+
*/
|
|
6
|
+
/** The value that narrows, or null while the other input has none: an empty text, an empty list and `false` count as none. */
|
|
7
|
+
export function narrowingValue(value) {
|
|
8
|
+
if (value === null || value === undefined || value === "" || value === false)
|
|
9
|
+
return null;
|
|
10
|
+
if (Array.isArray(value))
|
|
11
|
+
return value.length === 1 ? narrowingValue(value[0]) : null;
|
|
12
|
+
if (typeof value === "string" || typeof value === "number")
|
|
13
|
+
return value;
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
/** What a narrowed box says while the other input is empty: "Pick a group first". */
|
|
17
|
+
export function narrowingPlaceholder(narrowing, otherLabel) {
|
|
18
|
+
if (narrowing.placeholder)
|
|
19
|
+
return narrowing.placeholder;
|
|
20
|
+
if (narrowing.name === undefined)
|
|
21
|
+
return "";
|
|
22
|
+
const label = typeof otherLabel === "string" && otherLabel.trim() ? otherLabel.trim().toLocaleLowerCase() : narrowing.name;
|
|
23
|
+
return `Pick ${/^[aeiou]/i.test(label) ? "an" : "a"} ${label} first`;
|
|
24
|
+
}
|
|
25
|
+
const EMPTY_PAGE = { items: [], total: 0, hasMore: false };
|
|
26
|
+
/** A narrowing by a fixed value (`{ key, value }`), not by another input. */
|
|
27
|
+
export function isFixedNarrowing(narrowing) {
|
|
28
|
+
return narrowing.name === undefined;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* An input's params narrowed by the other input's value as it is now (or by the fixed `value` the narrowing gives): static `options` filtered to the records whose
|
|
32
|
+
* `key` field holds it; `loadOptions` asked with `request.narrow` (crudPicker reads it: from the server when its
|
|
33
|
+
* endpoint takes the parent, else from the list it keeps, narrowed in the browser), and a `loadKey` of its own per
|
|
34
|
+
* value, so the list loads afresh when the other value changes. While the other input is empty, no option is offered
|
|
35
|
+
* and the box says what to pick first. Params without `narrowedBy` are answered as they are.
|
|
36
|
+
*
|
|
37
|
+
* @example narrowInputParams(packageParams, form.get("subscriptionGroupId"), "Group")
|
|
38
|
+
*/
|
|
39
|
+
export function narrowInputParams(params, otherValue, otherLabel) {
|
|
40
|
+
const narrowing = params.narrowedBy;
|
|
41
|
+
if (!narrowing)
|
|
42
|
+
return params;
|
|
43
|
+
const fixed = narrowing.name === undefined;
|
|
44
|
+
const key = narrowing.key ?? narrowing.name ?? "";
|
|
45
|
+
const value = narrowingValue(fixed ? narrowing.value : otherValue);
|
|
46
|
+
const orUnset = narrowing.orUnset === true;
|
|
47
|
+
const keeps = (item) => {
|
|
48
|
+
if (item === null || typeof item !== "object")
|
|
49
|
+
return false;
|
|
50
|
+
const field = item[key];
|
|
51
|
+
return (value !== null && String(field) === String(value)) || (orUnset && (field === null || field === undefined || field === ""));
|
|
52
|
+
};
|
|
53
|
+
const own = params;
|
|
54
|
+
const narrowed = { ...own, loadKey: `${own.loadKey === undefined ? "" : String(own.loadKey)}|${narrowing.name ?? key}=${value === null ? "" : String(value)}` };
|
|
55
|
+
const placeholder = value === null ? narrowingPlaceholder(narrowing, otherLabel) : "";
|
|
56
|
+
if (placeholder)
|
|
57
|
+
narrowed.placeholder = placeholder;
|
|
58
|
+
// Nothing to narrow by offers nothing, unless the options with no value in the field are offered too (`orUnset`).
|
|
59
|
+
const none = value === null && !orUnset;
|
|
60
|
+
if (Array.isArray(own.options))
|
|
61
|
+
narrowed.options = none ? [] : own.options.filter(keeps);
|
|
62
|
+
const load = own.loadOptions;
|
|
63
|
+
if (load) {
|
|
64
|
+
narrowed.loadOptions = (request) => (none ? Promise.resolve(EMPTY_PAGE) : load({ ...request, narrow: { key, value, ...(orUnset && { orUnset }) } }));
|
|
65
|
+
}
|
|
66
|
+
return narrowed;
|
|
67
|
+
}
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type InputParams, type InputValidationContext, type RowsInputProps, type RowValue } from "../Interfaces/FormInterfaces.ts";
|
|
2
2
|
/** Keys that place an input in a form; a renderer leaves them out of the component's props. */
|
|
3
3
|
export declare const INPUT_LAYOUT_KEYS: readonly ["span", "width", "grow", "hidden"];
|
|
4
4
|
/** Inputs whose value is `true` or `false`. */
|
|
5
5
|
export declare const isBooleanInput: (params: InputParams) => params is import("../Shared.Index.ts").CheckBoxParams | import("../Shared.Index.ts").SwitchParams | import("../Shared.Index.ts").RadioParams;
|
|
6
|
+
/**
|
|
7
|
+
* The member name of an input type, for a message or a log: `inputTypeName(EInputTypes.RichText)` is "RichText". A number
|
|
8
|
+
* that is no member, such as one read from old data, comes back as its digits.
|
|
9
|
+
*/
|
|
10
|
+
export declare const inputTypeName: (type: number) => string;
|
|
11
|
+
/**
|
|
12
|
+
* Whether an input holds a value of the form. A picture does not: it is the owner's file, changed at once through the
|
|
13
|
+
* file backend, so the form keeps no field for it and a save sends nothing under its name.
|
|
14
|
+
*/
|
|
15
|
+
export declare const holdsValue: (params: InputParams) => params is import("../Shared.Index.ts").TextInputParams | import("../Shared.Index.ts").TextAreaParams | import("../Shared.Index.ts").NumberInputParams | import("../Shared.Index.ts").CodeInputParams | import("../Shared.Index.ts").CheckBoxParams | import("../Shared.Index.ts").SwitchParams | import("../Shared.Index.ts").RadioParams | import("../Shared.Index.ts").CheckBoxGroupParams | import("../Shared.Index.ts").RadioGroupParams | import("../Shared.Index.ts").DropdownParams | import("../Shared.Index.ts").DateParams | import("../Shared.Index.ts").DateRangeParams | import("../Shared.Index.ts").TimeParams | import("../Shared.Index.ts").DateTimeParams | import("../Shared.Index.ts").SliderParams | import("../Shared.Index.ts").RangeSliderParams | import("../Shared.Index.ts").MarkdownParams | import("../Shared.Index.ts").RichTextParams | import("../Shared.Index.ts").TreeParams | import("../Shared.Index.ts").TabularParams | import("../Shared.Index.ts").GroupParams;
|
|
16
|
+
/**
|
|
17
|
+
* Whether what is typed in an input is worth asking about before it is dropped: not a password or a one-time code (a
|
|
18
|
+
* `Code` box), which are typed again in a moment and never kept in a draft. Such a value alone makes no form ask
|
|
19
|
+
* "Discard your changes?" on Cancel or close, nor the page ask before it is left.
|
|
20
|
+
*/
|
|
21
|
+
export declare const keepsTyping: (params: InputParams) => boolean;
|
|
6
22
|
/** Inputs whose value is an array of rows. */
|
|
7
23
|
export declare const isRowsInput: (params: InputParams) => params is import("../Shared.Index.ts").TabularParams | import("../Shared.Index.ts").GroupParams;
|
|
8
24
|
/**
|
|
@@ -23,6 +39,33 @@ export declare function normalizeInputValue(params: InputParams, value: unknown)
|
|
|
23
39
|
export declare function isEmptyInputValue(value: unknown): boolean;
|
|
24
40
|
/** Equal values: the same primitive, or arrays with the same items in the same order. */
|
|
25
41
|
export declare function inputValuesEqual(a: unknown, b: unknown): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* The inputs with some of them fixed for one opening of a form: each input `locked` names (input name -> why) turns
|
|
44
|
+
* read-only and says why on any try to change it (`readOnlyMessage`), the lock-and-note look every input has. Its value
|
|
45
|
+
* stays in the form and is sent as before. A required input with no value in `values` stays free: fixed empty, the form
|
|
46
|
+
* would never ask for it, since read-only inputs are not checked. Names a form does not have are skipped.
|
|
47
|
+
*
|
|
48
|
+
* Each fixed input is a copy made from its own property descriptors, never a spread: a spread would read a getter once
|
|
49
|
+
* (`get readOnly()` or `get options()` following other values through `dependsOn`) and freeze it.
|
|
50
|
+
*
|
|
51
|
+
* To show fixed inputs disabled instead (dimmed, out of the Tab order, no note), write `disabled` for `readOnly` in the
|
|
52
|
+
* copy below.
|
|
53
|
+
*
|
|
54
|
+
* `known` are records the caller holds for the fixed values - the row picked in another list that a new record is added
|
|
55
|
+
* for: a fixed dropdown whose value one of them holds (by the dropdown's `valueKey`) gets it as a selected option, so its
|
|
56
|
+
* box names the value at once, with no lookup.
|
|
57
|
+
*
|
|
58
|
+
* @example lockInputs(REGION_INPUTS, { countryId: "Added inside Bagmati." }, { countryId: "c7" })
|
|
59
|
+
*/
|
|
60
|
+
export declare function lockInputs(inputs: readonly InputParams[], locked: Readonly<Record<string, string>>, values?: Readonly<Record<string, unknown>>, known?: readonly Readonly<Record<string, unknown>>[]): InputParams[];
|
|
61
|
+
/**
|
|
62
|
+
* A form's `onFieldChange` that never writes the inputs fixed for an opening (`lockInputs`): a rule such as "a province
|
|
63
|
+
* sits right under its country" still changes a free field, and leaves a fixed one as the form opened it. With nothing
|
|
64
|
+
* fixed, or no rule, the rule as it is.
|
|
65
|
+
*
|
|
66
|
+
* @example lockedFieldChange(form.onFieldChange, ["countryId", "parentId"])
|
|
67
|
+
*/
|
|
68
|
+
export declare function lockedFieldChange<TValues extends Record<string, unknown>>(onFieldChange: ((name: string, value: unknown, values: TValues) => Partial<TValues> | null | undefined | void) | undefined, fixed: readonly string[]): ((name: string, value: unknown, values: TValues) => Partial<TValues> | null | undefined | void) | undefined;
|
|
26
69
|
/**
|
|
27
70
|
* Checks a value against its input's rules and returns the first message, or `null` when it is valid: the same
|
|
28
71
|
* message the input shows. Pure, so a form can check thousands of values on submit, including rows not on screen.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { DEFAULT_DATE_PREFERENCES } from "../Interfaces/DateInterfaces.js";
|
|
2
|
+
import { EInputTypes } from "../Interfaces/FormInterfaces.js";
|
|
2
3
|
import { formatCode, loadCode, validateCode } from "./CodeHelpers.js";
|
|
3
4
|
import { formatDate, formatDateRange, toDateRange, toIsoDate, usesDevanagari } from "./DateHelpers.js";
|
|
4
5
|
import { formatDateTime, toUtcDateTime } from "./DateTimeHelpers.js";
|
|
@@ -15,9 +16,27 @@ import { chooseRowMessage, duplicateRowMessage, maxRowsMessage, minRowsMessage,
|
|
|
15
16
|
/** Keys that place an input in a form; a renderer leaves them out of the component's props. */
|
|
16
17
|
export const INPUT_LAYOUT_KEYS = ["span", "width", "grow", "hidden"];
|
|
17
18
|
/** Inputs whose value is `true` or `false`. */
|
|
18
|
-
export const isBooleanInput = (params) => params.type ===
|
|
19
|
+
export const isBooleanInput = (params) => params.type === EInputTypes.CheckBox || params.type === EInputTypes.Switch || params.type === EInputTypes.Radio;
|
|
20
|
+
/** Each `EInputTypes` number with its member name. */
|
|
21
|
+
const INPUT_TYPE_NAMES = new Map(Object.entries(EInputTypes).map(([name, value]) => [value, name]));
|
|
22
|
+
/**
|
|
23
|
+
* The member name of an input type, for a message or a log: `inputTypeName(EInputTypes.RichText)` is "RichText". A number
|
|
24
|
+
* that is no member, such as one read from old data, comes back as its digits.
|
|
25
|
+
*/
|
|
26
|
+
export const inputTypeName = (type) => INPUT_TYPE_NAMES.get(type) ?? String(type);
|
|
27
|
+
/**
|
|
28
|
+
* Whether an input holds a value of the form. A picture does not: it is the owner's file, changed at once through the
|
|
29
|
+
* file backend, so the form keeps no field for it and a save sends nothing under its name.
|
|
30
|
+
*/
|
|
31
|
+
export const holdsValue = (params) => params.type !== EInputTypes.Picture;
|
|
32
|
+
/**
|
|
33
|
+
* Whether what is typed in an input is worth asking about before it is dropped: not a password or a one-time code (a
|
|
34
|
+
* `Code` box), which are typed again in a moment and never kept in a draft. Such a value alone makes no form ask
|
|
35
|
+
* "Discard your changes?" on Cancel or close, nor the page ask before it is left.
|
|
36
|
+
*/
|
|
37
|
+
export const keepsTyping = (params) => params.type !== EInputTypes.Password && params.type !== EInputTypes.Code;
|
|
19
38
|
/** Inputs whose value is an array of rows. */
|
|
20
|
-
export const isRowsInput = (params) => params.type ===
|
|
39
|
+
export const isRowsInput = (params) => params.type === EInputTypes.Tabular || params.type === EInputTypes.Group;
|
|
21
40
|
/**
|
|
22
41
|
* The name an input's messages use, as the input itself picks it: `fieldName`, or the label when it is text. A checkbox's
|
|
23
42
|
* label is usually a sentence, so it uses `fieldName` only.
|
|
@@ -26,35 +45,36 @@ export function inputFieldName(params) {
|
|
|
26
45
|
const { fieldName } = params;
|
|
27
46
|
if (fieldName)
|
|
28
47
|
return fieldName;
|
|
29
|
-
if (params.type ===
|
|
48
|
+
if (params.type === EInputTypes.CheckBox || params.type === EInputTypes.Switch)
|
|
30
49
|
return undefined;
|
|
31
50
|
return typeof params.label === "string" ? params.label : undefined;
|
|
32
51
|
}
|
|
33
52
|
/** The value of an input with nothing in it: "" for text, `null` for a number or a date, `false`, `[]`, and so on. */
|
|
34
53
|
export function emptyInputValue(params) {
|
|
35
54
|
switch (params.type) {
|
|
36
|
-
case
|
|
37
|
-
case
|
|
38
|
-
case
|
|
39
|
-
case
|
|
40
|
-
case
|
|
55
|
+
case EInputTypes.Number:
|
|
56
|
+
case EInputTypes.Date:
|
|
57
|
+
case EInputTypes.Time:
|
|
58
|
+
case EInputTypes.DateTime:
|
|
59
|
+
case EInputTypes.RadioGroup:
|
|
60
|
+
case EInputTypes.Picture:
|
|
41
61
|
return null;
|
|
42
|
-
case
|
|
43
|
-
case
|
|
44
|
-
case
|
|
62
|
+
case EInputTypes.CheckBox:
|
|
63
|
+
case EInputTypes.Switch:
|
|
64
|
+
case EInputTypes.Radio:
|
|
45
65
|
return false;
|
|
46
|
-
case
|
|
47
|
-
case
|
|
48
|
-
case
|
|
49
|
-
case
|
|
66
|
+
case EInputTypes.CheckBoxGroup:
|
|
67
|
+
case EInputTypes.Tree:
|
|
68
|
+
case EInputTypes.Tabular:
|
|
69
|
+
case EInputTypes.Group:
|
|
50
70
|
return [];
|
|
51
|
-
case
|
|
71
|
+
case EInputTypes.Dropdown:
|
|
52
72
|
return params.multiple ? [] : null;
|
|
53
|
-
case
|
|
73
|
+
case EInputTypes.DateRange:
|
|
54
74
|
return [null, null];
|
|
55
|
-
case
|
|
75
|
+
case EInputTypes.Slider:
|
|
56
76
|
return params.min ?? 0;
|
|
57
|
-
case
|
|
77
|
+
case EInputTypes.RangeSlider:
|
|
58
78
|
return [params.min ?? 0, params.max ?? 100];
|
|
59
79
|
default:
|
|
60
80
|
return "";
|
|
@@ -77,39 +97,39 @@ export function normalizeInputValue(params, value) {
|
|
|
77
97
|
return emptyInputValue(params);
|
|
78
98
|
}
|
|
79
99
|
switch (params.type) {
|
|
80
|
-
case
|
|
100
|
+
case EInputTypes.Number: {
|
|
81
101
|
if (typeof value === "number")
|
|
82
102
|
return Number.isNaN(value) ? null : value;
|
|
83
103
|
return typeof value === "string" ? parseNumber(value, params.locale) : null;
|
|
84
104
|
}
|
|
85
|
-
case
|
|
86
|
-
case
|
|
87
|
-
case
|
|
105
|
+
case EInputTypes.CheckBox:
|
|
106
|
+
case EInputTypes.Switch:
|
|
107
|
+
case EInputTypes.Radio:
|
|
88
108
|
return value === true || value === "true" || value === 1;
|
|
89
|
-
case
|
|
109
|
+
case EInputTypes.Date:
|
|
90
110
|
return toIsoDate(value) ?? (typeof value === "string" ? value : null);
|
|
91
|
-
case
|
|
111
|
+
case EInputTypes.DateRange:
|
|
92
112
|
return toDateRange(Array.isArray(value) ? value : null);
|
|
93
|
-
case
|
|
113
|
+
case EInputTypes.Time:
|
|
94
114
|
return toIsoTime(value, normalizeTimeStep(params.step) % 60 !== 0) ?? (typeof value === "string" ? value : null);
|
|
95
|
-
case
|
|
115
|
+
case EInputTypes.DateTime:
|
|
96
116
|
return toUtcDateTime(value) ?? (typeof value === "string" ? value : null);
|
|
97
|
-
case
|
|
98
|
-
case
|
|
99
|
-
case
|
|
100
|
-
case
|
|
117
|
+
case EInputTypes.CheckBoxGroup:
|
|
118
|
+
case EInputTypes.Tree:
|
|
119
|
+
case EInputTypes.Tabular:
|
|
120
|
+
case EInputTypes.Group:
|
|
101
121
|
return Array.isArray(value) ? value : [];
|
|
102
|
-
case
|
|
122
|
+
case EInputTypes.Dropdown:
|
|
103
123
|
if (params.multiple)
|
|
104
124
|
return Array.isArray(value) ? value : [value];
|
|
105
125
|
return Array.isArray(value) ? (value[0] ?? null) : value;
|
|
106
|
-
case
|
|
126
|
+
case EInputTypes.Slider:
|
|
107
127
|
return typeof value === "number" ? value : (parseNumber(String(value)) ?? params.min ?? 0);
|
|
108
|
-
case
|
|
128
|
+
case EInputTypes.RangeSlider:
|
|
109
129
|
return Array.isArray(value) && value.length === 2 ? value : emptyInputValue(params);
|
|
110
|
-
case
|
|
130
|
+
case EInputTypes.RadioGroup:
|
|
111
131
|
return value;
|
|
112
|
-
case
|
|
132
|
+
case EInputTypes.Code:
|
|
113
133
|
// Only separators and case: a saved code that does not fit stays as it is, so its check refuses the save.
|
|
114
134
|
return loadCode(value, params);
|
|
115
135
|
default:
|
|
@@ -134,6 +154,67 @@ export function inputValuesEqual(a, b) {
|
|
|
134
154
|
return false;
|
|
135
155
|
return a.every((item, index) => Object.is(item, b[index]));
|
|
136
156
|
}
|
|
157
|
+
/**
|
|
158
|
+
* The inputs with some of them fixed for one opening of a form: each input `locked` names (input name -> why) turns
|
|
159
|
+
* read-only and says why on any try to change it (`readOnlyMessage`), the lock-and-note look every input has. Its value
|
|
160
|
+
* stays in the form and is sent as before. A required input with no value in `values` stays free: fixed empty, the form
|
|
161
|
+
* would never ask for it, since read-only inputs are not checked. Names a form does not have are skipped.
|
|
162
|
+
*
|
|
163
|
+
* Each fixed input is a copy made from its own property descriptors, never a spread: a spread would read a getter once
|
|
164
|
+
* (`get readOnly()` or `get options()` following other values through `dependsOn`) and freeze it.
|
|
165
|
+
*
|
|
166
|
+
* To show fixed inputs disabled instead (dimmed, out of the Tab order, no note), write `disabled` for `readOnly` in the
|
|
167
|
+
* copy below.
|
|
168
|
+
*
|
|
169
|
+
* `known` are records the caller holds for the fixed values - the row picked in another list that a new record is added
|
|
170
|
+
* for: a fixed dropdown whose value one of them holds (by the dropdown's `valueKey`) gets it as a selected option, so its
|
|
171
|
+
* box names the value at once, with no lookup.
|
|
172
|
+
*
|
|
173
|
+
* @example lockInputs(REGION_INPUTS, { countryId: "Added inside Bagmati." }, { countryId: "c7" })
|
|
174
|
+
*/
|
|
175
|
+
export function lockInputs(inputs, locked, values = {}, known = []) {
|
|
176
|
+
return inputs.map(params => {
|
|
177
|
+
const reason = locked[params.name];
|
|
178
|
+
if (reason === undefined)
|
|
179
|
+
return params;
|
|
180
|
+
const required = params.required === true;
|
|
181
|
+
if (required && isEmptyInputValue(values[params.name]))
|
|
182
|
+
return params;
|
|
183
|
+
const fixed = {
|
|
184
|
+
...Object.getOwnPropertyDescriptors(params),
|
|
185
|
+
readOnly: { value: true, enumerable: true, writable: true, configurable: true },
|
|
186
|
+
readOnlyMessage: { value: reason, enumerable: true, writable: true, configurable: true },
|
|
187
|
+
};
|
|
188
|
+
const value = values[params.name];
|
|
189
|
+
if (params.type === EInputTypes.Dropdown && !params.multiple && !isEmptyInputValue(value)) {
|
|
190
|
+
const valueKey = params.valueKey ?? "value";
|
|
191
|
+
const record = known.find(item => String(item[valueKey]) === String(value));
|
|
192
|
+
if (record)
|
|
193
|
+
fixed.selectedOptions = { value: [...(params.selectedOptions ?? []), record], enumerable: true, writable: true, configurable: true };
|
|
194
|
+
}
|
|
195
|
+
return Object.create(Object.getPrototypeOf(params), fixed);
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* A form's `onFieldChange` that never writes the inputs fixed for an opening (`lockInputs`): a rule such as "a province
|
|
200
|
+
* sits right under its country" still changes a free field, and leaves a fixed one as the form opened it. With nothing
|
|
201
|
+
* fixed, or no rule, the rule as it is.
|
|
202
|
+
*
|
|
203
|
+
* @example lockedFieldChange(form.onFieldChange, ["countryId", "parentId"])
|
|
204
|
+
*/
|
|
205
|
+
export function lockedFieldChange(onFieldChange, fixed) {
|
|
206
|
+
if (!onFieldChange || fixed.length === 0)
|
|
207
|
+
return onFieldChange;
|
|
208
|
+
return (name, value, values) => {
|
|
209
|
+
const patch = onFieldChange(name, value, values);
|
|
210
|
+
if (!patch)
|
|
211
|
+
return patch;
|
|
212
|
+
const kept = { ...patch };
|
|
213
|
+
for (const field of fixed)
|
|
214
|
+
delete kept[field];
|
|
215
|
+
return kept;
|
|
216
|
+
};
|
|
217
|
+
}
|
|
137
218
|
function dateSettings(params, preferences) {
|
|
138
219
|
return {
|
|
139
220
|
calendar: params.calendar ?? preferences.calendar,
|
|
@@ -164,35 +245,35 @@ export function validateInput(params, value, context = {}) {
|
|
|
164
245
|
const name = inputFieldName(params);
|
|
165
246
|
const preferences = context.preferences ?? DEFAULT_DATE_PREFERENCES;
|
|
166
247
|
switch (params.type) {
|
|
167
|
-
case
|
|
248
|
+
case EInputTypes.Number:
|
|
168
249
|
return validateNumber(value, params, name, limit => formatNumber(limit, { locale: params.locale, grouping: true }));
|
|
169
|
-
case
|
|
170
|
-
case
|
|
250
|
+
case EInputTypes.CheckBox:
|
|
251
|
+
case EInputTypes.Switch:
|
|
171
252
|
return validateCheck(value === true, params, params.fieldName);
|
|
172
|
-
case
|
|
253
|
+
case EInputTypes.Radio:
|
|
173
254
|
// One row at a time can have it on; whether one must is the rows' rule.
|
|
174
255
|
return null;
|
|
175
|
-
case
|
|
256
|
+
case EInputTypes.CheckBoxGroup:
|
|
176
257
|
return validateSelection(asArray(value), params, name);
|
|
177
|
-
case
|
|
258
|
+
case EInputTypes.RadioGroup: {
|
|
178
259
|
const { validate } = params;
|
|
179
260
|
return validateSelection(asArray(value), { required: params.required, validate: validate && (values => validate(values[0] ?? null)) }, name);
|
|
180
261
|
}
|
|
181
|
-
case
|
|
262
|
+
case EInputTypes.Dropdown:
|
|
182
263
|
return validateSelection(asArray(value), { required: params.required, min: params.min, max: params.max, validate: params.validate }, name);
|
|
183
|
-
case
|
|
264
|
+
case EInputTypes.Date: {
|
|
184
265
|
const settings = dateSettings(params, preferences);
|
|
185
266
|
return validateDate(value, params, name, iso => formatDate(iso, settings));
|
|
186
267
|
}
|
|
187
|
-
case
|
|
268
|
+
case EInputTypes.DateRange: {
|
|
188
269
|
const settings = dateSettings(params, preferences);
|
|
189
270
|
return validateDateRange(value, params, name, iso => formatDate(iso, settings));
|
|
190
271
|
}
|
|
191
|
-
case
|
|
272
|
+
case EInputTypes.Time: {
|
|
192
273
|
const settings = timeSettings(params, preferences);
|
|
193
274
|
return validateTime(value, params, name, iso => formatTime(iso, settings));
|
|
194
275
|
}
|
|
195
|
-
case
|
|
276
|
+
case EInputTypes.DateTime: {
|
|
196
277
|
const seconds = normalizeTimeStep(params.step) % 60 !== 0;
|
|
197
278
|
return validateDateTime(value, params, name, {
|
|
198
279
|
...dateSettings(params, preferences),
|
|
@@ -201,23 +282,24 @@ export function validateInput(params, value, context = {}) {
|
|
|
201
282
|
seconds,
|
|
202
283
|
});
|
|
203
284
|
}
|
|
204
|
-
case
|
|
285
|
+
case EInputTypes.Code:
|
|
205
286
|
return validateCode(value, params, name);
|
|
206
|
-
case
|
|
287
|
+
case EInputTypes.Slider:
|
|
207
288
|
return params.validate?.(value) || null;
|
|
208
|
-
case
|
|
289
|
+
case EInputTypes.RangeSlider:
|
|
209
290
|
return params.validate?.(value) || null;
|
|
210
|
-
case
|
|
291
|
+
case EInputTypes.Tree:
|
|
292
|
+
case EInputTypes.Picture:
|
|
211
293
|
return null;
|
|
212
|
-
case
|
|
294
|
+
case EInputTypes.RichText:
|
|
213
295
|
return validateRichText(value, params, name);
|
|
214
|
-
case
|
|
215
|
-
case
|
|
296
|
+
case EInputTypes.Tabular:
|
|
297
|
+
case EInputTypes.Group: {
|
|
216
298
|
const result = validateRows(asArray(value), params, context);
|
|
217
299
|
if (result.message)
|
|
218
300
|
return result.message;
|
|
219
301
|
const first = result.cells[0];
|
|
220
|
-
return first ? `${rowsItemNames(params, params.type ===
|
|
302
|
+
return first ? `${rowsItemNames(params, params.type === EInputTypes.Tabular ? "Row" : "Item").title} ${first.index + 1}: ${first.message}` : null;
|
|
221
303
|
}
|
|
222
304
|
default:
|
|
223
305
|
return validateText(value, params, name);
|
|
@@ -263,7 +345,7 @@ export function rowsMessage(rows, rules, fallback = "Row") {
|
|
|
263
345
|
if (rules.max !== undefined && count > rules.max)
|
|
264
346
|
return maxRowsMessage(rules.max, names.item, names.items);
|
|
265
347
|
for (const params of rules.inputs) {
|
|
266
|
-
if (params.type !==
|
|
348
|
+
if (params.type !== EInputTypes.Radio || !params.required || params.hidden)
|
|
267
349
|
continue;
|
|
268
350
|
if (!rows.some(row => row[params.name] === true))
|
|
269
351
|
return chooseRowMessage(radioName(params), names.item);
|
|
@@ -348,47 +430,48 @@ export function formatInputValue(params, value, context = {}) {
|
|
|
348
430
|
return "";
|
|
349
431
|
const preferences = context.preferences ?? DEFAULT_DATE_PREFERENCES;
|
|
350
432
|
switch (params.type) {
|
|
351
|
-
case
|
|
433
|
+
case EInputTypes.Number: {
|
|
352
434
|
const text = formatNumber(value, { ...params, grouping: params.grouping ?? true });
|
|
353
435
|
const prefix = typeof params.prefix === "string" ? params.prefix + " " : "";
|
|
354
436
|
const suffix = typeof params.suffix === "string" ? " " + params.suffix : "";
|
|
355
437
|
return prefix + text + suffix;
|
|
356
438
|
}
|
|
357
|
-
case
|
|
358
|
-
case
|
|
359
|
-
case
|
|
439
|
+
case EInputTypes.CheckBox:
|
|
440
|
+
case EInputTypes.Switch:
|
|
441
|
+
case EInputTypes.Radio:
|
|
360
442
|
return typeof params.label === "string" ? params.label : "";
|
|
361
|
-
case
|
|
443
|
+
case EInputTypes.Dropdown:
|
|
362
444
|
return asArray(value)
|
|
363
445
|
.map(item => optionLabel(params.options, item, params.valueKey, params.labelKey))
|
|
364
446
|
.join(", ");
|
|
365
|
-
case
|
|
366
|
-
case
|
|
447
|
+
case EInputTypes.CheckBoxGroup:
|
|
448
|
+
case EInputTypes.RadioGroup:
|
|
367
449
|
return asArray(value)
|
|
368
450
|
.map(item => optionLabel(params.options, item))
|
|
369
451
|
.join(", ");
|
|
370
|
-
case
|
|
452
|
+
case EInputTypes.Date:
|
|
371
453
|
return formatDate(value, dateSettings(params, preferences));
|
|
372
|
-
case
|
|
454
|
+
case EInputTypes.DateRange:
|
|
373
455
|
return formatDateRange(value, dateSettings(params, preferences));
|
|
374
|
-
case
|
|
456
|
+
case EInputTypes.Time:
|
|
375
457
|
return formatTime(value, timeSettings(params, preferences));
|
|
376
|
-
case
|
|
458
|
+
case EInputTypes.DateTime:
|
|
377
459
|
return formatDateTime(value, { ...dateSettings(params, preferences), timeFormat: params.timeFormat ?? preferences.timeFormat, timeZone: params.timeZone });
|
|
378
|
-
case
|
|
460
|
+
case EInputTypes.Code:
|
|
379
461
|
return formatCode(value, params);
|
|
380
|
-
case
|
|
462
|
+
case EInputTypes.Slider:
|
|
381
463
|
return formatNumber(value, params);
|
|
382
|
-
case
|
|
464
|
+
case EInputTypes.RangeSlider:
|
|
383
465
|
return asArray(value)
|
|
384
466
|
.map(item => formatNumber(item, params))
|
|
385
467
|
.join(" – ");
|
|
386
|
-
case
|
|
387
|
-
case
|
|
388
|
-
case
|
|
468
|
+
case EInputTypes.Tree:
|
|
469
|
+
case EInputTypes.Tabular:
|
|
470
|
+
case EInputTypes.Group:
|
|
471
|
+
case EInputTypes.Picture:
|
|
389
472
|
return "";
|
|
390
473
|
default: {
|
|
391
|
-
const text = params.type ===
|
|
474
|
+
const text = params.type === EInputTypes.RichText ? richTextToPlainText(String(value)) : String(value).trim();
|
|
392
475
|
const line = text.split("\n", 1)[0] ?? "";
|
|
393
476
|
return line.length > 60 ? line.slice(0, 57) + "…" : line;
|
|
394
477
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { ApiClient } from "./ApiClient.ts";
|
|
2
|
+
import { FileAdapter } from "./FileAdapter.ts";
|
|
3
|
+
import { type ApiModuleValue, type ApiResult } from "../Interfaces/ApiInterfaces.ts";
|
|
4
|
+
import type { FileCallOptions, FileCopy, FileOwner, FileUpload, OwnerFiles, StoredFile } from "../Interfaces/FileInterfaces.ts";
|
|
5
|
+
/**
|
|
6
|
+
* Why an owner's files are read only when its module refuses a write ticket with a 404 but a read ticket finds it: the
|
|
7
|
+
* owner is not in use now (pending, ended, in the trash or deleted). Its files stay where they are.
|
|
8
|
+
*/
|
|
9
|
+
export declare const OWNER_NOT_IN_USE_REASON = "This record is not in use now, so its files can be seen but not changed.";
|
|
10
|
+
/** What the adapter sends its calls with: the app's `api` (nexus-shared/client), so its token and headers go with them. */
|
|
11
|
+
export type FileApiClient = Pick<ApiClient<{
|
|
12
|
+
toast?: false;
|
|
13
|
+
}>, "send">;
|
|
14
|
+
export interface NexusDriveAdapterOptions {
|
|
15
|
+
/** The client the calls go through: `api` from nexus-shared/client. */
|
|
16
|
+
client: FileApiClient;
|
|
17
|
+
/** Reads the editor's pointer file. Default the browser's `fetch`. */
|
|
18
|
+
fetch?: typeof fetch;
|
|
19
|
+
/** The app's Drive module. Default `NexusModule.Drive`. */
|
|
20
|
+
drive?: ApiModuleValue;
|
|
21
|
+
/** The pointer file that names the current editor. Default `nexus-image-editor.txt` (Drive's `copy-image-editor.mjs`). */
|
|
22
|
+
editorPointer?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The Nexus Drive (`Nexus.Drives`, `App/Api/File/...`) behind the owner modules' tickets (`App/Api/Files/...`).
|
|
26
|
+
* Register another with `defineFileAdapter` to keep files elsewhere.
|
|
27
|
+
*/
|
|
28
|
+
export declare class NexusDriveAdapter extends FileAdapter {
|
|
29
|
+
readonly drive: ApiModuleValue;
|
|
30
|
+
readonly editorPointer: string;
|
|
31
|
+
private readonly tickets;
|
|
32
|
+
private readonly client;
|
|
33
|
+
private readonly fetcher;
|
|
34
|
+
constructor(options: NexusDriveAdapterOptions);
|
|
35
|
+
private driveEndpoint;
|
|
36
|
+
/** A write ticket for the owner, kept while it is good. */
|
|
37
|
+
private writeTicket;
|
|
38
|
+
/** Calls Drive with the owner's write ticket, asking for a fresh one once when Drive says it ran out. */
|
|
39
|
+
private withTicket;
|
|
40
|
+
/** A read ticket for several owners of one category. */
|
|
41
|
+
private readTicket;
|
|
42
|
+
list(owner: FileOwner<ApiModuleValue>, options?: FileCallOptions): Promise<ApiResult<OwnerFiles>>;
|
|
43
|
+
primaries(module: ApiModuleValue, category: string, ownerIds: readonly string[], options?: FileCallOptions): Promise<ApiResult<(StoredFile | null)[]>>;
|
|
44
|
+
upload(owner: FileOwner<ApiModuleValue>, upload: FileUpload, options?: FileCallOptions): Promise<ApiResult<StoredFile>>;
|
|
45
|
+
setPrimary(owner: FileOwner<ApiModuleValue>, fileId: string | null, options?: FileCallOptions): Promise<ApiResult<unknown>>;
|
|
46
|
+
rename(owner: FileOwner<ApiModuleValue>, fileId: string, name: string, options?: FileCallOptions): Promise<ApiResult<unknown>>;
|
|
47
|
+
remove(owner: FileOwner<ApiModuleValue>, fileId: string, options?: FileCallOptions): Promise<ApiResult<unknown>>;
|
|
48
|
+
fileUrl(file: StoredFile, copy: FileCopy): string;
|
|
49
|
+
/** Reads Drive's pointer file (`Assets/File/nexus-image-editor.txt`), which names the versioned module beside it. */
|
|
50
|
+
editorModuleUrl(signal?: AbortSignal): Promise<string>;
|
|
51
|
+
}
|
|
52
|
+
/** Reads one of Drive's `FileResponseContract`s; null when it is not one. */
|
|
53
|
+
export declare function readStoredFile(value: unknown): StoredFile | null;
|
|
54
|
+
/** Reads Drive's `FileListResponseContract`. */
|
|
55
|
+
export declare function readOwnerFiles(value: unknown): OwnerFiles;
|