@lobb-js/studio 0.42.0 → 0.43.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.
Files changed (32) hide show
  1. package/dist/components/confirmationDialog/confirmationDialog.svelte +1 -1
  2. package/dist/components/dataTable/dataTable.svelte +42 -16
  3. package/dist/components/dataTable/listViewChildren.svelte +60 -77
  4. package/dist/components/dataTable/listViewChildren.svelte.d.ts +1 -1
  5. package/dist/components/dataTable/table.svelte +8 -56
  6. package/dist/components/dataTable/table.svelte.d.ts +1 -2
  7. package/dist/components/detailView/changeTreeUtils.d.ts +7 -0
  8. package/dist/components/detailView/changeTreeUtils.js +47 -0
  9. package/dist/components/detailView/create/createDetailView.svelte +17 -13
  10. package/dist/components/detailView/detailView.svelte +7 -2
  11. package/dist/components/detailView/detailView.svelte.d.ts +1 -0
  12. package/dist/components/detailView/fieldInput.svelte +10 -9
  13. package/dist/components/detailView/fieldInput.svelte.d.ts +1 -0
  14. package/dist/components/detailView/update/updateDetailView.svelte +22 -18
  15. package/dist/components/drawer.svelte +15 -2
  16. package/dist/components/foreingKeyInput.svelte +163 -68
  17. package/dist/components/foreingKeyInput.svelte.d.ts +1 -1
  18. package/dist/components/polymorphicInput.svelte +112 -63
  19. package/dist/components/polymorphicInput.svelte.d.ts +1 -0
  20. package/package.json +2 -2
  21. package/src/lib/components/confirmationDialog/confirmationDialog.svelte +1 -1
  22. package/src/lib/components/dataTable/dataTable.svelte +42 -16
  23. package/src/lib/components/dataTable/listViewChildren.svelte +60 -77
  24. package/src/lib/components/dataTable/table.svelte +8 -56
  25. package/src/lib/components/detailView/changeTreeUtils.ts +39 -0
  26. package/src/lib/components/detailView/create/createDetailView.svelte +17 -13
  27. package/src/lib/components/detailView/detailView.svelte +7 -2
  28. package/src/lib/components/detailView/fieldInput.svelte +10 -9
  29. package/src/lib/components/detailView/update/updateDetailView.svelte +22 -18
  30. package/src/lib/components/drawer.svelte +15 -2
  31. package/src/lib/components/foreingKeyInput.svelte +163 -68
  32. package/src/lib/components/polymorphicInput.svelte +112 -63
@@ -2,11 +2,11 @@
2
2
  import { onMount } from "svelte";
3
3
  import Input from "./ui/input/input.svelte";
4
4
  import SelectRecord from "./selectRecord.svelte";
5
- import UpdateDetailViewButton from "./detailView/update/updateDetailViewButton.svelte";
6
5
  import CreateDetailView from "./detailView/create/createDetailView.svelte";
6
+ import UpdateDetailView from "./detailView/update/updateDetailView.svelte";
7
7
  import { getCollectionPrimaryField } from "./dataTable/utils";
8
8
  import { getStudioContext } from "../context";
9
- import { ExternalLink, Plus } from "lucide-svelte";
9
+ import { Plus, Link, Pencil, Unlink, Trash, RotateCcw, RefreshCw } from "lucide-svelte";
10
10
  import Button from "./ui/button/button.svelte";
11
11
 
12
12
  const { lobb, ctx } = getStudioContext();
@@ -15,7 +15,7 @@
15
15
  parentCollectionName: string;
16
16
  collectionName: string;
17
17
  fieldName: string;
18
- value?: number | null;
18
+ value?: any;
19
19
  destructive?: boolean;
20
20
  entry: Record<string, any>;
21
21
  }
@@ -29,96 +29,180 @@
29
29
  entry,
30
30
  }: LocalProps = $props();
31
31
 
32
- let displayName = $state<string | null>(null);
33
32
  let createDrawerOpen = $state(false);
33
+ let editDrawerOpen = $state(false);
34
+ let editValues: Record<string, any> | undefined = $state(undefined);
35
+ let originalId = $state<number | null>(null);
36
+ let initialValue = $state<any>(undefined);
37
+ let unlinked = $state(false);
34
38
 
