Skip to content

Commit

Permalink
feat: SchemaSQL
Browse files Browse the repository at this point in the history
  • Loading branch information
dineug committed Dec 2, 2023
1 parent 3bc7d73 commit 9182d64
Show file tree
Hide file tree
Showing 28 changed files with 2,381 additions and 16 deletions.
2 changes: 1 addition & 1 deletion packages/erd-editor-schema/src/v3/schema/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export type Settings = {
export const CanvasType = {
ERD: 'ERD',
visualization: '@dineug/builtin-visualization',
SQL_DDL: '@dineug/builtin-sql-ddl',
schemaSQL: '@dineug/builtin-schema-sql',
generatorCode: '@dineug/builtin-generator-code',
} as const;
export type CanvasType = ValuesType<typeof CanvasType>;
Expand Down
1 change: 1 addition & 0 deletions packages/erd-editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"@easylogic/colorpicker": "1.10.11",
"@floating-ui/dom": "1.5.3",
"@fortawesome/free-solid-svg-icons": "6.4.2",
"@fortawesome/free-regular-svg-icons": "6.4.2",
"@mdi/js": "7.2.96",
"@radix-ui/colors": "2.1.0",
"@rollup/plugin-typescript": "^11.1.2",
Expand Down
3 changes: 3 additions & 0 deletions packages/erd-editor/src/components/erd-editor/ErdEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { fromEvent, throttleTime } from 'rxjs';
import { appContext, createAppContext } from '@/components/appContext';
import Erd from '@/components/erd/Erd';
import GlobalStyles from '@/components/global-styles/GlobalStyles';
import SchemaSQL from '@/components/schema-sql/SchemaSQL';
import Theme from '@/components/theme/Theme';
import ToastContainer from '@/components/toast-container/ToastContainer';
import Toolbar from '@/components/toolbar/Toolbar';
Expand Down Expand Up @@ -174,6 +175,8 @@ const ErdEditor: FC<ErdEditorProps, ErdEditorElement> = (props, ctx) => {
)}
${settings.canvasType === CanvasType.visualization
? html`<${Visualization} />`
: settings.canvasType === CanvasType.schemaSQL
? html`<${SchemaSQL} />`
: null}
</div>
<${ToastContainer} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { arrayHas, isArray, isString } from '@dineug/shared';
import { get, isEmpty, omit } from 'lodash-es';

import { AppContext } from '@/components/appContext';
import { DatabaseVendorToDatabase } from '@/constants/sql/database';
import { clearAction } from '@/engine/modules/editor/atom.actions';
import { initialLoadJsonAction$ } from '@/engine/modules/editor/generator.actions';
import { useDarkMode } from '@/hooks/useDarkMode';
Expand All @@ -20,7 +21,8 @@ import {
} from '@/themes/radix-ui-theme';
import { Theme, ThemeTokens } from '@/themes/tokens';
import { KeyBindingName, KeyBindingNameList } from '@/utils/keyboard-shortcut';
import { toSafeString } from '@/utils/validation';
import { createSchemaSQL } from '@/utils/schemaSQL';
import { hasDatabaseVendor, toSafeString } from '@/utils/validation';

import { ErdEditorElement, ErdEditorProps } from './ErdEditor';

