@multiplatform.one/frappe-ui 7.34.2 → 7.34.4

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.
Files changed (121) hide show
  1. package/dist/cjs/FrappeForm.cjs +1 -1
  2. package/dist/cjs/FrappeForm.native.js +1 -1
  3. package/dist/cjs/FrappeForm.native.js.map +1 -1
  4. package/dist/cjs/FrappeListView.cjs +1 -1
  5. package/dist/cjs/FrappeListView.native.js +1 -1
  6. package/dist/cjs/FrappeListView.native.js.map +1 -1
  7. package/dist/cjs/FrappeReportBuilder.cjs +8 -6
  8. package/dist/cjs/FrappeReportBuilder.native.js +8 -6
  9. package/dist/cjs/FrappeReportBuilder.native.js.map +1 -1
  10. package/dist/cjs/FrappeTable.cjs +3 -2
  11. package/dist/cjs/FrappeTable.native.js +3 -2
  12. package/dist/cjs/FrappeTable.native.js.map +1 -1
  13. package/dist/cjs/desk/DeskFormPage.cjs +3 -3
  14. package/dist/cjs/desk/DeskFormPage.native.js +3 -3
  15. package/dist/cjs/desk/DeskFormPage.native.js.map +1 -1
  16. package/dist/cjs/desk/DeskListPage.cjs +1 -1
  17. package/dist/cjs/desk/DeskListPage.native.js +1 -1
  18. package/dist/cjs/desk/DeskListPage.native.js.map +1 -1
  19. package/dist/cjs/list/listColumns.cjs +1 -0
  20. package/dist/cjs/list/listColumns.native.js +1 -0
  21. package/dist/cjs/list/listColumns.native.js.map +1 -1
  22. package/dist/cjs/recordShape.cjs +1 -1
  23. package/dist/cjs/recordShape.native.js +1 -1
  24. package/dist/cjs/recordShape.native.js.map +1 -1
  25. package/dist/cjs/useFrappeForm.cjs +10 -1
  26. package/dist/cjs/useFrappeForm.native.js +10 -1
  27. package/dist/cjs/useFrappeForm.native.js.map +1 -1
  28. package/dist/esm/FrappeForm.mjs +1 -1
  29. package/dist/esm/FrappeForm.mjs.map +1 -1
  30. package/dist/esm/FrappeForm.native.js +1 -1
  31. package/dist/esm/FrappeForm.native.js.map +1 -1
  32. package/dist/esm/FrappeListView.mjs +1 -1
  33. package/dist/esm/FrappeListView.mjs.map +1 -1
  34. package/dist/esm/FrappeListView.native.js +1 -1
  35. package/dist/esm/FrappeListView.native.js.map +1 -1
  36. package/dist/esm/FrappeReportBuilder.mjs +9 -7
  37. package/dist/esm/FrappeReportBuilder.mjs.map +1 -1
  38. package/dist/esm/FrappeReportBuilder.native.js +9 -7
  39. package/dist/esm/FrappeReportBuilder.native.js.map +1 -1
  40. package/dist/esm/FrappeTable.mjs +3 -2
  41. package/dist/esm/FrappeTable.mjs.map +1 -1
  42. package/dist/esm/FrappeTable.native.js +3 -2
  43. package/dist/esm/FrappeTable.native.js.map +1 -1
  44. package/dist/esm/desk/DeskFormPage.mjs +3 -3
  45. package/dist/esm/desk/DeskFormPage.mjs.map +1 -1
  46. package/dist/esm/desk/DeskFormPage.native.js +3 -3
  47. package/dist/esm/desk/DeskFormPage.native.js.map +1 -1
  48. package/dist/esm/desk/DeskListPage.mjs +1 -1
  49. package/dist/esm/desk/DeskListPage.mjs.map +1 -1
  50. package/dist/esm/desk/DeskListPage.native.js +1 -1
  51. package/dist/esm/desk/DeskListPage.native.js.map +1 -1
  52. package/dist/esm/list/listColumns.mjs +1 -0
  53. package/dist/esm/list/listColumns.mjs.map +1 -1
  54. package/dist/esm/list/listColumns.native.js +1 -0
  55. package/dist/esm/list/listColumns.native.js.map +1 -1
  56. package/dist/esm/recordShape.mjs +1 -1
  57. package/dist/esm/recordShape.mjs.map +1 -1
  58. package/dist/esm/recordShape.native.js +1 -1
  59. package/dist/esm/recordShape.native.js.map +1 -1
  60. package/dist/esm/useFrappeForm.mjs +10 -1
  61. package/dist/esm/useFrappeForm.mjs.map +1 -1
  62. package/dist/esm/useFrappeForm.native.js +10 -1
  63. package/dist/esm/useFrappeForm.native.js.map +1 -1
  64. package/dist/jsx/FrappeForm.mjs +1 -1
  65. package/dist/jsx/FrappeForm.mjs.map +1 -1
  66. package/dist/jsx/FrappeForm.native.js +1 -1
  67. package/dist/jsx/FrappeForm.native.js.map +1 -1
  68. package/dist/jsx/FrappeListView.mjs +1 -1
  69. package/dist/jsx/FrappeListView.mjs.map +1 -1
  70. package/dist/jsx/FrappeListView.native.js +1 -1
  71. package/dist/jsx/FrappeListView.native.js.map +1 -1
  72. package/dist/jsx/FrappeReportBuilder.mjs +9 -7
  73. package/dist/jsx/FrappeReportBuilder.mjs.map +1 -1
  74. package/dist/jsx/FrappeReportBuilder.native.js +8 -6
  75. package/dist/jsx/FrappeReportBuilder.native.js.map +1 -1
  76. package/dist/jsx/FrappeTable.mjs +3 -2
  77. package/dist/jsx/FrappeTable.mjs.map +1 -1
  78. package/dist/jsx/FrappeTable.native.js +3 -2
  79. package/dist/jsx/FrappeTable.native.js.map +1 -1
  80. package/dist/jsx/desk/DeskFormPage.mjs +3 -3
  81. package/dist/jsx/desk/DeskFormPage.mjs.map +1 -1
  82. package/dist/jsx/desk/DeskFormPage.native.js +3 -3
  83. package/dist/jsx/desk/DeskFormPage.native.js.map +1 -1
  84. package/dist/jsx/desk/DeskListPage.mjs +1 -1
  85. package/dist/jsx/desk/DeskListPage.mjs.map +1 -1
  86. package/dist/jsx/desk/DeskListPage.native.js +1 -1
  87. package/dist/jsx/desk/DeskListPage.native.js.map +1 -1
  88. package/dist/jsx/list/listColumns.mjs +1 -0
  89. package/dist/jsx/list/listColumns.mjs.map +1 -1
  90. package/dist/jsx/list/listColumns.native.js +1 -0
  91. package/dist/jsx/list/listColumns.native.js.map +1 -1
  92. package/dist/jsx/recordShape.mjs +1 -1
  93. package/dist/jsx/recordShape.mjs.map +1 -1
  94. package/dist/jsx/recordShape.native.js +1 -1
  95. package/dist/jsx/recordShape.native.js.map +1 -1
  96. package/dist/jsx/useFrappeForm.mjs +10 -1
  97. package/dist/jsx/useFrappeForm.mjs.map +1 -1
  98. package/dist/jsx/useFrappeForm.native.js +10 -1
  99. package/dist/jsx/useFrappeForm.native.js.map +1 -1
  100. package/package.json +16 -16
  101. package/src/FrappeForm.tsx +1 -1
  102. package/src/FrappeListView.shape.spec.tsx +67 -0
  103. package/src/FrappeListView.tsx +1 -1
  104. package/src/FrappeReportBuilder.tsx +11 -8
  105. package/src/FrappeTable.tsx +5 -2
  106. package/src/desk/DeskFormPage.tsx +3 -3
  107. package/src/desk/DeskListPage.tsx +1 -1
  108. package/src/desk/deskDocumentRoutes.spec.tsx +65 -0
  109. package/src/list/listColumns.spec.tsx +30 -0
  110. package/src/list/listColumns.tsx +1 -0
  111. package/src/recordShape.spec.ts +15 -0
  112. package/src/recordShape.ts +10 -2
  113. package/src/useFrappeForm.spec.tsx +82 -0
  114. package/src/useFrappeForm.ts +13 -1
  115. package/types/FrappeReportBuilder.d.ts.map +1 -1
  116. package/types/FrappeTable.d.ts +3 -1
  117. package/types/FrappeTable.d.ts.map +1 -1
  118. package/types/list/listColumns.d.ts.map +1 -1
  119. package/types/recordShape.d.ts +1 -1
  120. package/types/recordShape.d.ts.map +1 -1
  121. package/types/useFrappeForm.d.ts.map +1 -1
