@multiplatform.one/frappe-ui 7.23.1 → 7.24.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/FrappeCalendar.cjs +1 -1
- package/dist/cjs/FrappeCalendar.native.js +1 -1
- package/dist/cjs/FrappeCalendar.native.js.map +1 -1
- package/dist/cjs/FrappeDashboard.cjs +1 -1
- package/dist/cjs/FrappeDashboard.native.js +1 -1
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +8 -0
- package/dist/cjs/FrappeForm.native.js +9 -0
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeImageView.cjs +1 -1
- package/dist/cjs/FrappeImageView.native.js +1 -1
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeInsights.cjs +380 -0
- package/dist/cjs/FrappeInsights.native.js +447 -0
- package/dist/cjs/FrappeInsights.native.js.map +1 -0
- package/dist/cjs/FrappeLikedBy.cjs +5 -2
- package/dist/cjs/FrappeLikedBy.native.js +5 -2
- package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +406 -39
- package/dist/cjs/FrappeListView.native.js +469 -42
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeNotConfigured.cjs +54 -0
- package/dist/cjs/FrappeNotConfigured.native.js +58 -0
- package/dist/cjs/FrappeNotConfigured.native.js.map +1 -0
- package/dist/cjs/FrappeRecordView.cjs +199 -0
- package/dist/cjs/FrappeRecordView.native.js +218 -0
- package/dist/cjs/FrappeRecordView.native.js.map +1 -0
- 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.cjs +1 -1
- package/dist/cjs/FrappeReportView.native.js +2 -2
- package/dist/cjs/FrappeReportView.native.js.map +1 -1
- package/dist/cjs/FrappeTreeView.cjs +1 -1
- package/dist/cjs/FrappeTreeView.native.js +1 -1
- package/dist/cjs/desk/awesomebar.cjs +1 -1
- package/dist/cjs/desk/awesomebar.native.js +3 -3
- package/dist/cjs/desk/awesomebar.native.js.map +1 -1
- package/dist/cjs/fields/CodeEditor/index.cjs +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js +1 -1
- package/dist/cjs/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/cjs/fields/Color/index.cjs +1 -0
- package/dist/cjs/fields/Color/index.native.js +1 -0
- package/dist/cjs/fields/Color/index.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload.cjs +1 -1
- package/dist/cjs/fields/FileUpload.native.js +1 -1
- package/dist/cjs/fields/FileUpload.native.js.map +1 -1
- package/dist/cjs/fields/Heading/index.cjs +19 -12
- package/dist/cjs/fields/Heading/index.native.js +22 -13
- package/dist/cjs/fields/Heading/index.native.js.map +1 -1
- package/dist/cjs/fields/MarkdownEditor/index.cjs +2 -1
- package/dist/cjs/fields/MarkdownEditor/index.native.js +1 -1
- package/dist/cjs/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/cjs/frappeNavigation.cjs +12 -2
- package/dist/cjs/frappeNavigation.native.js +13 -2
- package/dist/cjs/frappeNavigation.native.js.map +1 -1
- package/dist/cjs/index.cjs +34 -0
- package/dist/cjs/index.native.js +34 -0
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/insights/InsightsFacetTags.cjs +147 -0
- package/dist/cjs/insights/InsightsFacetTags.native.js +165 -0
- package/dist/cjs/insights/InsightsFacetTags.native.js.map +1 -0
- package/dist/cjs/insights/InsightsKpiBand.cjs +124 -0
- package/dist/cjs/insights/InsightsKpiBand.native.js +133 -0
- package/dist/cjs/insights/InsightsKpiBand.native.js.map +1 -0
- package/dist/cjs/insights/InsightsLeaders.cjs +150 -0
- package/dist/cjs/insights/InsightsLeaders.native.js +178 -0
- package/dist/cjs/insights/InsightsLeaders.native.js.map +1 -0
- package/dist/cjs/insights/InsightsRecords.cjs +105 -0
- package/dist/cjs/insights/InsightsRecords.native.js +109 -0
- package/dist/cjs/insights/InsightsRecords.native.js.map +1 -0
- package/dist/cjs/insights/InsightsTable.cjs +157 -0
- package/dist/cjs/insights/InsightsTable.native.js +194 -0
- package/dist/cjs/insights/InsightsTable.native.js.map +1 -0
- package/dist/cjs/insights/insightsData.cjs +114 -0
- package/dist/cjs/insights/insightsData.native.js +220 -0
- package/dist/cjs/insights/insightsData.native.js.map +1 -0
- package/dist/cjs/insights/insightsRecord.cjs +35 -0
- package/dist/cjs/insights/insightsRecord.native.js +38 -0
- package/dist/cjs/insights/insightsRecord.native.js.map +1 -0
- package/dist/cjs/list/FacetBadge.cjs +62 -0
- package/dist/cjs/list/FacetBadge.native.js +66 -0
- package/dist/cjs/list/FacetBadge.native.js.map +1 -0
- package/dist/cjs/list/FacetRail.cjs +199 -0
- package/dist/cjs/list/FacetRail.native.js +223 -0
- package/dist/cjs/list/FacetRail.native.js.map +1 -0
- package/dist/cjs/list/ImageWell.cjs +111 -0
- package/dist/cjs/list/ImageWell.native.js +126 -0
- package/dist/cjs/list/ImageWell.native.js.map +1 -0
- package/dist/cjs/list/ListControls.cjs +226 -0
- package/dist/cjs/list/ListControls.native.js +252 -0
- package/dist/cjs/list/ListControls.native.js.map +1 -0
- package/dist/cjs/list/ListToastHost.cjs +54 -0
- package/dist/cjs/list/ListToastHost.native.js +59 -0
- package/dist/cjs/list/ListToastHost.native.js.map +1 -0
- package/dist/cjs/list/RangeFilter.cjs +122 -0
- package/dist/cjs/list/RangeFilter.native.js +135 -0
- package/dist/cjs/list/RangeFilter.native.js.map +1 -0
- package/dist/cjs/list/RecordCard.cjs +233 -0
- package/dist/cjs/list/RecordCard.native.js +173 -0
- package/dist/cjs/list/RecordCard.native.js.map +1 -0
- package/dist/cjs/list/ShufflePanel.cjs +112 -0
- package/dist/cjs/list/ShufflePanel.native.js +139 -0
- package/dist/cjs/list/ShufflePanel.native.js.map +1 -0
- package/dist/cjs/list/facetReading.cjs +71 -0
- package/dist/cjs/list/facetReading.native.js +163 -0
- package/dist/cjs/list/facetReading.native.js.map +1 -0
- package/dist/cjs/list/favorites.cjs +79 -0
- package/dist/cjs/list/favorites.native.js +91 -0
- package/dist/cjs/list/favorites.native.js.map +1 -0
- package/dist/cjs/list/listState.cjs +100 -0
- package/dist/cjs/list/listState.native.js +234 -0
- package/dist/cjs/list/listState.native.js.map +1 -0
- package/dist/cjs/list/recordLook.cjs +35 -0
- package/dist/cjs/list/recordLook.native.js +39 -0
- package/dist/cjs/list/recordLook.native.js.map +1 -0
- package/dist/cjs/list/useListControls.cjs +189 -0
- package/dist/cjs/list/useListControls.native.js +272 -0
- package/dist/cjs/list/useListControls.native.js.map +1 -0
- package/dist/cjs/record/RecordBars.cjs +200 -0
- package/dist/cjs/record/RecordBars.native.js +225 -0
- package/dist/cjs/record/RecordBars.native.js.map +1 -0
- package/dist/cjs/record/RecordGallery.cjs +67 -0
- package/dist/cjs/record/RecordGallery.native.js +75 -0
- package/dist/cjs/record/RecordGallery.native.js.map +1 -0
- package/dist/cjs/record/RecordHero.cjs +239 -0
- package/dist/cjs/record/RecordHero.native.js +250 -0
- package/dist/cjs/record/RecordHero.native.js.map +1 -0
- package/dist/cjs/record/RecordPage.cjs +330 -0
- package/dist/cjs/record/RecordPage.native.js +364 -0
- package/dist/cjs/record/RecordPage.native.js.map +1 -0
- package/dist/cjs/record/RecordPager.cjs +125 -0
- package/dist/cjs/record/RecordPager.native.js +130 -0
- package/dist/cjs/record/RecordPager.native.js.map +1 -0
- package/dist/cjs/record/RecordRows.cjs +126 -0
- package/dist/cjs/record/RecordRows.native.js +140 -0
- package/dist/cjs/record/RecordRows.native.js.map +1 -0
- package/dist/cjs/record/recordData.cjs +122 -0
- package/dist/cjs/record/recordData.native.js +189 -0
- package/dist/cjs/record/recordData.native.js.map +1 -0
- package/dist/cjs/record/recordSections.cjs +30 -0
- package/dist/cjs/record/recordSections.native.js +33 -0
- package/dist/cjs/record/recordSections.native.js.map +1 -0
- package/dist/cjs/useFrappeFacets.cjs +1 -1
- package/dist/cjs/useFrappeFacets.native.js +1 -1
- package/dist/cjs/useFrappeFacets.native.js.map +1 -1
- package/dist/esm/FrappeCalendar.mjs +1 -1
- package/dist/esm/FrappeCalendar.mjs.map +1 -1
- package/dist/esm/FrappeCalendar.native.js +1 -1
- package/dist/esm/FrappeCalendar.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.mjs +1 -1
- package/dist/esm/FrappeDashboard.mjs.map +1 -1
- package/dist/esm/FrappeDashboard.native.js +1 -1
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +8 -0
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +9 -0
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeImageView.mjs +1 -1
- package/dist/esm/FrappeImageView.mjs.map +1 -1
- package/dist/esm/FrappeImageView.native.js +1 -1
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeInsights.mjs +355 -0
- package/dist/esm/FrappeInsights.mjs.map +1 -0
- package/dist/esm/FrappeInsights.native.js +419 -0
- package/dist/esm/FrappeInsights.native.js.map +1 -0
- package/dist/esm/FrappeLikedBy.mjs +6 -3
- package/dist/esm/FrappeLikedBy.mjs.map +1 -1
- package/dist/esm/FrappeLikedBy.native.js +6 -3
- package/dist/esm/FrappeLikedBy.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +410 -43
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +473 -46
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeNotConfigured.mjs +29 -0
- package/dist/esm/FrappeNotConfigured.mjs.map +1 -0
- package/dist/esm/FrappeNotConfigured.native.js +30 -0
- package/dist/esm/FrappeNotConfigured.native.js.map +1 -0
- package/dist/esm/FrappeRecordView.mjs +174 -0
- package/dist/esm/FrappeRecordView.mjs.map +1 -0
- package/dist/esm/FrappeRecordView.native.js +190 -0
- package/dist/esm/FrappeRecordView.native.js.map +1 -0
- 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.mjs +1 -1
- package/dist/esm/FrappeReportView.mjs.map +1 -1
- package/dist/esm/FrappeReportView.native.js +2 -2
- package/dist/esm/FrappeReportView.native.js.map +1 -1
- package/dist/esm/FrappeTreeView.mjs +1 -1
- package/dist/esm/FrappeTreeView.mjs.map +1 -1
- package/dist/esm/FrappeTreeView.native.js +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 +3 -3
- package/dist/esm/desk/awesomebar.native.js.map +1 -1
- package/dist/esm/fields/CodeEditor/index.mjs +2 -2
- package/dist/esm/fields/CodeEditor/index.mjs.map +1 -1
- package/dist/esm/fields/CodeEditor/index.native.js +2 -2
- package/dist/esm/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/esm/fields/Color/index.mjs +1 -0
- package/dist/esm/fields/Color/index.mjs.map +1 -1
- package/dist/esm/fields/Color/index.native.js +1 -0
- package/dist/esm/fields/Color/index.native.js.map +1 -1
- package/dist/esm/fields/FileUpload.mjs +2 -2
- package/dist/esm/fields/FileUpload.mjs.map +1 -1
- package/dist/esm/fields/FileUpload.native.js +2 -2
- package/dist/esm/fields/FileUpload.native.js.map +1 -1
- package/dist/esm/fields/Heading/index.mjs +21 -14
- package/dist/esm/fields/Heading/index.mjs.map +1 -1
- package/dist/esm/fields/Heading/index.native.js +24 -15
- package/dist/esm/fields/Heading/index.native.js.map +1 -1
- package/dist/esm/fields/MarkdownEditor/index.mjs +2 -1
- package/dist/esm/fields/MarkdownEditor/index.mjs.map +1 -1
- package/dist/esm/fields/MarkdownEditor/index.native.js +2 -2
- package/dist/esm/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/esm/frappeNavigation.mjs +11 -2
- package/dist/esm/frappeNavigation.mjs.map +1 -1
- package/dist/esm/frappeNavigation.native.js +12 -2
- package/dist/esm/frappeNavigation.native.js.map +1 -1
- package/dist/esm/index.mjs +14 -2
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +14 -2
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/insights/InsightsFacetTags.mjs +122 -0
- package/dist/esm/insights/InsightsFacetTags.mjs.map +1 -0
- package/dist/esm/insights/InsightsFacetTags.native.js +137 -0
- package/dist/esm/insights/InsightsFacetTags.native.js.map +1 -0
- package/dist/esm/insights/InsightsKpiBand.mjs +99 -0
- package/dist/esm/insights/InsightsKpiBand.mjs.map +1 -0
- package/dist/esm/insights/InsightsKpiBand.native.js +105 -0
- package/dist/esm/insights/InsightsKpiBand.native.js.map +1 -0
- package/dist/esm/insights/InsightsLeaders.mjs +125 -0
- package/dist/esm/insights/InsightsLeaders.mjs.map +1 -0
- package/dist/esm/insights/InsightsLeaders.native.js +150 -0
- package/dist/esm/insights/InsightsLeaders.native.js.map +1 -0
- package/dist/esm/insights/InsightsRecords.mjs +80 -0
- package/dist/esm/insights/InsightsRecords.mjs.map +1 -0
- package/dist/esm/insights/InsightsRecords.native.js +81 -0
- package/dist/esm/insights/InsightsRecords.native.js.map +1 -0
- package/dist/esm/insights/InsightsTable.mjs +132 -0
- package/dist/esm/insights/InsightsTable.mjs.map +1 -0
- package/dist/esm/insights/InsightsTable.native.js +166 -0
- package/dist/esm/insights/InsightsTable.native.js.map +1 -0
- package/dist/esm/insights/insightsData.mjs +82 -0
- package/dist/esm/insights/insightsData.mjs.map +1 -0
- package/dist/esm/insights/insightsData.native.js +185 -0
- package/dist/esm/insights/insightsData.native.js.map +1 -0
- package/dist/esm/insights/insightsRecord.mjs +9 -0
- package/dist/esm/insights/insightsRecord.mjs.map +1 -0
- package/dist/esm/insights/insightsRecord.native.js +9 -0
- package/dist/esm/insights/insightsRecord.native.js.map +1 -0
- package/dist/esm/list/FacetBadge.mjs +37 -0
- package/dist/esm/list/FacetBadge.mjs.map +1 -0
- package/dist/esm/list/FacetBadge.native.js +38 -0
- package/dist/esm/list/FacetBadge.native.js.map +1 -0
- package/dist/esm/list/FacetRail.mjs +174 -0
- package/dist/esm/list/FacetRail.mjs.map +1 -0
- package/dist/esm/list/FacetRail.native.js +195 -0
- package/dist/esm/list/FacetRail.native.js.map +1 -0
- package/dist/esm/list/ImageWell.mjs +86 -0
- package/dist/esm/list/ImageWell.mjs.map +1 -0
- package/dist/esm/list/ImageWell.native.js +98 -0
- package/dist/esm/list/ImageWell.native.js.map +1 -0
- package/dist/esm/list/ListControls.mjs +201 -0
- package/dist/esm/list/ListControls.mjs.map +1 -0
- package/dist/esm/list/ListControls.native.js +224 -0
- package/dist/esm/list/ListControls.native.js.map +1 -0
- package/dist/esm/list/ListToastHost.mjs +18 -0
- package/dist/esm/list/ListToastHost.mjs.map +1 -0
- package/dist/esm/list/ListToastHost.native.js +20 -0
- package/dist/esm/list/ListToastHost.native.js.map +1 -0
- package/dist/esm/list/RangeFilter.mjs +85 -0
- package/dist/esm/list/RangeFilter.mjs.map +1 -0
- package/dist/esm/list/RangeFilter.native.js +95 -0
- package/dist/esm/list/RangeFilter.native.js.map +1 -0
- package/dist/esm/list/RecordCard.mjs +208 -0
- package/dist/esm/list/RecordCard.mjs.map +1 -0
- package/dist/esm/list/RecordCard.native.js +145 -0
- package/dist/esm/list/RecordCard.native.js.map +1 -0
- package/dist/esm/list/ShufflePanel.mjs +87 -0
- package/dist/esm/list/ShufflePanel.mjs.map +1 -0
- package/dist/esm/list/ShufflePanel.native.js +111 -0
- package/dist/esm/list/ShufflePanel.native.js.map +1 -0
- package/dist/esm/list/facetReading.mjs +45 -0
- package/dist/esm/list/facetReading.mjs.map +1 -0
- package/dist/esm/list/facetReading.native.js +134 -0
- package/dist/esm/list/facetReading.native.js.map +1 -0
- package/dist/esm/list/favorites.mjs +50 -0
- package/dist/esm/list/favorites.mjs.map +1 -0
- package/dist/esm/list/favorites.native.js +59 -0
- package/dist/esm/list/favorites.native.js.map +1 -0
- package/dist/esm/list/listState.mjs +71 -0
- package/dist/esm/list/listState.mjs.map +1 -0
- package/dist/esm/list/listState.native.js +202 -0
- package/dist/esm/list/listState.native.js.map +1 -0
- package/dist/esm/list/recordLook.mjs +10 -0
- package/dist/esm/list/recordLook.mjs.map +1 -0
- package/dist/esm/list/recordLook.native.js +11 -0
- package/dist/esm/list/recordLook.native.js.map +1 -0
- package/dist/esm/list/useListControls.mjs +164 -0
- package/dist/esm/list/useListControls.mjs.map +1 -0
- package/dist/esm/list/useListControls.native.js +244 -0
- package/dist/esm/list/useListControls.native.js.map +1 -0
- package/dist/esm/record/RecordBars.mjs +175 -0
- package/dist/esm/record/RecordBars.mjs.map +1 -0
- package/dist/esm/record/RecordBars.native.js +197 -0
- package/dist/esm/record/RecordBars.native.js.map +1 -0
- package/dist/esm/record/RecordGallery.mjs +42 -0
- package/dist/esm/record/RecordGallery.mjs.map +1 -0
- package/dist/esm/record/RecordGallery.native.js +47 -0
- package/dist/esm/record/RecordGallery.native.js.map +1 -0
- package/dist/esm/record/RecordHero.mjs +205 -0
- package/dist/esm/record/RecordHero.mjs.map +1 -0
- package/dist/esm/record/RecordHero.native.js +213 -0
- package/dist/esm/record/RecordHero.native.js.map +1 -0
- package/dist/esm/record/RecordPage.mjs +305 -0
- package/dist/esm/record/RecordPage.mjs.map +1 -0
- package/dist/esm/record/RecordPage.native.js +336 -0
- package/dist/esm/record/RecordPage.native.js.map +1 -0
- package/dist/esm/record/RecordPager.mjs +100 -0
- package/dist/esm/record/RecordPager.mjs.map +1 -0
- package/dist/esm/record/RecordPager.native.js +102 -0
- package/dist/esm/record/RecordPager.native.js.map +1 -0
- package/dist/esm/record/RecordRows.mjs +101 -0
- package/dist/esm/record/RecordRows.mjs.map +1 -0
- package/dist/esm/record/RecordRows.native.js +112 -0
- package/dist/esm/record/RecordRows.native.js.map +1 -0
- package/dist/esm/record/recordData.mjs +92 -0
- package/dist/esm/record/recordData.mjs.map +1 -0
- package/dist/esm/record/recordData.native.js +156 -0
- package/dist/esm/record/recordData.native.js.map +1 -0
- package/dist/esm/record/recordSections.mjs +5 -0
- package/dist/esm/record/recordSections.mjs.map +1 -0
- package/dist/esm/record/recordSections.native.js +5 -0
- package/dist/esm/record/recordSections.native.js.map +1 -0
- package/dist/esm/useFrappeFacets.mjs +1 -1
- package/dist/esm/useFrappeFacets.mjs.map +1 -1
- package/dist/esm/useFrappeFacets.native.js +1 -1
- package/dist/esm/useFrappeFacets.native.js.map +1 -1
- package/dist/jsx/FrappeCalendar.mjs +1 -1
- package/dist/jsx/FrappeCalendar.mjs.map +1 -1
- package/dist/jsx/FrappeCalendar.native.js +1 -1
- package/dist/jsx/FrappeCalendar.native.js.map +1 -1
- package/dist/jsx/FrappeDashboard.mjs +1 -1
- package/dist/jsx/FrappeDashboard.mjs.map +1 -1
- package/dist/jsx/FrappeDashboard.native.js +1 -1
- package/dist/jsx/FrappeDashboard.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +8 -0
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +9 -0
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeImageView.mjs +1 -1
- package/dist/jsx/FrappeImageView.mjs.map +1 -1
- package/dist/jsx/FrappeImageView.native.js +1 -1
- package/dist/jsx/FrappeImageView.native.js.map +1 -1
- package/dist/jsx/FrappeInsights.mjs +355 -0
- package/dist/jsx/FrappeInsights.mjs.map +1 -0
- package/dist/jsx/FrappeInsights.native.js +447 -0
- package/dist/jsx/FrappeInsights.native.js.map +1 -0
- package/dist/jsx/FrappeLikedBy.mjs +6 -3
- package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
- package/dist/jsx/FrappeLikedBy.native.js +5 -2
- package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +410 -43
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +469 -42
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeNotConfigured.mjs +29 -0
- package/dist/jsx/FrappeNotConfigured.mjs.map +1 -0
- package/dist/jsx/FrappeNotConfigured.native.js +58 -0
- package/dist/jsx/FrappeNotConfigured.native.js.map +1 -0
- package/dist/jsx/FrappeRecordView.mjs +174 -0
- package/dist/jsx/FrappeRecordView.mjs.map +1 -0
- package/dist/jsx/FrappeRecordView.native.js +218 -0
- package/dist/jsx/FrappeRecordView.native.js.map +1 -0
- 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/FrappeReportView.mjs +1 -1
- package/dist/jsx/FrappeReportView.mjs.map +1 -1
- package/dist/jsx/FrappeReportView.native.js +2 -2
- package/dist/jsx/FrappeReportView.native.js.map +1 -1
- package/dist/jsx/FrappeTreeView.mjs +1 -1
- package/dist/jsx/FrappeTreeView.mjs.map +1 -1
- package/dist/jsx/FrappeTreeView.native.js +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 +3 -3
- package/dist/jsx/desk/awesomebar.native.js.map +1 -1
- package/dist/jsx/fields/CodeEditor/index.mjs +2 -2
- package/dist/jsx/fields/CodeEditor/index.mjs.map +1 -1
- package/dist/jsx/fields/CodeEditor/index.native.js +1 -1
- package/dist/jsx/fields/CodeEditor/index.native.js.map +1 -1
- package/dist/jsx/fields/Color/index.mjs +1 -0
- package/dist/jsx/fields/Color/index.mjs.map +1 -1
- package/dist/jsx/fields/Color/index.native.js +1 -0
- package/dist/jsx/fields/Color/index.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload.mjs +2 -2
- package/dist/jsx/fields/FileUpload.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload.native.js +1 -1
- package/dist/jsx/fields/FileUpload.native.js.map +1 -1
- package/dist/jsx/fields/Heading/index.mjs +21 -14
- package/dist/jsx/fields/Heading/index.mjs.map +1 -1
- package/dist/jsx/fields/Heading/index.native.js +22 -13
- package/dist/jsx/fields/Heading/index.native.js.map +1 -1
- package/dist/jsx/fields/MarkdownEditor/index.mjs +2 -1
- package/dist/jsx/fields/MarkdownEditor/index.mjs.map +1 -1
- package/dist/jsx/fields/MarkdownEditor/index.native.js +1 -1
- package/dist/jsx/fields/MarkdownEditor/index.native.js.map +1 -1
- package/dist/jsx/frappeNavigation.mjs +11 -2
- package/dist/jsx/frappeNavigation.mjs.map +1 -1
- package/dist/jsx/frappeNavigation.native.js +13 -2
- package/dist/jsx/frappeNavigation.native.js.map +1 -1
- package/dist/jsx/index.js +14 -2
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +14 -2
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +34 -0
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/insights/InsightsFacetTags.mjs +122 -0
- package/dist/jsx/insights/InsightsFacetTags.mjs.map +1 -0
- package/dist/jsx/insights/InsightsFacetTags.native.js +165 -0
- package/dist/jsx/insights/InsightsFacetTags.native.js.map +1 -0
- package/dist/jsx/insights/InsightsKpiBand.mjs +99 -0
- package/dist/jsx/insights/InsightsKpiBand.mjs.map +1 -0
- package/dist/jsx/insights/InsightsKpiBand.native.js +133 -0
- package/dist/jsx/insights/InsightsKpiBand.native.js.map +1 -0
- package/dist/jsx/insights/InsightsLeaders.mjs +125 -0
- package/dist/jsx/insights/InsightsLeaders.mjs.map +1 -0
- package/dist/jsx/insights/InsightsLeaders.native.js +178 -0
- package/dist/jsx/insights/InsightsLeaders.native.js.map +1 -0
- package/dist/jsx/insights/InsightsRecords.mjs +80 -0
- package/dist/jsx/insights/InsightsRecords.mjs.map +1 -0
- package/dist/jsx/insights/InsightsRecords.native.js +109 -0
- package/dist/jsx/insights/InsightsRecords.native.js.map +1 -0
- package/dist/jsx/insights/InsightsTable.mjs +132 -0
- package/dist/jsx/insights/InsightsTable.mjs.map +1 -0
- package/dist/jsx/insights/InsightsTable.native.js +194 -0
- package/dist/jsx/insights/InsightsTable.native.js.map +1 -0
- package/dist/jsx/insights/insightsData.mjs +82 -0
- package/dist/jsx/insights/insightsData.mjs.map +1 -0
- package/dist/jsx/insights/insightsData.native.js +220 -0
- package/dist/jsx/insights/insightsData.native.js.map +1 -0
- package/dist/jsx/insights/insightsRecord.mjs +9 -0
- package/dist/jsx/insights/insightsRecord.mjs.map +1 -0
- package/dist/jsx/insights/insightsRecord.native.js +38 -0
- package/dist/jsx/insights/insightsRecord.native.js.map +1 -0
- package/dist/jsx/list/FacetBadge.mjs +37 -0
- package/dist/jsx/list/FacetBadge.mjs.map +1 -0
- package/dist/jsx/list/FacetBadge.native.js +66 -0
- package/dist/jsx/list/FacetBadge.native.js.map +1 -0
- package/dist/jsx/list/FacetRail.mjs +174 -0
- package/dist/jsx/list/FacetRail.mjs.map +1 -0
- package/dist/jsx/list/FacetRail.native.js +223 -0
- package/dist/jsx/list/FacetRail.native.js.map +1 -0
- package/dist/jsx/list/ImageWell.mjs +86 -0
- package/dist/jsx/list/ImageWell.mjs.map +1 -0
- package/dist/jsx/list/ImageWell.native.js +126 -0
- package/dist/jsx/list/ImageWell.native.js.map +1 -0
- package/dist/jsx/list/ListControls.mjs +201 -0
- package/dist/jsx/list/ListControls.mjs.map +1 -0
- package/dist/jsx/list/ListControls.native.js +252 -0
- package/dist/jsx/list/ListControls.native.js.map +1 -0
- package/dist/jsx/list/ListToastHost.mjs +18 -0
- package/dist/jsx/list/ListToastHost.mjs.map +1 -0
- package/dist/jsx/list/ListToastHost.native.js +59 -0
- package/dist/jsx/list/ListToastHost.native.js.map +1 -0
- package/dist/jsx/list/RangeFilter.mjs +85 -0
- package/dist/jsx/list/RangeFilter.mjs.map +1 -0
- package/dist/jsx/list/RangeFilter.native.js +135 -0
- package/dist/jsx/list/RangeFilter.native.js.map +1 -0
- package/dist/jsx/list/RecordCard.mjs +208 -0
- package/dist/jsx/list/RecordCard.mjs.map +1 -0
- package/dist/jsx/list/RecordCard.native.js +173 -0
- package/dist/jsx/list/RecordCard.native.js.map +1 -0
- package/dist/jsx/list/ShufflePanel.mjs +87 -0
- package/dist/jsx/list/ShufflePanel.mjs.map +1 -0
- package/dist/jsx/list/ShufflePanel.native.js +139 -0
- package/dist/jsx/list/ShufflePanel.native.js.map +1 -0
- package/dist/jsx/list/facetReading.mjs +45 -0
- package/dist/jsx/list/facetReading.mjs.map +1 -0
- package/dist/jsx/list/facetReading.native.js +163 -0
- package/dist/jsx/list/facetReading.native.js.map +1 -0
- package/dist/jsx/list/favorites.mjs +50 -0
- package/dist/jsx/list/favorites.mjs.map +1 -0
- package/dist/jsx/list/favorites.native.js +91 -0
- package/dist/jsx/list/favorites.native.js.map +1 -0
- package/dist/jsx/list/listState.mjs +71 -0
- package/dist/jsx/list/listState.mjs.map +1 -0
- package/dist/jsx/list/listState.native.js +234 -0
- package/dist/jsx/list/listState.native.js.map +1 -0
- package/dist/jsx/list/recordLook.mjs +10 -0
- package/dist/jsx/list/recordLook.mjs.map +1 -0
- package/dist/jsx/list/recordLook.native.js +39 -0
- package/dist/jsx/list/recordLook.native.js.map +1 -0
- package/dist/jsx/list/useListControls.mjs +164 -0
- package/dist/jsx/list/useListControls.mjs.map +1 -0
- package/dist/jsx/list/useListControls.native.js +272 -0
- package/dist/jsx/list/useListControls.native.js.map +1 -0
- package/dist/jsx/record/RecordBars.mjs +175 -0
- package/dist/jsx/record/RecordBars.mjs.map +1 -0
- package/dist/jsx/record/RecordBars.native.js +225 -0
- package/dist/jsx/record/RecordBars.native.js.map +1 -0
- package/dist/jsx/record/RecordGallery.mjs +42 -0
- package/dist/jsx/record/RecordGallery.mjs.map +1 -0
- package/dist/jsx/record/RecordGallery.native.js +75 -0
- package/dist/jsx/record/RecordGallery.native.js.map +1 -0
- package/dist/jsx/record/RecordHero.mjs +205 -0
- package/dist/jsx/record/RecordHero.mjs.map +1 -0
- package/dist/jsx/record/RecordHero.native.js +250 -0
- package/dist/jsx/record/RecordHero.native.js.map +1 -0
- package/dist/jsx/record/RecordPage.mjs +305 -0
- package/dist/jsx/record/RecordPage.mjs.map +1 -0
- package/dist/jsx/record/RecordPage.native.js +364 -0
- package/dist/jsx/record/RecordPage.native.js.map +1 -0
- package/dist/jsx/record/RecordPager.mjs +100 -0
- package/dist/jsx/record/RecordPager.mjs.map +1 -0
- package/dist/jsx/record/RecordPager.native.js +130 -0
- package/dist/jsx/record/RecordPager.native.js.map +1 -0
- package/dist/jsx/record/RecordRows.mjs +101 -0
- package/dist/jsx/record/RecordRows.mjs.map +1 -0
- package/dist/jsx/record/RecordRows.native.js +140 -0
- package/dist/jsx/record/RecordRows.native.js.map +1 -0
- package/dist/jsx/record/recordData.mjs +92 -0
- package/dist/jsx/record/recordData.mjs.map +1 -0
- package/dist/jsx/record/recordData.native.js +189 -0
- package/dist/jsx/record/recordData.native.js.map +1 -0
- package/dist/jsx/record/recordSections.mjs +5 -0
- package/dist/jsx/record/recordSections.mjs.map +1 -0
- package/dist/jsx/record/recordSections.native.js +33 -0
- package/dist/jsx/record/recordSections.native.js.map +1 -0
- package/dist/jsx/useFrappeFacets.mjs +1 -1
- package/dist/jsx/useFrappeFacets.mjs.map +1 -1
- package/dist/jsx/useFrappeFacets.native.js +1 -1
- package/dist/jsx/useFrappeFacets.native.js.map +1 -1
- package/package.json +16 -16
- package/src/FormSidebar.stories.tsx +2 -0
- package/src/FrappeCalendar.stories.tsx +2 -0
- package/src/FrappeCalendar.tsx +2 -2
- package/src/FrappeChartCard.stories.tsx +2 -0
- package/src/FrappeDashboard.stories.tsx +2 -0
- package/src/FrappeDashboard.tsx +2 -2
- package/src/FrappeForm.tsx +7 -1
- package/src/FrappeImageView.stories.tsx +2 -0
- package/src/FrappeImageView.tsx +2 -1
- package/src/FrappeInsights.spec.tsx +171 -0
- package/src/FrappeInsights.tsx +422 -0
- package/src/FrappeKPICard.stories.tsx +3 -3
- package/src/FrappeKanban.stories.tsx +4 -8
- package/src/FrappeLikedBy.tsx +7 -5
- package/src/FrappeListView.card.spec.tsx +157 -0
- package/src/FrappeListView.controls.spec.tsx +225 -0
- package/src/FrappeListView.seed.spec.tsx +30 -0
- package/src/FrappeListView.stories.tsx +2 -0
- package/src/FrappeListView.tsx +589 -45
- package/src/FrappeNotConfigured.tsx +29 -0
- package/src/FrappeRecordView.spec.tsx +276 -0
- package/src/FrappeRecordView.tsx +231 -0
- package/src/FrappeReportBuilder.tsx +4 -5
- package/src/FrappeReportView.tsx +1 -1
- package/src/FrappeTreeView.tsx +1 -1
- package/src/clientCache.auth.spec.tsx +94 -0
- package/src/desk/DeskFormSidebar.stories.tsx +2 -0
- package/src/desk/DeskShell.stories.tsx +12 -6
- package/src/desk/awesomebar.auth.spec.tsx +77 -0
- package/src/desk/awesomebar.tsx +1 -1
- package/src/fields/CodeEditor/index.tsx +8 -2
- package/src/fields/Color/Color.stories.tsx +2 -0
- package/src/fields/Color/index.tsx +1 -0
- package/src/fields/FileUpload.tsx +8 -2
- package/src/fields/Heading/index.tsx +41 -17
- package/src/fields/MarkdownEditor/index.native.tsx +8 -2
- package/src/fields/MarkdownEditor/index.tsx +8 -1
- package/src/fields/ReadOnly/ReadOnly.stories.tsx +2 -0
- package/src/frappeNavigation.loader.spec.tsx +45 -0
- package/src/frappeNavigation.tsx +32 -1
- package/src/frappeRoutes.notConfigured.spec.tsx +77 -0
- package/src/index.ts +53 -1
- package/src/insights/InsightsFacetTags.tsx +131 -0
- package/src/insights/InsightsKpiBand.tsx +114 -0
- package/src/insights/InsightsLeaders.tsx +146 -0
- package/src/insights/InsightsRecords.tsx +71 -0
- package/src/insights/InsightsTable.tsx +169 -0
- package/src/insights/insightsData.spec.ts +143 -0
- package/src/insights/insightsData.ts +122 -0
- package/src/insights/insightsRecord.ts +36 -0
- package/src/list/FacetBadge.tsx +41 -0
- package/src/list/FacetRail.tsx +235 -0
- package/src/list/ImageWell.tsx +110 -0
- package/src/list/ListControls.tsx +208 -0
- package/src/list/ListToastHost.tsx +27 -0
- package/src/list/RangeFilter.tsx +83 -0
- package/src/list/RecordCard.native.tsx +126 -0
- package/src/list/RecordCard.tsx +260 -0
- package/src/list/ShufflePanel.tsx +107 -0
- package/src/list/facetReading.ts +79 -0
- package/src/list/favorites.spec.ts +80 -0
- package/src/list/favorites.ts +79 -0
- package/src/list/listState.spec.ts +156 -0
- package/src/list/listState.ts +184 -0
- package/src/list/recordLook.ts +37 -0
- package/src/list/useListControls.tsx +223 -0
- package/src/record/RecordBars.tsx +187 -0
- package/src/record/RecordGallery.tsx +47 -0
- package/src/record/RecordHero.tsx +186 -0
- package/src/record/RecordPage.tsx +358 -0
- package/src/record/RecordPager.tsx +97 -0
- package/src/record/RecordRows.tsx +90 -0
- package/src/record/recordData.spec.ts +148 -0
- package/src/record/recordData.ts +124 -0
- package/src/record/recordSections.ts +62 -0
- package/src/schemaForm/SchemaForm.stories.tsx +2 -2
- package/src/useFrappeFacets.ts +14 -7
- package/types/FrappeForm.d.ts +2 -1
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeImageView.d.ts.map +1 -1
- package/types/FrappeInsights.d.ts +55 -0
- package/types/FrappeInsights.d.ts.map +1 -0
- package/types/FrappeLikedBy.d.ts.map +1 -1
- package/types/FrappeListView.d.ts +85 -3
- package/types/FrappeListView.d.ts.map +1 -1
- package/types/FrappeNotConfigured.d.ts +11 -0
- package/types/FrappeNotConfigured.d.ts.map +1 -0
- package/types/FrappeRecordView.d.ts +69 -0
- package/types/FrappeRecordView.d.ts.map +1 -0
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/fields/CodeEditor/index.d.ts.map +1 -1
- package/types/fields/Color/index.d.ts.map +1 -1
- package/types/fields/FileUpload.d.ts.map +1 -1
- package/types/fields/Heading/index.d.ts.map +1 -1
- package/types/fields/MarkdownEditor/index.d.ts.map +1 -1
- package/types/fields/MarkdownEditor/index.native.d.ts.map +1 -1
- package/types/frappeNavigation.d.ts +21 -0
- package/types/frappeNavigation.d.ts.map +1 -1
- package/types/index.d.ts +14 -2
- package/types/index.d.ts.map +1 -1
- package/types/insights/InsightsFacetTags.d.ts +11 -0
- package/types/insights/InsightsFacetTags.d.ts.map +1 -0
- package/types/insights/InsightsKpiBand.d.ts +22 -0
- package/types/insights/InsightsKpiBand.d.ts.map +1 -0
- package/types/insights/InsightsLeaders.d.ts +16 -0
- package/types/insights/InsightsLeaders.d.ts.map +1 -0
- package/types/insights/InsightsRecords.d.ts +19 -0
- package/types/insights/InsightsRecords.d.ts.map +1 -0
- package/types/insights/InsightsTable.d.ts +17 -0
- package/types/insights/InsightsTable.d.ts.map +1 -0
- package/types/insights/insightsData.d.ts +45 -0
- package/types/insights/insightsData.d.ts.map +1 -0
- package/types/insights/insightsRecord.d.ts +29 -0
- package/types/insights/insightsRecord.d.ts.map +1 -0
- package/types/list/FacetBadge.d.ts +13 -0
- package/types/list/FacetBadge.d.ts.map +1 -0
- package/types/list/FacetRail.d.ts +26 -0
- package/types/list/FacetRail.d.ts.map +1 -0
- package/types/list/ImageWell.d.ts +24 -0
- package/types/list/ImageWell.d.ts.map +1 -0
- package/types/list/ListControls.d.ts +30 -0
- package/types/list/ListControls.d.ts.map +1 -0
- package/types/list/ListToastHost.d.ts +7 -0
- package/types/list/ListToastHost.d.ts.map +1 -0
- package/types/list/RangeFilter.d.ts +14 -0
- package/types/list/RangeFilter.d.ts.map +1 -0
- package/types/list/RecordCard.d.ts +38 -0
- package/types/list/RecordCard.d.ts.map +1 -0
- package/types/list/RecordCard.native.d.ts +9 -0
- package/types/list/RecordCard.native.d.ts.map +1 -0
- package/types/list/ShufflePanel.d.ts +24 -0
- package/types/list/ShufflePanel.d.ts.map +1 -0
- package/types/list/facetReading.d.ts +33 -0
- package/types/list/facetReading.d.ts.map +1 -0
- package/types/list/favorites.d.ts +26 -0
- package/types/list/favorites.d.ts.map +1 -0
- package/types/list/listState.d.ts +94 -0
- package/types/list/listState.d.ts.map +1 -0
- package/types/list/recordLook.d.ts +25 -0
- package/types/list/recordLook.d.ts.map +1 -0
- package/types/list/useListControls.d.ts +48 -0
- package/types/list/useListControls.d.ts.map +1 -0
- package/types/record/RecordBars.d.ts +11 -0
- package/types/record/RecordBars.d.ts.map +1 -0
- package/types/record/RecordGallery.d.ts +17 -0
- package/types/record/RecordGallery.d.ts.map +1 -0
- package/types/record/RecordHero.d.ts +42 -0
- package/types/record/RecordHero.d.ts.map +1 -0
- package/types/record/RecordPage.d.ts +54 -0
- package/types/record/RecordPage.d.ts.map +1 -0
- package/types/record/RecordPager.d.ts +13 -0
- package/types/record/RecordPager.d.ts.map +1 -0
- package/types/record/RecordRows.d.ts +13 -0
- package/types/record/RecordRows.d.ts.map +1 -0
- package/types/record/recordData.d.ts +46 -0
- package/types/record/recordData.d.ts.map +1 -0
- package/types/record/recordSections.d.ts +67 -0
- package/types/record/recordSections.d.ts.map +1 -0
- package/types/useFrappeFacets.d.ts.map +1 -1
package/src/FrappeListView.tsx
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { HttpClient, useDocTypeMeta } from "@multiplatform.one/frappe";
|
|
2
2
|
import type { DataTableColumn } from "@multiplatform.one/table";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
ArrowsClockwiseIcon,
|
|
5
|
+
HeartIcon,
|
|
6
|
+
ImageIcon,
|
|
7
|
+
ListIcon,
|
|
8
|
+
MagnifyingGlassIcon,
|
|
9
|
+
PlusIcon,
|
|
10
|
+
SparkleIcon,
|
|
11
|
+
TableIcon,
|
|
12
|
+
} from "@phosphor-icons/react";
|
|
4
13
|
import React, { useState, useMemo, useCallback, useEffect } from "react";
|
|
5
14
|
import { useTranslation } from "react-i18next";
|
|
6
15
|
import { Button, SearchInput, Spinner } from "@multiplatform.one/forms";
|
|
@@ -9,21 +18,44 @@ import { SavedFilterDropdown, useSavedFilters, type ParsedFilter } from "@multip
|
|
|
9
18
|
import {
|
|
10
19
|
AsyncBoundary,
|
|
11
20
|
Avatar,
|
|
21
|
+
EmptyState,
|
|
12
22
|
ListPageLayout,
|
|
13
23
|
PageHeader,
|
|
24
|
+
SkipLink,
|
|
25
|
+
Tooltip,
|
|
14
26
|
ViewSwitcher,
|
|
15
27
|
componentColors,
|
|
28
|
+
showToast,
|
|
16
29
|
type ImageGridProps,
|
|
17
30
|
} from "@multiplatform.one/components";
|
|
18
31
|
import { pressTargetStyle, useResolvedKnobs } from "@multiplatform.one/theme";
|
|
19
32
|
import { storage } from "@multiplatform.one/store";
|
|
20
33
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
21
34
|
import { FrappeList, type FrappeListProps } from "./FrappeList";
|
|
35
|
+
import { FrappeNotConfigured } from "./FrappeNotConfigured";
|
|
36
|
+
import { FrappeRowsReader, type FrappeRowsSnapshot } from "./FrappeRowsReader";
|
|
22
37
|
import { FrappeTable } from "./FrappeTable";
|
|
23
38
|
import { useDocRights } from "./formEngine/useDocRights";
|
|
24
|
-
import { frappeRouteHref, useFrappeRouter } from "./frappeNavigation";
|
|
39
|
+
import { frappeRouteHref, useFrappeRouter, useRouteLoaderData } from "./frappeNavigation";
|
|
25
40
|
import { connectionsFromMeta, type FrappeConnection } from "./frappeConnections";
|
|
26
41
|
import { isPermissionError } from "./liveErrors";
|
|
42
|
+
import { favoritesKey } from "./list/favorites";
|
|
43
|
+
import { RecordCard } from "./list/RecordCard";
|
|
44
|
+
import { recordTitle, type FrappeRecordLook } from "./list/recordLook";
|
|
45
|
+
import { ListControls } from "./list/ListControls";
|
|
46
|
+
import {
|
|
47
|
+
isListNarrowed,
|
|
48
|
+
listStateFilters,
|
|
49
|
+
listStateOrderBy,
|
|
50
|
+
type FrappeListControls,
|
|
51
|
+
type FrappeListFacet,
|
|
52
|
+
type FrappeListFilter,
|
|
53
|
+
type FrappeListRange,
|
|
54
|
+
type FrappeListSort,
|
|
55
|
+
} from "./list/listState";
|
|
56
|
+
import { ListToastHost } from "./list/ListToastHost";
|
|
57
|
+
import { ShufflePanel } from "./list/ShufflePanel";
|
|
58
|
+
import { useListControls } from "./list/useListControls";
|
|
27
59
|
import { useConnectionFilters, type FrappeDoctypeFilter } from "./useConnectionFilters";
|
|
28
60
|
|
|
29
61
|
interface ListFieldConfig {
|
|
@@ -34,6 +66,30 @@ interface ListFieldConfig {
|
|
|
34
66
|
|
|
35
67
|
export type ListViewMode = "list" | "table" | "grid";
|
|
36
68
|
|
|
69
|
+
/** What a card needs from the list beyond its row. */
|
|
70
|
+
export interface FrappeListCard {
|
|
71
|
+
/** The record's page, when the list is routed. */
|
|
72
|
+
href?: string;
|
|
73
|
+
/** Opens the record the way a row press does. */
|
|
74
|
+
open: () => void;
|
|
75
|
+
/** Facet param to the record's values (a Pokemon's types, in slot order). */
|
|
76
|
+
facets: Record<string, string[]>;
|
|
77
|
+
/** Present when the list offers favorites. */
|
|
78
|
+
favorite?: { active: boolean; toggle: () => void };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** A page-header action of a routed list; icon-only under sm. */
|
|
82
|
+
export interface FrappeListAction {
|
|
83
|
+
label: string;
|
|
84
|
+
icon?: React.ComponentType<{ size?: number }>;
|
|
85
|
+
/** Opened through the FrappeProvider's navigation. */
|
|
86
|
+
href?: string;
|
|
87
|
+
onPress?: () => void;
|
|
88
|
+
/** Tooltip. */
|
|
89
|
+
hint?: string;
|
|
90
|
+
testID?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
37
93
|
export interface FrappeListViewProps<TDoc extends { name: string; doctype: string }> extends Omit<
|
|
38
94
|
YStackProps,
|
|
39
95
|
"children"
|
|
@@ -70,14 +126,27 @@ export interface FrappeListViewProps<TDoc extends { name: string; doctype: strin
|
|
|
70
126
|
orderBy?: FrappeListProps<TDoc>["orderBy"];
|
|
71
127
|
limit?: number;
|
|
72
128
|
initialRows?: readonly Partial<TDoc>[];
|
|
129
|
+
/**
|
|
130
|
+
* The route's loader (`frappeListLoader`): the rows it rendered on the
|
|
131
|
+
* server seed the list, read through the host's navigation.
|
|
132
|
+
*/
|
|
133
|
+
loader?: (...args: never[]) => Promise<{ rows: readonly Partial<TDoc>[] }>;
|
|
73
134
|
columns?: DataTableColumn<Partial<TDoc>>[];
|
|
74
135
|
displayFields?: ListFieldConfig[];
|
|
75
136
|
/**
|
|
76
137
|
* Per-row card slot. Given, the view gains a card grid (`grid` mode, the
|
|
77
138
|
* catalog ImageGrid) that draws each row with it; loading, empty and error
|
|
78
|
-
* stay the view's own states.
|
|
139
|
+
* stay the view's own states. A host that draws the grid itself may leave
|
|
140
|
+
* `card` out.
|
|
79
141
|
*/
|
|
80
|
-
renderCard?: (doc: Partial<TDoc>, index: number) => React.ReactNode;
|
|
142
|
+
renderCard?: (doc: Partial<TDoc>, index: number, card?: FrappeListCard) => React.ReactNode;
|
|
143
|
+
/**
|
|
144
|
+
* How the doctype's records present. With `images` and no card slot, the
|
|
145
|
+
* grid draws each record as a RecordCard: the look's title, code,
|
|
146
|
+
* subtitle and images, the well tinted and badged by the first facet that
|
|
147
|
+
* declares tints, the favorite heart when the list keeps favorites.
|
|
148
|
+
*/
|
|
149
|
+
look?: FrappeRecordLook<TDoc>;
|
|
81
150
|
/** Card grid: column count, tile rung and media aspect. */
|
|
82
151
|
gridProps?: Pick<ImageGridProps<Partial<TDoc>>, "columns" | "tileSize" | "mediaAspect">;
|
|
83
152
|
/** Replaces the default empty message in list and card modes. */
|
|
@@ -97,6 +166,40 @@ export interface FrappeListViewProps<TDoc extends { name: string; doctype: strin
|
|
|
97
166
|
showFilterSidebar?: boolean;
|
|
98
167
|
/** @deprecated The toolbar always renders the List/Table switcher now. */
|
|
99
168
|
enableViewSwitcher?: boolean;
|
|
169
|
+
/** Routed page title; defaults to the doctype. */
|
|
170
|
+
title?: string;
|
|
171
|
+
/** Routed page subtitle from the number of records the list reads. */
|
|
172
|
+
subtitle?: (count: number) => string;
|
|
173
|
+
/**
|
|
174
|
+
* Routed page actions. With the toolbar off, the view switcher and Add
|
|
175
|
+
* join them in the page header.
|
|
176
|
+
*/
|
|
177
|
+
actions?: readonly FrappeListAction[];
|
|
178
|
+
/** Header content ahead of the actions. */
|
|
179
|
+
headerAccessory?: React.ReactNode;
|
|
180
|
+
/** The field that names a record in toasts; defaults to meta.title_field. */
|
|
181
|
+
titleField?: string;
|
|
182
|
+
/** Sort choices, first is the default; given, a Sort select joins the controls. */
|
|
183
|
+
sorts?: readonly FrappeListSort[];
|
|
184
|
+
/** The bench filters a search becomes; defaults to a like on the title field. */
|
|
185
|
+
searchFilter?: (query: string) => readonly FrappeListFilter[];
|
|
186
|
+
searchPlaceholder?: string;
|
|
187
|
+
/** One chip rail per facet, with each value's record count. */
|
|
188
|
+
facets?: readonly FrappeListFacet[];
|
|
189
|
+
/** One minimum-value slider per numeric field. */
|
|
190
|
+
ranges?: readonly FrappeListRange[];
|
|
191
|
+
/**
|
|
192
|
+
* Star records on this device and filter to them: true keys the stars by
|
|
193
|
+
* doctype, a string names the storage key.
|
|
194
|
+
*/
|
|
195
|
+
favorites?: boolean | string;
|
|
196
|
+
/** A random-record picker; `label` names a record on its wheel. */
|
|
197
|
+
shuffle?: { label: (doc: Partial<TDoc>) => string };
|
|
198
|
+
/**
|
|
199
|
+
* Keep the controls and the view in the route's query params, so a
|
|
200
|
+
* refresh or a shared link reproduces the list.
|
|
201
|
+
*/
|
|
202
|
+
urlState?: boolean;
|
|
100
203
|
baseURL?: string;
|
|
101
204
|
auth?: { useToken?: boolean; token?: string; type?: string };
|
|
102
205
|
syncOptions?: Record<string, unknown>;
|
|
@@ -104,6 +207,9 @@ export interface FrappeListViewProps<TDoc extends { name: string; doctype: strin
|
|
|
104
207
|
|
|
105
208
|
const storageKeyPrefix = "frappe-listview-";
|
|
106
209
|
|
|
210
|
+
/** Cards whose images load eagerly; the rest wait until they near the viewport. */
|
|
211
|
+
const eagerCards = 6;
|
|
212
|
+
|
|
107
213
|
// Frappe document bookkeeping keys -- never useful as display columns.
|
|
108
214
|
const internalDocKeys = new Set([
|
|
109
215
|
"name",
|
|
@@ -170,8 +276,20 @@ async function setStoredViewMode(doctype: string, mode: ListViewMode): Promise<v
|
|
|
170
276
|
*
|
|
171
277
|
* Delegates to `FrappeList` (which delegates to generic `List`) or
|
|
172
278
|
* `FrappeTable` (which delegates to `DataTable`) based on the view mode.
|
|
279
|
+
* With neither a bench URL nor a fixture corpus it says Frappe is not
|
|
280
|
+
* configured.
|
|
173
281
|
*/
|
|
174
|
-
export function FrappeListView<TDoc extends { name: string; doctype: string }>(
|
|
282
|
+
export function FrappeListView<TDoc extends { name: string; doctype: string }>(
|
|
283
|
+
props: FrappeListViewProps<TDoc>,
|
|
284
|
+
) {
|
|
285
|
+
const config = useFrappeConfig();
|
|
286
|
+
if (!(props.baseURL ?? config?.baseURL) && !config?.fixtures) {
|
|
287
|
+
return <FrappeNotConfigured doctype={props.doctype} page={props.route !== undefined} />;
|
|
288
|
+
}
|
|
289
|
+
return <FrappeListViewBody<TDoc> {...props} />;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function FrappeListViewBody<TDoc extends { name: string; doctype: string }>({
|
|
175
293
|
doctype,
|
|
176
294
|
fields,
|
|
177
295
|
connections,
|
|
@@ -184,10 +302,12 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
184
302
|
route,
|
|
185
303
|
orderBy,
|
|
186
304
|
limit,
|
|
187
|
-
initialRows,
|
|
305
|
+
initialRows: initialRowsProp,
|
|
306
|
+
loader,
|
|
188
307
|
columns,
|
|
189
308
|
displayFields,
|
|
190
309
|
renderCard,
|
|
310
|
+
look,
|
|
191
311
|
gridProps,
|
|
192
312
|
emptyState,
|
|
193
313
|
onRetry,
|
|
@@ -198,13 +318,27 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
198
318
|
showFilterSidebar = false,
|
|
199
319
|
// deprecated: switcher always renders; destructured so it stays out of stackProps
|
|
200
320
|
enableViewSwitcher: _enableViewSwitcher,
|
|
321
|
+
title,
|
|
322
|
+
subtitle,
|
|
323
|
+
actions,
|
|
324
|
+
headerAccessory,
|
|
325
|
+
titleField,
|
|
326
|
+
sorts,
|
|
327
|
+
searchFilter,
|
|
328
|
+
searchPlaceholder,
|
|
329
|
+
facets,
|
|
330
|
+
ranges,
|
|
331
|
+
favorites,
|
|
332
|
+
shuffle,
|
|
333
|
+
urlState = false,
|
|
201
334
|
baseURL,
|
|
202
335
|
auth,
|
|
203
336
|
syncOptions,
|
|
204
337
|
...stackProps
|
|
205
338
|
}: FrappeListViewProps<TDoc>) {
|
|
206
339
|
const config = useFrappeConfig();
|
|
207
|
-
const
|
|
340
|
+
const router = useFrappeRouter();
|
|
341
|
+
const navigate = router?.navigate;
|
|
208
342
|
const { knobProps } = useResolvedKnobs();
|
|
209
343
|
const { t } = useTranslation();
|
|
210
344
|
const theme = useTheme();
|
|
@@ -229,9 +363,6 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
229
363
|
};
|
|
230
364
|
|
|
231
365
|
const [storedViewMode, setViewModeState] = useState<ListViewMode>(defaultViewMode);
|
|
232
|
-
const requestedViewMode = controlledViewMode ?? storedViewMode;
|
|
233
|
-
const viewMode: ListViewMode =
|
|
234
|
-
requestedViewMode === "grid" && !renderCard ? "list" : requestedViewMode;
|
|
235
366
|
|
|
236
367
|
useEffect(() => {
|
|
237
368
|
let cancelled = false;
|
|
@@ -247,16 +378,6 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
247
378
|
};
|
|
248
379
|
}, [doctype, defaultViewMode]);
|
|
249
380
|
|
|
250
|
-
const setViewMode = useCallback(
|
|
251
|
-
(mode: ListViewMode) => {
|
|
252
|
-
onViewModeChange?.(mode);
|
|
253
|
-
if (controlledViewMode !== undefined) return;
|
|
254
|
-
setViewModeState(mode);
|
|
255
|
-
void setStoredViewMode(doctype, mode);
|
|
256
|
-
},
|
|
257
|
-
[doctype, controlledViewMode, onViewModeChange],
|
|
258
|
-
);
|
|
259
|
-
|
|
260
381
|
const {
|
|
261
382
|
meta,
|
|
262
383
|
isLoading: isMetaLoading,
|
|
@@ -277,15 +398,6 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
277
398
|
(route !== undefined && navigate
|
|
278
399
|
? () => navigate(frappeRouteHref(route, { mode: "create" }))
|
|
279
400
|
: undefined));
|
|
280
|
-
const asPage = (view: React.ReactElement) =>
|
|
281
|
-
route === undefined ? (
|
|
282
|
-
view
|
|
283
|
-
) : (
|
|
284
|
-
<ListPageLayout scroll={false} header={<PageHeader title={doctype} divider={false} />}>
|
|
285
|
-
{view}
|
|
286
|
-
</ListPageLayout>
|
|
287
|
-
);
|
|
288
|
-
|
|
289
401
|
// Guest fallback: DocType meta is permission-gated (Guests get 403) while
|
|
290
402
|
// the documents themselves are often guest-readable. Peek one doc with
|
|
291
403
|
// fields=["*"] and derive display fields from its keys so the views render
|
|
@@ -459,10 +571,108 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
459
571
|
() => connections ?? (isMetaLoading ? undefined : connectionsFromMeta(meta)),
|
|
460
572
|
[connections, isMetaLoading, meta],
|
|
461
573
|
);
|
|
574
|
+
|
|
575
|
+
const searchField = useMemo(() => {
|
|
576
|
+
if (meta?.title_field) return meta.title_field;
|
|
577
|
+
if (metaListFields.length > 0) return metaListFields[0].fieldname;
|
|
578
|
+
if (peekedFields && peekedFields.length > 0) return peekedFields[0];
|
|
579
|
+
return "name";
|
|
580
|
+
}, [meta, metaListFields, peekedFields]);
|
|
581
|
+
|
|
582
|
+
// The list's controls (sorts, facets, ranges, favorites, shuffle) own a
|
|
583
|
+
// state the filters and order derive from; a list without them keeps the
|
|
584
|
+
// plain search band below and its own view memory.
|
|
585
|
+
const hasCards = Boolean(renderCard || look?.images);
|
|
586
|
+
const listControls: FrappeListControls = {
|
|
587
|
+
sorts,
|
|
588
|
+
facets,
|
|
589
|
+
ranges,
|
|
590
|
+
views: hasCards ? ["grid", "list", "table"] : ["list", "table"],
|
|
591
|
+
defaultView: defaultViewMode,
|
|
592
|
+
};
|
|
593
|
+
const hasControls = Boolean(
|
|
594
|
+
sorts?.length || facets?.length || ranges?.length || favorites || shuffle,
|
|
595
|
+
);
|
|
596
|
+
const favoritesStorageKey = favorites
|
|
597
|
+
? typeof favorites === "string"
|
|
598
|
+
? favorites
|
|
599
|
+
: favoritesKey(doctype)
|
|
600
|
+
: undefined;
|
|
601
|
+
const list = useListControls({
|
|
602
|
+
doctype,
|
|
603
|
+
controls: listControls,
|
|
604
|
+
connections: effectiveConnections,
|
|
605
|
+
connection: connectionConfig,
|
|
606
|
+
limit,
|
|
607
|
+
favoritesKey: favoritesStorageKey,
|
|
608
|
+
router: urlState ? router : undefined,
|
|
609
|
+
readBase: Boolean(subtitle || facets?.length || ranges?.length),
|
|
610
|
+
});
|
|
611
|
+
const updateList = list.update;
|
|
612
|
+
|
|
613
|
+
const requestedViewMode =
|
|
614
|
+
controlledViewMode ?? (urlState ? list.state.view : undefined) ?? storedViewMode;
|
|
615
|
+
const viewMode: ListViewMode =
|
|
616
|
+
requestedViewMode === "grid" && !hasCards ? "list" : requestedViewMode;
|
|
617
|
+
|
|
618
|
+
const setViewMode = useCallback(
|
|
619
|
+
(mode: ListViewMode) => {
|
|
620
|
+
onViewModeChange?.(mode);
|
|
621
|
+
if (controlledViewMode !== undefined) return;
|
|
622
|
+
if (urlState) {
|
|
623
|
+
updateList({ view: mode });
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
setViewModeState(mode);
|
|
627
|
+
void setStoredViewMode(doctype, mode);
|
|
628
|
+
},
|
|
629
|
+
[doctype, controlledViewMode, onViewModeChange, urlState, updateList],
|
|
630
|
+
);
|
|
631
|
+
|
|
632
|
+
const controlsKey = JSON.stringify({
|
|
633
|
+
facets: facets?.map((facet) => [facet.param, facet.field, facet.doctype]),
|
|
634
|
+
ranges: ranges?.map((range) => [range.param, range.field]),
|
|
635
|
+
sorts: sorts?.map((sort) => [sort.value, sort.orderBy]),
|
|
636
|
+
});
|
|
637
|
+
const controlFilters = useMemo(() => {
|
|
638
|
+
if (!hasControls) return activeFilters;
|
|
639
|
+
const base = !activeFilters
|
|
640
|
+
? []
|
|
641
|
+
: Array.isArray(activeFilters)
|
|
642
|
+
? activeFilters
|
|
643
|
+
: Object.entries(activeFilters).map(([field, value]) => [field, "=", value]);
|
|
644
|
+
return listStateFilters(list.state, listControls, {
|
|
645
|
+
base: base as FrappeListFilter[],
|
|
646
|
+
search: searchFilter ?? ((query) => [[searchField, "like", `%${query}%`]]),
|
|
647
|
+
favorites: list.favorites.favoriteSet,
|
|
648
|
+
});
|
|
649
|
+
// controlsKey stands for the facet and range definitions listControls carries.
|
|
650
|
+
}, [
|
|
651
|
+
hasControls,
|
|
652
|
+
activeFilters,
|
|
653
|
+
list.state,
|
|
654
|
+
list.favorites.favoriteSet,
|
|
655
|
+
searchFilter,
|
|
656
|
+
searchField,
|
|
657
|
+
controlsKey,
|
|
658
|
+
]);
|
|
659
|
+
const effectiveOrderBy = hasControls
|
|
660
|
+
? (listStateOrderBy(list.state, listControls, orderBy) as typeof orderBy)
|
|
661
|
+
: orderBy;
|
|
662
|
+
// The server page is the unfiltered list in its default order; any other
|
|
663
|
+
// query waits for its own read rather than flash rows it would drop.
|
|
664
|
+
const loaded = useRouteLoaderData(loader) as { rows?: readonly Partial<TDoc>[] } | undefined;
|
|
665
|
+
const initialRows = initialRowsProp ?? loaded?.rows;
|
|
666
|
+
const seedRows =
|
|
667
|
+
!hasControls ||
|
|
668
|
+
(!isListNarrowed(list.state) && (!sorts?.length || list.state.sort === sorts[0].value))
|
|
669
|
+
? initialRows
|
|
670
|
+
: undefined;
|
|
671
|
+
|
|
462
672
|
const linkFilters = useConnectionFilters(
|
|
463
673
|
connectionConfig,
|
|
464
674
|
doctype,
|
|
465
|
-
|
|
675
|
+
controlFilters as Parameters<typeof useConnectionFilters>[2],
|
|
466
676
|
effectiveConnections,
|
|
467
677
|
);
|
|
468
678
|
const resolvedFilters = linkFilters.filters as typeof activeFilters;
|
|
@@ -474,13 +684,6 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
474
684
|
const [searchText, setSearchText] = useState("");
|
|
475
685
|
const [debouncedSearch, setDebouncedSearch] = useState("");
|
|
476
686
|
|
|
477
|
-
const searchField = useMemo(() => {
|
|
478
|
-
if (meta?.title_field) return meta.title_field;
|
|
479
|
-
if (metaListFields.length > 0) return metaListFields[0].fieldname;
|
|
480
|
-
if (peekedFields && peekedFields.length > 0) return peekedFields[0];
|
|
481
|
-
return "name";
|
|
482
|
-
}, [meta, metaListFields, peekedFields]);
|
|
483
|
-
|
|
484
687
|
const listFilters = useMemo(() => {
|
|
485
688
|
const query = debouncedSearch.trim();
|
|
486
689
|
if (!query) return resolvedFilters;
|
|
@@ -538,6 +741,343 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
538
741
|
[savedFiltersHook],
|
|
539
742
|
);
|
|
540
743
|
|
|
744
|
+
const slug = doctype.toLowerCase().replace(/\s+/g, "-");
|
|
745
|
+
const searchId = `${slug}-list-search`;
|
|
746
|
+
const resultsId = `${slug}-results`;
|
|
747
|
+
const nameField = titleField ?? meta?.title_field;
|
|
748
|
+
|
|
749
|
+
const [shuffleOpen, setShuffleOpen] = useState(false);
|
|
750
|
+
const [shuffleRows, setShuffleRows] = useState<Partial<TDoc>[]>([]);
|
|
751
|
+
const handleShuffleRows = useCallback(
|
|
752
|
+
(snapshot: FrappeRowsSnapshot<TDoc>) => setShuffleRows(snapshot.rows),
|
|
753
|
+
[],
|
|
754
|
+
);
|
|
755
|
+
const shuffleOrderKey = JSON.stringify(sorts?.[0]?.orderBy ?? orderBy ?? null);
|
|
756
|
+
const shuffleFiltersKey = JSON.stringify(resolvedFilters ?? null);
|
|
757
|
+
const shuffleFieldsKey = JSON.stringify(effectiveFields);
|
|
758
|
+
const shuffleOptions = useMemo(
|
|
759
|
+
() => ({
|
|
760
|
+
fields: JSON.parse(shuffleFieldsKey),
|
|
761
|
+
filters: JSON.parse(shuffleFiltersKey) ?? undefined,
|
|
762
|
+
orderBy: JSON.parse(shuffleOrderKey) ?? undefined,
|
|
763
|
+
limit: limit ?? 0,
|
|
764
|
+
}),
|
|
765
|
+
[shuffleFieldsKey, shuffleFiltersKey, shuffleOrderKey, limit],
|
|
766
|
+
);
|
|
767
|
+
|
|
768
|
+
const { isFavorite, toggle: toggleStar } = list.favorites;
|
|
769
|
+
const toggleFavorite = useCallback(
|
|
770
|
+
(doc: Partial<TDoc>) => {
|
|
771
|
+
const name = doc.name;
|
|
772
|
+
if (!name) return;
|
|
773
|
+
const starred = isFavorite(name);
|
|
774
|
+
toggleStar(name);
|
|
775
|
+
const titleValue = nameField ? (doc as Record<string, unknown>)[nameField] : undefined;
|
|
776
|
+
const label = typeof titleValue === "string" && titleValue ? titleValue : name;
|
|
777
|
+
showToast(
|
|
778
|
+
starred
|
|
779
|
+
? {
|
|
780
|
+
id: `${slug}-favorite-${name}`,
|
|
781
|
+
title: t("{{name}} removed from favorites", { name: label }),
|
|
782
|
+
intent: "accent",
|
|
783
|
+
action: { label: t("Undo"), onPress: () => toggleStar(name) },
|
|
784
|
+
}
|
|
785
|
+
: {
|
|
786
|
+
id: `${slug}-favorite-${name}`,
|
|
787
|
+
title: t("{{name}} added to favorites", { name: label }),
|
|
788
|
+
intent: "success",
|
|
789
|
+
},
|
|
790
|
+
);
|
|
791
|
+
},
|
|
792
|
+
[isFavorite, toggleStar, nameField, slug, t],
|
|
793
|
+
);
|
|
794
|
+
|
|
795
|
+
const cardFor = (doc: Partial<TDoc>): FrappeListCard => {
|
|
796
|
+
const name = doc.name ?? "";
|
|
797
|
+
const row = doc as Record<string, unknown>;
|
|
798
|
+
return {
|
|
799
|
+
href:
|
|
800
|
+
route !== undefined && name ? frappeRouteHref(route, { mode: "view", name }) : undefined,
|
|
801
|
+
open: () => onItemClick?.(doc),
|
|
802
|
+
facets: Object.fromEntries(
|
|
803
|
+
(facets ?? []).map((facet) => [
|
|
804
|
+
facet.param,
|
|
805
|
+
facet.doctype
|
|
806
|
+
? (list.facets[facet.param]?.values.get(name) ?? [])
|
|
807
|
+
: row[facet.field] === undefined || row[facet.field] === null
|
|
808
|
+
? []
|
|
809
|
+
: [String(row[facet.field])],
|
|
810
|
+
]),
|
|
811
|
+
),
|
|
812
|
+
favorite:
|
|
813
|
+
favoritesStorageKey && name
|
|
814
|
+
? { active: isFavorite(name), toggle: () => toggleFavorite(doc) }
|
|
815
|
+
: undefined,
|
|
816
|
+
};
|
|
817
|
+
};
|
|
818
|
+
const tintFacet = facets?.find((facet) => facet.tint);
|
|
819
|
+
const drawRecordCard = (doc: Partial<TDoc>, index: number) => {
|
|
820
|
+
const card = cardFor(doc);
|
|
821
|
+
const name = doc.name ?? "";
|
|
822
|
+
const values = tintFacet ? (card.facets[tintFacet.param] ?? []) : [];
|
|
823
|
+
const title = recordTitle(doc, look, nameField);
|
|
824
|
+
return (
|
|
825
|
+
<RecordCard
|
|
826
|
+
title={title}
|
|
827
|
+
subtitle={look?.subtitle?.(doc)}
|
|
828
|
+
code={look?.code?.(doc)}
|
|
829
|
+
images={look?.images?.(doc, finalBaseURL) ?? []}
|
|
830
|
+
tints={values.slice(0, 2).map((value) => tintFacet?.tint?.(value))}
|
|
831
|
+
badges={values.map((value) => ({
|
|
832
|
+
value,
|
|
833
|
+
label: tintFacet?.optionLabel?.(value) ?? value,
|
|
834
|
+
tint: tintFacet?.tint?.(value),
|
|
835
|
+
}))}
|
|
836
|
+
href={card.href}
|
|
837
|
+
onPress={card.open}
|
|
838
|
+
favorite={card.favorite}
|
|
839
|
+
lazy={index >= eagerCards}
|
|
840
|
+
testID={`${slug}-card-${name}`}
|
|
841
|
+
favoriteTestID={`${slug}-favorite-${name}`}
|
|
842
|
+
/>
|
|
843
|
+
);
|
|
844
|
+
};
|
|
845
|
+
const drawCard = renderCard
|
|
846
|
+
? (doc: Partial<TDoc>, index: number) => renderCard(doc, index, cardFor(doc))
|
|
847
|
+
: look?.images
|
|
848
|
+
? drawRecordCard
|
|
849
|
+
: undefined;
|
|
850
|
+
|
|
851
|
+
// "/" jumps to the search box on web, the common list-page affordance.
|
|
852
|
+
// Document scope adds no tab stop (LC-49); it stands down while the reader
|
|
853
|
+
// types in any editable control or works inside an open overlay.
|
|
854
|
+
useEffect(() => {
|
|
855
|
+
if (!isWeb || typeof document === "undefined" || !showSearch) return;
|
|
856
|
+
const handleKeyDown = (event: KeyboardEvent) => {
|
|
857
|
+
if (event.key !== "/" || event.metaKey || event.ctrlKey || event.altKey) return;
|
|
858
|
+
if (event.defaultPrevented) return;
|
|
859
|
+
const target = event.target as HTMLElement | null;
|
|
860
|
+
if (target) {
|
|
861
|
+
const tag = target.tagName;
|
|
862
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return;
|
|
863
|
+
if (target.isContentEditable) return;
|
|
864
|
+
if (target.closest?.('[role="dialog"], [role="menu"], [role="listbox"]')) return;
|
|
865
|
+
}
|
|
866
|
+
const input = document.getElementById(searchId)?.querySelector("input");
|
|
867
|
+
if (!input) return;
|
|
868
|
+
event.preventDefault();
|
|
869
|
+
input.focus();
|
|
870
|
+
input.select?.();
|
|
871
|
+
};
|
|
872
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
873
|
+
return () => document.removeEventListener("keydown", handleKeyDown);
|
|
874
|
+
}, [searchId, showSearch]);
|
|
875
|
+
|
|
876
|
+
const headerOwnsTools = route !== undefined && !showToolbar;
|
|
877
|
+
const pressFor = (action: FrappeListAction) =>
|
|
878
|
+
action.onPress ?? (action.href && navigate ? () => navigate(action.href as string) : undefined);
|
|
879
|
+
const headerActions =
|
|
880
|
+
headerOwnsTools || headerAccessory || actions?.length ? (
|
|
881
|
+
<XStack {...knobProps.gap} alignItems="center" flexWrap="wrap" flexShrink={1} minWidth={0}>
|
|
882
|
+
{headerOwnsTools ? (
|
|
883
|
+
<Tooltip content={t("Switch views")}>
|
|
884
|
+
<XStack>
|
|
885
|
+
<ViewSwitcher
|
|
886
|
+
views={[
|
|
887
|
+
...(hasCards ? [{ type: "grid", label: t("Cards"), icon: ImageIcon }] : []),
|
|
888
|
+
{ type: "list", label: t("List"), icon: ListIcon },
|
|
889
|
+
{ type: "table", label: t("Table"), icon: TableIcon },
|
|
890
|
+
]}
|
|
891
|
+
currentView={viewMode}
|
|
892
|
+
onViewChange={(v) => setViewMode(v as ListViewMode)}
|
|
893
|
+
/>
|
|
894
|
+
</XStack>
|
|
895
|
+
</Tooltip>
|
|
896
|
+
) : null}
|
|
897
|
+
{headerAccessory}
|
|
898
|
+
{actions?.map((action) => {
|
|
899
|
+
const Icon = action.icon;
|
|
900
|
+
const onPress = pressFor(action);
|
|
901
|
+
return (
|
|
902
|
+
<React.Fragment key={action.label}>
|
|
903
|
+
<Tooltip content={action.hint ?? action.label}>
|
|
904
|
+
<Button
|
|
905
|
+
outlined
|
|
906
|
+
onPress={onPress}
|
|
907
|
+
icon={Icon ? <Icon size={16} /> : undefined}
|
|
908
|
+
$max-sm={{ display: "none" }}
|
|
909
|
+
testID={action.testID}
|
|
910
|
+
>
|
|
911
|
+
{action.label}
|
|
912
|
+
</Button>
|
|
913
|
+
</Tooltip>
|
|
914
|
+
<Button
|
|
915
|
+
outlined
|
|
916
|
+
circular
|
|
917
|
+
onPress={onPress}
|
|
918
|
+
icon={Icon ? <Icon size={16} /> : undefined}
|
|
919
|
+
display="none"
|
|
920
|
+
aria-label={action.label}
|
|
921
|
+
$max-sm={{ display: "flex" }}
|
|
922
|
+
/>
|
|
923
|
+
</React.Fragment>
|
|
924
|
+
);
|
|
925
|
+
})}
|
|
926
|
+
{headerOwnsTools && onAdd ? (
|
|
927
|
+
<>
|
|
928
|
+
<Button
|
|
929
|
+
theme="accent"
|
|
930
|
+
onPress={onAdd}
|
|
931
|
+
icon={<PlusIcon size={16} />}
|
|
932
|
+
$max-sm={{ display: "none" }}
|
|
933
|
+
>
|
|
934
|
+
{t("Add {{doctype}}", { doctype })}
|
|
935
|
+
</Button>
|
|
936
|
+
<Button
|
|
937
|
+
theme="accent"
|
|
938
|
+
onPress={onAdd}
|
|
939
|
+
icon={<PlusIcon size={16} />}
|
|
940
|
+
display="none"
|
|
941
|
+
$max-sm={{ display: "flex" }}
|
|
942
|
+
>
|
|
943
|
+
{t("Add")}
|
|
944
|
+
</Button>
|
|
945
|
+
</>
|
|
946
|
+
) : null}
|
|
947
|
+
</XStack>
|
|
948
|
+
) : undefined;
|
|
949
|
+
|
|
950
|
+
const controlsBand = hasControls ? (
|
|
951
|
+
<ListControls
|
|
952
|
+
controls={listControls}
|
|
953
|
+
list={list}
|
|
954
|
+
searchId={searchId}
|
|
955
|
+
searchPlaceholder={searchPlaceholder}
|
|
956
|
+
showSearch={showSearch}
|
|
957
|
+
showFavorites={Boolean(favoritesStorageKey)}
|
|
958
|
+
shuffle={
|
|
959
|
+
shuffle
|
|
960
|
+
? {
|
|
961
|
+
open: shuffleOpen,
|
|
962
|
+
toggle: () => setShuffleOpen((open) => !open),
|
|
963
|
+
panelId: `${slug}-shuffle-panel`,
|
|
964
|
+
}
|
|
965
|
+
: undefined
|
|
966
|
+
}
|
|
967
|
+
shufflePanel={
|
|
968
|
+
shuffle && shuffleOpen && shuffleRows.length > 0 && drawCard ? (
|
|
969
|
+
<ShufflePanel<Partial<TDoc>>
|
|
970
|
+
id={`${slug}-shuffle-panel`}
|
|
971
|
+
label={t("Surprise me")}
|
|
972
|
+
rows={shuffleRows}
|
|
973
|
+
itemLabel={shuffle.label}
|
|
974
|
+
renderPick={(doc) => drawCard(doc, 0)}
|
|
975
|
+
onGo={(doc) => {
|
|
976
|
+
setShuffleOpen(false);
|
|
977
|
+
onItemClick?.(doc);
|
|
978
|
+
}}
|
|
979
|
+
testID={`${slug}-shuffle-panel`}
|
|
980
|
+
/>
|
|
981
|
+
) : null
|
|
982
|
+
}
|
|
983
|
+
separator={!surface}
|
|
984
|
+
testID={slug}
|
|
985
|
+
/>
|
|
986
|
+
) : null;
|
|
987
|
+
|
|
988
|
+
const asPage = (view: React.ReactElement) => {
|
|
989
|
+
const extras = (
|
|
990
|
+
<>
|
|
991
|
+
{list.readers}
|
|
992
|
+
{shuffle && shuffleOpen && !linkFilters.pending ? (
|
|
993
|
+
<FrappeRowsReader<TDoc>
|
|
994
|
+
connection={connectionConfig}
|
|
995
|
+
doctype={doctype}
|
|
996
|
+
options={shuffleOptions as never}
|
|
997
|
+
onChange={handleShuffleRows}
|
|
998
|
+
/>
|
|
999
|
+
) : null}
|
|
1000
|
+
{favoritesStorageKey ? <ListToastHost /> : null}
|
|
1001
|
+
</>
|
|
1002
|
+
);
|
|
1003
|
+
if (route === undefined) {
|
|
1004
|
+
return controlsBand ? (
|
|
1005
|
+
<YStack {...knobProps.gap} flex={viewMode === "grid" ? undefined : 1}>
|
|
1006
|
+
{controlsBand}
|
|
1007
|
+
{view}
|
|
1008
|
+
{extras}
|
|
1009
|
+
</YStack>
|
|
1010
|
+
) : (
|
|
1011
|
+
<>
|
|
1012
|
+
{view}
|
|
1013
|
+
{extras}
|
|
1014
|
+
</>
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
return (
|
|
1018
|
+
<ListPageLayout
|
|
1019
|
+
scroll={!surface}
|
|
1020
|
+
header={
|
|
1021
|
+
<>
|
|
1022
|
+
{controlsBand ? <SkipLink targetId={resultsId}>{t("Skip to results")}</SkipLink> : null}
|
|
1023
|
+
<PageHeader
|
|
1024
|
+
title={title ?? doctype}
|
|
1025
|
+
subtitle={subtitle && list.total !== undefined ? subtitle(list.total) : undefined}
|
|
1026
|
+
actions={headerActions}
|
|
1027
|
+
divider={!surface}
|
|
1028
|
+
/>
|
|
1029
|
+
</>
|
|
1030
|
+
}
|
|
1031
|
+
toolbar={controlsBand ?? undefined}
|
|
1032
|
+
>
|
|
1033
|
+
{view}
|
|
1034
|
+
{extras}
|
|
1035
|
+
</ListPageLayout>
|
|
1036
|
+
);
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
const controlsEmptyState = hasControls ? (
|
|
1040
|
+
<EmptyState
|
|
1041
|
+
aria-live="polite"
|
|
1042
|
+
icon={
|
|
1043
|
+
list.state.favoritesOnly ? (
|
|
1044
|
+
<HeartIcon size={28} />
|
|
1045
|
+
) : isListNarrowed(list.state) ? (
|
|
1046
|
+
<MagnifyingGlassIcon size={28} />
|
|
1047
|
+
) : (
|
|
1048
|
+
<SparkleIcon size={28} />
|
|
1049
|
+
)
|
|
1050
|
+
}
|
|
1051
|
+
title={
|
|
1052
|
+
list.state.favoritesOnly
|
|
1053
|
+
? t("No favorites yet")
|
|
1054
|
+
: list.state.search.trim()
|
|
1055
|
+
? t('No match for "{{query}}"', { query: list.state.search.trim() })
|
|
1056
|
+
: isListNarrowed(list.state)
|
|
1057
|
+
? t("No {{doctype}} match the active filters", { doctype })
|
|
1058
|
+
: t("No {{doctype}} yet", { doctype })
|
|
1059
|
+
}
|
|
1060
|
+
description={
|
|
1061
|
+
list.state.favoritesOnly
|
|
1062
|
+
? t("Tap the heart on a record to favorite it.")
|
|
1063
|
+
: isListNarrowed(list.state)
|
|
1064
|
+
? t("Try a different search or filter.")
|
|
1065
|
+
: undefined
|
|
1066
|
+
}
|
|
1067
|
+
action={
|
|
1068
|
+
isListNarrowed(list.state) ? (
|
|
1069
|
+
<Button outlined onPress={list.clear}>
|
|
1070
|
+
{t("Clear filters")}
|
|
1071
|
+
</Button>
|
|
1072
|
+
) : onAdd ? (
|
|
1073
|
+
<Button theme="accent" onPress={onAdd}>
|
|
1074
|
+
{t("Add your first {{doctype}}", { doctype })}
|
|
1075
|
+
</Button>
|
|
1076
|
+
) : undefined
|
|
1077
|
+
}
|
|
1078
|
+
/>
|
|
1079
|
+
) : undefined;
|
|
1080
|
+
|
|
541
1081
|
// Named fields need no schema to read or draw: the view renders now (on
|
|
542
1082
|
// the server too) and labels settle when meta lands.
|
|
543
1083
|
if (isMetaLoading && !fields) {
|
|
@@ -546,10 +1086,11 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
546
1086
|
{...knobProps.panelPadding}
|
|
547
1087
|
alignItems="center"
|
|
548
1088
|
justifyContent="center"
|
|
1089
|
+
gap="$2"
|
|
549
1090
|
{...stackProps}
|
|
550
1091
|
>
|
|
551
1092
|
<Spinner size="large" />
|
|
552
|
-
<Text {...knobProps.body} color={knobProps.textAccentColor}
|
|
1093
|
+
<Text {...knobProps.body} color={knobProps.textAccentColor}>
|
|
553
1094
|
{t("Loading {{doctype}} schema...", { doctype })}
|
|
554
1095
|
</Text>
|
|
555
1096
|
</YStack>,
|
|
@@ -573,7 +1114,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
573
1114
|
<XStack alignItems="center" {...knobProps.gap}>
|
|
574
1115
|
<ViewSwitcher
|
|
575
1116
|
views={[
|
|
576
|
-
...(
|
|
1117
|
+
...(hasCards ? [{ type: "grid", label: t("Cards") }] : []),
|
|
577
1118
|
{ type: "list", label: t("List") },
|
|
578
1119
|
{ type: "table", label: t("Table") },
|
|
579
1120
|
]}
|
|
@@ -678,7 +1219,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
678
1219
|
borderBottomWidth={1}
|
|
679
1220
|
borderBottomColor="$borderColor"
|
|
680
1221
|
>
|
|
681
|
-
<View flex={1}>
|
|
1222
|
+
<View flex={1} id={searchId}>
|
|
682
1223
|
<SearchInput
|
|
683
1224
|
value={searchText}
|
|
684
1225
|
onChange={setSearchText}
|
|
@@ -698,19 +1239,19 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
698
1239
|
const isGrid = viewMode === "grid";
|
|
699
1240
|
return (
|
|
700
1241
|
<YStack flex={isGrid ? undefined : 1}>
|
|
701
|
-
{showSearch ? renderListSearch() : null}
|
|
1242
|
+
{showSearch && !hasControls ? renderListSearch() : null}
|
|
702
1243
|
<FrappeList
|
|
703
1244
|
key={`${viewMode}-${refreshKey}`}
|
|
704
1245
|
layout={isGrid ? "grid" : "list"}
|
|
705
1246
|
gridProps={gridProps}
|
|
706
|
-
emptyState={emptyState}
|
|
1247
|
+
emptyState={emptyState ?? controlsEmptyState}
|
|
707
1248
|
pageSize={pageSize}
|
|
708
1249
|
onRetry={onRetry ?? handleRefresh}
|
|
709
1250
|
doctype={doctype}
|
|
710
1251
|
fields={effectiveFields as readonly ("name" | "doctype")[]}
|
|
711
1252
|
filters={listFilters as Partial<{ name: string; doctype: string }>}
|
|
712
1253
|
renderItem={
|
|
713
|
-
(isGrid &&
|
|
1254
|
+
(isGrid && drawCard ? drawCard : renderListItem) as unknown as (
|
|
714
1255
|
item: Partial<{ name: string; doctype: string }>,
|
|
715
1256
|
index: number,
|
|
716
1257
|
) => React.ReactNode
|
|
@@ -723,10 +1264,12 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
723
1264
|
baseURL={finalBaseURL}
|
|
724
1265
|
auth={finalAuth}
|
|
725
1266
|
syncOptions={finalSyncOptions}
|
|
726
|
-
orderBy={
|
|
1267
|
+
orderBy={
|
|
1268
|
+
effectiveOrderBy as FrappeListProps<{ name: string; doctype: string }>["orderBy"]
|
|
1269
|
+
}
|
|
727
1270
|
limit={limit}
|
|
728
1271
|
initialRows={
|
|
729
|
-
|
|
1272
|
+
seedRows as FrappeListProps<{ name: string; doctype: string }>["initialRows"]
|
|
730
1273
|
}
|
|
731
1274
|
// Only override when narrowing is active: FrappeList's own
|
|
732
1275
|
// "No {doctype} records found" stays the true-empty message.
|
|
@@ -779,6 +1322,7 @@ export function FrappeListView<TDoc extends { name: string; doctype: string }>({
|
|
|
779
1322
|
{...(surface ? knobProps.containerRadius : {})}
|
|
780
1323
|
overflow={surface ? "hidden" : undefined}
|
|
781
1324
|
testID={`${doctype.toLowerCase()}-list`}
|
|
1325
|
+
{...(hasControls ? { id: resultsId } : {})}
|
|
782
1326
|
{...stackProps}
|
|
783
1327
|
>
|
|
784
1328
|
{renderToolbar()}
|