@lobb-js/studio 0.29.0 → 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.
- package/README.md +1 -0
- package/dist/actions.d.ts +2 -0
- package/dist/components/Studio.svelte +39 -43
- package/dist/components/StudioRoot.svelte +19 -0
- package/dist/components/StudioRoot.svelte.d.ts +6 -0
- package/dist/components/breadCrumbs.svelte +5 -4
- package/dist/components/codeEditor.svelte +1 -1
- package/dist/components/dataTable/dataTable.svelte +35 -20
- package/dist/components/dataTable/dataTable.svelte.d.ts +2 -1
- package/dist/components/dataTable/dataTableTabs.svelte +4 -2
- package/dist/components/dataTable/dataTableTabs.svelte.d.ts +2 -0
- package/dist/components/dataTable/header.svelte +15 -11
- package/dist/components/dataTable/header.svelte.d.ts +1 -0
- package/dist/components/dataTable/listViewChildren.svelte +4 -6
- package/dist/components/dataTable/listViewChildren.svelte.d.ts +0 -1
- package/dist/components/dataTable/table.svelte +8 -10
- package/dist/components/dataTable/table.svelte.d.ts +0 -1
- package/dist/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
- package/dist/components/dataTableDrawer/dataTableDrawer.svelte.d.ts +2 -0
- package/dist/components/detailView/create/children.svelte +1 -1
- package/dist/components/detailView/create/createDetailView.svelte +19 -61
- package/dist/components/detailView/create/createManyView.svelte +2 -4
- package/dist/components/detailView/detailView.svelte +81 -0
- package/dist/components/detailView/detailView.svelte.d.ts +8 -0
- 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/updateDetailView.svelte +32 -69
- package/dist/components/diffViewer.svelte +1 -1
- package/dist/components/extensionsComponents.svelte +3 -1
- package/dist/components/foreingKeyInput.svelte +2 -2
- package/dist/components/importButton.svelte +12 -9
- package/dist/components/landing.svelte +7 -0
- package/dist/components/landing.svelte.d.ts +6 -14
- package/dist/components/miniSidebar.svelte +86 -15
- package/dist/components/miniSidebar.svelte.d.ts +2 -17
- 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/collections/collections.svelte +32 -10
- package/dist/components/routes/data_model/dataModel.svelte +6 -28
- package/dist/components/routes/data_model/dataModel.svelte.d.ts +17 -2
- package/dist/components/routes/extensions/publicExtension.svelte +19 -0
- package/dist/components/routes/extensions/publicExtension.svelte.d.ts +13 -0
- package/dist/components/routes/home.svelte +2 -2
- package/dist/components/routes/workflows/workflows.svelte +4 -4
- package/dist/components/sidebar/sidebar.svelte +1 -1
- package/dist/components/sidebar/sidebarElements.svelte +4 -4
- package/dist/components/singletone.svelte +4 -6
- package/dist/components/ui/button/button.svelte +2 -3
- package/dist/components/workflowEditor.svelte +2 -2
- package/dist/eventSystem.d.ts +1 -1
- package/dist/eventSystem.js +7 -5
- package/dist/extensions/extension.types.d.ts +38 -14
- package/dist/extensions/extensionUtils.js +4 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/store.types.d.ts +1 -1
- package/dist/studioLifecycle.svelte.d.ts +2 -0
- package/dist/studioLifecycle.svelte.js +15 -0
- package/package.json +3 -4
- package/src/app.css +3 -0
- package/src/lib/actions.ts +2 -0
- package/src/lib/components/Studio.svelte +39 -43
- package/src/lib/components/StudioRoot.svelte +19 -0
- package/src/lib/components/breadCrumbs.svelte +5 -4
- package/src/lib/components/codeEditor.svelte +1 -1
- package/src/lib/components/dataTable/dataTable.svelte +35 -20
- package/src/lib/components/dataTable/dataTableTabs.svelte +4 -2
- package/src/lib/components/dataTable/header.svelte +15 -11
- package/src/lib/components/dataTable/listViewChildren.svelte +4 -6
- package/src/lib/components/dataTable/table.svelte +8 -10
- package/src/lib/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
- package/src/lib/components/detailView/create/children.svelte +1 -1
- package/src/lib/components/detailView/create/createDetailView.svelte +19 -61
- package/src/lib/components/detailView/create/createManyView.svelte +2 -4
- package/src/lib/components/detailView/detailView.svelte +81 -0
- 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/updateDetailView.svelte +32 -69
- package/src/lib/components/diffViewer.svelte +1 -1
- package/src/lib/components/extensionsComponents.svelte +3 -1
- package/src/lib/components/foreingKeyInput.svelte +2 -2
- package/src/lib/components/importButton.svelte +12 -9
- package/src/lib/components/landing.svelte +7 -0
- package/src/lib/components/miniSidebar.svelte +86 -15
- 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/collections/collections.svelte +32 -10
- package/src/lib/components/routes/data_model/dataModel.svelte +6 -28
- package/src/lib/components/routes/extensions/publicExtension.svelte +19 -0
- package/src/lib/components/routes/home.svelte +2 -2
- package/src/lib/components/routes/workflows/workflows.svelte +4 -4
- package/src/lib/components/sidebar/sidebar.svelte +1 -1
- package/src/lib/components/sidebar/sidebarElements.svelte +4 -4
- package/src/lib/components/singletone.svelte +4 -6
- package/src/lib/components/ui/button/button.svelte +2 -3
- package/src/lib/components/workflowEditor.svelte +2 -2
- package/src/lib/eventSystem.ts +8 -7
- package/src/lib/extensions/extension.types.ts +39 -6
- package/src/lib/extensions/extensionUtils.ts +4 -2
- package/src/lib/index.ts +3 -1
- package/src/lib/store.types.ts +1 -1
- package/src/lib/studioLifecycle.svelte.ts +17 -0
- package/dist/components/routes/data_model/syncManager.svelte +0 -94
- package/dist/components/routes/data_model/syncManager.svelte.d.ts +0 -3
- package/src/lib/components/routes/data_model/syncManager.svelte +0 -94
package/README.md
CHANGED
package/dist/actions.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CreateDetailViewProp } from "./components/detailView/create/createDetailView.svelte";
|
|
2
2
|
import type { UpdateDetailViewProp } from "./components/detailView/update/updateDetailView.svelte";
|
|
3
3
|
import type { StudioContext } from "./context";
|
|
4
|
+
import type { CollectionTab } from "./store.types";
|
|
4
5
|
export interface OpenDataTableDrawerProps {
|
|
5
6
|
collectionName: string;
|
|
6
7
|
filter?: Record<string, any>;
|
|
@@ -8,6 +9,7 @@ export interface OpenDataTableDrawerProps {
|
|
|
8
9
|
showHeader?: boolean;
|
|
9
10
|
showFooter?: boolean;
|
|
10
11
|
position?: "side" | "bottom";
|
|
12
|
+
tabs?: CollectionTab[];
|
|
11
13
|
}
|
|
12
14
|
export declare function showDialog(title: string, description: string): Promise<boolean>;
|
|
13
15
|
export declare function openCreateDetailView(studioContext: StudioContext, props: CreateDetailViewProp): void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Toaster } from "./ui/sonner";
|
|
3
|
-
import { onMount
|
|
3
|
+
import { onMount } from "svelte";
|
|
4
4
|
import { ModeWatcher } from "mode-watcher";
|
|
5
5
|
import { createLobb } from "../store.svelte";
|
|
6
6
|
import { setStudioContext } from "../context";
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
import { LoaderCircle, ServerOff } from "lucide-svelte";
|
|
9
9
|
import MiniSidebar from "./miniSidebar.svelte";
|
|
10
10
|
import * as Tooltip from "./ui/tooltip";
|
|
11
|
-
import {
|
|
11
|
+
import { page } from "$app/state";
|
|
12
|
+
import { afterNavigate } from "$app/navigation";
|
|
12
13
|
import {
|
|
13
14
|
executeExtensionsOnStartup,
|
|
14
15
|
executeExtensionsOnRouteChange,
|
|
@@ -22,6 +23,7 @@
|
|
|
22
23
|
import Collections from "./routes/collections/collections.svelte";
|
|
23
24
|
import Workflows from "./routes/workflows/workflows.svelte";
|
|
24
25
|
import Extension from "./routes/extensions/extension.svelte";
|
|
26
|
+
import PublicExtension from "./routes/extensions/publicExtension.svelte";
|
|
25
27
|
|
|
26
28
|
interface StudioProps {
|
|
27
29
|
lobbUrl?: string;
|
|
@@ -42,13 +44,11 @@
|
|
|
42
44
|
|
|
43
45
|
let status: "loading" | "error" | "ready" = $state("loading");
|
|
44
46
|
let isSmallScreen = $derived(!mediaQueries.sm.current);
|
|
45
|
-
let cleanupRouter: (() => void) | undefined;
|
|
46
47
|
|
|
47
48
|
onMount(async () => {
|
|
48
49
|
// Remove the static loading screen defined in app.html — it shows instantly
|
|
49
50
|
// before JS loads to avoid a blank page, and is replaced by the Studio UI.
|
|
50
51
|
document.getElementById("app-loading")?.remove();
|
|
51
|
-
cleanupRouter = initRouter();
|
|
52
52
|
try {
|
|
53
53
|
ctx.meta = await lobb.getMeta();
|
|
54
54
|
ctx.extensions = await loadExtensions(lobb, ctx, extensionMap);
|
|
@@ -59,19 +59,13 @@
|
|
|
59
59
|
console.error(err);
|
|
60
60
|
status = "error";
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
// Fire onRouteChange hooks on every navigation
|
|
64
|
-
const onRouteChange = () => executeExtensionsOnRouteChange(lobb, ctx as any, window.location.pathname);
|
|
65
|
-
const originalPushState = history.pushState.bind(history);
|
|
66
|
-
history.pushState = function (...args) {
|
|
67
|
-
originalPushState(...args);
|
|
68
|
-
onRouteChange();
|
|
69
|
-
};
|
|
70
|
-
window.addEventListener("popstate", onRouteChange);
|
|
71
62
|
});
|
|
72
63
|
|
|
73
|
-
|
|
74
|
-
|
|
64
|
+
// Fire onRouteChange hooks via SvelteKit's afterNavigate lifecycle instead
|
|
65
|
+
// of monkey-patching history.pushState. Runs both on initial mount and on
|
|
66
|
+
// every client-side navigation.
|
|
67
|
+
afterNavigate(() => {
|
|
68
|
+
executeExtensionsOnRouteChange(lobb, ctx as any, page.url.pathname);
|
|
75
69
|
});
|
|
76
70
|
</script>
|
|
77
71
|
|
|
@@ -94,6 +88,18 @@
|
|
|
94
88
|
<div class="text-xs">Could not connect to the lobb server at this endpoint ({ctx.lobbUrl})</div>
|
|
95
89
|
</div>
|
|
96
90
|
</div>
|
|
91
|
+
{:else if page.url.pathname.startsWith("/studio/public/")}
|
|
92
|
+
<!-- Public extension pages skip the dashboard chrome (no sidebar, no
|
|
93
|
+
header) since the viewer is unauthenticated and shouldn't see any
|
|
94
|
+
navigation to gated areas. -->
|
|
95
|
+
<Tooltip.Provider delayDuration={0} disableHoverableContent={true}>
|
|
96
|
+
<main class="bg-background h-screen w-screen">
|
|
97
|
+
<PublicExtension
|
|
98
|
+
extension={page.url.pathname.split("/")[3]}
|
|
99
|
+
page={page.url.pathname.split("/")[4]}
|
|
100
|
+
/>
|
|
101
|
+
</main>
|
|
102
|
+
</Tooltip.Provider>
|
|
97
103
|
{:else}
|
|
98
104
|
<Tooltip.Provider delayDuration={0} disableHoverableContent={true}>
|
|
99
105
|
<main
|
|
@@ -103,34 +109,24 @@
|
|
|
103
109
|
<MiniSidebar />
|
|
104
110
|
<div class="second_grid">
|
|
105
111
|
<Header />
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
<Workflows workflowName={params?.workflow} />
|
|
125
|
-
{/snippet}
|
|
126
|
-
</Route>
|
|
127
|
-
<Route key="extensions" path="/extensions/:extension?/:page?/*">
|
|
128
|
-
{#snippet children(params)}
|
|
129
|
-
<Extension extension={params?.extension} page={params?.page} />
|
|
130
|
-
{/snippet}
|
|
131
|
-
</Route>
|
|
132
|
-
<Fallback>Not Found</Fallback>
|
|
133
|
-
</Router>
|
|
112
|
+
{#if page.url.pathname.replace(/\/$/, "") === "/studio"}
|
|
113
|
+
<Home />
|
|
114
|
+
{:else if page.url.pathname.startsWith("/studio/collections")}
|
|
115
|
+
<Collections collectionName={page.url.pathname.split("/")[3]} />
|
|
116
|
+
{:else if page.url.pathname.startsWith("/studio/datamodel")}
|
|
117
|
+
<DataModel />
|
|
118
|
+
{:else if page.url.pathname.startsWith("/studio/workflows")}
|
|
119
|
+
<Workflows workflowName={page.url.pathname.split("/")[3]} />
|
|
120
|
+
{:else if page.url.pathname.startsWith("/studio/extensions")}
|
|
121
|
+
<Extension
|
|
122
|
+
extension={page.url.pathname.split("/")[3]}
|
|
123
|
+
page={page.url.pathname.split("/")[4]}
|
|
124
|
+
/>
|
|
125
|
+
{:else}
|
|
126
|
+
<div class="flex h-full w-full items-center justify-center text-muted-foreground">
|
|
127
|
+
Not Found
|
|
128
|
+
</div>
|
|
129
|
+
{/if}
|
|
134
130
|
</div>
|
|
135
131
|
</main>
|
|
136
132
|
</Tooltip.Provider>
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import Studio from "./Studio.svelte";
|
|
3
|
+
import { getStudioMountKey } from "../studioLifecycle.svelte";
|
|
4
|
+
|
|
5
|
+
interface StudioRootProps {
|
|
6
|
+
lobbUrl?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let { lobbUrl }: StudioRootProps = $props();
|
|
10
|
+
|
|
11
|
+
// Tracked so any change to the mount key tears down the Studio tree and
|
|
12
|
+
// mounts a fresh one — fresh ctx, fresh extension load, fresh /me, etc.
|
|
13
|
+
// Bumped by remountStudio() on login/logout.
|
|
14
|
+
const mountKey = $derived(getStudioMountKey());
|
|
15
|
+
</script>
|
|
16
|
+
|
|
17
|
+
{#key mountKey}
|
|
18
|
+
<Studio {lobbUrl} />
|
|
19
|
+
{/key}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import * as Breadcrumb from "./ui/breadcrumb";
|
|
3
3
|
import { mediaQueries } from "../utils";
|
|
4
|
-
import {
|
|
4
|
+
import { page } from "$app/state";
|
|
5
|
+
import { goto } from "$app/navigation";
|
|
5
6
|
|
|
6
7
|
const isSmall = $derived(!mediaQueries.sm.current);
|
|
7
8
|
const pathNames = $derived(
|
|
8
|
-
|
|
9
|
+
page.url.pathname
|
|
9
10
|
.replace("/studio", "")
|
|
10
11
|
.split("/")
|
|
11
12
|
.filter((el: any) => el !== "")
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
{:else}
|
|
27
28
|
<Breadcrumb.Link
|
|
28
29
|
class="cursor-pointer"
|
|
29
|
-
onclick={() =>
|
|
30
|
+
onclick={() => goto("/studio")}
|
|
30
31
|
>
|
|
31
32
|
Home
|
|
32
33
|
</Breadcrumb.Link>
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
<Breadcrumb.Link
|
|
46
47
|
class="cursor-pointer"
|
|
47
48
|
onclick={() =>
|
|
48
|
-
|
|
49
|
+
goto(`/studio/${currentFullPaths}`)}
|
|
49
50
|
>
|
|
50
51
|
{path}
|
|
51
52
|
</Breadcrumb.Link>
|
|
@@ -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-soft h-60', className)}>
|
|
136
136
|
<div bind:this={editorContainer} class="h-full w-full pl-2" />
|
|
137
137
|
</div>
|
|
138
138
|
|
|
@@ -24,8 +24,11 @@
|
|
|
24
24
|
import type { Changes, ChildrenChanges } from "../detailView/utils";
|
|
25
25
|
import ExtensionsComponents from "../extensionsComponents.svelte";
|
|
26
26
|
import { getExtensionUtils, loadExtensionComponents } from "../../extensions/extensionUtils";
|
|
27
|
+
import { emitEvent } from "../../eventSystem";
|
|
28
|
+
import { onMount } from "svelte";
|
|
27
29
|
import Tabs from "./dataTableTabs.svelte";
|
|
28
30
|
import { fade } from "svelte/transition";
|
|
31
|
+
import type { CollectionTab } from "../../store.types";
|
|
29
32
|
|
|
30
33
|
const { lobb, ctx } = getStudioContext();
|
|
31
34
|
|
|
@@ -38,9 +41,9 @@
|
|
|
38
41
|
showHeader?: boolean;
|
|
39
42
|
showFooter?: boolean;
|
|
40
43
|
showImport?: boolean;
|
|
41
|
-
unifiedBgColor?: "bg-muted/30" | "bg-background";
|
|
42
44
|
showDelete?: boolean;
|
|
43
45
|
tableProps?: Partial<TableProps>;
|
|
46
|
+
tabs?: CollectionTab[];
|
|
44
47
|
headerLeft?: Snippet<[]>;
|
|
45
48
|
}
|
|
46
49
|
|
|
@@ -53,12 +56,26 @@
|
|
|
53
56
|
showHeader = true,
|
|
54
57
|
showFooter = true,
|
|
55
58
|
showImport = true,
|
|
56
|
-
unifiedBgColor,
|
|
57
59
|
showDelete = false,
|
|
58
60
|
tableProps,
|
|
61
|
+
tabs,
|
|
59
62
|
headerLeft,
|
|
60
63
|
}: Props = $props();
|
|
61
64
|
|
|
65
|
+
// Gate row/header buttons by the current user's permissions:
|
|
66
|
+
// - showUpdate → per-row edit button
|
|
67
|
+
// - showCreate → header's Create + Import buttons (passed to Header)
|
|
68
|
+
let showUpdate = $state(false);
|
|
69
|
+
let showCreate = $state(false);
|
|
70
|
+
onMount(async () => {
|
|
71
|
+
const [update, create] = await Promise.all([
|
|
72
|
+
emitEvent({ lobb, ctx }, "auth.canAccess", { collection: collectionName, action: "update" }),
|
|
73
|
+
emitEvent({ lobb, ctx }, "auth.canAccess", { collection: collectionName, action: "create" }),
|
|
74
|
+
]);
|
|
75
|
+
showUpdate = update === true;
|
|
76
|
+
showCreate = create === true;
|
|
77
|
+
});
|
|
78
|
+
|
|
62
79
|
function getOrCreateUpdatedSlot(recordId: string): Changes | undefined {
|
|
63
80
|
if (!changes) return undefined;
|
|
64
81
|
let slot = changes.updated.find((u) => String(u.id) === String(recordId));
|
|
@@ -191,10 +208,7 @@
|
|
|
191
208
|
|
|
192
209
|
<div
|
|
193
210
|
bind:clientWidth={dataTableContainerWidth}
|
|
194
|
-
class="
|
|
195
|
-
flex flex-col overflow-auto h-full w-full
|
|
196
|
-
{unifiedBgColor ? unifiedBgColor : ''}
|
|
197
|
-
"
|
|
211
|
+
class="flex flex-col overflow-auto h-full w-full"
|
|
198
212
|
>
|
|
199
213
|
{#snippet rowActionsSnippet(entry: Record<string, any>)}
|
|
200
214
|
<ExtensionsComponents
|
|
@@ -212,6 +226,7 @@
|
|
|
212
226
|
{collectionName}
|
|
213
227
|
bind:selectedRecords
|
|
214
228
|
{showImport}
|
|
229
|
+
{showCreate}
|
|
215
230
|
{parentContext}
|
|
216
231
|
{changes}
|
|
217
232
|
>
|
|
@@ -220,7 +235,7 @@
|
|
|
220
235
|
{/snippet}
|
|
221
236
|
</Header>
|
|
222
237
|
{/if}
|
|
223
|
-
<Tabs {collectionName} {filter} bind:activeTabFilter />
|
|
238
|
+
<Tabs {collectionName} {filter} {tabs} bind:activeTabFilter />
|
|
224
239
|
<div class="relative flex-1 overflow-auto w-full">
|
|
225
240
|
{#key activeTabFilter}
|
|
226
241
|
<div class="h-full w-full" in:fade={{ duration: 120 }}>
|
|
@@ -240,22 +255,23 @@
|
|
|
240
255
|
showLastColumnBorder={true}
|
|
241
256
|
bind:sort={params.sort}
|
|
242
257
|
bind:selectedRecords
|
|
243
|
-
{unifiedBgColor}
|
|
244
258
|
bind:tableWidth={dataTableWidth}
|
|
245
259
|
{...tableProps}
|
|
246
260
|
rowActions={hasRowActions ? rowActionsSnippet : undefined}>
|
|
247
261
|
{#snippet tools(entry)}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
262
|
+
{#if showUpdate}
|
|
263
|
+
<UpdateDetailViewButton
|
|
264
|
+
{collectionName}
|
|
265
|
+
recordId={entry.id}
|
|
266
|
+
variant="ghost"
|
|
267
|
+
class="h-5 w-5 px-0 py-0 text-muted-foreground hover:bg-transparent"
|
|
268
|
+
Icon={Pencil}
|
|
269
|
+
changes={getOrCreateUpdatedSlot(String(entry.id))}
|
|
270
|
+
onSuccessfullSave={async () => {
|
|
271
|
+
params = { ...params };
|
|
272
|
+
}}
|
|
273
|
+
></UpdateDetailViewButton>
|
|
274
|
+
{/if}
|
|
259
275
|
{#if parentContext}
|
|
260
276
|
<Button
|
|
261
277
|
class="h-6 w-6 text-muted-foreground hover:bg-transparent"
|
|
@@ -293,7 +309,6 @@
|
|
|
293
309
|
width={dataTableWidth > dataTableContainerWidth
|
|
294
310
|
? dataTableContainerWidth
|
|
295
311
|
: dataTableWidth}
|
|
296
|
-
unifiedBgColor={unifiedBgColor ?? "bg-background"}
|
|
297
312
|
/>
|
|
298
313
|
{/snippet}
|
|
299
314
|
</Table>
|
|
@@ -5,6 +5,7 @@ export interface ParentContext {
|
|
|
5
5
|
import { type TableProps } from "./table.svelte";
|
|
6
6
|
import type { Snippet } from "svelte";
|
|
7
7
|
import type { ChildrenChanges } from "../detailView/utils";
|
|
8
|
+
import type { CollectionTab } from "../../store.types";
|
|
8
9
|
interface Props {
|
|
9
10
|
collectionName: string;
|
|
10
11
|
filter?: any;
|
|
@@ -14,9 +15,9 @@ interface Props {
|
|
|
14
15
|
showHeader?: boolean;
|
|
15
16
|
showFooter?: boolean;
|
|
16
17
|
showImport?: boolean;
|
|
17
|
-
unifiedBgColor?: "bg-muted/30" | "bg-background";
|
|
18
18
|
showDelete?: boolean;
|
|
19
19
|
tableProps?: Partial<TableProps>;
|
|
20
|
+
tabs?: CollectionTab[];
|
|
20
21
|
headerLeft?: Snippet<[]>;
|
|
21
22
|
}
|
|
22
23
|
declare const DataTable: import("svelte").Component<Props, {}, "changes">;
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { getStudioContext } from "../../context";
|
|
3
|
+
import type { CollectionTab } from "../../store.types";
|
|
3
4
|
|
|
4
5
|
const { lobb, ctx } = getStudioContext();
|
|
5
6
|
|
|
6
7
|
interface Props {
|
|
7
8
|
collectionName: string;
|
|
8
9
|
filter?: any;
|
|
10
|
+
tabs?: CollectionTab[];
|
|
9
11
|
activeTabFilter?: any;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
let { collectionName, filter, activeTabFilter = $bindable() }: Props = $props();
|
|
14
|
+
let { collectionName, filter, tabs: tabsProp, activeTabFilter = $bindable() }: Props = $props();
|
|
13
15
|
|
|
14
|
-
const tabs = ctx.meta.collections[collectionName].ui?.tabs;
|
|
16
|
+
const tabs: CollectionTab[] | undefined = $derived(tabsProp ?? ctx.meta.collections[collectionName].ui?.tabs);
|
|
15
17
|
let activeTab = $state<string | null>(null);
|
|
16
18
|
let tabCounts = $state<Record<string, number>>({});
|
|
17
19
|
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
parentContext?: ParentContext;
|
|
26
26
|
changes?: ChildrenChanges;
|
|
27
27
|
showImport?: boolean;
|
|
28
|
+
showCreate?: boolean;
|
|
28
29
|
left?: Snippet<[]>;
|
|
29
30
|
}
|
|
30
31
|
|
|
@@ -35,6 +36,7 @@
|
|
|
35
36
|
parentContext,
|
|
36
37
|
changes,
|
|
37
38
|
showImport = true,
|
|
39
|
+
showCreate = false,
|
|
38
40
|
left
|
|
39
41
|
}: Props = $props();
|
|
40
42
|
|
|
@@ -167,7 +169,7 @@
|
|
|
167
169
|
>
|
|
168
170
|
{headerIsSmall ? "" : "Refresh"}
|
|
169
171
|
</Button>
|
|
170
|
-
{#if showImport}
|
|
172
|
+
{#if showImport && showCreate}
|
|
171
173
|
<Tooltip.Provider delayDuration={0}>
|
|
172
174
|
<Tooltip.Root>
|
|
173
175
|
<Tooltip.Trigger>
|
|
@@ -200,15 +202,17 @@
|
|
|
200
202
|
{headerIsSmall ? "" : "Link"}
|
|
201
203
|
</SelectRecord>
|
|
202
204
|
{/if}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
205
|
+
{#if showCreate}
|
|
206
|
+
<CreateDetailViewButton
|
|
207
|
+
{collectionName}
|
|
208
|
+
variant="default"
|
|
209
|
+
class="h-7 px-3 text-xs font-normal"
|
|
210
|
+
Icon={Plus}
|
|
211
|
+
changes={changes ? createChanges : undefined}
|
|
212
|
+
onSuccessfullSave={handleCreateSuccess}
|
|
213
|
+
>
|
|
214
|
+
{headerIsSmall ? "" : "Create"}
|
|
215
|
+
</CreateDetailViewButton>
|
|
216
|
+
{/if}
|
|
213
217
|
</div>
|
|
214
218
|
</div>
|
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
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>;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
340
|
-
|
|
337
|
+
sticky left-0 top-0 overflow-auto bg-muted-soft
|
|
338
|
+
|
|
341
339
|
{expandedRows[index] ? 'border-t' : ''}
|
|
342
340
|
"
|
|
343
341
|
>
|
|
@@ -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
|
-
|
|
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, {}, "">;
|
|
@@ -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-soft border rounded-md overflow-hidden"
|
|
41
41
|
bind:value={entry[child.collection]}
|
|
42
42
|
>
|
|
43
43
|
<CreateManyView
|