@multiplatform.one/frappe-ui 7.11.0 → 7.15.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/README.md +2 -2
- package/dist/cjs/FrappeDashboard.cjs +8 -10
- package/dist/cjs/FrappeDashboard.native.js +8 -14
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +465 -175
- package/dist/cjs/FrappeForm.native.js +611 -207
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeFormConnections.cjs +125 -0
- package/dist/cjs/FrappeFormConnections.native.js +149 -0
- package/dist/cjs/FrappeFormConnections.native.js.map +1 -0
- package/dist/cjs/FrappeImageView.cjs +7 -9
- package/dist/cjs/FrappeImageView.native.js +7 -13
- package/dist/cjs/FrappeImageView.native.js.map +1 -1
- package/dist/cjs/FrappeList.cjs +29 -4
- package/dist/cjs/FrappeList.native.js +37 -5
- package/dist/cjs/FrappeList.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +102 -29
- package/dist/cjs/FrappeListView.native.js +109 -29
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeProvider.cjs +7 -2
- package/dist/cjs/FrappeProvider.native.js +7 -2
- package/dist/cjs/FrappeProvider.native.js.map +1 -1
- package/dist/cjs/FrappeReportBuilder.cjs +10 -11
- package/dist/cjs/FrappeReportBuilder.native.js +10 -16
- package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
- package/dist/cjs/FrappeRowsReader.cjs +49 -0
- package/dist/cjs/FrappeRowsReader.native.js +53 -0
- package/dist/cjs/FrappeRowsReader.native.js.map +1 -0
- package/dist/cjs/FrappeTable.cjs +18 -6
- package/dist/cjs/FrappeTable.native.js +24 -6
- package/dist/cjs/FrappeTable.native.js.map +1 -1
- package/dist/cjs/fieldRegistry.cjs +36 -11
- package/dist/cjs/fieldRegistry.native.js +59 -11
- package/dist/cjs/fieldRegistry.native.js.map +1 -1
- package/dist/cjs/fields/Date/index.native.js +5 -2
- package/dist/cjs/fields/Date/index.native.js.map +1 -1
- package/dist/cjs/fields/Date/sheetKeyboard.cjs +2 -2
- package/dist/cjs/fields/Date/sheetKeyboard.native.js +2 -2
- package/dist/cjs/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/cjs/fields/DateRange/index.cjs +2 -1
- package/dist/cjs/fields/DateRange/index.native.js +4 -1
- package/dist/cjs/fields/DateRange/index.native.js.map +1 -1
- package/dist/cjs/formEngine/index.cjs +4 -2
- package/dist/cjs/formEngine/index.native.js +3 -1
- package/dist/cjs/formEngine/index.native.js.map +1 -1
- package/dist/cjs/formEngine/useSessionRoles.cjs +77 -0
- package/dist/cjs/formEngine/useSessionRoles.native.js +84 -0
- package/dist/cjs/formEngine/useSessionRoles.native.js.map +1 -0
- package/dist/cjs/frappeConnections.cjs +41 -0
- package/dist/cjs/frappeConnections.native.js +50 -0
- package/dist/cjs/frappeConnections.native.js.map +1 -0
- package/dist/cjs/frappeNavigation.cjs +107 -0
- package/dist/cjs/frappeNavigation.native.js +112 -0
- package/dist/cjs/frappeNavigation.native.js.map +1 -0
- package/dist/cjs/index.cjs +18 -1
- package/dist/cjs/index.native.js +18 -1
- package/dist/cjs/index.native.js.map +1 -1
- package/dist/cjs/schemaForm/index.cjs +4 -1
- package/dist/cjs/schemaForm/index.native.js +4 -1
- package/dist/cjs/schemaForm/index.native.js.map +1 -1
- package/dist/cjs/useConnectionFilters.cjs +146 -0
- package/dist/cjs/useConnectionFilters.native.js +213 -0
- package/dist/cjs/useConnectionFilters.native.js.map +1 -0
- package/dist/cjs/useFrappePagination.cjs +37 -18
- package/dist/cjs/useFrappePagination.native.js +59 -23
- package/dist/cjs/useFrappePagination.native.js.map +1 -1
- package/dist/cjs/useFrappeRows.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.mjs +9 -11
- package/dist/esm/FrappeDashboard.mjs.map +1 -1
- package/dist/esm/FrappeDashboard.native.js +9 -15
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +471 -181
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +599 -195
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeFormConnections.mjs +99 -0
- package/dist/esm/FrappeFormConnections.mjs.map +1 -0
- package/dist/esm/FrappeFormConnections.native.js +120 -0
- package/dist/esm/FrappeFormConnections.native.js.map +1 -0
- package/dist/esm/FrappeImageView.mjs +8 -10
- package/dist/esm/FrappeImageView.mjs.map +1 -1
- package/dist/esm/FrappeImageView.native.js +8 -14
- package/dist/esm/FrappeImageView.native.js.map +1 -1
- package/dist/esm/FrappeList.mjs +31 -6
- package/dist/esm/FrappeList.mjs.map +1 -1
- package/dist/esm/FrappeList.native.js +39 -7
- package/dist/esm/FrappeList.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +103 -30
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +110 -30
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeProvider.mjs +7 -2
- package/dist/esm/FrappeProvider.mjs.map +1 -1
- package/dist/esm/FrappeProvider.native.js +7 -2
- package/dist/esm/FrappeProvider.native.js.map +1 -1
- package/dist/esm/FrappeReportBuilder.mjs +11 -12
- package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
- package/dist/esm/FrappeReportBuilder.native.js +11 -17
- package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
- package/dist/esm/FrappeRowsReader.mjs +24 -0
- package/dist/esm/FrappeRowsReader.mjs.map +1 -0
- package/dist/esm/FrappeRowsReader.native.js +25 -0
- package/dist/esm/FrappeRowsReader.native.js.map +1 -0
- package/dist/esm/FrappeTable.mjs +18 -6
- package/dist/esm/FrappeTable.mjs.map +1 -1
- package/dist/esm/FrappeTable.native.js +24 -6
- package/dist/esm/FrappeTable.native.js.map +1 -1
- package/dist/esm/fieldRegistry.mjs +35 -12
- package/dist/esm/fieldRegistry.mjs.map +1 -1
- package/dist/esm/fieldRegistry.native.js +58 -12
- package/dist/esm/fieldRegistry.native.js.map +1 -1
- package/dist/esm/fields/Date/index.native.js +6 -3
- package/dist/esm/fields/Date/index.native.js.map +1 -1
- package/dist/esm/fields/Date/sheetKeyboard.mjs +2 -2
- package/dist/esm/fields/Date/sheetKeyboard.mjs.map +1 -1
- package/dist/esm/fields/Date/sheetKeyboard.native.js +2 -2
- package/dist/esm/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/esm/fields/DateRange/index.mjs +2 -1
- package/dist/esm/fields/DateRange/index.mjs.map +1 -1
- package/dist/esm/fields/DateRange/index.native.js +4 -1
- package/dist/esm/fields/DateRange/index.native.js.map +1 -1
- package/dist/esm/formEngine/index.mjs +2 -1
- package/dist/esm/formEngine/index.mjs.map +1 -1
- package/dist/esm/formEngine/index.native.js +2 -1
- package/dist/esm/formEngine/index.native.js.map +1 -1
- package/dist/esm/formEngine/useSessionRoles.mjs +52 -0
- package/dist/esm/formEngine/useSessionRoles.mjs.map +1 -0
- package/dist/esm/formEngine/useSessionRoles.native.js +56 -0
- package/dist/esm/formEngine/useSessionRoles.native.js.map +1 -0
- package/dist/esm/frappeConnections.mjs +15 -0
- package/dist/esm/frappeConnections.mjs.map +1 -0
- package/dist/esm/frappeConnections.native.js +21 -0
- package/dist/esm/frappeConnections.native.js.map +1 -0
- package/dist/esm/frappeNavigation.mjs +78 -0
- package/dist/esm/frappeNavigation.mjs.map +1 -0
- package/dist/esm/frappeNavigation.native.js +80 -0
- package/dist/esm/frappeNavigation.native.js.map +1 -0
- package/dist/esm/index.mjs +7 -3
- package/dist/esm/index.mjs.map +1 -1
- package/dist/esm/index.native.js +7 -3
- package/dist/esm/index.native.js.map +1 -1
- package/dist/esm/schemaForm/index.mjs +4 -1
- package/dist/esm/schemaForm/index.mjs.map +1 -1
- package/dist/esm/schemaForm/index.native.js +4 -1
- package/dist/esm/schemaForm/index.native.js.map +1 -1
- package/dist/esm/useConnectionFilters.mjs +121 -0
- package/dist/esm/useConnectionFilters.mjs.map +1 -0
- package/dist/esm/useConnectionFilters.native.js +185 -0
- package/dist/esm/useConnectionFilters.native.js.map +1 -0
- package/dist/esm/useFrappePagination.mjs +38 -19
- package/dist/esm/useFrappePagination.mjs.map +1 -1
- package/dist/esm/useFrappePagination.native.js +60 -24
- package/dist/esm/useFrappePagination.native.js.map +1 -1
- package/dist/esm/useFrappeRows.mjs.map +1 -1
- package/dist/esm/useFrappeRows.native.js.map +1 -1
- package/dist/jsx/FrappeDashboard.mjs +9 -11
- package/dist/jsx/FrappeDashboard.mjs.map +1 -1
- package/dist/jsx/FrappeDashboard.native.js +8 -14
- package/dist/jsx/FrappeDashboard.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +471 -181
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +611 -207
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeFormConnections.mjs +99 -0
- package/dist/jsx/FrappeFormConnections.mjs.map +1 -0
- package/dist/jsx/FrappeFormConnections.native.js +149 -0
- package/dist/jsx/FrappeFormConnections.native.js.map +1 -0
- package/dist/jsx/FrappeImageView.mjs +8 -10
- package/dist/jsx/FrappeImageView.mjs.map +1 -1
- package/dist/jsx/FrappeImageView.native.js +7 -13
- package/dist/jsx/FrappeImageView.native.js.map +1 -1
- package/dist/jsx/FrappeList.mjs +31 -6
- package/dist/jsx/FrappeList.mjs.map +1 -1
- package/dist/jsx/FrappeList.native.js +37 -5
- package/dist/jsx/FrappeList.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +103 -30
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +109 -29
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeProvider.mjs +7 -2
- package/dist/jsx/FrappeProvider.mjs.map +1 -1
- package/dist/jsx/FrappeProvider.native.js +7 -2
- package/dist/jsx/FrappeProvider.native.js.map +1 -1
- package/dist/jsx/FrappeReportBuilder.mjs +11 -12
- package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
- package/dist/jsx/FrappeReportBuilder.native.js +10 -16
- package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
- package/dist/jsx/FrappeRowsReader.mjs +24 -0
- package/dist/jsx/FrappeRowsReader.mjs.map +1 -0
- package/dist/jsx/FrappeRowsReader.native.js +53 -0
- package/dist/jsx/FrappeRowsReader.native.js.map +1 -0
- package/dist/jsx/FrappeTable.mjs +18 -6
- package/dist/jsx/FrappeTable.mjs.map +1 -1
- package/dist/jsx/FrappeTable.native.js +24 -6
- package/dist/jsx/FrappeTable.native.js.map +1 -1
- package/dist/jsx/fieldRegistry.mjs +35 -12
- package/dist/jsx/fieldRegistry.mjs.map +1 -1
- package/dist/jsx/fieldRegistry.native.js +59 -11
- package/dist/jsx/fieldRegistry.native.js.map +1 -1
- package/dist/jsx/fields/Date/index.native.js +5 -2
- package/dist/jsx/fields/Date/index.native.js.map +1 -1
- package/dist/jsx/fields/Date/sheetKeyboard.mjs +2 -2
- package/dist/jsx/fields/Date/sheetKeyboard.mjs.map +1 -1
- package/dist/jsx/fields/Date/sheetKeyboard.native.js +2 -2
- package/dist/jsx/fields/Date/sheetKeyboard.native.js.map +1 -1
- package/dist/jsx/fields/DateRange/index.mjs +2 -1
- package/dist/jsx/fields/DateRange/index.mjs.map +1 -1
- package/dist/jsx/fields/DateRange/index.native.js +4 -1
- package/dist/jsx/fields/DateRange/index.native.js.map +1 -1
- package/dist/jsx/formEngine/index.mjs +2 -1
- package/dist/jsx/formEngine/index.mjs.map +1 -1
- package/dist/jsx/formEngine/index.native.js +3 -1
- package/dist/jsx/formEngine/index.native.js.map +1 -1
- package/dist/jsx/formEngine/useSessionRoles.mjs +52 -0
- package/dist/jsx/formEngine/useSessionRoles.mjs.map +1 -0
- package/dist/jsx/formEngine/useSessionRoles.native.js +84 -0
- package/dist/jsx/formEngine/useSessionRoles.native.js.map +1 -0
- package/dist/jsx/frappeConnections.mjs +15 -0
- package/dist/jsx/frappeConnections.mjs.map +1 -0
- package/dist/jsx/frappeConnections.native.js +50 -0
- package/dist/jsx/frappeConnections.native.js.map +1 -0
- package/dist/jsx/frappeNavigation.mjs +78 -0
- package/dist/jsx/frappeNavigation.mjs.map +1 -0
- package/dist/jsx/frappeNavigation.native.js +112 -0
- package/dist/jsx/frappeNavigation.native.js.map +1 -0
- package/dist/jsx/index.js +7 -3
- package/dist/jsx/index.js.map +1 -1
- package/dist/jsx/index.mjs +7 -3
- package/dist/jsx/index.mjs.map +1 -1
- package/dist/jsx/index.native.js +18 -1
- package/dist/jsx/index.native.js.map +1 -1
- package/dist/jsx/schemaForm/index.mjs +4 -1
- package/dist/jsx/schemaForm/index.mjs.map +1 -1
- package/dist/jsx/schemaForm/index.native.js +4 -1
- package/dist/jsx/schemaForm/index.native.js.map +1 -1
- package/dist/jsx/useConnectionFilters.mjs +121 -0
- package/dist/jsx/useConnectionFilters.mjs.map +1 -0
- package/dist/jsx/useConnectionFilters.native.js +213 -0
- package/dist/jsx/useConnectionFilters.native.js.map +1 -0
- package/dist/jsx/useFrappePagination.mjs +38 -19
- package/dist/jsx/useFrappePagination.mjs.map +1 -1
- package/dist/jsx/useFrappePagination.native.js +59 -23
- package/dist/jsx/useFrappePagination.native.js.map +1 -1
- package/dist/jsx/useFrappeRows.mjs.map +1 -1
- package/dist/jsx/useFrappeRows.native.js.map +1 -1
- package/package.json +24 -20
- package/src/FileBrowser/AttachLibrary.stories.tsx +23 -0
- package/src/FrappeDashboard.tsx +11 -16
- package/src/FrappeForm.connections.spec.tsx +280 -0
- package/src/FrappeForm.connections.stories.tsx +93 -0
- package/src/FrappeForm.deskSemantics.spec.tsx +284 -0
- package/src/FrappeForm.tsx +560 -145
- package/src/FrappeFormConnections.tsx +148 -0
- package/src/FrappeGuestMeta.spec.tsx +143 -0
- package/src/FrappeImageView.tsx +8 -12
- package/src/FrappeList.tsx +71 -15
- package/src/FrappeListView.cards.spec.tsx +175 -0
- package/src/FrappeListView.cards.stories.tsx +131 -0
- package/src/FrappeListView.connections.spec.tsx +192 -0
- package/src/FrappeListView.connections.stories.tsx +99 -0
- package/src/FrappeListView.seed.spec.tsx +228 -0
- package/src/FrappeListView.tsx +177 -31
- package/src/FrappeProvider.tsx +13 -1
- package/src/FrappeReportBuilder.tsx +11 -19
- package/src/FrappeRowsReader.tsx +38 -0
- package/src/FrappeTable.optionalProps.spec.tsx +249 -0
- package/src/FrappeTable.spec.tsx +32 -42
- package/src/FrappeTable.stories.spec.tsx +55 -0
- package/src/FrappeTable.stories.tsx +28 -37
- package/src/FrappeTable.tsx +108 -45
- package/src/childTableDependsOn.spec.tsx +85 -0
- package/src/desk/DeskFormSidebar.spec.tsx +20 -0
- package/src/desk/DeskFormSidebar.stories.tsx +42 -0
- package/src/fieldRegistry.spec.tsx +27 -64
- package/src/fieldRegistry.ts +71 -14
- package/src/fields/Date/index.native.tsx +4 -2
- package/src/fields/Date/sheetKeyboard.spec.ts +14 -5
- package/src/fields/Date/sheetKeyboard.ts +12 -4
- package/src/fields/DateRange/DateRange.spec.tsx +67 -0
- package/src/fields/DateRange/index.tsx +5 -1
- package/src/fields/LinkTree.spec.tsx +8 -0
- package/src/fields/LinkTree.stories.tsx +28 -5
- package/src/fields/Select/Select.hydration.spec.tsx +177 -0
- package/src/formEngine/doctypeMeta.ts +15 -114
- package/src/formEngine/index.ts +2 -0
- package/src/formEngine/seam.spec.ts +23 -4
- package/src/formEngine/useSessionRoles.ts +73 -0
- package/src/frappeConnections.ts +50 -0
- package/src/frappeNavigation.tsx +112 -0
- package/src/frappeRoutes.spec.tsx +335 -0
- package/src/index.ts +28 -1
- package/src/schemaForm/index.tsx +1 -0
- package/src/useConnectionFilters.tsx +157 -0
- package/src/useFrappePagination.ts +70 -26
- package/src/useFrappeRows.sharedPath.spec.tsx +206 -0
- package/src/useFrappeRows.ts +5 -4
- package/types/FrappeDashboard.d.ts +3 -4
- package/types/FrappeDashboard.d.ts.map +1 -1
- package/types/FrappeForm.d.ts +57 -5
- package/types/FrappeForm.d.ts.map +1 -1
- package/types/FrappeFormConnections.d.ts +18 -0
- package/types/FrappeFormConnections.d.ts.map +1 -0
- package/types/FrappeImageView.d.ts +2 -3
- package/types/FrappeImageView.d.ts.map +1 -1
- package/types/FrappeList.d.ts +20 -2
- package/types/FrappeList.d.ts.map +1 -1
- package/types/FrappeListView.d.ts +53 -3
- package/types/FrappeListView.d.ts.map +1 -1
- package/types/FrappeProvider.d.ts +8 -1
- package/types/FrappeProvider.d.ts.map +1 -1
- package/types/FrappeReportBuilder.d.ts.map +1 -1
- package/types/FrappeRowsReader.d.ts +26 -0
- package/types/FrappeRowsReader.d.ts.map +1 -0
- package/types/FrappeTable.d.ts +39 -8
- package/types/FrappeTable.d.ts.map +1 -1
- package/types/fieldRegistry.d.ts +17 -3
- package/types/fieldRegistry.d.ts.map +1 -1
- package/types/fields/Date/index.native.d.ts.map +1 -1
- package/types/fields/Date/sheetKeyboard.d.ts +4 -3
- package/types/fields/Date/sheetKeyboard.d.ts.map +1 -1
- package/types/fields/DateRange/index.d.ts.map +1 -1
- package/types/formEngine/doctypeMeta.d.ts +10 -114
- package/types/formEngine/doctypeMeta.d.ts.map +1 -1
- package/types/formEngine/index.d.ts +1 -0
- package/types/formEngine/index.d.ts.map +1 -1
- package/types/formEngine/useSessionRoles.d.ts +19 -0
- package/types/formEngine/useSessionRoles.d.ts.map +1 -0
- package/types/frappeConnections.d.ts +33 -0
- package/types/frappeConnections.d.ts.map +1 -0
- package/types/frappeNavigation.d.ts +49 -0
- package/types/frappeNavigation.d.ts.map +1 -0
- package/types/index.d.ts +7 -3
- package/types/index.d.ts.map +1 -1
- package/types/schemaForm/index.d.ts.map +1 -1
- package/types/useConnectionFilters.d.ts +34 -0
- package/types/useConnectionFilters.d.ts.map +1 -0
- package/types/useFrappePagination.d.ts +18 -5
- package/types/useFrappePagination.d.ts.map +1 -1
- package/types/useFrappeRows.d.ts +5 -4
- package/types/useFrappeRows.d.ts.map +1 -1
- package/src/FileBrowser/AttachLibrary.spec.tsx +0 -74
package/src/FrappeDashboard.tsx
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
useFrappeCollection,
|
|
3
|
-
useFrappeDoctypeEvents,
|
|
4
|
-
useLiveQuery,
|
|
5
|
-
} from "@multiplatform.one/frappe";
|
|
1
|
+
import { useFrappeDoctypeEvents } from "@multiplatform.one/frappe";
|
|
6
2
|
import { Dashboard, type DashboardWidget } from "@multiplatform.one/components";
|
|
7
3
|
import { Button, Spinner, formCommonColors } from "@multiplatform.one/forms";
|
|
8
4
|
import { ArrowsClockwiseIcon } from "@phosphor-icons/react";
|
|
@@ -11,6 +7,7 @@ import { useTranslation } from "react-i18next";
|
|
|
11
7
|
import { Text, XStack, YStack, type YStackProps, H3 } from "tamagui";
|
|
12
8
|
import { formatTimeOfDay, useResolvedKnobs } from "@multiplatform.one/theme";
|
|
13
9
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
10
|
+
import { useFrappeRows } from "./useFrappeRows";
|
|
14
11
|
|
|
15
12
|
/**
|
|
16
13
|
* Data source configuration for live data.
|
|
@@ -103,16 +100,15 @@ function LiveDashboardContent<TDoc extends { name: string; doctype: string }>({
|
|
|
103
100
|
const { knobProps } = useResolvedKnobs();
|
|
104
101
|
const { t } = useTranslation();
|
|
105
102
|
|
|
106
|
-
const
|
|
103
|
+
const {
|
|
104
|
+
rows: liveData,
|
|
105
|
+
isQueryLoading: isLiveLoading,
|
|
106
|
+
isError,
|
|
107
|
+
} = useFrappeRows<TDoc>(connectionConfig as any, dataSource.doctype, {
|
|
107
108
|
fields: dataSource.fields,
|
|
108
109
|
filters: dataSource.filters,
|
|
110
|
+
limit: null,
|
|
109
111
|
});
|
|
110
|
-
const {
|
|
111
|
-
data: rawData,
|
|
112
|
-
isLoading: isLiveLoading,
|
|
113
|
-
isError,
|
|
114
|
-
} = useLiveQuery((q) => (collection ? q.from({ _list: collection }) : null), [collection]);
|
|
115
|
-
const liveData = useMemo(() => (rawData as TDoc[] | undefined) ?? [], [rawData]);
|
|
116
112
|
|
|
117
113
|
// Live staleness: a realtime change on the source doctype marks the view
|
|
118
114
|
// stale until the collection reconciles (data identity changes) or a
|
|
@@ -240,10 +236,9 @@ function LiveDashboardContent<TDoc extends { name: string; doctype: string }>({
|
|
|
240
236
|
/**
|
|
241
237
|
* Thin Frappe wrapper around the generic Dashboard component.
|
|
242
238
|
*
|
|
243
|
-
* Fetches live data via `
|
|
244
|
-
*
|
|
245
|
-
*
|
|
246
|
-
* `@multiplatform.one/components`.
|
|
239
|
+
* Fetches live data via `useFrappeRows` if a `dataSource` is configured,
|
|
240
|
+
* transforms it into widget data, and passes everything to the generic
|
|
241
|
+
* `Dashboard` from `@multiplatform.one/components`.
|
|
247
242
|
*/
|
|
248
243
|
export function FrappeDashboard<TDoc extends { name: string; doctype: string }>({
|
|
249
244
|
baseURL,
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
// FrappeForm renders a doctype's connections (MPO-331): the doctypes that
|
|
2
|
+
// link back to the record through a Link field, read from meta.links or
|
|
3
|
+
// declared. A Pokemon shows its type, ability and move rows, which live in
|
|
4
|
+
// three standalone junction doctypes, not child tables. The same form hosts
|
|
5
|
+
// a detail page: render-prop mode hands those rows to `children`, and a
|
|
6
|
+
// server-rendered document stands in until the live read answers.
|
|
7
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
8
|
+
import { renderWithProviders, TestProviders } from "@multiplatform.one/test-utils";
|
|
9
|
+
import { cleanup, fireEvent, screen, waitFor } from "@testing-library/react";
|
|
10
|
+
import i18next from "i18next";
|
|
11
|
+
import { renderToString } from "react-dom/server";
|
|
12
|
+
import { initReactI18next } from "react-i18next";
|
|
13
|
+
import { Text } from "tamagui";
|
|
14
|
+
import { afterEach, beforeAll, describe, expect, it, vi } from "vitest";
|
|
15
|
+
import {
|
|
16
|
+
rosterFixtureData,
|
|
17
|
+
rosterPokemonMeta,
|
|
18
|
+
type RosterPokemon,
|
|
19
|
+
} from "../tests/fixtures/pokemonRoster";
|
|
20
|
+
import type { FrappeConnection } from "./frappeConnections";
|
|
21
|
+
import { FrappeForm, type FrappeConnectionRows, type FrappeFormProps } from "./FrappeForm";
|
|
22
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
23
|
+
|
|
24
|
+
const host = "https://form-connections.spec.test";
|
|
25
|
+
|
|
26
|
+
beforeAll(async () => {
|
|
27
|
+
await i18next.use(initReactI18next).init({
|
|
28
|
+
lng: "en",
|
|
29
|
+
interpolation: { escapeValue: false },
|
|
30
|
+
resources: { en: { translation: {} } },
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
cleanup();
|
|
36
|
+
vi.restoreAllMocks();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const pokemonConnections: FrappeConnection[] = [
|
|
40
|
+
{ doctype: "Pokemon Poke Type", fieldname: "pokemon", fields: ["poke_type", "slot"] },
|
|
41
|
+
{ doctype: "Pokemon Poke Ability", fieldname: "pokemon", fields: ["poke_ability", "is_hidden"] },
|
|
42
|
+
{
|
|
43
|
+
doctype: "Pokemon Poke Move",
|
|
44
|
+
fieldname: "pokemon",
|
|
45
|
+
fields: ["poke_move", "level_learned_at", "move_learn_method"],
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
function corpus(meta: Record<string, unknown> = rosterPokemonMeta) {
|
|
50
|
+
return new InMemoryFixtureProvider({
|
|
51
|
+
DocType: [{ name: "Pokemon", ...meta, doctype: "DocType" }],
|
|
52
|
+
...rosterFixtureData(),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function renderForm(
|
|
57
|
+
props: Partial<FrappeFormProps<RosterPokemon>>,
|
|
58
|
+
fixtures: InMemoryFixtureProvider = corpus(),
|
|
59
|
+
) {
|
|
60
|
+
return renderWithProviders(
|
|
61
|
+
<FrappeProvider baseURL={host} fixtures={fixtures}>
|
|
62
|
+
<FrappeForm<RosterPokemon>
|
|
63
|
+
doctype="Pokemon"
|
|
64
|
+
showSidebar={false}
|
|
65
|
+
showTimeline={false}
|
|
66
|
+
{...props}
|
|
67
|
+
/>
|
|
68
|
+
</FrappeProvider>,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function RowsProbe({ connections }: { connections: FrappeConnectionRows }) {
|
|
73
|
+
return (
|
|
74
|
+
<>
|
|
75
|
+
{Object.entries(connections).map(([doctype, rows]) => (
|
|
76
|
+
<Text key={doctype} testID={`rows-${doctype}`}>
|
|
77
|
+
{rows
|
|
78
|
+
.map((row) => String(row.poke_type ?? row.poke_ability ?? row.poke_move))
|
|
79
|
+
.sort()
|
|
80
|
+
.join(",")}
|
|
81
|
+
</Text>
|
|
82
|
+
))}
|
|
83
|
+
</>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
describe("FrappeForm connections, schema mode", () => {
|
|
88
|
+
it("shows the record's type, ability and move rows from meta.links on a Connections tab", async () => {
|
|
89
|
+
renderForm({ name: "bulbasaur" });
|
|
90
|
+
await waitFor(() => expect(screen.getByText("Connections")).toBeTruthy());
|
|
91
|
+
fireEvent.click(screen.getByText("Connections"));
|
|
92
|
+
await waitFor(() => expect(screen.getByText("grass")).toBeTruthy());
|
|
93
|
+
expect(screen.getByText("poison")).toBeTruthy();
|
|
94
|
+
expect(screen.getByText("overgrow")).toBeTruthy();
|
|
95
|
+
expect(screen.getByText("chlorophyll")).toBeTruthy();
|
|
96
|
+
expect(screen.getByText("tackle")).toBeTruthy();
|
|
97
|
+
expect(screen.getByText("vine-whip")).toBeTruthy();
|
|
98
|
+
expect(screen.queryByText("thunderbolt")).toBeNull();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("uses declared connections where meta carries no links", async () => {
|
|
102
|
+
const { links: _links, ...metaWithoutLinks } = rosterPokemonMeta;
|
|
103
|
+
renderForm(
|
|
104
|
+
{ name: "pikachu", connections: pokemonConnections.slice(2) },
|
|
105
|
+
corpus(metaWithoutLinks),
|
|
106
|
+
);
|
|
107
|
+
await waitFor(() => expect(screen.getByText("Connections")).toBeTruthy());
|
|
108
|
+
fireEvent.click(screen.getByText("Connections"));
|
|
109
|
+
await waitFor(() => expect(screen.getByText("thunderbolt")).toBeTruthy());
|
|
110
|
+
expect(screen.getByText("quick-attack")).toBeTruthy();
|
|
111
|
+
expect(screen.queryByText("static")).toBeNull();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("names each connection with its row count", async () => {
|
|
115
|
+
renderForm({ name: "pikachu", connections: pokemonConnections });
|
|
116
|
+
await waitFor(() => expect(screen.getByText("Connections")).toBeTruthy());
|
|
117
|
+
fireEvent.click(screen.getByText("Connections"));
|
|
118
|
+
await waitFor(() => expect(screen.getByText("Pokemon Poke Move (3)")).toBeTruthy());
|
|
119
|
+
expect(screen.getByText("Pokemon Poke Type (1)")).toBeTruthy();
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("an unlinked record says so instead of showing an empty table", async () => {
|
|
123
|
+
renderForm({ name: "eevee", connections: pokemonConnections.slice(1, 2) });
|
|
124
|
+
await waitFor(() => expect(screen.getByText("Connections")).toBeTruthy());
|
|
125
|
+
fireEvent.click(screen.getByText("Connections"));
|
|
126
|
+
await waitFor(() => expect(screen.getByText("No Pokemon Poke Ability rows")).toBeTruthy());
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("a new record has no connections yet", async () => {
|
|
130
|
+
renderForm({});
|
|
131
|
+
await waitFor(() => expect(screen.getByText("Save")).toBeTruthy());
|
|
132
|
+
expect(screen.queryByText("Connections")).toBeNull();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it("showConnections={false} leaves the tab out", async () => {
|
|
136
|
+
renderForm({ name: "bulbasaur", showConnections: false });
|
|
137
|
+
await waitFor(() => expect(screen.getByText("Save")).toBeTruthy());
|
|
138
|
+
expect(screen.queryByText("Connections")).toBeNull();
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
describe("FrappeForm connections, render-prop mode", () => {
|
|
143
|
+
it("hands children the record's linked rows per doctype", async () => {
|
|
144
|
+
renderForm({
|
|
145
|
+
name: "bulbasaur",
|
|
146
|
+
connections: pokemonConnections,
|
|
147
|
+
showToolbar: false,
|
|
148
|
+
children: ({ connections }) => <RowsProbe connections={connections} />,
|
|
149
|
+
});
|
|
150
|
+
await waitFor(() =>
|
|
151
|
+
expect(screen.getByTestId("rows-Pokemon Poke Type").textContent).toBe("grass,poison"),
|
|
152
|
+
);
|
|
153
|
+
expect(screen.getByTestId("rows-Pokemon Poke Ability").textContent).toBe(
|
|
154
|
+
"chlorophyll,overgrow",
|
|
155
|
+
);
|
|
156
|
+
expect(screen.getByTestId("rows-Pokemon Poke Move").textContent).toBe("tackle,vine-whip");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("reads connections from meta.links when none are declared", async () => {
|
|
160
|
+
renderForm({
|
|
161
|
+
name: "pikachu",
|
|
162
|
+
showToolbar: false,
|
|
163
|
+
children: ({ connections }) => <RowsProbe connections={connections} />,
|
|
164
|
+
});
|
|
165
|
+
await waitFor(() =>
|
|
166
|
+
expect(screen.getByTestId("rows-Pokemon Poke Type").textContent).toBe("electric"),
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
describe("FrappeForm hosting a detail page", () => {
|
|
172
|
+
const seed = {
|
|
173
|
+
name: "bulbasaur",
|
|
174
|
+
doctype: "Pokemon",
|
|
175
|
+
pokemon_name: "bulbasaur (server)",
|
|
176
|
+
} as Partial<RosterPokemon>;
|
|
177
|
+
|
|
178
|
+
const detail = ({ doc }: { doc: Partial<RosterPokemon> }) => (
|
|
179
|
+
<Text testID="detail-name">{doc.pokemon_name}</Text>
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
it("renders the server-rendered document on the server", () => {
|
|
183
|
+
const html = renderToString(
|
|
184
|
+
<TestProviders>
|
|
185
|
+
<FrappeProvider baseURL={host} fixtures={corpus()}>
|
|
186
|
+
<FrappeForm<RosterPokemon>
|
|
187
|
+
doctype="Pokemon"
|
|
188
|
+
name="bulbasaur"
|
|
189
|
+
initialDoc={seed}
|
|
190
|
+
showToolbar={false}
|
|
191
|
+
showSidebar={false}
|
|
192
|
+
showTimeline={false}
|
|
193
|
+
notFoundFallback={<Text>missing</Text>}
|
|
194
|
+
>
|
|
195
|
+
{detail}
|
|
196
|
+
</FrappeForm>
|
|
197
|
+
</FrappeProvider>
|
|
198
|
+
</TestProviders>,
|
|
199
|
+
);
|
|
200
|
+
expect(html).toContain("bulbasaur (server)");
|
|
201
|
+
expect(html).not.toContain("missing");
|
|
202
|
+
expect(html).not.toContain("frappe-form-skeleton");
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("shows the server document until the live read lands, then the live one", async () => {
|
|
206
|
+
const fixtures = corpus();
|
|
207
|
+
let release: () => void = () => undefined;
|
|
208
|
+
const gate = new Promise<void>((resolve) => {
|
|
209
|
+
release = resolve;
|
|
210
|
+
});
|
|
211
|
+
const getDoc = fixtures.getDoc.bind(fixtures);
|
|
212
|
+
vi.spyOn(fixtures, "getDoc").mockImplementation(async (...args) => {
|
|
213
|
+
await gate;
|
|
214
|
+
return getDoc(...args);
|
|
215
|
+
});
|
|
216
|
+
renderForm(
|
|
217
|
+
{ name: "bulbasaur", initialDoc: seed, showToolbar: false, children: detail },
|
|
218
|
+
fixtures,
|
|
219
|
+
);
|
|
220
|
+
expect(screen.getByTestId("detail-name").textContent).toBe("bulbasaur (server)");
|
|
221
|
+
release();
|
|
222
|
+
await waitFor(() => expect(screen.getByTestId("detail-name").textContent).toBe("bulbasaur"));
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("ignores a server document for another name", async () => {
|
|
226
|
+
renderForm({
|
|
227
|
+
name: "pikachu",
|
|
228
|
+
initialDoc: seed,
|
|
229
|
+
showToolbar: false,
|
|
230
|
+
children: detail,
|
|
231
|
+
});
|
|
232
|
+
await waitFor(() => expect(screen.getByTestId("detail-name").textContent).toBe("pikachu"));
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
it("takes the page's own loading, not-found and error states", async () => {
|
|
236
|
+
const fixtures = corpus();
|
|
237
|
+
let release: () => void = () => undefined;
|
|
238
|
+
const gate = new Promise<void>((resolve) => {
|
|
239
|
+
release = resolve;
|
|
240
|
+
});
|
|
241
|
+
const getDoc = fixtures.getDoc.bind(fixtures);
|
|
242
|
+
vi.spyOn(fixtures, "getDoc").mockImplementation(async (...args) => {
|
|
243
|
+
await gate;
|
|
244
|
+
return getDoc(...args);
|
|
245
|
+
});
|
|
246
|
+
renderForm(
|
|
247
|
+
{
|
|
248
|
+
name: "missingno",
|
|
249
|
+
showToolbar: false,
|
|
250
|
+
children: detail,
|
|
251
|
+
loadingFallback: <Text>page skeleton</Text>,
|
|
252
|
+
notFoundFallback: <Text>no such pokemon</Text>,
|
|
253
|
+
},
|
|
254
|
+
fixtures,
|
|
255
|
+
);
|
|
256
|
+
expect(screen.getByText("page skeleton")).toBeTruthy();
|
|
257
|
+
release();
|
|
258
|
+
await waitFor(() => expect(screen.getByText("no such pokemon")).toBeTruthy());
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("a failed read is the error state, not not-found", async () => {
|
|
262
|
+
const fixtures = corpus();
|
|
263
|
+
vi.spyOn(fixtures, "getDoc").mockImplementation(async (doctype, ...rest) => {
|
|
264
|
+
if (doctype === "Pokemon") throw Object.assign(new Error("PermissionError"), { status: 403 });
|
|
265
|
+
return InMemoryFixtureProvider.prototype.getDoc.call(fixtures, doctype, ...rest);
|
|
266
|
+
});
|
|
267
|
+
renderForm(
|
|
268
|
+
{
|
|
269
|
+
name: "bulbasaur",
|
|
270
|
+
showToolbar: false,
|
|
271
|
+
children: detail,
|
|
272
|
+
notFoundFallback: <Text>no such pokemon</Text>,
|
|
273
|
+
errorFallback: <Text>could not load</Text>,
|
|
274
|
+
},
|
|
275
|
+
fixtures,
|
|
276
|
+
);
|
|
277
|
+
await waitFor(() => expect(screen.getByText("could not load")).toBeTruthy());
|
|
278
|
+
expect(screen.queryByText("no such pokemon")).toBeNull();
|
|
279
|
+
});
|
|
280
|
+
});
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { Chip } from "@multiplatform.one/components";
|
|
2
|
+
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
3
|
+
import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
4
|
+
import { Text, XStack, YStack } from "tamagui";
|
|
5
|
+
import {
|
|
6
|
+
rosterFixtureData,
|
|
7
|
+
rosterPokemonMeta,
|
|
8
|
+
type RosterPokemon,
|
|
9
|
+
} from "../tests/fixtures/pokemonRoster";
|
|
10
|
+
import type { FrappeConnection } from "./frappeConnections";
|
|
11
|
+
import { FrappeForm, type FrappeConnectionRows } from "./FrappeForm";
|
|
12
|
+
import { FrappeProvider } from "./FrappeProvider";
|
|
13
|
+
|
|
14
|
+
export default {
|
|
15
|
+
title: "FrappeUI/FrappeForm Connections",
|
|
16
|
+
component: FrappeForm,
|
|
17
|
+
tags: ["!test"],
|
|
18
|
+
parameters: {
|
|
19
|
+
status: { type: "stable" },
|
|
20
|
+
docs: {
|
|
21
|
+
description: {
|
|
22
|
+
component:
|
|
23
|
+
"A record's connections: the doctypes linking back to it through a Link field (meta.links, or declared with `connections`). Schema mode lists them on a Connections tab; render-prop mode hands the rows to `children`, which is how a detail page renders them its own way. Pokemon's types, abilities and moves are standalone junction doctypes on the pokemon fixtures.",
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const host = "https://form-connections.mock.test";
|
|
30
|
+
|
|
31
|
+
const fixtures = () =>
|
|
32
|
+
new InMemoryFixtureProvider({
|
|
33
|
+
DocType: [{ ...rosterPokemonMeta, doctype: "DocType" }],
|
|
34
|
+
...rosterFixtureData(),
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const pokemonConnections: FrappeConnection[] = [
|
|
38
|
+
{ doctype: "Pokemon Poke Type", fieldname: "pokemon", fields: ["poke_type", "slot"] },
|
|
39
|
+
{ doctype: "Pokemon Poke Ability", fieldname: "pokemon", fields: ["poke_ability", "is_hidden"] },
|
|
40
|
+
{
|
|
41
|
+
doctype: "Pokemon Poke Move",
|
|
42
|
+
fieldname: "pokemon",
|
|
43
|
+
fields: ["poke_move", "level_learned_at", "move_learn_method"],
|
|
44
|
+
},
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const ConnectionsTab = () => (
|
|
48
|
+
<FrappeProvider baseURL={host} fixtures={fixtures()}>
|
|
49
|
+
<FrappeForm<RosterPokemon> doctype="Pokemon" name="bulbasaur" showSidebar={false} />
|
|
50
|
+
</FrappeProvider>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
function PokemonDetail({
|
|
54
|
+
doc,
|
|
55
|
+
connections,
|
|
56
|
+
}: {
|
|
57
|
+
doc: Partial<RosterPokemon>;
|
|
58
|
+
connections: FrappeConnectionRows;
|
|
59
|
+
}) {
|
|
60
|
+
const { knobProps } = useResolvedKnobs();
|
|
61
|
+
const types = connections["Pokemon Poke Type"] ?? [];
|
|
62
|
+
const moves = connections["Pokemon Poke Move"] ?? [];
|
|
63
|
+
return (
|
|
64
|
+
<YStack {...knobProps.gap}>
|
|
65
|
+
<Text {...knobProps.body} fontWeight="700" textTransform="capitalize">
|
|
66
|
+
{doc.pokemon_name}
|
|
67
|
+
</Text>
|
|
68
|
+
<XStack {...knobProps.gap}>
|
|
69
|
+
{types.map((row) => (
|
|
70
|
+
<Chip key={String(row.name)}>{String(row.poke_type)}</Chip>
|
|
71
|
+
))}
|
|
72
|
+
</XStack>
|
|
73
|
+
<Text {...knobProps.label} color="$color10">
|
|
74
|
+
{moves.map((row) => String(row.poke_move)).join(" · ")}
|
|
75
|
+
</Text>
|
|
76
|
+
</YStack>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export const DetailPage = () => (
|
|
81
|
+
<FrappeProvider baseURL={host} fixtures={fixtures()}>
|
|
82
|
+
<FrappeForm<RosterPokemon>
|
|
83
|
+
doctype="Pokemon"
|
|
84
|
+
name="pikachu"
|
|
85
|
+
connections={pokemonConnections}
|
|
86
|
+
showToolbar={false}
|
|
87
|
+
showSidebar={false}
|
|
88
|
+
showTimeline={false}
|
|
89
|
+
>
|
|
90
|
+
{({ doc, connections }) => <PokemonDetail doc={doc} connections={connections} />}
|
|
91
|
+
</FrappeForm>
|
|
92
|
+
</FrappeProvider>
|
|
93
|
+
);
|