@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
package/src/FrappeCalendar.tsx
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useFrappeCollection, useLiveQuery } from "@multiplatform.one/frappe";
|
|
2
1
|
import {
|
|
3
2
|
Calendar,
|
|
4
3
|
eventChipTextColor,
|
|
@@ -18,6 +17,7 @@ import {
|
|
|
18
17
|
import { FrappeConnectionIndicator } from "./FrappeConnectionIndicator";
|
|
19
18
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
20
19
|
import { describeSyncError } from "./syncError";
|
|
20
|
+
import { useFrappeRows } from "./useFrappeRows";
|
|
21
21
|
import { resolveFrappeEventColor } from "./frappeEventColor";
|
|
22
22
|
|
|
23
23
|
export type CalendarViewType = "month" | "week" | "day";
|
|
@@ -111,9 +111,6 @@ export function FrappeCalendar<TDoc extends { name: string; doctype: string }>({
|
|
|
111
111
|
const { knobProps } = useResolvedKnobs();
|
|
112
112
|
const { t } = useTranslation();
|
|
113
113
|
const [actionError, setActionError] = useState<Error | null>(null);
|
|
114
|
-
// Honest error state: the collection swallows failed subscription fetches
|
|
115
|
-
// (calendar would just look empty) — onSyncError reports them here.
|
|
116
|
-
const [syncError, setSyncError] = useState<unknown>(null);
|
|
117
114
|
const height =
|
|
118
115
|
heightProp ?? (knobProps.sizeToken === "$3" ? 480 : knobProps.sizeToken === "$5" ? 720 : 600);
|
|
119
116
|
|
|
@@ -121,8 +118,10 @@ export function FrappeCalendar<TDoc extends { name: string; doctype: string }>({
|
|
|
121
118
|
const finalAuth = auth ?? config?.auth;
|
|
122
119
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
123
120
|
|
|
124
|
-
if (!finalBaseURL) {
|
|
125
|
-
throw new Error(
|
|
121
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
122
|
+
throw new Error(
|
|
123
|
+
"FrappeCalendar requires baseURL prop or FrappeProvider with baseURL or fixtures",
|
|
124
|
+
);
|
|
126
125
|
}
|
|
127
126
|
|
|
128
127
|
// Ensure required fields are fetched
|
|
@@ -163,25 +162,29 @@ export function FrappeCalendar<TDoc extends { name: string; doctype: string }>({
|
|
|
163
162
|
],
|
|
164
163
|
);
|
|
165
164
|
|
|
166
|
-
|
|
165
|
+
// The shared doctype read (MPO-251). `mapError` keeps this calendar's own
|
|
166
|
+
// error copy (describeSyncError); real subscription failures still win over
|
|
167
|
+
// the generic isError flag inside the hook, because they carry an
|
|
168
|
+
// actionable message. `limit: null` keeps the bench's own page length.
|
|
169
|
+
const mapSyncError = useCallback(
|
|
170
|
+
(err: unknown) => new Error(describeSyncError(err, doctype, t)),
|
|
171
|
+
[doctype, t],
|
|
172
|
+
);
|
|
173
|
+
const {
|
|
174
|
+
rows: docs,
|
|
175
|
+
isQueryLoading: isLoading,
|
|
176
|
+
error: queryError,
|
|
177
|
+
collection,
|
|
178
|
+
} = useFrappeRows<TDoc>(connectionConfig, doctype, {
|
|
167
179
|
fields: effectiveFields,
|
|
168
180
|
filters,
|
|
169
|
-
|
|
181
|
+
limit: null,
|
|
182
|
+
mapError: mapSyncError,
|
|
183
|
+
messages: {
|
|
184
|
+
permission: t("You do not have permission to view {{doctype}}", { doctype }),
|
|
185
|
+
generic: t("Failed to load {{doctype}} events", { doctype }),
|
|
186
|
+
},
|
|
170
187
|
});
|
|
171
|
-
const {
|
|
172
|
-
data: rawData,
|
|
173
|
-
isLoading,
|
|
174
|
-
isError,
|
|
175
|
-
} = useLiveQuery((q) => (collection ? q.from({ _list: collection }) : null), [collection]);
|
|
176
|
-
const docs = useMemo(() => (rawData as TDoc[] | undefined) ?? [], [rawData]);
|
|
177
|
-
// Real subscription failures (permission-error, network, bad doctype) win
|
|
178
|
-
// over the generic isError flag — they carry an actionable message.
|
|
179
|
-
const queryError =
|
|
180
|
-
syncError != null
|
|
181
|
-
? new Error(describeSyncError(syncError, doctype, t))
|
|
182
|
-
: isError
|
|
183
|
-
? new Error(t("Failed to load {{doctype}} events", { doctype }))
|
|
184
|
-
: null;
|
|
185
188
|
|
|
186
189
|
// Scheme-aware palette for resolving NAMED doc colors (P-15): Frappe's
|
|
187
190
|
// palette references ("blue", "Red") map to sanctioned solids per scheme;
|
package/src/FrappeForm.tsx
CHANGED
|
@@ -171,11 +171,15 @@ export interface AssignmentTodoRow {
|
|
|
171
171
|
reference_name?: string;
|
|
172
172
|
}
|
|
173
173
|
|
|
174
|
-
/**
|
|
175
|
-
|
|
174
|
+
/**
|
|
175
|
+
* Resolves a Frappe file field value (e.g. `/files/x.png`) to a full URL.
|
|
176
|
+
* A site-relative path needs a server to hang off, so it resolves to nothing
|
|
177
|
+
* on a fixtures-only host (no baseURL); absolute URLs still pass through.
|
|
178
|
+
*/
|
|
179
|
+
export function resolveFileUrl(value: unknown, baseURL: string | undefined): string | undefined {
|
|
176
180
|
if (!value || typeof value !== "string") return undefined;
|
|
177
181
|
if (value.startsWith("http://") || value.startsWith("https://")) return value;
|
|
178
|
-
if (value.startsWith("/")) return `${baseURL.replace(/\/$/, "")}${value}
|
|
182
|
+
if (value.startsWith("/")) return baseURL ? `${baseURL.replace(/\/$/, "")}${value}` : undefined;
|
|
179
183
|
return value;
|
|
180
184
|
}
|
|
181
185
|
|
package/src/FrappeGantt.tsx
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import { useFrappeCollection, useLiveQuery } from "@multiplatform.one/frappe";
|
|
2
1
|
import {
|
|
2
|
+
Alert,
|
|
3
3
|
GanttView,
|
|
4
4
|
type GanttItemMoveRange,
|
|
5
5
|
type GanttTask,
|
|
6
6
|
type GanttZoom,
|
|
7
7
|
} from "@multiplatform.one/components";
|
|
8
8
|
import React, { useCallback, useMemo, useState, type ReactNode } from "react";
|
|
9
|
-
import {
|
|
9
|
+
import { YStack, type YStackProps } from "tamagui";
|
|
10
10
|
import { useTranslation } from "react-i18next";
|
|
11
|
-
import { formCommonColors } from "@multiplatform.one/forms";
|
|
12
11
|
import {
|
|
13
12
|
formatCalendarDate,
|
|
14
13
|
parseCalendarDate,
|
|
@@ -18,6 +17,7 @@ import {
|
|
|
18
17
|
import { FrappeConnectionIndicator } from "./FrappeConnectionIndicator";
|
|
19
18
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
20
19
|
import { describeSyncError } from "./syncError";
|
|
20
|
+
import { useFrappeRows } from "./useFrappeRows";
|
|
21
21
|
import { resolveFrappeEventColor } from "./frappeEventColor";
|
|
22
22
|
|
|
23
23
|
export interface FrappeGanttProps<TDoc extends { name: string; doctype: string }> extends Omit<
|
|
@@ -113,16 +113,13 @@ export function FrappeGantt<TDoc extends { name: string; doctype: string }>({
|
|
|
113
113
|
const { knobProps } = useResolvedKnobs();
|
|
114
114
|
const { t } = useTranslation();
|
|
115
115
|
const [actionError, setActionError] = useState<Error | null>(null);
|
|
116
|
-
// Honest error state: the collection swallows failed subscription fetches
|
|
117
|
-
// (the chart would just look empty) — onSyncError reports them here.
|
|
118
|
-
const [syncError, setSyncError] = useState<unknown>(null);
|
|
119
116
|
|
|
120
117
|
const finalBaseURL = baseURL ?? config?.baseURL;
|
|
121
118
|
const finalAuth = auth ?? config?.auth;
|
|
122
119
|
const finalSyncOptions = syncOptions ?? config?.syncOptions;
|
|
123
120
|
|
|
124
|
-
if (!finalBaseURL) {
|
|
125
|
-
throw new Error("FrappeGantt requires baseURL prop or FrappeProvider with baseURL");
|
|
121
|
+
if (!finalBaseURL && !config?.fixtures) {
|
|
122
|
+
throw new Error("FrappeGantt requires baseURL prop or FrappeProvider with baseURL or fixtures");
|
|
126
123
|
}
|
|
127
124
|
|
|
128
125
|
// Ensure required fields are fetched
|
|
@@ -162,25 +159,29 @@ export function FrappeGantt<TDoc extends { name: string; doctype: string }>({
|
|
|
162
159
|
],
|
|
163
160
|
);
|
|
164
161
|
|
|
165
|
-
|
|
162
|
+
// The shared doctype read (MPO-251). `mapError` keeps this chart's own
|
|
163
|
+
// error copy (describeSyncError); real subscription failures still win over
|
|
164
|
+
// the generic isError flag inside the hook, because they carry an
|
|
165
|
+
// actionable message. `limit: null` keeps the bench's own page length.
|
|
166
|
+
const mapSyncError = useCallback(
|
|
167
|
+
(err: unknown) => new Error(describeSyncError(err, doctype, t)),
|
|
168
|
+
[doctype, t],
|
|
169
|
+
);
|
|
170
|
+
const {
|
|
171
|
+
rows: docs,
|
|
172
|
+
isQueryLoading: isLoading,
|
|
173
|
+
error: queryError,
|
|
174
|
+
collection,
|
|
175
|
+
} = useFrappeRows<TDoc>(connectionConfig, doctype, {
|
|
166
176
|
fields: effectiveFields,
|
|
167
177
|
filters,
|
|
168
|
-
|
|
178
|
+
limit: null,
|
|
179
|
+
mapError: mapSyncError,
|
|
180
|
+
messages: {
|
|
181
|
+
permission: t("You do not have permission to view {{doctype}}", { doctype }),
|
|
182
|
+
generic: t("Failed to load {{doctype}} tasks", { doctype }),
|
|
183
|
+
},
|
|
169
184
|
});
|
|
170
|
-
const {
|
|
171
|
-
data: rawData,
|
|
172
|
-
isLoading,
|
|
173
|
-
isError,
|
|
174
|
-
} = useLiveQuery((q) => (collection ? q.from({ _list: collection }) : null), [collection]);
|
|
175
|
-
const docs = useMemo(() => (rawData as TDoc[] | undefined) ?? [], [rawData]);
|
|
176
|
-
// Real subscription failures (permission-error, network, bad doctype) win
|
|
177
|
-
// over the generic isError flag — they carry an actionable message.
|
|
178
|
-
const queryError =
|
|
179
|
-
syncError !== null && syncError !== undefined
|
|
180
|
-
? new Error(describeSyncError(syncError, doctype, t))
|
|
181
|
-
: isError
|
|
182
|
-
? new Error(t("Failed to load {{doctype}} tasks", { doctype }))
|
|
183
|
-
: null;
|
|
184
185
|
|
|
185
186
|
// Scheme-aware palette for resolving NAMED doc colors (P-15 / LC-27):
|
|
186
187
|
// Frappe's palette references ("blue", "Red") map to sanctioned solids per
|
|
@@ -255,23 +256,12 @@ export function FrappeGantt<TDoc extends { name: string; doctype: string }>({
|
|
|
255
256
|
<YStack {...knobProps.gap}>
|
|
256
257
|
<FrappeConnectionIndicator config={connectionConfig} />
|
|
257
258
|
{actionError ? (
|
|
258
|
-
<
|
|
259
|
-
{
|
|
260
|
-
|
|
261
|
-
backgroundColor="$red2"
|
|
262
|
-
borderColor="$red7"
|
|
263
|
-
borderWidth={1}
|
|
264
|
-
>
|
|
265
|
-
<Text color={formCommonColors.error} {...knobProps.label}>
|
|
266
|
-
{t("Action failed")}
|
|
267
|
-
</Text>
|
|
268
|
-
<Text color={formCommonColors.muted} {...knobProps.label}>
|
|
269
|
-
{actionError.message}
|
|
270
|
-
</Text>
|
|
271
|
-
</YStack>
|
|
259
|
+
<Alert intent="error" title={t("Action failed")}>
|
|
260
|
+
{actionError.message}
|
|
261
|
+
</Alert>
|
|
272
262
|
) : null}
|
|
273
263
|
<GanttView
|
|
274
|
-
{...knobProps.
|
|
264
|
+
{...knobProps.containerRadius}
|
|
275
265
|
tasks={tasks}
|
|
276
266
|
zoom={zoom}
|
|
277
267
|
isLoading={isLoading}
|
package/src/FrappeImageView.tsx
CHANGED
|
@@ -4,7 +4,7 @@ import { ImageSquareIcon } from "@phosphor-icons/react";
|
|
|
4
4
|
import React, { useMemo } from "react";
|
|
5
5
|
import { useTranslation } from "react-i18next";
|
|
6
6
|
import { Spinner, formCommonColors } from "@multiplatform.one/forms";
|
|
7
|
-
import { Image, Text, YStack, type YStackProps } from "tamagui";
|
|
7
|
+
import { Image, Text, YStack, useTheme, type YStackProps } from "tamagui";
|
|
8
8
|
import { isServer } from "@multiplatform.one/platform";
|
|
9
9
|
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
10
10
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
@@ -167,6 +167,7 @@ function FrappeImageViewClient<TDoc extends { name: string; doctype: string }>({
|
|
|
167
167
|
syncOptions,
|
|
168
168
|
...stackProps
|
|
169
169
|
}: FrappeImageViewProps<TDoc>) {
|
|
170
|
+
const theme = useTheme();
|
|
170
171
|
const config = useFrappeConfig();
|
|
171
172
|
const { knobProps } = useResolvedKnobs();
|
|
172
173
|
const { t } = useTranslation();
|
|
@@ -273,7 +274,7 @@ function FrappeImageViewClient<TDoc extends { name: string; doctype: string }>({
|
|
|
273
274
|
const iconSize = Number(knobProps.controlIcon?.width) || 16;
|
|
274
275
|
return (
|
|
275
276
|
<YStack {...knobProps.panelPadding} alignItems="center" {...knobProps.gap} {...stackProps}>
|
|
276
|
-
<ImageSquareIcon size={iconSize * 2} color={
|
|
277
|
+
<ImageSquareIcon size={iconSize * 2} color={theme.color11?.val ?? "currentColor"} />
|
|
277
278
|
<Text color={formCommonColors.muted} {...knobProps.body}>
|
|
278
279
|
{t("No image field configured for {{doctype}}", { doctype })}
|
|
279
280
|
</Text>
|
|
@@ -332,6 +333,7 @@ function FrappeImageCard({
|
|
|
332
333
|
onItemClick?: (doc: Partial<unknown>) => void;
|
|
333
334
|
knobProps: ReturnType<typeof useResolvedKnobs>["knobProps"];
|
|
334
335
|
}) {
|
|
336
|
+
const theme = useTheme();
|
|
335
337
|
const imageUrl = getImageUrl(doc[imageField], baseURL);
|
|
336
338
|
const title = doc[titleField] || doc.name;
|
|
337
339
|
const subtitle = subtitleField ? doc[subtitleField] : undefined;
|
|
@@ -371,7 +373,7 @@ function FrappeImageCard({
|
|
|
371
373
|
alignItems="center"
|
|
372
374
|
justifyContent="center"
|
|
373
375
|
>
|
|
374
|
-
<ImageSquareIcon size={iconSize * 2} color={
|
|
376
|
+
<ImageSquareIcon size={iconSize * 2} color={theme.color11?.val ?? "currentColor"} />
|
|
375
377
|
</YStack>
|
|
376
378
|
)}
|
|
377
379
|
<Card.Footer>
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
});
|
package/src/FrappeKPICard.tsx
CHANGED
|
@@ -11,6 +11,12 @@
|
|
|
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 `baseURL` in scope (neither the prop nor a
|
|
16
|
+
* FrappeProvider) is a misconfiguration, not static mode: the caller asked
|
|
17
|
+
* for a computed figure and there is nowhere to compute it. The card renders
|
|
18
|
+
* the not-configured surface and warns in dev. It never falls back to
|
|
19
|
+
* `config.value`, which would present an uncomputed number as the KPI.
|
|
14
20
|
*/
|
|
15
21
|
import {
|
|
16
22
|
AsyncBoundary,
|
|
@@ -19,10 +25,11 @@ import {
|
|
|
19
25
|
Skeleton,
|
|
20
26
|
type KPICardConfig,
|
|
21
27
|
} from "@multiplatform.one/components";
|
|
22
|
-
import React, { useMemo } from "react";
|
|
28
|
+
import React, { useEffect, useMemo } from "react";
|
|
23
29
|
import { useTranslation } from "react-i18next";
|
|
24
30
|
import { type YStackProps } from "tamagui";
|
|
25
31
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
32
|
+
import { frappeDevWarn } from "./shared/devWarn";
|
|
26
33
|
import {
|
|
27
34
|
useFrappeAggregate,
|
|
28
35
|
type FrappeAggregateConnection,
|
|
@@ -44,11 +51,13 @@ export interface FrappeKPIDataSource {
|
|
|
44
51
|
export interface FrappeKPICardProps extends Omit<YStackProps, "children"> {
|
|
45
52
|
/**
|
|
46
53
|
* KPI chrome (title, format, trend, icon…). In live mode `value` is
|
|
47
|
-
* overridden by the aggregate; in static mode it renders as-is.
|
|
54
|
+
* overridden by the aggregate; in static mode it renders as-is. With a
|
|
55
|
+
* `dataSource` and no `baseURL`, `value` is not rendered at all.
|
|
48
56
|
*/
|
|
49
57
|
config: KPICardConfig;
|
|
50
58
|
/** When set, the card's value goes live against this doctype. */
|
|
51
59
|
dataSource?: FrappeKPIDataSource;
|
|
60
|
+
/** Falls back to the FrappeProvider's. Required whenever `dataSource` is set. */
|
|
52
61
|
baseURL?: string;
|
|
53
62
|
auth?: { useToken?: boolean; token?: string; type?: string };
|
|
54
63
|
syncOptions?: unknown;
|
|
@@ -92,6 +101,18 @@ export function FrappeKPICard({
|
|
|
92
101
|
}
|
|
93
102
|
: undefined;
|
|
94
103
|
|
|
104
|
+
const missingBaseURL = !!dataSource && !finalBaseURL;
|
|
105
|
+
const doctype = dataSource?.doctype;
|
|
106
|
+
useEffect(() => {
|
|
107
|
+
if (!missingBaseURL) return;
|
|
108
|
+
frappeDevWarn("kpi-datasource-without-baseurl", {
|
|
109
|
+
component: "FrappeKPICard",
|
|
110
|
+
id: config.id,
|
|
111
|
+
doctype,
|
|
112
|
+
suggest: "set baseURL on FrappeKPICard or on the FrappeProvider above it",
|
|
113
|
+
});
|
|
114
|
+
}, [missingBaseURL, config.id, doctype]);
|
|
115
|
+
|
|
95
116
|
const { value, isLoading, isStale, error, isPermissionError } = useFrappeAggregate(connection, {
|
|
96
117
|
doctype: dataSource?.doctype ?? "",
|
|
97
118
|
aggregate: dataSource?.aggregate,
|
|
@@ -106,11 +127,30 @@ export function FrappeKPICard({
|
|
|
106
127
|
return { ...config, value: value ?? "—" };
|
|
107
128
|
}, [config, dataSource, value]);
|
|
108
129
|
|
|
109
|
-
// Static passthrough
|
|
110
|
-
|
|
130
|
+
// Static passthrough. The caller supplied the figure and asked for no
|
|
131
|
+
// computation.
|
|
132
|
+
if (!dataSource) {
|
|
111
133
|
return <KPICard config={config} {...stackProps} />;
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
// A requested figure with nowhere to compute it. `config.value` is the
|
|
137
|
+
// caller's placeholder, so painting it here would publish a number nothing
|
|
138
|
+
// downstream could tell was never computed.
|
|
139
|
+
if (!connection) {
|
|
140
|
+
return (
|
|
141
|
+
<AsyncBoundary
|
|
142
|
+
compact
|
|
143
|
+
error
|
|
144
|
+
errorTitle={t("{{title}} is not configured", { title: config.title })}
|
|
145
|
+
errorDescription={t(
|
|
146
|
+
"This card reads {{doctype}} live, but no Frappe baseURL is in scope, so the figure was never computed.",
|
|
147
|
+
{ doctype: dataSource.doctype },
|
|
148
|
+
)}
|
|
149
|
+
{...stackProps}
|
|
150
|
+
/>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
114
154
|
if (isLoading) {
|
|
115
155
|
return <KPICardSkeleton {...stackProps} />;
|
|
116
156
|
}
|
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(
|