35
- onMount(async () => {
36
- if (value == null) return;
37
- try {
38
- const res = await lobb.findOne(collectionName, value);
39
- const record = (await res.json()).data;
40
- const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
41
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
42
- } catch {
43
- displayName = null;
39
+ onMount(() => { initialValue = value; });
40
+
41
+ // Derived state from value
42
+ const isPendingCreate = $derived(value && typeof value === 'object' && value.create);
43
+ const isPendingEdit = $derived(value && typeof value === 'object' && value.id && value.update);
44
+ const isStagedDelete = $derived(value && typeof value === 'object' && value.delete === true);
45
+ const isStagedUnlink = $derived(unlinked);
46
+ const hasRealId = $derived(value != null && typeof value === 'number');
47
+ const isNewLink = $derived(hasRealId && initialValue !== undefined && initialValue == null && value !== initialValue);
48
+ const isReplaced = $derived(hasRealId && initialValue !== undefined && initialValue != null && value !== initialValue);
49
+ const isEmpty = $derived((value == null || value === 0) && !unlinked);
50
+ const isZeroPlaceholder = $derived(value === 0);
51
+
52
+ const bgClass = $derived(
53
+ isPendingCreate ? '!bg-green-500/5 border-green-500/40' :
54
+ isNewLink ? '!bg-blue-500/5 border-blue-500/40' :
55
+ isReplaced ? '!bg-orange-500/5 border-orange-500/40' :
56
+ isPendingEdit ? '!bg-orange-500/5 border-orange-500/40' :
57
+ isStagedUnlink ? '!bg-slate-500/5 border-slate-500/40' :
58
+ isStagedDelete ? '!bg-red-500/5 border-red-500/40' :
59
+ ''
60
+ );
61
+
62
+ const displayId = $derived(
63
+ isPendingEdit ? (value as any).id :
64
+ isStagedUnlink ? originalId :
65
+ isStagedDelete ? originalId :
66
+ hasRealId ? value :
67
+ null
68
+ );
69
+
70
+ async function handleCreated(record: any) {
71
+ // dry-run result has no id — store as pending create
72
+ if (!record.id) {
73
+ value = { create: record };
74
+ } else {
75
+ value = record.id;
44
76
  }
45
- });
77
+ }
46
78
 
47
- $effect(() => {
48
- if (value == null) displayName = null;
49
- });
79
+ async function openEdit() {
80
+ const res = await lobb.findAll(collectionName, { filter: { id: value }, limit: 1 });
81
+ const result = await res.json();
82
+ editValues = result.data[0];
83
+ editDrawerOpen = true;
84
+ }
85
+
86
+ function handleEditChanges(changes: import('./detailView/utils').Changes) {
87
+ if (Object.keys(changes.data).length === 0) {
88
+ value = (editValues as any)?.id ?? value;
89
+ } else {
90
+ value = { id: (editValues as any)?.id ?? value, update: changes.data };
91
+ }
92
+ }
50
93
 
51
94
  function handleSelect(selectedEntry: any) {
52
- const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
53
95
  value = selectedEntry.id;
54
- displayName = primaryFieldName ? String(selectedEntry[primaryFieldName]) : null;
55
96
  }
56
97
 
57
- async function handleCreated(record: any) {
58
- const primaryFieldName = getCollectionPrimaryField(ctx, collectionName);
59
- value = record.id;
60
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
98
+ function handleUnlink() {
99
+ if (hasRealId) {
100
+ originalId = value as number;
101
+ unlinked = true;
102
+ value = null;
103
+ }
104
+ }
105
+
106
+ async function handleDelete() {
107
+ if (hasRealId) {
108
+ originalId = value as number;
109
+ value = { delete: true };
110
+ }
61
111
  }
62
112
 
63
- const idIsZero = $derived(value === 0);
113
+ function handleRevert() {
114
+ if (originalId != null) {
115
+ value = originalId;
116
+ originalId = null;
117
+ } else {
118
+ value = null;
119
+ }
120
+ unlinked = false;
121
+ }
64
122
  </script>
65
123
 
66
- {#if !idIsZero}
124
+ {#if !isZeroPlaceholder}
67
125
  <div class="relative">
68
- <div class="flex gap-2 absolute right-0 top-0 mr-9 h-full items-center text-xs">
69
- {#if value != null}
70
- <UpdateDetailViewButton
71
- collectionName={collectionName}
72
- recordId={value}
126
+ <!-- Action buttons overlay on the right -->
127
+ <div class="flex gap-1 absolute right-0 top-0 mr-9 h-full items-center text-xs">
128
+ {#if isStagedUnlink || isStagedDelete || isPendingCreate || isPendingEdit}
129
+ <Button
130
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
73
131
  variant="ghost"
74
- class="h-5 w-5 px-0 py-0 text-muted-foreground hover:bg-transparent"
75
- Icon={ExternalLink}
76
- ></UpdateDetailViewButton>
77
- {/if}
78
- {#if displayName}
79
- <div class="flex items-center bg-background rounded-full border h-6 px-3 shadow-sm">
80
- {displayName}
81
- </div>
132
+ Icon={RotateCcw}
133
+ onclick={handleRevert}
134
+ title="Revert"
135
+ ></Button>
136
+ {:else if hasRealId}
137
+ <Button
138
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
139
+ variant="ghost"
140
+ Icon={Trash}
141
+ onclick={handleDelete}
142
+ title="Delete record"
143
+ ></Button>
144
+ <Button
145
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
146
+ variant="ghost"
147
+ Icon={Unlink}
148
+ onclick={handleUnlink}
149
+ title="Unlink"
150
+ ></Button>
151
+ <Button
152
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
153
+ variant="ghost"
154
+ Icon={Pencil}
155
+ onclick={openEdit}
156
+ title="Edit record"
157
+ ></Button>
158
+ <SelectRecord
159
+ class="h-5 w-5 px-0 py-0 hover:bg-transparent text-muted-foreground"
160
+ variant="ghost"
161
+ {collectionName}
162
+ onSelect={handleSelect}
163
+ additionalFilter={{ id: { $ne: value } }}
164
+ title="Replace"
165
+ {entry}
166
+ >
167
+ {#snippet children()}<RefreshCw size="13" />{/snippet}
168
+ </SelectRecord>
169
+ {:else if isEmpty}
170
+ <Button
171
+ class="h-6 px-2 font-normal text-xs"
172
+ variant="outline"
173
+ Icon={Plus}
174
+ onclick={() => (createDrawerOpen = true)}
175
+ >
176
+ Create
177
+ </Button>
178
+ <SelectRecord
179
+ class="h-6 px-2 font-normal text-xs"
180
+ variant="outline"
181
+ {parentCollectionName}
182
+ {collectionName}
183
+ {fieldName}
184
+ onSelect={handleSelect}
185
+ text="Link"
186
+ {entry}
187
+ />
82
188
  {/if}
83
- <Button
84
- class="h-6 px-2 font-normal text-xs"
85
- variant="outline"
86
- Icon={Plus}
87
- onclick={() => (createDrawerOpen = true)}
88
- >
89
- Create
90
- </Button>
91
- <SelectRecord
92
- class="h-6 px-2 font-normal text-xs"
93
- variant="outline"
94
- {parentCollectionName}
95
- {collectionName}
96
- {fieldName}
97
- onSelect={handleSelect}
98
- text="Select"
99
- {entry}
100
- />
101
189
  </div>
190
+
191
+ <!-- Input field colored by state -->
102
192
  <Input
103
- placeholder={"NULL"}
193
+ placeholder={isEmpty ? "NULL" : ""}
104
194
  type="number"
105
- class="
106
- bg-muted text-xs
107
- {destructive ? 'border-destructive bg-destructive/10' : ''}
108
- "
195
+ class="bg-muted text-xs {bgClass} {destructive ? '!bg-destructive/10 border-destructive' : ''}"
196
+ disabled={isPendingCreate || isPendingEdit}
109
197
  bind:value={
110
- () => value ?? "",
111
- (v) => (value = (v === "" || v == null) ? null : Number(v))
198
+ () => displayId ?? "",
199
+ (v) => { if (hasRealId || isEmpty) value = (v === "" || v == null) ? null : Number(v); }
112
200
  }
113
201
  />
114
202
  </div>
115
203
  {:else}
116
204
  <div class="relative z-10">
117
- <Input
118
- placeholder={"PARENT ID"}
119
- class="bg-muted text-xs"
120
- disabled={true}
121
- />
205
+ <Input placeholder="PARENT ID" class="bg-muted text-xs" disabled={true} />
122
206
  </div>
123
207
  {/if}
124
208
 
@@ -126,6 +210,17 @@
126
210
  <CreateDetailView
127
211
  collectionName={collectionName}
128
212
  onCreated={handleCreated}
213
+ onChanges={() => {}}
129
214
  onCancel={async () => { createDrawerOpen = false; }}
130
215
  />
131
216
  {/if}
217
+
218
+ {#if editDrawerOpen && editValues}
219
+ <UpdateDetailView
220
+ collectionName={collectionName}
221
+ recordId={String(editValues.id)}
222
+ values={editValues}
223
+ onChanges={handleEditChanges}
224
+ onCancel={async () => { editDrawerOpen = false; editValues = undefined; }}
225
+ />
226
+ {/if}
@@ -4,16 +4,17 @@
4
4
  import DataTable from "./dataTable/dataTable.svelte";
5
5
  import Drawer from "./drawer.svelte";
6
6
  import * as Popover from "./ui/popover/index";
7
- import { getCollectionPrimaryField } from "./dataTable/utils";
8
7
  import { getStudioContext } from "../context";
9
- import { ArrowLeft, Link, ChevronDown, Plus } from "lucide-svelte";
8
+ import { ArrowLeft, Link, ChevronDown, Plus, Pencil, Unlink, Trash, RotateCcw, RefreshCw } from "lucide-svelte";
10
9
  import CreateDetailView from "./detailView/create/createDetailView.svelte";
10
+ import UpdateDetailView from "./detailView/update/updateDetailView.svelte";
11
11
 
12
12
  const { ctx, lobb } = getStudioContext();
13
13
 
14
14
  interface Props {
15
15
  collectionField: string;
16
16
  idField: string;
17
+ virtualField: string;
17
18
  targetCollections: string[];
18
19
  entry: Record<string, any>;
19
20
  destructive?: boolean;
@@ -22,39 +23,52 @@
22
23
  let {
23
24
  collectionField,
24
25
  idField,
26
+ virtualField,
25
27
  targetCollections,
26
28
  entry = $bindable(),
27
29
  destructive,
28
30
  }: Props = $props();
29
31
 
32
+
30
33
  const selectedCollection = $derived(entry[collectionField] ?? null);
31
- const selectedId = $derived(entry[idField] ?? null);
34
+ const selectedId = $derived(entry[idField] ?? null);
35
+ const virtualVal = $derived(entry[virtualField] ?? null);
36
+
37
+ let initialId = $state<number | null | undefined>(undefined);
38
+ let unlinked = $state(false);
39
+ onMount(() => { initialId = entry[idField] ?? null; });
40
+
41
+ // State derived from virtual field and real fields
42
+ const isPendingCreate = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.create);
43
+ const isPendingEdit = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.update);
44
+ const isStagedUnlink = $derived(unlinked);
45
+ const isStagedDelete = $derived(virtualVal && typeof virtualVal === 'object' && virtualVal.delete === true);
46
+ const hasRealValue = $derived(selectedId != null && !isPendingCreate && !isPendingEdit && !isStagedUnlink && !isStagedDelete);
47
+ const isNewLink = $derived(hasRealValue && initialId !== undefined && initialId == null && selectedId !== initialId);
48
+ const isReplaced = $derived(hasRealValue && initialId !== undefined && initialId != null && selectedId !== initialId);
49
+ const isEmpty = $derived(!unlinked && (!selectedCollection || (selectedId == null && !isPendingCreate && !isPendingEdit && !isStagedDelete)));
50
+
51
+ const bgClass = $derived(
52
+ isPendingCreate ? '!bg-green-500/5 border-green-500/40' :
53
+ isNewLink ? '!bg-blue-500/5 border-blue-500/40' :
54
+ isReplaced ? '!bg-orange-500/5 border-orange-500/40' :
55
+ isPendingEdit ? '!bg-orange-500/5 border-orange-500/40' :
56
+ isStagedUnlink ? '!bg-slate-500/5 border-slate-500/40' :
57
+ isStagedDelete ? '!bg-red-500/5 border-red-500/40' :
58
+ ''
59
+ );
32
60
 
33
- let displayName = $state<string | null>(null);
34
61
  let collectionPopoverOpen = $state(false);
35
62
  let recordDrawerOpen = $state(false);
36
63
  let createDrawerOpen = $state(false);
37
-
38
- onMount(async () => {
39
- if (selectedCollection == null || selectedId == null) return;
40
- try {
41
- const res = await lobb.findOne(selectedCollection, selectedId);
42
- const record = await res.json();
43
- const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection);
44
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
45
- } catch {
46
- displayName = null;
47
- }
48
- });
49
-
50
- $effect(() => {
51
- if (entry[idField] == null) displayName = null;
52
- });
64
+ let editDrawerOpen = $state(false);
65
+ let editValues: Record<string, any> | undefined = $state(undefined);
66
+ let originalSnapshot: { collection: string; id: number } | null = $state(null);
53
67
 
54
68
  function onCollectionChange(col: string) {
55
69
  collectionPopoverOpen = false;
56
70
  if (entry[collectionField] !== col) {
57
- entry = { ...entry, [collectionField]: col, [idField]: null };
71
+ entry = { ...entry, [collectionField]: col, [idField]: null, [virtualField]: undefined };
58
72
  }
59
73
  }
60
74
 
@@ -65,20 +79,60 @@
65
79
  }
66
80
 
67
81
  function onRecordSelect(record: any) {
68
- const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection!);
69
- entry = { ...entry, [idField]: record.id };
70
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
82
+ entry = { ...entry, [idField]: record.id, [virtualField]: undefined };
71
83
  recordDrawerOpen = false;
72
84
  }
73
85
 
74
86
  async function onPolyCreated(record: any) {
75
- const primaryFieldName = getCollectionPrimaryField(ctx, selectedCollection!);
76
- entry = { ...entry, [idField]: record.id };
77
- displayName = primaryFieldName ? String(record[primaryFieldName]) : null;
87
+ if (!record.id) {
88
+ entry = { ...entry, [virtualField]: { collection: selectedCollection, create: record }, [collectionField]: selectedCollection, [idField]: null };
89
+ } else {
90
+ entry = { ...entry, [idField]: record.id, [virtualField]: undefined };
91
+ }
92
+ }
93
+
94
+ async function openEdit() {
95
+ const res = await lobb.findAll(selectedCollection!, { filter: { id: selectedId }, limit: 1 });
96
+ const result = await res.json();
97
+ editValues = result.data[0];
98
+ editDrawerOpen = true;
99
+ }
100
+
101
+ function handleEditChanges(changes: import('./detailView/utils').Changes) {
102
+ if (Object.keys(changes.data).length === 0) {
103
+ entry = { ...entry, [virtualField]: undefined };
104
+ } else {
105
+ entry = { ...entry, [virtualField]: { collection: selectedCollection, id: selectedId, update: changes.data } };
106
+ }
107
+ }
108
+
109
+ function handleUnlink() {
110
+ if (hasRealValue) {
111
+ originalSnapshot = { collection: selectedCollection!, id: selectedId! };
112
+ unlinked = true;
113
+ entry = { ...entry, [collectionField]: null, [idField]: null, [virtualField]: undefined };
114
+ }
115
+ }
116
+
117
+ async function handleDelete() {
118
+ if (hasRealValue) {
119
+ originalSnapshot = { collection: selectedCollection!, id: selectedId! };
120
+ entry = { ...entry, [virtualField]: { delete: true } };
121
+ }
122
+ }
123
+
124
+ function handleRevert() {
125
+ if (originalSnapshot) {
126
+ entry = { ...entry, [collectionField]: originalSnapshot.collection, [idField]: originalSnapshot.id, [virtualField]: undefined };
127
+ originalSnapshot = null;
128
+ } else {
129
+ entry = { ...entry, [collectionField]: null, [idField]: null, [virtualField]: undefined };
130
+ }
131
+ unlinked = false;
78
132
  }
79
133
  </script>
80
134
 
81
- <div class="flex h-9 w-full items-center gap-1.5 rounded-md border pl-1.5 pr-9 text-xs bg-muted {destructive ? 'border-destructive bg-destructive/10' : ''}">
135
+ <div class="flex h-9 w-full items-center gap-1.5 rounded-md border pl-1.5 pr-9 text-xs bg-muted {bgClass} {destructive ? '!bg-destructive/10 border-destructive' : ''}">
82
136
  <!-- Collection picker -->
83
137
  <Popover.Root bind:open={collectionPopoverOpen}>
84
138
  <Popover.Trigger>
@@ -107,39 +161,32 @@
107
161
  </Popover.Content>
108
162
  </Popover.Root>
109
163
 
110
- <!-- Transparent id input -->
164
+ <!-- ID input (only editable when real value or empty) -->
111
165
  <input
112
166
  placeholder="NULL"
113
167
  type="number"
114
168
  class="min-w-0 flex-1 bg-transparent outline-none text-xs placeholder:text-muted-foreground"
115
- value={selectedId ?? ""}
169
+ value={isStagedUnlink || isStagedDelete ? (virtualVal?.id ?? '') : (selectedId ?? "")}
170
+ disabled={isPendingCreate || isPendingEdit}
116
171
  oninput={onIdChange}
117
172
  />
118
173
 
119
- <!-- Primary field badge -->
120
- {#if displayName}
121
- <div class="flex shrink-0 items-center bg-background rounded-full border h-6 px-3 shadow-sm">
122
- {displayName}
123
- </div>
124
- {/if}
125
-
126
- <!-- Create / Select record buttons -->
127
- {#if selectedCollection}
128
- <Button
129
- class="h-6 shrink-0 px-2 font-normal text-xs"
130
- variant="outline"
131
- onclick={() => (createDrawerOpen = true)}
132
- >
174
+ <!-- Action buttons -->
175
+ {#if isStagedUnlink || isStagedDelete || isPendingCreate || isPendingEdit}
176
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={RotateCcw} onclick={handleRevert} title="Revert"></Button>
177
+ {:else if hasRealValue}
178
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Trash} onclick={handleDelete} title="Delete record"></Button>
179
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Unlink} onclick={handleUnlink} title="Unlink"></Button>
180
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={Pencil} onclick={openEdit} title="Edit record"></Button>
181
+ <Button class="h-5 w-5 px-0 shrink-0 hover:bg-transparent text-muted-foreground" variant="ghost" Icon={RefreshCw} onclick={() => (recordDrawerOpen = true)} title="Replace"></Button>
182
+ {:else if selectedCollection && !isPendingCreate}
183
+ <Button class="h-6 shrink-0 px-2 font-normal text-xs" variant="outline" onclick={() => (createDrawerOpen = true)}>
133
184
  <Plus size="13" />
134
185
  Create
135
186
  </Button>
136
- <Button
137
- class="h-6 shrink-0 px-2 font-normal text-xs"
138
- variant="outline"
139
- onclick={() => (recordDrawerOpen = true)}
140
- >
187
+ <Button class="h-6 shrink-0 px-2 font-normal text-xs" variant="outline" onclick={() => (recordDrawerOpen = true)}>
141
188
  <Link size="13" />
142
- Select
189
+ Link
143
190
  </Button>
144
191
  {/if}
145
192
  </div>
@@ -147,26 +194,17 @@
147
194
  {#if recordDrawerOpen}
148
195
  <Drawer onHide={async () => { recordDrawerOpen = false }}>
149
196
  <div class="flex h-12 items-center gap-4 border-b px-4">
150
- <Button
151
- variant="outline"
152
- onclick={() => (recordDrawerOpen = false)}
153
- class="h-8 w-8 rounded-full text-xs font-normal"
154
- Icon={ArrowLeft}
155
- />
197
+ <Button variant="outline" onclick={() => (recordDrawerOpen = false)} class="h-8 w-8 rounded-full text-xs font-normal" Icon={ArrowLeft} />
156
198
  <div class="flex items-center gap-2">
157
199
  <div class="text-sm">Select record from</div>
158
- <span class="rounded-md border bg-muted px-2 py-0.5 text-sm">
159
- {selectedCollection}
160
- </span>
200
+ <span class="rounded-md border bg-muted px-2 py-0.5 text-sm">{selectedCollection}</span>
161
201
  </div>
162
202
  </div>
163
203
  <div class="flex-1 overflow-y-auto bg-muted">
164
204
  <DataTable
165
205
  collectionName={selectedCollection!}
166
- tableProps={{
167
- showCheckboxes: false,
168
- select: { onSelect: onRecordSelect },
169
- }}
206
+ filter={selectedId != null ? { id: { $ne: selectedId } } : undefined}
207
+ tableProps={{ showCheckboxes: false, select: { onSelect: onRecordSelect } }}
170
208
  />
171
209
  </div>
172
210
  </Drawer>
@@ -176,6 +214,17 @@
176
214
  <CreateDetailView
177
215
  collectionName={selectedCollection}
178
216
  onCreated={onPolyCreated}
217
+ onChanges={() => {}}
179
218
  onCancel={async () => { createDrawerOpen = false; }}
180
219
  />
181
220
  {/if}
221
+
222
+ {#if editDrawerOpen && editValues && selectedCollection}
223
+ <UpdateDetailView
224
+ collectionName={selectedCollection}
225
+ recordId={String(editValues.id)}
226
+ values={editValues}
227
+ onChanges={handleEditChanges}
228
+ onCancel={async () => { editDrawerOpen = false; editValues = undefined; }}
229
+ />
230
+ {/if}