@multiplatform.one/frappe-ui 7.67.0 → 7.69.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/FileBrowser/index.cjs +15 -25
- package/dist/cjs/FileBrowser/index.native.js +15 -25
- package/dist/cjs/FileBrowser/index.native.js.map +1 -1
- package/dist/cjs/FormSidebar.cjs +37 -22
- package/dist/cjs/FormSidebar.native.js +41 -24
- package/dist/cjs/FormSidebar.native.js.map +1 -1
- package/dist/cjs/FrappeAssignment.cjs +0 -3
- package/dist/cjs/FrappeAssignment.native.js +0 -3
- package/dist/cjs/FrappeAssignment.native.js.map +1 -1
- package/dist/cjs/FrappeDashboard.cjs +0 -2
- package/dist/cjs/FrappeDashboard.native.js +0 -2
- package/dist/cjs/FrappeDashboard.native.js.map +1 -1
- package/dist/cjs/FrappeForm.cjs +6 -5
- package/dist/cjs/FrappeForm.native.js +6 -5
- package/dist/cjs/FrappeForm.native.js.map +1 -1
- package/dist/cjs/FrappeFormActions.cjs +20 -30
- package/dist/cjs/FrappeFormActions.native.js +23 -31
- package/dist/cjs/FrappeFormActions.native.js.map +1 -1
- package/dist/cjs/FrappeKanban.cjs +0 -1
- package/dist/cjs/FrappeKanban.native.js +0 -1
- package/dist/cjs/FrappeKanban.native.js.map +1 -1
- package/dist/cjs/FrappeLikedBy.cjs +1 -1
- package/dist/cjs/FrappeLikedBy.native.js +1 -1
- package/dist/cjs/FrappeLikedBy.native.js.map +1 -1
- package/dist/cjs/FrappeListView.cjs +0 -1
- package/dist/cjs/FrappeListView.native.js +0 -1
- package/dist/cjs/FrappeListView.native.js.map +1 -1
- package/dist/cjs/FrappeReportView.cjs +2 -4
- package/dist/cjs/FrappeReportView.native.js +2 -4
- package/dist/cjs/FrappeReportView.native.js.map +1 -1
- package/dist/cjs/desk/DeskShell.cjs +0 -1
- package/dist/cjs/desk/DeskShell.native.js +0 -1
- package/dist/cjs/desk/DeskShell.native.js.map +1 -1
- package/dist/cjs/fields/FileUpload.cjs +53 -58
- package/dist/cjs/fields/FileUpload.native.js +53 -56
- package/dist/cjs/fields/FileUpload.native.js.map +1 -1
- package/dist/cjs/list/ListControls.cjs +1 -3
- package/dist/cjs/list/ListControls.native.js +1 -3
- package/dist/cjs/list/ListControls.native.js.map +1 -1
- package/dist/cjs/list/ListControlsSheet.cjs +5 -15
- package/dist/cjs/list/ListControlsSheet.native.js +7 -17
- package/dist/cjs/list/ListControlsSheet.native.js.map +1 -1
- package/dist/cjs/list/ListSidebarToolbar.cjs +5 -20
- package/dist/cjs/list/ListSidebarToolbar.native.js +7 -22
- package/dist/cjs/list/ListSidebarToolbar.native.js.map +1 -1
- package/dist/cjs/list/RecordCard.cjs +2 -14
- package/dist/cjs/list/RecordCard.native.js +2 -10
- package/dist/cjs/list/RecordCard.native.js.map +1 -1
- package/dist/cjs/list/ShufflePanel.cjs +0 -2
- package/dist/cjs/list/ShufflePanel.native.js +0 -2
- package/dist/cjs/list/ShufflePanel.native.js.map +1 -1
- package/dist/cjs/list/listColumns.cjs +1 -1
- package/dist/cjs/list/listColumns.native.js +1 -1
- package/dist/cjs/list/listColumns.native.js.map +1 -1
- package/dist/cjs/record/RecordPage.cjs +4 -10
- package/dist/cjs/record/RecordPage.native.js +4 -10
- package/dist/cjs/record/RecordPage.native.js.map +1 -1
- package/dist/cjs/report/ReportViewToolbar.cjs +8 -10
- package/dist/cjs/report/ReportViewToolbar.native.js +8 -10
- package/dist/cjs/report/ReportViewToolbar.native.js.map +1 -1
- package/dist/esm/FileBrowser/index.mjs +16 -26
- package/dist/esm/FileBrowser/index.mjs.map +1 -1
- package/dist/esm/FileBrowser/index.native.js +16 -26
- package/dist/esm/FileBrowser/index.native.js.map +1 -1
- package/dist/esm/FormSidebar.mjs +41 -26
- package/dist/esm/FormSidebar.mjs.map +1 -1
- package/dist/esm/FormSidebar.native.js +45 -28
- package/dist/esm/FormSidebar.native.js.map +1 -1
- package/dist/esm/FrappeAssignment.mjs +0 -3
- package/dist/esm/FrappeAssignment.mjs.map +1 -1
- package/dist/esm/FrappeAssignment.native.js +0 -3
- package/dist/esm/FrappeAssignment.native.js.map +1 -1
- package/dist/esm/FrappeDashboard.mjs +0 -2
- package/dist/esm/FrappeDashboard.mjs.map +1 -1
- package/dist/esm/FrappeDashboard.native.js +0 -2
- package/dist/esm/FrappeDashboard.native.js.map +1 -1
- package/dist/esm/FrappeForm.mjs +7 -6
- package/dist/esm/FrappeForm.mjs.map +1 -1
- package/dist/esm/FrappeForm.native.js +7 -6
- package/dist/esm/FrappeForm.native.js.map +1 -1
- package/dist/esm/FrappeFormActions.mjs +22 -32
- package/dist/esm/FrappeFormActions.mjs.map +1 -1
- package/dist/esm/FrappeFormActions.native.js +25 -33
- package/dist/esm/FrappeFormActions.native.js.map +1 -1
- package/dist/esm/FrappeKanban.mjs +0 -1
- package/dist/esm/FrappeKanban.mjs.map +1 -1
- package/dist/esm/FrappeKanban.native.js +0 -1
- package/dist/esm/FrappeKanban.native.js.map +1 -1
- package/dist/esm/FrappeLikedBy.mjs +1 -1
- package/dist/esm/FrappeLikedBy.mjs.map +1 -1
- package/dist/esm/FrappeLikedBy.native.js +1 -1
- package/dist/esm/FrappeLikedBy.native.js.map +1 -1
- package/dist/esm/FrappeListView.mjs +0 -1
- package/dist/esm/FrappeListView.mjs.map +1 -1
- package/dist/esm/FrappeListView.native.js +0 -1
- package/dist/esm/FrappeListView.native.js.map +1 -1
- package/dist/esm/FrappeReportView.mjs +3 -5
- package/dist/esm/FrappeReportView.mjs.map +1 -1
- package/dist/esm/FrappeReportView.native.js +3 -5
- package/dist/esm/FrappeReportView.native.js.map +1 -1
- package/dist/esm/desk/DeskShell.mjs +0 -1
- package/dist/esm/desk/DeskShell.mjs.map +1 -1
- package/dist/esm/desk/DeskShell.native.js +0 -1
- package/dist/esm/desk/DeskShell.native.js.map +1 -1
- package/dist/esm/fields/FileUpload.mjs +57 -62
- package/dist/esm/fields/FileUpload.mjs.map +1 -1
- package/dist/esm/fields/FileUpload.native.js +57 -60
- package/dist/esm/fields/FileUpload.native.js.map +1 -1
- package/dist/esm/list/ListControls.mjs +1 -3
- package/dist/esm/list/ListControls.mjs.map +1 -1
- package/dist/esm/list/ListControls.native.js +1 -3
- package/dist/esm/list/ListControls.native.js.map +1 -1
- package/dist/esm/list/ListControlsSheet.mjs +6 -16
- package/dist/esm/list/ListControlsSheet.mjs.map +1 -1
- package/dist/esm/list/ListControlsSheet.native.js +8 -18
- package/dist/esm/list/ListControlsSheet.native.js.map +1 -1
- package/dist/esm/list/ListSidebarToolbar.mjs +6 -21
- package/dist/esm/list/ListSidebarToolbar.mjs.map +1 -1
- package/dist/esm/list/ListSidebarToolbar.native.js +8 -23
- package/dist/esm/list/ListSidebarToolbar.native.js.map +1 -1
- package/dist/esm/list/RecordCard.mjs +2 -14
- package/dist/esm/list/RecordCard.mjs.map +1 -1
- package/dist/esm/list/RecordCard.native.js +2 -10
- package/dist/esm/list/RecordCard.native.js.map +1 -1
- package/dist/esm/list/ShufflePanel.mjs +0 -2
- package/dist/esm/list/ShufflePanel.mjs.map +1 -1
- package/dist/esm/list/ShufflePanel.native.js +0 -2
- package/dist/esm/list/ShufflePanel.native.js.map +1 -1
- package/dist/esm/list/listColumns.mjs +1 -1
- package/dist/esm/list/listColumns.mjs.map +1 -1
- package/dist/esm/list/listColumns.native.js +1 -1
- package/dist/esm/list/listColumns.native.js.map +1 -1
- package/dist/esm/record/RecordPage.mjs +4 -10
- package/dist/esm/record/RecordPage.mjs.map +1 -1
- package/dist/esm/record/RecordPage.native.js +4 -10
- package/dist/esm/record/RecordPage.native.js.map +1 -1
- package/dist/esm/report/ReportViewToolbar.mjs +9 -11
- package/dist/esm/report/ReportViewToolbar.mjs.map +1 -1
- package/dist/esm/report/ReportViewToolbar.native.js +9 -11
- package/dist/esm/report/ReportViewToolbar.native.js.map +1 -1
- package/dist/jsx/FileBrowser/index.mjs +16 -26
- package/dist/jsx/FileBrowser/index.mjs.map +1 -1
- package/dist/jsx/FileBrowser/index.native.js +15 -25
- package/dist/jsx/FileBrowser/index.native.js.map +1 -1
- package/dist/jsx/FormSidebar.mjs +41 -26
- package/dist/jsx/FormSidebar.mjs.map +1 -1
- package/dist/jsx/FormSidebar.native.js +41 -24
- package/dist/jsx/FormSidebar.native.js.map +1 -1
- package/dist/jsx/FrappeAssignment.mjs +0 -3
- package/dist/jsx/FrappeAssignment.mjs.map +1 -1
- package/dist/jsx/FrappeAssignment.native.js +0 -3
- package/dist/jsx/FrappeAssignment.native.js.map +1 -1
- package/dist/jsx/FrappeDashboard.mjs +0 -2
- package/dist/jsx/FrappeDashboard.mjs.map +1 -1
- package/dist/jsx/FrappeDashboard.native.js +0 -2
- package/dist/jsx/FrappeDashboard.native.js.map +1 -1
- package/dist/jsx/FrappeForm.mjs +7 -6
- package/dist/jsx/FrappeForm.mjs.map +1 -1
- package/dist/jsx/FrappeForm.native.js +6 -5
- package/dist/jsx/FrappeForm.native.js.map +1 -1
- package/dist/jsx/FrappeFormActions.mjs +22 -32
- package/dist/jsx/FrappeFormActions.mjs.map +1 -1
- package/dist/jsx/FrappeFormActions.native.js +23 -31
- package/dist/jsx/FrappeFormActions.native.js.map +1 -1
- package/dist/jsx/FrappeKanban.mjs +0 -1
- package/dist/jsx/FrappeKanban.mjs.map +1 -1
- package/dist/jsx/FrappeKanban.native.js +0 -1
- package/dist/jsx/FrappeKanban.native.js.map +1 -1
- package/dist/jsx/FrappeLikedBy.mjs +1 -1
- package/dist/jsx/FrappeLikedBy.mjs.map +1 -1
- package/dist/jsx/FrappeLikedBy.native.js +1 -1
- package/dist/jsx/FrappeLikedBy.native.js.map +1 -1
- package/dist/jsx/FrappeListView.mjs +0 -1
- package/dist/jsx/FrappeListView.mjs.map +1 -1
- package/dist/jsx/FrappeListView.native.js +0 -1
- package/dist/jsx/FrappeListView.native.js.map +1 -1
- package/dist/jsx/FrappeReportView.mjs +3 -5
- package/dist/jsx/FrappeReportView.mjs.map +1 -1
- package/dist/jsx/FrappeReportView.native.js +2 -4
- package/dist/jsx/FrappeReportView.native.js.map +1 -1
- package/dist/jsx/desk/DeskShell.mjs +0 -1
- package/dist/jsx/desk/DeskShell.mjs.map +1 -1
- package/dist/jsx/desk/DeskShell.native.js +0 -1
- package/dist/jsx/desk/DeskShell.native.js.map +1 -1
- package/dist/jsx/fields/FileUpload.mjs +57 -62
- package/dist/jsx/fields/FileUpload.mjs.map +1 -1
- package/dist/jsx/fields/FileUpload.native.js +53 -56
- package/dist/jsx/fields/FileUpload.native.js.map +1 -1
- package/dist/jsx/list/ListControls.mjs +1 -3
- package/dist/jsx/list/ListControls.mjs.map +1 -1
- package/dist/jsx/list/ListControls.native.js +1 -3
- package/dist/jsx/list/ListControls.native.js.map +1 -1
- package/dist/jsx/list/ListControlsSheet.mjs +6 -16
- package/dist/jsx/list/ListControlsSheet.mjs.map +1 -1
- package/dist/jsx/list/ListControlsSheet.native.js +7 -17
- package/dist/jsx/list/ListControlsSheet.native.js.map +1 -1
- package/dist/jsx/list/ListSidebarToolbar.mjs +6 -21
- package/dist/jsx/list/ListSidebarToolbar.mjs.map +1 -1
- package/dist/jsx/list/ListSidebarToolbar.native.js +7 -22
- package/dist/jsx/list/ListSidebarToolbar.native.js.map +1 -1
- package/dist/jsx/list/RecordCard.mjs +2 -14
- package/dist/jsx/list/RecordCard.mjs.map +1 -1
- package/dist/jsx/list/RecordCard.native.js +2 -10
- package/dist/jsx/list/RecordCard.native.js.map +1 -1
- package/dist/jsx/list/ShufflePanel.mjs +0 -2
- package/dist/jsx/list/ShufflePanel.mjs.map +1 -1
- package/dist/jsx/list/ShufflePanel.native.js +0 -2
- package/dist/jsx/list/ShufflePanel.native.js.map +1 -1
- package/dist/jsx/list/listColumns.mjs +1 -1
- package/dist/jsx/list/listColumns.mjs.map +1 -1
- package/dist/jsx/list/listColumns.native.js +1 -1
- package/dist/jsx/list/listColumns.native.js.map +1 -1
- package/dist/jsx/record/RecordPage.mjs +4 -10
- package/dist/jsx/record/RecordPage.mjs.map +1 -1
- package/dist/jsx/record/RecordPage.native.js +4 -10
- package/dist/jsx/record/RecordPage.native.js.map +1 -1
- package/dist/jsx/report/ReportViewToolbar.mjs +9 -11
- package/dist/jsx/report/ReportViewToolbar.mjs.map +1 -1
- package/dist/jsx/report/ReportViewToolbar.native.js +8 -10
- package/dist/jsx/report/ReportViewToolbar.native.js.map +1 -1
- package/package.json +16 -16
- package/src/FileBrowser/index.tsx +11 -15
- package/src/FormSidebar.tsx +53 -33
- package/src/FrappeAssignment.tsx +0 -3
- package/src/FrappeDashboard.spec.tsx +7 -3
- package/src/FrappeDashboard.tsx +0 -2
- package/src/FrappeForm.connections.spec.tsx +2 -2
- package/src/FrappeForm.deskSemantics.spec.tsx +2 -2
- package/src/FrappeForm.lifecycle.spec.tsx +27 -27
- package/src/FrappeForm.tsx +11 -7
- package/src/FrappeFormActions.tsx +24 -38
- package/src/FrappeKanban.tsx +0 -1
- package/src/FrappeLikedBy.tsx +1 -1
- package/src/FrappeListView.spec.tsx +7 -3
- package/src/FrappeListView.tsx +0 -1
- package/src/FrappeReportView.tsx +3 -6
- package/src/desk/DeskShell.tsx +0 -1
- package/src/desk/deskDocumentRoutes.spec.tsx +7 -4
- package/src/fields/Date/typeParity.spec.tsx +6 -4
- package/src/fields/FileUpload.spec.tsx +20 -3
- package/src/fields/FileUpload.tsx +65 -69
- package/src/list/ListControls.tsx +1 -3
- package/src/list/ListControlsSheet.tsx +10 -12
- package/src/list/ListSidebarToolbar.tsx +7 -18
- package/src/list/RecordCard.native.tsx +2 -7
- package/src/list/RecordCard.tsx +2 -8
- package/src/list/ShufflePanel.tsx +0 -2
- package/src/list/listColumns.tsx +1 -1
- package/src/record/RecordPage.tsx +2 -10
- package/src/report/ReportViewToolbar.tsx +9 -11
- package/src/useFrappeForm.spec.tsx +1 -1
- package/types/FileBrowser/index.d.ts.map +1 -1
- package/types/FormSidebar.d.ts.map +1 -1
- package/types/FrappeAssignment.d.ts.map +1 -1
- package/types/FrappeDashboard.d.ts.map +1 -1
- package/types/FrappeFormActions.d.ts.map +1 -1
- package/types/FrappeKanban.d.ts.map +1 -1
- package/types/FrappeReportView.d.ts.map +1 -1
- package/types/desk/DeskShell.d.ts.map +1 -1
- package/types/fields/FileUpload.d.ts.map +1 -1
- package/types/list/ListControls.d.ts.map +1 -1
- package/types/list/ListControlsSheet.d.ts.map +1 -1
- package/types/list/ListSidebarToolbar.d.ts.map +1 -1
- package/types/list/RecordCard.d.ts.map +1 -1
- package/types/list/RecordCard.native.d.ts.map +1 -1
- package/types/list/ShufflePanel.d.ts.map +1 -1
- package/types/record/RecordPage.d.ts.map +1 -1
- package/types/report/ReportViewToolbar.d.ts.map +1 -1
package/src/FrappeDashboard.tsx
CHANGED
|
@@ -206,7 +206,6 @@ function LiveDashboardContent<TDoc extends { name: string; doctype: string }>({
|
|
|
206
206
|
`loading` (not bare `disabled`) is the derived busy state. */}
|
|
207
207
|
<Button
|
|
208
208
|
size="$2"
|
|
209
|
-
circular
|
|
210
209
|
icon={ArrowsClockwiseIcon}
|
|
211
210
|
onPress={onRefresh}
|
|
212
211
|
loading={isRefreshing || isLiveLoading}
|
|
@@ -328,7 +327,6 @@ export function FrappeDashboard<TDoc extends { name: string; doctype: string }>(
|
|
|
328
327
|
{/* LC-54: house Button, own-box floor (see the live-path refresh). */}
|
|
329
328
|
<Button
|
|
330
329
|
size="$2"
|
|
331
|
-
circular
|
|
332
330
|
icon={ArrowsClockwiseIcon}
|
|
333
331
|
onPress={bumpRefresh}
|
|
334
332
|
loading={isRefreshing}
|
|
@@ -128,13 +128,13 @@ describe("FrappeForm connections, schema mode", () => {
|
|
|
128
128
|
|
|
129
129
|
it("a new record has no connections yet", async () => {
|
|
130
130
|
renderForm({});
|
|
131
|
-
await waitFor(() => expect(screen.
|
|
131
|
+
await waitFor(() => expect(screen.getByLabelText("Save")).toBeTruthy());
|
|
132
132
|
expect(screen.queryByText("Connections")).toBeNull();
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
it("showConnections={false} leaves the tab out", async () => {
|
|
136
136
|
renderForm({ name: "bulbasaur", showConnections: false });
|
|
137
|
-
await waitFor(() => expect(screen.
|
|
137
|
+
await waitFor(() => expect(screen.getByLabelText("Save")).toBeTruthy());
|
|
138
138
|
expect(screen.queryByText("Connections")).toBeNull();
|
|
139
139
|
});
|
|
140
140
|
});
|
|
@@ -192,7 +192,7 @@ describe("FrappeForm resolves a doctype through the desk form engine", () => {
|
|
|
192
192
|
it("save refuses an empty field that mandatory_depends_on made required", async () => {
|
|
193
193
|
renderForm({ name: "LOAN-APPROVED", roles: ["Loan Officer"] });
|
|
194
194
|
await expectProbe("status", "val=Approved");
|
|
195
|
-
fireEvent.click(screen.
|
|
195
|
+
fireEvent.click(screen.getByLabelText("Save"));
|
|
196
196
|
await expectProbe("reason", "err=Reason is required");
|
|
197
197
|
});
|
|
198
198
|
|
|
@@ -276,7 +276,7 @@ describe("FrappeForm resolves a doctype through the desk form engine", () => {
|
|
|
276
276
|
renderForm();
|
|
277
277
|
await screen.findByTestId("probe-status");
|
|
278
278
|
expect(screen.getByText("Name")).toBeTruthy();
|
|
279
|
-
fireEvent.click(screen.
|
|
279
|
+
fireEvent.click(screen.getByLabelText("Save"));
|
|
280
280
|
await waitFor(() => {
|
|
281
281
|
expect(screen.getByText("Name is required")).toBeTruthy();
|
|
282
282
|
});
|
|
@@ -132,7 +132,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
132
132
|
renderForm(fixtures, { name: "LOAN-DRAFT" });
|
|
133
133
|
await expectProbe("employee_name", "val=Ada Lovelace");
|
|
134
134
|
await expectStatus("draft");
|
|
135
|
-
expect(screen.
|
|
135
|
+
expect(screen.queryByLabelText("Save")).toBeNull();
|
|
136
136
|
|
|
137
137
|
fireEvent.click(screen.getByText("Submit"));
|
|
138
138
|
await waitFor(() => expect(confirm).toHaveBeenCalledWith("Permanently Submit LOAN-DRAFT?"));
|
|
@@ -172,7 +172,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
172
172
|
|
|
173
173
|
fireEvent.click(screen.getByTestId("set-remarks"));
|
|
174
174
|
await expectStatus("notSaved");
|
|
175
|
-
expect(screen.
|
|
175
|
+
expect(screen.getByLabelText("Save")).toBeTruthy();
|
|
176
176
|
expect(screen.queryByText("Submit")).toBeNull();
|
|
177
177
|
});
|
|
178
178
|
|
|
@@ -185,8 +185,8 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
185
185
|
onAmend: vi.fn(),
|
|
186
186
|
});
|
|
187
187
|
await expectStatus("submitted");
|
|
188
|
-
expect(screen.
|
|
189
|
-
expect(screen.
|
|
188
|
+
expect(screen.queryByLabelText("Delete")).toBeNull();
|
|
189
|
+
expect(screen.getByLabelText("Close")).toBeTruthy();
|
|
190
190
|
expect(screen.getByTestId("frappe-form-cancel-document").textContent).toContain(
|
|
191
191
|
"Cancel Document",
|
|
192
192
|
);
|
|
@@ -196,7 +196,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
196
196
|
await expectStatus("cancelled");
|
|
197
197
|
await waitFor(async () => expect(await docstatusOf(fixtures, "LOAN-SUBMITTED")).toBe(2));
|
|
198
198
|
expect(screen.getByText("Amend")).toBeTruthy();
|
|
199
|
-
expect(screen.
|
|
199
|
+
expect(screen.getByLabelText("Delete")).toBeTruthy();
|
|
200
200
|
});
|
|
201
201
|
|
|
202
202
|
it("an allow_on_submit edit turns Cancel into Update, which keeps the document submitted", async () => {
|
|
@@ -205,10 +205,10 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
205
205
|
await expectStatus("submitted");
|
|
206
206
|
|
|
207
207
|
fireEvent.click(screen.getByTestId("set-remarks"));
|
|
208
|
-
await waitFor(() => expect(screen.
|
|
208
|
+
await waitFor(() => expect(screen.getByLabelText("Update")).toBeTruthy());
|
|
209
209
|
expect(screen.queryByTestId("frappe-form-cancel-document")).toBeNull();
|
|
210
210
|
|
|
211
|
-
fireEvent.click(screen.
|
|
211
|
+
fireEvent.click(screen.getByLabelText("Update"));
|
|
212
212
|
await waitFor(async () =>
|
|
213
213
|
expect((await fixtures.getDoc("Asset Loan", "LOAN-SUBMITTED"))?.remarks).toBe("edited"),
|
|
214
214
|
);
|
|
@@ -255,7 +255,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
255
255
|
await expectStatus("notSaved");
|
|
256
256
|
await expectProbe("employee_name", "val=Katherine Johnson");
|
|
257
257
|
await expectProbe("serial_no", "ro=false");
|
|
258
|
-
fireEvent.click(screen.
|
|
258
|
+
fireEvent.click(screen.getByLabelText("Save"));
|
|
259
259
|
await waitFor(async () => {
|
|
260
260
|
const amendments = await fixtures.getList("Asset Loan", {
|
|
261
261
|
filters: { amended_from: "LOAN-CANCELLED" },
|
|
@@ -279,7 +279,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
279
279
|
renderForm(corpus(), { name: "LOAN-SUBMITTED", roles: ["Loan Officer"], onCancel: vi.fn() });
|
|
280
280
|
await expectStatus("submitted");
|
|
281
281
|
expect(screen.queryByTestId("frappe-form-cancel-document")).toBeNull();
|
|
282
|
-
expect(screen.
|
|
282
|
+
expect(screen.getByLabelText("Cancel")).toBeTruthy();
|
|
283
283
|
cleanup();
|
|
284
284
|
|
|
285
285
|
renderForm(corpus(), { name: "LOAN-CANCELLED", roles: ["Loan Officer"], onAmend: vi.fn() });
|
|
@@ -289,7 +289,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
289
289
|
|
|
290
290
|
renderForm(corpus(), { name: "LOAN-DRAFT", roles: ["Loan Clerk"] });
|
|
291
291
|
await expectStatus("draft");
|
|
292
|
-
expect(screen.
|
|
292
|
+
expect(screen.getByLabelText("Save")).toBeTruthy();
|
|
293
293
|
expect(screen.queryByText("Submit")).toBeNull();
|
|
294
294
|
});
|
|
295
295
|
|
|
@@ -305,7 +305,7 @@ describe("FrappeForm runs the desk docstatus lifecycle", () => {
|
|
|
305
305
|
renderForm(corpus(), { name: "LOAN-SUBMITTED", roles: ["Auditor"], onCancel: vi.fn() });
|
|
306
306
|
await expectStatus("submitted");
|
|
307
307
|
expect(screen.queryByTestId("frappe-form-cancel-document")).toBeNull();
|
|
308
|
-
expect(screen.
|
|
308
|
+
expect(screen.getByLabelText("Cancel")).toBeTruthy();
|
|
309
309
|
cleanup();
|
|
310
310
|
|
|
311
311
|
renderForm(corpus(), { name: "LOAN-CANCELLED", roles: ["Auditor"], onAmend: vi.fn() });
|
|
@@ -326,11 +326,11 @@ describe("a read-only record view keeps desk's lifecycle beside Edit", () => {
|
|
|
326
326
|
const onEdit = vi.fn();
|
|
327
327
|
renderForm(fixtures, { name: "LOAN-DRAFT", onEdit, onCancel: vi.fn(), onDelete: vi.fn() });
|
|
328
328
|
await expectStatus("draft");
|
|
329
|
-
expect(screen.
|
|
330
|
-
expect(screen.
|
|
331
|
-
expect(screen.
|
|
329
|
+
expect(screen.queryByLabelText("Save")).toBeNull();
|
|
330
|
+
expect(screen.queryByLabelText("Cancel")).toBeNull();
|
|
331
|
+
expect(screen.getByLabelText("Delete")).toBeTruthy();
|
|
332
332
|
|
|
333
|
-
fireEvent.click(screen.
|
|
333
|
+
fireEvent.click(screen.getByLabelText("Edit"));
|
|
334
334
|
expect(onEdit).toHaveBeenCalledTimes(1);
|
|
335
335
|
|
|
336
336
|
fireEvent.click(screen.getByText("Submit"));
|
|
@@ -338,30 +338,30 @@ describe("a read-only record view keeps desk's lifecycle beside Edit", () => {
|
|
|
338
338
|
await waitFor(async () => expect(await docstatusOf(fixtures, "LOAN-DRAFT")).toBe(1));
|
|
339
339
|
await expectStatus("submitted");
|
|
340
340
|
expect(screen.getByText("Cancel Document")).toBeTruthy();
|
|
341
|
-
expect(screen.
|
|
342
|
-
expect(screen.
|
|
341
|
+
expect(screen.getByLabelText("Edit")).toBeTruthy();
|
|
342
|
+
expect(screen.queryByLabelText("Delete")).toBeNull();
|
|
343
343
|
});
|
|
344
344
|
|
|
345
345
|
it("a submitted document offers Cancel Document, and its allow_on_submit field keeps Edit", async () => {
|
|
346
346
|
const fixtures = corpus();
|
|
347
347
|
renderForm(fixtures, { name: "LOAN-SUBMITTED", onEdit: vi.fn(), onCancel: vi.fn() });
|
|
348
348
|
await expectStatus("submitted");
|
|
349
|
-
expect(screen.
|
|
350
|
-
expect(screen.
|
|
351
|
-
expect(screen.
|
|
349
|
+
expect(screen.getByLabelText("Edit")).toBeTruthy();
|
|
350
|
+
expect(screen.queryByLabelText("Cancel")).toBeNull();
|
|
351
|
+
expect(screen.queryByLabelText("Close")).toBeNull();
|
|
352
352
|
|
|
353
353
|
fireEvent.click(screen.getByText("Cancel Document"));
|
|
354
354
|
await waitFor(() => expect(confirm).toHaveBeenCalledWith("Permanently Cancel LOAN-SUBMITTED?"));
|
|
355
355
|
await waitFor(async () => expect(await docstatusOf(fixtures, "LOAN-SUBMITTED")).toBe(2));
|
|
356
356
|
await expectStatus("cancelled");
|
|
357
|
-
expect(screen.
|
|
357
|
+
expect(screen.queryByLabelText("Edit")).toBeNull();
|
|
358
358
|
});
|
|
359
359
|
|
|
360
360
|
it("a cancelled document offers Amend and no Edit", async () => {
|
|
361
361
|
const onAmend = vi.fn();
|
|
362
362
|
renderForm(corpus(), { name: "LOAN-CANCELLED", onEdit: vi.fn(), onAmend });
|
|
363
363
|
await expectStatus("cancelled");
|
|
364
|
-
expect(screen.
|
|
364
|
+
expect(screen.queryByLabelText("Edit")).toBeNull();
|
|
365
365
|
|
|
366
366
|
fireEvent.click(screen.getByText("Amend"));
|
|
367
367
|
await waitFor(() => expect(onAmend).toHaveBeenCalled());
|
|
@@ -374,7 +374,7 @@ describe("a submittable doctype's routed pages", () => {
|
|
|
374
374
|
const pushed = renderPage(corpus(), "/loans/LOAN-DRAFT");
|
|
375
375
|
await expectStatus("draft");
|
|
376
376
|
expect(screen.getByText("Submit")).toBeTruthy();
|
|
377
|
-
expect(screen.
|
|
377
|
+
expect(screen.queryByLabelText("Save")).toBeNull();
|
|
378
378
|
|
|
379
379
|
// LC-145: Submit is the bar's one action, so Edit rides the "…" menu.
|
|
380
380
|
fireEvent.click(screen.getByTestId("frappe-form-menu"));
|
|
@@ -386,14 +386,14 @@ describe("a submittable doctype's routed pages", () => {
|
|
|
386
386
|
const pushed = renderPage(corpus(), "/loans/LOAN-DRAFT/edit");
|
|
387
387
|
await expectStatus("draft");
|
|
388
388
|
expect(screen.getByText("Submit")).toBeTruthy();
|
|
389
|
-
expect(screen.
|
|
389
|
+
expect(screen.queryByLabelText("Edit")).toBeNull();
|
|
390
390
|
|
|
391
391
|
fireEvent.click(screen.getByTestId("set-remarks"));
|
|
392
392
|
await expectStatus("notSaved");
|
|
393
|
-
expect(screen.
|
|
393
|
+
expect(screen.getByLabelText("Save")).toBeTruthy();
|
|
394
394
|
expect(screen.queryByText("Submit")).toBeNull();
|
|
395
395
|
|
|
396
|
-
fireEvent.click(screen.
|
|
396
|
+
fireEvent.click(screen.getAllByLabelText(/^(Cancel|Back to .+ list)$/)[0]!);
|
|
397
397
|
expect(pushed).toEqual(["/loans/LOAN-DRAFT"]);
|
|
398
398
|
});
|
|
399
399
|
|
|
@@ -449,7 +449,7 @@ describe("the leave button stays live while a write is in flight (LC-30)", () =>
|
|
|
449
449
|
const onCancel = vi.fn();
|
|
450
450
|
renderForm(fixtures, { name: "LOAN-SUBMITTED", onCancel });
|
|
451
451
|
await expectStatus("submitted");
|
|
452
|
-
expect(screen.getByTestId("frappe-form-close").
|
|
452
|
+
expect(screen.getByTestId("frappe-form-close").getAttribute("aria-label")).toBe("Close");
|
|
453
453
|
|
|
454
454
|
fireEvent.click(screen.getByTestId("frappe-form-cancel-document"));
|
|
455
455
|
await waitFor(() =>
|
package/src/FrappeForm.tsx
CHANGED
|
@@ -23,7 +23,7 @@ import type React from "react";
|
|
|
23
23
|
import { useEffect, useMemo, useState } from "react";
|
|
24
24
|
import type { TFunction } from "i18next";
|
|
25
25
|
import { useTranslation } from "react-i18next";
|
|
26
|
-
import {
|
|
26
|
+
import { IconButton, Input, formCommonColors, standardActions } from "@multiplatform.one/forms";
|
|
27
27
|
import { Text as TamaguiText, XStack, YStack } from "tamagui";
|
|
28
28
|
import { hairlineWidth, useResolvedKnobs } from "@multiplatform.one/theme";
|
|
29
29
|
import { useFrappeConfig } from "./FrappeProvider";
|
|
@@ -677,13 +677,17 @@ function FrappeFormView<TDoc extends { name: string; doctype: string }>({
|
|
|
677
677
|
<YStack flex={1} backgroundColor="$background" testID="frappe-form-route-editor">
|
|
678
678
|
<XStack alignItems="center" gap="$2" paddingHorizontal="$2" paddingVertical="$1">
|
|
679
679
|
<XStack flex={1} flexBasis={0} justifyContent="flex-start">
|
|
680
|
-
<
|
|
681
|
-
|
|
680
|
+
<IconButton
|
|
681
|
+
icon={standardActions.cancel.icon}
|
|
682
|
+
edge="start"
|
|
683
|
+
data-mp-action="cancel"
|
|
682
684
|
onPress={onCancel ? handleCancel : routePage.onBack}
|
|
683
|
-
aria-label={
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
685
|
+
aria-label={
|
|
686
|
+
onCancel
|
|
687
|
+
? t(standardActions.cancel.label)
|
|
688
|
+
: t("Back to {{doctype}} list", { doctype })
|
|
689
|
+
}
|
|
690
|
+
/>
|
|
687
691
|
</XStack>
|
|
688
692
|
<Text
|
|
689
693
|
flexShrink={1}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ActionButton,
|
|
2
3
|
Chip,
|
|
3
4
|
DropdownMenu,
|
|
4
5
|
PageMenuButton,
|
|
@@ -10,7 +11,6 @@ import { useResolvedKnobs } from "@multiplatform.one/theme";
|
|
|
10
11
|
import {
|
|
11
12
|
ArrowCounterClockwiseIcon,
|
|
12
13
|
CheckCircleIcon,
|
|
13
|
-
FloppyDiskIcon,
|
|
14
14
|
PencilSimpleIcon,
|
|
15
15
|
ProhibitIcon,
|
|
16
16
|
TrashIcon,
|
|
@@ -122,33 +122,27 @@ export function FrappeFormActions({
|
|
|
122
122
|
)}
|
|
123
123
|
|
|
124
124
|
{onDelete && (
|
|
125
|
-
<
|
|
126
|
-
|
|
125
|
+
<ActionButton
|
|
126
|
+
kind="delete"
|
|
127
127
|
error
|
|
128
|
-
icon={TrashIcon}
|
|
129
128
|
loading={busy}
|
|
130
129
|
disabled={disabled}
|
|
131
130
|
disabledReason={disabled ? readOnlyReason : undefined}
|
|
132
131
|
disabledReasonPlacement="inline"
|
|
133
132
|
onPress={onDelete}
|
|
134
|
-
|
|
135
|
-
{t("Delete")}
|
|
136
|
-
</Button>
|
|
133
|
+
/>
|
|
137
134
|
)}
|
|
138
135
|
|
|
139
136
|
{onClose && (
|
|
140
|
-
<
|
|
141
|
-
|
|
142
|
-
|
|
137
|
+
<ActionButton
|
|
138
|
+
// A submitted document's own Cancel sits beside this button.
|
|
139
|
+
kind={action === "cancel" ? "close" : "cancel"}
|
|
143
140
|
disabled={closeDisabled}
|
|
144
141
|
disabledReason={closeDisabled ? readOnlyReason : undefined}
|
|
145
142
|
disabledReasonPlacement="inline"
|
|
146
143
|
onPress={onClose}
|
|
147
144
|
testID="frappe-form-close"
|
|
148
|
-
|
|
149
|
-
{/* A submitted document's own Cancel sits beside this button. */}
|
|
150
|
-
{action === "cancel" ? t("Close") : t("Cancel")}
|
|
151
|
-
</Button>
|
|
145
|
+
/>
|
|
152
146
|
)}
|
|
153
147
|
|
|
154
148
|
{action === "cancel" && (
|
|
@@ -169,18 +163,14 @@ export function FrappeFormActions({
|
|
|
169
163
|
)}
|
|
170
164
|
|
|
171
165
|
{onEdit && (
|
|
172
|
-
<
|
|
173
|
-
|
|
174
|
-
outlined={action === "submit"}
|
|
175
|
-
icon={PencilSimpleIcon}
|
|
166
|
+
<ActionButton
|
|
167
|
+
kind="edit"
|
|
176
168
|
disabled={disabled}
|
|
177
169
|
disabledReason={disabled ? readOnlyReason : undefined}
|
|
178
170
|
disabledReasonPlacement="inline"
|
|
179
171
|
onPress={onEdit}
|
|
180
172
|
testID="frappe-form-edit"
|
|
181
|
-
|
|
182
|
-
{t("Edit")}
|
|
183
|
-
</Button>
|
|
173
|
+
/>
|
|
184
174
|
)}
|
|
185
175
|
|
|
186
176
|
{action === "amend" && onAmend && (
|
|
@@ -208,6 +198,7 @@ export function FrappeFormActions({
|
|
|
208
198
|
|
|
209
199
|
{action === "submit" && (
|
|
210
200
|
<Button
|
|
201
|
+
// action-word-escape: Frappe's docstatus Submit, a lifecycle step a check would hide
|
|
211
202
|
accent
|
|
212
203
|
icon={CheckCircleIcon}
|
|
213
204
|
flex={footer ? 1 : undefined}
|
|
@@ -223,19 +214,16 @@ export function FrappeFormActions({
|
|
|
223
214
|
)}
|
|
224
215
|
|
|
225
216
|
{(action === "save" || action === "update") && (
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
flex={footer ? 1 : undefined}
|
|
217
|
+
<ActionButton
|
|
218
|
+
kind="save"
|
|
219
|
+
label={action === "update" ? t("Update") : undefined}
|
|
230
220
|
loading={busy}
|
|
231
221
|
disabled={disabled}
|
|
232
222
|
disabledReason={disabled ? readOnlyReason : undefined}
|
|
233
223
|
disabledReasonPlacement="inline"
|
|
234
224
|
onPress={onSave}
|
|
235
225
|
testID="frappe-form-save"
|
|
236
|
-
|
|
237
|
-
{busy ? t("Saving...") : action === "update" ? t("Update") : t("Save")}
|
|
238
|
-
</Button>
|
|
226
|
+
/>
|
|
239
227
|
)}
|
|
240
228
|
</XStack>
|
|
241
229
|
);
|
|
@@ -269,19 +257,19 @@ export function FrappeFormHeaderActions({
|
|
|
269
257
|
|
|
270
258
|
const primary =
|
|
271
259
|
action === "save" || action === "update" ? (
|
|
272
|
-
<
|
|
273
|
-
|
|
260
|
+
<ActionButton
|
|
261
|
+
kind="save"
|
|
262
|
+
label={action === "update" ? t("Update") : undefined}
|
|
274
263
|
loading={busy}
|
|
275
264
|
disabled={disabled}
|
|
276
265
|
disabledReason={disabled ? readOnlyReason : undefined}
|
|
277
266
|
disabledReasonPlacement="inline"
|
|
278
267
|
onPress={onSave}
|
|
279
268
|
testID="frappe-form-save"
|
|
280
|
-
|
|
281
|
-
{busy ? t("Saving...") : action === "update" ? t("Update") : t("Save")}
|
|
282
|
-
</Button>
|
|
269
|
+
/>
|
|
283
270
|
) : action === "submit" ? (
|
|
284
271
|
<Button
|
|
272
|
+
// action-word-escape: Frappe's docstatus Submit, a lifecycle step a check would hide
|
|
285
273
|
accent
|
|
286
274
|
loading={busy}
|
|
287
275
|
disabled={disabled}
|
|
@@ -312,16 +300,14 @@ export function FrappeFormHeaderActions({
|
|
|
312
300
|
{t("Amend")}
|
|
313
301
|
</Button>
|
|
314
302
|
) : onEdit ? (
|
|
315
|
-
<
|
|
316
|
-
|
|
303
|
+
<ActionButton
|
|
304
|
+
kind="edit"
|
|
317
305
|
disabled={disabled}
|
|
318
306
|
disabledReason={disabled ? readOnlyReason : undefined}
|
|
319
307
|
disabledReasonPlacement="inline"
|
|
320
308
|
onPress={onEdit}
|
|
321
309
|
testID="frappe-form-edit"
|
|
322
|
-
|
|
323
|
-
{t("Edit")}
|
|
324
|
-
</Button>
|
|
310
|
+
/>
|
|
325
311
|
) : null;
|
|
326
312
|
|
|
327
313
|
const lifecyclePrimary =
|
package/src/FrappeKanban.tsx
CHANGED
|
@@ -266,7 +266,6 @@ export function FrappeKanban<TDoc extends { name: string; doctype: string }>({
|
|
|
266
266
|
{canQuickAdd && column.id !== "__unassigned__" && (
|
|
267
267
|
<Button
|
|
268
268
|
size="$2"
|
|
269
|
-
circular
|
|
270
269
|
chromeless
|
|
271
270
|
icon={PlusIcon}
|
|
272
271
|
aria-label={t("Add card to {{column}}", { column: column.title })}
|
package/src/FrappeLikedBy.tsx
CHANGED
|
@@ -281,10 +281,10 @@ function FrappeLikedByBody({
|
|
|
281
281
|
<XStack alignItems="center" gap="$2">
|
|
282
282
|
<Button
|
|
283
283
|
size="$2"
|
|
284
|
-
circular
|
|
285
284
|
chromeless
|
|
286
285
|
disabled={!canToggle}
|
|
287
286
|
aria-pressed={liked}
|
|
287
|
+
selected={false}
|
|
288
288
|
aria-label={liked ? t("Unlike") : t("Like")}
|
|
289
289
|
onPress={handleToggle}
|
|
290
290
|
icon={
|
|
@@ -130,10 +130,14 @@ describe("FrappeListView refresh press floor (LC-54 amendment)", () => {
|
|
|
130
130
|
expect(refresh.className).not.toMatch(negativeMarginAtom);
|
|
131
131
|
const token = refresh.getAttribute("data-size-token") as SizeTokens;
|
|
132
132
|
const px = Number(getVariableValue(getSize(token)));
|
|
133
|
-
|
|
134
|
-
|
|
133
|
+
// LC-176: the bare glyph sits in a square box at its control height, inside
|
|
134
|
+
// the token box, and slop restores the 44pt press floor.
|
|
135
|
+
const box = Number(/(?:^| )_mih-(\d+)px/.exec(refresh.className)?.[1]);
|
|
136
|
+
expect(refresh.className).toContain(`_miw-${box}px`);
|
|
137
|
+
expect(box).toBeGreaterThan(0);
|
|
138
|
+
expect(box).toBeLessThanOrEqual(px);
|
|
135
139
|
const slop = Number(refresh.getAttribute("data-mp-press-slop") ?? 0);
|
|
136
|
-
expect(
|
|
140
|
+
expect(box + slop * 2).toBeGreaterThanOrEqual(44);
|
|
137
141
|
});
|
|
138
142
|
|
|
139
143
|
it("hover feedback rides the button's own in-slot box (house channel)", async () => {
|
package/src/FrappeListView.tsx
CHANGED
|
@@ -1202,7 +1202,6 @@ function FrappeListViewBody<TDoc extends { name: string; doctype: string }>({
|
|
|
1202
1202
|
feedback stays inside its own layout slot. */}
|
|
1203
1203
|
<Button
|
|
1204
1204
|
size="$2"
|
|
1205
|
-
circular
|
|
1206
1205
|
chromeless
|
|
1207
1206
|
icon={ArrowsClockwiseIcon}
|
|
1208
1207
|
onPress={handleRefresh}
|
package/src/FrappeReportView.tsx
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
* hidden where the web download pipeline does not exist.
|
|
41
41
|
*/
|
|
42
42
|
import { AsyncBoundary, EmptyState } from "@multiplatform.one/components";
|
|
43
|
-
import {
|
|
43
|
+
import { DatePicker, IconButton, Spinner, formCommonColors } from "@multiplatform.one/forms";
|
|
44
44
|
import {
|
|
45
45
|
DataTable,
|
|
46
46
|
DataTableExport,
|
|
@@ -477,14 +477,11 @@ export function FrappeReportView({
|
|
|
477
477
|
</XStack>
|
|
478
478
|
)}
|
|
479
479
|
{refreshShown && (
|
|
480
|
-
<
|
|
481
|
-
size="$2"
|
|
480
|
+
<IconButton
|
|
482
481
|
icon={ArrowClockwiseIcon}
|
|
483
482
|
onPress={refresh}
|
|
484
483
|
aria-label={t("Refresh report")}
|
|
485
|
-
|
|
486
|
-
{t("Refresh")}
|
|
487
|
-
</Button>
|
|
484
|
+
/>
|
|
488
485
|
)}
|
|
489
486
|
{exportEnabled && rows.length > 0 && (
|
|
490
487
|
<DataTableExport
|
package/src/desk/DeskShell.tsx
CHANGED
|
@@ -21,9 +21,12 @@ vi.mock("../FrappeListView", () => ({
|
|
|
21
21
|
}));
|
|
22
22
|
vi.mock("../FrappeForm", () => ({
|
|
23
23
|
FrappeForm: ({ onSave, name }: { onSave: (doc: { name: string }) => void; name?: string }) => (
|
|
24
|
-
<button
|
|
25
|
-
Save
|
|
26
|
-
|
|
24
|
+
<button
|
|
25
|
+
aria-label="Save"
|
|
26
|
+
onClick={() => onSave({ name: state.name })}
|
|
27
|
+
data-testid="form"
|
|
28
|
+
data-name={name}
|
|
29
|
+
/>
|
|
27
30
|
),
|
|
28
31
|
}));
|
|
29
32
|
vi.mock("@multiplatform.one/components", () => ({
|
|
@@ -59,7 +62,7 @@ describe.each(["A/B", "A?B", "A#B", "A B", "Pokémon", "A%2FB"])("desk document
|
|
|
59
62
|
state.name = name;
|
|
60
63
|
const navigate = vi.fn();
|
|
61
64
|
render(<DeskFormPage doctype="todo" onNavigate={navigate} />);
|
|
62
|
-
fireEvent.click(screen.
|
|
65
|
+
fireEvent.click(screen.getByLabelText("Save"));
|
|
63
66
|
expect(navigate).toHaveBeenCalledWith(path);
|
|
64
67
|
});
|
|
65
68
|
});
|
|
@@ -119,10 +119,12 @@ async function pressText(root: ParentNode, text: string) {
|
|
|
119
119
|
let target: Element | null = null;
|
|
120
120
|
await waitFor(
|
|
121
121
|
() => {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
// LC-260: Next and Done are icon buttons, named by their label.
|
|
123
|
+
const node =
|
|
124
|
+
Array.from(root.querySelectorAll("*")).find(
|
|
125
|
+
(el) => el.children.length === 0 && norm(el.textContent ?? "") === norm(text),
|
|
126
|
+
) ?? root.querySelector(`[aria-label="${text}"]`);
|
|
127
|
+
if (!node) throw new Error(`no element with text or label "${text}"`);
|
|
126
128
|
target = node;
|
|
127
129
|
},
|
|
128
130
|
{ timeout: 30_000 },
|
|
@@ -123,7 +123,7 @@ describe("FileUpload size gate", () => {
|
|
|
123
123
|
* `aria-label` still fails. Recorded on MPO-123.
|
|
124
124
|
*/
|
|
125
125
|
const buttonLabelled = (container: HTMLElement, prefix: string) =>
|
|
126
|
-
Array.from(container.querySelectorAll("button")).find((b) =>
|
|
126
|
+
Array.from(container.querySelectorAll('button, [role="button"]')).find((b) =>
|
|
127
127
|
(b.getAttribute("aria-label") ?? "").startsWith(prefix),
|
|
128
128
|
);
|
|
129
129
|
|
|
@@ -226,8 +226,9 @@ describe("FileUpload transfer", () => {
|
|
|
226
226
|
/^Retry \S/,
|
|
227
227
|
);
|
|
228
228
|
expect(remove?.getAttribute("aria-label")).toMatch(/^Remove \S/);
|
|
229
|
-
//
|
|
230
|
-
expect(buttonLabelled(result.container, "Retry ")?.textContent).
|
|
229
|
+
// LC-260: the button shows only its glyph; the name lives on the label.
|
|
230
|
+
expect(buttonLabelled(result.container, "Retry ")?.textContent).toBe("");
|
|
231
|
+
expect(buttonLabelled(result.container, "Retry ")?.querySelector("svg")).toBeTruthy();
|
|
231
232
|
|
|
232
233
|
await act(async () => {
|
|
233
234
|
fireEvent.click(buttonLabelled(result.container, "Retry ") as Element);
|
|
@@ -292,6 +293,22 @@ describe("FileUpload with a value", () => {
|
|
|
292
293
|
expect(onChange).toHaveBeenCalledWith("");
|
|
293
294
|
});
|
|
294
295
|
|
|
296
|
+
it("an image's Replace and Remove are glyphs in one media capsule over it (LC-260, LC-176)", () => {
|
|
297
|
+
const result = renderWithProviders(
|
|
298
|
+
<FileUpload label="Photo" value="/files/sprite.png" isImage onChange={() => {}} />,
|
|
299
|
+
);
|
|
300
|
+
const actions = result.container.querySelector('[data-file-upload="preview-actions"]');
|
|
301
|
+
expect(actions).toBeTruthy();
|
|
302
|
+
const capsule = actions!.querySelector('[data-mp-icon-button-group="media"]');
|
|
303
|
+
expect(capsule).toBeTruthy();
|
|
304
|
+
const buttons = Array.from(capsule!.querySelectorAll("[data-mp-action]"));
|
|
305
|
+
expect(buttons.map((b) => b.getAttribute("aria-label"))).toEqual(["Replace", "Remove"]);
|
|
306
|
+
for (const button of buttons) {
|
|
307
|
+
expect(button.getAttribute("data-mp-icon-button")).not.toBe("media");
|
|
308
|
+
expect(button.textContent).toBe("");
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
|
|
295
312
|
it("readOnly hides Replace and Remove — the value is visible, not editable", () => {
|
|
296
313
|
const result = renderWithProviders(
|
|
297
314
|
<FileUpload label="Attachment" value="/files/report.pdf" readOnly onChange={() => {}} />,
|