@lobb-js/studio 0.28.6 → 0.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.
Files changed (160) hide show
  1. package/README.md +1 -0
  2. package/dist/actions.d.ts +2 -0
  3. package/dist/components/Studio.svelte +46 -47
  4. package/dist/components/StudioRoot.svelte +19 -0
  5. package/dist/components/StudioRoot.svelte.d.ts +6 -0
  6. package/dist/components/breadCrumbs.svelte +5 -4
  7. package/dist/components/codeEditor.svelte +1 -1
  8. package/dist/components/combobox.svelte +3 -3
  9. package/dist/components/confirmationDialog/confirmationDialog.svelte +1 -1
  10. package/dist/components/dataTable/dataTable.svelte +108 -101
  11. package/dist/components/dataTable/dataTable.svelte.d.ts +5 -20
  12. package/dist/components/dataTable/dataTableTabs.svelte +4 -2
  13. package/dist/components/dataTable/dataTableTabs.svelte.d.ts +2 -0
  14. package/dist/components/dataTable/filter.svelte +1 -1
  15. package/dist/components/dataTable/filterButton.svelte +1 -1
  16. package/dist/components/dataTable/header.svelte +30 -47
  17. package/dist/components/dataTable/header.svelte.d.ts +4 -2
  18. package/dist/components/dataTable/listViewChildren.svelte +4 -6
  19. package/dist/components/dataTable/listViewChildren.svelte.d.ts +0 -1
  20. package/dist/components/dataTable/sort.svelte +1 -1
  21. package/dist/components/dataTable/sortButton.svelte +2 -2
  22. package/dist/components/dataTable/table.svelte +8 -10
  23. package/dist/components/dataTable/table.svelte.d.ts +0 -1
  24. package/dist/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
  25. package/dist/components/dataTableDrawer/dataTableDrawer.svelte.d.ts +2 -0
  26. package/dist/components/detailView/create/children.svelte +2 -2
  27. package/dist/components/detailView/create/createDetailView.svelte +81 -88
  28. package/dist/components/detailView/create/createDetailView.svelte.d.ts +2 -2
  29. package/dist/components/detailView/create/createDetailViewButton.svelte +2 -2
  30. package/dist/components/detailView/create/createDetailViewButton.svelte.d.ts +1 -1
  31. package/dist/components/detailView/create/createManyView.svelte +12 -10
  32. package/dist/components/detailView/detailView.svelte +81 -0
  33. package/dist/components/detailView/detailView.svelte.d.ts +8 -0
  34. package/dist/components/detailView/fieldInput.svelte +11 -11
  35. package/dist/components/detailView/fieldInputReplacement.svelte +8 -8
  36. package/dist/components/detailView/passwordInput.svelte +1 -1
  37. package/dist/components/detailView/update/detailViewChildren.svelte +15 -26
  38. package/dist/components/detailView/update/detailViewChildren.svelte.d.ts +3 -8
  39. package/dist/components/detailView/update/updateDetailView.svelte +90 -69
  40. package/dist/components/detailView/update/updateDetailView.svelte.d.ts +2 -2
  41. package/dist/components/detailView/update/updateDetailViewButton.svelte +3 -2
  42. package/dist/components/detailView/update/updateDetailViewButton.svelte.d.ts +1 -1
  43. package/dist/components/detailView/utils.d.ts +17 -0
  44. package/dist/components/diffViewer.svelte +1 -1
  45. package/dist/components/extensionsComponents.svelte +3 -1
  46. package/dist/components/foreingKeyInput.svelte +2 -2
  47. package/dist/components/importButton.svelte +12 -9
  48. package/dist/components/landing.svelte +7 -0
  49. package/dist/components/landing.svelte.d.ts +6 -14
  50. package/dist/components/miniSidebar.svelte +90 -19
  51. package/dist/components/miniSidebar.svelte.d.ts +2 -17
  52. package/dist/components/polymorphicInput.svelte +1 -1
  53. package/dist/components/rangeCalendarButton.svelte +13 -13
  54. package/dist/components/richTextEditor.svelte +1 -1
  55. package/dist/components/routes/collections/collection.svelte +3 -3
  56. package/dist/components/routes/collections/collections.svelte +34 -12
  57. package/dist/components/routes/data_model/dataModel.svelte +6 -28
  58. package/dist/components/routes/data_model/dataModel.svelte.d.ts +17 -2
  59. package/dist/components/routes/extensions/extension.svelte +1 -1
  60. package/dist/components/routes/extensions/publicExtension.svelte +19 -0
  61. package/dist/components/routes/extensions/publicExtension.svelte.d.ts +13 -0
  62. package/dist/components/routes/home.svelte +3 -3
  63. package/dist/components/routes/workflows/workflows.svelte +9 -9
  64. package/dist/components/selectRecord.svelte +2 -21
  65. package/dist/components/setServerPage.svelte +1 -1
  66. package/dist/components/sidebar/sidebar.svelte +1 -1
  67. package/dist/components/sidebar/sidebarElements.svelte +4 -4
  68. package/dist/components/singletone.svelte +4 -6
  69. package/dist/components/ui/alert-dialog/alert-dialog-action.svelte +1 -1
  70. package/dist/components/ui/alert-dialog/alert-dialog-cancel.svelte +1 -1
  71. package/dist/components/ui/button/button.svelte +2 -3
  72. package/dist/components/ui/command/command-dialog.svelte +1 -1
  73. package/dist/components/ui/range-calendar/range-calendar-day.svelte +1 -1
  74. package/dist/components/ui/range-calendar/range-calendar-next-button.svelte +1 -1
  75. package/dist/components/ui/range-calendar/range-calendar-prev-button.svelte +1 -1
  76. package/dist/components/ui/select/select-separator.svelte +1 -1
  77. package/dist/components/workflowEditor.svelte +5 -5
  78. package/dist/eventSystem.d.ts +1 -1
  79. package/dist/eventSystem.js +7 -5
  80. package/dist/extensions/extension.types.d.ts +38 -14
  81. package/dist/extensions/extensionUtils.js +4 -2
  82. package/dist/index.d.ts +3 -1
  83. package/dist/index.js +3 -1
  84. package/dist/store.types.d.ts +2 -2
  85. package/dist/studioLifecycle.svelte.d.ts +2 -0
  86. package/dist/studioLifecycle.svelte.js +15 -0
  87. package/package.json +3 -4
  88. package/src/app.css +3 -0
  89. package/src/lib/actions.ts +2 -0
  90. package/src/lib/components/Studio.svelte +46 -47
  91. package/src/lib/components/StudioRoot.svelte +19 -0
  92. package/src/lib/components/breadCrumbs.svelte +5 -4
  93. package/src/lib/components/codeEditor.svelte +1 -1
  94. package/src/lib/components/combobox.svelte +3 -3
  95. package/src/lib/components/confirmationDialog/confirmationDialog.svelte +1 -1
  96. package/src/lib/components/dataTable/dataTable.svelte +108 -101
  97. package/src/lib/components/dataTable/dataTableTabs.svelte +4 -2
  98. package/src/lib/components/dataTable/filter.svelte +1 -1
  99. package/src/lib/components/dataTable/filterButton.svelte +1 -1
  100. package/src/lib/components/dataTable/header.svelte +30 -47
  101. package/src/lib/components/dataTable/listViewChildren.svelte +4 -6
  102. package/src/lib/components/dataTable/sort.svelte +1 -1
  103. package/src/lib/components/dataTable/sortButton.svelte +2 -2
  104. package/src/lib/components/dataTable/table.svelte +8 -10
  105. package/src/lib/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
  106. package/src/lib/components/detailView/create/children.svelte +2 -2
  107. package/src/lib/components/detailView/create/createDetailView.svelte +81 -88
  108. package/src/lib/components/detailView/create/createDetailViewButton.svelte +2 -2
  109. package/src/lib/components/detailView/create/createManyView.svelte +12 -10
  110. package/src/lib/components/detailView/detailView.svelte +81 -0
  111. package/src/lib/components/detailView/fieldInput.svelte +11 -11
  112. package/src/lib/components/detailView/fieldInputReplacement.svelte +8 -8
  113. package/src/lib/components/detailView/passwordInput.svelte +1 -1
  114. package/src/lib/components/detailView/update/detailViewChildren.svelte +15 -26
  115. package/src/lib/components/detailView/update/updateDetailView.svelte +90 -69
  116. package/src/lib/components/detailView/update/updateDetailViewButton.svelte +3 -2
  117. package/src/lib/components/detailView/utils.ts +13 -0
  118. package/src/lib/components/diffViewer.svelte +1 -1
  119. package/src/lib/components/extensionsComponents.svelte +3 -1
  120. package/src/lib/components/foreingKeyInput.svelte +2 -2
  121. package/src/lib/components/importButton.svelte +12 -9
  122. package/src/lib/components/landing.svelte +7 -0
  123. package/src/lib/components/miniSidebar.svelte +90 -19
  124. package/src/lib/components/polymorphicInput.svelte +1 -1
  125. package/src/lib/components/rangeCalendarButton.svelte +13 -13
  126. package/src/lib/components/richTextEditor.svelte +1 -1
  127. package/src/lib/components/routes/collections/collection.svelte +3 -3
  128. package/src/lib/components/routes/collections/collections.svelte +34 -12
  129. package/src/lib/components/routes/data_model/dataModel.svelte +6 -28
  130. package/src/lib/components/routes/extensions/extension.svelte +1 -1
  131. package/src/lib/components/routes/extensions/publicExtension.svelte +19 -0
  132. package/src/lib/components/routes/home.svelte +3 -3
  133. package/src/lib/components/routes/workflows/workflows.svelte +9 -9
  134. package/src/lib/components/selectRecord.svelte +2 -21
  135. package/src/lib/components/setServerPage.svelte +1 -1
  136. package/src/lib/components/sidebar/sidebar.svelte +1 -1
  137. package/src/lib/components/sidebar/sidebarElements.svelte +4 -4
  138. package/src/lib/components/singletone.svelte +4 -6
  139. package/src/lib/components/ui/alert-dialog/alert-dialog-action.svelte +1 -1
  140. package/src/lib/components/ui/alert-dialog/alert-dialog-cancel.svelte +1 -1
  141. package/src/lib/components/ui/button/button.svelte +2 -3
  142. package/src/lib/components/ui/command/command-dialog.svelte +1 -1
  143. package/src/lib/components/ui/range-calendar/range-calendar-day.svelte +1 -1
  144. package/src/lib/components/ui/range-calendar/range-calendar-next-button.svelte +1 -1
  145. package/src/lib/components/ui/range-calendar/range-calendar-prev-button.svelte +1 -1
  146. package/src/lib/components/ui/select/select-separator.svelte +1 -1
  147. package/src/lib/components/workflowEditor.svelte +5 -5
  148. package/src/lib/eventSystem.ts +8 -7
  149. package/src/lib/extensions/extension.types.ts +39 -6
  150. package/src/lib/extensions/extensionUtils.ts +4 -2
  151. package/src/lib/index.ts +3 -1
  152. package/src/lib/store.types.ts +2 -2
  153. package/src/lib/studioLifecycle.svelte.ts +17 -0
  154. package/vite-plugins/index.js +2 -4
  155. package/vite-plugins/utils.js +15 -0
  156. package/vite-plugins/{workspace-optimize.js → workspace-fs-allow.js} +4 -18
  157. package/dist/components/routes/data_model/syncManager.svelte +0 -94
  158. package/dist/components/routes/data_model/syncManager.svelte.d.ts +0 -3
  159. package/src/lib/components/routes/data_model/syncManager.svelte +0 -94
  160. package/vite-plugins/contextual-lib-alias.js +0 -67
