@lobb-js/studio 0.34.0 → 0.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/codeEditor.svelte +1 -1
- package/dist/components/dataTable/table.svelte +4 -4
- package/dist/components/dataTable/utils.js +2 -1
- package/dist/components/detailView/create/children.svelte +1 -1
- package/dist/components/detailView/create/createDetailViewChildren.svelte +1 -1
- package/dist/components/detailView/create/createManyView.svelte +2 -2
- package/dist/components/detailView/detailView.svelte +2 -1
- package/dist/components/detailView/fieldInput.svelte +10 -10
- package/dist/components/detailView/fieldInputReplacement.svelte +7 -7
- package/dist/components/detailView/passwordInput.svelte +1 -1
- package/dist/components/detailView/update/updateDetailViewChildren.svelte +1 -1
- package/dist/components/diffViewer.svelte +1 -1
- package/dist/components/foreingKeyInput.svelte +2 -2
- package/dist/components/importButton.svelte +19 -3
- package/dist/components/polymorphicInput.svelte +1 -1
- package/dist/components/rangeCalendarButton.svelte +10 -10
- package/dist/components/richTextEditor.svelte +1 -1
- package/dist/components/routes/extensions/publicExtension.svelte +1 -1
- package/dist/components/sidebar/sidebar.svelte +1 -1
- package/dist/components/sidebar/sidebarElements.svelte +2 -2
- package/dist/components/ui/accordion/index.d.ts +1 -1
- package/dist/components/ui/command/command-dialog.svelte.d.ts +1 -1
- package/dist/components/ui/command/command-input.svelte.d.ts +1 -1
- package/dist/components/ui/command/command.svelte.d.ts +1 -1
- package/dist/components/ui/input/input.svelte.d.ts +1 -1
- package/dist/components/ui/range-calendar/range-calendar.svelte.d.ts +1 -1
- package/dist/components/ui/textarea/textarea.svelte.d.ts +1 -1
- package/dist/extensions/extension.types.d.ts +6 -0
- package/dist/extensions/extensionUtils.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/store.types.d.ts +3 -9
- package/dist/utils.d.ts +3 -0
- package/dist/utils.js +20 -0
- package/package.json +2 -2
- package/src/app.css +2 -5
- package/src/lib/components/codeEditor.svelte +1 -1
- package/src/lib/components/dataTable/table.svelte +4 -4
- package/src/lib/components/dataTable/utils.ts +2 -1
- package/src/lib/components/detailView/create/children.svelte +1 -1
- package/src/lib/components/detailView/create/createDetailViewChildren.svelte +1 -1
- package/src/lib/components/detailView/create/createManyView.svelte +2 -2
- package/src/lib/components/detailView/detailView.svelte +2 -1
- package/src/lib/components/detailView/fieldInput.svelte +10 -10
- package/src/lib/components/detailView/fieldInputReplacement.svelte +7 -7
- package/src/lib/components/detailView/passwordInput.svelte +1 -1
- package/src/lib/components/detailView/update/updateDetailViewChildren.svelte +1 -1
- package/src/lib/components/diffViewer.svelte +1 -1
- package/src/lib/components/foreingKeyInput.svelte +2 -2
- package/src/lib/components/importButton.svelte +19 -3
- package/src/lib/components/polymorphicInput.svelte +1 -1
- package/src/lib/components/rangeCalendarButton.svelte +10 -10
- package/src/lib/components/richTextEditor.svelte +1 -1
- package/src/lib/components/routes/extensions/publicExtension.svelte +1 -1
- package/src/lib/components/sidebar/sidebar.svelte +1 -1
- package/src/lib/components/sidebar/sidebarElements.svelte +2 -2
- package/src/lib/extensions/extension.types.ts +6 -0
- package/src/lib/extensions/extensionUtils.ts +1 -0
- package/src/lib/index.ts +2 -1
- package/src/lib/store.types.ts +6 -6
- package/src/lib/utils.ts +22 -0
package/dist/utils.js
CHANGED
|
@@ -12,6 +12,26 @@ export const mediaQueries = {
|
|
|
12
12
|
xl: new MediaQuery('min-width: 1280px'),
|
|
13
13
|
'2xl': new MediaQuery('min-width: 1536px'),
|
|
14
14
|
};
|
|
15
|
+
// User-facing label for a field type. "string"/"text" are jargon to
|
|
16
|
+
// non-technical users, so we surface "Text"/"Long text" instead. Types
|
|
17
|
+
// not in the map fall through to the raw identifier — extend as needed.
|
|
18
|
+
const FIELD_TYPE_LABELS = {
|
|
19
|
+
string: "Text",
|
|
20
|
+
text: "Long text",
|
|
21
|
+
};
|
|
22
|
+
export function getFieldTypeLabel(type) {
|
|
23
|
+
if (!type)
|
|
24
|
+
return "";
|
|
25
|
+
return FIELD_TYPE_LABELS[type] ?? type;
|
|
26
|
+
}
|
|
27
|
+
// Settings-based visibility check. Returns true when the project has
|
|
28
|
+
// opted to hide the UI element registered under the given identifier
|
|
29
|
+
// in its `ui.hide` config (e.g. "reports.dashboardShareButton").
|
|
30
|
+
// Components that support hiding wrap their render with
|
|
31
|
+
// `{#if !isHidden(ctx, "...")}`.
|
|
32
|
+
export function isHidden(ctx, id) {
|
|
33
|
+
return ctx?.meta?.ui?.hide?.[id] === true;
|
|
34
|
+
}
|
|
15
35
|
export function calculateDrawerWidth() {
|
|
16
36
|
const backgroundDrawerButtons = document.querySelectorAll(".backgroundDrawerButton");
|
|
17
37
|
const drawersCount = Array.from(backgroundDrawerButtons).length;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobb-js/studio",
|
|
3
3
|
"license": "UNLICENSED",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.36.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"postpublish": "./scripts/postpublish.sh"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
-
"@lobb-js/core": "^0.
|
|
45
|
+
"@lobb-js/core": "^0.36.0",
|
|
46
46
|
"@chromatic-com/storybook": "^4.1.2",
|
|
47
47
|
"@storybook/addon-a11y": "^10.0.1",
|
|
48
48
|
"@storybook/addon-docs": "^10.0.1",
|
package/src/app.css
CHANGED
|
@@ -26,7 +26,6 @@
|
|
|
26
26
|
|
|
27
27
|
--muted: oklch(0.97 0.001 138);
|
|
28
28
|
--muted-foreground: oklch(0.55 0.012 138);
|
|
29
|
-
--muted-soft: oklch(0.985 0.001 138);
|
|
30
29
|
|
|
31
30
|
--accent: oklch(0.95 0.001 138);
|
|
32
31
|
--accent-foreground: oklch(0.20 0.012 138);
|
|
@@ -47,7 +46,7 @@
|
|
|
47
46
|
--popover: oklch(0.18 0.012 138);
|
|
48
47
|
--popover-foreground: oklch(0.94 0.012 138);
|
|
49
48
|
|
|
50
|
-
--primary: oklch(0.72 0.20
|
|
49
|
+
--primary: oklch(0.72 0.20 138);
|
|
51
50
|
--primary-foreground: oklch(0.16 0.012 138);
|
|
52
51
|
|
|
53
52
|
--secondary: oklch(0.24 0.012 138);
|
|
@@ -55,7 +54,6 @@
|
|
|
55
54
|
|
|
56
55
|
--muted: oklch(0.24 0.012 138);
|
|
57
56
|
--muted-foreground: oklch(0.65 0.012 138);
|
|
58
|
-
--muted-soft: oklch(0.20 0.012 138);
|
|
59
57
|
|
|
60
58
|
--accent: oklch(0.27 0.012 138);
|
|
61
59
|
--accent-foreground: oklch(0.94 0.012 138);
|
|
@@ -64,7 +62,7 @@
|
|
|
64
62
|
|
|
65
63
|
--border: oklch(1 0 0 / 8%);
|
|
66
64
|
--input: oklch(1 0 0 / 12%);
|
|
67
|
-
--ring: oklch(0.72 0.20
|
|
65
|
+
--ring: oklch(0.72 0.20 138);
|
|
68
66
|
}
|
|
69
67
|
|
|
70
68
|
@theme inline {
|
|
@@ -84,7 +82,6 @@
|
|
|
84
82
|
--color-secondary-foreground: var(--secondary-foreground);
|
|
85
83
|
--color-muted: var(--muted);
|
|
86
84
|
--color-muted-foreground: var(--muted-foreground);
|
|
87
|
-
--color-muted-soft: var(--muted-soft);
|
|
88
85
|
--color-accent: var(--accent);
|
|
89
86
|
--color-accent-foreground: var(--accent-foreground);
|
|
90
87
|
--color-destructive: var(--destructive);
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
});
|
|
133
133
|
</script>
|
|
134
134
|
|
|
135
|
-
<div class={cn('resize-y rounded-md border bg-muted
|
|
135
|
+
<div class={cn('resize-y rounded-md border bg-muted h-60', className)}>
|
|
136
136
|
<div bind:this={editorContainer} class="h-full w-full pl-2" />
|
|
137
137
|
</div>
|
|
138
138
|
|
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
flex items-center p-2.5 text-xs h-10
|
|
183
183
|
border-r border-b gap-2
|
|
184
184
|
{headerBorderTop ? 'border-t' : ''}
|
|
185
|
-
bg-muted
|
|
185
|
+
bg-muted
|
|
186
186
|
"
|
|
187
187
|
>
|
|
188
188
|
<!-- collapsable toggle -->
|
|
@@ -207,7 +207,7 @@
|
|
|
207
207
|
class="
|
|
208
208
|
sticky top-0 z-10
|
|
209
209
|
flex items-center p-2.5 text-xs h-10
|
|
210
|
-
bg-muted
|
|
210
|
+
bg-muted
|
|
211
211
|
{lastColumn && !showLastColumnBorder ? '' : 'border-r'}
|
|
212
212
|
border-b gap-2
|
|
213
213
|
{headerBorderTop ? 'border-t' : ''}
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
class="
|
|
235
235
|
sticky top-0 right-0 z-20
|
|
236
236
|
flex items-center p-2.5 h-10
|
|
237
|
-
bg-muted
|
|
237
|
+
bg-muted
|
|
238
238
|
border-l border-b
|
|
239
239
|
{headerBorderTop ? 'border-t' : ''}
|
|
240
240
|
"
|
|
@@ -334,7 +334,7 @@
|
|
|
334
334
|
{expandedRows[index] ? '' : 'height: 0px;'}
|
|
335
335
|
"
|
|
336
336
|
class="
|
|
337
|
-
sticky left-0 top-0 overflow-auto bg-muted
|
|
337
|
+
sticky left-0 top-0 overflow-auto bg-muted
|
|
338
338
|
|
|
339
339
|
{expandedRows[index] ? 'border-t' : ''}
|
|
340
340
|
"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { TableProps } from "./table.svelte";
|
|
2
2
|
import type { CTX } from "../../store.types";
|
|
3
3
|
import { getFieldRelationTarget } from "../../relations";
|
|
4
|
+
import { getFieldTypeLabel } from "../../utils";
|
|
4
5
|
|
|
5
6
|
import {
|
|
6
7
|
Binary,
|
|
@@ -25,7 +26,7 @@ export function getCollectionColumns(ctx: CTX, collectionName: string): TablePro
|
|
|
25
26
|
if ((field as any).ui?.hidden) continue;
|
|
26
27
|
headers.push({
|
|
27
28
|
id: field.key,
|
|
28
|
-
subtext: field.type,
|
|
29
|
+
subtext: getFieldTypeLabel(field.type),
|
|
29
30
|
icon: getFieldIcon(ctx, fieldName, collectionName),
|
|
30
31
|
});
|
|
31
32
|
}
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
parentCollectionName={collectionName}
|
|
38
38
|
collectionName={child.collection}
|
|
39
39
|
parentRecord={{ id: entry.id, collectionName }}
|
|
40
|
-
class="bg-muted
|
|
40
|
+
class="bg-muted border rounded-md overflow-hidden"
|
|
41
41
|
bind:value={entry[child.collection]}
|
|
42
42
|
>
|
|
43
43
|
<CreateManyView
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
{#each children as child}
|
|
55
55
|
{@const localAdditions = (localChildren[child.collection]?.created.length ?? 0) + (localChildren[child.collection]?.linked.length ?? 0)}
|
|
56
56
|
{#if localAdditions === 0}
|
|
57
|
-
<div class="rounded-lg border bg-muted
|
|
57
|
+
<div class="rounded-lg border bg-muted overflow-hidden flex flex-col">
|
|
58
58
|
<div class="flex flex-col items-center justify-center gap-3 py-6 px-4">
|
|
59
59
|
<div class="flex flex-col items-center gap-2 text-center">
|
|
60
60
|
<div class="flex items-center gap-1.5 text-sm font-medium text-muted-foreground">
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
>
|
|
113
113
|
<div
|
|
114
114
|
class="
|
|
115
|
-
flex items-center justify-between px-2 h-10 bg-muted
|
|
115
|
+
flex items-center justify-between px-2 h-10 bg-muted
|
|
116
116
|
{expanded ? 'border-b' : ''}
|
|
117
117
|
"
|
|
118
118
|
>
|
|
@@ -165,7 +165,7 @@
|
|
|
165
165
|
</div>
|
|
166
166
|
</div>
|
|
167
167
|
{#if expanded}
|
|
168
|
-
<div bind:clientWidth={tableWidth} class="bg-muted
|
|
168
|
+
<div bind:clientWidth={tableWidth} class="bg-muted overflow-auto">
|
|
169
169
|
<Table
|
|
170
170
|
data={entries}
|
|
171
171
|
{columns}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { getExtensionUtils } from "../../extensions/extensionUtils";
|
|
7
7
|
import { getField, getFieldIcon } from "../dataTable/utils";
|
|
8
8
|
import FieldInput from "./fieldInput.svelte";
|
|
9
|
+
import { getFieldTypeLabel } from "../../utils";
|
|
9
10
|
|
|
10
11
|
interface Props {
|
|
11
12
|
collectionName: string;
|
|
@@ -50,7 +51,7 @@
|
|
|
50
51
|
<div class="h-fit">{field.label}</div>
|
|
51
52
|
<div class="flex h-fit items-center gap-1 text-[0.7rem] text-muted-foreground">
|
|
52
53
|
<FieldIcon size="12" />
|
|
53
|
-
{field.type}
|
|
54
|
+
{getFieldTypeLabel(field.type)}
|
|
54
55
|
</div>
|
|
55
56
|
</div>
|
|
56
57
|
</ExtensionsComponents>
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
{:else if field.label === "id"}
|
|
88
88
|
<Input
|
|
89
89
|
placeholder="AUTO GENERATED"
|
|
90
|
-
class="bg-muted
|
|
90
|
+
class="bg-muted text-xs"
|
|
91
91
|
bind:value
|
|
92
92
|
/>
|
|
93
93
|
{:else if fieldRelationTarget && entry}
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
>
|
|
128
128
|
<Select.Trigger
|
|
129
129
|
class="
|
|
130
|
-
h-9 w-full bg-muted
|
|
130
|
+
h-9 w-full bg-muted pr-8
|
|
131
131
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
132
132
|
"
|
|
133
133
|
>
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
160
160
|
type="text"
|
|
161
161
|
class="
|
|
162
|
-
bg-muted
|
|
162
|
+
bg-muted text-xs
|
|
163
163
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
164
164
|
"
|
|
165
165
|
bind:value
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
placeholder={ui?.placeholder ? ui.placeholder : value === "" ? "EMPTY STRING" : "NULL"}
|
|
170
170
|
rows={5}
|
|
171
171
|
class="
|
|
172
|
-
bg-muted
|
|
172
|
+
bg-muted text-xs
|
|
173
173
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
174
174
|
"
|
|
175
175
|
bind:value
|
|
@@ -179,7 +179,7 @@
|
|
|
179
179
|
type="date"
|
|
180
180
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
181
181
|
class="
|
|
182
|
-
dateInput block w-full bg-muted
|
|
182
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
183
183
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
184
184
|
"
|
|
185
185
|
bind:value={
|
|
@@ -198,7 +198,7 @@
|
|
|
198
198
|
type="time"
|
|
199
199
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
200
200
|
class="
|
|
201
|
-
dateInput block w-full bg-muted
|
|
201
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
202
202
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
203
203
|
"
|
|
204
204
|
bind:value={
|
|
@@ -216,7 +216,7 @@
|
|
|
216
216
|
type="datetime-local"
|
|
217
217
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
218
218
|
class="
|
|
219
|
-
dateInput block w-full bg-muted
|
|
219
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
220
220
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
221
221
|
"
|
|
222
222
|
bind:value={
|
|
@@ -237,7 +237,7 @@
|
|
|
237
237
|
<Select.Trigger
|
|
238
238
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
239
239
|
class="
|
|
240
|
-
bg-muted
|
|
240
|
+
bg-muted pr-9
|
|
241
241
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
242
242
|
"
|
|
243
243
|
>
|
|
@@ -265,7 +265,7 @@
|
|
|
265
265
|
scale={isFloat ? 20 : 0}
|
|
266
266
|
groupDigits={ui?.groupDigits ?? false}
|
|
267
267
|
class="
|
|
268
|
-
bg-muted
|
|
268
|
+
bg-muted text-xs
|
|
269
269
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
270
270
|
"
|
|
271
271
|
bind:value
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
placeholder={ui?.placeholder ? ui.placeholder : "NULL"}
|
|
276
276
|
type="text"
|
|
277
277
|
class="
|
|
278
|
-
bg-muted
|
|
278
|
+
bg-muted text-xs
|
|
279
279
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
280
280
|
"
|
|
281
281
|
bind:value
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
placeholder={field.placeholder ? field.placeholder : "NULL"}
|
|
50
50
|
type="text"
|
|
51
51
|
class="
|
|
52
|
-
bg-muted
|
|
52
|
+
bg-muted text-xs
|
|
53
53
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
54
54
|
"
|
|
55
55
|
bind:value
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
<Select.Trigger
|
|
65
65
|
placeholder={field.placeholder ? field.placeholder : "NULL"}
|
|
66
66
|
class="
|
|
67
|
-
h-9 w-full bg-muted
|
|
67
|
+
h-9 w-full bg-muted pr-8
|
|
68
68
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
69
69
|
"
|
|
70
70
|
>
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
placeholder={field.placeholder ? field.placeholder : value === "" ? "EMPTY STRING" : "NULL"}
|
|
85
85
|
rows={5}
|
|
86
86
|
class="
|
|
87
|
-
bg-muted
|
|
87
|
+
bg-muted text-xs
|
|
88
88
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
89
89
|
"
|
|
90
90
|
bind:value
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
<Input
|
|
99
99
|
type="date"
|
|
100
100
|
class="
|
|
101
|
-
dateInput block w-full bg-muted
|
|
101
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
102
102
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
103
103
|
"
|
|
104
104
|
bind:value={
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
<Input
|
|
117
117
|
type="time"
|
|
118
118
|
class="
|
|
119
|
-
dateInput block w-full bg-muted
|
|
119
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
120
120
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
121
121
|
"
|
|
122
122
|
bind:value={
|
|
@@ -133,7 +133,7 @@
|
|
|
133
133
|
<Input
|
|
134
134
|
type="datetime-local"
|
|
135
135
|
class="
|
|
136
|
-
dateInput block w-full bg-muted
|
|
136
|
+
dateInput block w-full bg-muted pr-9 text-xs
|
|
137
137
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
138
138
|
"
|
|
139
139
|
bind:value={
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
<Select.Root type="single" bind:value>
|
|
155
155
|
<Select.Trigger
|
|
156
156
|
class="
|
|
157
|
-
bg-muted
|
|
157
|
+
bg-muted pr-9
|
|
158
158
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
159
159
|
"
|
|
160
160
|
>
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
<Input
|
|
22
22
|
type="password"
|
|
23
23
|
placeholder="••••••"
|
|
24
|
-
class="bg-muted
|
|
24
|
+
class="bg-muted text-xs {destructive ? 'border-destructive bg-destructive/10' : ''}"
|
|
25
25
|
value={displayValue}
|
|
26
26
|
oninput={onInput}
|
|
27
27
|
/>
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
{@const localAdditions = (localChildren[child.collection]?.created.length ?? 0) + (localChildren[child.collection]?.linked.length ?? 0)}
|
|
63
63
|
{@const showEmpty = serverCount !== undefined && serverCount === 0 && localAdditions === 0}
|
|
64
64
|
{#if showEmpty}
|
|
65
|
-
<div class="rounded-lg border bg-muted
|
|
65
|
+
<div class="rounded-lg border bg-muted overflow-hidden flex flex-col">
|
|
66
66
|
<div class="flex flex-col items-center justify-center gap-3 py-6 px-4">
|
|
67
67
|
<div class="flex flex-col items-center gap-2 text-center">
|
|
68
68
|
<div class="flex items-center gap-1.5 text-sm font-medium text-muted-foreground">
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
});
|
|
97
97
|
</script>
|
|
98
98
|
|
|
99
|
-
<div class={cn("w-full resize-y rounded-md border bg-muted
|
|
99
|
+
<div class={cn("w-full resize-y rounded-md border bg-muted shadow-sm", className)}>
|
|
100
100
|
<div
|
|
101
101
|
bind:this={editorContainer}
|
|
102
102
|
class="editor pl-2"
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
placeholder={"NULL"}
|
|
86
86
|
type="number"
|
|
87
87
|
class="
|
|
88
|
-
bg-muted
|
|
88
|
+
bg-muted text-xs
|
|
89
89
|
{destructive ? 'border-destructive bg-destructive/10' : ''}
|
|
90
90
|
"
|
|
91
91
|
bind:value={
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
<div class="relative z-10">
|
|
99
99
|
<Input
|
|
100
100
|
placeholder={"PARENT ID"}
|
|
101
|
-
class="bg-muted
|
|
101
|
+
class="bg-muted text-xs"
|
|
102
102
|
disabled={true}
|
|
103
103
|
/>
|
|
104
104
|
</div>
|
|
@@ -86,7 +86,23 @@
|
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
function detectAndParse(content: string): any[] {
|
|
89
|
+
async function detectAndParse(content: string): Promise<any[]> {
|
|
90
|
+
// Give projects a chance to take over parsing for non-standard
|
|
91
|
+
// formats (preamble rows, multi-line cells, vendor exports, …) by
|
|
92
|
+
// registering a workflow on `studio.collections.import.parse`. The
|
|
93
|
+
// workflow receives the raw text and sets `handled: true` along
|
|
94
|
+
// with its own `rows`; if no workflow takes over, we fall through
|
|
95
|
+
// to the built-in JSON / simple-CSV detector.
|
|
96
|
+
const result = await emitEvent({ lobb, ctx }, "studio.collections.import.parse", {
|
|
97
|
+
collectionName,
|
|
98
|
+
content,
|
|
99
|
+
rows: null as any[] | null,
|
|
100
|
+
handled: false,
|
|
101
|
+
});
|
|
102
|
+
if (result?.handled && Array.isArray(result.rows)) {
|
|
103
|
+
return result.rows;
|
|
104
|
+
}
|
|
105
|
+
|
|
90
106
|
const trimmed = content.trim();
|
|
91
107
|
if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
|
|
92
108
|
const parsed = JSON.parse(trimmed);
|
|
@@ -98,7 +114,7 @@
|
|
|
98
114
|
async function processContent(content: string) {
|
|
99
115
|
parseError = "";
|
|
100
116
|
try {
|
|
101
|
-
const rows = detectAndParse(content);
|
|
117
|
+
const rows = await detectAndParse(content);
|
|
102
118
|
if (rows.length === 0) throw new Error("No data rows found");
|
|
103
119
|
transformedRows = applyColumnMapping(rows);
|
|
104
120
|
step = "preview";
|
|
@@ -249,7 +265,7 @@
|
|
|
249
265
|
/>
|
|
250
266
|
{:else}
|
|
251
267
|
<textarea
|
|
252
|
-
class="block h-56 w-full resize-none rounded-md border bg-muted
|
|
268
|
+
class="block h-56 w-full resize-none rounded-md border bg-muted p-3 font-mono text-sm focus:outline-none focus:ring-1 focus:ring-ring"
|
|
253
269
|
placeholder="Paste CSV or JSON here..."
|
|
254
270
|
bind:value={pasteContent}
|
|
255
271
|
></textarea>
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
}
|
|
71
71
|
</script>
|
|
72
72
|
|
|
73
|
-
<div class="flex h-9 w-full items-center gap-1.5 rounded-md border pl-1.5 pr-9 text-xs bg-muted
|
|
73
|
+
<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' : ''}">
|
|
74
74
|
<!-- Collection picker -->
|
|
75
75
|
<Popover.Root bind:open={collectionPopoverOpen}>
|
|
76
76
|
<Popover.Trigger>
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
class="flex flex-col overflow-hidden text-muted-foreground"
|
|
59
59
|
>
|
|
60
60
|
<button
|
|
61
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
61
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
62
62
|
onclick={() => {
|
|
63
63
|
const currentDate = today(getLocalTimeZone());
|
|
64
64
|
value = {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
Today
|
|
71
71
|
</button>
|
|
72
72
|
<button
|
|
73
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
73
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
74
74
|
onclick={() => {
|
|
75
75
|
const currentDate = today(getLocalTimeZone());
|
|
76
76
|
value = {
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
Yesterday
|
|
83
83
|
</button>
|
|
84
84
|
<button
|
|
85
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
85
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
86
86
|
onclick={() => {
|
|
87
87
|
const currentDate = today(getLocalTimeZone());
|
|
88
88
|
const weekStart = startOfWeek(currentDate, "en-US");
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
This week (Sun - Today)
|
|
96
96
|
</button>
|
|
97
97
|
<button
|
|
98
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
98
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
99
99
|
onclick={() => {
|
|
100
100
|
const currentDate = today(getLocalTimeZone());
|
|
101
101
|
const thisWeekStart = startOfWeek(
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
Last week (Sun - Sat)
|
|
119
119
|
</button>
|
|
120
120
|
<button
|
|
121
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
121
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
122
122
|
onclick={() => {
|
|
123
123
|
const currentDate = today(getLocalTimeZone());
|
|
124
124
|
value = {
|
|
@@ -130,7 +130,7 @@
|
|
|
130
130
|
Last 7 days
|
|
131
131
|
</button>
|
|
132
132
|
<button
|
|
133
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
133
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
134
134
|
onclick={() => {
|
|
135
135
|
const currentDate = today(getLocalTimeZone());
|
|
136
136
|
value = {
|
|
@@ -142,7 +142,7 @@
|
|
|
142
142
|
Last 30 days
|
|
143
143
|
</button>
|
|
144
144
|
<button
|
|
145
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
145
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
146
146
|
onclick={() => {
|
|
147
147
|
const currentDate = today(getLocalTimeZone());
|
|
148
148
|
value = {
|
|
@@ -154,7 +154,7 @@
|
|
|
154
154
|
Last 90 days
|
|
155
155
|
</button>
|
|
156
156
|
<button
|
|
157
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
157
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
158
158
|
onclick={() => {
|
|
159
159
|
const currentDate = today(getLocalTimeZone());
|
|
160
160
|
value = {
|
|
@@ -166,7 +166,7 @@
|
|
|
166
166
|
Last 12 months
|
|
167
167
|
</button>
|
|
168
168
|
<button
|
|
169
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
169
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
170
170
|
onclick={() => {
|
|
171
171
|
const currentDate = today(getLocalTimeZone());
|
|
172
172
|
const lastYearStart = currentDate
|
|
@@ -184,7 +184,7 @@
|
|
|
184
184
|
Last Calendar year
|
|
185
185
|
</button>
|
|
186
186
|
<button
|
|
187
|
-
class="text-start text-sm py-2 px-2 hover:bg-muted
|
|
187
|
+
class="text-start text-sm py-2 px-2 hover:bg-muted hover:text-primary"
|
|
188
188
|
onclick={() => {
|
|
189
189
|
const currentDate = today(getLocalTimeZone());
|
|
190
190
|
const yearStart = currentDate.set({
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
const { lobb, ctx } = getStudioContext();
|
|
9
9
|
</script>
|
|
10
10
|
|
|
11
|
-
<div class="grid h-full w-full overflow-
|
|
11
|
+
<div class="grid h-full w-full overflow-hidden bg-background">
|
|
12
12
|
{#key extension && page}
|
|
13
13
|
<ExtensionsComponents
|
|
14
14
|
name="publicPages.{page}"
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
{#if showSearch}
|
|
108
108
|
<div class="p-2">
|
|
109
109
|
<div
|
|
110
|
-
class="flex items-center px-4 py-1 text-muted-foreground bg-muted
|
|
110
|
+
class="flex items-center px-4 py-1 text-muted-foreground bg-muted border rounded-md"
|
|
111
111
|
>
|
|
112
112
|
<input
|
|
113
113
|
type="text"
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
{#each data as node, index}
|
|
59
59
|
{#if node.type === "directory"}
|
|
60
60
|
<button
|
|
61
|
-
class="flex items-center justify-between p-2 gap-2 text-muted-foreground rounded-md hover:bg-muted
|
|
61
|
+
class="flex items-center justify-between p-2 gap-2 text-muted-foreground rounded-md hover:bg-muted cursor-pointer"
|
|
62
62
|
onclick={() => toggleDir(index)}
|
|
63
63
|
>
|
|
64
64
|
<div class="flex items-center gap-2">
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
variant="ghost"
|
|
91
91
|
class="
|
|
92
92
|
flex items-center justify-between p-2 gap-2 text-muted-foreground
|
|
93
|
-
rounded-md {isselected ? 'bg-
|
|
93
|
+
rounded-md {isselected ? 'bg-accent' : 'hover:bg-muted'}
|
|
94
94
|
"
|
|
95
95
|
title={node.name}
|
|
96
96
|
>
|
|
@@ -73,6 +73,12 @@ export interface ExtensionUtils {
|
|
|
73
73
|
openDataTableDrawer: (props: OpenDataTableDrawerProps) => void;
|
|
74
74
|
openDataTablePopup: (props: OpenDataTablePopupProps) => void;
|
|
75
75
|
emitEvent: (eventName: string, input: any) => Promise<any>;
|
|
76
|
+
/**
|
|
77
|
+
* Shorthand for the standalone `isHidden(ctx, id)` helper — returns
|
|
78
|
+
* true when the project has opted to hide the UI element registered
|
|
79
|
+
* under the given identifier in its `ui.hide` config.
|
|
80
|
+
*/
|
|
81
|
+
isHidden: (id: string) => boolean;
|
|
76
82
|
components: Components;
|
|
77
83
|
mediaQueries: typeof mediaQueries;
|
|
78
84
|
intlDate: typeof intlDate;
|
|
@@ -70,6 +70,7 @@ export function getExtensionUtils(lobb: LobbClient, ctx: CTX): ExtensionUtils {
|
|
|
70
70
|
openDataTableDrawer: (props) => openDataTableDrawer({ lobb, ctx }, props),
|
|
71
71
|
openDataTablePopup: (props) => openDataTablePopup({ lobb, ctx }, props),
|
|
72
72
|
emitEvent: (eventName, input) => emitEvent({ lobb, ctx }, eventName, input),
|
|
73
|
+
isHidden: (id) => ctx.meta?.ui?.hide?.[id] === true,
|
|
73
74
|
components: getComponents(),
|
|
74
75
|
mediaQueries: mediaQueries,
|
|
75
76
|
intlDate: intlDate,
|
package/src/lib/index.ts
CHANGED
|
@@ -26,4 +26,5 @@ export { default as RangeCalendarButton } from "./components/rangeCalendarButton
|
|
|
26
26
|
export { default as DataTable } from "./components/dataTable/dataTable.svelte";
|
|
27
27
|
export { default as Drawer } from "./components/drawer.svelte";
|
|
28
28
|
export { default as SelectRecord } from "./components/selectRecord.svelte";
|
|
29
|
-
export { Switch } from "./components/ui/switch";
|
|
29
|
+
export { Switch } from "./components/ui/switch";
|
|
30
|
+
export { isHidden } from "./utils";
|
package/src/lib/store.types.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { Extension } from "./extensions/extension.types";
|
|
2
|
+
import type { UIConfig, UITheme } from "@lobb-js/core";
|
|
3
|
+
|
|
4
|
+
// Re-export so existing imports of UITheme from the studio package
|
|
5
|
+
// keep working without touching every consumer.
|
|
6
|
+
export type { UITheme };
|
|
2
7
|
|
|
3
8
|
export interface CollectionTab {
|
|
4
9
|
id?: string;
|
|
@@ -27,14 +32,9 @@ interface Collection {
|
|
|
27
32
|
}
|
|
28
33
|
type Collections = Record<string, Collection>;
|
|
29
34
|
|
|
30
|
-
export interface UITheme {
|
|
31
|
-
light?: Record<string, string>;
|
|
32
|
-
dark?: Record<string, string>;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
35
|
interface Meta {
|
|
36
36
|
version: string;
|
|
37
|
-
ui?:
|
|
37
|
+
ui?: UIConfig;
|
|
38
38
|
relations: Array<any>;
|
|
39
39
|
collections: Collections;
|
|
40
40
|
extensions: Record<string, any>;
|