@lobb-js/studio 0.1.34 → 0.1.36

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 (34) hide show
  1. package/package.json +2 -2
  2. package/src/lib/Lobb.d.ts +30 -0
  3. package/src/lib/Lobb.ts +241 -0
  4. package/src/lib/components/Studio.svelte +5 -5
  5. package/src/lib/components/routes/collections/collection.svelte +46 -0
  6. package/src/lib/components/routes/collections/collections.svelte +43 -0
  7. package/src/lib/components/routes/collections/collections.svelte.d.ts +5 -0
  8. package/src/lib/components/routes/data_model/dataModel.svelte +40 -0
  9. package/src/lib/components/routes/data_model/dataModel.svelte.d.ts +3 -0
  10. package/src/lib/components/routes/data_model/flow.css +22 -0
  11. package/src/lib/components/routes/data_model/flow.svelte +82 -0
  12. package/src/lib/components/routes/data_model/flow.svelte.d.ts +5 -0
  13. package/src/lib/components/routes/data_model/syncManager.svelte +93 -0
  14. package/src/lib/components/routes/data_model/syncManager.svelte.d.ts +3 -0
  15. package/src/lib/components/routes/data_model/utils.d.ts +4 -0
  16. package/src/lib/components/routes/data_model/utils.ts +35 -0
  17. package/src/lib/components/routes/extensions/extension.svelte +16 -0
  18. package/src/lib/components/routes/home.svelte +36 -0
  19. package/src/lib/components/routes/workflows/workflows.svelte +135 -0
  20. package/src/lib/components/routes/workflows/workflows.svelte.d.ts +5 -0
  21. package/src/lib/eventSystem.d.ts +1 -0
  22. package/src/lib/eventSystem.ts +38 -0
  23. package/src/lib/extensions/extension.types.d.ts +83 -0
  24. package/src/lib/extensions/extension.types.ts +93 -0
  25. package/src/lib/extensions/extensionUtils.d.ts +8 -0
  26. package/src/lib/extensions/extensionUtils.ts +192 -0
  27. package/src/lib/index.d.ts +9 -0
  28. package/src/lib/index.ts +36 -0
  29. package/src/lib/store.svelte.d.ts +4 -0
  30. package/src/lib/store.svelte.ts +33 -0
  31. package/src/lib/store.types.d.ts +26 -0
  32. package/src/lib/store.types.ts +28 -0
  33. package/src/lib/utils.d.ts +27 -0
  34. package/src/lib/utils.ts +84 -0
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@lobb-js/studio",
3
- "version": "0.1.34",
3
+ "version": "0.1.36",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
8
  "files": [
9
- "src/lib/components",
9
+ "src/lib",
10
10
  "vite-plugins"
11
11
  ],
