nexus-shared 1.1.21 → 3.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 +262 -0
- package/LICENSE +21 -0
- package/README.md +1000 -0
- package/dist/Client.Index.d.ts +55 -0
- package/dist/Client.Index.js +60 -0
- package/dist/Components/Chats/Chat.d.ts +28 -0
- package/dist/Components/Chats/Chat.js +19 -0
- package/dist/Components/Chats/ChatButton.d.ts +26 -0
- package/dist/Components/Chats/ChatButton.js +41 -0
- package/dist/Components/Chats/ChatComposer.d.ts +41 -0
- package/dist/Components/Chats/ChatComposer.js +177 -0
- package/dist/Components/Chats/ChatConversations.d.ts +35 -0
- package/dist/Components/Chats/ChatConversations.js +38 -0
- package/dist/Components/Chats/ChatPanel.d.ts +66 -0
- package/dist/Components/Chats/ChatPanel.js +94 -0
- package/dist/Components/Chats/ChatParts.d.ts +87 -0
- package/dist/Components/Chats/ChatParts.js +100 -0
- package/dist/Components/Chats/ChatThread.d.ts +22 -0
- package/dist/Components/Chats/ChatThread.js +96 -0
- package/dist/Components/Documents/Button.d.ts +29 -0
- package/dist/Components/Documents/Button.js +11 -0
- package/dist/Components/Documents/Menu.d.ts +102 -0
- package/dist/Components/Documents/Menu.js +242 -0
- package/dist/Components/Documents/SplitButton.d.ts +64 -0
- package/dist/Components/Documents/SplitButton.js +129 -0
- package/dist/Components/Documents/TabButtons.d.ts +80 -0
- package/dist/Components/Documents/TabButtons.js +38 -0
- package/dist/Components/Forms/ApiForm.d.ts +23 -0
- package/dist/Components/Forms/ApiForm.js +100 -0
- package/dist/Components/Forms/Crud.d.ts +17 -0
- package/dist/Components/Forms/Crud.js +708 -0
- package/dist/Components/Forms/CrudParts.d.ts +15 -0
- package/dist/Components/Forms/CrudParts.js +36 -0
- package/dist/Components/Forms/ExcelImport.d.ts +42 -0
- package/dist/Components/Forms/ExcelImport.js +190 -0
- package/dist/Components/Forms/Form.d.ts +52 -0
- package/dist/Components/Forms/Form.js +323 -0
- package/dist/Components/Forms/SubmitForm.d.ts +65 -0
- package/dist/Components/Forms/SubmitForm.js +198 -0
- package/dist/Components/Inputs/Calendar.d.ts +69 -0
- package/dist/Components/Inputs/Calendar.js +258 -0
- package/dist/Components/Inputs/CheckBox.d.ts +53 -0
- package/dist/Components/Inputs/CheckBox.js +87 -0
- package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
- package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
- package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
- package/dist/Components/Inputs/ChoiceField.js +169 -0
- package/dist/Components/Inputs/DatePicker.d.ts +54 -0
- package/dist/Components/Inputs/DatePicker.js +246 -0
- package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
- package/dist/Components/Inputs/DateRangePicker.js +283 -0
- package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
- package/dist/Components/Inputs/DateTimePicker.js +400 -0
- package/dist/Components/Inputs/Dropdown.d.ts +117 -0
- package/dist/Components/Inputs/Dropdown.js +839 -0
- package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
- package/dist/Components/Inputs/DropdownParts.js +102 -0
- package/dist/Components/Inputs/EditorShell.d.ts +45 -0
- package/dist/Components/Inputs/EditorShell.js +214 -0
- package/dist/Components/Inputs/Field.d.ts +53 -0
- package/dist/Components/Inputs/Field.js +16 -0
- package/dist/Components/Inputs/GroupForm.d.ts +20 -0
- package/dist/Components/Inputs/GroupForm.js +172 -0
- package/dist/Components/Inputs/InputField.d.ts +59 -0
- package/dist/Components/Inputs/InputField.js +169 -0
- package/dist/Components/Inputs/InputRenderer.d.ts +37 -0
- package/dist/Components/Inputs/InputRenderer.js +99 -0
- package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
- package/dist/Components/Inputs/MarkdownEditor.js +289 -0
- package/dist/Components/Inputs/NumberBox.d.ts +53 -0
- package/dist/Components/Inputs/NumberBox.js +228 -0
- package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
- package/dist/Components/Inputs/RadioGroup.js +43 -0
- package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
- package/dist/Components/Inputs/ReadOnlyNotice.js +117 -0
- package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
- package/dist/Components/Inputs/RichTextEditor.js +1170 -0
- package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
- package/dist/Components/Inputs/RichTextParts.js +157 -0
- package/dist/Components/Inputs/RowsInput.d.ts +115 -0
- package/dist/Components/Inputs/RowsInput.js +308 -0
- package/dist/Components/Inputs/Slider.d.ts +87 -0
- package/dist/Components/Inputs/Slider.js +216 -0
- package/dist/Components/Inputs/TabularForm.d.ts +27 -0
- package/dist/Components/Inputs/TabularForm.js +348 -0
- package/dist/Components/Inputs/TextArea.d.ts +43 -0
- package/dist/Components/Inputs/TextArea.js +31 -0
- package/dist/Components/Inputs/TextBox.d.ts +52 -0
- package/dist/Components/Inputs/TextBox.js +58 -0
- package/dist/Components/Inputs/TextField.d.ts +31 -0
- package/dist/Components/Inputs/TextField.js +35 -0
- package/dist/Components/Inputs/TimePanel.d.ts +34 -0
- package/dist/Components/Inputs/TimePanel.js +288 -0
- package/dist/Components/Inputs/TimePicker.d.ts +54 -0
- package/dist/Components/Inputs/TimePicker.js +240 -0
- package/dist/Components/Inputs/TreeView.d.ts +160 -0
- package/dist/Components/Inputs/TreeView.js +947 -0
- package/dist/Components/Layouts/MessageBox.d.ts +71 -0
- package/dist/Components/Layouts/MessageBox.js +104 -0
- package/dist/Components/Layouts/Popup.d.ts +92 -0
- package/dist/Components/Layouts/Popup.js +376 -0
- package/dist/Components/Layouts/PopupContext.d.ts +2 -0
- package/dist/Components/Layouts/PopupContext.js +4 -0
- package/dist/Components/Layouts/PopupDock.d.ts +22 -0
- package/dist/Components/Layouts/PopupDock.js +121 -0
- package/dist/Components/Layouts/PopupHost.d.ts +56 -0
- package/dist/Components/Layouts/PopupHost.js +163 -0
- package/dist/Components/Layouts/PopupRules.d.ts +30 -0
- package/dist/Components/Layouts/PopupRules.js +63 -0
- package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
- package/dist/Components/Layouts/ThemePicker.js +22 -0
- package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
- package/dist/Components/Layouts/ThemeScript.js +13 -0
- package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
- package/dist/Components/Layouts/ThemeSwitcher.js +49 -0
- package/dist/Components/Layouts/Toaster.d.ts +76 -0
- package/dist/Components/Layouts/Toaster.js +172 -0
- package/dist/Components/Viewers/DataTable.d.ts +25 -0
- package/dist/Components/Viewers/DataTable.js +596 -0
- package/dist/Components/Viewers/DataTableColumns.d.ts +28 -0
- package/dist/Components/Viewers/DataTableColumns.js +243 -0
- package/dist/Components/Viewers/DataTableParts.d.ts +138 -0
- package/dist/Components/Viewers/DataTableParts.js +157 -0
- package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
- package/dist/Components/Viewers/MarkdownView.js +79 -0
- package/dist/Components/Viewers/RichTextView.d.ts +18 -0
- package/dist/Components/Viewers/RichTextView.js +17 -0
- package/dist/Helpers/AnimationHelpers.d.ts +6 -0
- package/dist/Helpers/AnimationHelpers.js +35 -0
- package/dist/Helpers/ApiClient.d.ts +96 -0
- package/dist/Helpers/ApiClient.js +200 -0
- package/dist/Helpers/ApiFormHelpers.d.ts +49 -0
- package/dist/Helpers/ApiFormHelpers.js +120 -0
- package/dist/Helpers/ApiModules.d.ts +131 -0
- package/dist/Helpers/ApiModules.js +195 -0
- package/dist/Helpers/ApiResponses.d.ts +51 -0
- package/dist/Helpers/ApiResponses.js +250 -0
- package/dist/Helpers/ApiRoutes.d.ts +140 -0
- package/dist/Helpers/ApiRoutes.js +183 -0
- package/dist/Helpers/ApiToasts.d.ts +21 -0
- package/dist/Helpers/ApiToasts.js +22 -0
- package/dist/Helpers/ChatBackend.d.ts +134 -0
- package/dist/Helpers/ChatBackend.js +332 -0
- package/dist/Helpers/ChatHelpers.d.ts +189 -0
- package/dist/Helpers/ChatHelpers.js +486 -0
- package/dist/Helpers/ChatHooks.d.ts +81 -0
- package/dist/Helpers/ChatHooks.js +175 -0
- package/dist/Helpers/ChatStore.d.ts +132 -0
- package/dist/Helpers/ChatStore.js +394 -0
- package/dist/Helpers/ChatSummaries.d.ts +39 -0
- package/dist/Helpers/ChatSummaries.js +118 -0
- package/dist/Helpers/ClassHelpers.d.ts +3 -0
- package/dist/Helpers/ClassHelpers.js +4 -0
- package/dist/Helpers/CrudBackend.d.ts +98 -0
- package/dist/Helpers/CrudBackend.js +214 -0
- package/dist/Helpers/CrudHelpers.d.ts +111 -0
- package/dist/Helpers/CrudHelpers.js +267 -0
- package/dist/Helpers/DateHelpers.d.ts +88 -0
- package/dist/Helpers/DateHelpers.js +363 -0
- package/dist/Helpers/DatePreferences.d.ts +14 -0
- package/dist/Helpers/DatePreferences.js +94 -0
- package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
- package/dist/Helpers/DateTimeHelpers.js +286 -0
- package/dist/Helpers/DragHelpers.d.ts +129 -0
- package/dist/Helpers/DragHelpers.js +281 -0
- package/dist/Helpers/DropdownHelpers.d.ts +56 -0
- package/dist/Helpers/DropdownHelpers.js +180 -0
- package/dist/Helpers/ExcelBackend.d.ts +106 -0
- package/dist/Helpers/ExcelBackend.js +290 -0
- package/dist/Helpers/ExcelHelpers.d.ts +98 -0
- package/dist/Helpers/ExcelHelpers.js +302 -0
- package/dist/Helpers/FormDrafts.d.ts +18 -0
- package/dist/Helpers/FormDrafts.js +76 -0
- package/dist/Helpers/FormStore.d.ts +233 -0
- package/dist/Helpers/FormStore.js +752 -0
- package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
- package/dist/Helpers/InputParamsHelpers.js +388 -0
- package/dist/Helpers/MarkdownEditing.d.ts +27 -0
- package/dist/Helpers/MarkdownEditing.js +250 -0
- package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
- package/dist/Helpers/MarkdownHelpers.js +775 -0
- package/dist/Helpers/MessageBuilder.d.ts +74 -0
- package/dist/Helpers/MessageBuilder.js +252 -0
- package/dist/Helpers/NepaliCalendar.d.ts +25 -0
- package/dist/Helpers/NepaliCalendar.js +107 -0
- package/dist/Helpers/NumberHelpers.d.ts +71 -0
- package/dist/Helpers/NumberHelpers.js +202 -0
- package/dist/Helpers/Permissions.d.ts +62 -0
- package/dist/Helpers/Permissions.js +133 -0
- package/dist/Helpers/PopoverHelpers.d.ts +68 -0
- package/dist/Helpers/PopoverHelpers.js +195 -0
- package/dist/Helpers/RichTextHelpers.d.ts +77 -0
- package/dist/Helpers/RichTextHelpers.js +1072 -0
- package/dist/Helpers/RowsStore.d.ts +166 -0
- package/dist/Helpers/RowsStore.js +606 -0
- package/dist/Helpers/TableColumns.d.ts +47 -0
- package/dist/Helpers/TableColumns.js +282 -0
- package/dist/Helpers/TableExport.d.ts +30 -0
- package/dist/Helpers/TableExport.js +97 -0
- package/dist/Helpers/TableHelpers.d.ts +110 -0
- package/dist/Helpers/TableHelpers.js +301 -0
- package/dist/Helpers/TableStore.d.ts +142 -0
- package/dist/Helpers/TableStore.js +530 -0
- package/dist/Helpers/ThemeHelpers.d.ts +15 -0
- package/dist/Helpers/ThemeHelpers.js +16 -0
- package/dist/Helpers/TimeHelpers.d.ts +73 -0
- package/dist/Helpers/TimeHelpers.js +253 -0
- package/dist/Helpers/TreeStore.d.ts +188 -0
- package/dist/Helpers/TreeStore.js +577 -0
- package/dist/Helpers/ValidationHelpers.d.ts +124 -0
- package/dist/Helpers/ValidationHelpers.js +301 -0
- package/dist/Interfaces/ApiInterfaces.d.ts +174 -0
- package/dist/Interfaces/ApiInterfaces.js +30 -0
- package/dist/Interfaces/ChatInterfaces.d.ts +240 -0
- package/{src/sso-client.tsx → dist/Interfaces/ChatInterfaces.js} +1 -1
- package/dist/Interfaces/CrudInterfaces.d.ts +232 -0
- package/dist/Interfaces/CrudInterfaces.js +1 -0
- package/dist/Interfaces/DateInterfaces.d.ts +154 -0
- package/dist/Interfaces/DateInterfaces.js +29 -0
- package/dist/Interfaces/ExcelInterfaces.d.ts +215 -0
- package/dist/Interfaces/ExcelInterfaces.js +45 -0
- package/dist/Interfaces/FormInterfaces.d.ts +402 -0
- package/dist/Interfaces/FormInterfaces.js +1 -0
- package/dist/Interfaces/InputInterfaces.d.ts +141 -0
- package/dist/Interfaces/InputInterfaces.js +1 -0
- package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
- package/dist/Interfaces/MessageInterfaces.js +5 -0
- package/dist/Interfaces/TableInterfaces.d.ts +351 -0
- package/dist/Interfaces/TableInterfaces.js +1 -0
- package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
- package/dist/Interfaces/ThemeInterfaces.js +17 -0
- package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
- package/dist/Interfaces/TypeInterfaces.js +1 -0
- package/dist/Server.Index.d.ts +2 -0
- package/dist/Server.Index.js +5 -0
- package/dist/Services/ApiProxy.d.ts +32 -0
- package/dist/Services/ApiProxy.js +111 -0
- package/dist/Services/BrowserApi.d.ts +95 -0
- package/dist/Services/BrowserApi.js +129 -0
- package/dist/Services/ChatApi.d.ts +37 -0
- package/dist/Services/ChatApi.js +98 -0
- package/dist/Services/ExcelApi.d.ts +46 -0
- package/dist/Services/ExcelApi.js +196 -0
- package/dist/Services/ServerApi.d.ts +54 -0
- package/dist/Services/ServerApi.js +78 -0
- package/dist/Services/ThemeService.d.ts +17 -0
- package/dist/Services/ThemeService.js +83 -0
- package/dist/Shared.Index.d.ts +51 -0
- package/dist/Shared.Index.js +55 -0
- package/package.json +85 -33
- package/src/Styles/Nexus.Base.css +70 -0
- package/src/Styles/Nexus.Button.css +153 -0
- package/src/Styles/Nexus.Calendar.css +275 -0
- package/src/Styles/Nexus.Chat.css +1489 -0
- package/src/Styles/Nexus.Choice.css +345 -0
- package/src/Styles/Nexus.Crud.css +161 -0
- package/src/Styles/Nexus.DateTime.css +81 -0
- package/src/Styles/Nexus.Dropdown.css +774 -0
- package/src/Styles/Nexus.Editor.css +297 -0
- package/src/Styles/Nexus.Excel.css +370 -0
- package/src/Styles/Nexus.Form.css +321 -0
- package/src/Styles/Nexus.Index.css +36 -0
- package/src/Styles/Nexus.Input.css +637 -0
- package/src/Styles/Nexus.Markdown.css +265 -0
- package/src/Styles/Nexus.Menu.css +259 -0
- package/src/Styles/Nexus.Popup.css +731 -0
- package/src/Styles/Nexus.RichText.css +463 -0
- package/src/Styles/Nexus.Rows.css +596 -0
- package/src/Styles/Nexus.Slider.css +278 -0
- package/src/Styles/Nexus.Tab.Buttons.css +419 -0
- package/src/Styles/Nexus.Table.css +1296 -0
- package/src/Styles/Nexus.Theme.Picker.css +232 -0
- package/src/Styles/Nexus.Themes.css +194 -0
- package/src/Styles/Nexus.Time.css +147 -0
- package/src/Styles/Nexus.Toast.css +265 -0
- package/src/Styles/Nexus.Tokens.css +72 -0
- package/src/Styles/Nexus.Tree.css +435 -0
- package/src/api-services/authentication-service.tsx +0 -23
- package/src/api-services/preference-service.tsx +0 -5
- package/src/api-services/system-service.tsx +0 -29
- package/src/client.ts +0 -31
- package/src/components/documents/button.tsx +0 -133
- package/src/components/documents/icon-box.tsx +0 -93
- package/src/components/documents/page-title.tsx +0 -7
- package/src/components/documents/tab-button.tsx +0 -172
- package/src/components/documents/tag.tsx +0 -30
- package/src/components/index.js +0 -0
- package/src/components/inputs/checkbox-input.tsx +0 -66
- package/src/components/inputs/input-box.tsx +0 -48
- package/src/components/inputs/input-element.tsx +0 -65
- package/src/components/inputs/input-form.tsx +0 -164
- package/src/components/inputs/input.tsx +0 -181
- package/src/components/inputs/number-input.tsx +0 -108
- package/src/components/inputs/radiobox-input.tsx +0 -53
- package/src/components/inputs/textarea-input.tsx +0 -47
- package/src/components/inputs/textbox-input.tsx +0 -45
- package/src/components/layouts/global-dialogbox.tsx +0 -431
- package/src/components/layouts/global-layout.tsx +0 -64
- package/src/components/layouts/layout-helpers.tsx +0 -20
- package/src/components/layouts/panels/user-panel.tsx +0 -112
- package/src/components/layouts/utility-menu.tsx +0 -49
- package/src/components/panels/theme-panel.tsx +0 -46
- package/src/helpers/bitwise-helpers.tsx +0 -11
- package/src/helpers/browser-helpers.tsx +0 -156
- package/src/helpers/datasource-helpers.tsx +0 -99
- package/src/helpers/element-helpers.tsx +0 -123
- package/src/helpers/input-helpers.tsx +0 -74
- package/src/helpers/string-helpers.tsx +0 -28
- package/src/helpers/utility-helpers.tsx +0 -45
- package/src/helpers/validation-helpers.tsx +0 -302
- package/src/index.ts +0 -26
- package/src/interface.ts +0 -19
- package/src/interfaces/auth-token-interfaces.tsx +0 -6
- package/src/interfaces/browser-interfaces.tsx +0 -36
- package/src/interfaces/button-interfaces.tsx +0 -63
- package/src/interfaces/datasource-interfaces.tsx +0 -22
- package/src/interfaces/datatable-interfaces.tsx +0 -25
- package/src/interfaces/dialogbox-interfaces.tsx +0 -5
- package/src/interfaces/exception-interfaces.tsx +0 -99
- package/src/interfaces/http-interfaces.tsx +0 -129
- package/src/interfaces/icon-interfaces.tsx +0 -129
- package/src/interfaces/input-interfaces.tsx +0 -410
- package/src/interfaces/layout-interfaces.tsx +0 -191
- package/src/interfaces/menu-interfaces.tsx +0 -53
- package/src/interfaces/message-interfaces.tsx +0 -32
- package/src/interfaces/permission-interfaces.tsx +0 -9
- package/src/interfaces/storage-interfaces.tsx +0 -5
- package/src/interfaces/system-interfaces.tsx +0 -22
- package/src/interfaces/theme-interfaces.tsx +0 -123
- package/src/interfaces/type-interfaces.tsx +0 -28
- package/src/interfaces/user-interfaces.tsx +0 -47
- package/src/nexus-client.tsx +0 -21
- package/src/nexus.environments.tsx +0 -66
- package/src/proxy-api/proxy-backend.tsx +0 -60
- package/src/proxy-api/proxy-constants.tsx +0 -28
- package/src/proxy-api/proxy-helpers.tsx +0 -91
- package/src/proxy-api-client.tsx +0 -1
- package/src/proxy-api-server.tsx +0 -2
- package/src/services/http-client-services.tsx +0 -75
- package/src/services/http-services.tsx +0 -158
- package/src/services/loader-service.tsx +0 -185
- package/src/services/localstorage-service.tsx +0 -119
- package/src/services/message-services.tsx +0 -383
- package/src/services/theme-service.tsx +0 -163
- package/src/services/user-services.tsx +0 -10
- package/src/sso-config/auth-token-validation.ts +0 -16
- package/src/sso-config/callback-route.tsx +0 -35
- package/src/sso-config/cookie-encryption.ts +0 -51
- package/src/sso-config/cookie-helpers.tsx +0 -102
- package/src/sso-config/forgot-password-route.tsx +0 -36
- package/src/sso-config/oauth-callback-state.ts +0 -61
- package/src/sso-config/pkce-helpers.ts +0 -9
- package/src/sso-config/provider-complete-route.tsx +0 -18
- package/src/sso-config/redirect-context-actions.tsx +0 -45
- package/src/sso-config/redirect-context-helpers.tsx +0 -159
- package/src/sso-config/redirect-context-persist.tsx +0 -18
- package/src/sso-config/redirect-context-route.tsx +0 -45
- package/src/sso-config/refresh-route.tsx +0 -23
- package/src/sso-config/sign-in-route.tsx +0 -74
- package/src/sso-config/sign-out-route.tsx +0 -57
- package/src/sso-config/sign-up-route.tsx +0 -57
- package/src/sso-config/sso-backend-flow.ts +0 -38
- package/src/sso-config/sso-complete-route.tsx +0 -50
- package/src/sso-config/sso-config.ts +0 -59
- package/src/sso-config/sso-interfaces.tsx +0 -99
- package/src/sso-config/sso-response-helpers.tsx +0 -20
- package/src/sso-server.tsx +0 -21
- package/src/styles/nexus.animation.css +0 -269
- package/src/styles/nexus.core.css +0 -119
- package/src/styles/nexus.dialog.css +0 -144
- package/src/styles/nexus.grid-view.css +0 -42
- package/src/styles/nexus.icon.css +0 -51
- package/src/styles/nexus.input.css +0 -207
- package/src/styles/nexus.loader.css +0 -11
- package/src/styles/nexus.logic.css +0 -47
- package/src/styles/nexus.utility.css +0 -347
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { FormValues } from "../../Interfaces/FormInterfaces.ts";
|
|
3
|
+
import type { TableColumn } from "../../Interfaces/TableInterfaces.ts";
|
|
4
|
+
export interface CrudDetailsProps<TRow extends FormValues = FormValues> {
|
|
5
|
+
/** The record as the list has it, shown at once. */
|
|
6
|
+
row: TRow;
|
|
7
|
+
/** The fields, as the table's columns describe them; hidden columns included. */
|
|
8
|
+
columns: readonly TableColumn<TRow>[];
|
|
9
|
+
/** Loads the full record (fields the list leaves out); its values replace the row's when they come. */
|
|
10
|
+
load?: (signal: AbortSignal) => Promise<Partial<TRow> | null | undefined>;
|
|
11
|
+
/** Draws the details instead of the list of fields. */
|
|
12
|
+
render?: (row: TRow) => ReactNode;
|
|
13
|
+
}
|
|
14
|
+
/** A record's fields as label and value, two to a line where there is room, in the formats of the table's columns. */
|
|
15
|
+
export declare function CrudDetails<TRow extends FormValues = FormValues>({ row, columns, load, render }: CrudDetailsProps<TRow>): import("react").JSX.Element;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { iconInfoCircle, iconLoader2, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { isAbortError } from "../../Helpers/ApiResponses.js";
|
|
6
|
+
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
7
|
+
import { useBrowserTimeZone, useDatePreferences } from "../../Helpers/DatePreferences.js";
|
|
8
|
+
import { TableCellValue } from "../Viewers/DataTableParts.js";
|
|
9
|
+
/** A record's fields as label and value, two to a line where there is room, in the formats of the table's columns. */
|
|
10
|
+
export function CrudDetails({ row, columns, load, render }) {
|
|
11
|
+
const [record, setRecord] = useState(row);
|
|
12
|
+
const [state, setState] = useState(load ? "loading" : "done");
|
|
13
|
+
const preferences = useDatePreferences();
|
|
14
|
+
const timeZone = useBrowserTimeZone();
|
|
15
|
+
const options = useMemo(() => ({ preferences, timeZone: timeZone ?? undefined }), [preferences, timeZone]);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (!load)
|
|
18
|
+
return;
|
|
19
|
+
const controller = new AbortController();
|
|
20
|
+
load(controller.signal).then(full => {
|
|
21
|
+
if (controller.signal.aborted)
|
|
22
|
+
return;
|
|
23
|
+
if (full)
|
|
24
|
+
setRecord(current => ({ ...current, ...full }));
|
|
25
|
+
setState("done");
|
|
26
|
+
}, error => {
|
|
27
|
+
if (controller.signal.aborted || isAbortError(error))
|
|
28
|
+
return;
|
|
29
|
+
setState("failed");
|
|
30
|
+
});
|
|
31
|
+
return () => controller.abort();
|
|
32
|
+
// The record loads once per popup.
|
|
33
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
34
|
+
}, []);
|
|
35
|
+
return (_jsxs("div", { className: "nx-crud-details", "aria-busy": state === "loading" || undefined, children: [state === "loading" && (_jsxs("p", { className: "nx-crud-details__note", role: "status", children: [_jsx(InlineIcon, { icon: iconLoader2, className: "nx-spin" }), "Loading the full record\u2026"] })), state === "failed" && (_jsxs("p", { className: "nx-crud-details__note", role: "status", children: [_jsx(InlineIcon, { icon: iconInfoCircle }), "The full record could not be loaded; these are the values from the list."] })), render ? (render(record)) : (_jsx("dl", { className: "nx-crud-details__list", children: columns.map(column => (_jsxs("div", { className: cx("nx-crud-details__item", column.wrap && "nx-crud-details__item--wide"), children: [_jsx("dt", { className: "nx-crud-details__label", children: column.label }), _jsx("dd", { className: "nx-crud-details__value", children: _jsx(TableCellValue, { column: column, row: record, options: options }) })] }, column.key))) }))] }));
|
|
36
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import type { ExcelEndpoints, ExcelImportAnswer } from "../../Interfaces/ExcelInterfaces.ts";
|
|
3
|
+
import { type ExcelCallOptions } from "../../Services/ExcelApi.ts";
|
|
4
|
+
import { type PopupHandle } from "../Layouts/PopupHost.tsx";
|
|
5
|
+
/** What an import panel needs. */
|
|
6
|
+
export interface ExcelImportProps {
|
|
7
|
+
/** The model's spreadsheet endpoints: `excelEndpoints(CITIES)`, or the app's own four. */
|
|
8
|
+
endpoints: ExcelEndpoints;
|
|
9
|
+
/** What one row is: "city". Default: what the settings say. */
|
|
10
|
+
subject?: string;
|
|
11
|
+
/** Path values the calls need, such as a parent id. */
|
|
12
|
+
params?: ExcelCallOptions["params"];
|
|
13
|
+
/** After an import wrote something, to reload the list behind the panel. */
|
|
14
|
+
onImported?: (answer: ExcelImportAnswer) => void;
|
|
15
|
+
/** The Close button, and what it does. Without it, none shows (a popup has its own). */
|
|
16
|
+
onClose?: () => void;
|
|
17
|
+
/** No template download is offered, for a model whose file comes from somewhere else. */
|
|
18
|
+
templateDownload?: false;
|
|
19
|
+
/** The tallest each editor grows before its rows scroll. Default 320. */
|
|
20
|
+
maxHeight?: number;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The three steps of an import in one panel: the template, the file, and the review.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* <ExcelImport endpoints={CITY_SHEET} subject="city" onImported={() => table.reload()} />
|
|
28
|
+
*/
|
|
29
|
+
export declare function ExcelImport({ endpoints, subject: given, params, onImported, onClose, templateDownload, maxHeight, className }: ExcelImportProps): import("react").JSX.Element;
|
|
30
|
+
/** Options of the import popup: the panel's, plus what the window looks like. */
|
|
31
|
+
export interface OpenExcelImportOptions extends Omit<ExcelImportProps, "onClose"> {
|
|
32
|
+
/** The window's title. Default: "Import <subjects> from a spreadsheet". */
|
|
33
|
+
title?: ReactNode;
|
|
34
|
+
/** One popup per key. Default: the import endpoint's path, so one model opens one. */
|
|
35
|
+
popupKey?: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Opens the import panel as a window. This is the one line a data table's Import entry needs.
|
|
39
|
+
*
|
|
40
|
+
* @example onImport={() => openExcelImport({ endpoints: CITY_SHEET, subject: "city", onImported: reload })}
|
|
41
|
+
*/
|
|
42
|
+
export declare function openExcelImport({ title, popupKey, ...props }: OpenExcelImportOptions): PopupHandle;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { iconAlertTriangle, iconChevronDown, iconCircleCheck, iconCopy, iconDownload, iconFileImport, iconTable, iconUpload, InlineIcon } from "nexus-icons";
|
|
4
|
+
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
|
|
5
|
+
import { cx } from "../../Helpers/ClassHelpers.js";
|
|
6
|
+
import { EXCEL_FILE_ACCEPT, excelColumnInputs, excelCount, excelEditorRows, excelPlural, excelProblemPlace, excelProblems, excelRowsOfKind, excelSheetRows, excelText, excelWritableRows, isExcelRowEdited, } from "../../Helpers/ExcelHelpers.js";
|
|
7
|
+
import { ExcelRowKind } from "../../Interfaces/ExcelInterfaces.js";
|
|
8
|
+
import { downloadExcelTemplate, excelSettings, importExcelRows, verifyExcelFile } from "../../Services/ExcelApi.js";
|
|
9
|
+
import { toast } from "../Layouts/Toaster.js";
|
|
10
|
+
import { openPopup } from "../Layouts/PopupHost.js";
|
|
11
|
+
import { Button } from "../Documents/Button.js";
|
|
12
|
+
import { TabularForm } from "../Inputs/TabularForm.js";
|
|
13
|
+
const DEFAULT_MAX_HEIGHT = 320;
|
|
14
|
+
/**
|
|
15
|
+
* The three steps of an import in one panel: the template, the file, and the review.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* <ExcelImport endpoints={CITY_SHEET} subject="city" onImported={() => table.reload()} />
|
|
19
|
+
*/
|
|
20
|
+
export function ExcelImport({ endpoints, subject: given, params, onImported, onClose, templateDownload, maxHeight = DEFAULT_MAX_HEIGHT, className }) {
|
|
21
|
+
const id = useId();
|
|
22
|
+
const fileRef = useRef(null);
|
|
23
|
+
const newRef = useRef(null);
|
|
24
|
+
const sameRef = useRef(null);
|
|
25
|
+
const [settings, setSettings] = useState(null);
|
|
26
|
+
const [file, setFile] = useState(null);
|
|
27
|
+
const [verify, setVerify] = useState(null);
|
|
28
|
+
const [imported, setImported] = useState(null);
|
|
29
|
+
const [failure, setFailure] = useState(null);
|
|
30
|
+
const [busy, setBusy] = useState("settings");
|
|
31
|
+
/** Bumped on every answer: the editors take their rows again instead of being told to change them. */
|
|
32
|
+
const [generation, setGeneration] = useState(0);
|
|
33
|
+
// A page may well write its endpoints and its params as literals, which are a new object every render. What they
|
|
34
|
+
// say is what matters, so the settings are asked for again only when that changes.
|
|
35
|
+
const sheetKey = `${String(endpoints.settings.module)}|${endpoints.settings.path}|${JSON.stringify(params ?? null)}`;
|
|
36
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
37
|
+
const callOptions = useMemo(() => ({ params }), [sheetKey]);
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
let left = false;
|
|
40
|
+
void (async () => {
|
|
41
|
+
const answer = await excelSettings(endpoints, callOptions);
|
|
42
|
+
if (left)
|
|
43
|
+
return;
|
|
44
|
+
if (answer.ok && answer.result)
|
|
45
|
+
setSettings(answer.result);
|
|
46
|
+
setBusy(null);
|
|
47
|
+
})();
|
|
48
|
+
return () => {
|
|
49
|
+
left = true;
|
|
50
|
+
};
|
|
51
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
52
|
+
}, [sheetKey]);
|
|
53
|
+
const subject = given ?? verify?.subject ?? settings?.subject ?? "row";
|
|
54
|
+
const columns = verify?.columns ?? settings?.columns ?? [];
|
|
55
|
+
const inputs = useMemo(() => excelColumnInputs(columns), [columns]);
|
|
56
|
+
const fresh = useMemo(() => (verify ? excelWritableRows(verify.rows) : []), [verify]);
|
|
57
|
+
const same = useMemo(() => (verify ? excelRowsOfKind(verify.rows, ExcelRowKind.Duplicate) : []), [verify]);
|
|
58
|
+
const freshRows = useMemo(() => excelEditorRows(fresh, columns), [fresh, columns]);
|
|
59
|
+
const sameRows = useMemo(() => excelEditorRows(same, columns), [same, columns]);
|
|
60
|
+
function reset() {
|
|
61
|
+
setFile(null);
|
|
62
|
+
setVerify(null);
|
|
63
|
+
setImported(null);
|
|
64
|
+
setFailure(null);
|
|
65
|
+
setGeneration(value => value + 1);
|
|
66
|
+
if (fileRef.current)
|
|
67
|
+
fileRef.current.value = "";
|
|
68
|
+
}
|
|
69
|
+
async function onTemplate() {
|
|
70
|
+
setBusy("template");
|
|
71
|
+
await downloadExcelTemplate(endpoints, callOptions);
|
|
72
|
+
setBusy(null);
|
|
73
|
+
}
|
|
74
|
+
async function onPicked(picked) {
|
|
75
|
+
if (!picked)
|
|
76
|
+
return;
|
|
77
|
+
setFile(picked);
|
|
78
|
+
setVerify(null);
|
|
79
|
+
setImported(null);
|
|
80
|
+
setFailure(null);
|
|
81
|
+
setBusy("checking");
|
|
82
|
+
const answer = await verifyExcelFile(endpoints, picked, callOptions);
|
|
83
|
+
setBusy(null);
|
|
84
|
+
// Clearing the input is what lets the same file be picked again after a fix in the spreadsheet.
|
|
85
|
+
if (fileRef.current)
|
|
86
|
+
fileRef.current.value = "";
|
|
87
|
+
if (!answer.ok || !answer.result) {
|
|
88
|
+
setFailure(answer.message ?? excelText("verifyFailed"));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
setVerify(answer.result);
|
|
92
|
+
setGeneration(value => value + 1);
|
|
93
|
+
}
|
|
94
|
+
async function onImport() {
|
|
95
|
+
if (!verify)
|
|
96
|
+
return;
|
|
97
|
+
const newValues = newRef.current?.getValue() ?? freshRows;
|
|
98
|
+
const sameValues = sameRef.current?.getValue() ?? sameRows;
|
|
99
|
+
// A duplicate is never updated, so one the person left alone is not sent at all; one they edited is a new record.
|
|
100
|
+
const edited = sameValues.filter(row => isExcelRowEdited(row, columns));
|
|
101
|
+
if (newValues.length && newRef.current && !newRef.current.validate())
|
|
102
|
+
return;
|
|
103
|
+
if (edited.length && sameRef.current && !sameRef.current.validate())
|
|
104
|
+
return;
|
|
105
|
+
const rows = excelSheetRows([...newValues, ...edited], columns);
|
|
106
|
+
if (!rows.length) {
|
|
107
|
+
setFailure(excelText("importNothing"));
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
setBusy("importing");
|
|
111
|
+
const answer = await importExcelRows(endpoints, rows, callOptions);
|
|
112
|
+
setBusy(null);
|
|
113
|
+
if (!answer.ok) {
|
|
114
|
+
setFailure(answer.message ?? excelText("importedNone"));
|
|
115
|
+
if (answer.result)
|
|
116
|
+
setImported(answer.result);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
const written = answer.result;
|
|
120
|
+
if (!written)
|
|
121
|
+
return;
|
|
122
|
+
setFailure(null);
|
|
123
|
+
setImported(written);
|
|
124
|
+
toast.success(`${excelCount(written.created, subject)} imported`, { message: written.note });
|
|
125
|
+
// What was written is gone from the file's point of view: only what was refused stays to be fixed and sent again,
|
|
126
|
+
// and the counts are what those rows are now - not what the verify said about a file that has been half written.
|
|
127
|
+
const left = written.refused ?? [];
|
|
128
|
+
setVerify(current => current
|
|
129
|
+
? {
|
|
130
|
+
...current,
|
|
131
|
+
rows: left,
|
|
132
|
+
read: left.length,
|
|
133
|
+
new: left.filter(row => row.kind === ExcelRowKind.New).length,
|
|
134
|
+
duplicates: left.filter(row => row.kind === ExcelRowKind.Duplicate).length,
|
|
135
|
+
invalid: left.filter(row => row.kind === ExcelRowKind.Invalid).length,
|
|
136
|
+
isReady: false,
|
|
137
|
+
}
|
|
138
|
+
: current);
|
|
139
|
+
setGeneration(value => value + 1);
|
|
140
|
+
onImported?.(written);
|
|
141
|
+
}
|
|
142
|
+
/** A problem names a cell: clicking it brings that row into view and puts the caret in it. */
|
|
143
|
+
const goTo = (editor, list) => (problem) => {
|
|
144
|
+
const index = list.findIndex(row => row.number === problem.row);
|
|
145
|
+
if (index >= 0)
|
|
146
|
+
editor.current?.focusRow(index, problem.field);
|
|
147
|
+
};
|
|
148
|
+
const checking = busy === "checking";
|
|
149
|
+
const importing = busy === "importing";
|
|
150
|
+
const canImport = Boolean(verify) && !busy && (fresh.length > 0 || same.length > 0);
|
|
151
|
+
return (_jsxs("section", { className: cx("nx-excel", className), "aria-label": `Import ${excelPlural(subject)} from a spreadsheet`, "data-nx-excel": "", children: [_jsxs("ol", { className: "nx-excel__steps", children: [_jsxs("li", { children: ["Download the template", templateDownload === false ? "" : " below", ": every list in it is a dropdown, and the ids beside a choice fill themselves."] }), _jsxs("li", { children: ["Fill in one row per ", subject, ". Leave the locked columns alone."] }), _jsx("li", { children: "Send it here to be checked. Nothing is written until you import." })] }), _jsxs("div", { className: "nx-excel__pick", children: [templateDownload !== false && (_jsx(Button, { icon: _jsx(InlineIcon, { icon: iconDownload }), loading: busy === "template", onClick: onTemplate, children: excelText("template") })), _jsx("input", { ref: fileRef, id: `${id}-file`, className: "nx-visually-hidden", type: "file", accept: EXCEL_FILE_ACCEPT, onChange: event => void onPicked(event.currentTarget.files?.[0]) }), _jsx(Button, { variant: "primary", icon: _jsx(InlineIcon, { icon: iconFileImport }), loading: checking, onClick: () => fileRef.current?.click(), children: file ? excelText("change") : excelText("choose") }), _jsx("p", { className: "nx-excel__file", "data-nx-excel-file": "", children: checking ? (_jsxs(_Fragment, { children: [excelText("checking"), " ", _jsx("strong", { children: file?.name }), String.fromCharCode(8230)] })) : file ? (_jsx("strong", { children: file.name })) : (_jsx("span", { className: "nx-excel__muted", children: excelText("nothingPicked") })) }), settings && (_jsxs("p", { className: "nx-excel__limits", children: [excelCount(settings.maxImportRows, "row"), " at most per file"] }))] }), failure && (_jsxs("p", { className: "nx-excel__failure", role: "alert", "data-nx-excel-failure": "", children: [_jsx(InlineIcon, { icon: iconAlertTriangle, "aria-hidden": "true" }), _jsx("span", { children: failure })] })), imported && _jsx(ImportedReport, { answer: imported, subject: subject }), verify && (_jsxs("div", { className: "nx-excel__review", "data-nx-excel-review": "", children: [!imported && _jsx("p", { className: "nx-excel__note", children: verify.note }), _jsx(ReviewSection, { id: `${id}-new`, title: excelText("newRows"), tone: verify.invalid > 0 ? "warning" : "neutral", count: fresh.length, hint: verify.invalid > 0 ? `${excelCount(verify.invalid, "row")} to fix before anything is written.` : undefined, rows: fresh, onGo: goTo(newRef, fresh), open: true, children: _jsx(TabularForm, { ref: newRef, "aria-label": excelText("newRows"), inputs: inputs, itemLabel: subject, defaultValue: freshRows, addable: false, sortable: false, maxHeight: maxHeight, size: "sm" }, `new-${generation}`) }), _jsx(ReviewSection, { id: `${id}-same`, title: excelText("duplicates"), tone: "muted", count: same.length, hint: excelText("duplicateHint"), rows: same, onGo: goTo(sameRef, same), children: _jsx(TabularForm, { ref: sameRef, "aria-label": excelText("duplicates"), inputs: inputs, itemLabel: subject, defaultValue: sameRows, addable: false, removable: false, sortable: false, maxHeight: maxHeight, size: "sm" }, `same-${generation}`) })] })), _jsxs("footer", { className: "nx-excel__actions", children: [verify && (fresh.length > 0 || same.length > 0) && (_jsxs("p", { className: "nx-excel__sending", "data-nx-excel-sending": "", children: [fresh.length > 0 ? `${excelCount(fresh.length, subject)} to send.` : "Nothing to send yet.", same.length > 0 ? ` Edit ${same.length === 1 ? `the one ${subject}` : `one of the ${excelCount(same.length, subject)}`} already there to send it too.` : ""] })), _jsxs("div", { className: "nx-excel__buttons", children: [file && !busy && (_jsx(Button, { variant: "ghost", onClick: reset, children: excelText("startOver") })), onClose && (_jsx(Button, { variant: "secondary", onClick: onClose, children: excelText("close") })), _jsx(Button, { variant: "primary", icon: _jsx(InlineIcon, { icon: iconUpload }), loading: importing, disabled: !canImport, onClick: () => void onImport(), children: excelText("importLabel") })] })] })] }));
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* One half of the review: a line that says what these rows are and how many, and the editor under it. Collapsible,
|
|
155
|
+
* because a person with twenty duplicates and three new rows is looking at the three.
|
|
156
|
+
*/
|
|
157
|
+
function ReviewSection({ id, title, count, tone, hint, rows, onGo, open: openByDefault = false, children }) {
|
|
158
|
+
const [open, setOpen] = useState(openByDefault);
|
|
159
|
+
const problems = useMemo(() => excelProblems(rows), [rows]);
|
|
160
|
+
const duplicates = useMemo(() => rows.filter(row => row.duplicate), [rows]);
|
|
161
|
+
if (count === 0)
|
|
162
|
+
return null;
|
|
163
|
+
return (_jsxs("section", { className: "nx-excel__section", "data-open": open || undefined, "data-tone": tone, "data-nx-excel-section": title, children: [_jsx("h3", { className: "nx-excel__section-head", children: _jsxs("button", { type: "button", className: "nx-excel__toggle", "aria-expanded": open, "aria-controls": open ? id : undefined, onClick: () => setOpen(!open), children: [_jsx(InlineIcon, { icon: iconChevronDown, className: "nx-excel__chevron", "aria-hidden": "true" }), _jsx("span", { className: "nx-excel__title", children: title }), _jsx("span", { className: "nx-excel__tag", children: count.toLocaleString("en-US") }), hint && _jsx("span", { className: "nx-excel__hint", children: hint })] }) }), open && (_jsxs("div", { className: "nx-excel__section-body", id: id, children: [children, problems.length > 0 && _jsx(ProblemList, { problems: problems, onGo: onGo }), duplicates.length > 0 && (_jsxs("div", { className: "nx-excel__problems nx-excel__problems--same", "data-nx-excel-duplicates": "", children: [_jsxs("p", { className: "nx-excel__problems-head", children: [_jsx(InlineIcon, { icon: iconCopy, "aria-hidden": "true" }), _jsx("span", { children: excelText("whyDuplicate") })] }), _jsx("ul", { children: duplicates.map(row => (_jsxs("li", { children: [_jsxs("span", { className: "nx-excel__place", children: ["Row ", row.number] }), _jsx("span", { children: row.duplicate })] }, row.number))) })] }))] }))] }));
|
|
164
|
+
}
|
|
165
|
+
/** What the server found wrong, each naming the cell the person reads, and taking them to it. */
|
|
166
|
+
function ProblemList({ problems, onGo }) {
|
|
167
|
+
return (_jsxs("div", { className: "nx-excel__problems", "data-nx-excel-problems": "", children: [_jsxs("p", { className: "nx-excel__problems-head", children: [_jsx(InlineIcon, { icon: iconAlertTriangle, "aria-hidden": "true" }), _jsx("span", { children: excelText("toFix") })] }), _jsx("ul", { children: problems.map(problem => (_jsxs("li", { children: [onGo ? (_jsx("button", { type: "button", className: "nx-excel__place nx-excel__go", onClick: () => onGo(problem), children: excelProblemPlace(problem) })) : (_jsx("span", { className: "nx-excel__place", children: excelProblemPlace(problem) })), _jsx("span", { children: problem.message })] }, `${problem.row}:${problem.column}:${problem.message}`))) })] }));
|
|
168
|
+
}
|
|
169
|
+
/** What the import did, in the backend's own words, and what it did not write. */
|
|
170
|
+
function ImportedReport({ answer, subject }) {
|
|
171
|
+
const wrote = answer.created > 0;
|
|
172
|
+
return (_jsxs("div", { className: cx("nx-excel__result", wrote ? "nx-excel__result--ok" : "nx-excel__result--none"), role: "status", "data-nx-excel-result": "", children: [_jsxs("p", { className: "nx-excel__result-head", children: [_jsx(InlineIcon, { icon: wrote ? iconCircleCheck : iconAlertTriangle, "aria-hidden": "true" }), _jsx("strong", { children: wrote ? `${excelCount(answer.created, subject)} added` : excelText("importedNone") })] }), _jsx("p", { className: "nx-excel__result-note", children: answer.note }), (answer.refused?.length ?? 0) > 0 && (_jsx("ul", { className: "nx-excel__refused", children: answer.refused?.map(row => (_jsxs("li", { children: [_jsxs("span", { className: "nx-excel__place", children: ["Row ", row.number] }), _jsx("span", { children: row.duplicate ?? row.problems?.[0]?.message ?? excelText("refused") })] }, row.number))) }))] }));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Opens the import panel as a window. This is the one line a data table's Import entry needs.
|
|
176
|
+
*
|
|
177
|
+
* @example onImport={() => openExcelImport({ endpoints: CITY_SHEET, subject: "city", onImported: reload })}
|
|
178
|
+
*/
|
|
179
|
+
export function openExcelImport({ title, popupKey, ...props }) {
|
|
180
|
+
const subject = props.subject ?? "row";
|
|
181
|
+
return openPopup({
|
|
182
|
+
key: popupKey ?? `nx-excel:${String(props.endpoints.import.module)}:${props.endpoints.import.path}`,
|
|
183
|
+
title: title ?? `Import ${excelPlural(subject)} from a spreadsheet`,
|
|
184
|
+
icon: _jsx(InlineIcon, { icon: iconTable }),
|
|
185
|
+
size: "xl",
|
|
186
|
+
closeOnBackdrop: false,
|
|
187
|
+
// No Close of its own: the window's title bar already has one, and two ways out of one panel is one too many.
|
|
188
|
+
content: _jsx(ExcelImport, { ...props }),
|
|
189
|
+
});
|
|
190
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { FormStore, type AnyFormStore, type FormStatus } from "../../Helpers/FormStore.ts";
|
|
2
|
+
import type { DatePreferences } from "../../Interfaces/DateInterfaces.ts";
|
|
3
|
+
import type { FormProps, FormValues, InputParams } from "../../Interfaces/FormInterfaces.ts";
|
|
4
|
+
/**
|
|
5
|
+
* A form store for the page to hold: pass it to a form as `form`, then read, watch, set, and submit through it.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* const form = useForm<Employee>();
|
|
9
|
+
* const country = useFormValue<string>(form, "country");
|
|
10
|
+
* <SubmitForm form={form} inputs={inputs} onSubmit={save} />
|
|
11
|
+
*/
|
|
12
|
+
export declare function useForm<TValues extends FormValues = FormValues>(): FormStore<TValues>;
|
|
13
|
+
/** One value of a form; the component renders again only when it changes. */
|
|
14
|
+
export declare function useFormValue<T = unknown>(form: AnyFormStore, name: string): T;
|
|
15
|
+
/** Every value of a form; the component renders again on every change, so keep it to small forms or summaries. */
|
|
16
|
+
export declare function useFormValues<TValues extends FormValues>(form: FormStore<TValues>): TValues;
|
|
17
|
+
/** What the form's frame shows: changed, submitting, problems, the form's message, drafts. */
|
|
18
|
+
export declare function useFormStatus(form: AnyFormStore): FormStatus;
|
|
19
|
+
/** The form's own store, or the one given. */
|
|
20
|
+
export declare function useFormStore<TValues extends FormValues>(given: FormStore<TValues> | undefined): FormStore<TValues>;
|
|
21
|
+
/** An input's name in the form's messages: its `fieldName`, its label when it is text, or its name. */
|
|
22
|
+
export declare function formInputLabel(params: InputParams | undefined, name?: string): string;
|
|
23
|
+
/** The names a list shows: all of them up to one more than `most` ("and 1 more" says less than the name), else the first `most`. */
|
|
24
|
+
export declare function namesToShow<T>(names: readonly T[], most?: number): {
|
|
25
|
+
shown: readonly T[];
|
|
26
|
+
more: number;
|
|
27
|
+
};
|
|
28
|
+
/** Names in a sentence: "A", "A and B", "A, B, and C", "A, B, C, and 3 more". */
|
|
29
|
+
export declare function listInSentence(names: readonly string[], most?: number): string;
|
|
30
|
+
/** A moment in the user's time format, with the date in their calendar when it was not today. */
|
|
31
|
+
export declare function formatFormTime(ms: number, preferences: DatePreferences): string;
|
|
32
|
+
/**
|
|
33
|
+
* Renders a list of input params on a 12-column grid (`span` in each input's params), with the values in a store outside
|
|
34
|
+
* React, so a form of any size types as fast as one input. The same params describe every input, so a CRUD page or a
|
|
35
|
+
* server can build a form from plain objects; a tabular or group input is one entry that holds rows.
|
|
36
|
+
*
|
|
37
|
+
* On its own it suits filters and settings that save as they change (`onValueChange`). `SubmitForm` adds checks on
|
|
38
|
+
* submit and the buttons; `ApiForm` sends the values to a server. Inside a plain `<form>`, each input sends its value
|
|
39
|
+
* under its name, and the form's own rule blocks the submit while it fails.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* <Form
|
|
43
|
+
* inputs={[
|
|
44
|
+
* { type: "text", name: "fullName", label: "Full name", required: true, span: 6 },
|
|
45
|
+
* { type: "email", name: "email", label: "Email", span: 6 },
|
|
46
|
+
* { type: "dropdown", name: "role", label: "Role", options: roles, span: 4 },
|
|
47
|
+
* ]}
|
|
48
|
+
* defaultValue={employee}
|
|
49
|
+
* onValueChange={values => saveFilters(values)}
|
|
50
|
+
* />
|
|
51
|
+
*/
|
|
52
|
+
export declare function Form<TValues extends FormValues = FormValues>(props: FormProps<TValues>): import("react").JSX.Element;
|