@@ -1,6 +1,8 @@
1
+ import type { CollectionTab } from "../../store.types";
1
2
  interface Props {
2
3
  collectionName: string;
3
4
  filter?: any;
5
+ tabs?: CollectionTab[];
4
6
  activeTabFilter?: any;
5
7
  }
6
8
  declare const DataTableTabs: import("svelte").Component<Props, {}, "activeTabFilter">;
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import * as Popover from "../../components/ui/popover/index.js";
2
+ import * as Popover from "../ui/popover/index.js";
3
3
  import Filter from "./filter.svelte";
4
4
  import {
5
5
  Plus,
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import * as Popover from "../../components/ui/popover/index.js";
2
+ import * as Popover from "../ui/popover/index.js";
3
3
  import { ListFilter } from "lucide-svelte";
4
4
  import { buttonVariants } from "../ui/button";
5
5
  import Filter from "./filter.svelte";
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { getStudioContext } from "../../context";
3
-
4
- const { lobb, ctx } = getStudioContext();
3
+ import type { Changes, ChildrenChanges } from "../detailView/utils";
4
+ import type { ParentContext } from "./dataTable.svelte";
5
5
  import { Download, ListRestart, Plus, Trash, Link } from "lucide-svelte";
6
6
  import * as Tooltip from "../ui/tooltip";
7
7
  import LlmButton from "../LlmButton.svelte";
@@ -15,15 +15,17 @@
15
15
  import ExtensionsComponents from "../extensionsComponents.svelte";
16
16
  import { getExtensionUtils } from "../../extensions/extensionUtils";
17
17
  import type { Snippet } from "svelte";
18
- import type { ParentContext, RecordOperation } from "./dataTable.svelte";
18
+
19
+ const { lobb, ctx } = getStudioContext();
19
20
 
20
21
  interface Props {
21
22
  collectionName: string;
22
23
  params: any;
23
24
  selectedRecords: string[];
24
25
  parentContext?: ParentContext;
25
- onOperation?: (op: RecordOperation) => void;
26
+ changes?: ChildrenChanges;
26
27
  showImport?: boolean;
28
+ showCreate?: boolean;
27
29
  left?: Snippet<[]>;
28
30
  }
29
31
 
@@ -32,37 +34,28 @@
32
34
  params = $bindable(),
33
35
  selectedRecords = $bindable(),
34
36
  parentContext,
35
- onOperation,
37
+ changes,
36
38
  showImport = true,
39
+ showCreate = false,
37
40
  left
38
41
  }: Props = $props();
