diff --git a/.vscode/launch.json b/.vscode/launch.json index c982c0c..a686ca2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -27,7 +27,7 @@ "outFiles": [ "${workspaceFolder}/packages/dbml-vs-code-extension/dist/extension/*.js" ], - "preLaunchTask": "yarn: build" + "preLaunchTask": "npm: build" }, { "name": "Preview Prisma Extension", @@ -39,7 +39,7 @@ "outFiles": [ "${workspaceFolder}/packages/prisma-vs-code-extension/dist/extension/*.js" ], - "preLaunchTask": "yarn: build:prisma" + "preLaunchTask": "npm: build:prisma" } ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 38b3778..92d89de 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -45,8 +45,6 @@ "cwd": "${workspaceFolder}/packages/dbml-vs-code-extension" } }, - - // prisma { "type": "npm", "script": "build:prisma", @@ -58,6 +56,15 @@ "options": { "cwd": "${workspaceFolder}/packages/prisma-vs-code-extension" } + }, + { + "type": "npm", + "script": "build", + "path": "packages/dbml-vs-code-extension", + "group": "build", + "problemMatcher": [], + "label": "npm: build - packages/dbml-vs-code-extension", + "detail": "npx vite build && yarn run generate:css" } ] } diff --git a/.yarn/install-state.gz b/.yarn/install-state.gz new file mode 100644 index 0000000..5f1bdde Binary files /dev/null and b/.yarn/install-state.gz differ diff --git a/packages/extension-shared/extension/types/webviewCommand.ts b/packages/extension-shared/extension/types/webviewCommand.ts index 0716524..bfcc81f 100644 --- a/packages/extension-shared/extension/types/webviewCommand.ts +++ b/packages/extension-shared/extension/types/webviewCommand.ts @@ -12,5 +12,6 @@ export interface WebviewPostMessage { export interface SetSchemaCommandPayload { type: string; payload: JSONTableSchema; + message?: string; key: string; } diff --git a/packages/extension-shared/extension/views/panel.ts b/packages/extension-shared/extension/views/panel.ts index 57a9797..9e6b432 100644 --- a/packages/extension-shared/extension/views/panel.ts +++ b/packages/extension-shared/extension/views/panel.ts @@ -176,7 +176,15 @@ export class MainPanel { MainPanel.diagnosticCollection.clear(); } catch (error) { console.error(JSON.stringify(error)); + if (error instanceof DiagnosticError) { + // eslint-disable-next-line @typescript-eslint/no-floating-promises + this.currentPanel?._panel.webview.postMessage({ + type: "setSchemaErrorMessage", + message: `${error.message}\n Line : ${error.location.start.line}:${error.location.start.column}`, + key: document.uri.toString(), + }); + MainPanel.diagnosticCollection.set(document.uri, [ new Diagnostic( new Range( diff --git a/packages/extension-shared/src/App.tsx b/packages/extension-shared/src/App.tsx index db86d16..82f0929 100644 --- a/packages/extension-shared/src/App.tsx +++ b/packages/extension-shared/src/App.tsx @@ -2,6 +2,7 @@ import DiagramViewer from "json-table-schema-visualizer/src/components/DiagramVi import { useCreateTheme } from "json-table-schema-visualizer/src/hooks/theme"; import ThemeProvider from "json-table-schema-visualizer/src/providers/ThemeProvider"; import NoSchemaMessage from "json-table-schema-visualizer/src/components/Messages/NoSchemaMessage"; +import ErrorMessage from "json-table-schema-visualizer/src/components/Messages/ErrorMessage"; import { type Theme } from "json-table-schema-visualizer/src/types/theme"; import ScrollDirectionProvider from "json-table-schema-visualizer/src/providers/ScrollDirectionProvider"; @@ -16,7 +17,11 @@ const App = () => { const { setTheme, theme, themeColors } = useCreateTheme( window.EXTENSION_DEFAULT_CONFIG?.theme, ); - const { schema, key } = useSchema(); + const { schema, key, schemaErrorMessage } = useSchema(); + + if (schemaErrorMessage !== null && schema === null) { + return ; + } if (schema === null) { return ; diff --git a/packages/extension-shared/src/hooks/schema.ts b/packages/extension-shared/src/hooks/schema.ts index a845457..9ed6639 100644 --- a/packages/extension-shared/src/hooks/schema.ts +++ b/packages/extension-shared/src/hooks/schema.ts @@ -9,12 +9,26 @@ import { type SetSchemaCommandPayload } from "../../extension/types/webviewComma export const useSchema = (): { schema: JSONTableSchema | null; key: string | null; + schemaErrorMessage: string | null; } => { + const [schemaErrorMessage, setSchemaErrorMessage] = useState( + null, + ); const [schema, setSchema] = useState(null); const [schemaKey, setSchemaKey] = useState(null); const updater = (e: MessageEvent): void => { const message = e.data as SetSchemaCommandPayload; + + if ( + message.type === "setSchemaErrorMessage" && + typeof message.message === "string" + ) { + setSchemaErrorMessage(message.message); + + return; + } + if ( !(message.type === "setSchema" && typeof message.payload === "object") ) { @@ -35,6 +49,7 @@ export const useSchema = (): { } setSchema(message.payload); + setSchemaErrorMessage(null); }; useEffect(() => { @@ -47,5 +62,5 @@ export const useSchema = (): { }; }, []); - return { schema, key: schemaKey }; + return { schema, key: schemaKey, schemaErrorMessage }; }; diff --git a/packages/json-table-schema-visualizer/src/components/DiagramViewer/DiagramWrapper.tsx b/packages/json-table-schema-visualizer/src/components/DiagramViewer/DiagramWrapper.tsx index ec78f8e..2208734 100644 --- a/packages/json-table-schema-visualizer/src/components/DiagramViewer/DiagramWrapper.tsx +++ b/packages/json-table-schema-visualizer/src/components/DiagramViewer/DiagramWrapper.tsx @@ -208,6 +208,45 @@ const DiagramWrapper = ({ children }: DiagramWrapperProps) => { }; }, []); + const onDownload = () => { + if (stageRef.current == null) return; + const stage = stageRef.current; + + // Save current stage state + const originalScale = stage.scaleX(); + const originalPosition = { ...stage.position() }; + + // Reset stage to scale 1 and position 0,0 to get actual content bounds + stage.scale({ x: 1, y: 1 }); + stage.position({ x: 0, y: 0 }); + + const contentBounds = stage.getClientRect({ relativeTo: stage }); + + // Calculate square dimensions (use the larger dimension) + const maxDimension = Math.max(contentBounds.width, contentBounds.height); + + // Center the content in the square + const offsetX = (maxDimension - contentBounds.width) / 2; + const offsetY = (maxDimension - contentBounds.height) / 2; + + const data = stage.toDataURL({ + x: contentBounds.x - offsetX, + y: contentBounds.y - offsetY, + width: maxDimension, + height: maxDimension, + pixelRatio: 2, + }); + + // Restore original stage state + stage.scale({ x: originalScale, y: originalScale }); + stage.position(originalPosition); + + const link = document.createElement("a"); + link.href = data; + link.download = `diagram-${Date.now()}.png`; + link.click(); + }; + return ( <> { - + ); }; diff --git a/packages/json-table-schema-visualizer/src/components/Messages/ErrorMessage.tsx b/packages/json-table-schema-visualizer/src/components/Messages/ErrorMessage.tsx new file mode 100644 index 0000000..71e1a14 --- /dev/null +++ b/packages/json-table-schema-visualizer/src/components/Messages/ErrorMessage.tsx @@ -0,0 +1,14 @@ +import MessageWrapper from "./MessageWrapper"; + +interface ErrorMessageProps { + message: string; +} +const ErrorMessage = ({ message }: ErrorMessageProps) => { + return ( + +

