@multiplatform.one/frappe-ui 7.7.6 → 7.10.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.cjs +7 -7
- package/dist/cjs/FormSidebar.native.js +7 -7
- 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.cjs +29 -3
- package/dist/cjs/FrappeChartCard.native.js +29 -3
- 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 +29 -3
- package/dist/cjs/FrappeKPICard.native.js +29 -3
- 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.cjs +6 -6
- package/dist/cjs/FrappeListView.native.js +6 -6
- 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.cjs +30 -2
- package/dist/cjs/fields/DateRange/index.native.js +34 -2
- 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.mjs +7 -7
- package/dist/esm/FormSidebar.mjs.map +1 -1
- package/dist/esm/FormSidebar.native.js +7 -7
- 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.mjs +30 -4
- package/dist/esm/FrappeChartCard.mjs.map +1 -1
- package/dist/esm/FrappeChartCard.native.js +30 -4
- 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 +30 -4
- package/dist/esm/FrappeKPICard.mjs.map +1 -1
- package/dist/esm/FrappeKPICard.native.js +30 -4
- 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.mjs +6 -6
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +6 -6
- 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.mjs +30 -2
- package/dist/esm/fields/DateRange/index.mjs.map +1 -1
- package/dist/esm/fields/DateRange/index.native.js +34 -2
- 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/FormSidebar.mjs +7 -7
- package/dist/jsx/FormSidebar.mjs.map +1 -1
- package/dist/jsx/FormSidebar.native.js +7 -7
- package/dist/jsx/FormSidebar.native.js.map +1 -1
- 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/FrappeChartCard.mjs +30 -4
- package/dist/jsx/FrappeChartCard.mjs.map +1 -1
- package/dist/jsx/FrappeChartCard.native.js +29 -3
- package/dist/jsx/FrappeChartCard.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 +30 -4
- package/dist/jsx/FrappeKPICard.mjs.map +1 -1
- package/dist/jsx/FrappeKPICard.native.js +29 -3
- 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/FrappeListView.mjs +6 -6
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +6 -6
- package/dist/jsx/FrappeListView.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/DateRange/index.mjs +30 -2
- package/dist/jsx/fields/DateRange/index.mjs.map +1 -1
- package/dist/jsx/fields/DateRange/index.native.js +34 -2
- package/dist/jsx/fields/DateRange/index.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/FormSidebar.tsx +7 -7
- package/src/FrappeCalendar.tsx +25 -22
- package/src/FrappeChartCard.spec.tsx +179 -0
- package/src/FrappeChartCard.tsx +55 -6
- package/src/FrappeForm.tsx +7 -3
- package/src/FrappeGantt.tsx +29 -39
- package/src/FrappeImageView.tsx +5 -3
- package/src/FrappeKPICard.spec.tsx +153 -0
- package/src/FrappeKPICard.tsx +52 -6
- package/src/FrappeKanban.tsx +24 -17
- package/src/FrappeLikedBy.tsx +1 -1
- package/src/FrappeList.tsx +3 -2
- package/src/FrappeListView.tsx +6 -6
- 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/Date.spec.tsx +8 -1
- package/src/fields/Date/nativePresentation.spec.tsx +8 -1
- package/src/fields/Date/typeParity.spec.tsx +27 -10
- package/src/fields/DateRange/DateRange.spec.tsx +87 -15
- package/src/fields/DateRange/index.tsx +47 -3
- 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 +44 -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/FrappeChartCard.d.ts +17 -1
- package/types/FrappeChartCard.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 +14 -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/DateRange/index.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,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-237: a `dataSource` with no `baseURL` in scope is a misconfiguration,
|
|
3
|
+
* not static mode. The card asked for a computed figure and there is nowhere
|
|
4
|
+
* to compute it, so `config.value` must never be painted as the KPI: a wrong
|
|
5
|
+
* number presented confidently is worse than a visible gap, because nothing
|
|
6
|
+
* downstream can tell it was never computed.
|
|
7
|
+
*
|
|
8
|
+
* Static mode (no `dataSource` at all) is the documented, intended path and
|
|
9
|
+
* is asserted here too, so the fix cannot over-correct into it.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
13
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
14
|
+
import { cleanup, screen, waitFor } from "@testing-library/react";
|
|
15
|
+
import i18next from "i18next";
|
|
16
|
+
import { initReactI18next } from "react-i18next";
|
|
17
|
+
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
|
18
|
+
import { FrappeKPICard } from "./FrappeKPICard";
|
|
19
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
20
|
+
import { __resetFrappeDevWarnSeen } from "./shared/devWarn";
|
|
21
|
+
|
|
22
|
+
beforeAll(async () => {
|
|
23
|
+
await i18next.use(initReactI18next).init({
|
|
24
|
+
lng: "en",
|
|
25
|
+
interpolation: { escapeValue: false },
|
|
26
|
+
resources: { en: { translation: {} } },
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
__resetFrappeDevWarnSeen();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
cleanup();
|
|
36
|
+
vi.restoreAllMocks();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const config = { id: "open-todos", title: "Open ToDos", value: 999, format: "number" as const };
|
|
40
|
+
|
|
41
|
+
describe("FrappeKPICard with a dataSource and no baseURL (MPO-237)", () => {
|
|
42
|
+
it("does not render config.value as though it were the computed figure", () => {
|
|
43
|
+
vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
44
|
+
renderWithProviders(<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />);
|
|
45
|
+
|
|
46
|
+
expect(screen.queryByText("999")).toBeNull();
|
|
47
|
+
expect(screen.getByText("Open ToDos is not configured")).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByText(/no Frappe baseURL is in scope/)).toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("logs a development warning naming the missing baseURL", () => {
|
|
52
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
53
|
+
renderWithProviders(<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />);
|
|
54
|
+
|
|
55
|
+
const line = warn.mock.calls.map((call) => String(call[0])).join("\n");
|
|
56
|
+
expect(line).toContain("[frappe-ui] kpi-datasource-without-baseurl");
|
|
57
|
+
expect(line).toContain("baseURL");
|
|
58
|
+
expect(line).toContain("component=FrappeKPICard");
|
|
59
|
+
expect(line).toContain("id=open-todos");
|
|
60
|
+
expect(line).toContain("doctype=ToDo");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("warns once per card, not once per render", () => {
|
|
64
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
65
|
+
const { rerender } = renderWithProviders(
|
|
66
|
+
<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />,
|
|
67
|
+
);
|
|
68
|
+
rerender(<FrappeKPICard config={{ ...config }} dataSource={{ doctype: "ToDo" }} />);
|
|
69
|
+
rerender(<FrappeKPICard config={{ ...config }} dataSource={{ doctype: "ToDo" }} />);
|
|
70
|
+
|
|
71
|
+
const lines = warn.mock.calls.filter((call) =>
|
|
72
|
+
String(call[0]).includes("kpi-datasource-without-baseurl"),
|
|
73
|
+
);
|
|
74
|
+
expect(lines).toHaveLength(1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("stays silent in production", () => {
|
|
78
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
79
|
+
const previous = process.env.NODE_ENV;
|
|
80
|
+
process.env.NODE_ENV = "production";
|
|
81
|
+
try {
|
|
82
|
+
renderWithProviders(<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />);
|
|
83
|
+
} finally {
|
|
84
|
+
process.env.NODE_ENV = previous;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
expect(
|
|
88
|
+
warn.mock.calls.filter((call) => String(call[0]).includes("kpi-datasource-without-baseurl")),
|
|
89
|
+
).toHaveLength(0);
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
describe("FrappeKPICard configured paths stay untouched (MPO-237)", () => {
|
|
94
|
+
it("renders config.value with no warning when no dataSource is set", () => {
|
|
95
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
96
|
+
renderWithProviders(<FrappeKPICard config={config} />);
|
|
97
|
+
|
|
98
|
+
expect(screen.getByText("999")).toBeInTheDocument();
|
|
99
|
+
expect(
|
|
100
|
+
warn.mock.calls.filter((call) => String(call[0]).includes("kpi-datasource-without-baseurl")),
|
|
101
|
+
).toHaveLength(0);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("computes the figure, and does not warn, when the provider supplies a baseURL", async () => {
|
|
105
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
106
|
+
renderWithProviders(
|
|
107
|
+
<FrappeProvider
|
|
108
|
+
baseURL="http://test"
|
|
109
|
+
fixtures={
|
|
110
|
+
new InMemoryFixtureProvider({
|
|
111
|
+
ToDo: [
|
|
112
|
+
{ name: "TD-1", doctype: "ToDo", status: "Open" },
|
|
113
|
+
{ name: "TD-2", doctype: "ToDo", status: "Open" },
|
|
114
|
+
],
|
|
115
|
+
})
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />
|
|
119
|
+
</FrappeProvider>,
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
await waitFor(() => expect(screen.getByText("2")).toBeInTheDocument());
|
|
123
|
+
expect(screen.queryByText("999")).toBeNull();
|
|
124
|
+
expect(
|
|
125
|
+
warn.mock.calls.filter((call) => String(call[0]).includes("kpi-datasource-without-baseurl")),
|
|
126
|
+
).toHaveLength(0);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("treats a fixture corpus as the data source when no baseURL is set (MPO-228)", async () => {
|
|
130
|
+
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
|
|
131
|
+
renderWithProviders(
|
|
132
|
+
<FrappeProvider
|
|
133
|
+
fixtures={
|
|
134
|
+
new InMemoryFixtureProvider({
|
|
135
|
+
ToDo: [
|
|
136
|
+
{ name: "TD-1", doctype: "ToDo", status: "Open" },
|
|
137
|
+
{ name: "TD-2", doctype: "ToDo", status: "Open" },
|
|
138
|
+
],
|
|
139
|
+
})
|
|
140
|
+
}
|
|
141
|
+
>
|
|
142
|
+
<FrappeKPICard config={config} dataSource={{ doctype: "ToDo" }} />
|
|
143
|
+
</FrappeProvider>,
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
await waitFor(() => expect(screen.getByText("2")).toBeInTheDocument());
|
|
147
|
+
expect(screen.queryByText("999")).toBeNull();
|
|
148
|
+
expect(screen.queryByText("Open ToDos is not configured")).toBeNull();
|
|
149
|
+
expect(
|
|
150
|
+
warn.mock.calls.filter((call) => String(call[0]).includes("kpi-datasource-without-baseurl")),
|
|
151
|
+
).toHaveLength(0);
|
|
152
|
+
});
|
|
153
|
+
});
|
package/src/FrappeKPICard.tsx
CHANGED
|
@@ -11,6 +11,14 @@
|
|
|
11
11
|
* (permission failures called out explicitly), a subtle stale affordance
|
|
12
12
|
* (the card dims while a post-event refetch is in flight), and "—" when the
|
|
13
13
|
* aggregate has no result (e.g. avg over an empty set).
|
|
14
|
+
*
|
|
15
|
+
* A `dataSource` with no data source in scope — no `baseURL` from the prop
|
|
16
|
+
* or a FrappeProvider, and no fixture corpus either — is a misconfiguration,
|
|
17
|
+
* not static mode: the caller asked for a computed figure and there is
|
|
18
|
+
* nowhere to compute it. The card renders the not-configured surface and
|
|
19
|
+
* warns in dev. It never falls back to `config.value`, which would present
|
|
20
|
+
* an uncomputed number as the KPI. A fixture corpus answers every read
|
|
21
|
+
* locally, so it stands in for a baseURL (MPO-228).
|
|
14
22
|
*/
|
|
15
23
|
import {
|
|
16
24
|
AsyncBoundary,
|
|
@@ -19,10 +27,11 @@ import {
|
|
|
19
27
|
Skeleton,
|
|
20
28
|
type KPICardConfig,
|
|
21
29
|
} from "@multiplatform.one/components";
|
|
22
|
-
import React, { useMemo } from "react";
|
|
30
|
+
import React, { useEffect, useMemo } from "react";
|
|
23
31
|
import { useTranslation } from "react-i18next";
|
|
24
32
|
import { type YStackProps } from "tamagui";
|
|
25
33
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
34
|
+
import { frappeDevWarn } from "./shared/devWarn";
|
|
26
35
|
import {
|
|
27
36
|
useFrappeAggregate,
|
|
28
37
|
type FrappeAggregateConnection,
|
|
@@ -44,11 +53,16 @@ export interface FrappeKPIDataSource {
|
|
|
44
53
|
export interface FrappeKPICardProps extends Omit<YStackProps, "children"> {
|
|
45
54
|
/**
|
|
46
55
|
* KPI chrome (title, format, trend, icon…). In live mode `value` is
|
|
47
|
-
* overridden by the aggregate; in static mode it renders as-is.
|
|
56
|
+
* overridden by the aggregate; in static mode it renders as-is. With a
|
|
57
|
+
* `dataSource` and no `baseURL`, `value` is not rendered at all.
|
|
48
58
|
*/
|
|
49
59
|
config: KPICardConfig;
|
|
50
60
|
/** When set, the card's value goes live against this doctype. */
|
|
51
61
|
dataSource?: FrappeKPIDataSource;
|
|
62
|
+
/**
|
|
63
|
+
* Falls back to the FrappeProvider's. Required whenever `dataSource` is
|
|
64
|
+
* set, unless the provider carries a fixture corpus.
|
|
65
|
+
*/
|
|
52
66
|
baseURL?: string;
|
|
53
67
|
auth?: { useToken?: boolean; token?: string; type?: string };
|
|
54
68
|
syncOptions?: unknown;
|
|
@@ -78,8 +92,9 @@ export function FrappeKPICard({
|
|
|
78
92
|
const { t } = useTranslation();
|
|
79
93
|
|
|
80
94
|
const finalBaseURL = baseURL ?? providerConfig?.baseURL;
|
|
95
|
+
const fixtures = providerConfig?.fixtures;
|
|
81
96
|
const connection: FrappeAggregateConnection | undefined =
|
|
82
|
-
dataSource && finalBaseURL
|
|
97
|
+
dataSource && (finalBaseURL || fixtures)
|
|
83
98
|
? {
|
|
84
99
|
baseURL: finalBaseURL,
|
|
85
100
|
socketPort: providerConfig?.socketPort,
|
|
@@ -88,10 +103,22 @@ export function FrappeKPICard({
|
|
|
88
103
|
auth: auth ?? providerConfig?.auth,
|
|
89
104
|
syncOptions: syncOptions ?? providerConfig?.syncOptions,
|
|
90
105
|
realtime: providerConfig?.realtime,
|
|
91
|
-
fixtures
|
|
106
|
+
fixtures,
|
|
92
107
|
}
|
|
93
108
|
: undefined;
|
|
94
109
|
|
|
110
|
+
const missingConnection = !!dataSource && !connection;
|
|
111
|
+
const doctype = dataSource?.doctype;
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
if (!missingConnection) return;
|
|
114
|
+
frappeDevWarn("kpi-datasource-without-baseurl", {
|
|
115
|
+
component: "FrappeKPICard",
|
|
116
|
+
id: config.id,
|
|
117
|
+
doctype,
|
|
118
|
+
suggest: "set baseURL on FrappeKPICard or on the FrappeProvider above it",
|
|
119
|
+
});
|
|
120
|
+
}, [missingConnection, config.id, doctype]);
|
|
121
|
+
|
|
95
122
|
const { value, isLoading, isStale, error, isPermissionError } = useFrappeAggregate(connection, {
|
|
96
123
|
doctype: dataSource?.doctype ?? "",
|
|
97
124
|
aggregate: dataSource?.aggregate,
|
|
@@ -106,11 +133,30 @@ export function FrappeKPICard({
|
|
|
106
133
|
return { ...config, value: value ?? "—" };
|
|
107
134
|
}, [config, dataSource, value]);
|
|
108
135
|
|
|
109
|
-
// Static passthrough
|
|
110
|
-
|
|
136
|
+
// Static passthrough. The caller supplied the figure and asked for no
|
|
137
|
+
// computation.
|
|
138
|
+
if (!dataSource) {
|
|
111
139
|
return <KPICard config={config} {...stackProps} />;
|
|
112
140
|
}
|
|
113
141
|
|
|
142
|
+
// A requested figure with nowhere to compute it. `config.value` is the
|
|
143
|
+
// caller's placeholder, so painting it here would publish a number nothing
|
|
144
|
+
// downstream could tell was never computed.
|
|
145
|
+
if (!connection) {
|
|
146
|
+
return (
|
|
147
|
+
<AsyncBoundary
|
|
148
|
+
compact
|
|
149
|
+
error
|
|
150
|
+
errorTitle={t("{{title}} is not configured", { title: config.title })}
|
|
151
|
+
errorDescription={t(
|
|
152
|
+
"This card reads {{doctype}} live, but no Frappe baseURL is in scope, so the figure was never computed.",
|
|
153
|
+
{ doctype: dataSource.doctype },
|
|
154
|
+
)}
|
|
155
|
+
{...stackProps}
|
|
156
|
+
/>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
114
160
|
if (isLoading) {
|
|
115
161
|
return <KPICardSkeleton {...stackProps} />;
|
|
116
162
|
}
|
package/src/FrappeKanban.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useFrappeCollection, useLiveQuery } from "@multiplatform.one/frappe";
|
|
2
1
|
import {
|
|
3
2
|
Kanban,
|
|
4
3
|
componentColors,
|
|
@@ -15,6 +14,7 @@ import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
|
15
14
|
import { FrappeConnectionIndicator } from "./FrappeConnectionIndicator";
|
|
16
15
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
17
16
|
import { describeSyncError } from "./syncError";
|
|
17
|
+
import { useFrappeRows } from "./useFrappeRows";
|
|
18
18
|
|
|
19
19
|
/**
|
|
20
20
|
* Configuration for a single Kanban column.
|
|
@@ -91,16 +91,15 @@ export function FrappeKanban<TDoc extends { name: string; doctype: string }>({
|
|
|
91
91
|
const { knobProps } = useResolvedKnobs();
|
|
92
92
|
const { t } = useTranslation();
|
|
93
93
|
const [actionError, setActionError] = useState<Error | null>(null);
|
|
94
|
-
// Honest error state: the collection swallows failed subscription fetches
|
|
95
|
-
// (board would just look empty) — onSyncError reports them here.
|
|
96
|
-
const [syncError, setSyncError] = useState<unknown>(null);
|
|
97
94
|
|
|
98
95
|
const finalBaseURL = baseURL ?? config?.baseURL;
|
|
99
96
|
const finalAuth = auth ?? config?.auth;
|
|
100
97
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
101
98
|
|
|
102
|
-
if (!finalBaseURL) {
|
|
103
|
-
throw new Error(
|
|
99
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
100
|
+
throw new Error(
|
|
101
|
+
"FrappeKanban requires baseURL prop or FrappeProvider with baseURL or fixtures",
|
|
102
|
+
);
|
|
104
103
|
}
|
|
105
104
|
|
|
106
105
|
// Ensure required fields are fetched
|
|
@@ -139,17 +138,25 @@ export function FrappeKanban<TDoc extends { name: string; doctype: string }>({
|
|
|
139
138
|
],
|
|
140
139
|
);
|
|
141
140
|
|
|
142
|
-
|
|
141
|
+
// The shared doctype read (MPO-251). `mapError` keeps this board's own
|
|
142
|
+
// error copy (describeSyncError) rather than the hook's default shape, and
|
|
143
|
+
// `limit: null` keeps the bench's own page length.
|
|
144
|
+
const mapSyncError = useCallback(
|
|
145
|
+
(err: unknown) => new Error(describeSyncError(err, doctype, t)),
|
|
146
|
+
[doctype, t],
|
|
147
|
+
);
|
|
148
|
+
const {
|
|
149
|
+
rows: cards,
|
|
150
|
+
isQueryLoading: isLoading,
|
|
151
|
+
isError,
|
|
152
|
+
syncError,
|
|
153
|
+
collection,
|
|
154
|
+
} = useFrappeRows<TDoc>(connectionConfig, doctype, {
|
|
143
155
|
fields: effectiveFields,
|
|
144
156
|
filters,
|
|
145
|
-
|
|
157
|
+
limit: null,
|
|
158
|
+
mapError: mapSyncError,
|
|
146
159
|
});
|
|
147
|
-
const {
|
|
148
|
-
data: rawData,
|
|
149
|
-
isLoading,
|
|
150
|
-
isError,
|
|
151
|
-
} = useLiveQuery((q) => (collection ? q.from({ _list: collection }) : null), [collection]);
|
|
152
|
-
const cards = useMemo(() => (rawData as TDoc[] | undefined) ?? [], [rawData]);
|
|
153
160
|
|
|
154
161
|
// Group cards by status into generic KanbanColumn format.
|
|
155
162
|
// Cards with an unknown status land in an "Unassigned" column so they
|
|
@@ -286,9 +293,9 @@ export function FrappeKanban<TDoc extends { name: string; doctype: string }>({
|
|
|
286
293
|
// Real subscription failure (permission-error, network, bad doctype)
|
|
287
294
|
// reported by the collection via onSyncError — honest error UI instead of
|
|
288
295
|
// an empty board. The `error` render prop stays the consumer override.
|
|
289
|
-
const boardError = syncError
|
|
290
|
-
if (
|
|
291
|
-
return <>{error(
|
|
296
|
+
const boardError = syncError ? syncError.message : null;
|
|
297
|
+
if (syncError && error) {
|
|
298
|
+
return <>{error(syncError)}</>;
|
|
292
299
|
}
|
|
293
300
|
|
|
294
301
|
// Opt-in query error panel via `error` prop. Empty/fixture-less collections
|
package/src/FrappeLikedBy.tsx
CHANGED
|
@@ -168,7 +168,7 @@ function FrappeLikedByBody({
|
|
|
168
168
|
|
|
169
169
|
const http = useMemo(
|
|
170
170
|
() =>
|
|
171
|
-
config && !config.fixtures
|
|
171
|
+
config?.baseURL && !config.fixtures
|
|
172
172
|
? new HttpClient(
|
|
173
173
|
config.baseURL,
|
|
174
174
|
config.auth as Parameters<typeof HttpClient.prototype.updateAuth>[0],
|
package/src/FrappeList.tsx
CHANGED
|
@@ -51,8 +51,9 @@ export function FrappeList<TDoc extends { name: string; doctype: string }>({
|
|
|
51
51
|
const finalAuth = auth ?? config?.auth;
|
|
52
52
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// Fixtures answer every read locally, so they stand in for a baseURL.
|
|
55
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
56
|
+
throw new Error("FrappeList requires baseURL prop or FrappeProvider with baseURL or fixtures");
|
|
56
57
|
}
|
|
57
58
|
|
|
58
59
|
const connectionConfig = useMemo(
|
package/src/FrappeListView.tsx
CHANGED
|
@@ -298,7 +298,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
298
298
|
{title}
|
|
299
299
|
</Text>
|
|
300
300
|
{subtitleParts.length > 0 && (
|
|
301
|
-
<Text {...knobProps.body} color={
|
|
301
|
+
<Text {...knobProps.body} color={knobProps.textAccentColor} numberOfLines={1}>
|
|
302
302
|
{subtitleParts.map((part, index) => (
|
|
303
303
|
<React.Fragment key={index}>
|
|
304
304
|
{index > 0 ? " · " : null}
|
|
@@ -432,7 +432,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
432
432
|
{...stackProps}
|
|
433
433
|
>
|
|
434
434
|
<Spinner size="large" />
|
|
435
|
-
<Text {...knobProps.body} color={
|
|
435
|
+
<Text {...knobProps.body} color={knobProps.textAccentColor} marginTop="$2">
|
|
436
436
|
{t("Loading {{doctype}} schema...", { doctype })}
|
|
437
437
|
</Text>
|
|
438
438
|
</YStack>
|
|
@@ -517,17 +517,17 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
517
517
|
{...knobProps.panelPadding}
|
|
518
518
|
{...knobProps.gap}
|
|
519
519
|
>
|
|
520
|
-
<Text {...knobProps.label} color={
|
|
520
|
+
<Text {...knobProps.label} color={knobProps.textAccentColor}>
|
|
521
521
|
{t("Filters")}
|
|
522
522
|
</Text>
|
|
523
523
|
{standardFilterFields.length > 0 && (
|
|
524
524
|
<YStack {...knobProps.gap}>
|
|
525
525
|
{standardFilterFields.map((field) => (
|
|
526
526
|
<YStack key={field.fieldname} {...knobProps.gap}>
|
|
527
|
-
<Text {...knobProps.label} color={
|
|
527
|
+
<Text {...knobProps.label} color={knobProps.textAccentColor}>
|
|
528
528
|
{field.label || field.fieldname}
|
|
529
529
|
</Text>
|
|
530
|
-
<Text {...knobProps.body} color={
|
|
530
|
+
<Text {...knobProps.body} color={knobProps.textAccentColor}>
|
|
531
531
|
{field.fieldtype === "Select" ? field.options || "—" : "—"}
|
|
532
532
|
</Text>
|
|
533
533
|
</YStack>
|
|
@@ -536,7 +536,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
536
536
|
)}
|
|
537
537
|
{savedFiltersHook.filters.length > 0 && (
|
|
538
538
|
<YStack {...knobProps.gap}>
|
|
539
|
-
<Text {...knobProps.label} color={
|
|
539
|
+
<Text {...knobProps.label} color={knobProps.textAccentColor}>
|
|
540
540
|
{t("Saved Filters")}
|
|
541
541
|
</Text>
|
|
542
542
|
<SavedFilterDropdown
|
|
@@ -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 = {
|