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,290 @@
|
|
|
1
|
+
import { readApiResponse } from "./ApiResponses.js";
|
|
2
|
+
import { ExcelRowKind } from "../Interfaces/ExcelInterfaces.js";
|
|
3
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
const text = (value) => {
|
|
5
|
+
if (value === undefined || value === null)
|
|
6
|
+
return null;
|
|
7
|
+
const written = String(value).trim();
|
|
8
|
+
return written.length ? written : null;
|
|
9
|
+
};
|
|
10
|
+
const count = (value, fallback = 0) => {
|
|
11
|
+
const number = Number(value);
|
|
12
|
+
return Number.isFinite(number) ? number : fallback;
|
|
13
|
+
};
|
|
14
|
+
/** The actions of a Nexus Excel controller, as the backend names them (`NexusExcelController`). */
|
|
15
|
+
export const EXCEL_ACTIONS = {
|
|
16
|
+
settings: "Excel/Settings",
|
|
17
|
+
template: "Excel/Template",
|
|
18
|
+
verify: "Excel/Verify",
|
|
19
|
+
import: "Excel/Import",
|
|
20
|
+
/** The model's own action, which the two controller bases leave to it. */
|
|
21
|
+
export: "Excel/Export",
|
|
22
|
+
};
|
|
23
|
+
const at = (controller, action) => `${controller}/${action}`;
|
|
24
|
+
/**
|
|
25
|
+
* The spreadsheet endpoints of a Nexus controller, named as the backend names them: `Excel/Settings`,
|
|
26
|
+
* `Excel/Template`, `Excel/Verify`, `Excel/Import`, and the model's own `Excel/Export`.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* export const CITIES = MODULES.controller(NexusModule.Configuration, "City", "city");
|
|
30
|
+
* export const CITY_SHEET = excelEndpoints(CITIES, { subject: "city" });
|
|
31
|
+
*/
|
|
32
|
+
export function excelEndpoints(controller, options = {}) {
|
|
33
|
+
const { module, controller: name } = controller;
|
|
34
|
+
const subject = options.subject;
|
|
35
|
+
const endpoint = (method, action, extras) => ({ module, path: at(name, action), method, ...(subject && { subject }), ...extras });
|
|
36
|
+
const [exportMethod, exportAction] = Array.isArray(options.exportAction) ? options.exportAction : ["POST", options.exportAction ?? EXCEL_ACTIONS.export];
|
|
37
|
+
return {
|
|
38
|
+
settings: endpoint("GET", EXCEL_ACTIONS.settings, { action: "load" }),
|
|
39
|
+
template: endpoint("GET", EXCEL_ACTIONS.template, { action: "download" }),
|
|
40
|
+
verify: endpoint("POST", EXCEL_ACTIONS.verify, { action: "upload", bodyType: "form-data" }),
|
|
41
|
+
import: endpoint("POST", EXCEL_ACTIONS.import, { action: "import" }),
|
|
42
|
+
...(options.exportable === false ? {} : { export: endpoint(exportMethod, exportAction, { action: "export" }) }),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export class ExcelBackend {
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* The Nexus backend. The four calls sit under one controller; an import sends `{ rows }`; an export sends the list
|
|
49
|
+
* request a Nexus pagination takes, without its paging, because an export is not a page; a download says what it came
|
|
50
|
+
* to in `X-Nexus-Export-*` headers.
|
|
51
|
+
*/
|
|
52
|
+
export class NexusExcelBackend extends ExcelBackend {
|
|
53
|
+
get uploadField() {
|
|
54
|
+
return "file";
|
|
55
|
+
}
|
|
56
|
+
importRequest(rows) {
|
|
57
|
+
return { rows };
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* The same request a Nexus listing takes, minus `skipCount` and `maxCount`: an export writes every row the search
|
|
61
|
+
* leaves, up to the backend's own limit, not the page the person happens to be on. With nothing sorted it follows
|
|
62
|
+
* the list's own order, newest first.
|
|
63
|
+
*/
|
|
64
|
+
exportRequest(query) {
|
|
65
|
+
return {
|
|
66
|
+
...query.filters,
|
|
67
|
+
searchKeyword: text(query.search) ?? undefined,
|
|
68
|
+
sorting: text(query.sort) ?? "creationTime",
|
|
69
|
+
sortType: query.direction ?? (query.sort ? "asc" : "desc"),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
readSettings(result) {
|
|
73
|
+
const answer = isRecord(result) ? result : {};
|
|
74
|
+
return {
|
|
75
|
+
subject: text(answer.subject) ?? "row",
|
|
76
|
+
templateFileName: text(answer.templateFileName) ?? undefined,
|
|
77
|
+
sheetRows: answer.sheetRows === undefined ? undefined : count(answer.sheetRows),
|
|
78
|
+
maxExportRows: count(answer.maxExportRows, DEFAULT_MAX_EXPORT_ROWS),
|
|
79
|
+
maxImportRows: count(answer.maxImportRows, DEFAULT_MAX_IMPORT_ROWS),
|
|
80
|
+
columns: readColumns(answer.columns),
|
|
81
|
+
inputs: Array.isArray(answer.inputs) ? answer.inputs : [],
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
readVerify(result) {
|
|
85
|
+
const answer = isRecord(result) ? result : {};
|
|
86
|
+
const rows = readRows(answer.rows);
|
|
87
|
+
const kinds = (kind) => rows.filter(row => row.kind === kind).length;
|
|
88
|
+
const read = count(answer.read, rows.length);
|
|
89
|
+
const fresh = answer.new === undefined ? kinds(ExcelRowKind.New) : count(answer.new);
|
|
90
|
+
const invalid = answer.invalid === undefined ? kinds(ExcelRowKind.Invalid) : count(answer.invalid);
|
|
91
|
+
return {
|
|
92
|
+
subject: text(answer.subject) ?? "row",
|
|
93
|
+
read,
|
|
94
|
+
new: fresh,
|
|
95
|
+
duplicates: answer.duplicates === undefined ? kinds(ExcelRowKind.Duplicate) : count(answer.duplicates),
|
|
96
|
+
invalid,
|
|
97
|
+
isReady: typeof answer.isReady === "boolean" ? answer.isReady : invalid === 0 && fresh > 0,
|
|
98
|
+
note: text(answer.note) ?? "",
|
|
99
|
+
columns: readColumns(answer.columns),
|
|
100
|
+
rows,
|
|
101
|
+
inputs: Array.isArray(answer.inputs) ? answer.inputs : [],
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
readImport(result) {
|
|
105
|
+
const answer = isRecord(result) ? result : {};
|
|
106
|
+
return {
|
|
107
|
+
sent: count(answer.sent),
|
|
108
|
+
created: count(answer.created),
|
|
109
|
+
duplicates: count(answer.duplicates),
|
|
110
|
+
invalid: count(answer.invalid),
|
|
111
|
+
refused: readRows(answer.refused),
|
|
112
|
+
note: text(answer.note) ?? "",
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
get downloadHeaders() {
|
|
116
|
+
return NEXUS_DOWNLOAD_HEADERS;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** The most rows one export writes when the backend does not say (`Nexus:Excel:MaxExportRows`). */
|
|
120
|
+
export const DEFAULT_MAX_EXPORT_ROWS = 5000;
|
|
121
|
+
/** The most rows one import takes when the backend does not say (`Nexus:Excel:MaxImportRows`). */
|
|
122
|
+
export const DEFAULT_MAX_IMPORT_ROWS = 2000;
|
|
123
|
+
/** What a Nexus download says about itself (`Excels/ExcelHeaders.cs`), all of them exposed by the CORS policy. */
|
|
124
|
+
export const NEXUS_DOWNLOAD_HEADERS = {
|
|
125
|
+
rows: "X-Nexus-Export-Rows",
|
|
126
|
+
skipped: "X-Nexus-Export-Skipped",
|
|
127
|
+
limit: "X-Nexus-Export-Limit",
|
|
128
|
+
note: "X-Nexus-Export-Note",
|
|
129
|
+
};
|
|
130
|
+
function readColumns(value) {
|
|
131
|
+
if (!Array.isArray(value))
|
|
132
|
+
return [];
|
|
133
|
+
const columns = [];
|
|
134
|
+
for (const item of value) {
|
|
135
|
+
if (!isRecord(item))
|
|
136
|
+
continue;
|
|
137
|
+
const field = text(item.field);
|
|
138
|
+
if (!field)
|
|
139
|
+
continue;
|
|
140
|
+
columns.push({
|
|
141
|
+
field,
|
|
142
|
+
header: text(item.header) ?? field,
|
|
143
|
+
dataType: count(item.dataType),
|
|
144
|
+
isRequired: item.isRequired === true,
|
|
145
|
+
isReadOnly: item.isReadOnly === true,
|
|
146
|
+
isReference: item.isReference === true,
|
|
147
|
+
list: text(item.list),
|
|
148
|
+
minLength: count(item.minLength),
|
|
149
|
+
maxLength: count(item.maxLength),
|
|
150
|
+
minimum: item.minimum === undefined || item.minimum === null ? null : count(item.minimum),
|
|
151
|
+
maximum: item.maximum === undefined || item.maximum === null ? null : count(item.maximum),
|
|
152
|
+
note: text(item.note),
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return columns;
|
|
156
|
+
}
|
|
157
|
+
/** A dictionary of texts: every value as text, so nothing read out of an answer can be sent back as a number or an id. */
|
|
158
|
+
function readValues(value) {
|
|
159
|
+
const values = {};
|
|
160
|
+
if (!isRecord(value))
|
|
161
|
+
return values;
|
|
162
|
+
for (const [key, item] of Object.entries(value))
|
|
163
|
+
values[key] = text(item);
|
|
164
|
+
return values;
|
|
165
|
+
}
|
|
166
|
+
function readProblems(value) {
|
|
167
|
+
if (!Array.isArray(value))
|
|
168
|
+
return [];
|
|
169
|
+
const problems = [];
|
|
170
|
+
for (const item of value) {
|
|
171
|
+
if (!isRecord(item))
|
|
172
|
+
continue;
|
|
173
|
+
problems.push({
|
|
174
|
+
row: count(item.row),
|
|
175
|
+
column: count(item.column),
|
|
176
|
+
cell: text(item.cell) ?? "",
|
|
177
|
+
header: text(item.header) ?? "",
|
|
178
|
+
field: text(item.field) ?? "",
|
|
179
|
+
message: text(item.message) ?? "",
|
|
180
|
+
messageCode: text(item.messageCode) ?? undefined,
|
|
181
|
+
errorCode: item.errorCode === undefined ? undefined : count(item.errorCode),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return problems;
|
|
185
|
+
}
|
|
186
|
+
function readRows(value) {
|
|
187
|
+
if (!Array.isArray(value))
|
|
188
|
+
return [];
|
|
189
|
+
const rows = [];
|
|
190
|
+
for (const [index, item] of value.entries()) {
|
|
191
|
+
if (!isRecord(item))
|
|
192
|
+
continue;
|
|
193
|
+
const problems = readProblems(item.problems);
|
|
194
|
+
const kind = item.kind === undefined ? (problems.length ? ExcelRowKind.Invalid : ExcelRowKind.New) : count(item.kind);
|
|
195
|
+
rows.push({
|
|
196
|
+
number: count(item.number, index + 1),
|
|
197
|
+
kind,
|
|
198
|
+
values: readValues(item.values),
|
|
199
|
+
labels: readValues(item.labels),
|
|
200
|
+
problems,
|
|
201
|
+
duplicate: text(item.duplicate),
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return rows;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Reads an answer whose problems are in `errorMessages`, which is how the backend answers a refusal now: nothing at the
|
|
208
|
+
* top level, and one entry per wrong field (`{ message, messageCode, errorCode, inputName }`) so every one of them is
|
|
209
|
+
* told at once. The first entry words the answer, and each entry that names an input lands on that input.
|
|
210
|
+
*
|
|
211
|
+
* Anything else - a success, a backend of another shape, problem details, a proxy answering while the service is down -
|
|
212
|
+
* goes to `readApiResponse`, which is also the default for every call that does not name a reader. It is used here
|
|
213
|
+
* because a spreadsheet's refusals are the whole point of the review: "no row could be written" has to reach the person
|
|
214
|
+
* in the backend's own words, not as a generic sentence.
|
|
215
|
+
*/
|
|
216
|
+
export function readExcelResponse(body, status) {
|
|
217
|
+
if (isRecord(body) && body.isSuccess !== true) {
|
|
218
|
+
const list = Array.isArray(body.errorMessages) ? body.errorMessages : isRecord(body.errorMessages) ? [body.errorMessages] : [];
|
|
219
|
+
const problems = list.filter(isRecord);
|
|
220
|
+
if (problems.length) {
|
|
221
|
+
const first = problems[0];
|
|
222
|
+
const errors = {};
|
|
223
|
+
for (const problem of problems) {
|
|
224
|
+
const input = text(problem.inputName);
|
|
225
|
+
const message = text(problem.message);
|
|
226
|
+
if (input && message && !(input in errors))
|
|
227
|
+
errors[input] = message;
|
|
228
|
+
}
|
|
229
|
+
return {
|
|
230
|
+
ok: false,
|
|
231
|
+
status: status ?? (typeof body.code === "number" ? body.code : undefined),
|
|
232
|
+
message: text(first.message) ?? undefined,
|
|
233
|
+
messageCode: text(first.messageCode) ?? undefined,
|
|
234
|
+
errorCode: first.errorCode === undefined ? undefined : count(first.errorCode),
|
|
235
|
+
...(Object.keys(errors).length ? { errors } : {}),
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
return readApiResponse(body, status);
|
|
240
|
+
}
|
|
241
|
+
let current = null;
|
|
242
|
+
/** Registers the app's spreadsheet conventions, once, beside its API modules. */
|
|
243
|
+
export function defineExcelBackend(backend) {
|
|
244
|
+
current = backend;
|
|
245
|
+
return backend;
|
|
246
|
+
}
|
|
247
|
+
/** The registered spreadsheet conventions, or the Nexus ones. */
|
|
248
|
+
export function getExcelBackend() {
|
|
249
|
+
return (current ??= new NexusExcelBackend());
|
|
250
|
+
}
|
|
251
|
+
/** The file name out of a `Content-Disposition`, `filename*` first (it carries the encoding) and `filename` after. */
|
|
252
|
+
export function readFileName(disposition) {
|
|
253
|
+
if (!disposition)
|
|
254
|
+
return undefined;
|
|
255
|
+
const encoded = /filename\*\s*=\s*([^;]+)/i.exec(disposition)?.[1]?.trim();
|
|
256
|
+
if (encoded) {
|
|
257
|
+
const parts = encoded.split("'");
|
|
258
|
+
const value = (parts.length >= 3 ? parts.slice(2).join("'") : encoded).trim();
|
|
259
|
+
try {
|
|
260
|
+
const name = decodeURIComponent(value.replace(/^"|"$/g, ""));
|
|
261
|
+
if (name)
|
|
262
|
+
return name;
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// A name that is not valid percent-encoding: fall through to the plain one.
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const plain = /filename\s*=\s*("([^"]*)"|[^;]+)/i.exec(disposition);
|
|
269
|
+
const name = (plain?.[2] ?? plain?.[1] ?? "").trim();
|
|
270
|
+
return name.length ? name : undefined;
|
|
271
|
+
}
|
|
272
|
+
/** What a download answered, as its own headers tell it. */
|
|
273
|
+
export function readDownloadHeaders(headers, blob, fallbackName) {
|
|
274
|
+
const names = getExcelBackend().downloadHeaders;
|
|
275
|
+
const number = (name) => {
|
|
276
|
+
const value = headers.get(name);
|
|
277
|
+
if (value === null)
|
|
278
|
+
return undefined;
|
|
279
|
+
const read = Number(value);
|
|
280
|
+
return Number.isFinite(read) ? read : undefined;
|
|
281
|
+
};
|
|
282
|
+
return {
|
|
283
|
+
blob,
|
|
284
|
+
fileName: readFileName(headers.get("Content-Disposition")) ?? fallbackName,
|
|
285
|
+
rows: number(names.rows),
|
|
286
|
+
skipped: number(names.skipped),
|
|
287
|
+
limit: number(names.limit),
|
|
288
|
+
note: text(headers.get(names.note)) ?? undefined,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { InputParams } from "../Interfaces/FormInterfaces.ts";
|
|
2
|
+
import type { ExcelCellProblem, ExcelColumnInfo, ExcelDownload, ExcelReviewRow, ExcelSheetRow } from "../Interfaces/ExcelInterfaces.ts";
|
|
3
|
+
/** What a spreadsheet file is called in a file picker. */
|
|
4
|
+
export declare const EXCEL_FILE_ACCEPT = ".xlsx,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
|
5
|
+
/** The field of an editor row that holds the sheet row it came from. Not a column, so no input is drawn for it. */
|
|
6
|
+
export declare const EXCEL_ROW_NUMBER = "__excelRow";
|
|
7
|
+
/** The field of an editor row that holds each reference column's key, which the person never sees or types. */
|
|
8
|
+
export declare const EXCEL_ROW_KEYS = "__excelKeys";
|
|
9
|
+
/** The field of an editor row that holds what the verify answered for it, so an edit can be told from an untouched row. */
|
|
10
|
+
export declare const EXCEL_ROW_SENT = "__excelSent";
|
|
11
|
+
/** One row of a review editor: a value per column, plus the three fields the editor carries for itself. */
|
|
12
|
+
export interface ExcelEditorRow {
|
|
13
|
+
[EXCEL_ROW_NUMBER]: number;
|
|
14
|
+
[EXCEL_ROW_KEYS]: Record<string, string | null>;
|
|
15
|
+
[EXCEL_ROW_SENT]: Record<string, string | null>;
|
|
16
|
+
[field: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
declare const DEFAULT_TEXT: {
|
|
19
|
+
readonly template: "Download template";
|
|
20
|
+
readonly templateHint: "The file to fill in: every list is a dropdown, and the ids beside a choice fill themselves.";
|
|
21
|
+
readonly choose: "Choose file";
|
|
22
|
+
readonly change: "Choose another file";
|
|
23
|
+
readonly checking: "Checking";
|
|
24
|
+
readonly nothingPicked: "No file picked yet.";
|
|
25
|
+
readonly verifyFailed: "The file could not be read.";
|
|
26
|
+
readonly newRows: "New rows";
|
|
27
|
+
readonly duplicates: "Already there";
|
|
28
|
+
readonly duplicateHint: "Nothing here is updated. Edit a row to add it as a new record instead.";
|
|
29
|
+
readonly toFix: "What needs fixing";
|
|
30
|
+
readonly whyDuplicate: "Why these are already there";
|
|
31
|
+
readonly referenceLocked: "Picked in the spreadsheet: this list belongs to the server.";
|
|
32
|
+
readonly generated: "The file fills this in.";
|
|
33
|
+
readonly importLabel: "Import";
|
|
34
|
+
readonly importNothing: "There is no row to import.";
|
|
35
|
+
readonly importedNone: "Nothing was written.";
|
|
36
|
+
readonly refused: "Not written";
|
|
37
|
+
readonly exportWarning: "Export is cut short";
|
|
38
|
+
readonly close: "Close";
|
|
39
|
+
readonly startOver: "Start over";
|
|
40
|
+
};
|
|
41
|
+
export type ExcelTextKey = keyof typeof DEFAULT_TEXT;
|
|
42
|
+
/** Rewords or translates the spreadsheet side's own texts. Names only what changes. */
|
|
43
|
+
export declare function configureExcelText(changes: Partial<Record<ExcelTextKey, string>>): void;
|
|
44
|
+
/** One of the spreadsheet side's texts. */
|
|
45
|
+
export declare function excelText(key: ExcelTextKey): string;
|
|
46
|
+
/**
|
|
47
|
+
* One column of a sheet as an input of the review editors. The rules are the ones the sheet told the person about and
|
|
48
|
+
* no others, so a fix made here is checked the way the file was.
|
|
49
|
+
*
|
|
50
|
+
* Three columns are read-only on purpose:
|
|
51
|
+
* - a **reference**, because its list is the backend's and is picked in the spreadsheet; the cell shows the words the
|
|
52
|
+
* person picked and the key travels back untouched (a key read out of an answer is never typed, and never an id);
|
|
53
|
+
* - a column the **file** fills;
|
|
54
|
+
* - and a **date and time** is a text box rather than a picker, because the sheet's moment is a zone-less wall clock
|
|
55
|
+
* while the picker's value is a UTC moment: a picker here would shift every value by the person's own offset.
|
|
56
|
+
*/
|
|
57
|
+
export declare function excelColumnInput(column: ExcelColumnInfo): InputParams;
|
|
58
|
+
/** Every column of a sheet as the inputs of one editor row, in the order they read. */
|
|
59
|
+
export declare function excelColumnInputs(columns: readonly ExcelColumnInfo[]): InputParams[];
|
|
60
|
+
/** Whether the person edits this column's cell at all, or only reads it. */
|
|
61
|
+
export declare function isExcelColumnEditable(column: ExcelColumnInfo): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* A verify's rows as the editors' rows: a value per column, the sheet's row number, and - held beside them, never
|
|
64
|
+
* drawn - each reference column's key and the values the verify answered with.
|
|
65
|
+
*
|
|
66
|
+
* A reference cell shows the **words** the person picked, because its key is not something anybody reads or types.
|
|
67
|
+
*/
|
|
68
|
+
export declare function excelEditorRows(rows: readonly ExcelReviewRow[], columns: readonly ExcelColumnInfo[]): ExcelEditorRow[];
|
|
69
|
+
/**
|
|
70
|
+
* The editors' rows as rows to send: every value as text, every reference as the key it came with, and the sheet's own
|
|
71
|
+
* row number kept so a problem can still name where it is.
|
|
72
|
+
*
|
|
73
|
+
* A cell the person did not touch goes back **exactly** as it came, which is what makes the round trip faithful: the
|
|
74
|
+
* backend reads its own text again, not a number an input rewrote on the way through.
|
|
75
|
+
*/
|
|
76
|
+
export declare function excelSheetRows(rows: readonly ExcelEditorRow[], columns: readonly ExcelColumnInfo[]): ExcelSheetRow[];
|
|
77
|
+
/** Whether the person changed anything in a row since the verify answered it. */
|
|
78
|
+
export declare function isExcelRowEdited(row: ExcelEditorRow, columns: readonly ExcelColumnInfo[]): boolean;
|
|
79
|
+
/** Where a problem is, as the person reads it: the cell, a middle dot, and the column's heading ("B7 - City name"). */
|
|
80
|
+
export declare function excelProblemPlace(problem: ExcelCellProblem): string;
|
|
81
|
+
/** Every problem of these rows, in the order the rows read. */
|
|
82
|
+
export declare function excelProblems(rows: readonly ExcelReviewRow[]): ExcelCellProblem[];
|
|
83
|
+
/** The rows of one kind. */
|
|
84
|
+
export declare function excelRowsOfKind(rows: readonly ExcelReviewRow[], ...kinds: readonly number[]): ExcelReviewRow[];
|
|
85
|
+
/** The rows an import would try to write: the new ones, and the ones still waiting on a fix. */
|
|
86
|
+
export declare function excelWritableRows(rows: readonly ExcelReviewRow[]): ExcelReviewRow[];
|
|
87
|
+
/** More than one of the subject: "cities", "boxes", "rows". An English ending, which a text change can replace. */
|
|
88
|
+
export declare function excelPlural(subject: string, plural?: string): string;
|
|
89
|
+
/** A count said in the subject's own words: "1 city", "12 cities". */
|
|
90
|
+
export declare function excelCount(rows: number, subject: string, plural?: string): string;
|
|
91
|
+
/**
|
|
92
|
+
* What to tell the person before an export that will be cut short, as the owner asked: what is on screen, what will be
|
|
93
|
+
* written, and that filtering is how they get the rest.
|
|
94
|
+
*/
|
|
95
|
+
export declare function excelExportWarning(rows: number, limit: number, subject: string): string;
|
|
96
|
+
/** Hands the person a file to save, under the name the answer gave it. */
|
|
97
|
+
export declare function saveExcelFile(download: ExcelDownload): void;
|
|
98
|
+
export {};
|