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.
Files changed (376) hide show
  1. package/CHANGELOG.md +262 -0
  2. package/LICENSE +21 -0
  3. package/README.md +1000 -0
  4. package/dist/Client.Index.d.ts +55 -0
  5. package/dist/Client.Index.js +60 -0
  6. package/dist/Components/Chats/Chat.d.ts +28 -0
  7. package/dist/Components/Chats/Chat.js +19 -0
  8. package/dist/Components/Chats/ChatButton.d.ts +26 -0
  9. package/dist/Components/Chats/ChatButton.js +41 -0
  10. package/dist/Components/Chats/ChatComposer.d.ts +41 -0
  11. package/dist/Components/Chats/ChatComposer.js +177 -0
  12. package/dist/Components/Chats/ChatConversations.d.ts +35 -0
  13. package/dist/Components/Chats/ChatConversations.js +38 -0
  14. package/dist/Components/Chats/ChatPanel.d.ts +66 -0
  15. package/dist/Components/Chats/ChatPanel.js +94 -0
  16. package/dist/Components/Chats/ChatParts.d.ts +87 -0
  17. package/dist/Components/Chats/ChatParts.js +100 -0
  18. package/dist/Components/Chats/ChatThread.d.ts +22 -0
  19. package/dist/Components/Chats/ChatThread.js +96 -0
  20. package/dist/Components/Documents/Button.d.ts +29 -0
  21. package/dist/Components/Documents/Button.js +11 -0
  22. package/dist/Components/Documents/Menu.d.ts +102 -0
  23. package/dist/Components/Documents/Menu.js +242 -0
  24. package/dist/Components/Documents/SplitButton.d.ts +64 -0
  25. package/dist/Components/Documents/SplitButton.js +129 -0
  26. package/dist/Components/Documents/TabButtons.d.ts +80 -0
  27. package/dist/Components/Documents/TabButtons.js +38 -0
  28. package/dist/Components/Forms/ApiForm.d.ts +23 -0
  29. package/dist/Components/Forms/ApiForm.js +100 -0
  30. package/dist/Components/Forms/Crud.d.ts +17 -0
  31. package/dist/Components/Forms/Crud.js +708 -0
  32. package/dist/Components/Forms/CrudParts.d.ts +15 -0
  33. package/dist/Components/Forms/CrudParts.js +36 -0
  34. package/dist/Components/Forms/ExcelImport.d.ts +42 -0
  35. package/dist/Components/Forms/ExcelImport.js +190 -0
  36. package/dist/Components/Forms/Form.d.ts +52 -0
  37. package/dist/Components/Forms/Form.js +323 -0
  38. package/dist/Components/Forms/SubmitForm.d.ts +65 -0
  39. package/dist/Components/Forms/SubmitForm.js +198 -0
  40. package/dist/Components/Inputs/Calendar.d.ts +69 -0
  41. package/dist/Components/Inputs/Calendar.js +258 -0
  42. package/dist/Components/Inputs/CheckBox.d.ts +53 -0
  43. package/dist/Components/Inputs/CheckBox.js +87 -0
  44. package/dist/Components/Inputs/CheckBoxGroup.d.ts +20 -0
  45. package/dist/Components/Inputs/CheckBoxGroup.js +80 -0
  46. package/dist/Components/Inputs/ChoiceField.d.ts +122 -0
  47. package/dist/Components/Inputs/ChoiceField.js +169 -0
  48. package/dist/Components/Inputs/DatePicker.d.ts +54 -0
  49. package/dist/Components/Inputs/DatePicker.js +246 -0
  50. package/dist/Components/Inputs/DateRangePicker.d.ts +62 -0
  51. package/dist/Components/Inputs/DateRangePicker.js +283 -0
  52. package/dist/Components/Inputs/DateTimePicker.d.ts +75 -0
  53. package/dist/Components/Inputs/DateTimePicker.js +400 -0
  54. package/dist/Components/Inputs/Dropdown.d.ts +117 -0
  55. package/dist/Components/Inputs/Dropdown.js +839 -0
  56. package/dist/Components/Inputs/DropdownParts.d.ts +84 -0
  57. package/dist/Components/Inputs/DropdownParts.js +102 -0
  58. package/dist/Components/Inputs/EditorShell.d.ts +45 -0
  59. package/dist/Components/Inputs/EditorShell.js +214 -0
  60. package/dist/Components/Inputs/Field.d.ts +53 -0
  61. package/dist/Components/Inputs/Field.js +16 -0
  62. package/dist/Components/Inputs/GroupForm.d.ts +20 -0
  63. package/dist/Components/Inputs/GroupForm.js +172 -0
  64. package/dist/Components/Inputs/InputField.d.ts +59 -0
  65. package/dist/Components/Inputs/InputField.js +169 -0
  66. package/dist/Components/Inputs/InputRenderer.d.ts +37 -0
  67. package/dist/Components/Inputs/InputRenderer.js +99 -0
  68. package/dist/Components/Inputs/MarkdownEditor.d.ts +67 -0
  69. package/dist/Components/Inputs/MarkdownEditor.js +289 -0
  70. package/dist/Components/Inputs/NumberBox.d.ts +53 -0
  71. package/dist/Components/Inputs/NumberBox.js +228 -0
  72. package/dist/Components/Inputs/RadioGroup.d.ts +20 -0
  73. package/dist/Components/Inputs/RadioGroup.js +43 -0
  74. package/dist/Components/Inputs/ReadOnlyNotice.d.ts +36 -0
  75. package/dist/Components/Inputs/ReadOnlyNotice.js +117 -0
  76. package/dist/Components/Inputs/RichTextEditor.d.ts +103 -0
  77. package/dist/Components/Inputs/RichTextEditor.js +1170 -0
  78. package/dist/Components/Inputs/RichTextParts.d.ts +63 -0
  79. package/dist/Components/Inputs/RichTextParts.js +157 -0
  80. package/dist/Components/Inputs/RowsInput.d.ts +115 -0
  81. package/dist/Components/Inputs/RowsInput.js +308 -0
  82. package/dist/Components/Inputs/Slider.d.ts +87 -0
  83. package/dist/Components/Inputs/Slider.js +216 -0
  84. package/dist/Components/Inputs/TabularForm.d.ts +27 -0
  85. package/dist/Components/Inputs/TabularForm.js +348 -0
  86. package/dist/Components/Inputs/TextArea.d.ts +43 -0
  87. package/dist/Components/Inputs/TextArea.js +31 -0
  88. package/dist/Components/Inputs/TextBox.d.ts +52 -0
  89. package/dist/Components/Inputs/TextBox.js +58 -0
  90. package/dist/Components/Inputs/TextField.d.ts +31 -0
  91. package/dist/Components/Inputs/TextField.js +35 -0
  92. package/dist/Components/Inputs/TimePanel.d.ts +34 -0
  93. package/dist/Components/Inputs/TimePanel.js +288 -0
  94. package/dist/Components/Inputs/TimePicker.d.ts +54 -0
  95. package/dist/Components/Inputs/TimePicker.js +240 -0
  96. package/dist/Components/Inputs/TreeView.d.ts +160 -0
  97. package/dist/Components/Inputs/TreeView.js +947 -0
  98. package/dist/Components/Layouts/MessageBox.d.ts +71 -0
  99. package/dist/Components/Layouts/MessageBox.js +104 -0
  100. package/dist/Components/Layouts/Popup.d.ts +92 -0
  101. package/dist/Components/Layouts/Popup.js +376 -0
  102. package/dist/Components/Layouts/PopupContext.d.ts +2 -0
  103. package/dist/Components/Layouts/PopupContext.js +4 -0
  104. package/dist/Components/Layouts/PopupDock.d.ts +22 -0
  105. package/dist/Components/Layouts/PopupDock.js +121 -0
  106. package/dist/Components/Layouts/PopupHost.d.ts +56 -0
  107. package/dist/Components/Layouts/PopupHost.js +163 -0
  108. package/dist/Components/Layouts/PopupRules.d.ts +30 -0
  109. package/dist/Components/Layouts/PopupRules.js +63 -0
  110. package/dist/Components/Layouts/ThemePicker.d.ts +13 -0
  111. package/dist/Components/Layouts/ThemePicker.js +22 -0
  112. package/dist/Components/Layouts/ThemeScript.d.ts +14 -0
  113. package/dist/Components/Layouts/ThemeScript.js +13 -0
  114. package/dist/Components/Layouts/ThemeSwitcher.d.ts +13 -0
  115. package/dist/Components/Layouts/ThemeSwitcher.js +49 -0
  116. package/dist/Components/Layouts/Toaster.d.ts +76 -0
  117. package/dist/Components/Layouts/Toaster.js +172 -0
  118. package/dist/Components/Viewers/DataTable.d.ts +25 -0
  119. package/dist/Components/Viewers/DataTable.js +596 -0
  120. package/dist/Components/Viewers/DataTableColumns.d.ts +28 -0
  121. package/dist/Components/Viewers/DataTableColumns.js +243 -0
  122. package/dist/Components/Viewers/DataTableParts.d.ts +138 -0
  123. package/dist/Components/Viewers/DataTableParts.js +157 -0
  124. package/dist/Components/Viewers/MarkdownView.d.ts +26 -0
  125. package/dist/Components/Viewers/MarkdownView.js +79 -0
  126. package/dist/Components/Viewers/RichTextView.d.ts +18 -0
  127. package/dist/Components/Viewers/RichTextView.js +17 -0
  128. package/dist/Helpers/AnimationHelpers.d.ts +6 -0
  129. package/dist/Helpers/AnimationHelpers.js +35 -0
  130. package/dist/Helpers/ApiClient.d.ts +96 -0
  131. package/dist/Helpers/ApiClient.js +200 -0
  132. package/dist/Helpers/ApiFormHelpers.d.ts +49 -0
  133. package/dist/Helpers/ApiFormHelpers.js +120 -0
  134. package/dist/Helpers/ApiModules.d.ts +131 -0
  135. package/dist/Helpers/ApiModules.js +195 -0
  136. package/dist/Helpers/ApiResponses.d.ts +51 -0
  137. package/dist/Helpers/ApiResponses.js +250 -0
  138. package/dist/Helpers/ApiRoutes.d.ts +140 -0
  139. package/dist/Helpers/ApiRoutes.js +183 -0
  140. package/dist/Helpers/ApiToasts.d.ts +21 -0
  141. package/dist/Helpers/ApiToasts.js +22 -0
  142. package/dist/Helpers/ChatBackend.d.ts +134 -0
  143. package/dist/Helpers/ChatBackend.js +332 -0
  144. package/dist/Helpers/ChatHelpers.d.ts +189 -0
  145. package/dist/Helpers/ChatHelpers.js +486 -0
  146. package/dist/Helpers/ChatHooks.d.ts +81 -0
  147. package/dist/Helpers/ChatHooks.js +175 -0
  148. package/dist/Helpers/ChatStore.d.ts +132 -0
  149. package/dist/Helpers/ChatStore.js +394 -0
  150. package/dist/Helpers/ChatSummaries.d.ts +39 -0
  151. package/dist/Helpers/ChatSummaries.js +118 -0
  152. package/dist/Helpers/ClassHelpers.d.ts +3 -0
  153. package/dist/Helpers/ClassHelpers.js +4 -0
  154. package/dist/Helpers/CrudBackend.d.ts +98 -0
  155. package/dist/Helpers/CrudBackend.js +214 -0
  156. package/dist/Helpers/CrudHelpers.d.ts +111 -0
  157. package/dist/Helpers/CrudHelpers.js +267 -0
  158. package/dist/Helpers/DateHelpers.d.ts +88 -0
  159. package/dist/Helpers/DateHelpers.js +363 -0
  160. package/dist/Helpers/DatePreferences.d.ts +14 -0
  161. package/dist/Helpers/DatePreferences.js +94 -0
  162. package/dist/Helpers/DateTimeHelpers.d.ts +87 -0
  163. package/dist/Helpers/DateTimeHelpers.js +286 -0
  164. package/dist/Helpers/DragHelpers.d.ts +129 -0
  165. package/dist/Helpers/DragHelpers.js +281 -0
  166. package/dist/Helpers/DropdownHelpers.d.ts +56 -0
  167. package/dist/Helpers/DropdownHelpers.js +180 -0
  168. package/dist/Helpers/ExcelBackend.d.ts +106 -0
  169. package/dist/Helpers/ExcelBackend.js +290 -0
  170. package/dist/Helpers/ExcelHelpers.d.ts +98 -0
  171. package/dist/Helpers/ExcelHelpers.js +302 -0
  172. package/dist/Helpers/FormDrafts.d.ts +18 -0
  173. package/dist/Helpers/FormDrafts.js +76 -0
  174. package/dist/Helpers/FormStore.d.ts +233 -0
  175. package/dist/Helpers/FormStore.js +752 -0
  176. package/dist/Helpers/InputParamsHelpers.d.ts +79 -0
  177. package/dist/Helpers/InputParamsHelpers.js +388 -0
  178. package/dist/Helpers/MarkdownEditing.d.ts +27 -0
  179. package/dist/Helpers/MarkdownEditing.js +250 -0
  180. package/dist/Helpers/MarkdownHelpers.d.ts +82 -0
  181. package/dist/Helpers/MarkdownHelpers.js +775 -0
  182. package/dist/Helpers/MessageBuilder.d.ts +74 -0
  183. package/dist/Helpers/MessageBuilder.js +252 -0
  184. package/dist/Helpers/NepaliCalendar.d.ts +25 -0
  185. package/dist/Helpers/NepaliCalendar.js +107 -0
  186. package/dist/Helpers/NumberHelpers.d.ts +71 -0
  187. package/dist/Helpers/NumberHelpers.js +202 -0
  188. package/dist/Helpers/Permissions.d.ts +62 -0
  189. package/dist/Helpers/Permissions.js +133 -0
  190. package/dist/Helpers/PopoverHelpers.d.ts +68 -0
  191. package/dist/Helpers/PopoverHelpers.js +195 -0
  192. package/dist/Helpers/RichTextHelpers.d.ts +77 -0
  193. package/dist/Helpers/RichTextHelpers.js +1072 -0
  194. package/dist/Helpers/RowsStore.d.ts +166 -0
  195. package/dist/Helpers/RowsStore.js +606 -0
  196. package/dist/Helpers/TableColumns.d.ts +47 -0
  197. package/dist/Helpers/TableColumns.js +282 -0
  198. package/dist/Helpers/TableExport.d.ts +30 -0
  199. package/dist/Helpers/TableExport.js +97 -0
  200. package/dist/Helpers/TableHelpers.d.ts +110 -0
  201. package/dist/Helpers/TableHelpers.js +301 -0
  202. package/dist/Helpers/TableStore.d.ts +142 -0
  203. package/dist/Helpers/TableStore.js +530 -0
  204. package/dist/Helpers/ThemeHelpers.d.ts +15 -0
  205. package/dist/Helpers/ThemeHelpers.js +16 -0
  206. package/dist/Helpers/TimeHelpers.d.ts +73 -0
  207. package/dist/Helpers/TimeHelpers.js +253 -0
  208. package/dist/Helpers/TreeStore.d.ts +188 -0
  209. package/dist/Helpers/TreeStore.js +577 -0
  210. package/dist/Helpers/ValidationHelpers.d.ts +124 -0
  211. package/dist/Helpers/ValidationHelpers.js +301 -0
  212. package/dist/Interfaces/ApiInterfaces.d.ts +174 -0
  213. package/dist/Interfaces/ApiInterfaces.js +30 -0
  214. package/dist/Interfaces/ChatInterfaces.d.ts +240 -0
  215. package/{src/sso-client.tsx → dist/Interfaces/ChatInterfaces.js} +1 -1
  216. package/dist/Interfaces/CrudInterfaces.d.ts +232 -0
  217. package/dist/Interfaces/CrudInterfaces.js +1 -0
  218. package/dist/Interfaces/DateInterfaces.d.ts +154 -0
  219. package/dist/Interfaces/DateInterfaces.js +29 -0
  220. package/dist/Interfaces/ExcelInterfaces.d.ts +215 -0
  221. package/dist/Interfaces/ExcelInterfaces.js +45 -0
  222. package/dist/Interfaces/FormInterfaces.d.ts +402 -0
  223. package/dist/Interfaces/FormInterfaces.js +1 -0
  224. package/dist/Interfaces/InputInterfaces.d.ts +141 -0
  225. package/dist/Interfaces/InputInterfaces.js +1 -0
  226. package/dist/Interfaces/MessageInterfaces.d.ts +111 -0
  227. package/dist/Interfaces/MessageInterfaces.js +5 -0
  228. package/dist/Interfaces/TableInterfaces.d.ts +351 -0
  229. package/dist/Interfaces/TableInterfaces.js +1 -0
  230. package/dist/Interfaces/ThemeInterfaces.d.ts +17 -0
  231. package/dist/Interfaces/ThemeInterfaces.js +17 -0
  232. package/dist/Interfaces/TypeInterfaces.d.ts +4 -0
  233. package/dist/Interfaces/TypeInterfaces.js +1 -0
  234. package/dist/Server.Index.d.ts +2 -0
  235. package/dist/Server.Index.js +5 -0
  236. package/dist/Services/ApiProxy.d.ts +32 -0
  237. package/dist/Services/ApiProxy.js +111 -0
  238. package/dist/Services/BrowserApi.d.ts +95 -0
  239. package/dist/Services/BrowserApi.js +129 -0
  240. package/dist/Services/ChatApi.d.ts +37 -0
  241. package/dist/Services/ChatApi.js +98 -0
  242. package/dist/Services/ExcelApi.d.ts +46 -0
  243. package/dist/Services/ExcelApi.js +196 -0
  244. package/dist/Services/ServerApi.d.ts +54 -0
  245. package/dist/Services/ServerApi.js +78 -0
  246. package/dist/Services/ThemeService.d.ts +17 -0
  247. package/dist/Services/ThemeService.js +83 -0
  248. package/dist/Shared.Index.d.ts +51 -0
  249. package/dist/Shared.Index.js +55 -0
  250. package/package.json +85 -33
  251. package/src/Styles/Nexus.Base.css +70 -0
  252. package/src/Styles/Nexus.Button.css +153 -0
  253. package/src/Styles/Nexus.Calendar.css +275 -0
  254. package/src/Styles/Nexus.Chat.css +1489 -0
  255. package/src/Styles/Nexus.Choice.css +345 -0
  256. package/src/Styles/Nexus.Crud.css +161 -0
  257. package/src/Styles/Nexus.DateTime.css +81 -0
  258. package/src/Styles/Nexus.Dropdown.css +774 -0
  259. package/src/Styles/Nexus.Editor.css +297 -0
  260. package/src/Styles/Nexus.Excel.css +370 -0
  261. package/src/Styles/Nexus.Form.css +321 -0
  262. package/src/Styles/Nexus.Index.css +36 -0
  263. package/src/Styles/Nexus.Input.css +637 -0
  264. package/src/Styles/Nexus.Markdown.css +265 -0
  265. package/src/Styles/Nexus.Menu.css +259 -0
  266. package/src/Styles/Nexus.Popup.css +731 -0
  267. package/src/Styles/Nexus.RichText.css +463 -0
  268. package/src/Styles/Nexus.Rows.css +596 -0
  269. package/src/Styles/Nexus.Slider.css +278 -0
  270. package/src/Styles/Nexus.Tab.Buttons.css +419 -0
  271. package/src/Styles/Nexus.Table.css +1296 -0
  272. package/src/Styles/Nexus.Theme.Picker.css +232 -0
  273. package/src/Styles/Nexus.Themes.css +194 -0
  274. package/src/Styles/Nexus.Time.css +147 -0
  275. package/src/Styles/Nexus.Toast.css +265 -0
  276. package/src/Styles/Nexus.Tokens.css +72 -0
  277. package/src/Styles/Nexus.Tree.css +435 -0
  278. package/src/api-services/authentication-service.tsx +0 -23
  279. package/src/api-services/preference-service.tsx +0 -5
  280. package/src/api-services/system-service.tsx +0 -29
  281. package/src/client.ts +0 -31
  282. package/src/components/documents/button.tsx +0 -133
  283. package/src/components/documents/icon-box.tsx +0 -93
  284. package/src/components/documents/page-title.tsx +0 -7
  285. package/src/components/documents/tab-button.tsx +0 -172
  286. package/src/components/documents/tag.tsx +0 -30
  287. package/src/components/index.js +0 -0
  288. package/src/components/inputs/checkbox-input.tsx +0 -66
  289. package/src/components/inputs/input-box.tsx +0 -48
  290. package/src/components/inputs/input-element.tsx +0 -65
  291. package/src/components/inputs/input-form.tsx +0 -164
  292. package/src/components/inputs/input.tsx +0 -181
  293. package/src/components/inputs/number-input.tsx +0 -108
  294. package/src/components/inputs/radiobox-input.tsx +0 -53
  295. package/src/components/inputs/textarea-input.tsx +0 -47
  296. package/src/components/inputs/textbox-input.tsx +0 -45
  297. package/src/components/layouts/global-dialogbox.tsx +0 -431
  298. package/src/components/layouts/global-layout.tsx +0 -64
  299. package/src/components/layouts/layout-helpers.tsx +0 -20
  300. package/src/components/layouts/panels/user-panel.tsx +0 -112
  301. package/src/components/layouts/utility-menu.tsx +0 -49
  302. package/src/components/panels/theme-panel.tsx +0 -46
  303. package/src/helpers/bitwise-helpers.tsx +0 -11
  304. package/src/helpers/browser-helpers.tsx +0 -156
  305. package/src/helpers/datasource-helpers.tsx +0 -99
  306. package/src/helpers/element-helpers.tsx +0 -123
  307. package/src/helpers/input-helpers.tsx +0 -74
  308. package/src/helpers/string-helpers.tsx +0 -28
  309. package/src/helpers/utility-helpers.tsx +0 -45
  310. package/src/helpers/validation-helpers.tsx +0 -302
  311. package/src/index.ts +0 -26
  312. package/src/interface.ts +0 -19
  313. package/src/interfaces/auth-token-interfaces.tsx +0 -6
  314. package/src/interfaces/browser-interfaces.tsx +0 -36
  315. package/src/interfaces/button-interfaces.tsx +0 -63
  316. package/src/interfaces/datasource-interfaces.tsx +0 -22
  317. package/src/interfaces/datatable-interfaces.tsx +0 -25
  318. package/src/interfaces/dialogbox-interfaces.tsx +0 -5
  319. package/src/interfaces/exception-interfaces.tsx +0 -99
  320. package/src/interfaces/http-interfaces.tsx +0 -129
  321. package/src/interfaces/icon-interfaces.tsx +0 -129
  322. package/src/interfaces/input-interfaces.tsx +0 -410
  323. package/src/interfaces/layout-interfaces.tsx +0 -191
  324. package/src/interfaces/menu-interfaces.tsx +0 -53
  325. package/src/interfaces/message-interfaces.tsx +0 -32
  326. package/src/interfaces/permission-interfaces.tsx +0 -9
  327. package/src/interfaces/storage-interfaces.tsx +0 -5
  328. package/src/interfaces/system-interfaces.tsx +0 -22
  329. package/src/interfaces/theme-interfaces.tsx +0 -123
  330. package/src/interfaces/type-interfaces.tsx +0 -28
  331. package/src/interfaces/user-interfaces.tsx +0 -47
  332. package/src/nexus-client.tsx +0 -21
  333. package/src/nexus.environments.tsx +0 -66
  334. package/src/proxy-api/proxy-backend.tsx +0 -60
  335. package/src/proxy-api/proxy-constants.tsx +0 -28
  336. package/src/proxy-api/proxy-helpers.tsx +0 -91
  337. package/src/proxy-api-client.tsx +0 -1
  338. package/src/proxy-api-server.tsx +0 -2
  339. package/src/services/http-client-services.tsx +0 -75
  340. package/src/services/http-services.tsx +0 -158
  341. package/src/services/loader-service.tsx +0 -185
  342. package/src/services/localstorage-service.tsx +0 -119
  343. package/src/services/message-services.tsx +0 -383
  344. package/src/services/theme-service.tsx +0 -163
  345. package/src/services/user-services.tsx +0 -10
  346. package/src/sso-config/auth-token-validation.ts +0 -16
  347. package/src/sso-config/callback-route.tsx +0 -35
  348. package/src/sso-config/cookie-encryption.ts +0 -51
  349. package/src/sso-config/cookie-helpers.tsx +0 -102
  350. package/src/sso-config/forgot-password-route.tsx +0 -36
  351. package/src/sso-config/oauth-callback-state.ts +0 -61
  352. package/src/sso-config/pkce-helpers.ts +0 -9
  353. package/src/sso-config/provider-complete-route.tsx +0 -18
  354. package/src/sso-config/redirect-context-actions.tsx +0 -45
  355. package/src/sso-config/redirect-context-helpers.tsx +0 -159
  356. package/src/sso-config/redirect-context-persist.tsx +0 -18
  357. package/src/sso-config/redirect-context-route.tsx +0 -45
  358. package/src/sso-config/refresh-route.tsx +0 -23
  359. package/src/sso-config/sign-in-route.tsx +0 -74
  360. package/src/sso-config/sign-out-route.tsx +0 -57
  361. package/src/sso-config/sign-up-route.tsx +0 -57
  362. package/src/sso-config/sso-backend-flow.ts +0 -38
  363. package/src/sso-config/sso-complete-route.tsx +0 -50
  364. package/src/sso-config/sso-config.ts +0 -59
  365. package/src/sso-config/sso-interfaces.tsx +0 -99
  366. package/src/sso-config/sso-response-helpers.tsx +0 -20
  367. package/src/sso-server.tsx +0 -21
  368. package/src/styles/nexus.animation.css +0 -269
  369. package/src/styles/nexus.core.css +0 -119
  370. package/src/styles/nexus.dialog.css +0 -144
  371. package/src/styles/nexus.grid-view.css +0 -42
  372. package/src/styles/nexus.icon.css +0 -51
  373. package/src/styles/nexus.input.css +0 -207
  374. package/src/styles/nexus.loader.css +0 -11
  375. package/src/styles/nexus.logic.css +0 -47
  376. package/src/styles/nexus.utility.css +0 -347
