diff --git a/src/components/gui/schema-sidebar-list.tsx b/src/components/gui/schema-sidebar-list.tsx index f9352a22..48dc211f 100644 --- a/src/components/gui/schema-sidebar-list.tsx +++ b/src/components/gui/schema-sidebar-list.tsx @@ -9,6 +9,7 @@ import SchemaCreateDialog from "./schema-editor/schema-create"; import { scc } from "@/core/command"; import { useConfig } from "@/context/config-provider"; import { OpenContextMenuList } from "@/core/channel-builtin"; +import { triggerEditorExtensionTab } from "@/extensions/trigger-editor"; interface SchemaListProps { search: string; @@ -141,7 +142,7 @@ export default function SchemaList({ search }: Readonly) { (item?: DatabaseSchemaItem) => { const selectedName = item?.name; const isTable = item?.type === "table"; - const isTrigger = item?.type === "trigger"; + // const isTrigger = item?.type === "trigger"; const createMenuSection = { title: "Create", @@ -154,17 +155,6 @@ export default function SchemaList({ search }: Readonly) { }); }, }, - databaseDriver.getFlags().supportCreateUpdateTrigger - ? { - title: "Create Trigger", - onClick: () => { - scc.tabs.openBuiltinTrigger({ - schemaName: item?.schemaName ?? currentSchemaName, - tableName: item?.tableSchema?.tableName, - }); - }, - } - : undefined, ...extensions.getResourceCreateMenu(), ], }; @@ -182,18 +172,6 @@ export default function SchemaList({ search }: Readonly) { }, } : undefined, - databaseDriver.getFlags().supportCreateUpdateTrigger && isTrigger - ? { - title: "Edit Trigger", - onClick: () => { - scc.tabs.openBuiltinTrigger({ - schemaName: item?.schemaName ?? currentSchemaName, - name: item.name, - tableName: item?.tableSchema?.tableName, - }); - }, - } - : undefined, ...extensions.getResourceContextMenu(item, "modification"), ] : []; @@ -282,10 +260,11 @@ export default function SchemaList({ search }: Readonly) { tableName: item.data.name, }); } else if (item.data.type === "trigger") { - scc.tabs.openBuiltinTrigger({ - schemaName: item.data.schemaName, - name: item.name, - }); + triggerEditorExtensionTab.open({ + schemaName: item.data.schemaName ?? '', + name: item.name ?? '', + tableName: item.data.tableName ?? '' + }) } else if (item.data.type === "schema") { if (databaseDriver.getFlags().supportUseStatement) { databaseDriver diff --git a/src/components/gui/schema-sidebar.tsx b/src/components/gui/schema-sidebar.tsx index b2556d69..f9d6eae1 100644 --- a/src/components/gui/schema-sidebar.tsx +++ b/src/components/gui/schema-sidebar.tsx @@ -49,16 +49,6 @@ export default function SchemaView() { }); } - if (flags.supportCreateUpdateTrigger) { - items.push({ - title: "Create Trigger", - key: "create-trigger", - onClick: () => { - scc.tabs.openBuiltinTrigger({ schemaName: currentSchemaName }); - }, - }); - } - return [...items, ...extensions.getResourceCreateMenu()]; }, [databaseDriver, currentSchemaName, extensions]); diff --git a/src/components/gui/table-combobox/TableColumnCombobox.tsx b/src/components/gui/table-combobox/TableColumnCombobox.tsx index fa61ab3b..4ad7320b 100644 --- a/src/components/gui/table-combobox/TableColumnCombobox.tsx +++ b/src/components/gui/table-combobox/TableColumnCombobox.tsx @@ -10,9 +10,9 @@ import { CommandInput, CommandItem, } from "../../ui/command"; -import { cn } from "../../lib/utils"; import type { DatabaseTableSchema } from "@/drivers/base-driver"; import { useDatabaseDriver } from "@/context/driver-provider"; +import { cn } from "@/lib/utils"; export default function TableColumnCombobox({ value, diff --git a/src/components/gui/table-optimized/TableHeader.tsx b/src/components/gui/table-optimized/TableHeader.tsx index 0f7bf882..f2ce78d7 100644 --- a/src/components/gui/table-optimized/TableHeader.tsx +++ b/src/components/gui/table-optimized/TableHeader.tsx @@ -1,8 +1,8 @@ import React, { type ReactElement } from "react"; import type { OptimizeTableHeaderWithIndexProps } from "."; import TableHeaderResizeHandler from "./TableHeaderResizeHandler"; -import { cn } from "../../lib/utils"; import OptimizeTableState from "./OptimizeTableState"; +import { cn } from "@/lib/utils"; export default function TableHeader({ idx, diff --git a/src/components/lib/utils.ts b/src/components/lib/utils.ts deleted file mode 100644 index c2b3c47d..00000000 --- a/src/components/lib/utils.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { type ClassValue, clsx } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} - -/** - * Funny workaround to make a scoped feature - */ -export function scoped(fn: () => T): T { - return fn(); -} - -/** - * Join everything together into a string - * - * @example - * const result = concat("henlo", "-", "world") - * // "henlo-world" - */ -export function concat(...inputs: string[]) { - return inputs.join(""); -} - -export interface ApiErrorResponse { - message: string; - detailedMessage?: string; -} - -/** - * Safely fetch data with a slightly typed response - * - * @example - * - * const { data, error } = await safeFetch(url) - * if (error) { - * console.log(error.message, error.detailedMessage) - * } else { - * console.log(data) // type User - * } - */ -export async function safeFetch( - url: string | URL, - init?: RequestInit -): Promise< - | { - data: Success; - error: null; - response: Response; - } - | { - data: null; - error: ApiErrorResponse; - response: Response; - } -> { - let response: Response = new Response(); - try { - response = await fetch(url, init); - if (!response.ok) { - const json = await response.json(); - return { data: null, error: json?.error || json, response }; - } else { - const data = await response.json(); - return { data, error: null, response }; - } - } catch (e) { - if (e instanceof Error) { - return { - response, - data: null, - error: { message: "Something went wrong", detailedMessage: e.message }, - }; - } - - return { - response, - data: null, - error: { message: "Unknown Error", detailedMessage: JSON.stringify(e) }, - }; - } -} diff --git a/src/core/builtin-tab/open-trigger-tab.tsx b/src/core/builtin-tab/open-trigger-tab.tsx deleted file mode 100644 index 5aa95269..00000000 --- a/src/core/builtin-tab/open-trigger-tab.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import TriggerTab from "@/components/gui/tabs/trigger-tab"; -import { LucideCog } from "lucide-react"; -import { createTabExtension } from "../extension-tab"; - -export const builtinOpenTriggerTab = createTabExtension<{ - schemaName: string; - tableName?: string; - name?: string; -}>({ - name: "trigger", - key: (options) => { - return ( - options.schemaName + - "-" + - (options?.tableName ?? "") + - "-" + - (options?.name ?? "") - ); - }, - generate: (options) => ({ - title: options.name || "New Trigger", - component: ( - - ), - icon: LucideCog, - }), -}); diff --git a/src/core/command/index.ts b/src/core/command/index.ts index f6cb5f72..58d6b6d6 100644 --- a/src/core/command/index.ts +++ b/src/core/command/index.ts @@ -8,7 +8,6 @@ import { builtinMassDropTableTab } from "../builtin-tab/open-mass-drop-table"; import { builtinOpenQueryTab } from "../builtin-tab/open-query-tab"; import { builtinOpenSchemaTab } from "../builtin-tab/open-schema-tab"; import { builtinOpenTableTab } from "../builtin-tab/open-table-tab"; -import { builtinOpenTriggerTab } from "../builtin-tab/open-trigger-tab"; import { tabCloseChannel } from "../extension-tab"; export const scc = { @@ -16,7 +15,6 @@ export const scc = { openBuiltinQuery: builtinOpenQueryTab.open, openBuiltinTable: builtinOpenTableTab.open, openBuiltinSchema: builtinOpenSchemaTab.open, - openBuiltinTrigger: builtinOpenTriggerTab.open, openBuiltinERD: builtinOpenERDTab.open, openBuiltinMassDropTable: builtinMassDropTableTab.open, diff --git a/src/core/standard-extension.tsx b/src/core/standard-extension.tsx index 9d338293..7b5f3558 100644 --- a/src/core/standard-extension.tsx +++ b/src/core/standard-extension.tsx @@ -4,7 +4,8 @@ import QueryHistoryConsoleLogExtension from "@/extensions/query-console-log"; import ViewEditorExtension from "@/extensions/view-editor"; +import TriggerEditorExtension from '@/extensions/trigger-editor'; export function createStandardExtensions() { - return [new QueryHistoryConsoleLogExtension(), new ViewEditorExtension()]; + return [new QueryHistoryConsoleLogExtension(), new TriggerEditorExtension(), new ViewEditorExtension()]; } diff --git a/src/extensions/trigger-editor/index.tsx b/src/extensions/trigger-editor/index.tsx new file mode 100644 index 00000000..80509be4 --- /dev/null +++ b/src/extensions/trigger-editor/index.tsx @@ -0,0 +1,52 @@ +import { StudioExtension } from "@/core/extension-base"; +import { StudioExtensionContext } from "@/core/extension-manager"; +import { createTabExtension } from "@/core/extension-tab"; +import TriggerTab from "./trigger-tab"; +import { LucideCog } from "lucide-react"; + +export const triggerEditorExtensionTab = createTabExtension<{ + schemaName?: string; + name?: string; + tableName?: string; +}>({ + name: 'trigger', + key: (options) => { + return `${options.schemaName}.${options.name}`; + }, + generate: (options) => ({ + title: options.name || 'New Trigger', + component: ( + + ), + icon: LucideCog, + }) +}) + +export default class TriggerEditorExtension extends StudioExtension { + extensionName = "trigger-editor"; + + init(studio: StudioExtensionContext): void { + studio.registerCreateResourceMenu({ + key: "trigger", + title: "Create Trigger", + onClick: () => { + triggerEditorExtensionTab.open({}); + }, + }); + + studio.registerResourceContextMenu((resource) => { + if (resource.type !== "trigger") return; + return { + key: "trigger", + title: "Edit Trigger", + onClick: () => { + triggerEditorExtensionTab.open({ + schemaName: resource.schemaName, + name: resource.name, + tableName: resource.tableName + }); + }, + }; + }, "modification"); + } +} diff --git a/src/components/gui/trigger-editor/trigger-controller.tsx b/src/extensions/trigger-editor/trigger-controller.tsx similarity index 96% rename from src/components/gui/trigger-editor/trigger-controller.tsx rename to src/extensions/trigger-editor/trigger-controller.tsx index 2df4483b..c68e902a 100644 --- a/src/components/gui/trigger-editor/trigger-controller.tsx +++ b/src/extensions/trigger-editor/trigger-controller.tsx @@ -1,8 +1,8 @@ +import CodePreview from "@/components/gui/code-preview"; import { Button, buttonVariants } from "@/components/ui/button"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; import { Separator } from "@/components/ui/separator"; import { LucideCode, LucideLoader, LucideSave } from "lucide-react"; -import CodePreview from "../code-preview"; interface Props { onSave: () => void; diff --git a/src/components/gui/trigger-editor/index.tsx b/src/extensions/trigger-editor/trigger-editor.tsx similarity index 95% rename from src/components/gui/trigger-editor/index.tsx rename to src/extensions/trigger-editor/trigger-editor.tsx index 964e74a4..d464416a 100644 --- a/src/components/gui/trigger-editor/index.tsx +++ b/src/extensions/trigger-editor/trigger-editor.tsx @@ -4,7 +4,6 @@ import { TriggerOperation, TriggerWhen, } from "@/drivers/base-driver"; -import TableCombobox from "../table-combobox/TableCombobox"; import { Input } from "@/components/ui/input"; import { Select, @@ -13,11 +12,12 @@ import { SelectTrigger, SelectValue, } from "@/components/ui/select"; -import SqlEditor from "../sql-editor"; import { produce } from "immer"; -import SchemaNameSelect from "../schema-editor/schema-name-select"; import { useSchema } from "@/context/schema-provider"; import { useMemo } from "react"; +import SchemaNameSelect from "@/components/gui/schema-editor/schema-name-select"; +import TableCombobox from "@/components/gui/table-combobox/TableCombobox"; +import SqlEditor from "@/components/gui/sql-editor"; export interface TriggerEditorProps { onChange: (value: DatabaseTriggerSchema) => void; diff --git a/src/components/gui/trigger-editor/trigger-save-dialog.tsx b/src/extensions/trigger-editor/trigger-save-dialog.tsx similarity index 71% rename from src/components/gui/trigger-editor/trigger-save-dialog.tsx rename to src/extensions/trigger-editor/trigger-save-dialog.tsx index cc3c56dc..bdb20e96 100644 --- a/src/components/gui/trigger-editor/trigger-save-dialog.tsx +++ b/src/extensions/trigger-editor/trigger-save-dialog.tsx @@ -5,15 +5,14 @@ import { AlertDialogFooter, AlertDialogTitle, } from "@/components/ui/alert-dialog"; -import { LucideAlertCircle, LucideLoader, LucideSave, LucideTableProperties } from "lucide-react"; +import { LucideAlertCircle, LucideLoader, LucideSave } from "lucide-react"; import { useCallback, useState } from "react"; -import CodePreview from "../code-preview"; import { Button } from "@/components/ui/button"; import { useDatabaseDriver } from "@/context/driver-provider"; -import TriggerTab from "../tabs/trigger-tab"; -import { useTabsContext } from "../windows-tab"; import { useSchema } from "@/context/schema-provider"; import { DatabaseTriggerSchema } from "@/drivers/base-driver"; +import CodePreview from "@/components/gui/code-preview"; +import { triggerEditorExtensionTab } from "."; interface Props { onClose: () => void; @@ -22,7 +21,6 @@ interface Props { } export function TriggerSaveDialog(props: Props) { - const { replaceCurrentTab } = useTabsContext(); const { refresh: refreshSchema } = useSchema(); const { databaseDriver } = useDatabaseDriver(); const [isExecuting, setIsExecuting] = useState(false); @@ -36,26 +34,18 @@ export function TriggerSaveDialog(props: Props) { ) .then(() => { refreshSchema(); - replaceCurrentTab({ - component: ( - - ), - key: "trigger-" + props.trigger.name || "", - identifier: "trigger-" + props.trigger.name || "", - title: props.trigger.name || "", - icon: LucideTableProperties, - }); + triggerEditorExtensionTab.replace({ + schemaName: props.trigger.schemaName, + name: props.trigger.name ?? '', + tableName: props.trigger.tableName + }) props.onClose(); }) .catch((err) => setErrorMessage((err as Error).message)) .finally(() => { setIsExecuting(false); }); - }, [databaseDriver, props, refreshSchema, replaceCurrentTab]) + }, [databaseDriver, props, refreshSchema]) return ( diff --git a/src/components/gui/tabs/trigger-tab.tsx b/src/extensions/trigger-editor/trigger-tab.tsx similarity index 91% rename from src/components/gui/tabs/trigger-tab.tsx rename to src/extensions/trigger-editor/trigger-tab.tsx index 3576b83d..84d3463b 100644 --- a/src/components/gui/tabs/trigger-tab.tsx +++ b/src/extensions/trigger-editor/trigger-tab.tsx @@ -1,13 +1,12 @@ -import TriggerEditor from "../trigger-editor"; -import { useCallback, useEffect, useMemo, useState } from "react"; -import { DatabaseTriggerSchema } from "@/drivers/base-driver"; +import OpacityLoading from "@/components/gui/loading-opacity"; import { useDatabaseDriver } from "@/context/driver-provider"; -import OpacityLoading from "../loading-opacity"; +import { DatabaseTriggerSchema } from "@/drivers/base-driver"; import { produce } from "immer"; -import { TriggerController } from "../trigger-editor/trigger-controller"; - import { isEqual } from "lodash"; -import { TriggerSaveDialog } from "../trigger-editor/trigger-save-dialog"; +import { useCallback, useEffect, useMemo, useState } from "react"; +import { TriggerController } from "./trigger-controller"; +import { TriggerSaveDialog } from "./trigger-save-dialog"; +import TriggerEditor from "./trigger-editor"; export interface TriggerTabProps { name: string; @@ -97,4 +96,4 @@ export default function TriggerTab({ ); -} +} \ No newline at end of file