@multiplatform.one/frappe-ui 7.7.6 → 7.8.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/dist/cjs/ChartCard.native.js.map +1 -1
- package/dist/cjs/FileBrowser/AttachLibrary.native.js.map +1 -1
- package/dist/cjs/FileBrowser/folderTree.native.js.map +1 -1
- package/dist/cjs/FileBrowser/index.native.js.map +1 -1
- package/dist/cjs/FileBrowser/types.native.js.map +1 -1
- package/dist/cjs/FileBrowser/viewPersistence.native.js.map +1 -1
- package/dist/cjs/FormSidebar.native.js.map +1 -1
- package/dist/cjs/FrappeAssignment.native.js.map +1 -1
- package/dist/cjs/FrappeCalendar.cjs +20 -17
- package/dist/cjs/FrappeCalendar.native.js +22 -21
- package/dist/cjs/FrappeCalendar.native.js.map +1 -1
- package/dist/cjs/FrappeChartCard.native.js.map +1 -1
- package/dist/cjs/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +1 -1
- package/dist/cjs/FrappeForm.native.js +2 -2
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeGantt.cjs +25 -34
- package/dist/cjs/FrappeGantt.native.js +27 -38
- package/dist/cjs/FrappeGantt.native.js.map +1 -1
- package/dist/cjs/FrappeImageView.cjs +4 -2
- package/dist/cjs/FrappeImageView.native.js +8 -4
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeKPICard.cjs +26 -1
- package/dist/cjs/FrappeKPICard.native.js +26 -1
- package/dist/cjs/FrappeKPICard.native.js.map +1 -1
- package/dist/cjs/FrappeKanban.cjs +16 -17
- package/dist/cjs/FrappeKanban.native.js +18 -21
- package/dist/cjs/FrappeKanban.native.js.map +1 -1
- package/dist/cjs/FrappeLikedBy.cjs +1 -1
- package/dist/cjs/FrappeLikedBy.native.js +1 -1
- package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
- package/dist/cjs/FrappeList.cjs +2 -2
- package/dist/cjs/FrappeList.native.js +2 -2
- package/dist/cjs/FrappeList.native.js.map +1 -1
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeProvider.native.js.map +1 -1
- package/dist/cjs/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/cjs/FrappeReportBuilder.cjs +2 -2
- package/dist/cjs/FrappeReportBuilder.native.js +2 -2
- package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
- package/dist/cjs/FrappeReportView.native.js +3 -3
- package/dist/cjs/FrappeReportView.native.js.map +1 -1
- package/dist/cjs/FrappeTable.cjs +35 -38
- package/dist/cjs/FrappeTable.native.js +38 -39
- package/dist/cjs/FrappeTable.native.js.map +1 -1
- package/dist/cjs/FrappeTreeView.cjs +85 -50
- package/dist/cjs/FrappeTreeView.native.js +129 -50
- package/dist/cjs/FrappeTreeView.native.js.map +1 -1
- package/dist/cjs/SyncErrorNotice.native.js.map +1 -1
- package/dist/cjs/commentActions.cjs +1 -1
- package/dist/cjs/commentActions.native.js +1 -1
- package/dist/cjs/commentActions.native.js.map +1 -1
- package/dist/cjs/components/attachments.native.js.map +1 -1
- package/dist/cjs/components/tags.native.js.map +1 -1
- package/dist/cjs/components/timeline.cjs +1 -1
- package/dist/cjs/components/timeline.native.js +1 -1
- package/dist/cjs/components/timeline.native.js.map +1 -1
- package/dist/cjs/dependsOn.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
- package/dist/cjs/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/cjs/desk/DeskListPage.native.js.map +1 -1
- package/dist/cjs/desk/DeskShell.cjs +2 -0
- package/dist/cjs/desk/DeskShell.native.js +2 -0
- package/dist/cjs/desk/DeskShell.native.js.map +1 -1
- package/dist/cjs/desk/DeskSidebar.native.js.map +1 -1
- package/dist/cjs/desk/awesomebar.cjs +1 -1
- package/dist/cjs/desk/awesomebar.native.js +1 -1
- package/dist/cjs/desk/awesomebar.native.js.map +1 -1
- package/dist/cjs/fieldOverrides.native.js.map +1 -1
- package/dist/cjs/fieldRegistry.native.js +31 -31
- package/dist/cjs/fieldRegistry.native.js.map +1 -1
- package/dist/cjs/fields/Barcode/index.native.js.map +1 -1
- package/dist/cjs/fields/Check/index.native.js.map +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/cjs/fields/Color/index.native.js.map +1 -1
- package/dist/cjs/fields/Data/index.native.js.map +1 -1
- package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/cjs/fields/Date/types.native.js.map +1 -1
- package/dist/cjs/fields/Date/wire.native.js.map +1 -1
- package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
- package/dist/cjs/fields/Duration/index.native.js.map +1 -1
- package/dist/cjs/fields/DynamicLink.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload.native.js.map +1 -1
- package/dist/cjs/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/cjs/fields/Geolocation/index.native.js.map +1 -1
- package/dist/cjs/fields/HTML/index.native.js.map +1 -1
- package/dist/cjs/fields/Heading/index.native.js.map +1 -1
- package/dist/cjs/fields/Icon/index.native.js.map +1 -1
- package/dist/cjs/fields/Link.native.js.map +1 -1
- package/dist/cjs/fields/LinkTree.native.js.map +1 -1
- package/dist/cjs/fields/LongText/index.native.js.map +1 -1
- package/dist/cjs/fields/MentionInput/index.cjs +4 -1
- package/dist/cjs/fields/MentionInput/index.native.js +4 -1
- package/dist/cjs/fields/MentionInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Numeric/index.native.js.map +1 -1
- package/dist/cjs/fields/OTPInput/index.native.js.map +1 -1
- package/dist/cjs/fields/Password/index.native.js.map +1 -1
- package/dist/cjs/fields/Phone/index.native.js.map +1 -1
- package/dist/cjs/fields/Progress/index.native.js.map +1 -1
- package/dist/cjs/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/Rating/index.native.js.map +1 -1
- package/dist/cjs/fields/ReadOnly/index.native.js.map +1 -1
- package/dist/cjs/fields/Select/index.native.js.map +1 -1
- package/dist/cjs/fields/Signature/index.native.js.map +1 -1
- package/dist/cjs/fields/Slider/index.native.js.map +1 -1
- package/dist/cjs/fields/SmallText/index.native.js.map +1 -1
- package/dist/cjs/fields/Switch/index.native.js.map +1 -1
- package/dist/cjs/fields/TableMultiSelect.native.js.map +1 -1
- package/dist/cjs/fields/TextEditor/types.native.js.map +1 -1
- package/dist/cjs/fields/TimePicker/index.native.js.map +1 -1
- package/dist/cjs/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/cjs/fields/shared/EditorPreviewPanes.native.js.map +1 -1
- package/dist/cjs/filterFields.native.js.map +1 -1
- package/dist/cjs/formEngine/createPrefill.native.js.map +1 -1
- package/dist/cjs/formEngine/dirtyTracking.native.js.map +1 -1
- package/dist/cjs/formEngine/doctypeMeta.native.js.map +1 -1
- package/dist/cjs/formEngine/fetchFrom.native.js.map +1 -1
- package/dist/cjs/formEngine/fieldPermissions.native.js.map +1 -1
- package/dist/cjs/formEngine/formActions.native.js.map +1 -1
- package/dist/cjs/formEngine/formLayout.native.js.map +1 -1
- package/dist/cjs/formEngine/index.native.js.map +1 -1
- package/dist/cjs/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/cjs/frappeEventColor.native.js.map +1 -1
- package/dist/cjs/frappeStoryTarget.native.js.map +1 -1
- package/dist/cjs/frappeUsers.native.js.map +1 -1
- package/dist/cjs/index.cjs +4 -0
- package/dist/cjs/index.native.js +38 -34
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/liveErrors.native.js.map +1 -1
- package/dist/cjs/resolveControl.native.js.map +1 -1
- package/dist/cjs/schemaForm/SchemaWizard.native.js.map +1 -1
- package/dist/cjs/schemaForm/applyFieldOrder.native.js.map +1 -1
- package/dist/cjs/schemaForm/index.cjs +10 -9
- package/dist/cjs/schemaForm/index.native.js +11 -10
- package/dist/cjs/schemaForm/index.native.js.map +1 -1
- package/dist/cjs/shared/devWarn.cjs +40 -0
- package/dist/cjs/shared/devWarn.native.js +45 -0
- package/dist/cjs/shared/devWarn.native.js.map +1 -0
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/syncError.native.js.map +1 -1
- package/dist/cjs/useFrappeAggregate.cjs +15 -8
- package/dist/cjs/useFrappeAggregate.native.js +15 -9
- package/dist/cjs/useFrappeAggregate.native.js.map +1 -1
- package/dist/cjs/useFrappeFacets.cjs +10 -9
- package/dist/cjs/useFrappeFacets.native.js +10 -10
- package/dist/cjs/useFrappeFacets.native.js.map +1 -1
- package/dist/cjs/useFrappePagination.native.js.map +1 -1
- package/dist/cjs/useFrappeRows.cjs +113 -0
- package/dist/cjs/useFrappeRows.native.js +129 -0
- package/dist/cjs/useFrappeRows.native.js.map +1 -0
- package/dist/esm/ChartCard.native.js.map +1 -1
- package/dist/esm/FileBrowser/AttachLibrary.native.js.map +1 -1
- package/dist/esm/FileBrowser/folderTree.native.js.map +1 -1
- package/dist/esm/FileBrowser/index.native.js.map +1 -1
- package/dist/esm/FileBrowser/types.native.js.map +1 -1
- package/dist/esm/FileBrowser/viewPersistence.native.js.map +1 -1
- package/dist/esm/FormSidebar.native.js.map +1 -1
- package/dist/esm/FrappeAssignment.native.js.map +1 -1
- package/dist/esm/FrappeCalendar.mjs +20 -17
- package/dist/esm/FrappeCalendar.mjs.map +1 -1
- package/dist/esm/FrappeCalendar.native.js +22 -21
- package/dist/esm/FrappeCalendar.native.js.map +1 -1
- package/dist/esm/FrappeChartCard.native.js.map +1 -1
- package/dist/esm/FrappeConnectionIndicator.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +1 -1
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +1 -1
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeGantt.mjs +27 -36
- package/dist/esm/FrappeGantt.mjs.map +1 -1
- package/dist/esm/FrappeGantt.native.js +29 -40
- package/dist/esm/FrappeGantt.native.js.map +1 -1
- package/dist/esm/FrappeImageView.mjs +5 -3
- package/dist/esm/FrappeImageView.mjs.map +1 -1
- package/dist/esm/FrappeImageView.native.js +9 -5
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeKPICard.mjs +27 -2
- package/dist/esm/FrappeKPICard.mjs.map +1 -1
- package/dist/esm/FrappeKPICard.native.js +27 -2
- package/dist/esm/FrappeKPICard.native.js.map +1 -1
- package/dist/esm/FrappeKanban.mjs +16 -17
- package/dist/esm/FrappeKanban.mjs.map +1 -1
- package/dist/esm/FrappeKanban.native.js +18 -21
- package/dist/esm/FrappeKanban.native.js.map +1 -1
- package/dist/esm/FrappeLikedBy.mjs +1 -1
- package/dist/esm/FrappeLikedBy.mjs.map +1 -1
- package/dist/esm/FrappeLikedBy.native.js +1 -1
- package/dist/esm/FrappeLikedBy.native.js.map +1 -1
- package/dist/esm/FrappeList.mjs +2 -2
- package/dist/esm/FrappeList.mjs.map +1 -1
- package/dist/esm/FrappeList.native.js +2 -2
- package/dist/esm/FrappeList.native.js.map +1 -1
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeProvider.mjs.map +1 -1
- package/dist/esm/FrappeProvider.native.js.map +1 -1
- package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/esm/FrappeReportBuilder.mjs +2 -2
- package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
- package/dist/esm/FrappeReportBuilder.native.js +2 -2
- package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
- package/dist/esm/FrappeReportView.native.js.map +1 -1
- package/dist/esm/FrappeTable.mjs +36 -39
- package/dist/esm/FrappeTable.mjs.map +1 -1
- package/dist/esm/FrappeTable.native.js +39 -40
- package/dist/esm/FrappeTable.native.js.map +1 -1
- package/dist/esm/FrappeTreeView.mjs +89 -55
- package/dist/esm/FrappeTreeView.mjs.map +1 -1
- package/dist/esm/FrappeTreeView.native.js +133 -55
- package/dist/esm/FrappeTreeView.native.js.map +1 -1
- package/dist/esm/SyncErrorNotice.native.js.map +1 -1
- package/dist/esm/commentActions.mjs +1 -1
- package/dist/esm/commentActions.mjs.map +1 -1
- package/dist/esm/commentActions.native.js +1 -1
- package/dist/esm/commentActions.native.js.map +1 -1
- package/dist/esm/components/attachments.native.js.map +1 -1
- package/dist/esm/components/tags.native.js.map +1 -1
- package/dist/esm/components/timeline.mjs +1 -1
- package/dist/esm/components/timeline.mjs.map +1 -1
- package/dist/esm/components/timeline.native.js +1 -1
- package/dist/esm/components/timeline.native.js.map +1 -1
- package/dist/esm/dependsOn.native.js.map +1 -1
- package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
- package/dist/esm/desk/DeskFormSidebar.native.js.map +1 -1
- package/dist/esm/desk/DeskListPage.native.js.map +1 -1
- package/dist/esm/desk/DeskShell.mjs +2 -0
- package/dist/esm/desk/DeskShell.mjs.map +1 -1
- package/dist/esm/desk/DeskShell.native.js +2 -0
- package/dist/esm/desk/DeskShell.native.js.map +1 -1
- package/dist/esm/desk/DeskSidebar.native.js.map +1 -1
- package/dist/esm/desk/awesomebar.mjs +1 -1
- package/dist/esm/desk/awesomebar.mjs.map +1 -1
- package/dist/esm/desk/awesomebar.native.js +1 -1
- package/dist/esm/desk/awesomebar.native.js.map +1 -1
- package/dist/esm/fieldOverrides.native.js.map +1 -1
- package/dist/esm/fieldRegistry.native.js.map +1 -1
- package/dist/esm/fields/Barcode/index.native.js.map +1 -1
- package/dist/esm/fields/Check/index.native.js.map +1 -1
- package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/esm/fields/Color/index.native.js.map +1 -1
- package/dist/esm/fields/Data/index.native.js.map +1 -1
- package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/esm/fields/Date/types.native.js.map +1 -1
- package/dist/esm/fields/Date/wire.native.js.map +1 -1
- package/dist/esm/fields/DateRange/index.native.js.map +1 -1
- package/dist/esm/fields/Duration/index.native.js.map +1 -1
- package/dist/esm/fields/DynamicLink.native.js.map +1 -1
- package/dist/esm/fields/FileUpload.native.js.map +1 -1
- package/dist/esm/fields/FileUploadField/index.native.js.map +1 -1
- package/dist/esm/fields/Geolocation/index.native.js.map +1 -1
- package/dist/esm/fields/HTML/index.native.js.map +1 -1
- package/dist/esm/fields/Heading/index.native.js.map +1 -1
- package/dist/esm/fields/Icon/index.native.js.map +1 -1
- package/dist/esm/fields/Link.native.js.map +1 -1
- package/dist/esm/fields/LinkTree.native.js.map +1 -1
- package/dist/esm/fields/LongText/index.native.js.map +1 -1
- package/dist/esm/fields/MentionInput/index.mjs +4 -1
- package/dist/esm/fields/MentionInput/index.mjs.map +1 -1
- package/dist/esm/fields/MentionInput/index.native.js +4 -1
- package/dist/esm/fields/MentionInput/index.native.js.map +1 -1
- package/dist/esm/fields/Numeric/index.native.js.map +1 -1
- package/dist/esm/fields/OTPInput/index.native.js.map +1 -1
- package/dist/esm/fields/Password/index.native.js.map +1 -1
- package/dist/esm/fields/Phone/index.native.js.map +1 -1
- package/dist/esm/fields/Progress/index.native.js.map +1 -1
- package/dist/esm/fields/RadioGroup/index.native.js.map +1 -1
- package/dist/esm/fields/Rating/index.native.js.map +1 -1
- package/dist/esm/fields/ReadOnly/index.native.js.map +1 -1
- package/dist/esm/fields/Select/index.native.js.map +1 -1
- package/dist/esm/fields/Signature/index.native.js.map +1 -1
- package/dist/esm/fields/Slider/index.native.js.map +1 -1
- package/dist/esm/fields/SmallText/index.native.js.map +1 -1
- package/dist/esm/fields/Switch/index.native.js.map +1 -1
- package/dist/esm/fields/TableMultiSelect.native.js.map +1 -1
- package/dist/esm/fields/TextEditor/types.native.js.map +1 -1
- package/dist/esm/fields/TimePicker/index.native.js.map +1 -1
- package/dist/esm/fields/ToggleGroup/index.native.js.map +1 -1
- package/dist/esm/fields/shared/EditorPreviewPanes.native.js.map +1 -1
- package/dist/esm/filterFields.native.js.map +1 -1
- package/dist/esm/formEngine/createPrefill.native.js.map +1 -1
- package/dist/esm/formEngine/dirtyTracking.native.js.map +1 -1
- package/dist/esm/formEngine/doctypeMeta.native.js.map +1 -1
- package/dist/esm/formEngine/fetchFrom.native.js.map +1 -1
- package/dist/esm/formEngine/fieldPermissions.native.js.map +1 -1
- package/dist/esm/formEngine/formActions.native.js.map +1 -1
- package/dist/esm/formEngine/formLayout.native.js.map +1 -1
- package/dist/esm/formEngine/index.native.js.map +1 -1
- package/dist/esm/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/esm/frappeEventColor.native.js.map +1 -1
- package/dist/esm/frappeStoryTarget.native.js.map +1 -1
- package/dist/esm/frappeUsers.native.js.map +1 -1
- package/dist/esm/index.mjs +2 -1
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +2 -1
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/liveErrors.native.js.map +1 -1
- package/dist/esm/resolveControl.native.js.map +1 -1
- package/dist/esm/schemaForm/SchemaWizard.native.js.map +1 -1
- package/dist/esm/schemaForm/applyFieldOrder.native.js.map +1 -1
- package/dist/esm/schemaForm/index.mjs +8 -7
- package/dist/esm/schemaForm/index.mjs.map +1 -1
- package/dist/esm/schemaForm/index.native.js +8 -7
- package/dist/esm/schemaForm/index.native.js.map +1 -1
- package/dist/esm/shared/devWarn.mjs +14 -0
- package/dist/esm/shared/devWarn.mjs.map +1 -0
- package/dist/esm/shared/devWarn.native.js +16 -0
- package/dist/esm/shared/devWarn.native.js.map +1 -0
- package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/esm/syncError.native.js.map +1 -1
- package/dist/esm/useFrappeAggregate.mjs +15 -8
- package/dist/esm/useFrappeAggregate.mjs.map +1 -1
- package/dist/esm/useFrappeAggregate.native.js +15 -9
- package/dist/esm/useFrappeAggregate.native.js.map +1 -1
- package/dist/esm/useFrappeFacets.mjs +10 -9
- package/dist/esm/useFrappeFacets.mjs.map +1 -1
- package/dist/esm/useFrappeFacets.native.js +10 -10
- package/dist/esm/useFrappeFacets.native.js.map +1 -1
- package/dist/esm/useFrappePagination.native.js.map +1 -1
- package/dist/esm/useFrappeRows.mjs +86 -0
- package/dist/esm/useFrappeRows.mjs.map +1 -0
- package/dist/esm/useFrappeRows.native.js +99 -0
- package/dist/esm/useFrappeRows.native.js.map +1 -0
- package/dist/jsx/FrappeCalendar.mjs +20 -17
- package/dist/jsx/FrappeCalendar.mjs.map +1 -1
- package/dist/jsx/FrappeCalendar.native.js +22 -21
- package/dist/jsx/FrappeCalendar.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +1 -1
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +1 -1
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeGantt.mjs +27 -36
- package/dist/jsx/FrappeGantt.mjs.map +1 -1
- package/dist/jsx/FrappeGantt.native.js +27 -38
- package/dist/jsx/FrappeGantt.native.js.map +1 -1
- package/dist/jsx/FrappeImageView.mjs +5 -3
- package/dist/jsx/FrappeImageView.mjs.map +1 -1
- package/dist/jsx/FrappeImageView.native.js +8 -4
- package/dist/jsx/FrappeImageView.native.js.map +1 -1
- package/dist/jsx/FrappeKPICard.mjs +27 -2
- package/dist/jsx/FrappeKPICard.mjs.map +1 -1
- package/dist/jsx/FrappeKPICard.native.js +26 -1
- package/dist/jsx/FrappeKPICard.native.js.map +1 -1
- package/dist/jsx/FrappeKanban.mjs +16 -17
- package/dist/jsx/FrappeKanban.mjs.map +1 -1
- package/dist/jsx/FrappeKanban.native.js +18 -21
- package/dist/jsx/FrappeKanban.native.js.map +1 -1
- package/dist/jsx/FrappeLikedBy.mjs +1 -1
- package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
- package/dist/jsx/FrappeLikedBy.native.js +1 -1
- package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
- package/dist/jsx/FrappeList.mjs +2 -2
- package/dist/jsx/FrappeList.mjs.map +1 -1
- package/dist/jsx/FrappeList.native.js +2 -2
- package/dist/jsx/FrappeList.native.js.map +1 -1
- package/dist/jsx/FrappeProvider.mjs.map +1 -1
- package/dist/jsx/FrappeProvider.native.js.map +1 -1
- package/dist/jsx/FrappeReportBuilder.mjs +2 -2
- package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
- package/dist/jsx/FrappeReportBuilder.native.js +2 -2
- package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
- package/dist/jsx/FrappeTable.mjs +36 -39
- package/dist/jsx/FrappeTable.mjs.map +1 -1
- package/dist/jsx/FrappeTable.native.js +38 -39
- package/dist/jsx/FrappeTable.native.js.map +1 -1
- package/dist/jsx/FrappeTreeView.mjs +89 -55
- package/dist/jsx/FrappeTreeView.mjs.map +1 -1
- package/dist/jsx/FrappeTreeView.native.js +129 -50
- package/dist/jsx/FrappeTreeView.native.js.map +1 -1
- package/dist/jsx/commentActions.mjs +1 -1
- package/dist/jsx/commentActions.mjs.map +1 -1
- package/dist/jsx/commentActions.native.js +1 -1
- package/dist/jsx/commentActions.native.js.map +1 -1
- package/dist/jsx/components/timeline.mjs +1 -1
- package/dist/jsx/components/timeline.mjs.map +1 -1
- package/dist/jsx/components/timeline.native.js +1 -1
- package/dist/jsx/desk/DeskShell.mjs +2 -0
- package/dist/jsx/desk/DeskShell.mjs.map +1 -1
- package/dist/jsx/desk/DeskShell.native.js +2 -0
- package/dist/jsx/desk/DeskShell.native.js.map +1 -1
- package/dist/jsx/desk/awesomebar.mjs +1 -1
- package/dist/jsx/desk/awesomebar.mjs.map +1 -1
- package/dist/jsx/desk/awesomebar.native.js +1 -1
- package/dist/jsx/desk/awesomebar.native.js.map +1 -1
- package/dist/jsx/fields/MentionInput/index.mjs +4 -1
- package/dist/jsx/fields/MentionInput/index.mjs.map +1 -1
- package/dist/jsx/fields/MentionInput/index.native.js +4 -1
- package/dist/jsx/fields/MentionInput/index.native.js.map +1 -1
- package/dist/jsx/index.js +2 -1
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +2 -1
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +4 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/schemaForm/index.mjs +8 -7
- package/dist/jsx/schemaForm/index.mjs.map +1 -1
- package/dist/jsx/schemaForm/index.native.js +10 -9
- package/dist/jsx/schemaForm/index.native.js.map +1 -1
- package/dist/jsx/shared/devWarn.mjs +14 -0
- package/dist/jsx/shared/devWarn.mjs.map +1 -0
- package/dist/jsx/shared/devWarn.native.js +45 -0
- package/dist/jsx/shared/devWarn.native.js.map +1 -0
- package/dist/jsx/useFrappeAggregate.mjs +15 -8
- package/dist/jsx/useFrappeAggregate.mjs.map +1 -1
- package/dist/jsx/useFrappeAggregate.native.js +15 -9
- package/dist/jsx/useFrappeAggregate.native.js.map +1 -1
- package/dist/jsx/useFrappeFacets.mjs +10 -9
- package/dist/jsx/useFrappeFacets.mjs.map +1 -1
- package/dist/jsx/useFrappeFacets.native.js +10 -10
- package/dist/jsx/useFrappeFacets.native.js.map +1 -1
- package/dist/jsx/useFrappeRows.mjs +86 -0
- package/dist/jsx/useFrappeRows.mjs.map +1 -0
- package/dist/jsx/useFrappeRows.native.js +129 -0
- package/dist/jsx/useFrappeRows.native.js.map +1 -0
- package/package.json +17 -16
- package/src/FileBrowser/FileBrowser.spec.tsx +11 -1
- package/src/FrappeCalendar.tsx +25 -22
- package/src/FrappeForm.tsx +7 -3
- package/src/FrappeGantt.tsx +29 -39
- package/src/FrappeImageView.tsx +5 -3
- package/src/FrappeKPICard.spec.tsx +128 -0
- package/src/FrappeKPICard.tsx +44 -4
- package/src/FrappeKanban.tsx +24 -17
- package/src/FrappeLikedBy.tsx +1 -1
- package/src/FrappeList.tsx +3 -2
- package/src/FrappeProvider.fixturesOnly.spec.tsx +129 -0
- package/src/FrappeProvider.tsx +16 -6
- package/src/FrappeReportBuilder.tsx +4 -2
- package/src/FrappeTable.autoHeight.spec.tsx +142 -0
- package/src/FrappeTable.rowAccumulator.spec.tsx +110 -0
- package/src/FrappeTable.tsx +75 -48
- package/src/FrappeTreeView.stories.tsx +59 -0
- package/src/FrappeTreeView.tsx +166 -56
- package/src/commentActions.ts +1 -1
- package/src/components/timeline.tsx +1 -1
- package/src/desk/DeskShell.tsx +2 -0
- package/src/desk/awesomebar.tsx +5 -2
- package/src/fields/CodeEditor/CodeEditor.spec.tsx +10 -9
- package/src/fields/Date/typeParity.spec.tsx +19 -9
- package/src/fields/Duration/Duration.spec.tsx +73 -0
- package/src/fields/MentionInput/MentionInput.spec.tsx +110 -0
- package/src/fields/MentionInput/index.tsx +4 -1
- package/src/fields/Password/index.tsx +1 -1
- package/src/fields/Progress/Progress.spec.tsx +9 -0
- package/src/fields/RadioGroup/RadioGroup.spec.tsx +93 -0
- package/src/fields/Signature/Signature.spec.tsx +105 -0
- package/src/fields/Slider/Slider.spec.tsx +73 -0
- package/src/fields/Switch/Switch.spec.tsx +65 -0
- package/src/fields/TextEditor/TextEditor.spec.tsx +2 -3
- package/src/fields/TextEditor/TextEditor.stories.tsx +31 -1
- package/src/fields/ToggleGroup/ToggleGroup.spec.tsx +110 -0
- package/src/frappeViews.designLaw.spec.ts +11 -7
- package/src/index.ts +13 -0
- package/src/schemaForm/index.tsx +6 -7
- package/src/shared/devWarn.ts +42 -0
- package/src/useFrappeAggregate.ts +17 -11
- package/src/useFrappeFacets.ts +17 -10
- package/src/useFrappeRows.spec.tsx +176 -0
- package/src/useFrappeRows.ts +293 -0
- package/types/FrappeCalendar.d.ts.map +1 -1
- package/types/FrappeForm.d.ts +6 -2
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeGantt.d.ts.map +1 -1
- package/types/FrappeImageView.d.ts.map +1 -1
- package/types/FrappeKPICard.d.ts +9 -1
- package/types/FrappeKPICard.d.ts.map +1 -1
- package/types/FrappeKanban.d.ts.map +1 -1
- package/types/FrappeList.d.ts.map +1 -1
- package/types/FrappeProvider.d.ts +16 -6
- package/types/FrappeProvider.d.ts.map +1 -1
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/FrappeTable.d.ts +20 -1
- package/types/FrappeTable.d.ts.map +1 -1
- package/types/FrappeTreeView.d.ts +38 -1
- package/types/FrappeTreeView.d.ts.map +1 -1
- package/types/desk/DeskShell.d.ts.map +1 -1
- package/types/desk/awesomebar.d.ts.map +1 -1
- package/types/fields/MentionInput/index.d.ts.map +1 -1
- package/types/fields/Password/index.d.ts +1 -1
- package/types/fields/Password/index.d.ts.map +1 -1
- package/types/index.d.ts +1 -0
- package/types/index.d.ts.map +1 -1
- package/types/schemaForm/index.d.ts.map +1 -1
- package/types/shared/devWarn.d.ts +23 -0
- package/types/shared/devWarn.d.ts.map +1 -0
- package/types/useFrappeAggregate.d.ts +2 -1
- package/types/useFrappeAggregate.d.ts.map +1 -1
- package/types/useFrappeFacets.d.ts +2 -1
- package/types/useFrappeFacets.d.ts.map +1 -1
- package/types/useFrappeRows.d.ts +186 -0
- package/types/useFrappeRows.d.ts.map +1 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A fixture corpus satisfies the connection requirement on its own (MPO-228).
|
|
3
|
+
*
|
|
4
|
+
* `createApp({ frappe: { fixtures } })` mounts a FrappeProvider with NO
|
|
5
|
+
* baseURL, so the collection-backed components must read the corpus instead
|
|
6
|
+
* of demanding a bench URL. These specs pin that: rows render, doctype meta
|
|
7
|
+
* comes from the corpus, and `fetch` is never called — a fixtures-only app
|
|
8
|
+
* runs with no server. The old error still fires when neither is configured.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
12
|
+
import type { DataTableColumn } from "@multiplatform.one/table";
|
|
13
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
14
|
+
import { cleanup, screen } from "@testing-library/react";
|
|
15
|
+
import i18next from "i18next";
|
|
16
|
+
import { initReactI18next } from "react-i18next";
|
|
17
|
+
import { Text } from "tamagui";
|
|
18
|
+
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
19
|
+
import { FrappeList } from "./FrappeList";
|
|
20
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
21
|
+
import { FrappeTable } from "./FrappeTable";
|
|
22
|
+
|
|
23
|
+
beforeAll(async () => {
|
|
24
|
+
await i18next.use(initReactI18next).init({
|
|
25
|
+
lng: "en",
|
|
26
|
+
interpolation: { escapeValue: false },
|
|
27
|
+
resources: { en: { translation: {} } },
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
cleanup();
|
|
33
|
+
vi.restoreAllMocks();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
interface Customer {
|
|
37
|
+
name: string;
|
|
38
|
+
doctype: string;
|
|
39
|
+
customer_name: string;
|
|
40
|
+
status: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const customers: Customer[] = [
|
|
44
|
+
{ name: "CUST-001", doctype: "Customer", customer_name: "Acme Corp", status: "Active" },
|
|
45
|
+
{ name: "CUST-002", doctype: "Customer", customer_name: "Globex", status: "Lead" },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const columns: DataTableColumn<Partial<Customer>>[] = [
|
|
49
|
+
{ id: "name", accessorKey: "name", header: "ID" },
|
|
50
|
+
{ id: "customer_name", accessorKey: "customer_name", header: "Customer Name" },
|
|
51
|
+
];
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Corpus carrying both documents and the getdoctype-shaped meta doc, so the
|
|
55
|
+
* table's `useDocTypeMeta` call is answered locally too (no filterableFields
|
|
56
|
+
* prop, which would skip that path).
|
|
57
|
+
*/
|
|
58
|
+
function fixtureCorpus() {
|
|
59
|
+
return new InMemoryFixtureProvider({
|
|
60
|
+
DocType: [
|
|
61
|
+
{
|
|
62
|
+
name: "Customer",
|
|
63
|
+
doctype: "DocType",
|
|
64
|
+
module: "Selling",
|
|
65
|
+
fields: [
|
|
66
|
+
{ fieldname: "customer_name", fieldtype: "Data", label: "Customer Name" },
|
|
67
|
+
{ fieldname: "status", fieldtype: "Select", label: "Status", options: "Active\nLead" },
|
|
68
|
+
],
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
Customer: customers,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Fails the test if anything dials the network. */
|
|
76
|
+
function forbidFetch() {
|
|
77
|
+
return vi.spyOn(globalThis, "fetch").mockImplementation((input) => {
|
|
78
|
+
throw new Error(`unexpected network request: ${String(input)}`);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
describe("FrappeProvider with fixtures and no baseURL", () => {
|
|
83
|
+
it("renders a FrappeTable off the corpus without touching the network", async () => {
|
|
84
|
+
const fetchSpy = forbidFetch();
|
|
85
|
+
renderWithProviders(
|
|
86
|
+
<FrappeProvider fixtures={fixtureCorpus()}>
|
|
87
|
+
<FrappeTable<Customer>
|
|
88
|
+
doctype="Customer"
|
|
89
|
+
columns={columns}
|
|
90
|
+
layout="table"
|
|
91
|
+
enablePagination={false}
|
|
92
|
+
/>
|
|
93
|
+
</FrappeProvider>,
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(await screen.findByText("Acme Corp")).toBeTruthy();
|
|
97
|
+
expect(await screen.findByText("Globex")).toBeTruthy();
|
|
98
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("renders a FrappeList off the corpus without touching the network", async () => {
|
|
102
|
+
const fetchSpy = forbidFetch();
|
|
103
|
+
renderWithProviders(
|
|
104
|
+
<FrappeProvider fixtures={fixtureCorpus()}>
|
|
105
|
+
<FrappeList<Customer>
|
|
106
|
+
doctype="Customer"
|
|
107
|
+
fields={["name", "customer_name"]}
|
|
108
|
+
renderItem={(item) => <Text>{item.customer_name}</Text>}
|
|
109
|
+
/>
|
|
110
|
+
</FrappeProvider>,
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(await screen.findByText("Acme Corp")).toBeTruthy();
|
|
114
|
+
expect(fetchSpy).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
describe("FrappeProvider with neither baseURL nor fixtures", () => {
|
|
119
|
+
it("still names what is missing", () => {
|
|
120
|
+
vi.spyOn(console, "error").mockImplementation(() => {});
|
|
121
|
+
expect(() =>
|
|
122
|
+
renderWithProviders(
|
|
123
|
+
<FrappeProvider>
|
|
124
|
+
<FrappeTable<Customer> doctype="Customer" columns={columns} layout="table" />
|
|
125
|
+
</FrappeProvider>,
|
|
126
|
+
),
|
|
127
|
+
).toThrow(/baseURL or fixtures/);
|
|
128
|
+
});
|
|
129
|
+
});
|
package/src/FrappeProvider.tsx
CHANGED
|
@@ -7,8 +7,12 @@ import React, { createContext, use, useContext } from "react";
|
|
|
7
7
|
* @category Types
|
|
8
8
|
*/
|
|
9
9
|
export interface FrappeConfig {
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* The base URL of the Frappe server. Required unless `fixtures` is set:
|
|
12
|
+
* a fixture corpus answers every read locally, so a fixtures-only app has
|
|
13
|
+
* no bench to name and nothing dials one.
|
|
14
|
+
*/
|
|
15
|
+
baseURL?: string;
|
|
12
16
|
/** False uses HTTP collections without a realtime transport. Defaults to true. */
|
|
13
17
|
realtime?: boolean;
|
|
14
18
|
/**
|
|
@@ -52,7 +56,10 @@ export interface FrappeConfig {
|
|
|
52
56
|
* can't forward WebSocket upgrades.
|
|
53
57
|
*/
|
|
54
58
|
socketOptions?: UseFrappeCollectionConfig["socketOptions"];
|
|
55
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Fixture corpus every read and write is served from. Set it without a
|
|
61
|
+
* `baseURL` to run the whole app off fixtures with no server.
|
|
62
|
+
*/
|
|
56
63
|
fixtures?: FixtureProvider;
|
|
57
64
|
}
|
|
58
65
|
|
|
@@ -66,8 +73,8 @@ const FrappeContext = createContext<FrappeConfig | undefined>(undefined);
|
|
|
66
73
|
export interface FrappeProviderProps {
|
|
67
74
|
/** Child components */
|
|
68
75
|
children: React.ReactNode;
|
|
69
|
-
/** The base URL of the Frappe server */
|
|
70
|
-
baseURL
|
|
76
|
+
/** The base URL of the Frappe server. Required unless `fixtures` is set. */
|
|
77
|
+
baseURL?: string;
|
|
71
78
|
/** False uses HTTP collections without a realtime transport. Defaults to true. */
|
|
72
79
|
realtime?: boolean;
|
|
73
80
|
/** Override port for Socket.IO realtime connection (e.g. 9000 in dev). */
|
|
@@ -89,7 +96,10 @@ export interface FrappeProviderProps {
|
|
|
89
96
|
syncOptions?: any;
|
|
90
97
|
/** Extra Socket.IO client options for the realtime connection. */
|
|
91
98
|
socketOptions?: UseFrappeCollectionConfig["socketOptions"];
|
|
92
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Fixture corpus every read and write is served from. Set it without a
|
|
101
|
+
* `baseURL` to run the whole app off fixtures with no server.
|
|
102
|
+
*/
|
|
93
103
|
fixtures?: FixtureProvider;
|
|
94
104
|
}
|
|
95
105
|
|
|
@@ -125,8 +125,10 @@ export function FrappeReportBuilder({
|
|
|
125
125
|
const finalAuth = auth ?? config?.auth;
|
|
126
126
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
127
127
|
|
|
128
|
-
if (!finalBaseURL) {
|
|
129
|
-
throw new Error(
|
|
128
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
129
|
+
throw new Error(
|
|
130
|
+
"FrappeReportBuilder requires baseURL prop or FrappeProvider with baseURL or fixtures",
|
|
131
|
+
);
|
|
130
132
|
}
|
|
131
133
|
|
|
132
134
|
const connectionConfig = {
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-229: FrappeTable must not collapse to a sliver in an auto-height parent.
|
|
3
|
+
*
|
|
4
|
+
* The wrapper YStack used `flex={1}`, which in React Native's flex model is
|
|
5
|
+
* `1 1 0` with a basis of ZERO. A basis-0 chain inside a parent that has no
|
|
6
|
+
* height of its own resolves to 0, so the whole table rendered as a one-row
|
|
7
|
+
* sliver. DataTableRoot's own root already avoids exactly this (grow 1 /
|
|
8
|
+
* shrink 1 / basis auto / minHeight 0, and it carries the note saying why).
|
|
9
|
+
* The FrappeTable wrapper sitting above it reintroduced the trap.
|
|
10
|
+
*
|
|
11
|
+
* Two halves here. The render cases pin the behaviour a caller sees: 12 rows
|
|
12
|
+
* in a plain auto-height parent, and the same table in a fixed-height parent.
|
|
13
|
+
* The source cases are the mechanical guard, because happy-dom runs no flex
|
|
14
|
+
* layout, so a basis-0 regression is invisible to a rendered assertion and
|
|
15
|
+
* only the geometry itself can be checked.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from "node:fs";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
21
|
+
import type { DataTableColumn } from "@multiplatform.one/table";
|
|
22
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
23
|
+
import { cleanup, screen } from "@testing-library/react";
|
|
24
|
+
import i18next from "i18next";
|
|
25
|
+
import { initReactI18next } from "react-i18next";
|
|
26
|
+
import { YStack } from "tamagui";
|
|
27
|
+
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
28
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
29
|
+
import { FrappeTable } from "./FrappeTable";
|
|
30
|
+
|
|
31
|
+
beforeAll(async () => {
|
|
32
|
+
if (!i18next.isInitialized) {
|
|
33
|
+
await i18next.use(initReactI18next).init({
|
|
34
|
+
lng: "en",
|
|
35
|
+
interpolation: { escapeValue: false },
|
|
36
|
+
resources: { en: { translation: {} } },
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
afterEach(() => {
|
|
42
|
+
cleanup();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
interface Customer {
|
|
46
|
+
name: string;
|
|
47
|
+
doctype: string;
|
|
48
|
+
customer_name: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const customers: Customer[] = Array.from({ length: 12 }, (_, index) => ({
|
|
52
|
+
name: `CUST-${String(index + 1).padStart(3, "0")}`,
|
|
53
|
+
doctype: "Customer",
|
|
54
|
+
customer_name: `Customer ${index + 1}`,
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
const columns: DataTableColumn<Partial<Customer>>[] = [
|
|
58
|
+
{ id: "name", accessorKey: "name", header: "ID" },
|
|
59
|
+
{ id: "customer_name", accessorKey: "customer_name", header: "Customer Name" },
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
// Supplied so the table does not go to useDocTypeMeta for the filter list.
|
|
63
|
+
const filterFields = [{ id: "customer_name", label: "Customer Name", type: "text" as const }];
|
|
64
|
+
|
|
65
|
+
function renderInParent(parent: React.ReactElement) {
|
|
66
|
+
return renderWithProviders(
|
|
67
|
+
<FrappeProvider
|
|
68
|
+
baseURL="https://frappetable-autoheight.spec.test"
|
|
69
|
+
fixtures={new InMemoryFixtureProvider({ Customer: customers })}
|
|
70
|
+
>
|
|
71
|
+
{parent}
|
|
72
|
+
</FrappeProvider>,
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const table = (
|
|
77
|
+
<FrappeTable<Customer>
|
|
78
|
+
doctype="Customer"
|
|
79
|
+
columns={columns}
|
|
80
|
+
filterableFields={filterFields}
|
|
81
|
+
layout="table"
|
|
82
|
+
enablePagination={false}
|
|
83
|
+
/>
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
const srcDir = path.resolve(__dirname, ".");
|
|
87
|
+
|
|
88
|
+
function read(file: string): string {
|
|
89
|
+
return fs.readFileSync(path.resolve(srcDir, file), "utf-8");
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function codeOnly(source: string): string {
|
|
93
|
+
return source.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
describe("FrappeTable in an auto-height parent (MPO-229)", () => {
|
|
97
|
+
it("renders every row inside a plain auto-height YStack", async () => {
|
|
98
|
+
renderInParent(<YStack>{table}</YStack>);
|
|
99
|
+
await screen.findByText("Customer 1");
|
|
100
|
+
for (const customer of customers) {
|
|
101
|
+
expect(screen.getByText(customer.customer_name)).toBeTruthy();
|
|
102
|
+
}
|
|
103
|
+
expect(screen.queryByText(/No Customer records found/i)).toBeNull();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("still renders every row inside a fixed-height parent", async () => {
|
|
107
|
+
renderInParent(<YStack height={400}>{table}</YStack>);
|
|
108
|
+
await screen.findByText("Customer 1");
|
|
109
|
+
for (const customer of customers) {
|
|
110
|
+
expect(screen.getByText(customer.customer_name)).toBeTruthy();
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("roots grow and shrink on a basis of auto, the same geometry as DataTableRoot", () => {
|
|
115
|
+
const source = codeOnly(read("FrappeTable.tsx"));
|
|
116
|
+
|
|
117
|
+
// flex={1} is 1 1 0 in RN. Basis 0 in an auto-height parent resolves to 0
|
|
118
|
+
// and the table collapses to a one-row sliver.
|
|
119
|
+
expect(source).not.toContain("flex={1}");
|
|
120
|
+
|
|
121
|
+
const tags = source.match(/<YStack\b[^>]*>/g) ?? [];
|
|
122
|
+
const roots = tags.filter((tag) => tag.includes("flexBasis"));
|
|
123
|
+
expect(roots.length).toBe(2);
|
|
124
|
+
for (const root of roots) {
|
|
125
|
+
expect(root).toContain("flexGrow={1}");
|
|
126
|
+
expect(root).toContain("flexShrink={1}");
|
|
127
|
+
expect(root).toContain('flexBasis="auto"');
|
|
128
|
+
expect(root).toContain("minHeight={0}");
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("DataTableRoot still carries the geometry FrappeTable copies", () => {
|
|
133
|
+
const source = codeOnly(read("../../table/src/components/DataTable/DataTableRoot.tsx"));
|
|
134
|
+
const tags = source.match(/<View\b[^>]*>/g) ?? [];
|
|
135
|
+
const root = tags.find((tag) => tag.includes("flexBasis"));
|
|
136
|
+
expect(root).toBeTruthy();
|
|
137
|
+
expect(root).toContain("flexGrow={1}");
|
|
138
|
+
expect(root).toContain("flexShrink={1}");
|
|
139
|
+
expect(root).toContain('flexBasis="auto"');
|
|
140
|
+
expect(root).toContain("minHeight={0}");
|
|
141
|
+
});
|
|
142
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A running balance on a FrappeTable (MPO-250).
|
|
3
|
+
*
|
|
4
|
+
* The gap this closes: `FrappeTableProps` omits `data`, so before the row
|
|
5
|
+
* accumulator existed there was NO prop that reached the rows. A consumer who
|
|
6
|
+
* wanted a folded column on a Frappe doctype had to fetch the doctype again
|
|
7
|
+
* itself and hand the folded rows to a bare DataTable — a second read path, a
|
|
8
|
+
* second error path, and no saved filters or refresh channel.
|
|
9
|
+
*
|
|
10
|
+
* What this locks: `rowAccumulator` passes through FrappeTable to the table,
|
|
11
|
+
* folds the rows FrappeTable already fetched, and the figures continue onto
|
|
12
|
+
* page two.
|
|
13
|
+
*
|
|
14
|
+
* Fixture-hermetic: postings ride InMemoryFixtureProvider.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
18
|
+
import type { DataTableColumn, RowAccumulator } from "@multiplatform.one/table";
|
|
19
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
20
|
+
import { cleanup, screen, waitFor } from "@testing-library/react";
|
|
21
|
+
import userEvent from "@testing-library/user-event";
|
|
22
|
+
import i18next from "i18next";
|
|
23
|
+
import { initReactI18next } from "react-i18next";
|
|
24
|
+
import { afterEach, beforeAll, describe, expect, it } from "vitest";
|
|
25
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
26
|
+
import { FrappeTable } from "./FrappeTable";
|
|
27
|
+
|
|
28
|
+
beforeAll(async () => {
|
|
29
|
+
await i18next.use(initReactI18next).init({
|
|
30
|
+
lng: "en",
|
|
31
|
+
interpolation: { escapeValue: false },
|
|
32
|
+
resources: { en: { translation: {} } },
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
afterEach(() => cleanup());
|
|
37
|
+
|
|
38
|
+
interface Posting {
|
|
39
|
+
name: string;
|
|
40
|
+
doctype: string;
|
|
41
|
+
date: string;
|
|
42
|
+
payee: string;
|
|
43
|
+
amount: number;
|
|
44
|
+
/** Derived by the accumulator — declared on the doc type so a column can
|
|
45
|
+
* name it in accessorKey. */
|
|
46
|
+
running?: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const postings: Posting[] = Array.from({ length: 8 }, (_, i) => ({
|
|
50
|
+
name: `POST-${String(i + 1).padStart(2, "0")}`,
|
|
51
|
+
doctype: "Posting",
|
|
52
|
+
date: `2026-02-${String(i + 1).padStart(2, "0")}`,
|
|
53
|
+
payee: `Payee ${i + 1}`,
|
|
54
|
+
amount: 10,
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
const runningBalance: RowAccumulator<Partial<Posting>, number> = {
|
|
58
|
+
initial: 0,
|
|
59
|
+
reduce: (carried, row) => carried + (row.amount ?? 0),
|
|
60
|
+
derive: (carried) => ({ running: carried }),
|
|
61
|
+
order: (a, b) => String(a.date).localeCompare(String(b.date)),
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const columns: DataTableColumn<Partial<Posting>>[] = [
|
|
65
|
+
{ id: "name", accessorKey: "name", header: "ID" },
|
|
66
|
+
{ id: "amount", accessorKey: "amount", header: "Amount" },
|
|
67
|
+
{
|
|
68
|
+
id: "running",
|
|
69
|
+
accessorKey: "running",
|
|
70
|
+
header: "Balance",
|
|
71
|
+
sortable: false,
|
|
72
|
+
// Marked so an assertion can tell a balance of 10 from an amount of 10.
|
|
73
|
+
cell: ({ row }) => `bal ${row.original.running}`,
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
|
|
77
|
+
const filterFields = [{ id: "payee", label: "Payee", type: "text" as const }];
|
|
78
|
+
|
|
79
|
+
describe("FrappeTable rowAccumulator", () => {
|
|
80
|
+
it("folds the rows FrappeTable fetched, and page two continues", async () => {
|
|
81
|
+
const user = userEvent.setup();
|
|
82
|
+
renderWithProviders(
|
|
83
|
+
<FrappeProvider
|
|
84
|
+
baseURL="https://frappetable-fold.spec.test"
|
|
85
|
+
fixtures={new InMemoryFixtureProvider({ Posting: postings })}
|
|
86
|
+
>
|
|
87
|
+
<FrappeTable<Posting>
|
|
88
|
+
doctype="Posting"
|
|
89
|
+
columns={columns}
|
|
90
|
+
fields={["name", "date", "payee", "amount"]}
|
|
91
|
+
filterableFields={filterFields}
|
|
92
|
+
rowAccumulator={runningBalance}
|
|
93
|
+
layout="table"
|
|
94
|
+
initialState={{ pagination: { pageIndex: 0, pageSize: 4 } }}
|
|
95
|
+
/>
|
|
96
|
+
</FrappeProvider>,
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
await waitFor(() => expect(screen.getByText("POST-01")).toBeTruthy());
|
|
100
|
+
expect(screen.getByText("bal 10")).toBeTruthy();
|
|
101
|
+
expect(screen.getByText("bal 40")).toBeTruthy();
|
|
102
|
+
expect(screen.queryByText("bal 50")).toBeNull();
|
|
103
|
+
|
|
104
|
+
await user.click(screen.getByLabelText("Go to next page"));
|
|
105
|
+
await waitFor(() => expect(screen.getByText("POST-05")).toBeTruthy());
|
|
106
|
+
expect(screen.getByText("bal 50"), "page two continues the fold").toBeTruthy();
|
|
107
|
+
expect(screen.getByText("bal 80")).toBeTruthy();
|
|
108
|
+
expect(screen.queryByText("bal 10"), "page one's opening balance is gone").toBeNull();
|
|
109
|
+
});
|
|
110
|
+
});
|
package/src/FrappeTable.tsx
CHANGED
|
@@ -3,9 +3,7 @@ import {
|
|
|
3
3
|
Order,
|
|
4
4
|
matchesFilters,
|
|
5
5
|
useDocTypeMeta,
|
|
6
|
-
useFrappeCollection,
|
|
7
6
|
useFrappeDoctypeEvents,
|
|
8
|
-
useLiveQuery,
|
|
9
7
|
} from "@multiplatform.one/frappe";
|
|
10
8
|
import {
|
|
11
9
|
DataTable,
|
|
@@ -25,12 +23,31 @@ import { FilterManager, SavedFilterDropdown, useSavedFilters } from "@multiplatf
|
|
|
25
23
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
26
24
|
import { FrappeReconnectIndicator } from "./FrappeReconnectIndicator";
|
|
27
25
|
import { docFieldsToFilterFields } from "./filterFields";
|
|
28
|
-
import {
|
|
26
|
+
import { useFrappeRows } from "./useFrappeRows";
|
|
29
27
|
|
|
30
28
|
/**
|
|
31
29
|
* Props for the FrappeTable component.
|
|
32
30
|
*
|
|
33
|
-
*
|
|
31
|
+
* `data` is omitted because FrappeTable fetches its own rows. Everything else
|
|
32
|
+
* on `DataTableProps` passes straight through — including `rowAccumulator`
|
|
33
|
+
* (MPO-250), so a Frappe-bound table CAN carry a folded column (a running
|
|
34
|
+
* balance, a per-row cumulative count) without the caller re-fetching the
|
|
35
|
+
* doctype and hand-assembling a DataTable. Declare the derived field on
|
|
36
|
+
* `TDoc` so a column can name it in `accessorKey`:
|
|
37
|
+
*
|
|
38
|
+
* ```tsx
|
|
39
|
+
* const balance: RowAccumulator<Partial<Posting>, string> = {
|
|
40
|
+
* initial: "0",
|
|
41
|
+
* reduce: (carried, row) => addMoney(carried, row.amount ?? "0"),
|
|
42
|
+
* derive: (carried) => ({ running: carried }),
|
|
43
|
+
* order: (a, b) => compareByDateThenName(a, b),
|
|
44
|
+
* };
|
|
45
|
+
* <FrappeTable<Posting & { running?: string }> doctype="Posting" rowAccumulator={balance} … />
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* The fold runs over the rows the table HOLDS, before pagination. In
|
|
49
|
+
* `serverSide` mode that is one page, so a running balance there needs the
|
|
50
|
+
* server to send the figure — the fold cannot invent rows it never got.
|
|
34
51
|
*/
|
|
35
52
|
export interface FrappeTableProps<TDoc extends { name: string; doctype: string }> extends Omit<
|
|
36
53
|
DataTableProps<Partial<TDoc>>,
|
|
@@ -310,8 +327,10 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
310
327
|
const finalAuth = auth ?? config?.auth;
|
|
311
328
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
312
329
|
|
|
313
|
-
|
|
314
|
-
|
|
330
|
+
// A fixture corpus is a complete data source, so it satisfies the same
|
|
331
|
+
// requirement a baseURL does: fixture mode never dials a server.
|
|
332
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
333
|
+
throw new Error("FrappeTable requires baseURL prop or FrappeProvider with baseURL or fixtures");
|
|
315
334
|
}
|
|
316
335
|
|
|
317
336
|
// One connection config for the live subscription (client mode), the
|
|
@@ -594,32 +613,31 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
594
613
|
// Always call the hook — toggling `savedFilters` must not change hook order (SB-M-012).
|
|
595
614
|
const savedFiltersHook = useSavedFilters({ userId });
|
|
596
615
|
|
|
597
|
-
//
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
)
|
|
608
|
-
},
|
|
616
|
+
// The client/live-collection read is the SHARED one (MPO-251): collection
|
|
617
|
+
// + live query + the honest error surface a bare collection swallows
|
|
618
|
+
// (without onSyncError a 403 or a dead server renders as an empty table).
|
|
619
|
+
// `limit: null` keeps the bench's own page length rather than the hook's
|
|
620
|
+
// default — FrappeTable paginates on the rows it is handed, and moving its
|
|
621
|
+
// row ceiling here would move it for every existing consumer.
|
|
622
|
+
const rowsMessages = useMemo(
|
|
623
|
+
() => ({
|
|
624
|
+
permission: t("You do not have permission to view {{doctype}}", { doctype }),
|
|
625
|
+
generic: t("Error loading {{doctype}}", { doctype }),
|
|
626
|
+
queryFailed: t("Failed to load {{doctype}}", { doctype }),
|
|
627
|
+
}),
|
|
609
628
|
[doctype, t],
|
|
610
629
|
);
|
|
611
|
-
|
|
612
|
-
const collection = useFrappeCollection<TDoc>(
|
|
613
|
-
serverSide ? undefined : connectionConfig,
|
|
614
|
-
serverSide ? "" : doctype,
|
|
615
|
-
serverSide ? undefined : { fields, filters: activeFilters, onSyncError: handleSyncError },
|
|
616
|
-
);
|
|
617
630
|
const {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
} =
|
|
622
|
-
|
|
631
|
+
rows: clientRows,
|
|
632
|
+
isQueryLoading: isRowsLoading,
|
|
633
|
+
error: liveError,
|
|
634
|
+
} = useFrappeRows<TDoc>(serverSide ? undefined : connectionConfig, doctype, {
|
|
635
|
+
fields,
|
|
636
|
+
filters: activeFilters,
|
|
637
|
+
limit: null,
|
|
638
|
+
enabled: !serverSide,
|
|
639
|
+
messages: rowsMessages,
|
|
640
|
+
});
|
|
623
641
|
|
|
624
642
|
// Keep-rows-and-reconcile for client/live-collection mode: a filter change
|
|
625
643
|
// swaps the collection (new subscription), which reports loading from
|
|
@@ -661,19 +679,6 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
661
679
|
? !infiniteServerMode && serverLoading && hasLoadedOnce
|
|
662
680
|
: isRowsLoading && lastGoodClientRows.current !== null;
|
|
663
681
|
|
|
664
|
-
// Reset stale errors when the underlying collection changes (new doctype
|
|
665
|
-
// or filters) so a recovered query doesn't keep showing the old failure.
|
|
666
|
-
useEffect(() => {
|
|
667
|
-
if (!serverSide) setErrorState(null);
|
|
668
|
-
}, [collection, serverSide]);
|
|
669
|
-
|
|
670
|
-
// Fallback surface for live-query failures the collection itself reports
|
|
671
|
-
// (onSyncError above carries the specific message when available).
|
|
672
|
-
useEffect(() => {
|
|
673
|
-
if (serverSide || !isLiveError) return;
|
|
674
|
-
setErrorState((prev) => prev ?? new Error(t("Failed to load {{doctype}}", { doctype })));
|
|
675
|
-
}, [serverSide, isLiveError, doctype, t]);
|
|
676
|
-
|
|
677
682
|
const handleSelectFilter = (filter: any) => {
|
|
678
683
|
if (filter) {
|
|
679
684
|
setActiveFilters(filter.filters);
|
|
@@ -697,8 +702,12 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
697
702
|
await savedFiltersHook.deleteFilter(name);
|
|
698
703
|
};
|
|
699
704
|
|
|
700
|
-
|
|
701
|
-
|
|
705
|
+
// serverSide failures come from the fetch above; client/live failures come
|
|
706
|
+
// from useFrappeRows. Only one path is ever live at a time.
|
|
707
|
+
const resolvedError = serverSide ? errorState : liveError;
|
|
708
|
+
|
|
709
|
+
if (resolvedError && error) {
|
|
710
|
+
return <>{error(resolvedError)}</>;
|
|
702
711
|
}
|
|
703
712
|
|
|
704
713
|
const rowData = rows ?? [];
|
|
@@ -706,8 +715,8 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
706
715
|
// Infinite serverSide delegates loading/empty chrome to DataTable.
|
|
707
716
|
// After the first load, NEVER replace DataTable with empty/loading chrome
|
|
708
717
|
// while a refetch is in flight — that was the named blank-the-list defect.
|
|
709
|
-
const boundaryState =
|
|
710
|
-
? { error:
|
|
718
|
+
const boundaryState = resolvedError
|
|
719
|
+
? { error: resolvedError }
|
|
711
720
|
: isRowsLoadingResolved
|
|
712
721
|
? { loading: loading ?? true }
|
|
713
722
|
: rowData.length === 0 && !infiniteServerMode && !isFetching
|
|
@@ -715,7 +724,16 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
715
724
|
: null;
|
|
716
725
|
if (boundaryState) {
|
|
717
726
|
return (
|
|
718
|
-
<YStack
|
|
727
|
+
<YStack
|
|
728
|
+
{...knobProps.gap}
|
|
729
|
+
// flexBasis auto, not flex={1}: a basis-0 chain resolves to 0 in an
|
|
730
|
+
// auto-height parent and collapses the table to a sliver. Same
|
|
731
|
+
// geometry as DataTableRoot's own root.
|
|
732
|
+
flexGrow={1}
|
|
733
|
+
flexShrink={1}
|
|
734
|
+
flexBasis="auto"
|
|
735
|
+
minHeight={0}
|
|
736
|
+
>
|
|
719
737
|
<FrappeReconnectIndicator config={connectionConfig} />
|
|
720
738
|
<AsyncBoundary
|
|
721
739
|
layout={layout === "list" || layout === "cards" ? "list" : "table"}
|
|
@@ -728,7 +746,16 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
|
|
|
728
746
|
}
|
|
729
747
|
|
|
730
748
|
return (
|
|
731
|
-
<YStack
|
|
749
|
+
<YStack
|
|
750
|
+
{...knobProps.gap}
|
|
751
|
+
// flexBasis auto, not flex={1}: a basis-0 chain resolves to 0 in an
|
|
752
|
+
// auto-height parent and collapses the table to a sliver. Same
|
|
753
|
+
// geometry as DataTableRoot's own root.
|
|
754
|
+
flexGrow={1}
|
|
755
|
+
flexShrink={1}
|
|
756
|
+
flexBasis="auto"
|
|
757
|
+
minHeight={0}
|
|
758
|
+
>
|
|
732
759
|
<FrappeReconnectIndicator config={connectionConfig} />
|
|
733
760
|
{savedFilters && savedFiltersHook && (
|
|
734
761
|
<XStack {...knobProps.gap} padding="$2">
|