12
12
  "exports": {
@@ -0,0 +1,30 @@
1
+ interface RouteParams {
2
+ method: string;
3
+ route: string;
4
+ payload?: any;
5
+ }
6
+ type OnResponseHandlers = (reponse: Response) => void;
7
+ export declare class Lobb {
8
+ lobbUrl: string;
9
+ private headers;
10
+ private onResponseHandlers;
11
+ constructor(lobbUrl: string);
12
+ onResponse(callback: OnResponseHandlers): Promise<void>;
13
+ setHeaders(headers: HeadersInit): void;
14
+ getHeaders(): HeadersInit;
15
+ getMeta(): Promise<any>;
16
+ findAll(collectionName: string, params: any): Promise<Response>;
17
+ findOne(collectionName: string, id: string, queryParams?: any): Promise<Response>;
18
+ createOne(collectionName: string, body: any, file?: File): Promise<Response>;
19
+ updateOne(collectionName: string, id: string, body: any): Promise<Response>;
20
+ readSingleton(collectionName: string): Promise<Response>;
21
+ updateSingleton(collectionName: string, body: Record<string, any>): Promise<Response>;
22
+ deleteOne(collectionName: string, id: string, force?: boolean): Promise<Response>;
23
+ deleteMany(collectionName: string, filter: any, force?: boolean): Promise<Response>;
24
+ createMany(collectionName: string, body: any): Promise<Response>;
25
+ updateMany(collectionName: string, body: any, filter: any): Promise<Response>;
26
+ transactions(body: any[], rollback?: boolean): Promise<Response>;
27
+ request(params: RouteParams): Promise<Response>;
28
+ private handleResponse;
29
+ }
30
+ export {};
@@ -0,0 +1,241 @@
1
+ import qs from "qs";
2
+ import { parseFunction } from "./utils";
3
+
4
+ interface RouteParams {
5
+ method: string;
6
+ route: string;
7
+ payload?: any;
8
+ }
9
+
10
+ type OnResponseHandlers = (reponse: Response) => void;
11
+
12
+ export class Lobb {
13
+ public lobbUrl: string;
14
+ private headers: HeadersInit = [];
15
+ private onResponseHandlers: Array<OnResponseHandlers> = [];
16
+
17
+ constructor(lobbUrl: string) {
18
+ this.lobbUrl = lobbUrl;
19
+ }
20
+
21
+ public async onResponse(callback: OnResponseHandlers) {
22
+ this.onResponseHandlers.push(callback);
23
+ }
24
+
25
+ public setHeaders(headers: HeadersInit) {
26
+ this.headers = headers;
27
+ }
28
+
29
+ public getHeaders() {
30
+ return this.headers;
31
+ }
32
+
33
+ public async getMeta() {
34
+ const response = await fetch(`${this.lobbUrl}/api/meta`, {
35
+ headers: this.headers,
36
+ });
37
+
38
+ const metaResponse = await this.handleResponse(response);
39
+ const meta = await metaResponse.json();
40
+
41
+ meta.studio_workflows = meta.studio_workflows.map((workflow: any) => {
42
+ return {
43
+ ...workflow,
44
+ handler: parseFunction(workflow.handler),
45
+ };
46
+ });
47
+
48
+ return meta;
49
+ }
50
+
51
+ // CRUD methods
52
+ public async findAll(collectionName: string, params: any) {
53
+ const response = await fetch(
54
+ `${this.lobbUrl}/api/collections/${collectionName}/search`,
55
+ {
56
+ method: "POST",
57
+ headers: this.headers,
58
+ body: JSON.stringify(params),
59
+ },
60
+ );
61
+ return await this.handleResponse(response);
62
+ }
63
+
64
+ public async findOne(
65
+ collectionName: string,
66
+ id: string,
67
+ queryParams?: any,
68
+ ) {
69
+ queryParams = queryParams ? `?${qs.stringify(queryParams)}` : "";
70
+ const response = await fetch(
71
+ `${this.lobbUrl}/api/collections/${collectionName}/${id}${queryParams}`,
72
+ {
73
+ method: "GET",
74
+ headers: this.headers,
75
+ },
76
+ );
77
+ return await this.handleResponse(response);
78
+ }
79
+
80
+ public async createOne(collectionName: string, body: any, file?: File) {
81
+ if (file) {
82
+ const formData = new FormData();
83
+ Object.keys(body).forEach((key) => {
84
+ formData.append(key, body[key]);
85
+ });
86
+ formData.append("file", file, file.name);
87
+ formData.append(
88
+ "payload",
89
+ JSON.stringify({
90
+ data: body,
91
+ }),
92
+ );
93
+ body = formData;
94
+ } else {
95
+ body = JSON.stringify({
96
+ data: body,
97
+ });
98
+ }
99
+ const response = await fetch(
100
+ `${this.lobbUrl}/api/collections/${collectionName}`,
101
+ {
102
+ method: "POST",
103
+ headers: this.headers,
104
+ body,
105
+ },
106
+ );
107
+ return await this.handleResponse(response);
108
+ }
109
+
110
+ public async updateOne(collectionName: string, id: string, body: any) {
111
+ const response = await fetch(
112
+ `${this.lobbUrl}/api/collections/${collectionName}/${id}`,
113
+ {
114
+ method: "PATCH",
115
+ headers: this.headers,
116
+ body: JSON.stringify({
117
+ data: body,
118
+ }),
119
+ },
120
+ );
121
+ return await this.handleResponse(response);
122
+ }
123
+
124
+ public async readSingleton(
125
+ collectionName: string,
126
+ ) {
127
+ const response = await fetch(
128
+ `${this.lobbUrl}/api/collections/${collectionName}/singleton`,
129
+ {
130
+ method: "GET",
131
+ headers: this.headers,
132
+ },
133
+ );
134
+ return await this.handleResponse(response);
135
+ }
136
+
137
+ public async updateSingleton(
138
+ collectionName: string,
139
+ body: Record<string, any>
140
+ ) {
141
+ const response = await fetch(
142
+ `${this.lobbUrl}/api/collections/${collectionName}/singleton`,
143
+ {
144
+ method: "PATCH",
145
+ headers: this.headers,
146
+ body: JSON.stringify({
147
+ data: body,
148
+ }),
149
+ },
150
+ );
151
+ return await this.handleResponse(response);
152
+ }
153
+
154
+ public async deleteOne(collectionName: string, id: string, force = false) {
155
+ const response = await fetch(
156
+ `${this.lobbUrl}/api/collections/${collectionName}/${id}${force ? "?force" : ""}`,
157
+ {
158
+ method: "DELETE",
159
+ headers: this.headers,
160
+ },
161
+ );
162
+ return await this.handleResponse(response);
163
+ }
164
+
165
+ public async deleteMany(collectionName: string, filter: any, force = false) {
166
+ const response = await fetch(
167
+ `${this.lobbUrl}/api/collections/${collectionName}${force ? "?force" : ""}`,
168
+ {
169
+ method: "DELETE",
170
+ headers: this.headers,
171
+ body: JSON.stringify({
172
+ filter,
173
+ }),
174
+ },
175
+ );
176
+ return await this.handleResponse(response);
177
+ }
178
+
179
+ public async createMany(collectionName: string, body: any) {
180
+ body = JSON.stringify({
181
+ data: body,
182
+ });
183
+ const response = await fetch(
184
+ `${this.lobbUrl}/api/collections/${collectionName}`,
185
+ {
186
+ method: "POST",
187
+ headers: this.headers,
188
+ body,
189
+ },
190
+ );
191
+ return await this.handleResponse(response);
192
+ }
193
+
194
+ public async updateMany(collectionName: string, body: any, filter: any) {
195
+ const response = await fetch(
196
+ `${this.lobbUrl}/api/collections/${collectionName}`,
197
+ {
198
+ method: "PATCH",
199
+ headers: this.headers,
200
+ body: JSON.stringify({
201
+ filter,
202
+ data: body,
203
+ }),
204
+ },
205
+ );
206
+ return await this.handleResponse(response);
207
+ }
208
+
209
+ public async transactions(body: any[], rollback?: boolean) {
210
+ const response = await fetch(
211
+ `${this.lobbUrl}/api/collections/transactions${
212
+ rollback ? "?rollback" : ""
213
+ }`,
214
+ {
215
+ method: "POST",
216
+ headers: this.headers,
217
+ body: JSON.stringify(body),
218
+ },
219
+ );
220
+ return await this.handleResponse(response);
221
+ }
222
+
223
+ // CUSTOM REQUEST methods
224
+ public async request(params: RouteParams) {
225
+ const response = await fetch(`${this.lobbUrl}${params.route}`, {
226
+ method: params.method,
227
+ headers: this.headers,
228
+ body: JSON.stringify(params.payload),
229
+ });
230
+ return await this.handleResponse(response);
231
+ }
232
+
233
+ // HELPER methods
234
+ private async handleResponse(response: Response): Promise<Response> {
235
+ for (let index = 0; index < this.onResponseHandlers.length; index++) {
236
+ const handler = this.onResponseHandlers[index];
237
+ handler(response.clone());
238
+ }
239
+ return response;
240
+ }
241
+ }
@@ -16,11 +16,11 @@
16
16
  loadExtensions,
17
17
  } from "$lib/extensions/extensionUtils";