@@ -0,0 +1,214 @@
1
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
2
+ export class CrudBackend {
3
+ /** Reads a whole list: an array, or the rows of a page. */
4
+ readList(result) {
5
+ if (Array.isArray(result))
6
+ return result;
7
+ return [...this.readPage(result).rows];
8
+ }
9
+ /**
10
+ * Changes an action's answer makes to rows, by key: a mass flag that answers each record's new status. Rows without
11
+ * an entry take the change the action stands for (a toggled flag). Default: none.
12
+ */
13
+ answeredChanges(result, rowKey) {
14
+ void result;
15
+ void rowKey;
16
+ return new Map();
17
+ }
18
+ /**
19
+ * The keys of the records an action changed, when its answer lists them: a mass trash where some records could not
20
+ * move. `null` when the answer does not say, and every record sent counts as changed. Default `null`.
21
+ */
22
+ answeredKeys(result, rowKey) {
23
+ void result;
24
+ void rowKey;
25
+ return null;
26
+ }
27
+ /**
28
+ * What an answer says about the one record an action wrote: the record itself, or only the fields that changed.
29
+ * `null` when it says nothing about it - a bare key, an empty body - and then the caller keeps what it has.
30
+ *
31
+ * **This is what spares a page its reload.** A save or a mark whose answer carries the record is written into the
32
+ * table, the pinned band and every list kept in the cache, and nothing is loaded again. Only answers of actions on
33
+ * **one** record are read here; a mass answer goes through `answeredChanges`, record by record.
34
+ */
35
+ answeredRow(result) {
36
+ void result;
37
+ return null;
38
+ }
39
+ /**
40
+ * The key an answer gives in place of the record: `Create` answering the new record's id. `null` when the answer
41
+ * is the record itself, or says nothing. With a key the new record goes straight into the list, and where there is
42
+ * a `details` endpoint it is read back on its own - one small request, never the whole list again.
43
+ */
44
+ answeredKey(result) {
45
+ void result;
46
+ return null;
47
+ }
48
+ /**
49
+ * Whether a record belongs in a list, read from the record itself. It is what lets one answer be written into the
50
+ * lists that are **not** on screen: a flagged record joins the flagged list, a trashed one leaves the active list
51
+ * and joins the trash, in the cache as well as in the table.
52
+ *
53
+ * `undefined` when the record does not say, and a list it cannot answer for is dropped from the cache and loads
54
+ * again when it is shown. Default: nothing is known, which is how every list behaved before.
55
+ */
56
+ listMembership(row, mode) {
57
+ void row;
58
+ void mode;
59
+ return undefined;
60
+ }
61
+ }
62
+ /*
63
+ * The Nexus record statuses, as the backend's `ERecordStatus` numbers them. A record's status is a number in a band,
64
+ * and the bands the owner settled on 2026-09-25 are:
65
+ *
66
+ * 0–39 active (anything under 40 is a live record)
67
+ * 0–29 active account
68
+ * 25–29 flag
69
+ * 30–39 pending, unverified, in review, approval required
70
+ * 40–59 trash
71
+ * 60+ delete
72
+ *
73
+ * The flag is a **range**, 25–29, and this file checks a single value: the seeded `ERecordStatus.Flagged` is 25, and
74
+ * nothing yet defines what 26–29 would mean. A range-aware check belongs with the per-project bands being built on
75
+ * `/v2/core-config`, so it is deliberately not here — and this note is here so the single value is not mistaken for
76
+ * the final answer.
77
+ */
78
+ /** The Nexus record status of a flagged record (`ERecordStatus.Flagged`), the bottom of the 25–29 flag band. */
79
+ export const NEXUS_FLAGGED_STATUS = 25;
80
+ /** The Nexus record status of an active record (`ERecordStatus.Active`), the bottom of the 0–39 active band. */
81
+ export const NEXUS_ACTIVE_STATUS = 0;
82
+ /** The Nexus record status of a record in the trash (`ERecordStatus.Trash`), the bottom of the 40–59 trash band. */
83
+ export const NEXUS_TRASH_STATUS = 40;
84
+ /** The Nexus record status of a deleted record (`ERecordStatus.PermanentDeleted`), the bottom of the 60+ delete band. */
85
+ export const NEXUS_DELETED_STATUS = 60;
86
+ /** Just past the flag band: a flagged record is 25–29, so 30 and up is live but not flagged. */
87
+ const NEXUS_FLAG_BAND_END = 30;
88
+ /**
89
+ * The Nexus backend: pages as `{ searchKeyword, skipCount, maxCount, sorting, sortType }` answered with
90
+ * `{ results, totalCount, filterCount }`, newest first unless a column is sorted; mass actions send the ids
91
+ * (`{ description, accountIds }` for descriptions); a flagged record has `recordStatus` 25, a pinned one `isPinned`.
92
+ */
93
+ export class NexusCrudBackend extends CrudBackend {
94
+ pageRequest(query, sortKey) {
95
+ return {
96
+ searchKeyword: query.search,
97
+ skipCount: (query.page - 1) * query.pageSize,
98
+ maxCount: query.pageSize,
99
+ sorting: query.sort ? (sortKey ?? query.sort.key) : "creationTime",
100
+ sortType: query.sort ? query.sort.direction : "desc",
101
+ };
102
+ }
103
+ readPage(result) {
104
+ if (Array.isArray(result))
105
+ return { rows: result };
106
+ if (!isRecord(result))
107
+ return { rows: [] };
108
+ const rows = (Array.isArray(result.results) ? result.results : []);
109
+ const total = Number(result.totalCount);
110
+ const matches = Number(result.filterCount);
111
+ return {
112
+ rows,
113
+ total: Number.isFinite(total) ? total : rows.length,
114
+ matches: Number.isFinite(matches) ? matches : Number.isFinite(total) ? total : rows.length,
115
+ };
116
+ }
117
+ massRequest(action, keys, values) {
118
+ return action === "description" ? { description: values?.description ?? null, accountIds: keys } : keys;
119
+ }
120
+ isFlagged(row) {
121
+ return Number(row.recordStatus) === NEXUS_FLAGGED_STATUS;
122
+ }
123
+ withFlag(row, on) {
124
+ return { ...row, recordStatus: on ? NEXUS_FLAGGED_STATUS : NEXUS_ACTIVE_STATUS };
125
+ }
126
+ isPinned(row) {
127
+ return row.isPinned === true;
128
+ }
129
+ withPin(row, on) {
130
+ return { ...row, isPinned: on };
131
+ }
132
+ /** Mass answers list the records they changed, with their new `recordStatus` and `isPinned`. */
133
+ answeredChanges(result, rowKey) {
134
+ const changes = new Map();
135
+ const items = Array.isArray(result) ? result : isRecord(result) && Array.isArray(result.results) ? result.results : [];
136
+ for (const item of items) {
137
+ if (!isRecord(item))
138
+ continue;
139
+ const key = item[rowKey];
140
+ if (key === undefined || key === null)
141
+ continue;
142
+ const change = {};
143
+ if ("recordStatus" in item)
144
+ change.recordStatus = item.recordStatus;
145
+ if ("isPinned" in item)
146
+ change.isPinned = item.isPinned;
147
+ if (Object.keys(change).length)
148
+ changes.set(String(key), change);
149
+ }
150
+ return changes;
151
+ }
152
+ /**
153
+ * A write answers the record it wrote, or a value that is not one. `Create` and `Update` answer the new record's
154
+ * **id token**, which says nothing the caller does not already hold, so it is read as nothing; a mark answers the
155
+ * record's new **`ERecordStatus`**, which is the one field that changed and is what puts the record in the right
156
+ * list without loading one. A backend that answers the whole record is read as that record.
157
+ */
158
+ answeredRow(result) {
159
+ if (isRecord(result))
160
+ return result;
161
+ // A token is text and a status is a number, so the two can never be read for each other.
162
+ if (typeof result === "number" && Number.isInteger(result) && result >= 0)
163
+ return { recordStatus: result };
164
+ return null;
165
+ }
166
+ /** `Create` and `Update` answer the record's id: a token when ids are encrypted, the number as text when not. */
167
+ answeredKey(result) {
168
+ return typeof result === "string" && result !== "" ? result : null;
169
+ }
170
+ /**
171
+ * The bands the owner settled on: under 40 is live, 25–29 of that is flagged, 40–59 is the trash, and 60 and up is
172
+ * deleted. A row without a `recordStatus` says nothing, and the lists it cannot answer for load again.
173
+ */
174
+ listMembership(row, mode) {
175
+ const status = row.recordStatus;
176
+ if (typeof status !== "number" || !Number.isFinite(status))
177
+ return undefined;
178
+ switch (mode) {
179
+ case "normal":
180
+ return status < NEXUS_TRASH_STATUS;
181
+ case "flag":
182
+ return status >= NEXUS_FLAGGED_STATUS && status < NEXUS_FLAG_BAND_END;
183
+ case "trash":
184
+ return status >= NEXUS_TRASH_STATUS && status < NEXUS_DELETED_STATUS;
185
+ case "deleted":
186
+ return status >= NEXUS_DELETED_STATUS;
187
+ default:
188
+ return undefined;
189
+ }
190
+ }
191
+ /** Mass answers list the records they changed (as records, or as ids); other answers say nothing. */
192
+ answeredKeys(result, rowKey) {
193
+ const items = Array.isArray(result) ? result : isRecord(result) && Array.isArray(result.results) ? result.results : null;
194
+ if (!items)
195
+ return null;
196
+ const keys = new Set();
197
+ for (const item of items) {
198
+ const key = isRecord(item) ? item[rowKey] : item;
199
+ if (typeof key === "string" || typeof key === "number")
200
+ keys.add(String(key));
201
+ }
202
+ return keys;
203
+ }
204
+ }
205
+ let current = null;
206
+ /** Registers the app's backend conventions, once, beside its API modules. */
207
+ export function defineCrudBackend(backend) {
208
+ current = backend;
209
+ return backend;
210
+ }
211
+ /** The registered backend conventions, or the Nexus ones. */
212
+ export function getCrudBackend() {
213
+ return (current ??= new NexusCrudBackend());
214
+ }
@@ -0,0 +1,111 @@
1
+ import type { ApiEndpoint } from "../Interfaces/ApiInterfaces.ts";
2
+ import type { CrudActionName, CrudEndpoints, CrudMassActionName, CrudMode, CrudRowActionName } from "../Interfaces/CrudInterfaces.ts";
3
+ import type { MessageActionName } from "../Interfaces/MessageInterfaces.ts";
4
+ import type { TablePage, TablePaging, TableRow } from "../Interfaces/TableInterfaces.ts";
5
+ /** Every list, in the order the CRUD shows them. */
6
+ export declare const CRUD_MODES: readonly CrudMode[];
7
+ /** The built-in actions on one record, per list, in their menu order. */
8
+ export declare const CRUD_ROW_ACTIONS: Readonly<Record<CrudMode, readonly CrudRowActionName[]>>;
9
+ /** The built-in actions on selected records, per list. */
10
+ export declare const CRUD_MASS_ACTIONS: Readonly<Record<CrudMode, readonly CrudMassActionName[]>>;
11
+ /**
12
+ * The built-in actions a list offers, in menu order, of those `allowed`. A controller without a trash (`trashless`: no
13
+ * trash endpoint, or trash not asked for) offers Delete where Move to trash would be. A trash the user may not use never
14
+ * turns into Delete.
15
+ */
16
+ export declare function crudRowActions(mode: CrudMode, allowed: (action: CrudRowActionName) => boolean, trashless?: boolean): CrudRowActionName[];
17
+ /** The built-in actions on selected records a list offers, with the same Delete for a controller without a trash. */
18
+ export declare function crudMassActions(mode: CrudMode, allowed: (action: CrudMassActionName) => boolean, trashless?: boolean): CrudMassActionName[];
19
+ /** The endpoint of a list: its full list for tables that page in the browser, its pages for server tables. */
20
+ export declare function crudListEndpoint(api: CrudEndpoints, mode: CrudMode, paging: TablePaging): ApiEndpoint | undefined;
21
+ /** The endpoint of a row action. `view` needs none of its own: it shows the row (and calls `details` when there is one). */
22
+ export declare function crudRowEndpoint(api: CrudEndpoints, action: CrudRowActionName): ApiEndpoint | undefined;
23
+ /** The lists a CRUD can offer: asked for, with an endpoint, and allowed. */
24
+ export declare function availableModes(api: CrudEndpoints, paging: TablePaging, wanted: readonly CrudMode[], can: (endpoint: ApiEndpoint) => boolean): CrudMode[];
25
+ /**
26
+ * Whether a built-in action can run: asked for, with an endpoint, and allowed. View also works without a `details`
27
+ * endpoint (it shows the row), but a `details` endpoint the user may not call hides it, as in the old CRUD.
28
+ */
29
+ export declare function actionAllowed(action: CrudActionName, api: CrudEndpoints, wanted: readonly CrudActionName[], can: (endpoint: ApiEndpoint) => boolean): boolean;
30
+ /** Whether a mass action can run: its row action is wanted, and its mass endpoint exists and is allowed. */
31
+ export declare function massActionAllowed(action: CrudMassActionName, api: CrudEndpoints, wanted: readonly CrudActionName[], can: (endpoint: ApiEndpoint) => boolean): boolean;
32
+ /**
33
+ * Whether a record leaves the list shown after an action. Trash, recover, delete, and moving back to the trash take it
34
+ * to another list, and unflagging leaves the flagged list. Pinning and unpinning never do: a pinned
35
+ * record stays in the list it is in. `markOn` is the record's new flag.
36
+ */
37
+ export declare function leavesList(action: CrudRowActionName | CrudMassActionName, mode: CrudMode, markOn?: boolean): boolean;
38
+ /** The message builder's action for a built-in action: "Guest recovered.", "Unpin 3 guests?" */
39
+ export declare function crudMessageAction(action: CrudRowActionName | CrudMassActionName, markOn?: boolean): MessageActionName;
40
+ /** What every CRUD follows, whatever module it shows. `configureCrud` changes it once, for the whole app. */
41
+ export interface CrudSettings {
42
+ /**
43
+ * Most records a user may pin. Default 100. Lowering it never unpins anything: a user over the new limit keeps their
44
+ * pins and can unpin, and may pin again once they are under it.
45
+ */
46
+ maxPins: number;
47
+ }
48
+ /**
49
+ * Changes what every CRUD follows, once, where the app registers its API modules: `configureCrud({ maxPins: 50 })`.
50
+ * Values left out keep what they had.
51
+ */
52
+ export declare function configureCrud(changes: Partial<CrudSettings>): CrudSettings;
53
+ /** The settings every CRUD follows. */
54
+ export declare function getCrudSettings(): CrudSettings;
55
+ /**
56
+ * How many more records may be pinned: the limit less the records pinned, never below zero. `pinned` is `undefined`
57
+ * when nothing counts the pins (no `pins` endpoint), and then there is no limit to keep.
58
+ */
59
+ export declare function pinRoom(pinned: number | undefined, max?: number): number;
60
+ /** Default time a CRUD keeps a list: 5 minutes. */
61
+ export declare const CRUD_CACHE_LIFETIME: number;
62
+ /** Lists kept while a page is open, by key, each for a lifetime. Plain values; nothing is written to storage. */
63
+ export declare class CrudCache<T = unknown> {
64
+ private entries;
65
+ readonly lifetime: number;
66
+ private now;
67
+ constructor(lifetime?: number, now?: () => number);
68
+ get(key: string): T | undefined;
69
+ set(key: string, value: T): void;
70
+ /** Replaces a value, keeping its age, so a changed list does not live longer than the list it came from. */
71
+ update(key: string, value: T): void;
72
+ /**
73
+ * Writes a change through every entry, each keeping its age: this is how a record that was saved or marked reaches
74
+ * the lists that are not on screen without a request. Returning `null` drops that entry, and its list loads again
75
+ * the next time it is shown.
76
+ */
77
+ map(change: (key: string, value: T) => T | null): void;
78
+ /** Drops every entry whose key passes the test. */
79
+ drop(test: (key: string) => boolean): void;
80
+ clear(): void;
81
+ get size(): number;
82
+ }
83
+ /**
84
+ * A record a change touched, as the lists kept in the cache are patched from it: how it is now, how it was, and
85
+ * whether it is in any list at all any more.
86
+ */
87
+ export interface CrudRowChange<TRow extends TableRow = TableRow> {
88
+ /** The record's key, as the table reads it. */
89
+ key: string;
90
+ /** The record as it is now. */
91
+ row: TRow;
92
+ /** The record as it was, when the page had it. Without it, a list that holds the record counts as having held it. */
93
+ before: TRow | undefined;
94
+ /** The record is in no list any more, whatever it says: it is taken out of every list kept. */
95
+ gone?: boolean;
96
+ }
97
+ /** The list a cache entry belongs to: the key itself for a whole list, its first part for one page of one. */
98
+ export declare function crudCacheMode(key: string): CrudMode;
99
+ /**
100
+ * One list kept in the cache, after a change: the records that belong in it are written in, the ones that no longer
101
+ * belong are taken out, and the entry is returned as it should now be. `null` means the list cannot be worked out
102
+ * and has to be loaded again.
103
+ *
104
+ * `member` is the backend's rule for which list a record belongs in (`CrudBackend.listMembership`). A record it
105
+ * cannot answer for drops the entry, which is what every list did before this.
106
+ *
107
+ * **A whole list** is patched: a record that joined it goes on top, where the table also shows a record just added.
108
+ * **One page of a list** is not: its order, its last row and its counts are the server's, so as soon as a record
109
+ * joined it or left it the page is dropped; a record that stayed is written in place, which costs nothing.
110
+ */
111
+ export declare function patchCachedList<TRow extends TableRow>(value: TablePage<TRow> | TRow[], mode: CrudMode, changes: readonly CrudRowChange<TRow>[], keyOf: (row: TRow) => string, member: (row: TRow, mode: CrudMode) => boolean | undefined): TablePage<TRow> | TRow[] | null;
@@ -0,0 +1,267 @@
1
+ /*
2
+ * The rules of the CRUD component, with no React: which lists and actions a controller offers, which actions each list
3
+ * shows, which records leave a list after an action, the settings every CRUD follows (how many records may be pinned),
4
+ * and the cache of lists kept while the page is open - including how a change is written into the lists kept, so that
5
+ * a record saved or marked costs no request on any list.
6
+ */
7
+ /** Every list, in the order the CRUD shows them. */
8
+ export const CRUD_MODES = ["normal", "flag", "trash", "deleted"];
9
+ const ACTIVE_ROW_ACTIONS = ["view", "edit", "flag", "pin", "trash"];
10
+ const ACTIVE_MASS_ACTIONS = ["flag", "pin", "description", "trash"];
11
+ /** The built-in actions on one record, per list, in their menu order. */
12
+ export const CRUD_ROW_ACTIONS = {
13
+ normal: ACTIVE_ROW_ACTIONS,
14
+ flag: ACTIVE_ROW_ACTIONS,
15
+ trash: ["view", "recover", "delete"],
16
+ deleted: ["view", "trashFromDelete"],
17
+ };
18
+ /** The built-in actions on selected records, per list. */
19
+ export const CRUD_MASS_ACTIONS = {
20
+ normal: ACTIVE_MASS_ACTIONS,
21
+ flag: ACTIVE_MASS_ACTIONS,
22
+ trash: ["recover", "description", "delete"],
23
+ deleted: ["trashFromDelete"],
24
+ };
25
+ /**
26
+ * The built-in actions a list offers, in menu order, of those `allowed`. A controller without a trash (`trashless`: no
27
+ * trash endpoint, or trash not asked for) offers Delete where Move to trash would be. A trash the user may not use never
28
+ * turns into Delete.
29
+ */
30
+ export function crudRowActions(mode, allowed, trashless = false) {
31
+ const list = [];
32
+ for (const action of CRUD_ROW_ACTIONS[mode]) {
33
+ if (action === "trash" && trashless) {
34
+ if (allowed("delete"))
35
+ list.push("delete");
36
+ }
37
+ else if (allowed(action))
38
+ list.push(action);
39
+ }
40
+ return list;
41
+ }
42
+ /** The built-in actions on selected records a list offers, with the same Delete for a controller without a trash. */
43
+ export function crudMassActions(mode, allowed, trashless = false) {
44
+ const list = [];
45
+ for (const action of CRUD_MASS_ACTIONS[mode]) {
46
+ if (action === "trash" && trashless) {
47
+ if (allowed("delete"))
48
+ list.push("delete");
49
+ }
50
+ else if (allowed(action))
51
+ list.push(action);
52
+ }
53
+ return list;
54
+ }
55
+ /** The endpoint of a list: its full list for tables that page in the browser, its pages for server tables. */
56
+ export function crudListEndpoint(api, mode, paging) {
57
+ return paging === "server" ? api.pages?.[mode] : api.lists?.[mode];
58
+ }
59
+ /** The endpoint of a row action. `view` needs none of its own: it shows the row (and calls `details` when there is one). */
60
+ export function crudRowEndpoint(api, action) {
61
+ if (action === "view")
62
+ return api.details;
63
+ if (action === "edit")
64
+ return api.update;
65
+ return api[action];
66
+ }
67
+ /** The lists a CRUD can offer: asked for, with an endpoint, and allowed. */
68
+ export function availableModes(api, paging, wanted, can) {
69
+ return CRUD_MODES.filter(mode => wanted.includes(mode)).filter(mode => {
70
+ const endpoint = crudListEndpoint(api, mode, paging);
71
+ return Boolean(endpoint) && can(endpoint);
72
+ });
73
+ }
74
+ /**
75
+ * Whether a built-in action can run: asked for, with an endpoint, and allowed. View also works without a `details`
76
+ * endpoint (it shows the row), but a `details` endpoint the user may not call hides it, as in the old CRUD.
77
+ */
78
+ export function actionAllowed(action, api, wanted, can) {
79
+ if (!wanted.includes(action))
80
+ return false;
81
+ if (action === "create")
82
+ return Boolean(api.create) && can(api.create);
83
+ if (action === "description")
84
+ return Boolean(api.mass?.description) && can(api.mass.description);
85
+ if (action === "view")
86
+ return !api.details || can(api.details);
87
+ const endpoint = crudRowEndpoint(api, action);
88
+ return Boolean(endpoint) && can(endpoint);
89
+ }
90
+ /** Whether a mass action can run: its row action is wanted, and its mass endpoint exists and is allowed. */
91
+ export function massActionAllowed(action, api, wanted, can) {
92
+ if (!wanted.includes(action))
93
+ return false;
94
+ const endpoint = api.mass?.[action];
95
+ return Boolean(endpoint) && can(endpoint);
96
+ }
97
+ /**
98
+ * Whether a record leaves the list shown after an action. Trash, recover, delete, and moving back to the trash take it
99
+ * to another list, and unflagging leaves the flagged list. Pinning and unpinning never do: a pinned
100
+ * record stays in the list it is in. `markOn` is the record's new flag.
101
+ */
102
+ export function leavesList(action, mode, markOn) {
103
+ switch (action) {
104
+ case "trash":
105
+ case "recover":
106
+ case "delete":
107
+ case "trashFromDelete":
108
+ return true;
109
+ case "flag":
110
+ return mode === "flag" && markOn === false;
111
+ default:
112
+ return false;
113
+ }
114
+ }
115
+ /** The message builder's action for a built-in action: "Guest recovered.", "Unpin 3 guests?" */
116
+ export function crudMessageAction(action, markOn) {
117
+ switch (action) {
118
+ case "flag":
119
+ return markOn === false ? "unflag" : "flag";
120
+ case "pin":
121
+ return markOn === false ? "unpin" : "pin";
122
+ case "trashFromDelete":
123
+ return "trash";
124
+ case "description":
125
+ return "update";
126
+ case "edit":
127
+ case "view":
128
+ return "save";
129
+ default:
130
+ return action;
131
+ }
132
+ }
133
+ const DEFAULT_CRUD_SETTINGS = { maxPins: 100 };
134
+ let crudSettings = DEFAULT_CRUD_SETTINGS;
135
+ /**
136
+ * Changes what every CRUD follows, once, where the app registers its API modules: `configureCrud({ maxPins: 50 })`.
137
+ * Values left out keep what they had.
138
+ */
139
+ export function configureCrud(changes) {
140
+ crudSettings = { ...crudSettings, ...changes };
141
+ return crudSettings;
142
+ }
143
+ /** The settings every CRUD follows. */
144
+ export function getCrudSettings() {
145
+ return crudSettings;
146
+ }
147
+ /**
148
+ * How many more records may be pinned: the limit less the records pinned, never below zero. `pinned` is `undefined`
149
+ * when nothing counts the pins (no `pins` endpoint), and then there is no limit to keep.
150
+ */
151
+ export function pinRoom(pinned, max = getCrudSettings().maxPins) {
152
+ if (pinned === undefined)
153
+ return Number.POSITIVE_INFINITY;
154
+ return Math.max(0, max - pinned);
155
+ }
156
+ /** Default time a CRUD keeps a list: 5 minutes. */
157
+ export const CRUD_CACHE_LIFETIME = 5 * 60 * 1000;
158
+ /** Lists kept while a page is open, by key, each for a lifetime. Plain values; nothing is written to storage. */
159
+ export class CrudCache {
160
+ entries = new Map();
161
+ lifetime;
162
+ now;
163
+ constructor(lifetime = CRUD_CACHE_LIFETIME, now = Date.now) {
164
+ this.lifetime = lifetime;
165
+ this.now = now;
166
+ }
167
+ get(key) {
168
+ const entry = this.entries.get(key);
169
+ if (!entry)
170
+ return undefined;
171
+ if (this.now() - entry.at > this.lifetime) {
172
+ this.entries.delete(key);
173
+ return undefined;
174
+ }
175
+ return entry.value;
176
+ }
177
+ set(key, value) {
178
+ if (this.lifetime > 0)
179
+ this.entries.set(key, { value, at: this.now() });
180
+ }
181
+ /** Replaces a value, keeping its age, so a changed list does not live longer than the list it came from. */
182
+ update(key, value) {
183
+ const entry = this.entries.get(key);
184
+ if (entry)
185
+ entry.value = value;
186
+ }
187
+ /**
188
+ * Writes a change through every entry, each keeping its age: this is how a record that was saved or marked reaches
189
+ * the lists that are not on screen without a request. Returning `null` drops that entry, and its list loads again
190
+ * the next time it is shown.
191
+ */
192
+ map(change) {
193
+ for (const [key, entry] of [...this.entries]) {
194
+ const next = change(key, entry.value);
195
+ if (next === null)
196
+ this.entries.delete(key);
197
+ else
198
+ entry.value = next;
199
+ }
200
+ }
201
+ /** Drops every entry whose key passes the test. */
202
+ drop(test) {
203
+ for (const key of [...this.entries.keys()])
204
+ if (test(key))
205
+ this.entries.delete(key);
206
+ }
207
+ clear() {
208
+ this.entries.clear();
209
+ }
210
+ get size() {
211
+ return this.entries.size;
212
+ }
213
+ }
214
+ /** The list a cache entry belongs to: the key itself for a whole list, its first part for one page of one. */
215
+ export function crudCacheMode(key) {
216
+ const bar = key.indexOf("|");
217
+ return (bar === -1 ? key : key.slice(0, bar));
218
+ }
219
+ /**
220
+ * One list kept in the cache, after a change: the records that belong in it are written in, the ones that no longer
221
+ * belong are taken out, and the entry is returned as it should now be. `null` means the list cannot be worked out
222
+ * and has to be loaded again.
223
+ *
224
+ * `member` is the backend's rule for which list a record belongs in (`CrudBackend.listMembership`). A record it
225
+ * cannot answer for drops the entry, which is what every list did before this.
226
+ *
227
+ * **A whole list** is patched: a record that joined it goes on top, where the table also shows a record just added.
228
+ * **One page of a list** is not: its order, its last row and its counts are the server's, so as soon as a record
229
+ * joined it or left it the page is dropped; a record that stayed is written in place, which costs nothing.
230
+ */
231
+ export function patchCachedList(value, mode, changes, keyOf, member) {
232
+ const paged = !Array.isArray(value);
233
+ const rows = paged ? [...value.rows] : [...value];
234
+ let touched = false;
235
+ for (const change of changes) {
236
+ const now = change.gone ? false : member(change.row, mode);
237
+ if (now === undefined)
238
+ return null;
239
+ const at = rows.findIndex(row => keyOf(row) === change.key);
240
+ const was = change.before ? member(change.before, mode) : at !== -1;
241
+ if (was === undefined)
242
+ return null;
243
+ if (paged) {
244
+ if (was !== now)
245
+ return null;
246
+ if (at !== -1) {
247
+ rows[at] = change.row;
248
+ touched = true;
249
+ }
250
+ continue;
251
+ }
252
+ if (now) {
253
+ if (at === -1)
254
+ rows.unshift(change.row);
255
+ else
256
+ rows[at] = change.row;
257
+ touched = true;
258
+ }
259
+ else if (at !== -1) {
260
+ rows.splice(at, 1);
261
+ touched = true;
262
+ }
263
+ }
264
+ if (!touched)
265
+ return value;
266
+ return paged ? { ...value, rows } : rows;
267
+ }