@lobb-js/studio 0.1.31 → 0.1.33
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/package.json +24 -14
- package/src/{Studio.svelte → lib/components/Studio.svelte} +8 -8
- package/src/lib/components/dataTable/childRecords.svelte +1 -1
- package/src/lib/components/detailView/create/children.svelte +1 -1
- package/src/lib/components/detailView/create/createDetailView.svelte +1 -1
- package/src/lib/components/detailView/fieldInput.svelte +1 -1
- package/src/lib/components/detailView/update/children.svelte +1 -1
- package/src/lib/components/detailView/update/updateDetailView.svelte +1 -1
- package/src/lib/components/extensionsComponents.svelte +1 -2
- package/src/lib/components/miniSidebar.svelte +1 -1
- package/{vite-plugin-contextual-lib.js → vite-plugins/contextual-lib-alias.js} +2 -7
- package/vite-plugins/index.js +21 -0
- package/vite-plugins/studio-source-resolver.js +41 -0
- package/.env.example +0 -1
- package/.storybook/main.ts +0 -31
- package/.storybook/preview.ts +0 -21
- package/.storybook/vitest.setup.ts +0 -7
- package/components.json +0 -16
- package/docker-entrypoint.sh +0 -7
- package/dockerfile +0 -27
- package/index.html +0 -13
- package/public/lobb.svg +0 -15
- package/src/app.css +0 -121
- package/src/components-export.ts +0 -21
- package/src/extensions/extension.types.ts +0 -93
- package/src/extensions/extensionUtils.ts +0 -192
- package/src/lib/Lobb.ts +0 -241
- package/src/lib/eventSystem.ts +0 -38
- package/src/lib/index.ts +0 -40
- package/src/lib/store.svelte.ts +0 -21
- package/src/lib/store.types.ts +0 -28
- package/src/lib/utils.ts +0 -84
- package/src/main.ts +0 -18
- package/src/routes/collections/collection.svelte +0 -46
- package/src/routes/collections/collections.svelte +0 -43
- package/src/routes/data_model/dataModel.svelte +0 -40
- package/src/routes/data_model/flow.css +0 -22
- package/src/routes/data_model/flow.svelte +0 -82
- package/src/routes/data_model/syncManager.svelte +0 -93
- package/src/routes/data_model/utils.ts +0 -35
- package/src/routes/extensions/extension.svelte +0 -16
- package/src/routes/home.svelte +0 -36
- package/src/routes/workflows/workflows.svelte +0 -135
- package/src/stories/Configure.mdx +0 -364
- package/src/stories/assets/accessibility.png +0 -0
- package/src/stories/assets/accessibility.svg +0 -1
- package/src/stories/assets/addon-library.png +0 -0
- package/src/stories/assets/assets.png +0 -0
- package/src/stories/assets/avif-test-image.avif +0 -0
- package/src/stories/assets/context.png +0 -0
- package/src/stories/assets/discord.svg +0 -1
- package/src/stories/assets/docs.png +0 -0
- package/src/stories/assets/figma-plugin.png +0 -0
- package/src/stories/assets/github.svg +0 -1
- package/src/stories/assets/share.png +0 -0
- package/src/stories/assets/styling.png +0 -0
- package/src/stories/assets/testing.png +0 -0
- package/src/stories/assets/theming.png +0 -0
- package/src/stories/assets/tutorials.svg +0 -1
- package/src/stories/assets/youtube.svg +0 -1
- package/src/stories/detailView/detailViewForm.stories.svelte +0 -79
- package/src/stories/examples/Button.stories.svelte +0 -31
- package/src/stories/examples/Button.svelte +0 -30
- package/src/stories/examples/Header.stories.svelte +0 -26
- package/src/stories/examples/Header.svelte +0 -45
- package/src/stories/examples/Page.stories.svelte +0 -29
- package/src/stories/examples/Page.svelte +0 -70
- package/src/stories/examples/button.css +0 -30
- package/src/stories/examples/header.css +0 -32
- package/src/stories/examples/page.css +0 -68
- package/src/vite-env.d.ts +0 -2
- package/svelte.config.js +0 -7
- package/todo.md +0 -24
- package/tsconfig.app.json +0 -25
- package/tsconfig.json +0 -14
- package/tsconfig.node.json +0 -24
- package/vite.build.svelte.config.ts +0 -18
- package/vite.config.ts +0 -84
- package/vite.extension.config.ts +0 -81
- package/vite_utils.ts +0 -28
- package/vitest.shims.d.ts +0 -1
package/src/lib/utils.ts
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { clsx, type ClassValue } from "clsx";
|
|
2
|
-
import { twMerge } from "tailwind-merge";
|
|
3
|
-
|
|
4
|
-
import { fileOpen } from 'browser-fs-access';
|
|
5
|
-
import { MediaQuery } from 'svelte/reactivity';
|
|
6
|
-
import { ctx } from "./store.svelte";
|
|
7
|
-
|
|
8
|
-
export function cn(...inputs: ClassValue[]) {
|
|
9
|
-
return twMerge(clsx(inputs));
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
13
|
-
export type WithoutChild<T> = T extends { child?: any } ? Omit<T, "child"> : T;
|
|
14
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
|
-
export type WithoutChildren<T> = T extends { children?: any } ? Omit<T, "children"> : T;
|
|
16
|
-
export type WithoutChildrenOrChild<T> = WithoutChildren<WithoutChild<T>>;
|
|
17
|
-
export type WithElementRef<T, U extends HTMLElement = HTMLElement> = T & { ref?: U | null };
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
export const mediaQueries = {
|
|
21
|
-
sm: new MediaQuery('min-width: 640px'),
|
|
22
|
-
md: new MediaQuery('min-width: 768px'),
|
|
23
|
-
lg: new MediaQuery('min-width: 1024px'),
|
|
24
|
-
xl: new MediaQuery('min-width: 1280px'),
|
|
25
|
-
'2xl': new MediaQuery('min-width: 1536px'),
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export async function getFileFromUser() {
|
|
29
|
-
return await fileOpen()
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
export function getFieldRelation(collectionName: string, fieldName: string) {
|
|
33
|
-
const relations = ctx.meta.relations;
|
|
34
|
-
for (let index = 0; index < relations.length; index++) {
|
|
35
|
-
const relation = relations[index];
|
|
36
|
-
if (relation.from.collection === collectionName && relation.from.field === fieldName) {
|
|
37
|
-
return relation;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export function getDiscriminatorFieldRelation(collectionName: string, fieldName: string) {
|
|
44
|
-
const relations = ctx.meta.relations;
|
|
45
|
-
for (let index = 0; index < relations.length; index++) {
|
|
46
|
-
const relation = relations[index];
|
|
47
|
-
if (relation.from.collection === collectionName && relation.from.discriminator === fieldName) {
|
|
48
|
-
return relation;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
export function recordHasChildrean(collectionName: string) {
|
|
55
|
-
for (let index = 0; index < ctx.meta.relations.length; index++) {
|
|
56
|
-
const relation = ctx.meta.relations[index];
|
|
57
|
-
if (relation.to.collection === collectionName) {
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
return false;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export function calculateDrawerWidth() {
|
|
65
|
-
const backgroundDrawerButtons = document.querySelectorAll(".backgroundDrawerButton");
|
|
66
|
-
const drawersCount = Array.from(backgroundDrawerButtons).length;
|
|
67
|
-
const width = 672 - (30 * drawersCount);
|
|
68
|
-
return width;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export function getChangedProperties(oldObj: Record<string, any>, newObj: Record<string, any>) {
|
|
72
|
-
const changes: Record<string, any> = {};
|
|
73
|
-
for (const key of Object.keys(newObj)) {
|
|
74
|
-
if (oldObj[key] !== newObj[key]) {
|
|
75
|
-
changes[key] = newObj[key];
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
return changes;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export function parseFunction(functionString: string) {
|
|
82
|
-
const functionObj = new Function("return " + functionString)();
|
|
83
|
-
return functionObj;
|
|
84
|
-
};
|
package/src/main.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import "./app.css";
|
|
2
|
-
|
|
3
|
-
import { mount } from 'svelte'
|
|
4
|
-
import Studio from './Studio.svelte'
|
|
5
|
-
|
|
6
|
-
declare global {
|
|
7
|
-
interface Window {
|
|
8
|
-
APP_ENV: {
|
|
9
|
-
LOBB_URL: string
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const app = mount(Studio, {
|
|
15
|
-
target: document.getElementById('app')!,
|
|
16
|
-
})
|
|
17
|
-
|
|
18
|
-
export default app
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import { CircleSlash2 } from "lucide-svelte";
|
|
3
|
-
import DataTable from "$lib/components/dataTable/dataTable.svelte";
|
|
4
|
-
import SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
|
|
5
|
-
import { ctx } from "$lib/store.svelte";
|
|
6
|
-
import Singletone from "$lib/components/singletone.svelte";
|
|
7
|
-
|
|
8
|
-
let { collectionName } = $props();
|
|
9
|
-
let isSingletonCollection = $derived(ctx.meta.collections[collectionName].singleton);
|
|
10
|
-
|
|
11
|
-
let containerWidth = $state();
|
|
12
|
-
</script>
|
|
13
|
-
|
|
14
|
-
<div bind:clientWidth={containerWidth} class="h-full">
|
|
15
|
-
{#if collectionName}
|
|
16
|
-
{#if isSingletonCollection}
|
|
17
|
-
<Singletone collectionName={collectionName} />
|
|
18
|
-
{:else}
|
|
19
|
-
<DataTable
|
|
20
|
-
{collectionName}
|
|
21
|
-
tableProps={{
|
|
22
|
-
parentWidth: containerWidth,
|
|
23
|
-
}}
|
|
24
|
-
>
|
|
25
|
-
{#snippet headerLeft()}
|
|
26
|
-
<SidebarTrigger />
|
|
27
|
-
{/snippet}
|
|
28
|
-
</DataTable>
|
|
29
|
-
{/if}
|
|
30
|
-
{:else}
|
|
31
|
-
<div
|
|
32
|
-
class="relative flex h-full w-full flex-col items-center justify-center gap-4 text-muted-foreground"
|
|
33
|
-
>
|
|
34
|
-
<CircleSlash2 class="opacity-50" size="50" />
|
|
35
|
-
<div class="flex flex-col items-center justify-center">
|
|
36
|
-
<div>No collection selected</div>
|
|
37
|
-
<div class="text-xs">
|
|
38
|
-
Select a collection to view its entries or create new ones
|
|
39
|
-
</div>
|
|
40
|
-
</div>
|
|
41
|
-
<div class="absolute top-0 left-0 p-2.5">
|
|
42
|
-
<SidebarTrigger />
|
|
43
|
-
</div>
|
|
44
|
-
</div>
|
|
45
|
-
{/if}
|
|
46
|
-
</div>
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SideBarData } from "$lib/components/sidebar/sidebarElements.svelte";
|
|
3
|
-
import Sidebar from "$lib/components/sidebar/sidebar.svelte";
|
|
4
|
-
import { ctx } from "$lib/store.svelte";
|
|
5
|
-
import Collection from "./collection.svelte";
|
|
6
|
-
import { Table } from "lucide-svelte";
|
|
7
|
-
|
|
8
|
-
let { collectionName } = $props();
|
|
9
|
-
|
|
10
|
-
const collectionsList = $state(getCollectionsList());
|
|
11
|
-
|
|
12
|
-
function getCollectionsList() {
|
|
13
|
-
const collections = ctx.meta.collections;
|
|
14
|
-
let collectionsOwners: SideBarData = Object.entries(collections).map(
|
|
15
|
-
([collectionName, collectionValue]) => {
|
|
16
|
-
return {
|
|
17
|
-
name: collectionName,
|
|
18
|
-
path: collectionValue.category ?? collectionValue.owner,
|
|
19
|
-
icon: Table,
|
|
20
|
-
href: `/collections/${collectionName}`,
|
|
21
|
-
};
|
|
22
|
-
},
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
// updating the path from '__project' and '__core' to a more readable names
|
|
26
|
-
collectionsOwners = collectionsOwners.map((item) => {
|
|
27
|
-
if (item.path === "__project") {
|
|
28
|
-
item.path = "project";
|
|
29
|
-
} else if (item.path === "__core") {
|
|
30
|
-
item.path = "core";
|
|
31
|
-
}
|
|
32
|
-
return item;
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return collectionsOwners;
|
|
36
|
-
}
|
|
37
|
-
</script>
|
|
38
|
-
|
|
39
|
-
<Sidebar title="Collections" data={collectionsList}>
|
|
40
|
-
{#key collectionName}
|
|
41
|
-
<Collection {collectionName} />
|
|
42
|
-
{/key}
|
|
43
|
-
</Sidebar>
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { SvelteFlowProvider } from "@xyflow/svelte";
|
|
3
|
-
import Flow from "./flow.svelte";
|
|
4
|
-
import Sidebar from "$lib/components/sidebar/sidebar.svelte";
|
|
5
|
-
import { location } from "@wjfe/n-savant";
|
|
6
|
-
import SyncManager from "./syncManager.svelte";
|
|
7
|
-
import SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
|
|
8
|
-
|
|
9
|
-
const currentPage = $derived(location.url.pathname.split("/")[2]);
|
|
10
|
-
</script>
|
|
11
|
-
|
|
12
|
-
<Sidebar
|
|
13
|
-
title="Data Model"
|
|
14
|
-
showSearch={false}
|
|
15
|
-
data={[
|
|
16
|
-
{
|
|
17
|
-
name: "graph",
|
|
18
|
-
href: "/datamodel/graph",
|
|
19
|
-
},
|
|
20
|
-
{
|
|
21
|
-
name: "query_editor",
|
|
22
|
-
href: "/datamodel/query_editor",
|
|
23
|
-
},
|
|
24
|
-
]}
|
|
25
|
-
>
|
|
26
|
-
<div class="relative h-full w-full">
|
|
27
|
-
{#if currentPage === "graph"}
|
|
28
|
-
<SvelteFlowProvider>
|
|
29
|
-
<div style:width="100%" style:height="100%">
|
|
30
|
-
<Flow />
|
|
31
|
-
</div>
|
|
32
|
-
</SvelteFlowProvider>
|
|
33
|
-
{:else if currentPage === "query_editor"}
|
|
34
|
-
<SyncManager />
|
|
35
|
-
{/if}
|
|
36
|
-
<div class="absolute top-0 left-0 p-2.5">
|
|
37
|
-
<SidebarTrigger />
|
|
38
|
-
</div>
|
|
39
|
-
</div>
|
|
40
|
-
</Sidebar>
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
.svelte-flow {
|
|
2
|
-
--xy-edge-stroke-default: hsl(var(--muted-foreground));
|
|
3
|
-
--xy-edge-stroke-selected-default: hsl(var(--primary));
|
|
4
|
-
--xy-connectionline-stroke-default: hsl(var(--primary));
|
|
5
|
-
--xy-attribution-background-color-default: transparent;
|
|
6
|
-
--xy-minimap-background-color-default: hsl(var(--background));
|
|
7
|
-
--xy-minimap-mask-background-color-default: hsl(var(--primary) / 0.1);
|
|
8
|
-
--xy-minimap-node-background-color-default: hsl(var(--primary) / 0.2);
|
|
9
|
-
--xy-background-color-default: hsl(var(--soft));
|
|
10
|
-
--xy-background-pattern-dots-color-default: hsl(var(--muted-foreground));
|
|
11
|
-
--xy-background-pattern-lines-color-default: hsl(var(--background));
|
|
12
|
-
--xy-background-pattern-cross-color-default: hsl(var(--soft));
|
|
13
|
-
--xy-node-border-default: 1px solid hsl(var(--primary) / 0.25);
|
|
14
|
-
--xy-node-background-color-default: hsl(var(--background));
|
|
15
|
-
--xy-node-boxshadow-selected-default: 0 0 0 0.5px hsl(var(--primary) / 0.5);
|
|
16
|
-
--xy-handle-background-color-default: hsl(var(--primary));
|
|
17
|
-
--xy-handle-border-color-default: hsl(var(--background));
|
|
18
|
-
--xy-controls-button-background-color-default: hsl(var(--background));
|
|
19
|
-
--xy-controls-button-background-color-hover-default: hsl(var(--muted));
|
|
20
|
-
--xy-controls-button-border-color-default: hsl(var(--muted));
|
|
21
|
-
--xy-edge-label-background-color-default: hsl(var(--background));
|
|
22
|
-
}
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import "@xyflow/svelte/dist/style.css";
|
|
3
|
-
import "./flow.css";
|
|
4
|
-
|
|
5
|
-
import type { Node, Edge } from "@xyflow/svelte";
|
|
6
|
-
|
|
7
|
-
import {
|
|
8
|
-
SvelteFlow,
|
|
9
|
-
Background,
|
|
10
|
-
MiniMap,
|
|
11
|
-
Controls,
|
|
12
|
-
useSvelteFlow,
|
|
13
|
-
} from "@xyflow/svelte";
|
|
14
|
-
import { getLayoutedElements } from "./utils";
|
|
15
|
-
import { onMount } from "svelte";
|
|
16
|
-
import { ctx } from "$lib/store.svelte";
|
|
17
|
-
|
|
18
|
-
const { fitView } = useSvelteFlow();
|
|
19
|
-
|
|
20
|
-
let nodes = $state.raw<Node[]>(generateNodes());
|
|
21
|
-
let edges = $state.raw<Edge[]>(generateEdges());
|
|
22
|
-
|
|
23
|
-
onMount(() => {
|
|
24
|
-
setTimeout(() => {
|
|
25
|
-
onLayout();
|
|
26
|
-
}, 0);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
function generateNodes() {
|
|
30
|
-
const localNodes: Node[] = [];
|
|
31
|
-
|
|
32
|
-
for (const [collectionName, collectionValue] of Object.entries(
|
|
33
|
-
ctx.meta.collections,
|
|
34
|
-
)) {
|
|
35
|
-
if (collectionValue.owner !== "__project") {
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
localNodes.push({
|
|
40
|
-
id: collectionName,
|
|
41
|
-
data: { label: collectionName },
|
|
42
|
-
position: { x: 0, y: 0 },
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return localNodes;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function generateEdges() {
|
|
50
|
-
const localEdges: Edge[] = [];
|
|
51
|
-
|
|
52
|
-
const relations = ctx.meta.relations;
|
|
53
|
-
for (let index = 0; index < relations.length; index++) {
|
|
54
|
-
const relation = relations[index];
|
|
55
|
-
localEdges.push({
|
|
56
|
-
id: `${relation.from.collection}_${relation.to.collection}`,
|
|
57
|
-
source: relation.from.collection,
|
|
58
|
-
target: relation.to.collection,
|
|
59
|
-
animated: true,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return localEdges;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function onLayout() {
|
|
67
|
-
const layouted = getLayoutedElements(nodes, edges);
|
|
68
|
-
|
|
69
|
-
nodes = [...layouted.nodes];
|
|
70
|
-
edges = [...layouted.edges];
|
|
71
|
-
|
|
72
|
-
fitView({
|
|
73
|
-
padding: 0.5,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
</script>
|
|
77
|
-
|
|
78
|
-
<SvelteFlow bind:nodes bind:edges>
|
|
79
|
-
<Background />
|
|
80
|
-
<MiniMap />
|
|
81
|
-
<Controls />
|
|
82
|
-
</SvelteFlow>
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import DiffViewer from "$lib/components/diffViewer.svelte";
|
|
3
|
-
import { ctx } from "$lib/store.svelte";
|
|
4
|
-
import { onMount } from "svelte";
|
|
5
|
-
import stringify from "json-stable-stringify";
|
|
6
|
-
import MonacoEditor from "$lib/components/monacoEditor.svelte";
|
|
7
|
-
import Table from "$lib/components/dataTable/table.svelte";
|
|
8
|
-
import Button from "$lib/components/ui/button/button.svelte";
|
|
9
|
-
import { LoaderCircle, SendHorizontal } from "lucide-svelte";
|
|
10
|
-
import { lobb } from "$lib";
|
|
11
|
-
|
|
12
|
-
let configSchema: string = $state("");
|
|
13
|
-
let dbSchema: string = $state("");
|
|
14
|
-
let sqlPrompt = $state("");
|
|
15
|
-
let sqlResult = $state([]);
|
|
16
|
-
|
|
17
|
-
onMount(() => {
|
|
18
|
-
loadSchemas();
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
async function loadSchemas() {
|
|
22
|
-
configSchema = "";
|
|
23
|
-
dbSchema = "";
|
|
24
|
-
const response = await fetch(`${ctx.lobbUrl}/api/schema/diff`);
|
|
25
|
-
const result = await response.json();
|
|
26
|
-
configSchema = stringify(result.dbSchema, {
|
|
27
|
-
space: 2,
|
|
28
|
-
}) as string;
|
|
29
|
-
dbSchema = stringify(result.configSchema, {
|
|
30
|
-
space: 2,
|
|
31
|
-
}) as string;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function handleExecute() {
|
|
35
|
-
const response = await lobb.createOne("core_query", {
|
|
36
|
-
query: sqlPrompt,
|
|
37
|
-
});
|
|
38
|
-
const result = await response.json();
|
|
39
|
-
sqlResult = result.data;
|
|
40
|
-
loadSchemas();
|
|
41
|
-
}
|
|
42
|
-
</script>
|
|
43
|
-
|
|
44
|
-
<div class="h-[50%] border-b">
|
|
45
|
-
{#if configSchema && dbSchema}
|
|
46
|
-
<DiffViewer
|
|
47
|
-
type="json"
|
|
48
|
-
original={configSchema}
|
|
49
|
-
modified={dbSchema}
|
|
50
|
-
class="h-full rounded-none border-0"
|
|
51
|
-
/>
|
|
52
|
-
{:else}
|
|
53
|
-
<div class="flex justify-center items-center h-full gap-2">
|
|
54
|
-
<LoaderCircle class="animate-spin" />
|
|
55
|
-
<div>loading...</div>
|
|
56
|
-
</div>
|
|
57
|
-
{/if}
|
|
58
|
-
</div>
|
|
59
|
-
<div class="flex h-[50%] w-full">
|
|
60
|
-
<div class="h-full flex-1 flex flex-col border-r">
|
|
61
|
-
<div
|
|
62
|
-
class="h-10 flex items-center px-2 bg-background border-b justify-between"
|
|
63
|
-
>
|
|
64
|
-
<div>Query Editor</div>
|
|
65
|
-
<Button
|
|
66
|
-
class="h-7 px-3 text-xs font-normal"
|
|
67
|
-
Icon={SendHorizontal}
|
|
68
|
-
onclick={handleExecute}
|
|
69
|
-
>
|
|
70
|
-
Execute
|
|
71
|
-
</Button>
|
|
72
|
-
</div>
|
|
73
|
-
<MonacoEditor
|
|
74
|
-
type="sql"
|
|
75
|
-
name="prompt"
|
|
76
|
-
bind:value={sqlPrompt}
|
|
77
|
-
class="flex-1 rounded-none border-0"
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
<div class="flex-1">
|
|
81
|
-
{#if Array.isArray(sqlResult) && sqlResult.length}
|
|
82
|
-
<Table
|
|
83
|
-
data={sqlResult}
|
|
84
|
-
showLastRowBorder={true}
|
|
85
|
-
showLastColumnBorder={true}
|
|
86
|
-
/>
|
|
87
|
-
{:else}
|
|
88
|
-
<div class="flex flex-1 h-full items-center justify-center">
|
|
89
|
-
No results
|
|
90
|
-
</div>
|
|
91
|
-
{/if}
|
|
92
|
-
</div>
|
|
93
|
-
</div>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import Dagre from '@dagrejs/dagre';
|
|
2
|
-
|
|
3
|
-
export function getLayoutedElements(nodes: any[], edges: any[]) {
|
|
4
|
-
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
|
|
5
|
-
g.setGraph({ rankdir: "LR" });
|
|
6
|
-
|
|
7
|
-
edges.forEach((edge) => g.setEdge(edge.source, edge.target));
|
|
8
|
-
nodes.forEach((node) => {
|
|
9
|
-
return g.setNode(node.id, {
|
|
10
|
-
...node,
|
|
11
|
-
width: node.measured?.width ?? 0,
|
|
12
|
-
height: node.measured?.height ?? 0,
|
|
13
|
-
});
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
Dagre.layout(g);
|
|
17
|
-
|
|
18
|
-
return {
|
|
19
|
-
nodes: nodes.map((node) => {
|
|
20
|
-
const position = g.node(node.id);
|
|
21
|
-
// We are shifting the dagre node position (anchor=center center) to the top left
|
|
22
|
-
// so it matches the Svelte Flow node anchor point (top left).
|
|
23
|
-
const x = position.x - (node.measured?.width ?? 0) / 2;
|
|
24
|
-
const y = position.y - (node.measured?.height ?? 0) / 2;
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
...node,
|
|
28
|
-
position: { x, y },
|
|
29
|
-
targetPosition: "left",
|
|
30
|
-
sourcePosition: "right",
|
|
31
|
-
};
|
|
32
|
-
}),
|
|
33
|
-
edges,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import ExtensionsComponents from "$lib/components/extensionsComponents.svelte";
|
|
3
|
-
import { getExtensionUtils } from "../../extensions/extensionUtils";
|
|
4
|
-
|
|
5
|
-
let { extension, page } = $props();
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<div class="grid overflow-auto bg-background">
|
|
9
|
-
{#key extension && page}
|
|
10
|
-
<ExtensionsComponents
|
|
11
|
-
name="pages.{page}"
|
|
12
|
-
utils={getExtensionUtils()}
|
|
13
|
-
filterByExtensions={[extension]}
|
|
14
|
-
/>
|
|
15
|
-
{/key}
|
|
16
|
-
</div>
|
package/src/routes/home.svelte
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<script>
|
|
2
|
-
import Button from "$lib/components/ui/button/button.svelte";
|
|
3
|
-
import { ctx } from "$lib/store.svelte";
|
|
4
|
-
import { location } from "@wjfe/n-savant";
|
|
5
|
-
import { ArrowRight } from "lucide-svelte";
|
|
6
|
-
</script>
|
|
7
|
-
|
|
8
|
-
<div class="flex flex-col">
|
|
9
|
-
<div
|
|
10
|
-
class="flex flex-1 w-full flex-col items-center justify-center gap-4 text-muted-foreground"
|
|
11
|
-
>
|
|
12
|
-
<div class="flex flex-col items-center justify-center p-4">
|
|
13
|
-
<div class="text-3xl">Welcome to Lobb!</div>
|
|
14
|
-
<div class="text-xs text-center">
|
|
15
|
-
Your journey starts here. Explore and make the most of your
|
|
16
|
-
experience.
|
|
17
|
-
</div>
|
|
18
|
-
</div>
|
|
19
|
-
<div class="flex flex-col items-center justify-center">
|
|
20
|
-
<Button
|
|
21
|
-
Icon={ArrowRight}
|
|
22
|
-
variant="outline"
|
|
23
|
-
class="h-7 px-3 text-xs font-normal"
|
|
24
|
-
onclick={() => location.navigate("/collections")}
|
|
25
|
-
>
|
|
26
|
-
Go to collections
|
|
27
|
-
</Button>
|
|
28
|
-
</div>
|
|
29
|
-
</div>
|
|
30
|
-
<div class="flex justify-end p-2 text-xs text-muted-foreground/50">
|
|
31
|
-
<div class="flex flex-col text-end">
|
|
32
|
-
<div>studio: v{ctx.studioVersion}</div>
|
|
33
|
-
<div>core: v{ctx.meta.version}</div>
|
|
34
|
-
</div>
|
|
35
|
-
</div>
|
|
36
|
-
</div>
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import type { SideBarData } from "$lib/components/sidebar/sidebarElements.svelte";
|
|
3
|
-
import WorkflowEditor, {
|
|
4
|
-
type WorkflowEntry,
|
|
5
|
-
} from "$lib/components/workflowEditor.svelte";
|
|
6
|
-
import { lobb } from "$lib";
|
|
7
|
-
import Sidebar from "$lib/components/sidebar/sidebar.svelte";
|
|
8
|
-
import Button from "$lib/components/ui/button/button.svelte";
|
|
9
|
-
import { ctx } from "$lib/store.svelte";
|
|
10
|
-
import { location } from "@wjfe/n-savant";
|
|
11
|
-
import { CircleSlash2, Plus, Trash2 } from "lucide-svelte";
|
|
12
|
-
import { onMount } from "svelte";
|
|
13
|
-
import { showDialog } from "$lib/components/confirmationDialog/store.svelte";
|
|
14
|
-
import SidebarTrigger from "$lib/components/sidebar/sidebarTrigger.svelte";
|
|
15
|
-
|
|
16
|
-
let { workflowName } = $props();
|
|
17
|
-
|
|
18
|
-
let sidebarData: SideBarData | null = $state(null);
|
|
19
|
-
let workflowEntry: WorkflowEntry | null = $state(null);
|
|
20
|
-
|
|
21
|
-
onMount(async () => {
|
|
22
|
-
getSidebarData();
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
$effect(() => {
|
|
26
|
-
fetchWorkflowData(workflowName);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
async function getSidebarData() {
|
|
30
|
-
const response = await lobb.findAll("core_workflows", {});
|
|
31
|
-
const result = await response.json();
|
|
32
|
-
const workflows: any[] = result.data;
|
|
33
|
-
sidebarData = workflows.map((workflow) => {
|
|
34
|
-
return {
|
|
35
|
-
name: workflow.name,
|
|
36
|
-
path: workflow.directory,
|
|
37
|
-
onclick: () => {
|
|
38
|
-
location.navigate(`/workflows/${workflow.name}`);
|
|
39
|
-
},
|
|
40
|
-
meta: {
|
|
41
|
-
id: workflow.id,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async function fetchWorkflowData(workflowName: string) {
|
|
48
|
-
if (workflowName && workflowName !== "new") {
|
|
49
|
-
const response = await lobb.findAll("core_workflows", {
|
|
50
|
-
filter: {
|
|
51
|
-
name: workflowName,
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
const result = await response.json();
|
|
55
|
-
const workflow = result.data[0];
|
|
56
|
-
workflowEntry = workflow;
|
|
57
|
-
} else {
|
|
58
|
-
const workflowHandlerDefaultValue =
|
|
59
|
-
ctx.meta.collections.core_workflows.fields.handler
|
|
60
|
-
.pre_processors.default;
|
|
61
|
-
workflowEntry = {
|
|
62
|
-
name: "",
|
|
63
|
-
event_name: "",
|
|
64
|
-
handler: workflowHandlerDefaultValue,
|
|
65
|
-
directory: "",
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
async function handleWorkflowDelete(
|
|
71
|
-
workflowName: string,
|
|
72
|
-
workflowId: string,
|
|
73
|
-
) {
|
|
74
|
-
const result = await showDialog(
|
|
75
|
-
"Are you sure?",
|
|
76
|
-
"This will delete the Workflow you selected.",
|
|
77
|
-
);
|
|
78
|
-
if (result) {
|
|
79
|
-
await lobb.deleteOne("core_workflows", workflowId);
|
|
80
|
-
getSidebarData();
|
|
81
|
-
if (workflowEntry && workflowName === workflowEntry.name) {
|
|
82
|
-
location.navigate("/workflows");
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
</script>
|
|
87
|
-
|
|
88
|
-
<Sidebar title="Workflows" data={sidebarData}>
|
|
89
|
-
{#snippet belowSearch()}
|
|
90
|
-
<div class="pb-4 px-2">
|
|
91
|
-
<Button
|
|
92
|
-
class="h-7 px-3 text-xs font-normal w-full"
|
|
93
|
-
variant="outline"
|
|
94
|
-
onclick={() => location.navigate("/workflows/new")}
|
|
95
|
-
Icon={Plus}
|
|
96
|
-
>
|
|
97
|
-
Create a Workflow
|
|
98
|
-
</Button>
|
|
99
|
-
</div>
|
|
100
|
-
{/snippet}
|
|
101
|
-
{#snippet elementRightSide(element)}
|
|
102
|
-
<Button
|
|
103
|
-
class="h-6 w-6 text-muted-foreground hover:bg-transparent"
|
|
104
|
-
variant="ghost"
|
|
105
|
-
size="icon"
|
|
106
|
-
onclick={() => handleWorkflowDelete(element.name, element.meta?.id)}
|
|
107
|
-
Icon={Trash2}
|
|
108
|
-
></Button>
|
|
109
|
-
{/snippet}
|
|
110
|
-
<div class="relative h-full w-full">
|
|
111
|
-
{#if workflowName === undefined}
|
|
112
|
-
<div
|
|
113
|
-
class="flex h-full w-full flex-col items-center justify-center gap-4 text-muted-foreground"
|
|
114
|
-
>
|
|
115
|
-
<CircleSlash2 class="opacity-50" size="50" />
|
|
116
|
-
<div class="flex flex-col items-center justify-center">
|
|
117
|
-
<div>No workflow selected</div>
|
|
118
|
-
<div class="text-xs">
|
|
119
|
-
Select a workflow to edit it or create new ones
|
|
120
|
-
</div>
|
|
121
|
-
</div>
|
|
122
|
-
</div>
|
|
123
|
-
{:else if workflowEntry}
|
|
124
|
-
{#key workflowEntry}
|
|
125
|
-
<WorkflowEditor
|
|
126
|
-
bind:workflow={workflowEntry}
|
|
127
|
-
refreshSidebar={getSidebarData}
|
|
128
|
-
/>
|
|
129
|
-
{/key}
|
|
130
|
-
{/if}
|
|
131
|
-
<div class="absolute top-0 left-0 p-2.5">
|
|
132
|
-
<SidebarTrigger />
|
|
133
|
-
</div>
|
|
134
|
-
</div>
|
|
135
|
-
</Sidebar>
|