18
18
  import { mediaQueries } from "$lib/utils";
19
- import Home from "../../routes/home.svelte";
20
- import DataModel from "../../routes/data_model/dataModel.svelte";
21
- import Collections from "../../routes/collections/collections.svelte";
22
- import Workflows from "../../routes/workflows/workflows.svelte";
23
- import Extension from "../../routes/extensions/extension.svelte";
19
+ import Home from "./routes/home.svelte";
20
+ import DataModel from "./routes/data_model/dataModel.svelte";
21
+ import Collections from "./routes/collections/collections.svelte";
22
+ import Workflows from "./routes/workflows/workflows.svelte";
23
+ import Extension from "./routes/extensions/extension.svelte";
24
24
 
25
25
  interface StudioProps {
26
26
  extensions?: any[];
@@ -0,0 +1,46 @@
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>
@@ -0,0 +1,43 @@
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>
@@ -0,0 +1,5 @@
1
+ declare const Collections: import("svelte").Component<{
2
+ collectionName: any;
3
+ }, {}, "">;
4
+ type Collections = ReturnType<typeof Collections>;
5
+ export default Collections;
@@ -0,0 +1,40 @@
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>
@@ -0,0 +1,3 @@
1
+ declare const DataModel: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DataModel = ReturnType<typeof DataModel>;
3
+ export default DataModel;
@@ -0,0 +1,22 @@
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
+ }
@@ -0,0 +1,82 @@
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>
@@ -0,0 +1,5 @@
1
+ import "@xyflow/svelte/dist/style.css";
2
+ import "./flow.css";
3
+ declare const Flow: import("svelte").Component<Record<string, never>, {}, "">;
4
+ type Flow = ReturnType<typeof Flow>;
5
+ export default Flow;
@@ -0,0 +1,93 @@
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>
@@ -0,0 +1,3 @@
1
+ declare const SyncManager: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type SyncManager = ReturnType<typeof SyncManager>;
3
+ export default SyncManager;
@@ -0,0 +1,4 @@
1
+ export declare function getLayoutedElements(nodes: any[], edges: any[]): {
2
+ nodes: any[];
3
+ edges: any[];
4
+ };