{message}

+
+ ); +}; + +export default ErrorMessage; diff --git a/packages/json-table-schema-visualizer/src/components/Toolbar/Export/Export.tsx b/packages/json-table-schema-visualizer/src/components/Toolbar/Export/Export.tsx new file mode 100644 index 0000000..22b6d8c --- /dev/null +++ b/packages/json-table-schema-visualizer/src/components/Toolbar/Export/Export.tsx @@ -0,0 +1,17 @@ +import { DownloadIcon } from "lucide-react"; + +import ToolbarButton from "../Button"; + +interface ExportButtonProps { + onDownload: () => void; +} + +const ExportButton = ({ onDownload }: ExportButtonProps) => { + return ( + + + + ); +}; + +export default ExportButton; diff --git a/packages/json-table-schema-visualizer/src/components/Toolbar/Toolbar.tsx b/packages/json-table-schema-visualizer/src/components/Toolbar/Toolbar.tsx index 0776235..1b6444e 100644 --- a/packages/json-table-schema-visualizer/src/components/Toolbar/Toolbar.tsx +++ b/packages/json-table-schema-visualizer/src/components/Toolbar/Toolbar.tsx @@ -4,14 +4,23 @@ import AutoArrangeTableButton from "./AutoArrage/AutoArrangeTables"; import ThemeToggler from "./ThemeToggler/ThemeToggler"; import DetailLevelToggle from "./DetailLevelToggle/DetailLevelToggle"; import FitToViewButton from "./FitToView/FitToView"; +import ExportButton from "./Export/Export"; -const Toolbar = ({ onFitToView }: { onFitToView: () => void }) => { +const Toolbar = ({ + onFitToView, + onDownload, +}: { + onFitToView: () => void; + onDownload: () => void; +}) => { return (
-
+
+ +
);