@lobb-js/studio 0.29.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. package/README.md +1 -0
  2. package/dist/actions.d.ts +11 -0
  3. package/dist/actions.js +16 -0
  4. package/dist/components/Studio.svelte +39 -43
  5. package/dist/components/StudioRoot.svelte +19 -0
  6. package/dist/components/StudioRoot.svelte.d.ts +6 -0
  7. package/dist/components/breadCrumbs.svelte +5 -4
  8. package/dist/components/codeEditor.svelte +1 -1
  9. package/dist/components/dataTable/dataTable.svelte +35 -20
  10. package/dist/components/dataTable/dataTable.svelte.d.ts +2 -1
  11. package/dist/components/dataTable/dataTableTabs.svelte +4 -2
  12. package/dist/components/dataTable/dataTableTabs.svelte.d.ts +2 -0
  13. package/dist/components/dataTable/header.svelte +15 -11
  14. package/dist/components/dataTable/header.svelte.d.ts +1 -0
  15. package/dist/components/dataTable/listViewChildren.svelte +4 -6
  16. package/dist/components/dataTable/listViewChildren.svelte.d.ts +0 -1
  17. package/dist/components/dataTable/table.svelte +8 -10
  18. package/dist/components/dataTable/table.svelte.d.ts +0 -1
  19. package/dist/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
  20. package/dist/components/dataTableDrawer/dataTableDrawer.svelte.d.ts +2 -0
  21. package/dist/components/dataTablePopup/dataTablePopup.svelte +67 -0
  22. package/dist/components/dataTablePopup/dataTablePopup.svelte.d.ts +15 -0
  23. package/dist/components/detailView/create/children.svelte +1 -1
  24. package/dist/components/detailView/create/createDetailView.svelte +19 -61
  25. package/dist/components/detailView/create/createManyView.svelte +2 -4
  26. package/dist/components/detailView/detailView.svelte +81 -0
  27. package/dist/components/detailView/detailView.svelte.d.ts +8 -0
  28. package/dist/components/detailView/fieldInput.svelte +10 -10
  29. package/dist/components/detailView/fieldInputReplacement.svelte +7 -7
  30. package/dist/components/detailView/passwordInput.svelte +1 -1
  31. package/dist/components/detailView/update/updateDetailView.svelte +32 -69
  32. package/dist/components/diffViewer.svelte +1 -1
  33. package/dist/components/extensionsComponents.svelte +3 -1
  34. package/dist/components/foreingKeyInput.svelte +2 -2
  35. package/dist/components/importButton.svelte +12 -9
  36. package/dist/components/landing.svelte +7 -0
  37. package/dist/components/landing.svelte.d.ts +6 -14
  38. package/dist/components/miniSidebar.svelte +86 -15
  39. package/dist/components/miniSidebar.svelte.d.ts +2 -17
  40. package/dist/components/polymorphicInput.svelte +1 -1
  41. package/dist/components/rangeCalendarButton.svelte +10 -10
  42. package/dist/components/richTextEditor.svelte +1 -1
  43. package/dist/components/routes/collections/collections.svelte +32 -10
  44. package/dist/components/routes/data_model/dataModel.svelte +6 -28
  45. package/dist/components/routes/data_model/dataModel.svelte.d.ts +17 -2
  46. package/dist/components/routes/extensions/publicExtension.svelte +19 -0
  47. package/dist/components/routes/extensions/publicExtension.svelte.d.ts +13 -0
  48. package/dist/components/routes/home.svelte +2 -2
  49. package/dist/components/routes/workflows/workflows.svelte +4 -4
  50. package/dist/components/sidebar/sidebar.svelte +1 -1
  51. package/dist/components/sidebar/sidebarElements.svelte +4 -4
  52. package/dist/components/singletone.svelte +4 -6
  53. package/dist/components/ui/button/button.svelte +2 -3
  54. package/dist/components/workflowEditor.svelte +2 -2
  55. package/dist/eventSystem.d.ts +1 -1
  56. package/dist/eventSystem.js +7 -5
  57. package/dist/extensions/extension.types.d.ts +39 -14
  58. package/dist/extensions/extensionUtils.js +6 -3
  59. package/dist/index.d.ts +3 -1
  60. package/dist/index.js +3 -1
  61. package/dist/store.types.d.ts +1 -1
  62. package/dist/studioLifecycle.svelte.d.ts +2 -0
  63. package/dist/studioLifecycle.svelte.js +15 -0
  64. package/package.json +3 -4
  65. package/src/app.css +3 -0
  66. package/src/lib/actions.ts +28 -0
  67. package/src/lib/components/Studio.svelte +39 -43
  68. package/src/lib/components/StudioRoot.svelte +19 -0
  69. package/src/lib/components/breadCrumbs.svelte +5 -4
  70. package/src/lib/components/codeEditor.svelte +1 -1
  71. package/src/lib/components/dataTable/dataTable.svelte +35 -20
  72. package/src/lib/components/dataTable/dataTableTabs.svelte +4 -2
  73. package/src/lib/components/dataTable/header.svelte +15 -11
  74. package/src/lib/components/dataTable/listViewChildren.svelte +4 -6
  75. package/src/lib/components/dataTable/table.svelte +8 -10
  76. package/src/lib/components/dataTableDrawer/dataTableDrawer.svelte +4 -1
  77. package/src/lib/components/dataTablePopup/dataTablePopup.svelte +67 -0
  78. package/src/lib/components/detailView/create/children.svelte +1 -1
  79. package/src/lib/components/detailView/create/createDetailView.svelte +19 -61
  80. package/src/lib/components/detailView/create/createManyView.svelte +2 -4
  81. package/src/lib/components/detailView/detailView.svelte +81 -0
  82. package/src/lib/components/detailView/fieldInput.svelte +10 -10
  83. package/src/lib/components/detailView/fieldInputReplacement.svelte +7 -7
  84. package/src/lib/components/detailView/passwordInput.svelte +1 -1
  85. package/src/lib/components/detailView/update/updateDetailView.svelte +32 -69
  86. package/src/lib/components/diffViewer.svelte +1 -1
  87. package/src/lib/components/extensionsComponents.svelte +3 -1
  88. package/src/lib/components/foreingKeyInput.svelte +2 -2
  89. package/src/lib/components/importButton.svelte +12 -9
  90. package/src/lib/components/landing.svelte +7 -0
  91. package/src/lib/components/miniSidebar.svelte +86 -15
  92. package/src/lib/components/polymorphicInput.svelte +1 -1
  93. package/src/lib/components/rangeCalendarButton.svelte +10 -10
  94. package/src/lib/components/richTextEditor.svelte +1 -1
  95. package/src/lib/components/routes/collections/collections.svelte +32 -10
  96. package/src/lib/components/routes/data_model/dataModel.svelte +6 -28
  97. package/src/lib/components/routes/extensions/publicExtension.svelte +19 -0
  98. package/src/lib/components/routes/home.svelte +2 -2
  99. package/src/lib/components/routes/workflows/workflows.svelte +4 -4
  100. package/src/lib/components/sidebar/sidebar.svelte +1 -1
  101. package/src/lib/components/sidebar/sidebarElements.svelte +4 -4
  102. package/src/lib/components/singletone.svelte +4 -6
  103. package/src/lib/components/ui/button/button.svelte +2 -3
  104. package/src/lib/components/workflowEditor.svelte +2 -2
  105. package/src/lib/eventSystem.ts +8 -7
  106. package/src/lib/extensions/extension.types.ts +40 -6
  107. package/src/lib/extensions/extensionUtils.ts +6 -3
  108. package/src/lib/index.ts +3 -1
  109. package/src/lib/store.types.ts +1 -1
  110. package/src/lib/studioLifecycle.svelte.ts +17 -0
  111. package/dist/components/routes/data_model/syncManager.svelte +0 -94
  112. package/dist/components/routes/data_model/syncManager.svelte.d.ts +0 -3
  113. package/src/lib/components/routes/data_model/syncManager.svelte +0 -94
