@multiplatform.one/backoffice 7.28.1 → 7.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/cjs/desk/DeskSurface.native.js.map +1 -1
- package/dist/cjs/form/DocFormScreen.cjs +167 -224
- package/dist/cjs/form/DocFormScreen.native.js +182 -259
- package/dist/cjs/form/DocFormScreen.native.js.map +1 -1
- package/dist/cjs/i18n/en.cjs +1 -0
- package/dist/cjs/i18n/en.native.js +1 -0
- package/dist/cjs/i18n/en.native.js.map +1 -1
- package/dist/cjs/list/ListBulkActionsBar.cjs +30 -18
- package/dist/cjs/list/ListBulkActionsBar.native.js +43 -31
- package/dist/cjs/list/ListBulkActionsBar.native.js.map +1 -1
- package/dist/cjs/list/sidebar-section.cjs +15 -7
- package/dist/cjs/list/sidebar-section.native.js +16 -7
- package/dist/cjs/list/sidebar-section.native.js.map +1 -1
- package/dist/cjs/report/DoctypeReportView.cjs +20 -374
- package/dist/cjs/report/DoctypeReportView.native.js +23 -455
- package/dist/cjs/report/DoctypeReportView.native.js.map +1 -1
- package/dist/cjs/report/QueryReportScreen.cjs +33 -23
- package/dist/cjs/report/QueryReportScreen.native.js +33 -23
- package/dist/cjs/report/QueryReportScreen.native.js.map +1 -1
- package/dist/cjs/report/queryReportColumns.cjs +3 -105
- package/dist/cjs/report/queryReportColumns.native.js +2 -129
- package/dist/cjs/report/queryReportColumns.native.js.map +1 -1
- package/dist/cjs/report/queryReportFilterBar.cjs +3 -4
- package/dist/cjs/report/queryReportFilterBar.native.js +3 -4
- package/dist/cjs/report/queryReportFilterBar.native.js.map +1 -1
- package/dist/cjs/report/queryReportUrlState.cjs +2 -2
- package/dist/cjs/report/queryReportUrlState.native.js +2 -2
- package/dist/cjs/report/queryReportUrlState.native.js.map +1 -1
- package/dist/cjs/report/report-grid.cjs +2 -426
- package/dist/cjs/report/report-grid.native.js +1 -479
- package/dist/cjs/report/report-grid.native.js.map +1 -1
- package/dist/cjs/report/report-toolbar.cjs +2 -228
- package/dist/cjs/report/report-toolbar.native.js +1 -274
- package/dist/cjs/report/report-toolbar.native.js.map +1 -1
- package/dist/cjs/report/reportShapes.cjs +12 -383
- package/dist/cjs/report/reportShapes.native.js +12 -501
- package/dist/cjs/report/reportShapes.native.js.map +1 -1
- package/dist/cjs/report/reportViewModel.cjs +20 -360
- package/dist/cjs/report/reportViewModel.native.js +19 -627
- package/dist/cjs/report/reportViewModel.native.js.map +1 -1
- package/dist/cjs/report/savedReports.cjs +2 -106
- package/dist/cjs/report/savedReports.native.js +1 -132
- package/dist/cjs/report/savedReports.native.js.map +1 -1
- package/dist/cjs/report/useQueryReport.cjs +11 -219
- package/dist/cjs/report/useQueryReport.native.js +11 -244
- package/dist/cjs/report/useQueryReport.native.js.map +1 -1
- package/dist/cjs/shared/measures.cjs +3 -5
- package/dist/cjs/shared/measures.native.js +3 -5
- package/dist/cjs/shared/measures.native.js.map +1 -1
- package/dist/cjs/views/ReportView.cjs +3 -256
- package/dist/cjs/views/ReportView.native.js +3 -382
- package/dist/cjs/views/ReportView.native.js.map +1 -1
- package/dist/cjs/views/report-controls.cjs +6 -6
- package/dist/cjs/views/report-controls.native.js +6 -6
- package/dist/cjs/views/report-controls.native.js.map +1 -1
- package/dist/esm/desk/DeskSurface.mjs.map +1 -1
- package/dist/esm/desk/DeskSurface.native.js.map +1 -1
- package/dist/esm/form/DocFormScreen.mjs +169 -226
- package/dist/esm/form/DocFormScreen.mjs.map +1 -1
- package/dist/esm/form/DocFormScreen.native.js +184 -261
- package/dist/esm/form/DocFormScreen.native.js.map +1 -1
- package/dist/esm/i18n/en.mjs +1 -0
- package/dist/esm/i18n/en.mjs.map +1 -1
- package/dist/esm/i18n/en.native.js +1 -0
- package/dist/esm/i18n/en.native.js.map +1 -1
- package/dist/esm/list/ListBulkActionsBar.mjs +31 -19
- package/dist/esm/list/ListBulkActionsBar.mjs.map +1 -1
- package/dist/esm/list/ListBulkActionsBar.native.js +37 -25
- package/dist/esm/list/ListBulkActionsBar.native.js.map +1 -1
- package/dist/esm/list/sidebar-section.mjs +16 -8
- package/dist/esm/list/sidebar-section.mjs.map +1 -1
- package/dist/esm/list/sidebar-section.native.js +17 -8
- package/dist/esm/list/sidebar-section.native.js.map +1 -1
- package/dist/esm/report/DoctypeReportView.mjs +21 -375
- package/dist/esm/report/DoctypeReportView.mjs.map +1 -1
- package/dist/esm/report/DoctypeReportView.native.js +24 -456
- package/dist/esm/report/DoctypeReportView.native.js.map +1 -1
- package/dist/esm/report/QueryReportScreen.mjs +26 -16
- package/dist/esm/report/QueryReportScreen.mjs.map +1 -1
- package/dist/esm/report/QueryReportScreen.native.js +26 -16
- package/dist/esm/report/QueryReportScreen.native.js.map +1 -1
- package/dist/esm/report/queryReportColumns.mjs +1 -103
- package/dist/esm/report/queryReportColumns.mjs.map +1 -1
- package/dist/esm/report/queryReportColumns.native.js +1 -117
- package/dist/esm/report/queryReportColumns.native.js.map +1 -1
- package/dist/esm/report/queryReportFilterBar.mjs +1 -2
- package/dist/esm/report/queryReportFilterBar.mjs.map +1 -1
- package/dist/esm/report/queryReportFilterBar.native.js +1 -2
- package/dist/esm/report/queryReportFilterBar.native.js.map +1 -1
- package/dist/esm/report/queryReportUrlState.mjs +1 -1
- package/dist/esm/report/queryReportUrlState.native.js +1 -1
- package/dist/esm/report/report-grid.mjs +1 -425
- package/dist/esm/report/report-grid.mjs.map +1 -1
- package/dist/esm/report/report-grid.native.js +1 -468
- package/dist/esm/report/report-grid.native.js.map +1 -1
- package/dist/esm/report/report-toolbar.mjs +2 -228
- package/dist/esm/report/report-toolbar.mjs.map +1 -1
- package/dist/esm/report/report-toolbar.native.js +2 -264
- package/dist/esm/report/report-toolbar.native.js.map +1 -1
- package/dist/esm/report/reportShapes.mjs +2 -373
- package/dist/esm/report/reportShapes.mjs.map +1 -1
- package/dist/esm/report/reportShapes.native.js +2 -491
- package/dist/esm/report/reportShapes.native.js.map +1 -1
- package/dist/esm/report/reportViewModel.mjs +2 -342
- package/dist/esm/report/reportViewModel.mjs.map +1 -1
- package/dist/esm/report/reportViewModel.native.js +2 -610
- package/dist/esm/report/reportViewModel.native.js.map +1 -1
- package/dist/esm/report/savedReports.mjs +1 -105
- package/dist/esm/report/savedReports.mjs.map +1 -1
- package/dist/esm/report/savedReports.native.js +1 -132
- package/dist/esm/report/savedReports.native.js.map +1 -1
- package/dist/esm/report/useQueryReport.mjs +2 -210
- package/dist/esm/report/useQueryReport.mjs.map +1 -1
- package/dist/esm/report/useQueryReport.native.js +2 -235
- package/dist/esm/report/useQueryReport.native.js.map +1 -1
- package/dist/esm/shared/measures.mjs +1 -3
- package/dist/esm/shared/measures.mjs.map +1 -1
- package/dist/esm/shared/measures.native.js +1 -3
- package/dist/esm/shared/measures.native.js.map +1 -1
- package/dist/esm/views/ReportView.mjs +3 -256
- package/dist/esm/views/ReportView.mjs.map +1 -1
- package/dist/esm/views/ReportView.native.js +3 -382
- package/dist/esm/views/ReportView.native.js.map +1 -1
- package/dist/esm/views/report-controls.mjs +3 -3
- package/dist/esm/views/report-controls.mjs.map +1 -1
- package/dist/esm/views/report-controls.native.js +3 -3
- package/dist/esm/views/report-controls.native.js.map +1 -1
- package/dist/jsx/desk/DeskSurface.mjs.map +1 -1
- package/dist/jsx/desk/DeskSurface.native.js.map +1 -1
- package/dist/jsx/form/DocFormScreen.mjs +169 -226
- package/dist/jsx/form/DocFormScreen.mjs.map +1 -1
- package/dist/jsx/form/DocFormScreen.native.js +182 -259
- package/dist/jsx/form/DocFormScreen.native.js.map +1 -1
- package/dist/jsx/i18n/en.mjs +1 -0
- package/dist/jsx/i18n/en.mjs.map +1 -1
- package/dist/jsx/i18n/en.native.js +1 -0
- package/dist/jsx/i18n/en.native.js.map +1 -1
- package/dist/jsx/list/ListBulkActionsBar.mjs +31 -19
- package/dist/jsx/list/ListBulkActionsBar.mjs.map +1 -1
- package/dist/jsx/list/ListBulkActionsBar.native.js +43 -31
- package/dist/jsx/list/ListBulkActionsBar.native.js.map +1 -1
- package/dist/jsx/list/sidebar-section.mjs +16 -8
- package/dist/jsx/list/sidebar-section.mjs.map +1 -1
- package/dist/jsx/list/sidebar-section.native.js +16 -7
- package/dist/jsx/list/sidebar-section.native.js.map +1 -1
- package/dist/jsx/report/DoctypeReportView.mjs +21 -375
- package/dist/jsx/report/DoctypeReportView.mjs.map +1 -1
- package/dist/jsx/report/DoctypeReportView.native.js +23 -455
- package/dist/jsx/report/DoctypeReportView.native.js.map +1 -1
- package/dist/jsx/report/QueryReportScreen.mjs +26 -16
- package/dist/jsx/report/QueryReportScreen.mjs.map +1 -1
- package/dist/jsx/report/QueryReportScreen.native.js +33 -23
- package/dist/jsx/report/QueryReportScreen.native.js.map +1 -1
- package/dist/jsx/report/queryReportColumns.mjs +1 -103
- package/dist/jsx/report/queryReportColumns.mjs.map +1 -1
- package/dist/jsx/report/queryReportColumns.native.js +2 -129
- package/dist/jsx/report/queryReportColumns.native.js.map +1 -1
- package/dist/jsx/report/queryReportFilterBar.mjs +1 -2
- package/dist/jsx/report/queryReportFilterBar.mjs.map +1 -1
- package/dist/jsx/report/queryReportFilterBar.native.js +3 -4
- package/dist/jsx/report/queryReportFilterBar.native.js.map +1 -1
- package/dist/jsx/report/queryReportUrlState.mjs +1 -1
- package/dist/jsx/report/queryReportUrlState.native.js +2 -2
- package/dist/jsx/report/queryReportUrlState.native.js.map +1 -1
- package/dist/jsx/report/report-grid.mjs +1 -425
- package/dist/jsx/report/report-grid.mjs.map +1 -1
- package/dist/jsx/report/report-grid.native.js +1 -479
- package/dist/jsx/report/report-grid.native.js.map +1 -1
- package/dist/jsx/report/report-toolbar.mjs +2 -228
- package/dist/jsx/report/report-toolbar.mjs.map +1 -1
- package/dist/jsx/report/report-toolbar.native.js +1 -274
- package/dist/jsx/report/report-toolbar.native.js.map +1 -1
- package/dist/jsx/report/reportShapes.mjs +2 -373
- package/dist/jsx/report/reportShapes.mjs.map +1 -1
- package/dist/jsx/report/reportShapes.native.js +12 -501
- package/dist/jsx/report/reportShapes.native.js.map +1 -1
- package/dist/jsx/report/reportViewModel.mjs +2 -342
- package/dist/jsx/report/reportViewModel.mjs.map +1 -1
- package/dist/jsx/report/reportViewModel.native.js +19 -627
- package/dist/jsx/report/reportViewModel.native.js.map +1 -1
- package/dist/jsx/report/savedReports.mjs +1 -105
- package/dist/jsx/report/savedReports.mjs.map +1 -1
- package/dist/jsx/report/savedReports.native.js +1 -132
- package/dist/jsx/report/savedReports.native.js.map +1 -1
- package/dist/jsx/report/useQueryReport.mjs +2 -210
- package/dist/jsx/report/useQueryReport.mjs.map +1 -1
- package/dist/jsx/report/useQueryReport.native.js +11 -244
- package/dist/jsx/report/useQueryReport.native.js.map +1 -1
- package/dist/jsx/shared/measures.mjs +1 -3
- package/dist/jsx/shared/measures.mjs.map +1 -1
- package/dist/jsx/shared/measures.native.js +3 -5
- package/dist/jsx/shared/measures.native.js.map +1 -1
- package/dist/jsx/views/ReportView.mjs +3 -256
- package/dist/jsx/views/ReportView.mjs.map +1 -1
- package/dist/jsx/views/ReportView.native.js +3 -382
- package/dist/jsx/views/ReportView.native.js.map +1 -1
- package/dist/jsx/views/report-controls.mjs +3 -3
- package/dist/jsx/views/report-controls.mjs.map +1 -1
- package/dist/jsx/views/report-controls.native.js +6 -6
- package/dist/jsx/views/report-controls.native.js.map +1 -1
- package/package.json +12 -12
- package/src/backofficeScreens.designLaw.spec.ts +0 -5
- package/src/desk/DeskSurface.tsx +4 -7
- package/src/form/DocFormScreen.chrome.spec.ts +77 -0
- package/src/form/DocFormScreen.guest.screen.spec.tsx +175 -0
- package/src/form/DocFormScreen.rights.spec.tsx +7 -3
- package/src/form/DocFormScreen.tsx +214 -315
- package/src/i18n/en.ts +1 -0
- package/src/list/ListBulkActionsBar.rights.spec.tsx +134 -0
- package/src/list/ListBulkActionsBar.screen.spec.tsx +7 -1
- package/src/list/ListBulkActionsBar.tsx +76 -57
- package/src/list/ListFilterBar.screen.spec.tsx +14 -13
- package/src/list/sidebar-section.tsx +11 -3
- package/src/report/DoctypeReportView.tsx +28 -550
- package/src/report/QueryReportScreen.spec.tsx +75 -1
- package/src/report/QueryReportScreen.tsx +38 -22
- package/src/report/queryReportColumns.tsx +4 -123
- package/src/report/queryReportFilterBar.tsx +3 -5
- package/src/report/queryReportUrlState.ts +1 -1
- package/src/report/report-grid.tsx +4 -529
- package/src/report/report-toolbar.tsx +4 -308
- package/src/report/reportShapes.ts +25 -613
- package/src/report/reportShim.spec.ts +162 -0
- package/src/report/reportViewModel.ts +32 -605
- package/src/report/savedReports.ts +4 -161
- package/src/report/useQueryReport.ts +9 -347
- package/src/shared/measures.ts +3 -11
- package/src/views/ReportView.screen.spec.tsx +25 -20
- package/src/views/ReportView.tsx +7 -439
- package/src/views/report-controls.tsx +12 -20
- package/types/desk/DeskSurface.d.ts.map +1 -1
- package/types/form/DocFormScreen.d.ts +2 -2
- package/types/form/DocFormScreen.d.ts.map +1 -1
- package/types/i18n/en.d.ts +1 -0
- package/types/i18n/en.d.ts.map +1 -1
- package/types/list/ListBulkActionsBar.d.ts.map +1 -1
- package/types/list/sidebar-section.d.ts.map +1 -1
- package/types/report/DoctypeReportView.d.ts.map +1 -1
- package/types/report/QueryReportScreen.d.ts +1 -1
- package/types/report/QueryReportScreen.d.ts.map +1 -1
- package/types/report/queryReportColumns.d.ts +2 -11
- package/types/report/queryReportColumns.d.ts.map +1 -1
- package/types/report/queryReportFilterBar.d.ts +1 -1
- package/types/report/queryReportFilterBar.d.ts.map +1 -1
- package/types/report/queryReportUrlState.d.ts +1 -1
- package/types/report/queryReportUrlState.d.ts.map +1 -1
- package/types/report/report-grid.d.ts +2 -19
- package/types/report/report-grid.d.ts.map +1 -1
- package/types/report/report-toolbar.d.ts +2 -29
- package/types/report/report-toolbar.d.ts.map +1 -1
- package/types/report/reportShapes.d.ts +2 -115
- package/types/report/reportShapes.d.ts.map +1 -1
- package/types/report/reportViewModel.d.ts +2 -135
- package/types/report/reportViewModel.d.ts.map +1 -1
- package/types/report/savedReports.d.ts +2 -18
- package/types/report/savedReports.d.ts.map +1 -1
- package/types/report/useQueryReport.d.ts +2 -35
- package/types/report/useQueryReport.d.ts.map +1 -1
- package/types/shared/measures.d.ts +1 -2
- package/types/shared/measures.d.ts.map +1 -1
- package/types/views/ReportView.d.ts +3 -22
- package/types/views/ReportView.d.ts.map +1 -1
- package/types/views/report-controls.d.ts +2 -5
- package/types/views/report-controls.d.ts.map +1 -1
- package/src/report/report-grid.spec.tsx +0 -175
- package/src/report/report-toolbar.spec.tsx +0 -90
- package/src/report/reportShapes.spec.ts +0 -391
- package/src/report/reportViewModel.spec.ts +0 -393
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@multiplatform.one/backoffice",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.29.0",
|
|
4
4
|
"description": "Embeddable Frappe desk recreation (backoffice) for the multiplatform.one stack",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"backoffice",
|
|
@@ -71,21 +71,21 @@
|
|
|
71
71
|
"access": "public"
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
|
-
"@multiplatform.one/components": "7.
|
|
75
|
-
"@multiplatform.one/forms": "7.
|
|
76
|
-
"@multiplatform.one/frappe": "7.
|
|
77
|
-
"@multiplatform.one/frappe-ui": "7.
|
|
78
|
-
"@multiplatform.one/i18n": "7.
|
|
79
|
-
"@multiplatform.one/platform": "7.
|
|
80
|
-
"@multiplatform.one/store": "7.
|
|
81
|
-
"@multiplatform.one/table": "7.
|
|
82
|
-
"@multiplatform.one/theme": "7.
|
|
74
|
+
"@multiplatform.one/components": "7.29.0",
|
|
75
|
+
"@multiplatform.one/forms": "7.29.0",
|
|
76
|
+
"@multiplatform.one/frappe": "7.29.0",
|
|
77
|
+
"@multiplatform.one/frappe-ui": "7.29.0",
|
|
78
|
+
"@multiplatform.one/i18n": "7.29.0",
|
|
79
|
+
"@multiplatform.one/platform": "7.29.0",
|
|
80
|
+
"@multiplatform.one/store": "7.29.0",
|
|
81
|
+
"@multiplatform.one/table": "7.29.0",
|
|
82
|
+
"@multiplatform.one/theme": "7.29.0",
|
|
83
83
|
"@phosphor-icons/react": "^2.1.10",
|
|
84
84
|
"tamagui": "2.7.6"
|
|
85
85
|
},
|
|
86
86
|
"devDependencies": {
|
|
87
|
-
"@multiplatform.one/config": "7.
|
|
88
|
-
"@multiplatform.one/test-utils": "7.
|
|
87
|
+
"@multiplatform.one/config": "7.29.0",
|
|
88
|
+
"@multiplatform.one/test-utils": "7.29.0",
|
|
89
89
|
"@tamagui/build": "2.7.6",
|
|
90
90
|
"@testing-library/react": "^16.3.2",
|
|
91
91
|
"@types/react-dom": "^19.2.3",
|
|
@@ -79,11 +79,6 @@ describe("Backoffice screens — design-law 100%", () => {
|
|
|
79
79
|
expect(source).not.toContain("toLocaleString");
|
|
80
80
|
});
|
|
81
81
|
|
|
82
|
-
it("report toolbar filters are catalog Chip, not 999-radius wells", () => {
|
|
83
|
-
expect(read("report/report-toolbar.tsx")).toContain("<Chip");
|
|
84
|
-
expect(read("report/report-toolbar.tsx")).not.toMatch(/borderRadius=\{999\}/);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
82
|
it("Workspace shortcut counts are catalog Chip; labels and titles weight 400", () => {
|
|
88
83
|
const shortcut = read("workspace/WorkspaceShortcut.tsx");
|
|
89
84
|
expect(shortcut).toContain("<Chip");
|
package/src/desk/DeskSurface.tsx
CHANGED
|
@@ -110,13 +110,10 @@ export function DeskSurface({
|
|
|
110
110
|
<NewDocSurface doctype={target.doctype} defaults={target.defaults} readOnly={readOnly} />
|
|
111
111
|
);
|
|
112
112
|
case "form":
|
|
113
|
-
//
|
|
114
|
-
//
|
|
115
|
-
//
|
|
116
|
-
//
|
|
117
|
-
// fetch_from, set_only_once or the *_depends_on chains yet. When it
|
|
118
|
-
// does, the exported FrappeForm becomes this branch's renderer. Swap
|
|
119
|
-
// here, nowhere else.
|
|
113
|
+
// DocFormScreen is desk chrome over FrappeForm (MPO-15): the fields
|
|
114
|
+
// are the exported FrappeForm's, on the controller useFrappeForm
|
|
115
|
+
// returns, so this branch and a bare <FrappeForm> resolve a doctype
|
|
116
|
+
// the same way.
|
|
120
117
|
return <DocFormScreen doctype={target.doctype} name={target.name} readOnly={readOnly} />;
|
|
121
118
|
case "report":
|
|
122
119
|
return <QueryReportScreen reportName={target.reportName} />;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MPO-15 AC2: DocFormScreen is page chrome over FrappeForm.
|
|
3
|
+
*
|
|
4
|
+
* The desk form page owns its toolbar, menu, dialogs, sidebar, timeline and
|
|
5
|
+
* banners. Which fields render, which are required, read-only or hidden, and
|
|
6
|
+
* how they lay out into tabs is FrappeForm's job, so the exported component
|
|
7
|
+
* and the desk can never resolve the same doctype differently again. Any
|
|
8
|
+
* DocField key name in the page, or an import of the layout engine, means the
|
|
9
|
+
* page has started resolving fields of its own.
|
|
10
|
+
*/
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import { describe, expect, it } from "vitest";
|
|
14
|
+
|
|
15
|
+
const source = fs.readFileSync(path.resolve(__dirname, "DocFormScreen.tsx"), "utf8");
|
|
16
|
+
|
|
17
|
+
const docFieldKeys = [
|
|
18
|
+
"fieldname",
|
|
19
|
+
"fieldtype",
|
|
20
|
+
"permlevel",
|
|
21
|
+
"depends_on",
|
|
22
|
+
"mandatory_depends_on",
|
|
23
|
+
"read_only_depends_on",
|
|
24
|
+
"collapsible_depends_on",
|
|
25
|
+
"set_only_once",
|
|
26
|
+
"fetch_from",
|
|
27
|
+
"reqd",
|
|
28
|
+
"hidden",
|
|
29
|
+
"read_only",
|
|
30
|
+
"allow_on_submit",
|
|
31
|
+
"in_list_view",
|
|
32
|
+
"options",
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const fieldResolution = [
|
|
36
|
+
"buildFormTabs",
|
|
37
|
+
"buildPermLevelMatrix",
|
|
38
|
+
"buildCopyValues",
|
|
39
|
+
"buildCreateDefaults",
|
|
40
|
+
"isPromptNamed",
|
|
41
|
+
"SchemaForm",
|
|
42
|
+
"useFormEngine",
|
|
43
|
+
"sessionDocRights",
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
function importedNames(from: string): string[] {
|
|
47
|
+
const names: string[] = [];
|
|
48
|
+
const pattern = /import\s+(?:type\s+)?\{([^}]*)\}\s+from\s+"([^"]+)"/g;
|
|
49
|
+
for (const match of source.matchAll(pattern)) {
|
|
50
|
+
if (match[2] !== from) continue;
|
|
51
|
+
for (const part of match[1].split(",")) {
|
|
52
|
+
const name = part
|
|
53
|
+
.trim()
|
|
54
|
+
.replace(/^type\s+/, "")
|
|
55
|
+
.split(/\s+as\s+/)[0];
|
|
56
|
+
if (name) names.push(name);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return names;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe("DocFormScreen is chrome over FrappeForm (MPO-15 AC2)", () => {
|
|
63
|
+
it.each(docFieldKeys)("names no DocField key: %s", (key) => {
|
|
64
|
+
expect(source).not.toMatch(new RegExp(`\\b${key}\\b`));
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it.each(fieldResolution)("does not resolve fields itself: %s", (name) => {
|
|
68
|
+
expect(source).not.toMatch(new RegExp(`\\b${name}\\b`));
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("renders the field body through FrappeForm and its controller", () => {
|
|
72
|
+
const frappeUi = importedNames("@multiplatform.one/frappe-ui");
|
|
73
|
+
expect(frappeUi).toContain("FrappeForm");
|
|
74
|
+
expect(frappeUi).toContain("useFrappeForm");
|
|
75
|
+
expect(source).toMatch(/<FrappeForm(?:<\w+>)?\s[^>]*\bform=\{form\}/s);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// LC-96 on the desk form (MPO-473). Signed out, pokemon's bench refuses
|
|
2
|
+
// getdoctype to Guest while Guest can still read the record, and the desk form
|
|
3
|
+
// stopped at its own "Could not load Pokemon" before FrappeForm could lay the
|
|
4
|
+
// record out. The bench below answers getdoctype the way Frappe's
|
|
5
|
+
// is_whitelisted refuses Guest (one message, a <details> summary and body) and
|
|
6
|
+
// answers or refuses the record per test.
|
|
7
|
+
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
8
|
+
import { fireEvent, screen, waitFor } from "@testing-library/react";
|
|
9
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
10
|
+
import { BackofficeProvider } from "../config/BackofficeProvider";
|
|
11
|
+
import { createMemoryNavigator } from "../navigation/navigator";
|
|
12
|
+
import { DocFormScreen } from "./DocFormScreen";
|
|
13
|
+
|
|
14
|
+
const doctype = "Poke Move";
|
|
15
|
+
|
|
16
|
+
const tackle = {
|
|
17
|
+
name: "a1b2c3",
|
|
18
|
+
doctype,
|
|
19
|
+
owner: "Administrator",
|
|
20
|
+
modified: "2026-09-29 10:00:00",
|
|
21
|
+
docstatus: 0,
|
|
22
|
+
idx: 0,
|
|
23
|
+
move_name: "tackle",
|
|
24
|
+
power: 40,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const refusal = {
|
|
28
|
+
message:
|
|
29
|
+
"<details><summary>You are not permitted to access this resource. Login to access</summary>Function <strong>frappe.desk.form.load.getdoctype</strong> is not whitelisted.</details>",
|
|
30
|
+
title: "Method Not Allowed",
|
|
31
|
+
indicator: "red",
|
|
32
|
+
raise_exception: 1,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const settle = { timeout: 8000 };
|
|
36
|
+
|
|
37
|
+
let run = 0;
|
|
38
|
+
let metaAnswer: "refused" | "broken" = "refused";
|
|
39
|
+
let recordReadable = true;
|
|
40
|
+
let metaReads = 0;
|
|
41
|
+
|
|
42
|
+
function json(body: unknown, status = 200) {
|
|
43
|
+
return new Response(JSON.stringify(body), {
|
|
44
|
+
status,
|
|
45
|
+
headers: { "content-type": "application/json" },
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function refused() {
|
|
50
|
+
return json(
|
|
51
|
+
{
|
|
52
|
+
exc_type: "PermissionError",
|
|
53
|
+
exception: `frappe.exceptions.PermissionError: ${refusal.message}`,
|
|
54
|
+
_server_messages: JSON.stringify([JSON.stringify(refusal)]),
|
|
55
|
+
},
|
|
56
|
+
403,
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
run += 1;
|
|
62
|
+
metaAnswer = "refused";
|
|
63
|
+
recordReadable = true;
|
|
64
|
+
metaReads = 0;
|
|
65
|
+
vi.stubGlobal("fetch", async (input: string | URL | Request) => {
|
|
66
|
+
const url = new URL(String(input instanceof Request ? input.url : input));
|
|
67
|
+
const method = url.pathname.replace(/^\/api\/method\//, "");
|
|
68
|
+
if (method === "frappe.desk.form.load.getdoctype") {
|
|
69
|
+
metaReads += 1;
|
|
70
|
+
return metaAnswer === "refused"
|
|
71
|
+
? refused()
|
|
72
|
+
: json({ exc_type: "ValidationError", exception: "Poke Move is being migrated" }, 417);
|
|
73
|
+
}
|
|
74
|
+
if (method.startsWith("frappe.")) return refused();
|
|
75
|
+
const resource = `/api/resource/${encodeURIComponent(doctype)}`;
|
|
76
|
+
if (url.pathname === resource || url.pathname.startsWith(`${resource}/`)) {
|
|
77
|
+
if (!recordReadable) {
|
|
78
|
+
return json({ exc_type: "PermissionError", exception: "Not permitted" }, 403);
|
|
79
|
+
}
|
|
80
|
+
return url.pathname === resource ? json({ data: [tackle] }) : json({ data: tackle });
|
|
81
|
+
}
|
|
82
|
+
return json({ data: [], message: [] });
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
afterEach(() => {
|
|
87
|
+
vi.restoreAllMocks();
|
|
88
|
+
vi.unstubAllGlobals();
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
function renderForm(name: string) {
|
|
92
|
+
return renderWithProviders(
|
|
93
|
+
<BackofficeProvider
|
|
94
|
+
frappe={{ baseURL: `https://desk-form-guest-${run}.spec.test` }}
|
|
95
|
+
navigation={createMemoryNavigator("/backoffice")}
|
|
96
|
+
>
|
|
97
|
+
<DocFormScreen doctype={doctype} name={name} />
|
|
98
|
+
</BackofficeProvider>,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function inputOf(label: string): HTMLInputElement {
|
|
103
|
+
const field = screen.getByLabelText(label, { exact: false });
|
|
104
|
+
return (
|
|
105
|
+
field instanceof HTMLInputElement ? field : field.querySelector("input")
|
|
106
|
+
) as HTMLInputElement;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function button(label: string): HTMLElement | undefined {
|
|
110
|
+
return Array.from(document.querySelectorAll('[role="button"], button')).find(
|
|
111
|
+
(node) => node.textContent?.trim() === label,
|
|
112
|
+
) as HTMLElement | undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
describe("DocFormScreen with DocType meta refused (LC-96)", () => {
|
|
116
|
+
it("lays out the record's own fields read-only instead of stopping at 'Could not load'", async () => {
|
|
117
|
+
renderForm("a1b2c3");
|
|
118
|
+
await waitFor(() => expect(inputOf("Power").value).toBe("40"), settle);
|
|
119
|
+
expect(inputOf("Power").disabled || inputOf("Power").readOnly).toBe(true);
|
|
120
|
+
expect(inputOf("Move Name").value).toBe("tackle");
|
|
121
|
+
expect(screen.queryByText(/Could not load/)).toBeNull();
|
|
122
|
+
expect(screen.queryByLabelText("Owner", { exact: true })).toBeNull();
|
|
123
|
+
expect(button("Save")).toBeUndefined();
|
|
124
|
+
expect(metaReads).toBe(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("offers nothing that needs the refused meta or docinfo", async () => {
|
|
128
|
+
renderForm("a1b2c3");
|
|
129
|
+
await waitFor(() => expect(inputOf("Power").value).toBe("40"), settle);
|
|
130
|
+
expect(screen.queryByText("Activity")).toBeNull();
|
|
131
|
+
fireEvent.click(screen.getByTestId("form-toolbar-menu"));
|
|
132
|
+
await waitFor(
|
|
133
|
+
() => expect(document.querySelectorAll('[role="menuitem"]').length).toBeGreaterThan(0),
|
|
134
|
+
settle,
|
|
135
|
+
);
|
|
136
|
+
const items = Array.from(document.querySelectorAll('[role="menuitem"]')).map(
|
|
137
|
+
(node) => node.textContent ?? "",
|
|
138
|
+
);
|
|
139
|
+
expect(items.some((label) => label.startsWith("Duplicate"))).toBe(false);
|
|
140
|
+
expect(items.some((label) => label.startsWith("Delete"))).toBe(false);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("says the reader can't open a record refused too, with no retry", async () => {
|
|
144
|
+
recordReadable = false;
|
|
145
|
+
renderForm("a1b2c3");
|
|
146
|
+
const state = await screen.findByTestId("frappe-form-not-permitted", {}, settle);
|
|
147
|
+
expect(state.textContent).toContain(`You can't open ${doctype} a1b2c3`);
|
|
148
|
+
expect(screen.queryByText(/Could not load/)).toBeNull();
|
|
149
|
+
expect(screen.queryByRole("button", { name: /retry/i })).toBeNull();
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("says the reader can't create, with each server message on its own line", async () => {
|
|
153
|
+
renderForm("new");
|
|
154
|
+
const state = await screen.findByTestId("frappe-form-not-permitted", {}, settle);
|
|
155
|
+
expect(state.textContent).toContain(`You can't create ${doctype}`);
|
|
156
|
+
const lines = Array.from(state.querySelectorAll("p")).map((node) => node.textContent);
|
|
157
|
+
expect(lines).toContain("You are not permitted to access this resource. Login to access");
|
|
158
|
+
expect(lines).toContain("Function frappe.desk.form.load.getdoctype is not whitelisted.");
|
|
159
|
+
expect(lines.some((line) => line?.includes("accessFunction"))).toBe(false);
|
|
160
|
+
expect(button("Save")).toBeUndefined();
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
it("keeps a meta read that failed for another reason a retryable error", async () => {
|
|
164
|
+
metaAnswer = "broken";
|
|
165
|
+
renderForm("a1b2c3");
|
|
166
|
+
await waitFor(
|
|
167
|
+
() => expect(screen.getByText(/Poke Move is being migrated/)).toBeTruthy(),
|
|
168
|
+
settle,
|
|
169
|
+
);
|
|
170
|
+
expect(screen.queryByTestId("frappe-form-not-permitted")).toBeNull();
|
|
171
|
+
const retry = screen.getByRole("button", { name: /retry/i });
|
|
172
|
+
fireEvent.click(retry);
|
|
173
|
+
await waitFor(() => expect(metaReads).toBe(2), settle);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
// usable permissions (a new record, or a token-auth bench answering
|
|
3
3
|
// {"null": 0}) the screen used to union every role's DocPerm rows, so any
|
|
4
4
|
// reader got an editable form and Save. It now resolves the session's roles.
|
|
5
|
+
// The form body is FrappeForm's (MPO-15 AC2), so a reader asking for a new
|
|
6
|
+
// record meets FrappeForm's not-permitted state, as desk refuses new_doc.
|
|
5
7
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
6
8
|
import { act, screen, waitFor } from "@testing-library/react";
|
|
7
9
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
@@ -111,13 +113,15 @@ describe("DocFormScreen rights without docinfo permissions", () => {
|
|
|
111
113
|
expect(moveNameInput().disabled || moveNameInput().readOnly).toBe(false);
|
|
112
114
|
});
|
|
113
115
|
|
|
114
|
-
it("
|
|
116
|
+
it("tells a reader they can't create one, with no Save", async () => {
|
|
115
117
|
roles = ["Guest"];
|
|
116
118
|
renderForm("new");
|
|
117
|
-
await waitFor(() => expect(
|
|
119
|
+
await waitFor(() => expect(screen.getByTestId("frappe-form-not-permitted")).toBeTruthy(), {
|
|
120
|
+
timeout: 5000,
|
|
121
|
+
});
|
|
118
122
|
await settle();
|
|
119
123
|
expect(saveButton()).toBeUndefined();
|
|
120
|
-
expect(
|
|
124
|
+
expect(screen.queryByLabelText("Move Name", { exact: false })).toBeNull();
|
|
121
125
|
});
|
|
122
126
|
|
|
123
127
|
it("gives a reader an existing record read-only", async () => {
|