Skip to content

Commit

Permalink
follow this style and please help correct it back
Browse files Browse the repository at this point in the history
  • Loading branch information
invisal committed Dec 27, 2024
1 parent 247310a commit e0f671a
Show file tree
Hide file tree
Showing 9 changed files with 218 additions and 117 deletions.
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@
"sql-formatter": "^15.3.2",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7",
"use-immer": "^0.11.0",
"xlsx": "^0.18.5",
"zod": "^3.22.4"
},
Expand Down
96 changes: 85 additions & 11 deletions src/components/gui/tabs/trigger-tab.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,103 @@
import { useSchema } from "@/context/schema-provider";
import TriggerEditor, { TriggerEditorProps } from "../trigger-editor";
import TriggerEditor from "../trigger-editor";
import { useTabsContext } from "../windows-tab";
import { LucideTableProperties } from "lucide-react";
import { useEffect, useState } from "react";
import { DatabaseTriggerSchema } from "@/drivers/base-driver";
import { useDatabaseDriver } from "@/context/driver-provider";
import OpacityLoading from "../loading-opacity";
import { produce } from "immer";
import { TriggerController } from "../trigger-editor/trigger-controller";

export default function TriggerTab(props: TriggerEditorProps) {
import { isEqual } from "lodash";

export interface TriggerTabProps {
name: string;
tableName?: string;
schemaName: string;
}

const EMPTY_DEFAULT_TRIGGER: DatabaseTriggerSchema = {
name: "",
operation: "INSERT",
when: "BEFORE",
tableName: "",
whenExpression: "",
statement: "",
schemaName: "",
};

export default function TriggerTab({
name,
schemaName,
tableName,
}: TriggerTabProps) {
const { databaseDriver } = useDatabaseDriver();
const { refresh: refreshSchema } = useSchema();
const { replaceCurrentTab } = useTabsContext();

const onSave = (trigger: TriggerEditorProps) => {
// If name is specified, it means the trigger is already exist
const [loading, setLoading] = useState(!!name);

// Loading the inital value
const [initialValue, setInitialValue] = useState<DatabaseTriggerSchema>(
() => {
return produce(EMPTY_DEFAULT_TRIGGER, (draft) => {
draft.tableName = tableName ?? "";
draft.schemaName = schemaName ?? "";
});
}
);
const [value, setValue] = useState<DatabaseTriggerSchema>(initialValue);

const hasChanged = !isEqual(initialValue, value);

// Loading the trigger
useEffect(() => {
if (name && schemaName) {
databaseDriver
.trigger(schemaName, name)
.then((triggerValue) => {
setValue(triggerValue);
setInitialValue(triggerValue);
})
.finally(() => setLoading(false));
}
}, [name, schemaName, databaseDriver]);

const onSave = () => {
refreshSchema();
console.log(trigger)
replaceCurrentTab({
component: (
<TriggerTab
tableName={trigger.tableName}
schemaName={trigger.schemaName}
name={trigger.name ?? ''}
tableName={value.tableName}
schemaName={value.schemaName}
name={value.name ?? ""}
/>
),
key: 'trigger-' + trigger.name || '',
identifier: 'trigger-' + trigger.name || '',
title: trigger.name || '',
key: "trigger-" + value.name || "",
identifier: "trigger-" + value.name || "",
title: value.name || "",
icon: LucideTableProperties,
});
};

if (loading) {
return <OpacityLoading />;
}

return <TriggerEditor {...props} onSave={onSave} />
return (
<div className="flex flex-col overflow-hidden w-full h-full">
<TriggerController
onSave={() => {
// @adam do something here
}}
onDiscard={() => {
setValue(initialValue);
}}
/>

<TriggerEditor value={value} onChange={setValue} />
</div>
);
}
134 changes: 74 additions & 60 deletions src/components/gui/trigger-editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,74 +1,74 @@
import { useDatabaseDriver } from "@/context/driver-provider";
import { DatabaseTriggerSchemaChange } from "@/drivers/base-driver";
import { LucideAlertCircle } from "lucide-react";
import { useState } from "react";
import {
DatabaseTriggerSchema,
TriggerOperation,
TriggerWhen,
} from "@/drivers/base-driver";
import TableCombobox from "../table-combobox/TableCombobox";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import SqlEditor from "../sql-editor";
import { TriggerController } from "./trigger-controller";
import { TriggerSaveDialog } from "./trigger-save-dialog";
import { useTriggerState } from "./trigger-state";
import { produce } from "immer";

export interface TriggerEditorProps {
name: string;
tableName?: string;
schemaName: string;
interface TriggerEditorProps {
onChange: (value: DatabaseTriggerSchema) => void;
value: DatabaseTriggerSchema;
}

interface Props extends TriggerEditorProps {
onSave: (trigger: TriggerEditorProps) => void;
}

export default function TriggerEditor(props: Props) {
const { name, tableName, schemaName } = props;
export default function TriggerEditor({ value, onChange }: TriggerEditorProps) {
const { databaseDriver } = useDatabaseDriver();
const { trigger, setTriggerField, error, onDiscard, previewScript } = useTriggerState(schemaName, name, tableName ?? '');
const [isExecuting, setIsExecuting] = useState(false);

return (
<div className="flex flex-col overflow-hidden w-full h-full">
{
isExecuting && (
<TriggerSaveDialog
onSave={(value) => {
props.onSave(value);
setIsExecuting(false);
}}
onClose={() => setIsExecuting(false)}
previewScript={previewScript}
schemaName={schemaName}
trigger={trigger as DatabaseTriggerSchemaChange}
tableName={tableName}
/>
)
}
<TriggerController
onSave={() => setIsExecuting(true)}
onDiscard={onDiscard}
previewScript={previewScript.join('\n')}
disabled={!trigger.name?.new || !schemaName || !trigger.isChange}
isExecuting={isExecuting}
/>
<>
<div className="p-4 flex flex-row gap-2">
<div className="w-full">
<div className="text-xs mb-2">Trigger Name</div>
<Input value={trigger?.name.new ?? trigger?.name.old ?? ""} onChange={e => setTriggerField('name', { ...trigger.name, new: e.currentTarget.value })} />
<Input
value={value.name}
onChange={(e) =>
onChange(
produce(value, (draft) => {
draft.name = e.currentTarget.value;
})
)
}
/>
</div>
<div className="w-[200px]">
<div className="text-xs mb-2">On Table</div>
<TableCombobox
schemaName={schemaName}
value={trigger?.tableName}
onChange={value => setTriggerField('tableName', value)}
schemaName={value.schemaName}
value={value.tableName}
onChange={(newTableName) => {
onChange(
produce(value, (draft) => {
draft.tableName = newTableName;
})
);
}}
/>
</div>
</div>
<div className="p-4 flex flex-col gap-2">
<div className="text-xs">Event</div>
<div className="flex gap-2">
<div className="w-[200px]">
<Select value={trigger?.when ?? "BEFORE"} onValueChange={value => setTriggerField('when', value)}>
<Select
value={value?.when ?? "BEFORE"}
onValueChange={(e) =>
onChange(
produce(value, (draft) => {
draft.when = e as TriggerWhen;
})
)
}
>
<SelectTrigger>
<SelectValue placeholder="When" />
</SelectTrigger>
Expand All @@ -80,7 +80,16 @@ export default function TriggerEditor(props: Props) {
</Select>
</div>
<div className="w-[200px]">
<Select value={trigger?.operation} onValueChange={value => setTriggerField('operation', value)}>
<Select
value={value?.operation}
onValueChange={(newOperation: TriggerOperation) => {
onChange(
produce(value, (draft) => {
draft.operation = newOperation;
})
);
}}
>
<SelectTrigger>
<SelectValue placeholder="Operation" />
</SelectTrigger>
Expand All @@ -93,22 +102,27 @@ export default function TriggerEditor(props: Props) {
</div>
</div>
</div>
{error && (
<div className="text-sm text-red-500 font-mono flex gap-4 justify-start items-end">
<LucideAlertCircle />
<p>{error}</p>
</div>
)}

<div className="grow overflow-hidden">
<div className="h-full">
<div className="text-xs my-2 mx-4">Trigger statement: (eg: &quot;SET NEW.columnA = TRIM(OLD.columnA)&quot;)</div>
<div className="text-xs my-2 mx-4">
Trigger statement: (eg: &quot;SET NEW.columnA =
TRIM(OLD.columnA)&quot;)
</div>

<SqlEditor
value={trigger?.statement ?? ""}
value={value?.statement ?? ""}
dialect={databaseDriver.getFlags().dialect}
onChange={value => setTriggerField('statement', value)}
onChange={(newStatement) =>
onChange(
produce(value, (draft) => {
draft.statement = newStatement;
})
)
}
/>
</div>
</div>
</div >
)
}
</>
);
}
41 changes: 27 additions & 14 deletions src/components/gui/trigger-editor/trigger-save-dialog.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { AlertDialog, AlertDialogCancel, AlertDialogContent, AlertDialogFooter, AlertDialogTitle } from "@/components/ui/alert-dialog";
import {
AlertDialog,
AlertDialogCancel,
AlertDialogContent,
AlertDialogFooter,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { LucideAlertCircle, LucideLoader, LucideSave } from "lucide-react";
import { useState } from "react";
import CodePreview from "../code-preview";
import { Button } from "@/components/ui/button";
import { useDatabaseDriver } from "@/context/driver-provider";
import { TriggerEditorProps } from ".";
import { DatabaseTriggerSchemaChange } from "@/drivers/base-driver";

interface Props {
Expand All @@ -23,21 +28,29 @@ export function TriggerSaveDialog(props: Props) {

const onSave = () => {
setIsExecuting(true);
const isCreated = !props.trigger.name.old
const isCreated = !props.trigger.name.old;
databaseDriver;
databaseDriver
databaseDriver.transaction(
isCreated ? props.previewScript : [`DROP TRIGGER IF EXISTS \`${props.schemaName}\`.\`${props.trigger.name.old}\``, ...props.previewScript],
).then(() => {
props.onSave({
tableName: props.tableName,
schemaName: props.schemaName,
name: props.trigger.name.new ?? ""
.transaction(
isCreated
? props.previewScript
: [
`DROP TRIGGER IF EXISTS \`${props.schemaName}\`.\`${props.trigger.name.old}\``,
...props.previewScript,
]
)
.then(() => {
props.onSave({
tableName: props.tableName,
schemaName: props.schemaName,
name: props.trigger.name.new ?? "",
});
})
}).catch((err) => setErrorMessage((err as Error).message))
.catch((err) => setErrorMessage((err as Error).message))
.finally(() => {
setIsExecuting(false);
});
}
};

return (
<AlertDialog open onOpenChange={props.onClose}>
Expand Down Expand Up @@ -66,5 +79,5 @@ export function TriggerSaveDialog(props: Props) {
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
)
}
);
}
Loading

0 comments on commit e0f671a

Please sign in to comment.