diff --git a/src/components/EditorHeader/ControlPanel.jsx b/src/components/EditorHeader/ControlPanel.jsx index f175e78..dbd5c64 100644 --- a/src/components/EditorHeader/ControlPanel.jsx +++ b/src/components/EditorHeader/ControlPanel.jsx @@ -71,6 +71,7 @@ import { exportSQL } from "../../utils/exportSQL"; import { databases } from "../../data/databases"; import { jsonToMermaid } from "../../utils/exportAs/mermaid"; import { isRtl } from "../../i18n/utils/rtl"; +import { jsonToDocumentation } from "../../utils/exportAs/documentation"; import { IdContext } from "../Workspace"; export default function ControlPanel({ @@ -1065,6 +1066,26 @@ export default function ControlPanel({ })); }, }, + { + readme: () => { + setModal(MODAL.CODE); + const result = jsonToDocumentation({ + tables: tables, + relationships: relationships, + notes: notes, + subjectAreas: areas, + database: database, + title: title, + ...(databases[database].hasTypes && { types: types }), + ...(databases[database].hasEnums && { enums: enums }), + }); + setExportData((prev) => ({ + ...prev, + data: result, + extension: "md", + })); + } + }, ], function: () => {}, }, diff --git a/src/i18n/locales/en.js b/src/i18n/locales/en.js index 1c0898d..8304eb1 100644 --- a/src/i18n/locales/en.js +++ b/src/i18n/locales/en.js @@ -238,6 +238,7 @@ const en = { unsigned: "Unsigned", share: "Share", copy_link: "Copy link", + readme: "README", }, }; diff --git a/src/i18n/locales/es.js b/src/i18n/locales/es.js index 173b297..d90df15 100644 --- a/src/i18n/locales/es.js +++ b/src/i18n/locales/es.js @@ -212,6 +212,7 @@ const es = { edit_relationship: "{{extra}} Editar relación {{refName}}", delete_relationship: "Eliminar relación {{refName}}", not_found: "No encontrado", + readme: "README", }, }; diff --git a/src/i18n/locales/fr.js b/src/i18n/locales/fr.js index 31cb97f..f4497ae 100644 --- a/src/i18n/locales/fr.js +++ b/src/i18n/locales/fr.js @@ -217,6 +217,7 @@ const fr = { edit_relationship: "{{extra}} Modifier la relation {{refName}}", delete_relationship: "Supprimer la relation {{refName}}", not_found: "Non trouvé", + readme: "README", }, }; diff --git a/src/utils/exportAs/documentation.js b/src/utils/exportAs/documentation.js new file mode 100644 index 0000000..e47900e --- /dev/null +++ b/src/utils/exportAs/documentation.js @@ -0,0 +1,70 @@ +import { dbToTypes } from "../../data/datatypes"; +import { jsonToMermaid } from "./mermaid"; +import { databases } from "../../data/databases"; + +export function jsonToDocumentation(obj) { + + const documentationSummary = obj.tables + .map((table) => { + return `\t- [${table.name}](#${table.name})`; + }).join("\n"); + + const documentationEntities = obj.tables + .map((table) => { + let enums = ""; + let indexes = table.indices.length > 0 ? table.indices.map((index) => { + return `| ${index.name} | ${index.unique ? "✅" : ""} | ${index.fields.join(", ")} |`; + }).join("\n") : ""; + const fields = table.fields + .map((field) => { + const fieldType = + field.type + + ((dbToTypes[obj.database][field.type].isSized || + dbToTypes[obj.database][field.type].hasPrecision) && + field.size && + field.size !== "" + ? "(" + field.size + ")" + : ""); + enums += (field.type === "ENUM" && field.values && field.values.length > 0) ? + `##### ${field.name}\n\n${field.values.map((index) => `- ${index}`).join("\n")}\n` : ""; + return `| **${field.name}** | ${fieldType} | ${field.primary ? "🔑 PK, " : ""}` + + `${field.nullable ? "null " : "not null "}${field.unique ? ", unique" : ""}${field.increment?", autoincrement":""}` + + `${field.default ? `, default: ${field.default}` : ""} | ` + + `${relationshipByField(table.id, obj.relationships, field.id)}` + + ` |${field.comment ? field.comment : ""} |`; + }).join("\n"); + return `### ${table.name}\n${table.comment ? table.comment : ""}\n` + + `| Name | Type | Settings | References | Note |\n` + + `|-------------|---------------|-------------------------------|-------------------------------|--------------------------------|\n` + + `${fields} \n${enums.length > 0 ? "\n#### Enums\n" + enums : ""}\n` + + `${indexes.length > 0 ? "\n#### Indexes\n| Name | Unique | Fields |\n|------|--------|--------|\n" + indexes : ""}`; + }).join("\n"); + + function relationshipByField(table, relationships, fieldId) { + return relationships.filter(r => r.startTableId === table && r.startFieldId === fieldId) + .map((rel) => rel.name); + + } + + const documentationRelationships = obj.relationships?.length + ? obj.relationships + .map((r) => { + const startTable = obj.tables[r.startTableId].name; + const endTable = obj.tables[r.endTableId].name; + return `- **${startTable} to ${endTable}**: ${r.cardinality}\n`; + }).join("") : ""; + + const documentationTypes = databases[obj.database].hasTypes && obj.types.length > 0 ? obj.types.map((type) => { + return `| Name | fields | Note |\n` + + `|-------------|---------------|--------------------------------|\n` + + `| ${type.name} | ${type.fields.map((field) => field.name).join(", ")} | ${type.comment ? type.comment : ""} |`; + }).join("\n") : ""; + + return `# ${obj.title} documentation\n## Summary\n\n- [Introduction](#introduction)\n- [Database Type](#database-type)\n`+ + `- [Table Structure](#table-structure)\n${documentationSummary}\n- [Relationships](#relationships)\n- [Database Diagram](#database-Diagram)\n\n`+ + `## Introduction\n\n## Database type\n\n- **Database system:** `+ + `${databases[obj.database].name}\n## Table structure\n\n${documentationEntities}`+ + `\n## Relationships\n\n${documentationRelationships}\n` + + `${databases[obj.database].hasTypes && obj.types.length > 0 ? `## Types\n\n` + documentationTypes + `\n\n` : "" }` + + `## Database Diagram\n\n\`\`\`mermaid\n${jsonToMermaid(obj)}\n\`\`\``; +} \ No newline at end of file diff --git a/src/utils/exportSQL/mariadb.js b/src/utils/exportSQL/mariadb.js index e7f5c55..e7f3588 100644 --- a/src/utils/exportSQL/mariadb.js +++ b/src/utils/exportSQL/mariadb.js @@ -1,4 +1,4 @@ -import { exportFieldComment, parseDefault } from "./shared"; +import { parseDefault } from "./shared"; import { dbToTypes } from "../../data/datatypes"; @@ -9,7 +9,7 @@ export function toMariaDB(diagram) { `CREATE OR REPLACE TABLE \`${table.name}\` (\n${table.fields .map( (field) => - `${exportFieldComment(field.comment)}\t\`${ + `\t\`${ field.name }\` ${field.type}${field.unsigned ? " UNSIGNED" : ""}${field.notNull ? " NOT NULL" : ""}${ field.increment ? " AUTO_INCREMENT" : "" diff --git a/src/utils/exportSQL/mysql.js b/src/utils/exportSQL/mysql.js index 2507523..484d457 100644 --- a/src/utils/exportSQL/mysql.js +++ b/src/utils/exportSQL/mysql.js @@ -9,7 +9,7 @@ export function toMySQL(diagram) { `CREATE TABLE \`${table.name}\` (\n${table.fields .map( (field) => - `\` ${field.type}${field.unsigned ? " UNSIGNED" : ""}${field.size !== undefined && field.size !== "" ? "(" + field.size + ")" : ""}${ + `\t\`${field.name}\` ${field.type}${field.unsigned ? " UNSIGNED" : ""}${field.size !== undefined && field.size !== "" ? "(" + field.size + ")" : ""}${ field.notNull ? " NOT NULL" : "" }${ field.increment ? " AUTO_INCREMENT" : ""