39
42
 
40
- async function handleLink(selected: any) {
41
- if (!parentContext) return;
42
- if (onOperation) {
43
- onOperation({ type: "link", record: selected });
44
- } else {
45
- await lobb.updateOne(
46
- parentContext.collectionName,
47
- String(parentContext.recordId),
48
- {},
49
- { [collectionName]: { link: [selected.id] } },
50
- );
43
+ // Local changes object for the create form (recording mode only)
44
+ let createChanges = $state<Changes>({ data: {}, children: {} });
45
+
46
+ function handleLink(record: any) {
47
+ if (changes) {
48
+ changes.linked.push(record);
49
+ } else if (parentContext) {
50
+ lobb.updateOne(parentContext.collectionName, String(parentContext.recordId), {}, { [collectionName]: { link: [record.id] } });
51
51
  resetTable();
52
52
  }
53
53
  }
54
54
 
55
- async function handleChildCreate(formData: any) {
56
- if (!parentContext) return;
57
- if (onOperation) {
58
- onOperation({ type: "create", record: formData });
55
+ async function handleCreateSuccess(snap: any) {
56
+ if (changes) {
57
+ changes.created.push({ data: snap.data });
59
58
  } else {
60
- await lobb.updateOne(
61
- parentContext.collectionName,
62
- String(parentContext.recordId),
63
- {},
64
- { [collectionName]: { create: [formData] } },
65
- );
66
59
  resetTable();
67
60
  }
68
61
  }
@@ -176,7 +169,7 @@
176
169
  >
177
170
  {headerIsSmall ? "" : "Refresh"}
178
171
  </Button>
179
- {#if showImport}
172
+ {#if showImport && showCreate}
180
173
  <Tooltip.Provider delayDuration={0}>
181
174
  <Tooltip.Root>
182
175
  <Tooltip.Trigger>
@@ -199,34 +192,24 @@
199
192
  refresh={() => { params = { ...params }; }}
200
193
  />
201
194
  {#if parentContext}
202
- {#if parentContext}
203
- <SelectRecord
204
- {collectionName}
205
- variant="outline"
206
- class="h-7 px-3 text-xs font-normal"
207
- Icon={Link}
208
- onSelect={handleLink}
209
- >
210
- {headerIsSmall ? "" : "Link"}
211
- </SelectRecord>
212
- {/if}
213
- <CreateDetailViewButton
195
+ <SelectRecord
214
196
  {collectionName}
215
- variant="default"
197
+ variant="outline"
216
198
  class="h-7 px-3 text-xs font-normal"
217
- Icon={Plus}
218
- rollback={true}
219
- onSuccessfullSave={handleChildCreate}
199
+ Icon={Link}
200
+ onSelect={handleLink}
220
201
  >
221
- {headerIsSmall ? "" : "Create"}
222
- </CreateDetailViewButton>
223
- {:else}
202
+ {headerIsSmall ? "" : "Link"}
203
+ </SelectRecord>
204
+ {/if}
205
+ {#if showCreate}
224
206
  <CreateDetailViewButton
225
207
  {collectionName}
226
208
  variant="default"
227
209
  class="h-7 px-3 text-xs font-normal"
228
210
  Icon={Plus}
229
- onSuccessfullSave={() => (params = { ...params })}
211
+ changes={changes ? createChanges : undefined}
212
+ onSuccessfullSave={handleCreateSuccess}
230
213
  >
231
214
  {headerIsSmall ? "" : "Create"}
232
215
  </CreateDetailViewButton>
@@ -1,12 +1,14 @@
1
+ import type { ChildrenChanges } from "../detailView/utils";
2
+ import type { ParentContext } from "./dataTable.svelte";
1
3
  import type { Snippet } from "svelte";
2
- import type { ParentContext, RecordOperation } from "./dataTable.svelte";
3
4
  interface Props {
4
5
  collectionName: string;
5
6
  params: any;
6
7
  selectedRecords: string[];
7
8
  parentContext?: ParentContext;
8
- onOperation?: (op: RecordOperation) => void;
9
+ changes?: ChildrenChanges;
9
10
  showImport?: boolean;
11
+ showCreate?: boolean;
10
12
  left?: Snippet<[]>;
11
13
  }
12
14
  declare const Header: import("svelte").Component<Props, {}, "selectedRecords" | "params">;
@@ -12,10 +12,9 @@
12
12
  collectionName: string;
13
13
  recordId: string;
14
14
  width: number;
15
- unifiedBgColor?: "bg-muted/30" | "bg-background";
16
15
  }
17
16
 
18
- let { collectionName, recordId, width, unifiedBgColor }: Props = $props();
17
+ let { collectionName, recordId, width }: Props = $props();
19
18
 
20
19
  const children = (ctx.meta.collections[collectionName]?.children ?? [])
21
20
  .filter((c: any) => c.type === "fk" || c.type === "m2m" || c.type === "polymorphic");
@@ -27,13 +26,13 @@
27
26
 
28
27
  <div class="flex" style="width: {width}px;">
29
28
  <div
30
- class="flex justify-center border-r {unifiedBgColor ? unifiedBgColor : 'bg-background'}"
29
+ class="flex justify-center border-r bg-background"
31
30
  style="width: 40px"
32
31
  ></div>
33
32
  <div class="flex-1 flex flex-col">
34
33
  {#each children as child, index}
35
34
  {@const lastRow = children.length - 1 === index}
36
- <div class="overflow-hidden {unifiedBgColor ? unifiedBgColor : 'bg-background'}">
35
+ <div class="overflow-hidden bg-background">
37
36
  <div
38
37
  bind:clientWidth={tableHeaderWidth}
39
38
  class="flex justify-between items-center gap-2 text-sm h-10 {expandedRows[index] || !lastRow ? 'border-b' : ''}"
@@ -75,7 +74,7 @@
75
74
  {#if expandedRows[index]}
76
75
  <div class="flex max-h-96 overflow-auto {lastRow ? '' : 'border-b'}">
77
76
  <div
78
- class="border-r {unifiedBgColor ? unifiedBgColor : ''}"
77
+ class="border-r"
79
78
  style="width: 100vw; max-width: 40px"
80
79
  ></div>
81
80
  <div class="flex-1" style="width: {tableHeaderWidth - 40}px;">
@@ -92,7 +91,6 @@
92
91
  showHeader={false}
93
92
  showFooter={false}
94
93
  showDelete={child.type === "fk"}
95
- {unifiedBgColor}
96
94
  tableProps={{ showLastRowBorder: false, showLastColumnBorder: false, showCheckboxes: false }}
97
95
  />
98
96
  </ExtensionsComponents>
@@ -2,7 +2,6 @@ interface Props {
2
2
  collectionName: string;
3
3
  recordId: string;
4
4
  width: number;
5
- unifiedBgColor?: "bg-muted/30" | "bg-background";
6
5
  }
7
6
  declare const ListViewChildren: import("svelte").Component<Props, {}, "">;
8
7
  type ListViewChildren = ReturnType<typeof ListViewChildren>;
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import * as _ from "lodash-es";
3
3
 
4
- import * as Popover from "../../components/ui/popover/index.js";
4
+ import * as Popover from "../ui/popover/index.js";
5
5
  import { ArrowDown, ArrowUp, GripVertical, Plus, X } from "lucide-svelte";
6
6
  import Button, { buttonVariants } from "../ui/button/button.svelte";
7
7
  import Label from "../ui/label/label.svelte";
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
- import * as Popover from "../../components/ui/popover/index.js";
2
+ import * as Popover from "../ui/popover/index.js";
3
3
  import { ArrowDownWideNarrow } from "lucide-svelte";
4
- import { buttonVariants } from "../../components/ui/button";
4
+ import { buttonVariants } from "../ui/button";
5
5
  import Sort from "./sort.svelte";
6
6
 
7
7
  interface Props {
@@ -38,7 +38,6 @@
38
38
 
39
39
  // other
40
40
  parentWidth?: number;
41
- unifiedBgColor?: "bg-muted/30" | "bg-background";
42
41
  select?: Select;
43
42
  tableWidth?: number;
44
43
  }
@@ -77,7 +76,6 @@
77
76
  tools,
78
77
  rowActions,
79
78
  collapsible,
80
- unifiedBgColor,
81
79
  select,
82
80
  tableWidth = $bindable(),
83
81
  }: TableProps = $props();
@@ -184,7 +182,7 @@
184
182
  flex items-center p-2.5 text-xs h-10
185
183
  border-r border-b gap-2
186
184
  {headerBorderTop ? 'border-t' : ''}
187
- {unifiedBgColor ? unifiedBgColor : 'bg-muted'}
185
+ bg-muted-soft
188
186
  "
189
187
  >
190
188
  <!-- collapsable toggle -->
@@ -209,7 +207,7 @@
209
207
  class="
210
208
  sticky top-0 z-10
211
209
  flex items-center p-2.5 text-xs h-10
212
- {unifiedBgColor ? unifiedBgColor : 'bg-muted'}
210
+ bg-muted-soft
213
211
  {lastColumn && !showLastColumnBorder ? '' : 'border-r'}
214
212
  border-b gap-2
215
213
  {headerBorderTop ? 'border-t' : ''}
@@ -236,7 +234,7 @@
236
234
  class="
237
235
  sticky top-0 right-0 z-20
238
236
  flex items-center p-2.5 h-10
239
- {unifiedBgColor ? unifiedBgColor : 'bg-muted'}
237
+ bg-muted-soft
240
238
  border-l border-b
241
239
  {headerBorderTop ? 'border-t' : ''}
242
240
  "
@@ -251,7 +249,7 @@
251
249
  class="
252
250
  sticky left-0
253
251
  flex items-center p-2.5 text-xs h-10
254
- {unifiedBgColor ? unifiedBgColor : 'bg-background'}
252
+ bg-background
255
253
  border-r gap-2
256
254
  "
257
255
  >
@@ -298,7 +296,7 @@
298
296
  class="
299
297
  flex items-center p-2.5 text-xs h-10 text-nowrap overflow-clip
300
298
  {select ? 'cursor-pointer' : ''}
301
- {unifiedBgColor ? unifiedBgColor : 'bg-background'}
299
+ bg-background
302
300
  {lastColumn && !showLastColumnBorder ? '' : 'border-r'}
303
301
  "
304
302
  >
@@ -315,7 +313,7 @@
315
313
  sticky right-0 z-10
316
314
  flex items-center p-2.5 text-xs h-10
317
315
  border-l gap-2
318
- {unifiedBgColor ? unifiedBgColor : 'bg-background'}
316
+ bg-background
319
317
  "
320
318
  >
321
319
  {@render rowActions?.(entry, index)}
@@ -336,8 +334,8 @@
336
334
  {expandedRows[index] ? '' : 'height: 0px;'}
337
335
  "
338
336
  class="
339
- sticky left-0 top-0 overflow-auto bg-muted/30
340
- {unifiedBgColor ? unifiedBgColor : ''}
337
+ sticky left-0 top-0 overflow-auto bg-muted-soft
338
+
341
339
  {expandedRows[index] ? 'border-t' : ''}
342
340
  "
343
341
  >
@@ -24,7 +24,6 @@ export interface TableProps {
24
24
  rowActions?: Snippet<[Entry, number]>;
25
25
  collapsible?: Snippet<[Entry, number]>;
26
26
  parentWidth?: number;
27
- unifiedBgColor?: "bg-muted/30" | "bg-background";
28
27
  select?: Select;
29
28
  tableWidth?: number;
30
29
  }
@@ -4,6 +4,7 @@
4
4
  import DataTable from "../dataTable/dataTable.svelte";
5
5
  import Drawer from "../drawer.svelte";
6
6
  import type { TableProps } from "../dataTable/table.svelte";
7
+ import type { CollectionTab } from "../../store.types";
7
8
 
8
9
  interface Props {
9
10
  collectionName: string;
@@ -13,6 +14,7 @@
13
14
  showFooter?: boolean;
14
15
  tableProps?: Partial<TableProps>;
15
16
  position?: "side" | "bottom";
17
+ tabs?: CollectionTab[];
16
18
  onClose?: () => void;
17
19
  }
18
20
 
@@ -24,6 +26,7 @@
24
26
  showFooter = true,
25
27
  tableProps,
26
28
  position = "side",
29
+ tabs,
27
30
  onClose,
28
31
  }: Props = $props();
29
32
  </script>
@@ -47,7 +50,7 @@
47
50
  {showHeader}
48
51
  {showFooter}
49
52
  {tableProps}
50
- unifiedBgColor="bg-background"
53
+ {tabs}
51
54
  />
52
55
  </div>
53
56
  </Drawer>
@@ -1,4 +1,5 @@
1
1
  import type { TableProps } from "../dataTable/table.svelte";
2
+ import type { CollectionTab } from "../../store.types";
2
3
  interface Props {
3
4
  collectionName: string;
4
5
  filter?: Record<string, any>;
@@ -7,6 +8,7 @@ interface Props {
7
8
  showFooter?: boolean;
8
9
  tableProps?: Partial<TableProps>;
9
10
  position?: "side" | "bottom";
11
+ tabs?: CollectionTab[];
10
12
  onClose?: () => void;
11
13
  }
12
14
  declare const DataTableDrawer: import("svelte").Component<Props, {}, "">;
@@ -2,7 +2,7 @@
2
2
  import { getStudioContext } from "../../../context";
3
3
  import { Link } from "lucide-svelte";
4
4
  import CreateManyView from "./createManyView.svelte";
5
- import ExtensionsComponents from "../../../components/extensionsComponents.svelte";
5
+ import ExtensionsComponents from "../../extensionsComponents.svelte";
6
6
  import { getExtensionUtils } from "../../../extensions/extensionUtils";
7
7
 
8
8
  const { ctx, lobb } = getStudioContext();
@@ -37,7 +37,7 @@
37
37
  parentCollectionName={collectionName}
38
38
  collectionName={child.collection}
39
39
  parentRecord={{ id: entry.id, collectionName }}
40
- class="bg-muted/30 border rounded-md overflow-hidden"
40
+ class="bg-muted-soft border rounded-md overflow-hidden"
41
41
  bind:value={entry[child.collection]}
42
42
  >
43
43
  <CreateManyView
@@ -8,114 +8,142 @@
8
8
  collectionName: string;
9
9
  values?: Record<string, any>;
10
10
  showRelatedRecords?: boolean;
11
- rollback?: boolean;
12
11
  submitButton?: SubmitButton;
13
12
  title?: Snippet<[string]>;
14
13
  onSuccessfullSave?: (entry: any) => Promise<void>;
15
14
  onCancel?: () => Promise<void>;
15
+ changes?: import("../utils").Changes | undefined;
16
16
  }
17
17
  </script>
18
18
 
19
19
  <script lang="ts">
20
20
  import { ArrowLeft, Plus, X } from "lucide-svelte";
21
- import Button from "../../../components/ui/button/button.svelte";
21
+ import Button from "../../ui/button/button.svelte";
22
22
  import { getStudioContext } from "../../../context";
23
23
  import { toast } from "svelte-sonner";
24
+ import { untrack } from "svelte";
24
25
 
25
26
  const { lobb, ctx } = getStudioContext();
26
- import ExtensionsComponents from "../../extensionsComponents.svelte";
27
- import { getExtensionUtils } from "../../../extensions/extensionUtils";
28
- import { getField, getFieldIcon } from "../../dataTable/utils";
29
27
  import Children from "./children.svelte";
30
- import {
31
- buildChildren,
32
- getDefaultEntry,
33
- } from "../utils";
28
+ import { buildChildren, getDefaultEntry } from "../utils";
29
+ import type { Changes } from "../utils";
34
30
  import { getChangedProperties } from "../../../utils";
35
31
  import type { Snippet } from "svelte";
36
- import FieldInput from "../fieldInput.svelte";
37
- import { emitEvent } from "../../../eventSystem";
38
- import Drawer from "../../../components/drawer.svelte";
32
+ import DetailView from "../detailView.svelte";
33
+ import Drawer from "../../drawer.svelte";
39
34
 
40
35
  let {
41
36
  collectionName,
42
- values = {},
37
+ values: passedValues = {} as Record<string, any>,
43
38
  showRelatedRecords = true,
44
- rollback = false,
45
39
  onCancel,
46
40
  onSuccessfullSave,
47
41
  title,
48
42
  submitButton,
43
+ changes: passedChanges = $bindable<Changes | undefined>(undefined),
49
44
  }: CreateDetailViewProp = $props();
50
45
 
46
+ const isRecordingMode = passedChanges !== undefined;
47
+ if (!isRecordingMode) passedChanges = { data: {}, children: {} };
48
+ const changes = passedChanges as Changes;
49
+
51
50
  const fieldNames = Object.keys(ctx.meta.collections[collectionName].fields);
52
- let entry: Record<string, any> = $state(
53
- getDefaultEntry(ctx, fieldNames, collectionName, values),
54
- );
55
- const initialEntry = $state.snapshot(entry);
51
+ let values = $state(getDefaultEntry(ctx, fieldNames, collectionName, passedValues));
56
52
  let fieldsErrors: Record<string, any> = $state({});
57
- const subCollections = ctx.meta.relations.filter((relation) => relation.to.collection === collectionName).map((relation) => relation.from.collection);
53
+
54
+ const childCollections = ctx.meta.relations
55
+ .filter((r) => r.to.collection === collectionName)
56
+ .map((r) => (r as any).from.collection);
57
+
58
58
  const subCollectionsValues: Record<string, any> = {};
59
- for (let index = 0; index < subCollections.length; index++) {
60
- const subCollection = subCollections[index];
61
- if (values[subCollection]) {
62
- subCollectionsValues[subCollection] = values[subCollection];
63
- }
59
+ for (const col of childCollections) {
60
+ if (passedValues[col]) subCollectionsValues[col] = passedValues[col];
64
61
  }
65
62
 
66
- async function handleSave() {
67
- let localEntry = getChangedProperties(initialEntry, $state.snapshot(entry));
63
+ $effect(() => {
64
+ const snap = $state.snapshot(values);
68
65
 
69
- await emitEvent({ lobb, ctx }, "studio.collections.preCreate", {
70
- collectionName,
71
- entry: localEntry,
72
- });
66
+ untrack(() => {
67
+ const data: Record<string, any> = {};
68
+ const children: Record<string, any> = {};
73
69
 
74
- // remove empty children records data
75
- for (const [key, value] of Object.entries(localEntry)) {
76
- if (Array.isArray(value) && !value.length) {
77
- delete localEntry[key];
70
+ for (const [key, value] of Object.entries(snap)) {
71
+ if (childCollections.includes(key) && Array.isArray(value)) {
72
+ children[key] = {
73
+ created: (value as any[]).filter((r) => !r.id).map((r) => ({ data: r })),
74
+ updated: [],
75
+ deleted: [],
76
+ linked: (value as any[]).filter((r) => r.id).map((r) => r.id),
77
+ unlinked: [],
78
+ };
79
+ } else if (value !== null && value !== undefined && value !== '') {
80
+ data[key] = value;
81
+ }
78
82
  }
79
- }
80
83
 
81
- if (rollback) {
82
- if (onSuccessfullSave) await onSuccessfullSave(localEntry);
83
- onCancel?.();
84
- return;
84
+ changes.data = data;
85
+ changes.children = children;
86
+
87
+ if (!isRecordingMode) {
88
+ console.log(`[${collectionName}] changes:`, $state.snapshot(changes));
89
+ }
90
+ });
91
+ });
92
+
93
+ function handleCancel() {
94
+ if (isRecordingMode) {
95
+ changes.data = {};
96
+ changes.children = {};
85
97
  }
98
+ onCancel?.();
99
+ }
86
100
 
87
- const children = buildChildren(ctx, collectionName, localEntry);
88
- const response = await lobb.createOne(collectionName, localEntry, children);
101
+ async function handleSave() {
102
+ const snap = $state.snapshot(changes);
89
103
 
90
- await emitEvent({ lobb, ctx }, "studio.collections.create", {
91
- collectionName,
92
- entry: localEntry,
93
- response: response,
94
- });
104
+ const children = buildChildren(ctx, collectionName, { ...snap.data, ...Object.fromEntries(
105
+ Object.entries(snap.children).map(([col, ops]) => [
106
+ col,
107
+ [
108
+ ...(ops.created.map((op) => op.data)),
109
+ ...(ops.linked.map((id) => ({ id }))),
110
+ ]
111
+ ])
112
+ )});
113
+
114
+ const response = await lobb.createOne(collectionName, snap.data, children, undefined, isRecordingMode);
115
+
116
+ if (response.status === 204) {
117
+ if (onSuccessfullSave) await onSuccessfullSave(snap);
118
+ toast.success(`The record was successfully created`);
119
+ handleCancel();
120
+ return;
121
+ }
95
122
 
96
123
  if (!response.bodyUsed) {
97
- let result = await response.json();
124
+ const result = await response.json();
98
125
  if (response.status >= 400) {
99
126
  if (result.message && result.details) {
100
127
  fieldsErrors = result.details;
101
128
  return;
102
129
  } else if (result.message) {
130
+ toast.error(result.message);
103
131
  return;
104
132
  }
105
133
  }
106
134
  }
107
135
 
108
- if (onSuccessfullSave) await onSuccessfullSave(localEntry);
136
+ if (onSuccessfullSave) await onSuccessfullSave(snap);
109
137
  toast.success(`The record was successfully created`);
110
138
  onCancel?.();
111
139
  }
112
140
  </script>
113
141
 
114
- <Drawer onHide={onCancel}>
142
+ <Drawer onHide={handleCancel}>
115
143
  <div class="flex h-12 items-center gap-4 border-b px-4">
116
144
  <Button
117
145
  variant="outline"
118
- onclick={onCancel}
146
+ onclick={handleCancel}
119
147
  class=" h-8 w-8 rounded-full text-xs font-normal"
120
148
  Icon={ArrowLeft}
121
149
  ></Button>
@@ -131,51 +159,16 @@
131
159
  </div>
132
160
  </div>
133
161
  <div class="flex-1 overflow-y-auto">
134
- <div class="flex flex-col gap-4 p-4">
135
- {#each fieldNames as fieldName}
136
- {#if !ctx.meta.collections[collectionName].fields[fieldName]?.ui?.hidden}
137
- {@const field = getField(ctx, fieldName, collectionName)}
138
- {@const FieldIcon = getFieldIcon(ctx, fieldName, collectionName)}
139
- <div class="flex flex-col gap-2">
140
- <div class="flex flex-1 items-end justify-between gap-2 text-xs">
141
- <div class="flex gap-2">
142
- <div class="h-fit">{field.label}</div>
143
- <div class="flex h-fit items-center gap-1 text-[0.7rem] text-muted-foreground">
144
- <FieldIcon size="12" />
145
- {field.type}
146
- </div>
147
- </div>
148
- <div>
149
- <ExtensionsComponents
150
- name="dvFields.topRight.{collectionName}.{fieldName}"
151
- utils={getExtensionUtils(lobb, ctx)}
152
- bind:value={entry[fieldName]}
153
- />
154
- </div>
155
- </div>
156
- <FieldInput
157
- {collectionName}
158
- {fieldName}
159
- bind:value={
160
- () => entry[fieldName],
161
- (v) => (entry = { ...entry, [fieldName]: v })
162
- }
163
- bind:entry
164
- errorMessages={fieldsErrors[fieldName]}
165
- />
166
- </div>
167
- {/if}
168
- {/each}
169
- </div>
162
+ <DetailView {collectionName} bind:entry={values} {fieldsErrors} />
170
163
  {#if showRelatedRecords}
171
- <Children {collectionName} values={subCollectionsValues} bind:entry />
164
+ <Children {collectionName} values={subCollectionsValues} bind:entry={values} />
172
165
  {/if}
173
166
  </div>
174
167
  <div class="flex h-12 items-center justify-end gap-2 border-t px-4">
175
168
  <div class="flex gap-3">
176
169
  <Button
177
170
  variant="outline"
178
- onclick={onCancel}
171
+ onclick={handleCancel}
179
172
  class="h-7 px-3 text-xs font-normal"
180
173
  Icon={X}
181
174
  >