Expand Down Expand Up @@ -185,9 +187,11 @@ export function useErdEditorAttachElement({
};

ctx.getSchemaSQL = databaseVendor => {
// TODO: createSchemaSQL
// createSchemaSQL(store);
return '';
const isDatabaseVendor = hasDatabaseVendor(databaseVendor ?? '');
const database = isDatabaseVendor
? get(DatabaseVendorToDatabase, databaseVendor ?? '')
: undefined;
return createSchemaSQL(store.state, database);
};

Object.defineProperty(ctx, 'value', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
exportPNG,
exportSchemaSQL,
} from '@/utils/file/exportFile';
import { createSchemaSQL } from '@/utils/schemaSQL';

export function createExportMenus(
app: AppContext,
Expand All @@ -32,13 +33,11 @@ export function createExportMenus(
{
icon: {
prefix: 'mdi',
name: 'database-import',
name: 'database-export',
},
name: 'Schema SQL',
onClick: () => {
// TODO: exportSQLDDL
console.log('exportSchemaSQL');
// exportSchemaSQL(createSchemaSQL(store), store.state.settings.databaseName);
exportSchemaSQL(createSchemaSQL(store.state), databaseName);
onClose();
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const button = css`
justify-content: center;
flex-shrink: 0;
border-radius: 6px;
cursor: pointer;
`;

export const soft = css`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { html, render } from '@dineug/r-html';
import type { Meta, StoryObj } from '@storybook/html';

import CodeBlock, { CodeBlockProps } from './CodeBlock';

const meta = {
title: 'Primitives/CodeBlock',
render: args => {
const fragment = document.createDocumentFragment();
render(fragment, html`<${CodeBlock} ...${args} />`);
return fragment;
},
argTypes: {
value: {
control: 'text',
},
onCopy: {
action: 'onCopy',
},
},
} satisfies Meta<CodeBlockProps>;

export default meta;
type Story = StoryObj<CodeBlockProps>;

export const Normal: Story = {
args: {
value: 'SELECT * FROM users;',
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { css } from '@dineug/r-html';

export const clipboard = css`
position: absolute;
top: 0;
right: 0;
padding: 8px;
margin: 8px;
cursor: pointer;
fill: var(--foreground);
color: var(--foreground);
opacity: 0;
transition: opacity 0.15s;
&:hover {
fill: var(--active);
color: var(--active);
}
`;

export const root = css`
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
min-height: 40px;
outline: none;
&:hover {
${clipboard} {
opacity: 1;
}
}
`;

export const code = css`
width: 100%;
height: 100%;
white-space: pre;
overflow: auto;
outline: none;
font-family: var(--code-font-family) !important;
color: var(--active);
padding: 16px;
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { FC, html, innerHTML } from '@dineug/r-html';

import Icon from '@/components/primitives/icon/Icon';

import * as styles from './CodeBlock.styles';

export type CodeBlockProps = {
value: string;
onCopy?: (value: string) => void;
};

const CodeBlock: FC<CodeBlockProps> = (props, ctx) => {
const handleCopy = () => {
props.onCopy?.(props.value);
};

return () => html`
<div class=${styles.root}>
<pre class=${['scrollbar', styles.code]}>${innerHTML(props.value)}</pre>
<div class=${styles.clipboard} title="Copy" @click=${handleCopy}>
<${Icon} prefix="far" name="copy" useTransition=${true} />
</div>
</div>
`;
};

export default CodeBlock;
2 changes: 2 additions & 0 deletions packages/erd-editor/src/components/primitives/icon/icons.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { faCopy } from '@fortawesome/free-regular-svg-icons';
import {
faCheck,
faChevronRight,
Expand Down Expand Up @@ -105,6 +106,7 @@ const icons = [
faSyncAlt,
faPalette,
faColumns,
faCopy,
createMDI('code-json', mdiCodeJson),
createMDI('database', mdiDatabase),
createMDI('database-import', mdiDatabaseImport),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { css } from '@dineug/r-html';

export const root = css`
position: relative;
height: 100%;
overflow: auto;
background-color: var(--canvas-background);
`;
78 changes: 78 additions & 0 deletions packages/erd-editor/src/components/schema-sql/SchemaSQL.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { delay } from '@dineug/go';
import { FC, html, observable, onBeforeMount, watch } from '@dineug/r-html';

import { useAppContext } from '@/components/appContext';
import CodeBlock from '@/components/primitives/code-block/CodeBlock';
import { useContextMenuRootProvider } from '@/components/primitives/context-menu/context-menu-root/contextMenuRootContext';
import Toast from '@/components/primitives/toast/Toast';
import SchemaSQLContextMenu from '@/components/schema-sql/schema-sql-context-menu/SchemaSQLContextMenu';
import { useUnmounted } from '@/hooks/useUnmounted';
import { copyToClipboard } from '@/utils/clipboard';
import { openToastAction } from '@/utils/emitter';
import { createSchemaSQL } from '@/utils/schemaSQL';

import * as styles from './SchemaSQL.styles';

export type SchemaSQLProps = {};

const SchemaSQL: FC<SchemaSQLProps> = (props, ctx) => {
const app = useAppContext(ctx);
const { addUnsubscribe } = useUnmounted();
const contextMenu = useContextMenuRootProvider(ctx);

const state = observable({
sql: '',
});

const setSQL = () => {
const { store } = app.value;
state.sql = createSchemaSQL(store.state);
};

const handleCopy = () => {
const { emitter } = app.value;

copyToClipboard(state.sql).then(() => {
emitter.emit(
openToastAction({
close: delay(2000),
message: html`<${Toast} description="Copied!" />`,
})
);
});
};

const handleContextmenuClose = () => {
contextMenu.state.show = false;
};

onBeforeMount(() => {
const { store } = app.value;
const { settings } = store.state;

setSQL();

addUnsubscribe(
watch(settings).subscribe(propName => {
if (propName !== 'database' && propName !== 'bracketType') {
return;
}

setSQL();
})
);
});

return () => html`
<div
class=${styles.root}
@contextmenu=${contextMenu.onContextmenu}
@mousedown=${contextMenu.onMousedown}
>
<${CodeBlock} value=${state.sql} .onCopy=${handleCopy} />
<${SchemaSQLContextMenu} .onClose=${handleContextmenuClose} />
</div>
`;
};

export default SchemaSQL;
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { FC, html } from '@dineug/r-html';

import { useAppContext } from '@/components/appContext';
import { createDatabaseMenus } from '@/components/erd/erd-context-menu/menus/databaseMenus';
import ContextMenu from '@/components/primitives/context-menu/ContextMenu';
import Icon from '@/components/primitives/icon/Icon';

import { createBracketMenus } from './menus/bracketMenus';

export type SchemaSQLContextMenuProps = {
onClose: () => void;
};

const SchemaSQLContextMenu: FC<SchemaSQLContextMenuProps> = (props, ctx) => {
const app = useAppContext(ctx);

const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`;

return () =>
html`<${ContextMenu.Root}
children=${html`
<${ContextMenu.Item}
children=${html`
<${ContextMenu.Menu}
icon=${html`
<${Icon} prefix="mdi" name="database" size=${14} />
`}
name="Database"
right=${chevronRightIcon}
/>
`}
subChildren=${html`${createDatabaseMenus(app.value).map(
menu => html`
<${ContextMenu.Item}
.onClick=${menu.onClick}
children=${html`
<${ContextMenu.Menu}
icon=${menu.checked
? html`<${Icon} name="check" size=${14} />`
: null}
name=${menu.name}
/>
`}
/>
`
)}`}
/>
<${ContextMenu.Item}
children=${html`
<${ContextMenu.Menu}
icon=${html`
<${Icon} prefix="mdi" name="code-brackets" size=${14} />
`}
name="Bracket"
right=${chevronRightIcon}
/>
`}
subChildren=${html`${createBracketMenus(app.value).map(
menu => html`
<${ContextMenu.Item}
.onClick=${menu.onClick}
children=${html`
<${ContextMenu.Menu}
icon=${menu.checked
? html`<${Icon} name="check" size=${14} />`
: null}
name=${menu.name}
/>
`}
/>
`
)}`}
/>
`}
/>`;
};

export default SchemaSQLContextMenu;
Loading

0 comments on commit 9182d64

Please sign in to comment.