@multiplatform.one/backoffice 7.28.1 → 7.29.1
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
|
@@ -1,161 +1,4 @@
|
|
|
1
|
-
// Saved reports
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// opens reports saved here and vice versa). Fixture mode (stories / no
|
|
6
|
-
// bench) keeps an in-memory list so the control stays demonstrable.
|
|
7
|
-
import { useFrappeConfig } from "@multiplatform.one/frappe-ui";
|
|
8
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
-
import { useFrappeApp } from "../shared/useFrappeApp";
|
|
10
|
-
import {
|
|
11
|
-
toDeskReportSettings,
|
|
12
|
-
fromDeskReportSettings,
|
|
13
|
-
type ReportViewConfig,
|
|
14
|
-
} from "./reportViewModel";
|
|
15
|
-
|
|
16
|
-
export interface SavedReportSummary {
|
|
17
|
-
/** Report document name (usually equals the report title). */
|
|
18
|
-
name: string;
|
|
19
|
-
reportName: string;
|
|
20
|
-
json?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface UseSavedReportsResult {
|
|
24
|
-
reports: SavedReportSummary[];
|
|
25
|
-
loading: boolean;
|
|
26
|
-
/** Load a saved report's view config (fields/filters/sort/…). */
|
|
27
|
-
load: (name: string) => Promise<ReportViewConfig | undefined>;
|
|
28
|
-
/** Create or update a Report doc; returns the server-side name. */
|
|
29
|
-
save: (name: string, config: ReportViewConfig) => Promise<string>;
|
|
30
|
-
remove: (name: string) => Promise<void>;
|
|
31
|
-
refresh: () => void;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
type ReportListRow = { name: string; report_name?: string; json?: string };
|
|
35
|
-
|
|
36
|
-
export function useSavedReports(doctype: string): UseSavedReportsResult {
|
|
37
|
-
const app = useFrappeApp();
|
|
38
|
-
const config = useFrappeConfig();
|
|
39
|
-
const fixtureMode = Boolean(config?.fixtures);
|
|
40
|
-
const [reports, setReports] = useState<SavedReportSummary[]>([]);
|
|
41
|
-
const [loading, setLoading] = useState(false);
|
|
42
|
-
const [generation, setGeneration] = useState(0);
|
|
43
|
-
// Fixture-mode saves live here (stories/tests) — never reaches a bench.
|
|
44
|
-
const memoryConfigs = useRef(new Map<string, ReportViewConfig>());
|
|
45
|
-
|
|
46
|
-
useEffect(() => {
|
|
47
|
-
memoryConfigs.current = new Map();
|
|
48
|
-
setReports([]);
|
|
49
|
-
}, [doctype]);
|
|
50
|
-
|
|
51
|
-
useEffect(() => {
|
|
52
|
-
if (!app || fixtureMode) return;
|
|
53
|
-
let cancelled = false;
|
|
54
|
-
setLoading(true);
|
|
55
|
-
app
|
|
56
|
-
.call()
|
|
57
|
-
.get<{ message?: ReportListRow[] }>("frappe.client.get_list", {
|
|
58
|
-
doctype: "Report",
|
|
59
|
-
filters: JSON.stringify([
|
|
60
|
-
["ref_doctype", "=", doctype],
|
|
61
|
-
["report_type", "=", "Report Builder"],
|
|
62
|
-
["disabled", "=", 0],
|
|
63
|
-
]),
|
|
64
|
-
fields: JSON.stringify(["name", "report_name", "json"]),
|
|
65
|
-
limit_page_length: 0,
|
|
66
|
-
order_by: "report_name asc",
|
|
67
|
-
})
|
|
68
|
-
.then((res) => {
|
|
69
|
-
if (cancelled) return;
|
|
70
|
-
const rows = res.payload?.message ?? [];
|
|
71
|
-
setReports(
|
|
72
|
-
rows.map((row) => ({
|
|
73
|
-
name: row.name,
|
|
74
|
-
reportName: row.report_name || row.name,
|
|
75
|
-
json: row.json,
|
|
76
|
-
})),
|
|
77
|
-
);
|
|
78
|
-
setLoading(false);
|
|
79
|
-
})
|
|
80
|
-
.catch(() => {
|
|
81
|
-
// Report doctype may be unreadable for restricted roles — the
|
|
82
|
-
// selector then simply offers no saved reports.
|
|
83
|
-
if (cancelled) return;
|
|
84
|
-
setReports([]);
|
|
85
|
-
setLoading(false);
|
|
86
|
-
});
|
|
87
|
-
return () => {
|
|
88
|
-
cancelled = true;
|
|
89
|
-
};
|
|
90
|
-
}, [app, fixtureMode, doctype, generation]);
|
|
91
|
-
|
|
92
|
-
const load = useCallback(
|
|
93
|
-
async (name: string): Promise<ReportViewConfig | undefined> => {
|
|
94
|
-
if (fixtureMode) return memoryConfigs.current.get(name);
|
|
95
|
-
const summary = reports.find((report) => report.name === name);
|
|
96
|
-
let json = summary?.json;
|
|
97
|
-
if (json === undefined && app) {
|
|
98
|
-
const res = await app
|
|
99
|
-
.call()
|
|
100
|
-
.get<{ message?: { json?: string } }>("frappe.client.get_value", {
|
|
101
|
-
doctype: "Report",
|
|
102
|
-
filters: JSON.stringify({ name }),
|
|
103
|
-
fieldname: JSON.stringify(["json"]),
|
|
104
|
-
});
|
|
105
|
-
json = res.payload?.message?.json;
|
|
106
|
-
}
|
|
107
|
-
if (!json) return undefined;
|
|
108
|
-
try {
|
|
109
|
-
return fromDeskReportSettings(doctype, JSON.parse(json));
|
|
110
|
-
} catch {
|
|
111
|
-
return undefined;
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
[app, fixtureMode, reports, doctype],
|
|
115
|
-
);
|
|
116
|
-
|
|
117
|
-
const save = useCallback(
|
|
118
|
-
async (name: string, viewConfig: ReportViewConfig): Promise<string> => {
|
|
119
|
-
const trimmed = name.trim();
|
|
120
|
-
if (!trimmed) throw new Error("Report name is required");
|
|
121
|
-
if (fixtureMode || !app) {
|
|
122
|
-
memoryConfigs.current.set(trimmed, viewConfig);
|
|
123
|
-
setReports((previous) => [
|
|
124
|
-
...previous.filter((report) => report.name !== trimmed),
|
|
125
|
-
{ name: trimmed, reportName: trimmed },
|
|
126
|
-
]);
|
|
127
|
-
return trimmed;
|
|
128
|
-
}
|
|
129
|
-
const res = await app
|
|
130
|
-
.call()
|
|
131
|
-
.post<{ message?: string }>("frappe.desk.reportview.save_report", {
|
|
132
|
-
name: trimmed,
|
|
133
|
-
doctype,
|
|
134
|
-
report_settings: JSON.stringify(toDeskReportSettings(doctype, viewConfig)),
|
|
135
|
-
});
|
|
136
|
-
setGeneration((value) => value + 1);
|
|
137
|
-
return res.payload?.message ?? trimmed;
|
|
138
|
-
},
|
|
139
|
-
[app, fixtureMode, doctype],
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
const remove = useCallback(
|
|
143
|
-
async (name: string): Promise<void> => {
|
|
144
|
-
if (fixtureMode || !app) {
|
|
145
|
-
memoryConfigs.current.delete(name);
|
|
146
|
-
setReports((previous) => previous.filter((report) => report.name !== name));
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
await app.call().post("frappe.desk.reportview.delete_report", { name });
|
|
150
|
-
setGeneration((value) => value + 1);
|
|
151
|
-
},
|
|
152
|
-
[app, fixtureMode, doctype],
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
const refresh = useCallback(() => setGeneration((value) => value + 1), []);
|
|
156
|
-
|
|
157
|
-
return useMemo(
|
|
158
|
-
() => ({ reports, loading, load, save, remove, refresh }),
|
|
159
|
-
[reports, loading, load, save, remove, refresh],
|
|
160
|
-
);
|
|
161
|
-
}
|
|
1
|
+
// Saved reports live in @multiplatform.one/frappe-ui (MPO-15, GL-28); this
|
|
2
|
+
// path keeps handing out the same names.
|
|
3
|
+
export { useSavedReports } from "@multiplatform.one/frappe-ui";
|
|
4
|
+
export type { SavedReportSummary, UseSavedReportsResult } from "@multiplatform.one/frappe-ui";
|
|
@@ -1,47 +1,6 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
// (frappe.desk.query_report.get_script) and runs
|
|
5
|
-
// frappe.desk.query_report.run. Wire-shape normalization (and the probed
|
|
6
|
-
// response documentation) lives in reportShapes.ts; this file owns
|
|
7
|
-
// fetch/state.
|
|
8
|
-
//
|
|
9
|
-
// GET /api/method/frappe.client.get {doctype:"Report", name}
|
|
10
|
-
// → {message: {report_name, ref_doctype, report_type, disabled,
|
|
11
|
-
// prepared_report, add_total_row, filters: [...], ...}}
|
|
12
|
-
// GET /api/method/frappe.desk.query_report.get_script {report_name}
|
|
13
|
-
// → {message: {script, html_format, execution_time, filters}}
|
|
14
|
-
//
|
|
15
|
-
// Filter meta sources (desk precedence, query_report.js setup): the script
|
|
16
|
-
// module's declarative `filters` win when the script declares any; the
|
|
17
|
-
// Report doc `filters` child table applies only when it doesn't. Script
|
|
18
|
-
// filters are extracted from the raw JS text without eval
|
|
19
|
-
// (reportShapes.extractScriptFilters) — entries beyond the declarative
|
|
20
|
-
// subset (get_query functions, dynamic defaults, desk-only fieldtypes)
|
|
21
|
-
// surface as `scriptFilterGap` so the screen can render an honest note.
|
|
22
|
-
// `ignore_prepared_report` forces a synchronous run for prepared reports
|
|
23
|
-
// (desk's background Prepared Report queue is out of scope here).
|
|
24
|
-
import type { FrappeApp } from "@multiplatform.one/frappe";
|
|
25
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
26
|
-
import { useFrappeApp } from "../shared/useFrappeApp";
|
|
27
|
-
import {
|
|
28
|
-
type QueryReportColumn,
|
|
29
|
-
type QueryReportFilterMeta,
|
|
30
|
-
type QueryReportFilters,
|
|
31
|
-
type QueryReportFixture,
|
|
32
|
-
type QueryReportMeta,
|
|
33
|
-
type QueryReportRow,
|
|
34
|
-
type QueryReportRunMessage,
|
|
35
|
-
buildRunFilters,
|
|
36
|
-
defaultFilterValues,
|
|
37
|
-
extractScriptFilters,
|
|
38
|
-
humanizeFrappeError,
|
|
39
|
-
isEmptyFilterValue,
|
|
40
|
-
normalizeFilterMeta,
|
|
41
|
-
normalizeQueryReportColumns,
|
|
42
|
-
normalizeQueryReportRows,
|
|
43
|
-
} from "./reportShapes";
|
|
44
|
-
|
|
1
|
+
// The query-report hook lives in @multiplatform.one/frappe-ui (MPO-15,
|
|
2
|
+
// GL-28), on the same transport as FrappeReportView; this path keeps
|
|
3
|
+
// handing out the same names, the model's included.
|
|
45
4
|
export {
|
|
46
5
|
buildRunFilters,
|
|
47
6
|
compactQueryReportFilters,
|
|
@@ -51,8 +10,9 @@ export {
|
|
|
51
10
|
normalizeQueryReportColumns,
|
|
52
11
|
normalizeQueryReportRows,
|
|
53
12
|
scrubFieldname,
|
|
54
|
-
stripHtml,
|
|
55
|
-
|
|
13
|
+
stripReportHtml as stripHtml,
|
|
14
|
+
useQueryReport,
|
|
15
|
+
} from "@multiplatform.one/frappe-ui";
|
|
56
16
|
export type {
|
|
57
17
|
QueryReportColumn,
|
|
58
18
|
QueryReportFilterMeta,
|
|
@@ -61,304 +21,6 @@ export type {
|
|
|
61
21
|
QueryReportMeta,
|
|
62
22
|
QueryReportRow,
|
|
63
23
|
ScriptFilterExtraction,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const SCRIPT_METHOD = "frappe.desk.query_report.get_script";
|
|
68
|
-
|
|
69
|
-
export interface UseQueryReportOptions {
|
|
70
|
-
fixture?: QueryReportFixture;
|
|
71
|
-
/** Filter values applied before the first run (report swaps re-apply them). */
|
|
72
|
-
initialFilters?: QueryReportFilters;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export interface UseQueryReportResult {
|
|
76
|
-
meta?: QueryReportMeta;
|
|
77
|
-
columns: QueryReportColumn[];
|
|
78
|
-
rows: QueryReportRow[];
|
|
79
|
-
/** True until the first meta+script+run cycle settles. */
|
|
80
|
-
loading: boolean;
|
|
81
|
-
/** True while a (re)run is in flight. */
|
|
82
|
-
running: boolean;
|
|
83
|
-
error?: Error;
|
|
84
|
-
/** The report's informational `message` payload (may embed HTML). */
|
|
85
|
-
serverMessage?: string;
|
|
86
|
-
/** Server-reported run time in seconds. */
|
|
87
|
-
executionTime?: number;
|
|
88
|
-
/** Merged filter meta: script-declared filters, else doc-level rows. */
|
|
89
|
-
filterMeta: QueryReportFilterMeta[];
|
|
90
|
-
/**
|
|
91
|
-
* True when the desk script declares filters this surface could not
|
|
92
|
-
* derive (non-declarative entries) — the honest "defined in code" note.
|
|
93
|
-
*/
|
|
94
|
-
scriptFilterGap: boolean;
|
|
95
|
-
/** Mandatory filters currently unfilled — the run is skipped while non-empty. */
|
|
96
|
-
missingRequired: QueryReportFilterMeta[];
|
|
97
|
-
filters: QueryReportFilters;
|
|
98
|
-
setFilters: (next: QueryReportFilters) => void;
|
|
99
|
-
reload: () => void;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
async function fetchReportMeta(app: FrappeApp, reportName: string): Promise<QueryReportMeta> {
|
|
103
|
-
const res = await app.call().get<{ message?: QueryReportMeta }>("frappe.client.get", {
|
|
104
|
-
doctype: "Report",
|
|
105
|
-
name: reportName,
|
|
106
|
-
});
|
|
107
|
-
const doc = res.payload?.message;
|
|
108
|
-
if (!doc) throw new Error(`Report "${reportName}" not found`);
|
|
109
|
-
return doc;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
async function fetchReportScript(app: FrappeApp, reportName: string): Promise<string | undefined> {
|
|
113
|
-
const res = await app.call().get<{ message?: { script?: string | null } }>(SCRIPT_METHOD, {
|
|
114
|
-
report_name: reportName,
|
|
115
|
-
});
|
|
116
|
-
const script = res.payload?.message?.script;
|
|
117
|
-
return typeof script === "string" ? script : undefined;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
export function useQueryReport(
|
|
121
|
-
reportName: string,
|
|
122
|
-
options: UseQueryReportOptions = {},
|
|
123
|
-
): UseQueryReportResult {
|
|
124
|
-
const { fixture } = options;
|
|
125
|
-
const app = useFrappeApp();
|
|
126
|
-
|
|
127
|
-
// Latest initialFilters without re-running effects on identity churn.
|
|
128
|
-
const initialFiltersRef = useRef(options.initialFilters);
|
|
129
|
-
initialFiltersRef.current = options.initialFilters;
|
|
130
|
-
|
|
131
|
-
const [meta, setMeta] = useState<QueryReportMeta | undefined>(undefined);
|
|
132
|
-
const [script, setScript] = useState<string | undefined>(undefined);
|
|
133
|
-
const [sourcesSettled, setSourcesSettled] = useState(false);
|
|
134
|
-
const [filters, setFiltersState] = useState<QueryReportFilters>(() => ({
|
|
135
|
-
...initialFiltersRef.current,
|
|
136
|
-
}));
|
|
137
|
-
const [columns, setColumns] = useState<QueryReportColumn[]>([]);
|
|
138
|
-
const [rows, setRows] = useState<QueryReportRow[]>([]);
|
|
139
|
-
const [loading, setLoading] = useState(true);
|
|
140
|
-
const [running, setRunning] = useState(false);
|
|
141
|
-
const [error, setError] = useState<Error | undefined>(undefined);
|
|
142
|
-
const [serverMessage, setServerMessage] = useState<string | undefined>(undefined);
|
|
143
|
-
const [executionTime, setExecutionTime] = useState<number | undefined>(undefined);
|
|
144
|
-
const [generation, setGeneration] = useState(0);
|
|
145
|
-
const seededFor = useRef<string | undefined>(undefined);
|
|
146
|
-
|
|
147
|
-
// The route component is reused across query-report navigations — a
|
|
148
|
-
// report swap resets filters and shows the loading state again.
|
|
149
|
-
const lastReport = useRef(reportName);
|
|
150
|
-
useEffect(() => {
|
|
151
|
-
if (lastReport.current === reportName) return;
|
|
152
|
-
lastReport.current = reportName;
|
|
153
|
-
setFiltersState({ ...initialFiltersRef.current });
|
|
154
|
-
setMeta(undefined);
|
|
155
|
-
setScript(undefined);
|
|
156
|
-
setSourcesSettled(false);
|
|
157
|
-
setColumns([]);
|
|
158
|
-
setRows([]);
|
|
159
|
-
setError(undefined);
|
|
160
|
-
setServerMessage(undefined);
|
|
161
|
-
setExecutionTime(undefined);
|
|
162
|
-
setLoading(true);
|
|
163
|
-
}, [reportName]);
|
|
164
|
-
|
|
165
|
-
// Report doc meta (title, ref_doctype, doc filters) + the desk script
|
|
166
|
-
// module, fetched together. Both are non-fatal niceties — the run below
|
|
167
|
-
// reports the real errors — but the run waits for them so declared
|
|
168
|
-
// defaults are seeded into the FIRST run (desk parity).
|
|
169
|
-
useEffect(() => {
|
|
170
|
-
if (fixture) return;
|
|
171
|
-
if (!app) {
|
|
172
|
-
setSourcesSettled(true);
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
let cancelled = false;
|
|
176
|
-
setSourcesSettled(false);
|
|
177
|
-
Promise.allSettled([fetchReportMeta(app, reportName), fetchReportScript(app, reportName)]).then(
|
|
178
|
-
([metaResult, scriptResult]) => {
|
|
179
|
-
if (cancelled) return;
|
|
180
|
-
const doc = metaResult.status === "fulfilled" ? metaResult.value : undefined;
|
|
181
|
-
const scriptText = scriptResult.status === "fulfilled" ? scriptResult.value : undefined;
|
|
182
|
-
if (doc) setMeta(doc);
|
|
183
|
-
if (scriptText) setScript(scriptText);
|
|
184
|
-
// Seed filter defaults once per report; user edits (and deep-link
|
|
185
|
-
// initialFilters, already in state) win over defaults.
|
|
186
|
-
if (seededFor.current !== reportName) {
|
|
187
|
-
seededFor.current = reportName;
|
|
188
|
-
const extraction = extractScriptFilters(scriptText);
|
|
189
|
-
const merged = extraction.declared
|
|
190
|
-
? extraction.filters
|
|
191
|
-
: normalizeFilterMeta(doc?.filters);
|
|
192
|
-
const defaults = defaultFilterValues(merged);
|
|
193
|
-
if (Object.keys(defaults).length > 0)
|
|
194
|
-
setFiltersState((previous) => ({ ...defaults, ...previous }));
|
|
195
|
-
}
|
|
196
|
-
setSourcesSettled(true);
|
|
197
|
-
},
|
|
198
|
-
);
|
|
199
|
-
return () => {
|
|
200
|
-
cancelled = true;
|
|
201
|
-
};
|
|
202
|
-
}, [app, fixture, reportName]);
|
|
203
|
-
|
|
204
|
-
const scriptExtraction = useMemo(
|
|
205
|
-
() => extractScriptFilters(fixture ? fixture.script : script),
|
|
206
|
-
[fixture, script],
|
|
207
|
-
);
|
|
208
|
-
const docFilterMeta = useMemo(
|
|
209
|
-
() => normalizeFilterMeta(fixture ? fixture.meta?.filters : meta?.filters),
|
|
210
|
-
[fixture, meta],
|
|
211
|
-
);
|
|
212
|
-
// Desk precedence (query_report.js): the script module's filters apply
|
|
213
|
-
// when the script declares the key at all; doc rows only otherwise.
|
|
214
|
-
const filterMeta = useMemo(
|
|
215
|
-
() => (scriptExtraction.declared ? scriptExtraction.filters : docFilterMeta),
|
|
216
|
-
[scriptExtraction, docFilterMeta],
|
|
217
|
-
);
|
|
218
|
-
const scriptFilterGap = scriptExtraction.declaredCount > scriptExtraction.filters.length;
|
|
219
|
-
|
|
220
|
-
// Fixture branch seeds defaults too (no fetch effect runs for fixtures).
|
|
221
|
-
useEffect(() => {
|
|
222
|
-
if (!fixture) return;
|
|
223
|
-
if (seededFor.current === reportName) return;
|
|
224
|
-
seededFor.current = reportName;
|
|
225
|
-
const defaults = defaultFilterValues(filterMeta);
|
|
226
|
-
if (Object.keys(defaults).length > 0)
|
|
227
|
-
setFiltersState((previous) => ({ ...defaults, ...previous }));
|
|
228
|
-
}, [fixture, reportName, filterMeta]);
|
|
229
|
-
|
|
230
|
-
// Desk parity: defaults SEED the controls (state) once; after that the
|
|
231
|
-
// gate reads the live values only — clearing a defaulted mandatory filter
|
|
232
|
-
// re-gates instead of firing a doomed run (desk's get_filter_values reads
|
|
233
|
-
// control values, not declarations).
|
|
234
|
-
const missingRequired = useMemo(
|
|
235
|
-
() =>
|
|
236
|
-
filterMeta.filter(
|
|
237
|
-
(filter) => filter.mandatory === 1 && isEmptyFilterValue(filters[filter.fieldname]),
|
|
238
|
-
),
|
|
239
|
-
[filterMeta, filters],
|
|
240
|
-
);
|
|
241
|
-
const hasMissingRequired = missingRequired.length > 0;
|
|
242
|
-
const metaDisabled = (fixture ? fixture.meta?.disabled : meta?.disabled) === 1;
|
|
243
|
-
|
|
244
|
-
useEffect(() => {
|
|
245
|
-
if (fixture) return;
|
|
246
|
-
if (!sourcesSettled) return;
|
|
247
|
-
if (metaDisabled) {
|
|
248
|
-
setLoading(false);
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
if (hasMissingRequired) {
|
|
252
|
-
setColumns([]);
|
|
253
|
-
setRows([]);
|
|
254
|
-
setError(undefined);
|
|
255
|
-
setLoading(false);
|
|
256
|
-
return;
|
|
257
|
-
}
|
|
258
|
-
if (!app) {
|
|
259
|
-
setError(new Error("No Frappe connection configured"));
|
|
260
|
-
setLoading(false);
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
let cancelled = false;
|
|
264
|
-
setRunning(true);
|
|
265
|
-
app
|
|
266
|
-
.call()
|
|
267
|
-
.post<{ message?: QueryReportRunMessage }>(RUN_METHOD, {
|
|
268
|
-
report_name: reportName,
|
|
269
|
-
filters: buildRunFilters(filterMeta, filters),
|
|
270
|
-
ignore_prepared_report: 1,
|
|
271
|
-
})
|
|
272
|
-
.then((res) => {
|
|
273
|
-
if (cancelled) return;
|
|
274
|
-
const message = res.payload?.message;
|
|
275
|
-
const nextColumns = normalizeQueryReportColumns(message?.columns);
|
|
276
|
-
setColumns(nextColumns);
|
|
277
|
-
setRows(normalizeQueryReportRows(message?.result, nextColumns));
|
|
278
|
-
setServerMessage(typeof message?.message === "string" ? message.message : undefined);
|
|
279
|
-
setExecutionTime(
|
|
280
|
-
typeof message?.execution_time === "number" ? message.execution_time : undefined,
|
|
281
|
-
);
|
|
282
|
-
setError(undefined);
|
|
283
|
-
})
|
|
284
|
-
.catch((err) => {
|
|
285
|
-
if (cancelled) return;
|
|
286
|
-
setColumns([]);
|
|
287
|
-
setRows([]);
|
|
288
|
-
setError(humanizeFrappeError(err));
|
|
289
|
-
})
|
|
290
|
-
.finally(() => {
|
|
291
|
-
if (cancelled) return;
|
|
292
|
-
setRunning(false);
|
|
293
|
-
setLoading(false);
|
|
294
|
-
});
|
|
295
|
-
return () => {
|
|
296
|
-
cancelled = true;
|
|
297
|
-
};
|
|
298
|
-
}, [
|
|
299
|
-
app,
|
|
300
|
-
fixture,
|
|
301
|
-
reportName,
|
|
302
|
-
filters,
|
|
303
|
-
filterMeta,
|
|
304
|
-
generation,
|
|
305
|
-
sourcesSettled,
|
|
306
|
-
metaDisabled,
|
|
307
|
-
hasMissingRequired,
|
|
308
|
-
]);
|
|
309
|
-
|
|
310
|
-
const setFilters = useCallback((next: QueryReportFilters) => {
|
|
311
|
-
setFiltersState(next);
|
|
312
|
-
}, []);
|
|
313
|
-
|
|
314
|
-
const reload = useCallback(() => {
|
|
315
|
-
setGeneration((previous) => previous + 1);
|
|
316
|
-
}, []);
|
|
317
|
-
|
|
318
|
-
// Fixture branch: static data, no RPCs (stories/tests).
|
|
319
|
-
const fixtureResult = useMemo(() => {
|
|
320
|
-
if (!fixture) return undefined;
|
|
321
|
-
const fixtureColumns = normalizeQueryReportColumns(fixture.columns);
|
|
322
|
-
return {
|
|
323
|
-
columns: fixtureColumns,
|
|
324
|
-
rows: normalizeQueryReportRows(fixture.rows, fixtureColumns),
|
|
325
|
-
meta: fixture.meta ? ({ name: reportName, ...fixture.meta } as QueryReportMeta) : undefined,
|
|
326
|
-
};
|
|
327
|
-
}, [fixture, reportName]);
|
|
328
|
-
|
|
329
|
-
if (fixtureResult) {
|
|
330
|
-
return {
|
|
331
|
-
meta: fixtureResult.meta,
|
|
332
|
-
columns: fixtureResult.columns,
|
|
333
|
-
rows: hasMissingRequired ? [] : fixtureResult.rows,
|
|
334
|
-
loading: false,
|
|
335
|
-
running: false,
|
|
336
|
-
error: undefined,
|
|
337
|
-
serverMessage: fixture?.message,
|
|
338
|
-
executionTime: undefined,
|
|
339
|
-
filterMeta,
|
|
340
|
-
scriptFilterGap,
|
|
341
|
-
missingRequired,
|
|
342
|
-
filters,
|
|
343
|
-
setFilters,
|
|
344
|
-
reload,
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
return {
|
|
349
|
-
meta,
|
|
350
|
-
columns,
|
|
351
|
-
rows,
|
|
352
|
-
loading,
|
|
353
|
-
running,
|
|
354
|
-
error,
|
|
355
|
-
serverMessage,
|
|
356
|
-
executionTime,
|
|
357
|
-
filterMeta,
|
|
358
|
-
scriptFilterGap,
|
|
359
|
-
missingRequired,
|
|
360
|
-
filters,
|
|
361
|
-
setFilters,
|
|
362
|
-
reload,
|
|
363
|
-
};
|
|
364
|
-
}
|
|
24
|
+
UseQueryReportOptions,
|
|
25
|
+
UseQueryReportResult,
|
|
26
|
+
} from "@multiplatform.one/frappe-ui";
|
package/src/shared/measures.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export
|
|
4
|
-
280,
|
|
5
|
-
"dialog body floor: a reading width for the form inside a dialog or popover",
|
|
6
|
-
);
|
|
7
|
-
|
|
8
|
-
export const overlayListMaxHeight = sizeRecipeEscape(
|
|
9
|
-
360,
|
|
10
|
-
"overlay list cap: a menu or popover list scrolls past this height instead of growing",
|
|
11
|
-
);
|
|
1
|
+
// The overlay measures live in @multiplatform.one/frappe-ui beside the report
|
|
2
|
+
// toolbar that moved there (MPO-15, GL-28); this path keeps handing them out.
|
|
3
|
+
export { dialogBodyMinWidth, overlayListMaxHeight } from "@multiplatform.one/frappe-ui";
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// The compatibility report view (MPO-414), still exported beside
|
|
2
|
-
// DoctypeReportView
|
|
3
|
-
//
|
|
4
|
-
//
|
|
2
|
+
// DoctypeReportView. Since MPO-15 (GL-28) it is that view under its old name,
|
|
3
|
+
// FrappeReportBuilder under the desk's navigation: it totals the filtered
|
|
4
|
+
// result, opens a record from the grid, applies and clears the ?f= base
|
|
5
|
+
// filters, and ANDs the desk scope into its queries (GL-5).
|
|
5
6
|
import React from "react";
|
|
6
7
|
import { InMemoryFixtureProvider } from "@multiplatform.one/frappe";
|
|
7
8
|
import { renderWithProviders } from "@multiplatform.one/test-utils";
|
|
@@ -66,25 +67,29 @@ function renderReport(filtersParam?: string, scope?: FrappeFilters): MemoryNavig
|
|
|
66
67
|
return navigation;
|
|
67
68
|
}
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
function rowNames(): string[] {
|
|
71
|
+
return Array.from(
|
|
72
|
+
document.querySelectorAll('[data-report-row="true"]'),
|
|
73
|
+
(row) => row.getAttribute("aria-label") ?? "",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function rowsAre(names: string[]) {
|
|
78
|
+
await waitFor(() => expect(rowNames().sort()).toEqual([...names].sort()), { timeout: 5000 });
|
|
71
79
|
}
|
|
72
80
|
|
|
73
81
|
describe("<ReportView />", () => {
|
|
74
|
-
it("
|
|
82
|
+
it("is the desk report view, totals row included", async () => {
|
|
75
83
|
renderReport();
|
|
76
|
-
await
|
|
77
|
-
const
|
|
78
|
-
|
|
79
|
-
.map((label) => label.parentElement?.textContent ?? "");
|
|
80
|
-
expect(strips.some((text) => text.includes("Amount: 123"))).toBe(true);
|
|
84
|
+
await rowsAre(["QLO-0001", "QLO-0002", "QLO-0003"]);
|
|
85
|
+
const totals = screen.getByText("Totals").closest("[role=row]") ?? screen.getByText("Totals");
|
|
86
|
+
expect(totals.parentElement?.textContent ?? totals.textContent).toContain("123");
|
|
81
87
|
});
|
|
82
88
|
|
|
83
|
-
it("opens a record from the
|
|
89
|
+
it("opens a record from the grid", async () => {
|
|
84
90
|
const navigation = renderReport();
|
|
85
|
-
await
|
|
86
|
-
fireEvent.click(screen.
|
|
87
|
-
fireEvent.click(await screen.findByText("Globex", { selector: "[role=menuitem] *" }));
|
|
91
|
+
await rowsAre(["QLO-0001", "QLO-0002", "QLO-0003"]);
|
|
92
|
+
fireEvent.click(screen.getByText("Globex"));
|
|
88
93
|
await waitFor(() =>
|
|
89
94
|
expect(navigation.getLocation().path).toBe("/backoffice/qalegacyorder/QLO-0002"),
|
|
90
95
|
);
|
|
@@ -92,17 +97,17 @@ describe("<ReportView />", () => {
|
|
|
92
97
|
|
|
93
98
|
it("applies the ?f= base filters and drops them from the address on clear", async () => {
|
|
94
99
|
const navigation = renderReport(encodeURIComponent(JSON.stringify([["status", "=", "Draft"]])));
|
|
95
|
-
await
|
|
100
|
+
await rowsAre(["QLO-0002", "QLO-0003"]);
|
|
96
101
|
fireEvent.click(screen.getByRole("button", { name: "Clear filters" }));
|
|
97
|
-
await
|
|
102
|
+
await rowsAre(["QLO-0001", "QLO-0002", "QLO-0003"]);
|
|
98
103
|
expect(navigation.getLocation().path).toBe("/backoffice/qalegacyorder/view/report");
|
|
99
104
|
});
|
|
100
105
|
|
|
101
|
-
it("ANDs the desk scope into the
|
|
106
|
+
it("ANDs the desk scope into the grid, with nothing to clear", async () => {
|
|
102
107
|
renderReport(undefined, [["status", "=", "Paid"]]);
|
|
103
|
-
await
|
|
108
|
+
await rowsAre(["QLO-0001"]);
|
|
104
109
|
expect(screen.queryByRole("button", { name: "Clear filters" })).toBeNull();
|
|
105
|
-
|
|
110
|
+
expect(screen.queryByText("Globex")).toBeNull();
|
|
106
111
|
expect(screen.getAllByText("ACME Corp").length).toBeGreaterThan(0);
|
|
107
112
|
});
|
|
108
113
|
});
|