@@ -49,7 +49,6 @@
49
49
  <script lang="ts">
50
50
  import { cn } from "../../../utils.js";
51
51
  import { LoaderCircle } from "lucide-svelte";
52
- import { Link, location } from "@wjfe/n-savant";
53
52
 
54
53
  let {
55
54
  class: className,
@@ -94,9 +93,9 @@
94
93
  {/snippet}
95
94
 
96
95
  {#if href}
97
- <Link {href} class={cn(buttonVariants({ variant, size }), className)}>
96
+ <a {href} class={cn(buttonVariants({ variant, size }), className)}>
98
97
  {@render innerPart()}
99
- </Link>
98
+ </a>
100
99
  {:else}
101
100
  <button
102
101
  bind:this={ref}
@@ -17,7 +17,7 @@
17
17
  const { lobb, ctx } = getStudioContext();
18
18
  import Button from "./ui/button/button.svelte";
19
19
  import Input from "./ui/input/input.svelte";
20
- import { location } from "@wjfe/n-savant";
20
+ import { goto } from "$app/navigation";
21
21
  import { Edit, Plus } from "lucide-svelte";
22
22
  import { toast } from "svelte-sonner";
23
23
  import { isEqual } from "lodash-es";
@@ -96,7 +96,7 @@
96
96
  const reponse = await lobb.createOne("core_workflows", workflow);
97
97
  const result = await reponse.json();
98
98
  const workflowEntry = result.data;
99
- location.navigate(`/studio/workflows/${workflowEntry.name}`);
99
+ goto(`/studio/workflows/${workflowEntry.name}`);
100
100
  await refreshSidebar();
101
101
  }
102
102
 
@@ -3,25 +3,26 @@ import type { StudioContext } from "./context";
3
3
  import { openCreateDetailView, openUpdateDetailView } from "./actions";
4
4
  import type { UpdateDetailViewProp } from "./components/detailView/update/updateDetailView.svelte";
5
5
 
6
- export async function emitEvent(studioContext: StudioContext, eventName: string, input: Record<string, any>) {
6
+ export async function emitEvent(studioContext: StudioContext, eventName: string, input: any): Promise<any> {
7
7
  const { ctx } = studioContext;
8
8
  const workflows = ctx.meta.studio_workflows.filter(
9
9
  (workflow) => {
10
- return eventName.startsWith(workflow.eventName);
10
+ return eventName === workflow.eventName;
11
11
  },
12
12
  );
13
13
 
14
14
  for (let index = 0; index < workflows.length; index++) {
15
15
  const workflow = workflows[index];
16
16
  try {
17
- const localOutput = await workflow.handler(
17
+ // Whatever the handler returns becomes the input for the next
18
+ // subscriber and the final emit() return. No special handling of
19
+ // undefined — chain handlers should return their input, override
20
+ // handlers return undefined to opt out, observer handlers can
21
+ // return nothing if no one downstream reads input.
22
+ input = await workflow.handler(
18
23
  input,
19
24
  await getEventContext(studioContext),
20
25
  );
21
-
22
- if (localOutput) {
23
- input = localOutput;
24
- }
25
26
  } catch (error) {
26
27
  toast.error((error as any).message);
27
28
  throw error;
@@ -11,7 +11,8 @@ import type CreateDetailViewButton from "../components/detailView/create/createD
11
11
  import type UpdateDetailViewButton from "../components/detailView/update/updateDetailViewButton.svelte";
12
12
  import type { mediaQueries } from "../utils";
13
13
  import type Table from "../components/dataTable/table.svelte";
14
- import type { Location } from "@wjfe/n-savant";
14
+ import type { page } from "$app/state";
15
+ import type { goto } from "$app/navigation";
15
16
  import type RangeCalendarButton from "../components/rangeCalendarButton.svelte";
16
17
  import type DataTable from "../components/dataTable/dataTable.svelte";
17
18
  import type Drawer from "../components/drawer.svelte";
@@ -22,7 +23,7 @@ import * as Icons from "lucide-svelte"
22
23
  import { ContextMenu } from "bits-ui";
23
24
  import * as Tooltip from "../components/ui/tooltip";
24
25
  import * as Breadcrumb from "../components/ui/breadcrumb";
25
- import { showDialog } from "../actions";
26
+ import { showDialog, type OpenDataTableDrawerProps, type OpenDataTablePopupProps } from "../actions";
26
27
  import { toast } from "svelte-sonner";
27
28
  import type Drawer from "../components/drawer.svelte";
28
29
  import { Switch } from "../components/ui/switch";
@@ -54,11 +55,24 @@ export interface Components {
54
55
  export interface ExtensionUtils {
55
56
  ctx: CTX;
56
57
  lobb: LobbClient;
57
- location: Location;
58
+ /**
59
+ * SvelteKit's reactive page proxy — exposes `url`, `params`, `route`,
60
+ * `data`, `state`, `error`. Access fields through the proxy
61
+ * (`utils.page.url.pathname`); don't destructure if you need
62
+ * reactivity (`const { url } = utils.page` is a one-time snapshot).
63
+ */
64
+ page: typeof page;
65
+ /**
66
+ * SvelteKit's client-side navigation. Same signature as
67
+ * `goto(href, options?)` — supports `replaceState`, `invalidateAll`,
68
+ * `noScroll`, `keepFocus`, etc.
69
+ */
70
+ goto: typeof goto;
58
71
  toast: typeof toast;
59
72
  showDialog: typeof showDialog;
60
- openDataTableDrawer: (props: { collectionName: string; filter?: Record<string, any>; title?: string; showHeader?: boolean; showFooter?: boolean; position?: "side" | "bottom" }) => void;
61
- emitEvent: (eventName: string, input: Record<string, any>) => Promise<Record<string, any>>;
73
+ openDataTableDrawer: (props: OpenDataTableDrawerProps) => void;
74
+ openDataTablePopup: (props: OpenDataTablePopupProps) => void;
75
+ emitEvent: (eventName: string, input: any) => Promise<any>;
62
76
  components: Components;
63
77
  mediaQueries: typeof mediaQueries;
64
78
  intlDate: typeof intlDate;
@@ -71,6 +85,24 @@ interface DashboardNav {
71
85
  href?: string;
72
86
  onclick?: () => void;
73
87
  navs?: DashboardNav[];
88
+ /**
89
+ * The collection(s) this nav item represents — i.e. the UI surface it
90
+ * exposes for that data.
91
+ *
92
+ * Visibility is derived from this: the auth extension's `auth.canAccess`
93
+ * workflow checks the current user's read permission on the represented
94
+ * collection(s), and the item is hidden if denied. Items without a
95
+ * `represents` value are always visible.
96
+ *
97
+ * @example
98
+ * // single collection
99
+ * { label: "Reports", href: "/reports", icon: BarChart, represents: "reports_dashboards" }
100
+ *
101
+ * @example
102
+ * // multiple collections — user must be able to read all of them
103
+ * { label: "Audit", href: "/audit", icon: ShieldCheck, represents: ["audit_log", "auth_users"] }
104
+ */
105
+ represents?: string | string[];
74
106
  }
75
107
 
76
108
  export interface DashboardNavs {
@@ -88,11 +120,13 @@ export interface ExtensionProps {
88
120
  // TODO: instead of doing them this way. you can make the components generic and have static keys and we can pass some dynamic data so that we for example extend the list view
89
121
  export type ExtensionComponentKey =
90
122
  | `pages.${string}`
123
+ | `publicPages.${string}`
91
124
  | "studio.listView"
92
125
  | `dvFields.topRight.${string}.${string}`
93
126
  | `detailView.update.subRecords.${string}`
94
127
  | `detailView.create.subRecords.${string}`
95
128
  | `detailView.fields.topRight.${string}.${string}`
129
+ | "detailView.field.label"
96
130
  | `detailView.fields.foreignKey.${string}`
97
131
  | `listView.entry.children.${string}`
98
132
  | `listView.entry.actions`
@@ -112,7 +146,7 @@ export interface StudioWorkflowContext {
112
146
 
113
147
  export interface StudioWorkflow {
114
148
  eventName: string;
115
- handler: (input: Record<string, any>, context: StudioWorkflowContext) => Promise<any>;
149
+ handler: (input: any, context: StudioWorkflowContext) => Promise<any>;
116
150
  }
117
151
 
118
152
  // extension exported object
@@ -7,7 +7,7 @@ import type {
7
7
  import type { LobbClient } from "@lobb-js/sdk";
8
8
  import type { CTX } from "../store.types";
9
9
  import { toast } from "svelte-sonner";
10
- import { showDialog, openDataTableDrawer } from "../actions";
10
+ import { showDialog, openDataTableDrawer, openDataTablePopup } from "../actions";
11
11
  import { emitEvent } from "../eventSystem";
12
12
  import { Button } from "../components/ui/button";
13
13
  import { Input } from "../components/ui/input";
@@ -26,7 +26,8 @@ import * as Breadcrumb from "../components/ui/breadcrumb";
26
26
  import { ContextMenu } from "bits-ui";
27
27
  import * as Popover from "../components/ui/popover";
28
28
  import * as Icons from "lucide-svelte";
29
- import { location } from "@wjfe/n-savant";
29
+ import { page } from "$app/state";
30
+ import { goto } from "$app/navigation";
30
31
  import RangeCalendarButton from "../components/rangeCalendarButton.svelte";
31
32
  import DataTable from "../components/dataTable/dataTable.svelte";
32
33
  import Drawer from "../components/drawer.svelte";
@@ -62,10 +63,12 @@ export function getExtensionUtils(lobb: LobbClient, ctx: CTX): ExtensionUtils {
62
63
  return {
63
64
  ctx: ctx,
64
65
  lobb: lobb,
65
- location: location,
66
+ page: page,
67
+ goto: goto,
66
68
  toast: toast,
67
69
  showDialog: showDialog,
68
70
  openDataTableDrawer: (props) => openDataTableDrawer({ lobb, ctx }, props),
71
+ openDataTablePopup: (props) => openDataTablePopup({ lobb, ctx }, props),
69
72
  emitEvent: (eventName, input) => emitEvent({ lobb, ctx }, eventName, input),
70
73
  components: getComponents(),
71
74
  mediaQueries: mediaQueries,
package/src/lib/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export type { ExtensionProps, Extension, ExtensionUtils } from "./extensions/extension.types"
2
2
 
3
- export { default as Studio } from "./components/Studio.svelte";
3
+ export { default as StudioRoot } from "./components/StudioRoot.svelte";
4
4
  export { default as Landing } from "./components/landing.svelte";
5
+ export { remountStudio } from "./studioLifecycle.svelte";
5
6
  export { Button } from "./components/ui/button";
6
7
  export { Input } from "./components/ui/input";
7
8
  export { Separator } from "./components/ui/separator";
@@ -11,6 +12,7 @@ export { default as Sidebar } from "./components/sidebar/sidebar.svelte";
11
12
  export { default as SidebarTrigger } from "./components/sidebar/sidebarTrigger.svelte";
12
13
  export { default as CreateDetailViewButton } from "./components/detailView/create/createDetailViewButton.svelte";
13
14
  export { default as UpdateDetailViewButton } from "./components/detailView/update/updateDetailViewButton.svelte";
15
+ export { default as DetailView } from "./components/detailView/detailView.svelte";
14
16
  export * as Tooltip from "./components/ui/tooltip";
15
17
  export * as Breadcrumb from "./components/ui/breadcrumb";
16
18
  export { ContextMenu } from "bits-ui";
@@ -1,6 +1,6 @@
1
1
  import type { Extension } from "./extensions/extension.types";
2
2
 
3
- interface CollectionTab {
3
+ export interface CollectionTab {
4
4
  id?: string;
5
5
  label: string;
6
6
  filter?: Record<string, any>;
@@ -0,0 +1,17 @@
1
+ // Module-level reactive signal that the Studio root listens to via {#key ...}.
2
+ // Bumping this value tears down the entire Studio component tree and mounts
3
+ // a fresh one, so onStartup re-runs and everything downstream (ctx,
4
+ // extensions, sidebar) initialises with the new session state.
5
+ //
6
+ // Use cases: after login, after logout, after a role/permissions change.
7
+ // Consumers (e.g. the auth extension) call `remountStudio()` instead of
8
+ // having every UI surface listen for auth changes reactively.
9
+ let mountKey = $state(0);
10
+
11
+ export function getStudioMountKey(): number {
12
+ return mountKey;
13
+ }
14
+
15
+ export function remountStudio(): void {
16
+ mountKey += 1;
17
+ }
@@ -1,94 +0,0 @@
1
- <script lang="ts">
2
- import DiffViewer from "../../diffViewer.svelte";
3
- import { getStudioContext } from "../../../context";
4
-
5
- const { lobb, ctx } = getStudioContext();
6
- import { onMount } from "svelte";
7
- import stringify from "json-stable-stringify";
8
- import CodeEditor from "../../codeEditor.svelte";
9
- import Table from "../../dataTable/table.svelte";
10
- import Button from "../../ui/button/button.svelte";
11
- import { LoaderCircle, SendHorizontal } from "lucide-svelte";
12
-
13
- let configSchema: string = $state("");
14
- let dbSchema: string = $state("");
15
- let sqlPrompt = $state("");
16
- let sqlResult = $state([]);
17
-
18
- onMount(() => {
19
- loadSchemas();
20
- });
21
-
22
- async function loadSchemas() {
23
- configSchema = "";
24
- dbSchema = "";
25
- const response = await fetch(`${ctx.lobbUrl}/api/schema/diff`);
26
- const result = await response.json();
27
- configSchema = stringify(result.dbSchema, {
28
- space: 2,
29
- }) as string;
30
- dbSchema = stringify(result.configSchema, {
31
- space: 2,
32
- }) as string;
33
- }
34
-
35
- async function handleExecute() {
36
- const response = await lobb.createOne("core_query", {
37
- query: sqlPrompt,
38
- });
39
- const result = await response.json();
40
- sqlResult = result.data;
41
- loadSchemas();
42
- }
43
- </script>
44
-
45
- <div class="h-[50%] border-b overflow-auto">
46
- {#if configSchema && dbSchema}
47
- <DiffViewer
48
- type="json"
49
- original={configSchema}
50
- modified={dbSchema}
51
- class="h-full rounded-none border-0"
52
- />
53
- {:else}
54
- <div class="flex justify-center items-center h-full gap-2">
55
- <LoaderCircle class="animate-spin" />
56
- <div>loading...</div>
57
- </div>
58
- {/if}
59
- </div>
60
- <div class="flex h-[50%] w-full">
61
- <div class="h-full flex-1 flex flex-col border-r">
62
- <div
63
- class="h-10 flex items-center px-2 bg-background border-b justify-between"
64
- >
65
- <div>Query Editor</div>
66
- <Button
67
- class="h-7 px-3 text-xs font-normal"
68
- Icon={SendHorizontal}
69
- onclick={handleExecute}
70
- >
71
- Execute
72
- </Button>
73
- </div>
74
- <CodeEditor
75
- type="sql"
76
- name="prompt"
77
- bind:value={sqlPrompt}
78
- class="flex-1 rounded-none border-0"
79
- />
80
- </div>
81
- <div class="flex-1">
82
- {#if Array.isArray(sqlResult) && sqlResult.length}
83
- <Table
84
- data={sqlResult}
85
- showLastRowBorder={true}
86
- showLastColumnBorder={true}
87
- />
88
- {:else}
89
- <div class="flex flex-1 h-full items-center justify-center">
90
- No results
91
- </div>
92
- {/if}
93
- </div>
94
- </div>
@@ -1,3 +0,0 @@
1
- declare const SyncManager: import("svelte").Component<Record<string, never>, {}, "">;
2
- type SyncManager = ReturnType<typeof SyncManager>;
3
- export default SyncManager;
@@ -1,94 +0,0 @@
1
- <script lang="ts">
2
- import DiffViewer from "../../diffViewer.svelte";
3
- import { getStudioContext } from "../../../context";
4
-
5
- const { lobb, ctx } = getStudioContext();
6
- import { onMount } from "svelte";
7
- import stringify from "json-stable-stringify";
8
- import CodeEditor from "../../codeEditor.svelte";
9
- import Table from "../../dataTable/table.svelte";
10
- import Button from "../../ui/button/button.svelte";
11
- import { LoaderCircle, SendHorizontal } from "lucide-svelte";
12
-
13
- let configSchema: string = $state("");
14
- let dbSchema: string = $state("");
15
- let sqlPrompt = $state("");
16
- let sqlResult = $state([]);
17
-
18
- onMount(() => {
19
- loadSchemas();
20
- });
21
-
22
- async function loadSchemas() {
23
- configSchema = "";
24
- dbSchema = "";
25
- const response = await fetch(`${ctx.lobbUrl}/api/schema/diff`);
26
- const result = await response.json();
27
- configSchema = stringify(result.dbSchema, {
28
- space: 2,
29
- }) as string;
30
- dbSchema = stringify(result.configSchema, {
31
- space: 2,
32
- }) as string;
33
- }
34
-
35
- async function handleExecute() {
36
- const response = await lobb.createOne("core_query", {
37
- query: sqlPrompt,
38
- });
39
- const result = await response.json();
40
- sqlResult = result.data;
41
- loadSchemas();
42
- }
43
- </script>
44
-
45
- <div class="h-[50%] border-b overflow-auto">
46
- {#if configSchema && dbSchema}
47
- <DiffViewer
48
- type="json"
49
- original={configSchema}
50
- modified={dbSchema}
51
- class="h-full rounded-none border-0"
52
- />
53
- {:else}
54
- <div class="flex justify-center items-center h-full gap-2">
55
- <LoaderCircle class="animate-spin" />
56
- <div>loading...</div>
57
- </div>
58
- {/if}
59
- </div>
60
- <div class="flex h-[50%] w-full">
61
- <div class="h-full flex-1 flex flex-col border-r">
62
- <div
63
- class="h-10 flex items-center px-2 bg-background border-b justify-between"
64
- >
65
- <div>Query Editor</div>
66
- <Button
67
- class="h-7 px-3 text-xs font-normal"
68
- Icon={SendHorizontal}
69
- onclick={handleExecute}
70
- >
71
- Execute
72
- </Button>
73
- </div>
74
- <CodeEditor
75
- type="sql"
76
- name="prompt"
77
- bind:value={sqlPrompt}
78
- class="flex-1 rounded-none border-0"
79
- />
80
- </div>
81
- <div class="flex-1">
82
- {#if Array.isArray(sqlResult) && sqlResult.length}
83
- <Table
84
- data={sqlResult}
85
- showLastRowBorder={true}
86
- showLastColumnBorder={true}
87
- />
88
- {:else}
89
- <div class="flex flex-1 h-full items-center justify-center">
90
- No results
91
- </div>
92
- {/if}
93
- </div>
94
- </div>