@multiplatform.one/frappe-ui 7.28.0 → 7.29.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.cjs +20 -3
- package/dist/cjs/FileBrowser/index.native.js +20 -3
- 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 +3 -2
- package/dist/cjs/FrappeCalendar.native.js +3 -2
- 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 +148 -464
- package/dist/cjs/FrappeForm.native.js +153 -634
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeFormActions.native.js.map +1 -1
- package/dist/cjs/FrappeFormConnections.native.js.map +1 -1
- package/dist/cjs/FrappeGantt.native.js.map +1 -1
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeInsights.native.js.map +1 -1
- package/dist/cjs/FrappeKPICard.native.js.map +1 -1
- package/dist/cjs/FrappeKanban.native.js.map +1 -1
- package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
- package/dist/cjs/FrappeList.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +5 -27
- package/dist/cjs/FrappeListView.native.js +11 -32
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeNotConfigured.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/FrappeRecordView.native.js.map +1 -1
- package/dist/cjs/FrappeReportBuilder.cjs +523 -309
- package/dist/cjs/FrappeReportBuilder.native.js +658 -353
- package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
- package/dist/cjs/FrappeReportView.cjs +35 -234
- package/dist/cjs/FrappeReportView.native.js +42 -286
- package/dist/cjs/FrappeReportView.native.js.map +1 -1
- package/dist/cjs/FrappeRowsReader.native.js.map +1 -1
- package/dist/cjs/FrappeTable.native.js.map +1 -1
- package/dist/cjs/FrappeTreeView.native.js.map +1 -1
- package/dist/cjs/SyncErrorNotice.native.js.map +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.native.js.map +1 -1
- package/dist/cjs/dependsOn.cjs +2 -2
- package/dist/cjs/dependsOn.native.js +1 -2
- 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.native.js.map +1 -1
- package/dist/cjs/desk/DeskSidebar.native.js.map +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.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.cjs +2 -2
- package/dist/cjs/fields/shared/EditorPreviewPanes.native.js +2 -2
- 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/docLifecycle.native.js.map +1 -1
- package/dist/cjs/formEngine/docPermissions.cjs +20 -0
- package/dist/cjs/formEngine/docPermissions.native.js +69 -0
- package/dist/cjs/formEngine/docPermissions.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.cjs +2 -0
- package/dist/cjs/formEngine/index.native.js +2 -0
- package/dist/cjs/formEngine/index.native.js.map +1 -1
- package/dist/cjs/formEngine/useAmendedAs.native.js.map +1 -1
- package/dist/cjs/formEngine/useDocRights.native.js.map +1 -1
- package/dist/cjs/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/cjs/formEngine/useSessionRoles.native.js.map +1 -1
- package/dist/cjs/frappeConnections.native.js.map +1 -1
- package/dist/cjs/frappeEventColor.native.js.map +1 -1
- package/dist/cjs/frappeNavigation.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 +67 -7
- package/dist/cjs/index.native.js +101 -41
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/insights/InsightsFacetTags.native.js.map +1 -1
- package/dist/cjs/insights/InsightsKpiBand.native.js.map +1 -1
- package/dist/cjs/insights/InsightsLeaders.native.js.map +1 -1
- package/dist/cjs/insights/InsightsRecords.native.js.map +1 -1
- package/dist/cjs/insights/InsightsTable.native.js.map +1 -1
- package/dist/cjs/insights/insightsData.native.js.map +1 -1
- package/dist/cjs/insights/insightsRecord.native.js.map +1 -1
- package/dist/cjs/list/FacetBadge.native.js.map +1 -1
- package/dist/cjs/list/FacetRail.native.js.map +1 -1
- package/dist/cjs/list/ImageWell.native.js.map +1 -1
- package/dist/cjs/list/ListControls.native.js.map +1 -1
- package/dist/cjs/list/ListToastHost.native.js.map +1 -1
- package/dist/cjs/list/RangeFilter.native.js.map +1 -1
- package/dist/cjs/list/ShufflePanel.native.js.map +1 -1
- package/dist/cjs/list/facetReading.native.js.map +1 -1
- package/dist/cjs/list/favorites.native.js.map +1 -1
- package/dist/cjs/list/listColumns.native.js.map +1 -1
- package/dist/cjs/list/listFields.native.js.map +1 -1
- package/dist/cjs/list/listFormat.native.js.map +1 -1
- package/dist/cjs/list/listState.native.js.map +1 -1
- package/dist/cjs/list/recordLook.native.js.map +1 -1
- package/dist/cjs/list/statusColors.native.js.map +1 -1
- package/dist/cjs/list/useListControls.native.js.map +1 -1
- package/dist/cjs/liveErrors.cjs +8 -2
- package/dist/cjs/liveErrors.native.js +8 -2
- package/dist/cjs/liveErrors.native.js.map +1 -1
- package/dist/cjs/measures.cjs +31 -0
- package/dist/cjs/measures.native.js +34 -0
- package/dist/cjs/measures.native.js.map +1 -0
- package/dist/cjs/record/RecordBars.native.js.map +1 -1
- package/dist/cjs/record/RecordGallery.native.js.map +1 -1
- package/dist/cjs/record/RecordHero.native.js.map +1 -1
- package/dist/cjs/record/RecordPage.native.js.map +1 -1
- package/dist/cjs/record/RecordPager.native.js.map +1 -1
- package/dist/cjs/record/RecordRows.native.js.map +1 -1
- package/dist/cjs/record/recordData.native.js.map +1 -1
- package/dist/cjs/record/recordSections.native.js.map +1 -1
- package/dist/cjs/recordShape.cjs +103 -0
- package/dist/cjs/recordShape.native.js +115 -0
- package/dist/cjs/recordShape.native.js.map +1 -0
- package/dist/cjs/report/ReportGrid.cjs +453 -0
- package/dist/cjs/report/ReportGrid.native.js +510 -0
- package/dist/cjs/report/ReportGrid.native.js.map +1 -0
- package/dist/cjs/report/ReportViewToolbar.cjs +253 -0
- package/dist/cjs/report/ReportViewToolbar.native.js +303 -0
- package/dist/cjs/report/ReportViewToolbar.native.js.map +1 -0
- package/dist/cjs/report/queryReport.cjs +444 -0
- package/dist/cjs/report/queryReport.native.js +588 -0
- package/dist/cjs/report/queryReport.native.js.map +1 -0
- package/dist/cjs/report/queryReportColumns.cjs +131 -0
- package/dist/cjs/report/queryReportColumns.native.js +159 -0
- package/dist/cjs/report/queryReportColumns.native.js.map +1 -0
- package/dist/cjs/report/reportViewModel.cjs +386 -0
- package/dist/cjs/report/reportViewModel.native.js +657 -0
- package/dist/cjs/report/reportViewModel.native.js.map +1 -0
- package/dist/cjs/report/savedReports.cjs +137 -0
- package/dist/cjs/report/savedReports.native.js +169 -0
- package/dist/cjs/report/savedReports.native.js.map +1 -0
- package/dist/cjs/report/useFrappeReport.cjs +184 -0
- package/dist/cjs/report/useFrappeReport.native.js +214 -0
- package/dist/cjs/report/useFrappeReport.native.js.map +1 -0
- package/dist/cjs/report/useQueryReport.cjs +201 -0
- package/dist/cjs/report/useQueryReport.native.js +233 -0
- package/dist/cjs/report/useQueryReport.native.js.map +1 -0
- 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.native.js +1 -1
- package/dist/cjs/schemaForm/index.native.js.map +1 -1
- package/dist/cjs/shared/devWarn.native.js.map +1 -1
- package/dist/cjs/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/cjs/syncError.native.js.map +1 -1
- package/dist/cjs/useConnectionFilters.native.js.map +1 -1
- package/dist/cjs/useFrappeAggregate.native.js.map +1 -1
- package/dist/cjs/useFrappeFacets.native.js.map +1 -1
- package/dist/cjs/useFrappeForm.cjs +558 -0
- package/dist/cjs/useFrappeForm.native.js +714 -0
- package/dist/cjs/useFrappeForm.native.js.map +1 -0
- package/dist/cjs/useFrappePagination.native.js.map +1 -1
- package/dist/cjs/useFrappeRows.native.js.map +1 -1
- 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.mjs +20 -3
- package/dist/esm/FileBrowser/index.mjs.map +1 -1
- package/dist/esm/FileBrowser/index.native.js +20 -3
- 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 +4 -3
- package/dist/esm/FrappeCalendar.mjs.map +1 -1
- package/dist/esm/FrappeCalendar.native.js +4 -3
- 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 +151 -467
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +155 -636
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeFormActions.native.js.map +1 -1
- package/dist/esm/FrappeFormConnections.native.js.map +1 -1
- package/dist/esm/FrappeGantt.native.js.map +1 -1
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeInsights.native.js.map +1 -1
- package/dist/esm/FrappeKPICard.native.js.map +1 -1
- package/dist/esm/FrappeKanban.native.js.map +1 -1
- package/dist/esm/FrappeLikedBy.native.js.map +1 -1
- package/dist/esm/FrappeList.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +6 -28
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +12 -33
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeNotConfigured.native.js.map +1 -1
- package/dist/esm/FrappeProvider.native.js.map +1 -1
- package/dist/esm/FrappeReconnectIndicator.native.js.map +1 -1
- package/dist/esm/FrappeRecordView.native.js.map +1 -1
- package/dist/esm/FrappeReportBuilder.mjs +526 -312
- package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
- package/dist/esm/FrappeReportBuilder.native.js +661 -356
- package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
- package/dist/esm/FrappeReportView.mjs +30 -229
- package/dist/esm/FrappeReportView.mjs.map +1 -1
- package/dist/esm/FrappeReportView.native.js +34 -278
- package/dist/esm/FrappeReportView.native.js.map +1 -1
- package/dist/esm/FrappeRowsReader.native.js.map +1 -1
- package/dist/esm/FrappeTable.native.js.map +1 -1
- package/dist/esm/FrappeTreeView.native.js.map +1 -1
- package/dist/esm/SyncErrorNotice.native.js.map +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.native.js.map +1 -1
- package/dist/esm/dependsOn.mjs +2 -2
- package/dist/esm/dependsOn.mjs.map +1 -1
- package/dist/esm/dependsOn.native.js +1 -2
- 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.native.js.map +1 -1
- package/dist/esm/desk/DeskSidebar.native.js.map +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.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.mjs +2 -2
- package/dist/esm/fields/shared/EditorPreviewPanes.mjs.map +1 -1
- package/dist/esm/fields/shared/EditorPreviewPanes.native.js +2 -2
- 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/docLifecycle.native.js.map +1 -1
- package/dist/esm/formEngine/docPermissions.mjs +19 -1
- package/dist/esm/formEngine/docPermissions.mjs.map +1 -1
- package/dist/esm/formEngine/docPermissions.native.js +68 -1
- package/dist/esm/formEngine/docPermissions.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.mjs +2 -2
- package/dist/esm/formEngine/index.mjs.map +1 -1
- package/dist/esm/formEngine/index.native.js +2 -2
- package/dist/esm/formEngine/index.native.js.map +1 -1
- package/dist/esm/formEngine/useAmendedAs.native.js.map +1 -1
- package/dist/esm/formEngine/useDocRights.native.js.map +1 -1
- package/dist/esm/formEngine/useFormEngine.native.js.map +1 -1
- package/dist/esm/formEngine/useSessionRoles.native.js.map +1 -1
- package/dist/esm/frappeConnections.native.js.map +1 -1
- package/dist/esm/frappeEventColor.native.js.map +1 -1
- package/dist/esm/frappeNavigation.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 +16 -4
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +16 -4
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/insights/InsightsFacetTags.native.js.map +1 -1
- package/dist/esm/insights/InsightsKpiBand.native.js.map +1 -1
- package/dist/esm/insights/InsightsLeaders.native.js.map +1 -1
- package/dist/esm/insights/InsightsRecords.native.js.map +1 -1
- package/dist/esm/insights/InsightsTable.native.js.map +1 -1
- package/dist/esm/insights/insightsData.native.js.map +1 -1
- package/dist/esm/insights/insightsRecord.native.js.map +1 -1
- package/dist/esm/list/FacetBadge.native.js.map +1 -1
- package/dist/esm/list/FacetRail.native.js.map +1 -1
- package/dist/esm/list/ImageWell.native.js.map +1 -1
- package/dist/esm/list/ListControls.native.js.map +1 -1
- package/dist/esm/list/ListToastHost.native.js.map +1 -1
- package/dist/esm/list/RangeFilter.native.js.map +1 -1
- package/dist/esm/list/ShufflePanel.native.js.map +1 -1
- package/dist/esm/list/facetReading.native.js.map +1 -1
- package/dist/esm/list/favorites.native.js.map +1 -1
- package/dist/esm/list/listColumns.native.js.map +1 -1
- package/dist/esm/list/listFields.native.js.map +1 -1
- package/dist/esm/list/listFormat.native.js.map +1 -1
- package/dist/esm/list/listState.native.js.map +1 -1
- package/dist/esm/list/recordLook.native.js.map +1 -1
- package/dist/esm/list/statusColors.native.js.map +1 -1
- package/dist/esm/list/useListControls.native.js.map +1 -1
- package/dist/esm/liveErrors.mjs +8 -3
- package/dist/esm/liveErrors.mjs.map +1 -1
- package/dist/esm/liveErrors.native.js +8 -3
- package/dist/esm/liveErrors.native.js.map +1 -1
- package/dist/esm/measures.mjs +5 -0
- package/dist/esm/measures.mjs.map +1 -0
- package/dist/esm/measures.native.js +5 -0
- package/dist/esm/measures.native.js.map +1 -0
- package/dist/esm/record/RecordBars.native.js.map +1 -1
- package/dist/esm/record/RecordGallery.native.js.map +1 -1
- package/dist/esm/record/RecordHero.native.js.map +1 -1
- package/dist/esm/record/RecordPage.native.js.map +1 -1
- package/dist/esm/record/RecordPager.native.js.map +1 -1
- package/dist/esm/record/RecordRows.native.js.map +1 -1
- package/dist/esm/record/recordData.native.js.map +1 -1
- package/dist/esm/record/recordSections.native.js.map +1 -1
- package/dist/esm/recordShape.mjs +74 -0
- package/dist/esm/recordShape.mjs.map +1 -0
- package/dist/esm/recordShape.native.js +83 -0
- package/dist/esm/recordShape.native.js.map +1 -0
- package/dist/esm/report/ReportGrid.mjs +428 -0
- package/dist/esm/report/ReportGrid.mjs.map +1 -0
- package/dist/esm/report/ReportGrid.native.js +471 -0
- package/dist/esm/report/ReportGrid.native.js.map +1 -0
- package/dist/esm/report/ReportViewToolbar.mjs +228 -0
- package/dist/esm/report/ReportViewToolbar.mjs.map +1 -0
- package/dist/esm/report/ReportViewToolbar.native.js +264 -0
- package/dist/esm/report/ReportViewToolbar.native.js.map +1 -0
- package/dist/esm/report/queryReport.mjs +404 -0
- package/dist/esm/report/queryReport.mjs.map +1 -0
- package/dist/esm/report/queryReport.native.js +545 -0
- package/dist/esm/report/queryReport.native.js.map +1 -0
- package/dist/esm/report/queryReportColumns.mjs +105 -0
- package/dist/esm/report/queryReportColumns.mjs.map +1 -0
- package/dist/esm/report/queryReportColumns.native.js +119 -0
- package/dist/esm/report/queryReportColumns.native.js.map +1 -0
- package/dist/esm/report/reportViewModel.mjs +343 -0
- package/dist/esm/report/reportViewModel.mjs.map +1 -0
- package/dist/esm/report/reportViewModel.native.js +611 -0
- package/dist/esm/report/reportViewModel.native.js.map +1 -0
- package/dist/esm/report/savedReports.mjs +112 -0
- package/dist/esm/report/savedReports.mjs.map +1 -0
- package/dist/esm/report/savedReports.native.js +141 -0
- package/dist/esm/report/savedReports.native.js.map +1 -0
- package/dist/esm/report/useFrappeReport.mjs +158 -0
- package/dist/esm/report/useFrappeReport.mjs.map +1 -0
- package/dist/esm/report/useFrappeReport.native.js +185 -0
- package/dist/esm/report/useFrappeReport.native.js.map +1 -0
- package/dist/esm/report/useQueryReport.mjs +176 -0
- package/dist/esm/report/useQueryReport.mjs.map +1 -0
- package/dist/esm/report/useQueryReport.native.js +205 -0
- package/dist/esm/report/useQueryReport.native.js.map +1 -0
- 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.native.js.map +1 -1
- package/dist/esm/shared/devWarn.native.js.map +1 -1
- package/dist/esm/shared/useKeyboardInset.native.js.map +1 -1
- package/dist/esm/syncError.native.js.map +1 -1
- package/dist/esm/useConnectionFilters.native.js.map +1 -1
- package/dist/esm/useFrappeAggregate.native.js.map +1 -1
- package/dist/esm/useFrappeFacets.native.js.map +1 -1
- package/dist/esm/useFrappeForm.mjs +533 -0
- package/dist/esm/useFrappeForm.mjs.map +1 -0
- package/dist/esm/useFrappeForm.native.js +686 -0
- package/dist/esm/useFrappeForm.native.js.map +1 -0
- package/dist/esm/useFrappePagination.native.js.map +1 -1
- package/dist/esm/useFrappeRows.native.js.map +1 -1
- package/dist/jsx/FileBrowser/index.mjs +20 -3
- package/dist/jsx/FileBrowser/index.mjs.map +1 -1
- package/dist/jsx/FileBrowser/index.native.js +20 -3
- package/dist/jsx/FileBrowser/index.native.js.map +1 -1
- package/dist/jsx/FrappeCalendar.mjs +4 -3
- package/dist/jsx/FrappeCalendar.mjs.map +1 -1
- package/dist/jsx/FrappeCalendar.native.js +3 -2
- package/dist/jsx/FrappeCalendar.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +151 -467
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +152 -633
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +6 -28
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +11 -32
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeReportBuilder.mjs +526 -312
- package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
- package/dist/jsx/FrappeReportBuilder.native.js +658 -353
- package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
- package/dist/jsx/FrappeReportView.mjs +30 -229
- package/dist/jsx/FrappeReportView.mjs.map +1 -1
- package/dist/jsx/FrappeReportView.native.js +39 -283
- package/dist/jsx/FrappeReportView.native.js.map +1 -1
- package/dist/jsx/dependsOn.mjs +2 -2
- package/dist/jsx/dependsOn.mjs.map +1 -1
- package/dist/jsx/dependsOn.native.js +1 -2
- package/dist/jsx/dependsOn.native.js.map +1 -1
- package/dist/jsx/fields/shared/EditorPreviewPanes.mjs +2 -2
- package/dist/jsx/fields/shared/EditorPreviewPanes.mjs.map +1 -1
- package/dist/jsx/fields/shared/EditorPreviewPanes.native.js +2 -2
- package/dist/jsx/fields/shared/EditorPreviewPanes.native.js.map +1 -1
- package/dist/jsx/formEngine/docPermissions.mjs +19 -1
- package/dist/jsx/formEngine/docPermissions.mjs.map +1 -1
- package/dist/jsx/formEngine/docPermissions.native.js +69 -0
- package/dist/jsx/formEngine/docPermissions.native.js.map +1 -1
- package/dist/jsx/formEngine/index.mjs +2 -2
- package/dist/jsx/formEngine/index.mjs.map +1 -1
- package/dist/jsx/formEngine/index.native.js +2 -0
- package/dist/jsx/formEngine/index.native.js.map +1 -1
- package/dist/jsx/index.js +16 -4
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +16 -4
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +67 -7
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/liveErrors.mjs +8 -3
- package/dist/jsx/liveErrors.mjs.map +1 -1
- package/dist/jsx/liveErrors.native.js +8 -2
- package/dist/jsx/liveErrors.native.js.map +1 -1
- package/dist/jsx/measures.mjs +5 -0
- package/dist/jsx/measures.mjs.map +1 -0
- package/dist/jsx/measures.native.js +34 -0
- package/dist/jsx/measures.native.js.map +1 -0
- package/dist/jsx/recordShape.mjs +74 -0
- package/dist/jsx/recordShape.mjs.map +1 -0
- package/dist/jsx/recordShape.native.js +115 -0
- package/dist/jsx/recordShape.native.js.map +1 -0
- package/dist/jsx/report/ReportGrid.mjs +428 -0
- package/dist/jsx/report/ReportGrid.mjs.map +1 -0
- package/dist/jsx/report/ReportGrid.native.js +510 -0
- package/dist/jsx/report/ReportGrid.native.js.map +1 -0
- package/dist/jsx/report/ReportViewToolbar.mjs +228 -0
- package/dist/jsx/report/ReportViewToolbar.mjs.map +1 -0
- package/dist/jsx/report/ReportViewToolbar.native.js +303 -0
- package/dist/jsx/report/ReportViewToolbar.native.js.map +1 -0
- package/dist/jsx/report/queryReport.mjs +404 -0
- package/dist/jsx/report/queryReport.mjs.map +1 -0
- package/dist/jsx/report/queryReport.native.js +588 -0
- package/dist/jsx/report/queryReport.native.js.map +1 -0
- package/dist/jsx/report/queryReportColumns.mjs +105 -0
- package/dist/jsx/report/queryReportColumns.mjs.map +1 -0
- package/dist/jsx/report/queryReportColumns.native.js +159 -0
- package/dist/jsx/report/queryReportColumns.native.js.map +1 -0
- package/dist/jsx/report/reportViewModel.mjs +343 -0
- package/dist/jsx/report/reportViewModel.mjs.map +1 -0
- package/dist/jsx/report/reportViewModel.native.js +657 -0
- package/dist/jsx/report/reportViewModel.native.js.map +1 -0
- package/dist/jsx/report/savedReports.mjs +112 -0
- package/dist/jsx/report/savedReports.mjs.map +1 -0
- package/dist/jsx/report/savedReports.native.js +169 -0
- package/dist/jsx/report/savedReports.native.js.map +1 -0
- package/dist/jsx/report/useFrappeReport.mjs +158 -0
- package/dist/jsx/report/useFrappeReport.mjs.map +1 -0
- package/dist/jsx/report/useFrappeReport.native.js +214 -0
- package/dist/jsx/report/useFrappeReport.native.js.map +1 -0
- package/dist/jsx/report/useQueryReport.mjs +176 -0
- package/dist/jsx/report/useQueryReport.mjs.map +1 -0
- package/dist/jsx/report/useQueryReport.native.js +233 -0
- package/dist/jsx/report/useQueryReport.native.js.map +1 -0
- package/dist/jsx/useFrappeForm.mjs +533 -0
- package/dist/jsx/useFrappeForm.mjs.map +1 -0
- package/dist/jsx/useFrappeForm.native.js +714 -0
- package/dist/jsx/useFrappeForm.native.js.map +1 -0
- package/package.json +16 -16
- package/src/FileBrowser/FileBrowser.spec.tsx +21 -0
- package/src/FileBrowser/FileBrowser.stories.tsx +27 -0
- package/src/FileBrowser/index.tsx +25 -2
- package/src/FrappeCalendar.tsx +8 -2
- package/src/FrappeForm.stories.tsx +52 -0
- package/src/FrappeForm.tsx +176 -565
- package/src/FrappeListView.cards.stories.tsx +3 -6
- package/src/FrappeListView.tsx +15 -55
- package/src/FrappeReportBuilder.stories.tsx +34 -7
- package/src/FrappeReportBuilder.tsx +790 -380
- package/src/FrappeReportView.spec.tsx +10 -6
- package/src/FrappeReportView.stories.tsx +20 -1
- package/src/FrappeReportView.tsx +89 -415
- package/src/dependsOn.ts +4 -1
- package/src/fields/shared/EditorPreviewPanes.tsx +2 -2
- package/src/formEngine/docPermissions.spec.ts +36 -1
- package/src/formEngine/docPermissions.ts +34 -0
- package/src/formEngine/index.ts +8 -1
- package/src/frappeRemainder.designLaw.spec.ts +9 -1
- package/src/frappeRoutes.spec.tsx +9 -0
- package/src/frappeViews.designLaw.spec.ts +15 -2
- package/src/guestFallback.spec.tsx +236 -0
- package/src/index.ts +117 -16
- package/src/liveErrors.spec.ts +10 -0
- package/src/liveErrors.ts +16 -3
- package/src/measures.ts +11 -0
- package/src/recordShape.spec.ts +100 -0
- package/src/recordShape.ts +133 -0
- package/src/report/ReportGrid.spec.tsx +175 -0
- package/src/report/ReportGrid.tsx +530 -0
- package/src/report/ReportViewToolbar.spec.tsx +90 -0
- package/src/report/ReportViewToolbar.tsx +314 -0
- package/src/report/queryReport.spec.ts +483 -0
- package/src/report/queryReport.ts +722 -0
- package/src/report/queryReportColumns.tsx +123 -0
- package/src/report/reportViewModel.spec.ts +393 -0
- package/src/report/reportViewModel.ts +617 -0
- package/src/report/savedReports.ts +172 -0
- package/src/report/seam.spec.ts +216 -0
- package/src/report/useFrappeReport.ts +241 -0
- package/src/report/useQueryReport.spec.tsx +131 -0
- package/src/report/useQueryReport.ts +309 -0
- package/src/useFrappeForm.spec.tsx +209 -0
- package/src/useFrappeForm.ts +778 -0
- package/types/FileBrowser/index.d.ts.map +1 -1
- package/types/FrappeCalendar.d.ts.map +1 -1
- package/types/FrappeForm.d.ts +21 -1
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeListView.d.ts.map +1 -1
- package/types/FrappeReportBuilder.d.ts +66 -16
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/FrappeReportView.d.ts +9 -127
- package/types/FrappeReportView.d.ts.map +1 -1
- package/types/dependsOn.d.ts.map +1 -1
- package/types/formEngine/docPermissions.d.ts +14 -0
- package/types/formEngine/docPermissions.d.ts.map +1 -1
- package/types/formEngine/index.d.ts +1 -1
- package/types/formEngine/index.d.ts.map +1 -1
- package/types/index.d.ts +15 -3
- package/types/index.d.ts.map +1 -1
- package/types/liveErrors.d.ts +9 -1
- package/types/liveErrors.d.ts.map +1 -1
- package/types/measures.d.ts +3 -0
- package/types/measures.d.ts.map +1 -0
- package/types/recordShape.d.ts +45 -0
- package/types/recordShape.d.ts.map +1 -0
- package/types/report/ReportGrid.d.ts +20 -0
- package/types/report/ReportGrid.d.ts.map +1 -0
- package/types/report/ReportViewToolbar.d.ts +31 -0
- package/types/report/ReportViewToolbar.d.ts.map +1 -0
- package/types/report/queryReport.d.ts +181 -0
- package/types/report/queryReport.d.ts.map +1 -0
- package/types/report/queryReportColumns.d.ts +12 -0
- package/types/report/queryReportColumns.d.ts.map +1 -0
- package/types/report/reportViewModel.d.ts +146 -0
- package/types/report/reportViewModel.d.ts.map +1 -0
- package/types/report/savedReports.d.ts +27 -0
- package/types/report/savedReports.d.ts.map +1 -0
- package/types/report/useFrappeReport.d.ts +60 -0
- package/types/report/useFrappeReport.d.ts.map +1 -0
- package/types/report/useQueryReport.d.ts +37 -0
- package/types/report/useQueryReport.d.ts.map +1 -0
- package/types/useFrappeForm.d.ts +142 -0
- package/types/useFrappeForm.d.ts.map +1 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { renderHook, waitFor } from "@testing-library/react";
|
|
2
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { fieldsFromRecord, recordFieldKeys, recordKeyLabel, useRecordShape } from "./recordShape";
|
|
4
|
+
|
|
5
|
+
const record = {
|
|
6
|
+
name: "a1b2c3",
|
|
7
|
+
doctype: "Poke Move",
|
|
8
|
+
owner: "Administrator",
|
|
9
|
+
creation: "2026-09-29 09:00:00",
|
|
10
|
+
modified: "2026-09-29 10:00:00",
|
|
11
|
+
modified_by: "Administrator",
|
|
12
|
+
docstatus: 0,
|
|
13
|
+
idx: 0,
|
|
14
|
+
_user_tags: null,
|
|
15
|
+
_comments: null,
|
|
16
|
+
_assign: null,
|
|
17
|
+
_liked_by: null,
|
|
18
|
+
_seen: null,
|
|
19
|
+
$origin: "remote",
|
|
20
|
+
$key: "a1b2c3",
|
|
21
|
+
move_name: "tackle",
|
|
22
|
+
power: 40,
|
|
23
|
+
accuracy: 0.95,
|
|
24
|
+
damage_class: null,
|
|
25
|
+
effects: [{ name: "row-1" }],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
describe("recordShape", () => {
|
|
29
|
+
it("keeps a record's own scalar keys in server order", () => {
|
|
30
|
+
expect(recordFieldKeys(record)).toEqual(["move_name", "power", "accuracy", "damage_class"]);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it("labels a key the way the desk labels a field", () => {
|
|
34
|
+
expect(recordKeyLabel("base_experience")).toBe("Base Experience");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("types each field from its value and marks it read-only", () => {
|
|
38
|
+
expect(fieldsFromRecord(record)).toEqual([
|
|
39
|
+
{ fieldname: "move_name", label: "Move Name", fieldtype: "Data", read_only: 1 },
|
|
40
|
+
{ fieldname: "power", label: "Power", fieldtype: "Int", read_only: 1 },
|
|
41
|
+
{ fieldname: "accuracy", label: "Accuracy", fieldtype: "Float", read_only: 1 },
|
|
42
|
+
{ fieldname: "damage_class", label: "Damage Class", fieldtype: "Data", read_only: 1 },
|
|
43
|
+
]);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("useRecordShape", () => {
|
|
48
|
+
afterEach(() => vi.unstubAllGlobals());
|
|
49
|
+
|
|
50
|
+
function stub(answer: () => Response) {
|
|
51
|
+
const reads: string[] = [];
|
|
52
|
+
vi.stubGlobal("fetch", async (input: string | URL | Request) => {
|
|
53
|
+
reads.push(String(input instanceof Request ? input.url : input));
|
|
54
|
+
return answer();
|
|
55
|
+
});
|
|
56
|
+
return reads;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
it("reads nothing until asked", () => {
|
|
60
|
+
const reads = stub(() => new Response("{}"));
|
|
61
|
+
const { result } = renderHook(() =>
|
|
62
|
+
useRecordShape({ baseURL: "http://shape.test" }, "Poke Move", false),
|
|
63
|
+
);
|
|
64
|
+
expect(result.current).toEqual({ fields: undefined, status: "idle" });
|
|
65
|
+
expect(reads).toEqual([]);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("samples one record with every field", async () => {
|
|
69
|
+
const reads = stub(() => Response.json({ data: [record] }));
|
|
70
|
+
const { result } = renderHook(() =>
|
|
71
|
+
useRecordShape({ baseURL: "http://shape.test" }, "Poke Move", true),
|
|
72
|
+
);
|
|
73
|
+
expect(result.current.status).toBe("pending");
|
|
74
|
+
await waitFor(() => expect(result.current.status).toBe("ready"));
|
|
75
|
+
expect(result.current.fields?.map((field) => field.fieldname)).toEqual([
|
|
76
|
+
"move_name",
|
|
77
|
+
"power",
|
|
78
|
+
"accuracy",
|
|
79
|
+
"damage_class",
|
|
80
|
+
]);
|
|
81
|
+
const url = new URL(reads[0] ?? "");
|
|
82
|
+
expect(url.pathname).toBe("/api/resource/Poke%20Move");
|
|
83
|
+
expect(url.searchParams.get("fields")).toBe('["*"]');
|
|
84
|
+
expect(url.searchParams.get("limit_page_length")).toBe("1");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("calls a refused or empty doctype unreadable", async () => {
|
|
88
|
+
stub(() => Response.json({ exc_type: "PermissionError" }, { status: 403 }));
|
|
89
|
+
const refused = renderHook(() =>
|
|
90
|
+
useRecordShape({ baseURL: "http://refused.test" }, "Poke Move", true),
|
|
91
|
+
);
|
|
92
|
+
await waitFor(() => expect(refused.result.current.status).toBe("unreadable"));
|
|
93
|
+
|
|
94
|
+
stub(() => Response.json({ data: [] }));
|
|
95
|
+
const empty = renderHook(() =>
|
|
96
|
+
useRecordShape({ baseURL: "http://empty.test" }, "Poke Move", true),
|
|
97
|
+
);
|
|
98
|
+
await waitFor(() => expect(empty.result.current.status).toBe("unreadable"));
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A doctype as far as one of its records shows it.
|
|
3
|
+
*
|
|
4
|
+
* DocType meta is permission-gated (Guest gets 403 on getdoctype) while the
|
|
5
|
+
* records themselves are often readable. A data-aware view that cannot read
|
|
6
|
+
* meta still owes the reader the weakest honest rendering of what they may
|
|
7
|
+
* read (LC-96): the record's own fields, labelled from their keys, typed from
|
|
8
|
+
* their values and read-only. These helpers are that shape, shared by every
|
|
9
|
+
* view that falls back to it.
|
|
10
|
+
*/
|
|
11
|
+
import { HttpClient, type AuthConfig, type DocTypeField } from "@multiplatform.one/frappe";
|
|
12
|
+
import { useEffect, useMemo, useState } from "react";
|
|
13
|
+
|
|
14
|
+
/** Keys every Frappe record carries that are bookkeeping, not fields of its doctype. */
|
|
15
|
+
export const recordBookkeepingKeys: ReadonlySet<string> = new Set([
|
|
16
|
+
"name",
|
|
17
|
+
"owner",
|
|
18
|
+
"creation",
|
|
19
|
+
"modified",
|
|
20
|
+
"modified_by",
|
|
21
|
+
"docstatus",
|
|
22
|
+
"idx",
|
|
23
|
+
"doctype",
|
|
24
|
+
"_user_tags",
|
|
25
|
+
"_comments",
|
|
26
|
+
"_assign",
|
|
27
|
+
"_liked_by",
|
|
28
|
+
"_seen",
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
function isFieldValue(value: unknown): value is string | number | null {
|
|
32
|
+
return value === null || typeof value === "string" || typeof value === "number";
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A record's own field keys in the order the server sent them. Bookkeeping
|
|
37
|
+
* keys, the live collection's `$` props ($origin, $key, $collectionId) and
|
|
38
|
+
* non-scalar values (child rows, objects) are dropped.
|
|
39
|
+
*/
|
|
40
|
+
export function recordFieldKeys(record: Record<string, unknown>): string[] {
|
|
41
|
+
return Object.entries(record)
|
|
42
|
+
.filter(
|
|
43
|
+
([key, value]) =>
|
|
44
|
+
!key.startsWith("$") && !recordBookkeepingKeys.has(key) && isFieldValue(value),
|
|
45
|
+
)
|
|
46
|
+
.map(([key]) => key);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** "base_experience" → "Base Experience", for a key no meta names. */
|
|
50
|
+
export function recordKeyLabel(key: string): string {
|
|
51
|
+
return key.replace(/_/g, " ").replace(/(^|\s)\S/g, (c) => c.toUpperCase());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The record's own fields as read-only doctype fields: Int or Float for a
|
|
56
|
+
* number, Data for anything else.
|
|
57
|
+
*/
|
|
58
|
+
export function fieldsFromRecord(record: Record<string, unknown>): DocTypeField[] {
|
|
59
|
+
return recordFieldKeys(record).map((key) => {
|
|
60
|
+
const value = record[key];
|
|
61
|
+
return {
|
|
62
|
+
fieldname: key,
|
|
63
|
+
label: recordKeyLabel(key),
|
|
64
|
+
fieldtype: typeof value === "number" ? (Number.isInteger(value) ? "Int" : "Float") : "Data",
|
|
65
|
+
read_only: 1,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export interface RecordShapeConnection {
|
|
71
|
+
baseURL?: string;
|
|
72
|
+
auth?: unknown;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export interface RecordShape {
|
|
76
|
+
/** The sampled record's fields, once it has been read. */
|
|
77
|
+
fields: DocTypeField[] | undefined;
|
|
78
|
+
/**
|
|
79
|
+
* `idle` when not asked, `pending` while the record is read, `ready` with
|
|
80
|
+
* fields, `unreadable` when the doctype has no record the reader may see.
|
|
81
|
+
*/
|
|
82
|
+
status: "idle" | "pending" | "ready" | "unreadable";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Reads one record of `doctype` (`fields: ["*"]`, one row) and returns its
|
|
87
|
+
* fields. Only reads while `enabled`; a view turns it on when meta is refused.
|
|
88
|
+
*/
|
|
89
|
+
export function useRecordShape(
|
|
90
|
+
connection: RecordShapeConnection | undefined,
|
|
91
|
+
doctype: string,
|
|
92
|
+
enabled: boolean,
|
|
93
|
+
): RecordShape {
|
|
94
|
+
const baseURL = connection?.baseURL;
|
|
95
|
+
const auth = connection?.auth;
|
|
96
|
+
const [sampled, setSampled] = useState<{
|
|
97
|
+
key: string;
|
|
98
|
+
fields: DocTypeField[] | undefined;
|
|
99
|
+
}>();
|
|
100
|
+
const key = `${baseURL ?? ""}\u0000${doctype}`;
|
|
101
|
+
const reads = enabled && Boolean(baseURL);
|
|
102
|
+
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!reads || !baseURL) return;
|
|
105
|
+
let cancelled = false;
|
|
106
|
+
const http = new HttpClient(baseURL, auth as AuthConfig | undefined);
|
|
107
|
+
void (async () => {
|
|
108
|
+
let fields: DocTypeField[] | undefined;
|
|
109
|
+
try {
|
|
110
|
+
const response = await http.get<{ data?: Record<string, unknown>[] }>(
|
|
111
|
+
`/api/resource/${encodeURIComponent(doctype)}`,
|
|
112
|
+
{ fields: ["*"], limit_page_length: 1 },
|
|
113
|
+
);
|
|
114
|
+
const sample = response.payload?.data?.[0];
|
|
115
|
+
fields = sample ? fieldsFromRecord(sample) : undefined;
|
|
116
|
+
} catch {
|
|
117
|
+
fields = undefined;
|
|
118
|
+
}
|
|
119
|
+
if (!cancelled) setSampled({ key, fields });
|
|
120
|
+
})();
|
|
121
|
+
return () => {
|
|
122
|
+
cancelled = true;
|
|
123
|
+
};
|
|
124
|
+
}, [reads, baseURL, auth, doctype, key]);
|
|
125
|
+
|
|
126
|
+
return useMemo((): RecordShape => {
|
|
127
|
+
if (!reads) return { fields: undefined, status: "idle" };
|
|
128
|
+
if (sampled?.key !== key) return { fields: undefined, status: "pending" };
|
|
129
|
+
return sampled.fields && sampled.fields.length > 0
|
|
130
|
+
? { fields: sampled.fields, status: "ready" }
|
|
131
|
+
: { fields: undefined, status: "unreadable" };
|
|
132
|
+
}, [reads, sampled, key]);
|
|
133
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ReportGrid row keyboard contract (LC-49 ONE-TAB-STOP, LC-50
|
|
3
|
+
* KEY-ACTIVATION, DG-A11Y-06 names).
|
|
4
|
+
*
|
|
5
|
+
* The data row is ONE pressable unit: click anywhere activates, Enter AND
|
|
6
|
+
* Space activate from the keyboard, the data-row set exposes exactly one
|
|
7
|
+
* tab stop (roving tabindex, arrows/Home/End move it), rows are named by
|
|
8
|
+
* doc identity, presses on inner interactive content (Link cells) never
|
|
9
|
+
* reach the row handler, and there is no per-cell pressable chrome inside
|
|
10
|
+
* body cells. Group header rows are not pressable and hold no tab stop.
|
|
11
|
+
*/
|
|
12
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
13
|
+
import { fireEvent, screen, waitFor } from "@testing-library/react";
|
|
14
|
+
import React from "react";
|
|
15
|
+
import { describe, expect, it, vi } from "vitest";
|
|
16
|
+
import { ReportGrid, type ReportGridProps } from "./ReportGrid";
|
|
17
|
+
import { buildGridRows, type ReportColumnDef, type ReportRow } from "./reportViewModel";
|
|
18
|
+
|
|
19
|
+
const columns: ReportColumnDef[] = [
|
|
20
|
+
{ fieldname: "name", label: "ID", fieldtype: "Data", kind: "text", width: 160, align: "left" },
|
|
21
|
+
{
|
|
22
|
+
fieldname: "status",
|
|
23
|
+
label: "Status",
|
|
24
|
+
fieldtype: "Select",
|
|
25
|
+
kind: "select",
|
|
26
|
+
options: "Open\nClosed",
|
|
27
|
+
width: 120,
|
|
28
|
+
align: "left",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
fieldname: "assigned_by",
|
|
32
|
+
label: "Assigned By",
|
|
33
|
+
fieldtype: "Link",
|
|
34
|
+
kind: "link",
|
|
35
|
+
options: "User",
|
|
36
|
+
width: 160,
|
|
37
|
+
align: "left",
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const dataRows: ReportRow[] = [
|
|
42
|
+
{ name: "TD-0001", status: "Open", assigned_by: "alice@example.com" },
|
|
43
|
+
{ name: "TD-0002", status: "Closed", assigned_by: "bob@example.com" },
|
|
44
|
+
{ name: "TD-0003", status: "Open", assigned_by: "carol@example.com" },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
function pressRows(container: HTMLElement): HTMLElement[] {
|
|
48
|
+
return Array.from(container.querySelectorAll('[data-report-row="true"]')) as HTMLElement[];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function renderGrid(overrides: Partial<ReportGridProps> = {}) {
|
|
52
|
+
const onOpenRow = vi.fn();
|
|
53
|
+
const onOpenLink = vi.fn();
|
|
54
|
+
const result = renderWithProviders(
|
|
55
|
+
<ReportGrid
|
|
56
|
+
columns={columns}
|
|
57
|
+
rows={buildGridRows(dataRows, 0, 20)}
|
|
58
|
+
sort={{ field: "modified", order: "desc" }}
|
|
59
|
+
onSortChange={vi.fn()}
|
|
60
|
+
columnFilters={{}}
|
|
61
|
+
onColumnFilterChange={vi.fn()}
|
|
62
|
+
onOpenRow={onOpenRow}
|
|
63
|
+
onOpenLink={onOpenLink}
|
|
64
|
+
totals={[]}
|
|
65
|
+
{...overrides}
|
|
66
|
+
/>,
|
|
67
|
+
);
|
|
68
|
+
return { ...result, onOpenRow, onOpenLink };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
describe("ReportGrid row activation (LC-50)", () => {
|
|
72
|
+
it("activates on a click anywhere in the row with the row's name", () => {
|
|
73
|
+
const { onOpenRow } = renderGrid();
|
|
74
|
+
fireEvent.click(screen.getByText("Closed"));
|
|
75
|
+
expect(onOpenRow).toHaveBeenCalledTimes(1);
|
|
76
|
+
expect(onOpenRow).toHaveBeenCalledWith("TD-0002");
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("activates on Enter AND Space, once per physical key press", () => {
|
|
80
|
+
const { container, onOpenRow } = renderGrid();
|
|
81
|
+
const rows = pressRows(container);
|
|
82
|
+
rows[0].focus();
|
|
83
|
+
|
|
84
|
+
fireEvent.keyDown(rows[0], { key: "Enter" });
|
|
85
|
+
expect(onOpenRow).toHaveBeenCalledTimes(1);
|
|
86
|
+
expect(onOpenRow).toHaveBeenLastCalledWith("TD-0001");
|
|
87
|
+
|
|
88
|
+
fireEvent.keyDown(rows[0], { key: " " });
|
|
89
|
+
expect(onOpenRow).toHaveBeenCalledTimes(2);
|
|
90
|
+
|
|
91
|
+
// Key auto-repeat never machine-guns activations.
|
|
92
|
+
fireEvent.keyDown(rows[0], { key: "Enter", repeat: true });
|
|
93
|
+
expect(onOpenRow).toHaveBeenCalledTimes(2);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("names each pressable row by doc identity (DG-A11Y-06)", () => {
|
|
97
|
+
const { container } = renderGrid();
|
|
98
|
+
expect(pressRows(container).map((row) => row.getAttribute("aria-label"))).toEqual([
|
|
99
|
+
"TD-0001",
|
|
100
|
+
"TD-0002",
|
|
101
|
+
"TD-0003",
|
|
102
|
+
]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
describe("ReportGrid roving tab stop (LC-49)", () => {
|
|
107
|
+
it("exposes exactly one tab stop; arrows and Home/End rove it", async () => {
|
|
108
|
+
const { container } = renderGrid();
|
|
109
|
+
const rows = pressRows(container);
|
|
110
|
+
expect(rows).toHaveLength(3);
|
|
111
|
+
expect(rows.map((row) => row.getAttribute("tabindex"))).toEqual(["0", "-1", "-1"]);
|
|
112
|
+
|
|
113
|
+
rows[0].focus();
|
|
114
|
+
expect(document.activeElement).toBe(rows[0]);
|
|
115
|
+
|
|
116
|
+
fireEvent.keyDown(rows[0], { key: "ArrowDown" });
|
|
117
|
+
expect(document.activeElement).toBe(rows[1]);
|
|
118
|
+
// The anchor follows focus: still exactly one tabindex=0.
|
|
119
|
+
await waitFor(() => {
|
|
120
|
+
const stops = pressRows(container).map((row) => row.getAttribute("tabindex"));
|
|
121
|
+
expect(stops).toEqual(["-1", "0", "-1"]);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
fireEvent.keyDown(rows[1], { key: "End" });
|
|
125
|
+
expect(document.activeElement).toBe(rows[2]);
|
|
126
|
+
fireEvent.keyDown(rows[2], { key: "Home" });
|
|
127
|
+
expect(document.activeElement).toBe(rows[0]);
|
|
128
|
+
fireEvent.keyDown(rows[0], { key: "ArrowUp" });
|
|
129
|
+
// Clamped at the first row — no wrap.
|
|
130
|
+
expect(document.activeElement).toBe(rows[0]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("group header rows are not pressable and hold no tab stop", () => {
|
|
134
|
+
const { container } = renderGrid({
|
|
135
|
+
rows: buildGridRows(dataRows, 0, 20, "status"),
|
|
136
|
+
groupByColumn: columns[1],
|
|
137
|
+
});
|
|
138
|
+
// Three data rows stay pressable; the injected group headers are not.
|
|
139
|
+
expect(pressRows(container)).toHaveLength(3);
|
|
140
|
+
const groupHeaderCells = Array.from(container.querySelectorAll('[role="rowheader"]'));
|
|
141
|
+
expect(groupHeaderCells.length).toBeGreaterThan(0);
|
|
142
|
+
for (const cell of groupHeaderCells) {
|
|
143
|
+
const groupRow = cell.closest('[role="row"]') as HTMLElement;
|
|
144
|
+
expect(groupRow.getAttribute("data-report-row")).toBeNull();
|
|
145
|
+
expect(groupRow.getAttribute("tabindex")).toBeNull();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe("ReportGrid inner interactive content wins", () => {
|
|
151
|
+
it("a Link cell press opens the linked doc, never the row", () => {
|
|
152
|
+
const { onOpenRow, onOpenLink } = renderGrid();
|
|
153
|
+
fireEvent.click(screen.getByText("alice@example.com"));
|
|
154
|
+
expect(onOpenLink).toHaveBeenCalledTimes(1);
|
|
155
|
+
expect(onOpenLink).toHaveBeenCalledWith("User", "alice@example.com");
|
|
156
|
+
expect(onOpenRow).not.toHaveBeenCalled();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("keys on focused inner content belong to that content, not the row", () => {
|
|
160
|
+
const { onOpenRow } = renderGrid();
|
|
161
|
+
// Keydown dispatched from the link bubbles to the row, where the
|
|
162
|
+
// target !== currentTarget guard hands it back to the inner control.
|
|
163
|
+
fireEvent.keyDown(screen.getByText("alice@example.com"), { key: "Enter" });
|
|
164
|
+
expect(onOpenRow).not.toHaveBeenCalled();
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("renders no per-cell pressable chrome inside body cells", () => {
|
|
168
|
+
const { container } = renderGrid();
|
|
169
|
+
const body = container.querySelector("tbody");
|
|
170
|
+
expect(body).not.toBeNull();
|
|
171
|
+
// Link cells are the only sanctioned inner interactive content; no
|
|
172
|
+
// per-cell buttons wrap plain values.
|
|
173
|
+
expect(body!.querySelectorAll('[role="button"], button')).toHaveLength(0);
|
|
174
|
+
});
|
|
175
|
+
});
|