@@ -0,0 +1,67 @@
1
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
2
+ import { act, screen, waitFor } from "@testing-library/react";
3
+ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { FrappeListView } from "./FrappeListView";
5
+ import { FrappeProvider } from "./FrappeProvider";
6
+
7
+ let run = 0;
8
+ let projections: string[][];
9
+ let answerShape: ((response: Response) => void) | undefined;
10
+ const record = { name: "move-1", move_name: "Tackle", power: 40 };
11
+
12
+ beforeEach(() => {
13
+ run += 1;
14
+ projections = [];
15
+ answerShape = undefined;
16
+ vi.stubGlobal("fetch", async (input: string | URL | Request) => {
17
+ const url = new URL(String(input instanceof Request ? input.url : input));
18
+ if (url.pathname === "/api/resource/Move") {
19
+ const fields = JSON.parse(url.searchParams.get("fields") ?? "[]") as string[];
20
+ if (fields.includes("*"))
21
+ return new Promise<Response>((resolve) => {
22
+ answerShape = resolve;
23
+ });
24
+ projections.push(fields);
25
+ return Response.json({ data: [record] });
26
+ }
27
+ return Response.json({ exc_type: "PermissionError" }, { status: 403 });
28
+ });
29
+ });
30
+ afterEach(() => vi.unstubAllGlobals());
31
+
32
+ function mount(mode: "list" | "table", explicit = false) {
33
+ return renderWithProviders(
34
+ <FrappeProvider baseURL={`https://shape-delay-${run}.test`} realtime={false}>
35
+ <FrappeListView<{ name: string; doctype: string; move_name: string; power: number }>
36
+ doctype="Move"
37
+ viewMode={mode}
38
+ fields={explicit ? ["name", "move_name"] : undefined}
39
+ showToolbar={false}
40
+ />
41
+ </FrappeProvider>,
42
+ );
43
+ }
44
+
45
+ describe("guest list projection", () => {
46
+ it.each(["list", "table"] as const)(
47
+ "waits for the shape before mounting the %s collection",
48
+ async (mode) => {
49
+ mount(mode);
50
+ await waitFor(() => expect(answerShape).toBeDefined());
51
+ await act(async () => {});
52
+ expect(projections).toEqual([]);
53
+ expect(screen.getByLabelText("Loading")).toBeTruthy();
54
+ await act(async () => answerShape?.(Response.json({ data: [record] })));
55
+ await waitFor(() => expect(screen.getByText("Tackle")).toBeTruthy());
56
+ expect(projections).toHaveLength(1);
57
+ expect(projections[0]).toEqual(expect.arrayContaining(["name", "move_name", "power"]));
58
+ },
59
+ );
60
+
61
+ it("keeps explicit fields immediate while the shape is delayed", async () => {
62
+ mount("table", true);
63
+ await waitFor(() => expect(screen.getByText("move-1")).toBeTruthy());
64
+ expect(projections).toHaveLength(1);
65
+ expect(projections[0]).toEqual(expect.arrayContaining(["name", "move_name"]));
66
+ });
67
+ });
@@ -1040,7 +1040,7 @@ function FrappeListViewBody<TDoc extends { name: string; doctype: string }>({
1040
1040
 
1041
1041
  // Named fields need no schema to read or draw: the view renders now (on
1042
1042
  // the server too) and labels settle when meta lands.
1043
- if (isMetaLoading && !fields) {
1043
+ if (!fields && (isMetaLoading || recordShape.status === "pending")) {
1044
1044
  return asPage(
1045
1045
  <YStack
1046
1046
  {...knobProps.panelPadding}
@@ -27,7 +27,6 @@ import {
27
27
  ScrollView,
28
28
  Spinner,
29
29
  YStack,
30
- isWeb,
31
30
  notify,
32
31
  type GroupByConfig,
33
32
  type ReportColumn,
@@ -822,7 +821,7 @@ function FrappeReportBuilderBody({
822
821
  );
823
822
  } else {
824
823
  body = (
825
- <YStack flex={1} minWidth={0} {...knobProps.gap}>
824
+ <YStack flexGrow={1} flexShrink={0} flexBasis="auto" minWidth={0} {...knobProps.gap}>
826
825
  {chartData.length > 0 && (
827
826
  <YStack {...knobProps.surface} {...knobProps.containerRadius} {...knobProps.panelPadding}>
828
827
  <BarChart data={chartData} />
@@ -845,7 +844,7 @@ function FrappeReportBuilderBody({
845
844
  }
846
845
 
847
846
  const content = (
848
- <YStack flex={1} minWidth={0} {...stackProps}>
847
+ <YStack flex={1} minWidth={0} minHeight={0} {...stackProps}>
849
848
  <ReportViewToolbar
850
849
  columns={allColumns}
851
850
  selected={selectedFieldnames}
@@ -865,9 +864,15 @@ function FrappeReportBuilderBody({
865
864
  onExport={exportEnabled ? handleExport : undefined}
866
865
  exportDisabled={total === 0}
867
866
  />
868
- <YStack flex={1} minWidth={0} paddingHorizontal="$3">
867
+ <ScrollView
868
+ flex={1}
869
+ minWidth={0}
870
+ minHeight={0}
871
+ paddingHorizontal="$3"
872
+ testID="frappe-report-scroll"
873
+ >
869
874
  {body}
870
- </YStack>
875
+ </ScrollView>
871
876
  {total > 0 && !syncError && (
872
877
  <YStack paddingHorizontal="$3" paddingVertical="$2">
873
878
  <DataTablePagination
@@ -889,9 +894,7 @@ function FrappeReportBuilderBody({
889
894
  </YStack>
890
895
  );
891
896
 
892
- // Native has no page-level scroll (the desk list precedent) — wrap so rows
893
- // below the fold stay reachable. Web keeps the flex layout.
894
- return isWeb ? content : <ScrollView flex={1}>{content}</ScrollView>;
897
+ return content;
895
898
  }
896
899
 
897
900
  export type { ReportColumn, GroupByConfig } from "@multiplatform.one/components";
@@ -122,6 +122,8 @@ export interface FrappeTableProps<TDoc extends { name: string; doctype: string }
122
122
  * Requires onStateChange for state sync; fetches data based on table state.
123
123
  */
124
124
  serverSide?: boolean;
125
+ /** Infinite mode may omit totals when the host owns the count. */
126
+ fetchTotalCount?: boolean;
125
127
  /**
126
128
  * Callback when filters, sort, or pagination change.
127
129
  * Used for server-side fetches when serverSide is true.
@@ -341,6 +343,7 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
341
343
  canCreateGlobalFilters = false,
342
344
  userId,
343
345
  serverSide = false,
346
+ fetchTotalCount = true,
344
347
  onStateChange: onStateChangeProp,
345
348
  refreshToken,
346
349
  paginationMode = "pages",
@@ -697,7 +700,7 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
697
700
  limit: params.limit,
698
701
  orderBy: params.orderBy,
699
702
  }),
700
- query.pageIndex === 0
703
+ query.pageIndex === 0 && fetchTotalCount
701
704
  ? frappeApp
702
705
  .db()
703
706
  .getCount(doctype, params.filters.length ? params.filters : undefined)
@@ -711,7 +714,7 @@ export function FrappeTable<TDoc extends { name: string; doctype: string }>({
711
714
  ]);
712
715
  return { rows, totalCount: count ?? undefined };
713
716
  },
714
- [frappeApp, doctype, serverFields],
717
+ [frappeApp, doctype, serverFields, fetchTotalCount],
715
718
  );
716
719
 
717
720
  const resolvedLoadPage = loadPageProp ?? (infiniteServerMode ? frappeLoadPage : undefined);
@@ -68,7 +68,7 @@ export function DeskFormPage({ doctype, name, onNavigate }: DeskFormPageProps) {
68
68
  if (!isCreate && name) {
69
69
  addToRecent({
70
70
  label: `${displayName}: ${name}`,
71
- path: `/desk/${doctype}/${name}`,
71
+ path: `/desk/${doctype}/${encodeURIComponent(name)}`,
72
72
  });
73
73
  }
74
74
  }, [doctype, name, displayName, isCreate]);
@@ -104,7 +104,7 @@ export function DeskFormPage({ doctype, name, onNavigate }: DeskFormPageProps) {
104
104
  <DeskShell
105
105
  breadcrumbs={breadcrumbs}
106
106
  onNavigate={handleNavigate}
107
- activePath={`/desk/${doctype}/${name || "new"}`}
107
+ activePath={`/desk/${doctype}/${encodeURIComponent(name || "new")}`}
108
108
  >
109
109
  {/* LC-29 PAGE-TEMPLATE: the canonical detail-page scaffold owns scroll,
110
110
  max-width, toolbar/header regions, and the supporting-pane aside.
@@ -151,7 +151,7 @@ export function DeskFormPage({ doctype, name, onNavigate }: DeskFormPageProps) {
151
151
  showTimeline
152
152
  onSave={(doc) => {
153
153
  if (isCreate && doc.name) {
154
- handleNavigate(`/desk/${doctype}/${doc.name}`);
154
+ handleNavigate(`/desk/${doctype}/${encodeURIComponent(doc.name)}`);
155
155
  }
156
156
  }}
157
157
  onCancel={() => handleNavigate(`/desk/${doctype}`)}
@@ -81,7 +81,7 @@ export function DeskListPage({ doctype, onNavigate }: DeskListPageProps) {
81
81
 
82
82
  const handleItemClick = (doc: Partial<{ name: string; doctype: string }>) => {
83
83
  if (!doc.name) return;
84
- const path = `/desk/${doctype}/${doc.name}`;
84
+ const path = `/desk/${doctype}/${encodeURIComponent(doc.name)}`;
85
85
  addToRecent({ label: `${displayName}: ${doc.name}`, path });
86
86
  handleNavigate(path);
87
87
  };
@@ -0,0 +1,65 @@
1
+ import type { ReactNode } from "react";
2
+ import { fireEvent, render, screen } from "@testing-library/react";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { DeskFormPage } from "./DeskFormPage";
5
+ import { DeskListPage } from "./DeskListPage";
6
+
7
+ const state = vi.hoisted(() => ({ name: "", recent: vi.fn() }));
8
+ vi.mock("./DeskSidebar", () => ({ addToRecent: state.recent }));
9
+ vi.mock("./DeskFormSidebar", () => ({ DeskFormSidebar: () => null }));
10
+ vi.mock("./DeskShell", () => ({
11
+ DeskShell: ({ children, activePath }: { children: ReactNode; activePath: string }) => (
12
+ <div data-testid="shell" data-path={activePath}>
13
+ {children}
14
+ </div>
15
+ ),
16
+ }));
17
+ vi.mock("../FrappeListView", () => ({
18
+ FrappeListView: ({ onItemClick }: { onItemClick: (doc: { name: string }) => void }) => (
19
+ <button onClick={() => onItemClick({ name: state.name })}>Open</button>
20
+ ),
21
+ }));
22
+ vi.mock("../FrappeForm", () => ({
23
+ FrappeForm: ({ onSave, name }: { onSave: (doc: { name: string }) => void; name?: string }) => (
24
+ <button onClick={() => onSave({ name: state.name })} data-testid="form" data-name={name}>
25
+ Save
26
+ </button>
27
+ ),
28
+ }));
29
+ vi.mock("@multiplatform.one/components", () => ({
30
+ PageHeader: () => null,
31
+ ListPageLayout: ({ children }: { children: ReactNode }) => children,
32
+ DetailPageLayout: ({ children }: { children: ReactNode }) => children,
33
+ }));
34
+ vi.mock("@multiplatform.one/forms", () => ({ Button: () => null, formCommonColors: {} }));
35
+ vi.mock("@multiplatform.one/theme", () => ({ useResolvedKnobs: () => ({ knobProps: {} }) }));
36
+ vi.mock("tamagui", () => ({ Text: () => null, YStack: () => null }));
37
+
38
+ beforeEach(() => state.recent.mockClear());
39
+
40
+ describe.each(["A/B", "A?B", "A#B", "A B", "Pokémon", "A%2FB"])("desk document %s", (name) => {
41
+ const path = `/desk/todo/${encodeURIComponent(name)}`;
42
+ it("encodes list navigation and recents", () => {
43
+ state.name = name;
44
+ const navigate = vi.fn();
45
+ render(<DeskListPage doctype="todo" onNavigate={navigate} />);
46
+ fireEvent.click(screen.getByText("Open"));
47
+ expect(navigate).toHaveBeenCalledWith(path);
48
+ expect(state.recent).toHaveBeenCalledWith({ label: `Todo: ${name}`, path });
49
+ });
50
+
51
+ it("encodes form recents and active path without changing the document name", () => {
52
+ render(<DeskFormPage doctype="todo" name={name} />);
53
+ expect(state.recent).toHaveBeenCalledWith({ label: `Todo: ${name}`, path });
54
+ expect(screen.getByTestId("shell").getAttribute("data-path")).toBe(path);
55
+ expect(screen.getByTestId("form").getAttribute("data-name")).toBe(name);
56
+ });
57
+
58
+ it("encodes the saved name when leaving create mode", () => {
59
+ state.name = name;
60
+ const navigate = vi.fn();
61
+ render(<DeskFormPage doctype="todo" onNavigate={navigate} />);
62
+ fireEvent.click(screen.getByText("Save"));
63
+ expect(navigate).toHaveBeenCalledWith(path);
64
+ });
65
+ });
@@ -0,0 +1,30 @@
1
+ import { renderWithProviders } from "@multiplatform.one/test-utils";
2
+ import { screen } from "@testing-library/react";
3
+ import { describe, expect, it } from "vitest";
4
+ import { buildListColumns } from "./listColumns";
5
+
6
+ describe("document list title", () => {
7
+ it("constrains a linked title so its single-line text can ellipsize", () => {
8
+ const title = "A long document title that must truncate within the reserved subject width";
9
+ const column = buildListColumns({
10
+ t: (_key, fallback) => fallback,
11
+ getDocHref: (name) => `/backoffice/todo/${name}`,
12
+ })[0]!;
13
+ const renderTitle = column.cell;
14
+ if (typeof renderTitle !== "function") throw new Error("Expected a title cell renderer");
15
+ renderWithProviders(
16
+ <>
17
+ {renderTitle({
18
+ row: { original: { name: "TODO-001" } },
19
+ getValue: () => title,
20
+ } as never)}
21
+ </>,
22
+ );
23
+ const link = screen.getByRole("link", { name: title });
24
+ expect(link.getAttribute("href")).toBe("/backoffice/todo/TODO-001");
25
+ expect(getComputedStyle(link).display).toBe("flex");
26
+ expect(getComputedStyle(link).minWidth).toBe("0px");
27
+ expect(getComputedStyle(screen.getByText(title)).textOverflow).toBe("ellipsis");
28
+ expect(getComputedStyle(screen.getByText(title)).whiteSpace).toBe("nowrap");
29
+ });
30
+ });
@@ -436,6 +436,7 @@ export function buildListColumns({
436
436
  return (
437
437
  <Anchor
438
438
  href={href}
439
+ display="flex"
439
440
  textDecorationLine="none"
440
441
  minWidth={0}
441
442
  flexShrink={1}
@@ -26,6 +26,21 @@ const record = {
26
26
  };
27
27
 
28
28
  describe("recordShape", () => {
29
+ it.each(["/files/photo.png", "/private/files/photo.JPEG", "/files/a.webp", "/files/a.svg"])(
30
+ "recognizes a Frappe image: %s",
31
+ (image) => {
32
+ expect(fieldsFromRecord({ image })[0]?.fieldtype).toBe("Attach Image");
33
+ },
34
+ );
35
+
36
+ it.each([
37
+ "https://other.test/photo.png",
38
+ "/files/a.png?download=1",
39
+ "/files/a.pdf",
40
+ "/files/a.png#x",
41
+ ])("keeps other paths as data: %s", (image) => {
42
+ expect(fieldsFromRecord({ image })[0]?.fieldtype).toBe("Data");
43
+ });
29
44
  it("keeps a record's own scalar keys in server order", () => {
30
45
  expect(recordFieldKeys(record)).toEqual(["move_name", "power", "accuracy", "damage_class"]);
31
46
  });
@@ -53,7 +53,7 @@ export function recordKeyLabel(key: string): string {
53
53
 
54
54
  /**
55
55
  * The record's own fields as read-only doctype fields: Int or Float for a
56
- * number, Data for anything else.
56
+ * number, Attach Image for a Frappe image file, Data otherwise.
57
57
  */
58
58
  export function fieldsFromRecord(record: Record<string, unknown>): DocTypeField[] {
59
59
  return recordFieldKeys(record).map((key) => {
@@ -61,7 +61,15 @@ export function fieldsFromRecord(record: Record<string, unknown>): DocTypeField[
61
61
  return {
62
62
  fieldname: key,
63
63
  label: recordKeyLabel(key),
64
- fieldtype: typeof value === "number" ? (Number.isInteger(value) ? "Int" : "Float") : "Data",
64
+ fieldtype:
65
+ typeof value === "number"
66
+ ? Number.isInteger(value)
67
+ ? "Int"
68
+ : "Float"
69
+ : typeof value === "string" &&
70
+ /^\/(private\/)?files\/[^?#]+\.(png|jpe?g|gif|webp|svg)$/i.test(value)
71
+ ? "Attach Image"
72
+ : "Data",
65
73
  read_only: 1,
66
74
  };
67
75
  });
@@ -207,3 +207,85 @@ describe("a caller-owned FrappeForm", () => {
207
207
  expect(created).toMatchObject({ subject: "Scanner", priority: "Medium", status: "Open" });
208
208
  });
209
209
  });
210
+
211
+ describe("save single-flight", () => {
212
+ it.each([false, true])("shares an edit save and releases it after failure=%s", async (fail) => {
213
+ const fixtures = ticketFixtures();
214
+ let release!: () => void;
215
+ const persistence = new Promise<void>((resolve) => {
216
+ release = resolve;
217
+ });
218
+ const updateDoc = fixtures.updateDoc.bind(fixtures);
219
+ const mutate = vi.spyOn(fixtures, "updateDoc").mockImplementationOnce(async (...args) => {
220
+ await persistence;
221
+ if (fail) throw new Error("Persistence refused");
222
+ return updateDoc(...args);
223
+ });
224
+ renderWithProviders(
225
+ <FrappeProvider baseURL={`http://single-flight-${fail}.test`} fixtures={fixtures}>
226
+ <Host doctype="Desk Ticket" name="TICKET-1" />
227
+ </FrappeProvider>,
228
+ );
229
+ await expectProbe("subject", "val=Printer");
230
+ act(() => {
231
+ controller?.setValue("subject", "Scanner");
232
+ controller?.setValue("resolution", "Rebooted");
233
+ });
234
+ let first!: Promise<string | undefined>;
235
+ let second!: Promise<string | undefined>;
236
+ act(() => {
237
+ first = controller!.save();
238
+ second = controller!.save();
239
+ });
240
+ expect(second).toBe(first);
241
+ await waitFor(() => expect(mutate).toHaveBeenCalledTimes(1));
242
+ expect(controller?.isSubmitting).toBe(true);
243
+ await act(async () => {
244
+ release();
245
+ expect(await first).toBe(fail ? undefined : "TICKET-1");
246
+ });
247
+ expect(controller?.isSubmitting).toBe(false);
248
+ act(() => controller?.setValue("subject", "Another edit"));
249
+ await act(async () => {
250
+ const retry = controller!.save();
251
+ expect(retry).not.toBe(first);
252
+ expect(await retry).toBe("TICKET-1");
253
+ });
254
+ expect(mutate).toHaveBeenCalledTimes(2);
255
+ });
256
+
257
+ it("shares a create save until persistence assigns its name", async () => {
258
+ const fixtures = ticketFixtures();
259
+ let release!: () => void;
260
+ const persistence = new Promise<void>((resolve) => {
261
+ release = resolve;
262
+ });
263
+ const createDoc = fixtures.createDoc.bind(fixtures);
264
+ const mutate = vi.spyOn(fixtures, "createDoc").mockImplementationOnce(async (...args) => {
265
+ await persistence;
266
+ return createDoc(...args);
267
+ });
268
+ renderWithProviders(
269
+ <FrappeProvider baseURL="http://single-flight-create.test" fixtures={fixtures}>
270
+ <Host doctype="Desk Ticket" />
271
+ </FrappeProvider>,
272
+ );
273
+ await expectProbe("priority", "val=Medium");
274
+ act(() => {
275
+ controller?.setValue("subject", "Scanner");
276
+ controller?.setValue("resolution", "Rebooted");
277
+ });
278
+ let first!: Promise<string | undefined>;
279
+ let second!: Promise<string | undefined>;
280
+ act(() => {
281
+ first = controller!.save();
282
+ second = controller!.save();
283
+ });
284
+ expect(second).toBe(first);
285
+ await waitFor(() => expect(mutate).toHaveBeenCalledTimes(1));
286
+ await act(async () => {
287
+ release();
288
+ expect(await first).toBeTruthy();
289
+ });
290
+ });
291
+ });
@@ -229,6 +229,7 @@ export function useFrappeForm<TDoc extends { name: string; doctype: string }>(
229
229
  const [saveConflict, setSaveConflict] = useState(false);
230
230
  const [wasDeleted, setWasDeleted] = useState(false);
231
231
  const [isSubmitting, setIsSubmitting] = useState(false);
232
+ const saveInFlight = useRef<Promise<string | undefined> | undefined>(undefined);
232
233
  const [errors, setErrors] = useState<Record<string, string>>({});
233
234
  const [activeTab, setActiveTab] = useState<string | undefined>(undefined);
234
235
  const everLoadedRef = useRef(false);
@@ -552,7 +553,7 @@ export function useFrappeForm<TDoc extends { name: string; doctype: string }>(
552
553
 
553
554
  const canWrite = isCreate ? rights.create : rights.write;
554
555
 
555
- const save = async (): Promise<string | undefined> => {
556
+ const persist = async (): Promise<string | undefined> => {
556
557
  if (wasDeleted || !canWrite || disabled) return undefined;
557
558
 
558
559
  const requiredErrors = validate();
@@ -618,6 +619,17 @@ export function useFrappeForm<TDoc extends { name: string; doctype: string }>(
618
619
  }
619
620
  };
620
621
 
622
+ const save = (): Promise<string | undefined> => {
623
+ if (saveInFlight.current) return saveInFlight.current;
624
+ const promise = Promise.resolve()
625
+ .then(persist)
626
+ .finally(() => {
627
+ if (saveInFlight.current === promise) saveInFlight.current = undefined;
628
+ });
629
+ saveInFlight.current = promise;
630
+ return promise;
631
+ };
632
+
621
633
  const reset = () => {
622
634
  if (baselineDoc) {
623
635
  setLocalDoc(baselineDoc);
@@ -1 +1 @@
1
- {"version":3,"file":"FrappeReportBuilder.d.ts","sourceRoot":"","sources":["../src/FrappeReportBuilder.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAQL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAavC,OAAc,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA0B3C,KAAK,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC;IAC7E,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,EAAE,CAAC;IAClD;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;IACtD,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACxC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,yEAAyE;IACzE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,0CAA0C;IAC1C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC;IACrD,4CAA4C;IAC5C,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,oDAAoD;IACpD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAqID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAMlE;AA4nBD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC"}
1
+ {"version":3,"file":"FrappeReportBuilder.d.ts","sourceRoot":"","sources":["../src/FrappeReportBuilder.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAOL,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,+BAA+B,CAAC;AAavC,OAAc,EAA6C,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AA0B3C,KAAK,WAAW,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAE7C,MAAM,WAAW,wBAAyB,SAAQ,IAAI,CAAC,WAAW,EAAE,UAAU,CAAC;IAC7E,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,EAAE,CAAC;IAClD;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,qFAAqF;IACrF,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC;IACtD,oFAAoF;IACpF,cAAc,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;IACxC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6BAA6B;IAC7B,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,yEAAyE;IACzE,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACnE,0CAA0C;IAC1C,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,IAAI,CAAC;IACrD,4CAA4C;IAC5C,OAAO,CAAC,EAAE,SAAS,CAAC;IACpB,oDAAoD;IACpD,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,SAAS,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACvC;AAqID,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,2CAMlE;AAgoBD,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC"}
@@ -91,6 +91,8 @@ export interface FrappeTableProps<TDoc extends {
91
91
  * Requires onStateChange for state sync; fetches data based on table state.
92
92
  */
93
93
  serverSide?: boolean;
94
+ /** Infinite mode may omit totals when the host owns the count. */
95
+ fetchTotalCount?: boolean;
94
96
  /**
95
97
  * Callback when filters, sort, or pagination change.
96
98
  * Used for server-side fetches when serverSide is true.
@@ -184,5 +186,5 @@ export declare function filterValueToFrappeTuple(fieldname: string, filterValue:
184
186
  export declare function FrappeTable<TDoc extends {
185
187
  name: string;
186
188
  doctype: string;
187
- }>({ baseURL, auth, syncOptions, doctype, columns: columnsProp, fields, filters: initialFilters, onRowClick, loading, error, savedFilters, canCreateGlobalFilters, userId, serverSide, onStateChange: onStateChangeProp, refreshToken, paginationMode, loadPage: loadPageProp, filterableFields: filterableFieldsProp, rights: rightsProp, layout, initialState, ...dataTableProps }: FrappeTableProps<TDoc>): import("react/jsx-runtime").JSX.Element;
189
+ }>({ baseURL, auth, syncOptions, doctype, columns: columnsProp, fields, filters: initialFilters, onRowClick, loading, error, savedFilters, canCreateGlobalFilters, userId, serverSide, fetchTotalCount, onStateChange: onStateChangeProp, refreshToken, paginationMode, loadPage: loadPageProp, filterableFields: filterableFieldsProp, rights: rightsProp, layout, initialState, ...dataTableProps }: FrappeTableProps<TDoc>): import("react/jsx-runtime").JSX.Element;
188
190
  //# sourceMappingURL=FrappeTable.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"FrappeTable.d.ts","sourceRoot":"","sources":["../src/FrappeTable.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FrappeTable.d.ts","sourceRoot":"","sources":["../src/FrappeTable.tsx"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"listColumns.d.ts","sourceRoot":"","sources":["../../src/list/listColumns.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAO3E,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvC,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,CAAC,EAAE,SAAS,CAAC;IACb,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5D;AAwUD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,CAAC,EACD,WAAW,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,GACd,EAAE,oBAAoB,GAAG,eAAe,CAAC,OAAO,CAAC,EAAE,CAqFnD"}
1
+ {"version":3,"file":"listColumns.d.ts","sourceRoot":"","sources":["../../src/list/listColumns.tsx"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AACtE,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAO3E,6EAA6E;AAC7E,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvC,KAAK,SAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;AAE3D,MAAM,WAAW,oBAAoB;IACnC,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,CAAC,EAAE,SAAS,CAAC;IACb,iEAAiE;IACjE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,KAAK,IAAI,CAAC;IAC1D,wDAAwD;IACxD,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC;;;;;;;OAOG;IACH,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,0EAA0E;IAC1E,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IACtC;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5D;AAwUD,oEAAoE;AACpE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,CAAC,EACD,WAAW,EACX,YAAY,EACZ,aAAa,EACb,UAAU,EACV,UAAU,EACV,aAAa,GACd,EAAE,oBAAoB,GAAG,eAAe,CAAC,OAAO,CAAC,EAAE,CAsFnD"}
@@ -21,7 +21,7 @@ export declare function recordFieldKeys(record: Record<string, unknown>): string
21
21
  export declare function recordKeyLabel(key: string): string;
22
22
  /**
23
23
  * The record's own fields as read-only doctype fields: Int or Float for a
24
- * number, Data for anything else.
24
+ * number, Attach Image for a Frappe image file, Data otherwise.
25
25
  */
26
26
  export declare function fieldsFromRecord(record: Record<string, unknown>): DocTypeField[];
27
27
  export interface RecordShapeConnection {
@@ -1 +1 @@
1
- {"version":3,"file":"recordShape.d.ts","sourceRoot":"","sources":["../src/recordShape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAG3F,wFAAwF;AACxF,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAcpD,CAAC;AAMH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAOzE;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,EAAE,CAUhF;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;CACrD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,qBAAqB,GAAG,SAAS,EAC7C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GACf,WAAW,CAwCb"}
1
+ {"version":3,"file":"recordShape.d.ts","sourceRoot":"","sources":["../src/recordShape.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAG3F,wFAAwF;AACxF,eAAO,MAAM,qBAAqB,EAAE,WAAW,CAAC,MAAM,CAcpD,CAAC;AAMH;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,EAAE,CAOzE;AAED,sEAAsE;AACtE,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAElD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,YAAY,EAAE,CAkBhF;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,MAAM,EAAE,YAAY,EAAE,GAAG,SAAS,CAAC;IACnC;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC;CACrD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,qBAAqB,GAAG,SAAS,EAC7C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GACf,WAAW,CAwCb"}
@@ -1 +1 @@
1
- {"version":3,"file":"useFrappeForm.d.ts","sourceRoot":"","sources":["../src/useFrappeForm.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useFrappeForm.d.ts","sourceRoot":"","sources":["../src/useFrappeForm.ts"],"names":[],"mappings":"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"}