mirror of
				https://github.com/Fabio286/antares.git
				synced 2025-06-05 21:59:22 +02:00 
			
		
		
		
	Merge pull request #890 from antares-sql/feat/mysql-check-support
Feat: MySQL check support
This commit is contained in:
		| @@ -55,6 +55,7 @@ export const defaults: Customizations = { | |||||||
|    tableArray: false, |    tableArray: false, | ||||||
|    tableRealCount: false, |    tableRealCount: false, | ||||||
|    tableDuplicate: false, |    tableDuplicate: false, | ||||||
|  |    tableCheck: false, | ||||||
|    viewSettings: false, |    viewSettings: false, | ||||||
|    triggerSettings: false, |    triggerSettings: false, | ||||||
|    triggerFunctionSettings: false, |    triggerFunctionSettings: false, | ||||||
|   | |||||||
| @@ -47,6 +47,7 @@ export const customizations: Customizations = { | |||||||
|    tableTruncateDisableFKCheck: true, |    tableTruncateDisableFKCheck: true, | ||||||
|    tableDuplicate: true, |    tableDuplicate: true, | ||||||
|    tableDdl: true, |    tableDdl: true, | ||||||
|  |    tableCheck: true, | ||||||
|    viewAdd: true, |    viewAdd: true, | ||||||
|    triggerAdd: true, |    triggerAdd: true, | ||||||
|    routineAdd: true, |    routineAdd: true, | ||||||
|   | |||||||
| @@ -159,6 +159,13 @@ export interface TableForeign { | |||||||
|    oldName?: string; |    oldName?: string; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | export interface TableCheck { | ||||||
|  |    // eslint-disable-next-line camelcase | ||||||
|  |    _antares_id?: string; | ||||||
|  |    name: string; | ||||||
|  |    clause: string; | ||||||
|  | } | ||||||
|  |  | ||||||
| export interface CreateTableParams { | export interface CreateTableParams { | ||||||
|    /** Connection UID */ |    /** Connection UID */ | ||||||
|    uid?: string; |    uid?: string; | ||||||
| @@ -166,6 +173,7 @@ export interface CreateTableParams { | |||||||
|    fields: TableField[]; |    fields: TableField[]; | ||||||
|    foreigns: TableForeign[]; |    foreigns: TableForeign[]; | ||||||
|    indexes: TableIndex[]; |    indexes: TableIndex[]; | ||||||
|  |    checks: TableCheck[]; | ||||||
|    options: TableOptions; |    options: TableOptions; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -193,6 +201,11 @@ export interface AlterTableParams { | |||||||
|       changes: TableForeign[]; |       changes: TableForeign[]; | ||||||
|       deletions: TableForeign[]; |       deletions: TableForeign[]; | ||||||
|    }; |    }; | ||||||
|  |    checkChanges: { | ||||||
|  |       additions: TableCheck[]; | ||||||
|  |       changes: TableCheck[]; | ||||||
|  |       deletions: TableCheck[]; | ||||||
|  |    }; | ||||||
|    options: TableOptions; |    options: TableOptions; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -43,6 +43,7 @@ export interface Customizations { | |||||||
|    tableArray?: boolean; |    tableArray?: boolean; | ||||||
|    tableRealCount?: boolean; |    tableRealCount?: boolean; | ||||||
|    tableTruncateDisableFKCheck?: boolean; |    tableTruncateDisableFKCheck?: boolean; | ||||||
|  |    tableCheck?: boolean; | ||||||
|    tableDdl?: boolean; |    tableDdl?: boolean; | ||||||
|    viewAdd?: boolean; |    viewAdd?: boolean; | ||||||
|    viewSettings?: boolean; |    viewSettings?: boolean; | ||||||
|   | |||||||
| @@ -87,6 +87,19 @@ export default (connections: Record<string, antares.Client>) => { | |||||||
|       } |       } | ||||||
|    }); |    }); | ||||||
|  |  | ||||||
|  |    ipcMain.handle('get-table-checks', async (event, params) => { | ||||||
|  |       if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; | ||||||
|  |  | ||||||
|  |       try { | ||||||
|  |          const result = await connections[params.uid].getTableChecks(params); | ||||||
|  |  | ||||||
|  |          return { status: 'success', response: result }; | ||||||
|  |       } | ||||||
|  |       catch (err) { | ||||||
|  |          return { status: 'error', response: err.toString() }; | ||||||
|  |       } | ||||||
|  |    }); | ||||||
|  |  | ||||||
|    ipcMain.handle('get-table-ddl', async (event, params) => { |    ipcMain.handle('get-table-ddl', async (event, params) => { | ||||||
|       if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; |       if (!validateSender(event.senderFrame)) return { status: 'error', response: 'Unauthorized process' }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -189,6 +189,10 @@ export abstract class BaseClient { | |||||||
|       throw new Error('Method "dropSchema" not implemented'); |       throw new Error('Method "dropSchema" not implemented'); | ||||||
|    } |    } | ||||||
|  |  | ||||||
|  |    getTableChecks (...args: any) { | ||||||
|  |       throw new Error('Method "getTableDll" not implemented'); | ||||||
|  |    } | ||||||
|  |  | ||||||
|    getTableDll (...args: any) { |    getTableDll (...args: any) { | ||||||
|       throw new Error('Method "getTableDll" not implemented'); |       throw new Error('Method "getTableDll" not implemented'); | ||||||
|    } |    } | ||||||
|   | |||||||
| @@ -161,6 +161,8 @@ export class MySQLClient extends BaseClient { | |||||||
|  |  | ||||||
|             this._ssh = new SSH2Promise({ |             this._ssh = new SSH2Promise({ | ||||||
|                ...this._params.ssh, |                ...this._params.ssh, | ||||||
|  |                reconnect: true, | ||||||
|  |                reconnectTries: 3, | ||||||
|                debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null |                debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
| @@ -689,6 +691,34 @@ export class MySQLClient extends BaseClient { | |||||||
|       return rows.length ? rows[0].count : 0; |       return rows.length ? rows[0].count : 0; | ||||||
|    } |    } | ||||||
|  |  | ||||||
|  |    async getTableChecks ({ schema, table }: { schema: string; table: string }): Promise<antares.TableCheck[]> { | ||||||
|  |       const { rows } = await this.raw(` | ||||||
|  |             SELECT  | ||||||
|  |                CONSTRAINT_NAME as name,  | ||||||
|  |                CHECK_CLAUSE as clausole  | ||||||
|  |             FROM information_schema.CHECK_CONSTRAINTS  | ||||||
|  |             WHERE CONSTRAINT_SCHEMA = "${schema}"  | ||||||
|  |             AND CONSTRAINT_NAME IN ( | ||||||
|  |                SELECT | ||||||
|  |                   CONSTRAINT_NAME | ||||||
|  |                FROM | ||||||
|  |                   information_schema.TABLE_CONSTRAINTS | ||||||
|  |                WHERE | ||||||
|  |                   TABLE_SCHEMA = "${schema}" | ||||||
|  |                   AND TABLE_NAME = "${table}" | ||||||
|  |                   AND CONSTRAINT_TYPE = 'CHECK' | ||||||
|  |             ) | ||||||
|  |          `); | ||||||
|  |  | ||||||
|  |       if (rows.length) { | ||||||
|  |          return rows.map(row => ({ | ||||||
|  |             name: row.name, | ||||||
|  |             clause: row.clausole | ||||||
|  |          })); | ||||||
|  |       } | ||||||
|  |       return []; | ||||||
|  |    } | ||||||
|  |  | ||||||
|    async getTableOptions ({ schema, table }: { schema: string; table: string }) { |    async getTableOptions ({ schema, table }: { schema: string; table: string }) { | ||||||
|       /* eslint-disable camelcase */ |       /* eslint-disable camelcase */ | ||||||
|       interface TableOptionsResult { |       interface TableOptionsResult { | ||||||
| @@ -865,11 +895,13 @@ export class MySQLClient extends BaseClient { | |||||||
|          fields, |          fields, | ||||||
|          foreigns, |          foreigns, | ||||||
|          indexes, |          indexes, | ||||||
|  |          checks, | ||||||
|          options |          options | ||||||
|       } = params; |       } = params; | ||||||
|       const newColumns: string[] = []; |       const newColumns: string[] = []; | ||||||
|       const newIndexes: string[] = []; |       const newIndexes: string[] = []; | ||||||
|       const newForeigns: string[] = []; |       const newForeigns: string[] = []; | ||||||
|  |       const newChecks: string[] = []; | ||||||
|  |  | ||||||
|       let sql = `CREATE TABLE \`${schema}\`.\`${options.name}\``; |       let sql = `CREATE TABLE \`${schema}\`.\`${options.name}\``; | ||||||
|  |  | ||||||
| @@ -910,7 +942,13 @@ export class MySQLClient extends BaseClient { | |||||||
|          newForeigns.push(`CONSTRAINT \`${foreign.constraintName}\` FOREIGN KEY (\`${foreign.field}\`) REFERENCES \`${foreign.refTable}\` (\`${foreign.refField}\`) ON UPDATE ${foreign.onUpdate} ON DELETE ${foreign.onDelete}`); |          newForeigns.push(`CONSTRAINT \`${foreign.constraintName}\` FOREIGN KEY (\`${foreign.field}\`) REFERENCES \`${foreign.refTable}\` (\`${foreign.refField}\`) ON UPDATE ${foreign.onUpdate} ON DELETE ${foreign.onDelete}`); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns].join(', ')}) COMMENT='${options.comment}', COLLATE='${options.collation}', ENGINE=${options.engine}`; |       // ADD TABLE CHECKS | ||||||
|  |       checks.forEach(check => { | ||||||
|  |          if (!check.clause.trim().length) return; | ||||||
|  |          newChecks.push(`${check.name ? `CONSTRAINT \`${check.name}\` ` : ''}CHECK (${check.clause})`); | ||||||
|  |       }); | ||||||
|  |  | ||||||
|  |       sql = `${sql} (${[...newColumns, ...newIndexes, ...newForeigns, ...newChecks].join(', ')}) COMMENT='${options.comment}', COLLATE='${options.collation}', ENGINE=${options.engine}`; | ||||||
|  |  | ||||||
|       return await this.raw(sql); |       return await this.raw(sql); | ||||||
|    } |    } | ||||||
| @@ -924,6 +962,7 @@ export class MySQLClient extends BaseClient { | |||||||
|          changes, |          changes, | ||||||
|          indexChanges, |          indexChanges, | ||||||
|          foreignChanges, |          foreignChanges, | ||||||
|  |          checkChanges, | ||||||
|          options |          options | ||||||
|       } = params; |       } = params; | ||||||
|  |  | ||||||
| @@ -931,6 +970,7 @@ export class MySQLClient extends BaseClient { | |||||||
|       const alterColumnsAdd: string[] = []; |       const alterColumnsAdd: string[] = []; | ||||||
|       const alterColumnsChange: string[] = []; |       const alterColumnsChange: string[] = []; | ||||||
|       const alterColumnsDrop: string[] = []; |       const alterColumnsDrop: string[] = []; | ||||||
|  |       const alterQueryes: string[] = []; | ||||||
|  |  | ||||||
|       // OPTIONS |       // OPTIONS | ||||||
|       if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`); |       if ('comment' in options) alterColumnsChange.push(`COMMENT='${options.comment}'`); | ||||||
| @@ -976,6 +1016,12 @@ export class MySQLClient extends BaseClient { | |||||||
|          alterColumnsAdd.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`); |          alterColumnsAdd.push(`ADD CONSTRAINT \`${addition.constraintName}\` FOREIGN KEY (\`${addition.field}\`) REFERENCES \`${addition.refTable}\` (\`${addition.refField}\`) ON UPDATE ${addition.onUpdate} ON DELETE ${addition.onDelete}`); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  |       // ADD TABLE CHECKS | ||||||
|  |       checkChanges.additions.forEach(addition => { | ||||||
|  |          if (!addition.clause.trim().length) return; | ||||||
|  |          alterColumnsAdd.push(`ADD ${addition.name ? `CONSTRAINT \`${addition.name}\` ` : ''}CHECK (${addition.clause})`); | ||||||
|  |       }); | ||||||
|  |  | ||||||
|       // CHANGE FIELDS |       // CHANGE FIELDS | ||||||
|       changes.forEach(change => { |       changes.forEach(change => { | ||||||
|          const typeInfo = this.getTypeInfo(change.type); |          const typeInfo = this.getTypeInfo(change.type); | ||||||
| @@ -987,9 +1033,9 @@ export class MySQLClient extends BaseClient { | |||||||
|             ${change.zerofill ? 'ZEROFILL' : ''} |             ${change.zerofill ? 'ZEROFILL' : ''} | ||||||
|             ${change.nullable ? 'NULL' : 'NOT NULL'} |             ${change.nullable ? 'NULL' : 'NOT NULL'} | ||||||
|             ${change.autoIncrement ? 'AUTO_INCREMENT' : ''} |             ${change.autoIncrement ? 'AUTO_INCREMENT' : ''} | ||||||
|  |             ${change.collation ? `COLLATE ${change.collation}` : ''} | ||||||
|             ${change.default !== null ? `DEFAULT ${change.default || '\'\''}` : ''} |             ${change.default !== null ? `DEFAULT ${change.default || '\'\''}` : ''} | ||||||
|             ${change.comment ? `COMMENT '${change.comment}'` : ''} |             ${change.comment ? `COMMENT '${change.comment}'` : ''} | ||||||
|             ${change.collation ? `COLLATE ${change.collation}` : ''} |  | ||||||
|             ${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''} |             ${change.onUpdate ? `ON UPDATE ${change.onUpdate}` : ''} | ||||||
|             ${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`); |             ${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`); | ||||||
|       }); |       }); | ||||||
| @@ -1020,6 +1066,13 @@ export class MySQLClient extends BaseClient { | |||||||
|          alterColumnsChange.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`); |          alterColumnsChange.push(`ADD CONSTRAINT \`${change.constraintName}\` FOREIGN KEY (\`${change.field}\`) REFERENCES \`${change.refTable}\` (\`${change.refField}\`) ON UPDATE ${change.onUpdate} ON DELETE ${change.onDelete}`); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|  |       // CHANGE CHECK TABLE | ||||||
|  |       checkChanges.changes.forEach(change => { | ||||||
|  |          if (!change.clause.trim().length) return; | ||||||
|  |          alterQueryes.push(`${sql} DROP CONSTRAINT \`${change.name}\``); | ||||||
|  |          alterQueryes.push(`${sql} ADD ${change.name ? `CONSTRAINT \`${change.name}\` ` : ''}CHECK (${change.clause})`); | ||||||
|  |       }); | ||||||
|  |  | ||||||
|       // DROP FIELDS |       // DROP FIELDS | ||||||
|       deletions.forEach(deletion => { |       deletions.forEach(deletion => { | ||||||
|          alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``); |          alterColumnsDrop.push(`DROP COLUMN \`${deletion.name}\``); | ||||||
| @@ -1038,7 +1091,11 @@ export class MySQLClient extends BaseClient { | |||||||
|          alterColumnsDrop.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``); |          alterColumnsDrop.push(`DROP FOREIGN KEY \`${deletion.constraintName}\``); | ||||||
|       }); |       }); | ||||||
|  |  | ||||||
|       const alterQueryes = []; |       // DROP CHECK TABLE | ||||||
|  |       checkChanges.deletions.forEach(deletion => { | ||||||
|  |          alterQueryes.push(`${sql} DROP CONSTRAINT \`${deletion.name}\``); | ||||||
|  |       }); | ||||||
|  |  | ||||||
|       if (alterColumnsAdd.length) alterQueryes.push(sql+alterColumnsAdd.join(', ')); |       if (alterColumnsAdd.length) alterQueryes.push(sql+alterColumnsAdd.join(', ')); | ||||||
|       if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', ')); |       if (alterColumnsChange.length) alterQueryes.push(sql+alterColumnsChange.join(', ')); | ||||||
|       if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', ')); |       if (alterColumnsDrop.length) alterQueryes.push(sql+alterColumnsDrop.join(', ')); | ||||||
|   | |||||||
| @@ -168,6 +168,8 @@ export class PostgreSQLClient extends BaseClient { | |||||||
|          try { |          try { | ||||||
|             this._ssh = new SSH2Promise({ |             this._ssh = new SSH2Promise({ | ||||||
|                ...this._params.ssh, |                ...this._params.ssh, | ||||||
|  |                reconnect: true, | ||||||
|  |                reconnectTries: 3, | ||||||
|                debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null |                debug: process.env.NODE_ENV !== 'production' ? (s) => console.log(s) : null | ||||||
|             }); |             }); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -72,6 +72,19 @@ | |||||||
|                   /> |                   /> | ||||||
|                   <span>{{ t('database.foreignKeys') }}</span> |                   <span>{{ t('database.foreignKeys') }}</span> | ||||||
|                </button> |                </button> | ||||||
|  |                <button | ||||||
|  |                   class="btn btn-dark btn-sm ml-2 mr-0" | ||||||
|  |                   :disabled="isSaving || !localFields.length" | ||||||
|  |                   :title="t('database.manageTableChecks')" | ||||||
|  |                   @click="showTableChecksModal" | ||||||
|  |                > | ||||||
|  |                   <BaseIcon | ||||||
|  |                      class="mr-1" | ||||||
|  |                      icon-name="mdiTableCheck" | ||||||
|  |                      :size="24" | ||||||
|  |                   /> | ||||||
|  |                   <span>{{ t('database.tableChecks') }}</span> | ||||||
|  |                </button> | ||||||
|             </div> |             </div> | ||||||
|             <div class="workspace-query-info"> |             <div class="workspace-query-info"> | ||||||
|                <div class="d-flex" :title="t('database.schema')"> |                <div class="d-flex" :title="t('database.schema')"> | ||||||
| @@ -183,11 +196,19 @@ | |||||||
|          @hide="hideForeignModal" |          @hide="hideForeignModal" | ||||||
|          @foreigns-update="foreignsUpdate" |          @foreigns-update="foreignsUpdate" | ||||||
|       /> |       /> | ||||||
|  |       <WorkspaceTabPropsTableChecksModal | ||||||
|  |          v-if="isTableChecksModal" | ||||||
|  |          :local-checks="localTableChecks" | ||||||
|  |          table="new" | ||||||
|  |          :workspace="workspace" | ||||||
|  |          @hide="hideTableChecksModal" | ||||||
|  |          @checks-update="checksUpdate" | ||||||
|  |       /> | ||||||
|    </div> |    </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { ConnectionParams, TableField, TableForeign, TableIndex, TableOptions } from 'common/interfaces/antares'; | import { ConnectionParams, TableCheck, TableField, TableForeign, TableIndex, TableOptions } from 'common/interfaces/antares'; | ||||||
| import { uidGen } from 'common/libs/uidGen'; | import { uidGen } from 'common/libs/uidGen'; | ||||||
| import { ipcRenderer } from 'electron'; | import { ipcRenderer } from 'electron'; | ||||||
| import { storeToRefs } from 'pinia'; | import { storeToRefs } from 'pinia'; | ||||||
| @@ -198,6 +219,7 @@ import BaseIcon from '@/components/BaseIcon.vue'; | |||||||
| import BaseLoader from '@/components/BaseLoader.vue'; | import BaseLoader from '@/components/BaseLoader.vue'; | ||||||
| import BaseSelect from '@/components/BaseSelect.vue'; | import BaseSelect from '@/components/BaseSelect.vue'; | ||||||
| import WorkspaceTabNewTableEmptyState from '@/components/WorkspaceTabNewTableEmptyState.vue'; | import WorkspaceTabNewTableEmptyState from '@/components/WorkspaceTabNewTableEmptyState.vue'; | ||||||
|  | import WorkspaceTabPropsTableChecksModal from '@/components/WorkspaceTabPropsTableChecksModal.vue'; | ||||||
| import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue'; | import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue'; | ||||||
| import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue'; | import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue'; | ||||||
| import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal.vue'; | import WorkspaceTabPropsTableIndexesModal from '@/components/WorkspaceTabPropsTableIndexesModal.vue'; | ||||||
| @@ -236,12 +258,16 @@ const isLoading = ref(false); | |||||||
| const isSaving = ref(false); | const isSaving = ref(false); | ||||||
| const isIndexesModal = ref(false); | const isIndexesModal = ref(false); | ||||||
| const isForeignModal = ref(false); | const isForeignModal = ref(false); | ||||||
|  | const isTableChecksModal = ref(false); | ||||||
|  |  | ||||||
| const originalFields: Ref<TableField[]> = ref([]); | const originalFields: Ref<TableField[]> = ref([]); | ||||||
| const localFields: Ref<TableField[]> = ref([]); | const localFields: Ref<TableField[]> = ref([]); | ||||||
| const originalKeyUsage: Ref<TableForeign[]> = ref([]); | const originalKeyUsage: Ref<TableForeign[]> = ref([]); | ||||||
| const localKeyUsage: Ref<TableForeign[]> = ref([]); | const localKeyUsage: Ref<TableForeign[]> = ref([]); | ||||||
| const originalIndexes: Ref<TableIndex[]> = ref([]); | const originalIndexes: Ref<TableIndex[]> = ref([]); | ||||||
| const localIndexes: Ref<TableIndex[]> = ref([]); | const localIndexes: Ref<TableIndex[]> = ref([]); | ||||||
|  | const originalTableChecks: Ref<TableCheck[]> = ref([]); | ||||||
|  | const localTableChecks: Ref<TableCheck[]> = ref([]); | ||||||
| const tableOptions: Ref<TableOptions> = ref(null); | const tableOptions: Ref<TableOptions> = ref(null); | ||||||
| const localOptions: Ref<TableOptions> = ref(null); | const localOptions: Ref<TableOptions> = ref(null); | ||||||
| const newFieldsCounter = ref(0); | const newFieldsCounter = ref(0); | ||||||
| @@ -274,6 +300,7 @@ const isChanged = computed(() => { | |||||||
|    return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) || |    return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) || | ||||||
|       JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) || |       JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) || | ||||||
|       JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) || |       JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) || | ||||||
|  |       JSON.stringify(originalTableChecks.value) !== JSON.stringify(localTableChecks.value) || | ||||||
|       JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value); |       JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| @@ -291,6 +318,7 @@ const saveChanges = async () => { | |||||||
|       fields: localFields.value, |       fields: localFields.value, | ||||||
|       foreigns: localKeyUsage.value, |       foreigns: localKeyUsage.value, | ||||||
|       indexes: localIndexes.value, |       indexes: localIndexes.value, | ||||||
|  |       checks: localTableChecks.value, | ||||||
|       options: localOptions.value |       options: localOptions.value | ||||||
|    }; |    }; | ||||||
|  |  | ||||||
| @@ -326,6 +354,7 @@ const clearChanges = () => { | |||||||
|    localFields.value = JSON.parse(JSON.stringify(originalFields.value)); |    localFields.value = JSON.parse(JSON.stringify(originalFields.value)); | ||||||
|    localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value)); |    localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value)); | ||||||
|    localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value)); |    localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value)); | ||||||
|  |    localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value)); | ||||||
|  |  | ||||||
|    tableOptions.value = { |    tableOptions.value = { | ||||||
|       name: '', |       name: '', | ||||||
| @@ -446,10 +475,22 @@ const hideForeignModal = () => { | |||||||
|    isForeignModal.value = false; |    isForeignModal.value = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const showTableChecksModal = () => { | ||||||
|  |    isTableChecksModal.value = true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const hideTableChecksModal = () => { | ||||||
|  |    isTableChecksModal.value = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const foreignsUpdate = (foreigns: TableForeign[]) => { | const foreignsUpdate = (foreigns: TableForeign[]) => { | ||||||
|    localKeyUsage.value = foreigns; |    localKeyUsage.value = foreigns; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const checksUpdate = (checks: TableCheck[]) => { | ||||||
|  |    localTableChecks.value = checks; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const saveContentListener = () => { | const saveContentListener = () => { | ||||||
|    const hasModalOpen = !!document.querySelectorAll('.modal.active').length; |    const hasModalOpen = !!document.querySelectorAll('.modal.active').length; | ||||||
|    if (props.isSelected && !hasModalOpen && isChanged.value) |    if (props.isSelected && !hasModalOpen && isChanged.value) | ||||||
|   | |||||||
| @@ -62,7 +62,7 @@ | |||||||
|                <button |                <button | ||||||
|                   class="btn btn-dark btn-sm mr-0" |                   class="btn btn-dark btn-sm mr-0" | ||||||
|                   :disabled="isSaving" |                   :disabled="isSaving" | ||||||
|                   :title="t('database.manageIndexes')" |                   :title="t('database.manageForeignKeys')" | ||||||
|                   @click="showForeignModal" |                   @click="showForeignModal" | ||||||
|                > |                > | ||||||
|                   <BaseIcon |                   <BaseIcon | ||||||
| @@ -72,6 +72,19 @@ | |||||||
|                   /> |                   /> | ||||||
|                   <span>{{ t('database.foreignKeys') }}</span> |                   <span>{{ t('database.foreignKeys') }}</span> | ||||||
|                </button> |                </button> | ||||||
|  |                <button | ||||||
|  |                   class="btn btn-dark btn-sm ml-2 mr-0" | ||||||
|  |                   :disabled="isSaving" | ||||||
|  |                   :title="t('database.manageTableChecks')" | ||||||
|  |                   @click="showTableChecksModal" | ||||||
|  |                > | ||||||
|  |                   <BaseIcon | ||||||
|  |                      class="mr-1" | ||||||
|  |                      icon-name="mdiTableCheck" | ||||||
|  |                      :size="24" | ||||||
|  |                   /> | ||||||
|  |                   <span>{{ t('database.tableChecks') }}</span> | ||||||
|  |                </button> | ||||||
|  |  | ||||||
|                <div class="divider-vert py-3" /> |                <div class="divider-vert py-3" /> | ||||||
|  |  | ||||||
| @@ -218,11 +231,19 @@ | |||||||
|          :workspace="workspace" |          :workspace="workspace" | ||||||
|          @hide="hideDdlModal" |          @hide="hideDdlModal" | ||||||
|       /> |       /> | ||||||
|  |       <WorkspaceTabPropsTableChecksModal | ||||||
|  |          v-if="isTableChecksModal" | ||||||
|  |          :local-checks="localTableChecks" | ||||||
|  |          :table="table" | ||||||
|  |          :workspace="workspace" | ||||||
|  |          @hide="hideTableChecksModal" | ||||||
|  |          @checks-update="checksUpdate" | ||||||
|  |       /> | ||||||
|    </div> |    </div> | ||||||
| </template> | </template> | ||||||
|  |  | ||||||
| <script setup lang="ts"> | <script setup lang="ts"> | ||||||
| import { AlterTableParams, TableField, TableForeign, TableIndex, TableInfos, TableOptions } from 'common/interfaces/antares'; | import { AlterTableParams, TableCheck, TableField, TableForeign, TableIndex, TableInfos, TableOptions } from 'common/interfaces/antares'; | ||||||
| import { uidGen } from 'common/libs/uidGen'; | import { uidGen } from 'common/libs/uidGen'; | ||||||
| import { ipcRenderer } from 'electron'; | import { ipcRenderer } from 'electron'; | ||||||
| import { storeToRefs } from 'pinia'; | import { storeToRefs } from 'pinia'; | ||||||
| @@ -232,6 +253,7 @@ import { useI18n } from 'vue-i18n'; | |||||||
| import BaseIcon from '@/components/BaseIcon.vue'; | import BaseIcon from '@/components/BaseIcon.vue'; | ||||||
| import BaseLoader from '@/components/BaseLoader.vue'; | import BaseLoader from '@/components/BaseLoader.vue'; | ||||||
| import BaseSelect from '@/components/BaseSelect.vue'; | import BaseSelect from '@/components/BaseSelect.vue'; | ||||||
|  | import WorkspaceTabPropsTableChecksModal from '@/components/WorkspaceTabPropsTableChecksModal.vue'; | ||||||
| import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue'; | import WorkspaceTabPropsTableDdlModal from '@/components/WorkspaceTabPropsTableDdlModal.vue'; | ||||||
| import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue'; | import WorkspaceTabPropsTableFields from '@/components/WorkspaceTabPropsTableFields.vue'; | ||||||
| import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue'; | import WorkspaceTabPropsTableForeignModal from '@/components/WorkspaceTabPropsTableForeignModal.vue'; | ||||||
| @@ -273,13 +295,17 @@ const isLoading = ref(false); | |||||||
| const isSaving = ref(false); | const isSaving = ref(false); | ||||||
| const isIndexesModal = ref(false); | const isIndexesModal = ref(false); | ||||||
| const isForeignModal = ref(false); | const isForeignModal = ref(false); | ||||||
|  | const isTableChecksModal = ref(false); | ||||||
| const isDdlModal = ref(false); | const isDdlModal = ref(false); | ||||||
|  |  | ||||||
| const originalFields: Ref<TableField[]> = ref([]); | const originalFields: Ref<TableField[]> = ref([]); | ||||||
| const localFields: Ref<TableField[]> = ref([]); | const localFields: Ref<TableField[]> = ref([]); | ||||||
| const originalKeyUsage: Ref<TableForeign[]> = ref([]); | const originalKeyUsage: Ref<TableForeign[]> = ref([]); | ||||||
| const localKeyUsage: Ref<TableForeign[]> = ref([]); | const localKeyUsage: Ref<TableForeign[]> = ref([]); | ||||||
| const originalIndexes: Ref<TableIndex[]> = ref([]); | const originalIndexes: Ref<TableIndex[]> = ref([]); | ||||||
| const localIndexes: Ref<TableIndex[]> = ref([]); | const localIndexes: Ref<TableIndex[]> = ref([]); | ||||||
|  | const originalTableChecks: Ref<TableCheck[]> = ref([]); | ||||||
|  | const localTableChecks: Ref<TableCheck[]> = ref([]); | ||||||
| const tableOptions: Ref<TableOptions> = ref(null); | const tableOptions: Ref<TableOptions> = ref(null); | ||||||
| const localOptions: Ref<TableOptions> = ref({} as TableOptions); | const localOptions: Ref<TableOptions> = ref({} as TableOptions); | ||||||
| const lastTable = ref(null); | const lastTable = ref(null); | ||||||
| @@ -307,6 +333,7 @@ const isChanged = computed(() => { | |||||||
|    return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) || |    return JSON.stringify(originalFields.value) !== JSON.stringify(localFields.value) || | ||||||
|       JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) || |       JSON.stringify(originalKeyUsage.value) !== JSON.stringify(localKeyUsage.value) || | ||||||
|       JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) || |       JSON.stringify(originalIndexes.value) !== JSON.stringify(localIndexes.value) || | ||||||
|  |       JSON.stringify(originalTableChecks.value) !== JSON.stringify(localTableChecks.value) || | ||||||
|       JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value); |       JSON.stringify(tableOptions.value) !== JSON.stringify(localOptions.value); | ||||||
| }); | }); | ||||||
|  |  | ||||||
| @@ -430,6 +457,27 @@ const getFieldsData = async () => { | |||||||
|       addNotification({ status: 'error', message: err.stack }); |       addNotification({ status: 'error', message: err.stack }); | ||||||
|    } |    } | ||||||
|  |  | ||||||
|  |    if (workspace.value.customizations.tableCheck) { | ||||||
|  |       try { // Table checks | ||||||
|  |          const { status, response } = await Tables.getTableChecks(params); | ||||||
|  |  | ||||||
|  |          if (status === 'success') { | ||||||
|  |             originalTableChecks.value = response.map((check: TableCheck) => { | ||||||
|  |                return { | ||||||
|  |                   _antares_id: uidGen(), | ||||||
|  |                   ...check | ||||||
|  |                }; | ||||||
|  |             }); | ||||||
|  |             localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value)); | ||||||
|  |          } | ||||||
|  |          else | ||||||
|  |             addNotification({ status: 'error', message: response }); | ||||||
|  |       } | ||||||
|  |       catch (err) { | ||||||
|  |          addNotification({ status: 'error', message: err.stack }); | ||||||
|  |       } | ||||||
|  |    } | ||||||
|  |  | ||||||
|    isLoading.value = false; |    isLoading.value = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -527,6 +575,33 @@ const saveChanges = async () => { | |||||||
|    // Foreigns Deletions |    // Foreigns Deletions | ||||||
|    foreignChanges.deletions = originalKeyUsage.value.filter(foreign => !localForeignIDs.includes(foreign._antares_id)); |    foreignChanges.deletions = originalKeyUsage.value.filter(foreign => !localForeignIDs.includes(foreign._antares_id)); | ||||||
|  |  | ||||||
|  |    // CHECKS | ||||||
|  |    const checkChanges = { | ||||||
|  |       additions: [] as TableCheck[], | ||||||
|  |       changes: [] as TableCheck[], | ||||||
|  |       deletions: [] as TableCheck[] | ||||||
|  |    }; | ||||||
|  |    const originalCheckIDs = originalTableChecks.value.reduce((acc, curr) => [...acc, curr._antares_id], []); | ||||||
|  |    const localCheckIDs = localTableChecks.value.reduce((acc, curr) => [...acc, curr._antares_id], []); | ||||||
|  |  | ||||||
|  |    // Check Additions | ||||||
|  |    checkChanges.additions = localTableChecks.value.filter(check => !originalCheckIDs.includes(check._antares_id)); | ||||||
|  |  | ||||||
|  |    // Check Changes | ||||||
|  |    originalTableChecks.value.forEach(originalCheck => { | ||||||
|  |       const lI = localTableChecks.value.findIndex(localCheck => localCheck._antares_id === originalCheck._antares_id); | ||||||
|  |       if (JSON.stringify(originalCheck) !== JSON.stringify(localTableChecks.value[lI])) { | ||||||
|  |          if (localTableChecks.value[lI]) { | ||||||
|  |             checkChanges.changes.push({ | ||||||
|  |                ...localTableChecks.value[lI] | ||||||
|  |             }); | ||||||
|  |          } | ||||||
|  |       } | ||||||
|  |    }); | ||||||
|  |  | ||||||
|  |    // Check Deletions | ||||||
|  |    checkChanges.deletions = originalTableChecks.value.filter(check => !localCheckIDs.includes(check._antares_id)); | ||||||
|  |  | ||||||
|    // ALTER |    // ALTER | ||||||
|    const params = { |    const params = { | ||||||
|       uid: props.connection.uid, |       uid: props.connection.uid, | ||||||
| @@ -543,6 +618,7 @@ const saveChanges = async () => { | |||||||
|       deletions, |       deletions, | ||||||
|       indexChanges, |       indexChanges, | ||||||
|       foreignChanges, |       foreignChanges, | ||||||
|  |       checkChanges, | ||||||
|       options |       options | ||||||
|    } as unknown as AlterTableParams; |    } as unknown as AlterTableParams; | ||||||
|  |  | ||||||
| @@ -583,6 +659,7 @@ const clearChanges = () => { | |||||||
|    localFields.value = JSON.parse(JSON.stringify(originalFields.value)); |    localFields.value = JSON.parse(JSON.stringify(originalFields.value)); | ||||||
|    localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value)); |    localIndexes.value = JSON.parse(JSON.stringify(originalIndexes.value)); | ||||||
|    localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value)); |    localKeyUsage.value = JSON.parse(JSON.stringify(originalKeyUsage.value)); | ||||||
|  |    localTableChecks.value = JSON.parse(JSON.stringify(originalTableChecks.value)); | ||||||
|    localOptions.value = JSON.parse(JSON.stringify(tableOptions.value)); |    localOptions.value = JSON.parse(JSON.stringify(tableOptions.value)); | ||||||
|    newFieldsCounter.value = 0; |    newFieldsCounter.value = 0; | ||||||
| }; | }; | ||||||
| @@ -702,6 +779,14 @@ const hideForeignModal = () => { | |||||||
|    isForeignModal.value = false; |    isForeignModal.value = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const showTableChecksModal = () => { | ||||||
|  |    isTableChecksModal.value = true; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const hideTableChecksModal = () => { | ||||||
|  |    isTableChecksModal.value = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const showDdlModal = () => { | const showDdlModal = () => { | ||||||
|    isDdlModal.value = true; |    isDdlModal.value = true; | ||||||
| }; | }; | ||||||
| @@ -714,6 +799,10 @@ const foreignsUpdate = (foreigns: TableForeign[]) => { | |||||||
|    localKeyUsage.value = foreigns; |    localKeyUsage.value = foreigns; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | const checksUpdate = (checks: TableCheck[]) => { | ||||||
|  |    localTableChecks.value = checks; | ||||||
|  | }; | ||||||
|  |  | ||||||
| const saveContentListener = () => { | const saveContentListener = () => { | ||||||
|    const hasModalOpen = !!document.querySelectorAll('.modal.active').length; |    const hasModalOpen = !!document.querySelectorAll('.modal.active').length; | ||||||
|    if (props.isSelected && !hasModalOpen && isChanged.value) |    if (props.isSelected && !hasModalOpen && isChanged.value) | ||||||
|   | |||||||
							
								
								
									
										268
									
								
								src/renderer/components/WorkspaceTabPropsTableChecksModal.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										268
									
								
								src/renderer/components/WorkspaceTabPropsTableChecksModal.vue
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,268 @@ | |||||||
|  | <template> | ||||||
|  |    <ConfirmModal | ||||||
|  |       :confirm-text="t('general.confirm')" | ||||||
|  |       size="medium" | ||||||
|  |       class="options-modal" | ||||||
|  |       @confirm="confirmChecksChange" | ||||||
|  |       @hide="$emit('hide')" | ||||||
|  |    > | ||||||
|  |       <template #header> | ||||||
|  |          <div class="d-flex"> | ||||||
|  |             <BaseIcon | ||||||
|  |                class="mr-1" | ||||||
|  |                icon-name="mdiTableCheck" | ||||||
|  |                :size="24" | ||||||
|  |             /> | ||||||
|  |             <span class="cut-text">{{ t('database.tableChecks') }} "{{ table }}"</span> | ||||||
|  |          </div> | ||||||
|  |       </template> | ||||||
|  |       <template #body> | ||||||
|  |          <div class="columns col-gapless"> | ||||||
|  |             <div class="column col-5"> | ||||||
|  |                <div class="panel" :style="{ height: modalInnerHeight + 'px'}"> | ||||||
|  |                   <div class="panel-header pt-0 pl-0"> | ||||||
|  |                      <div class="d-flex"> | ||||||
|  |                         <button class="btn btn-dark btn-sm d-flex" @click="addCheck"> | ||||||
|  |                            <BaseIcon | ||||||
|  |                               class="mr-1" | ||||||
|  |                               icon-name="mdiCheckboxMarkedCirclePlusOutline" | ||||||
|  |                               :size="24" | ||||||
|  |                            /> | ||||||
|  |                            <span>{{ t('general.add') }}</span> | ||||||
|  |                         </button> | ||||||
|  |                         <button | ||||||
|  |                            class="btn btn-dark btn-sm d-flex ml-2 mr-0" | ||||||
|  |                            :title="t('database.clearChanges')" | ||||||
|  |                            :disabled="!isChanged" | ||||||
|  |                            @click.prevent="clearChanges" | ||||||
|  |                         > | ||||||
|  |                            <BaseIcon | ||||||
|  |                               class="mr-1" | ||||||
|  |                               icon-name="mdiDeleteSweep" | ||||||
|  |                               :size="24" | ||||||
|  |                            /> | ||||||
|  |                            <span>{{ t('general.clear') }}</span> | ||||||
|  |                         </button> | ||||||
|  |                      </div> | ||||||
|  |                   </div> | ||||||
|  |                   <div ref="checksPanel" class="panel-body p-0 pr-1"> | ||||||
|  |                      <div | ||||||
|  |                         v-for="check in checksProxy" | ||||||
|  |                         :key="check._antares_id" | ||||||
|  |                         class="tile tile-centered c-hand mb-1 p-1" | ||||||
|  |                         :class="{'selected-element': selectedCheckID === check._antares_id}" | ||||||
|  |                         @click="selectCheck($event, check._antares_id)" | ||||||
|  |                      > | ||||||
|  |                         <div class="tile-icon"> | ||||||
|  |                            <div> | ||||||
|  |                               <BaseIcon | ||||||
|  |                                  class="mt-2 column-key" | ||||||
|  |                                  icon-name="mdiCheckboxMarkedCircleOutline" | ||||||
|  |                                  :size="24" | ||||||
|  |                               /> | ||||||
|  |                            </div> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="tile-content"> | ||||||
|  |                            <div class="tile-title"> | ||||||
|  |                               {{ check.name }} | ||||||
|  |                            </div> | ||||||
|  |                            <small class="tile-subtitle text-gray d-inline-block cut-text" style="width: 100%;">{{ check.clause }}</small> | ||||||
|  |                         </div> | ||||||
|  |                         <div class="tile-action"> | ||||||
|  |                            <button | ||||||
|  |                               class="btn btn-link remove-field p-0 mr-2" | ||||||
|  |                               :title="t('general.delete')" | ||||||
|  |                               @click.prevent="removeCheck(check._antares_id)" | ||||||
|  |                            > | ||||||
|  |                               <BaseIcon | ||||||
|  |                                  icon-name="mdiClose" | ||||||
|  |                                  :size="18" | ||||||
|  |                                  class="mt-2" | ||||||
|  |                               /> | ||||||
|  |                            </button> | ||||||
|  |                         </div> | ||||||
|  |                      </div> | ||||||
|  |                   </div> | ||||||
|  |                </div> | ||||||
|  |             </div> | ||||||
|  |  | ||||||
|  |             <div class="column col-7 pl-2 editor-col"> | ||||||
|  |                <form | ||||||
|  |                   v-if="selectedCheckObj" | ||||||
|  |                   :style="{ height: modalInnerHeight + 'px'}" | ||||||
|  |                   class="form-horizontal" | ||||||
|  |                > | ||||||
|  |                   <div class="form-group"> | ||||||
|  |                      <label class="form-label col-3"> | ||||||
|  |                         {{ t('general.name') }} | ||||||
|  |                      </label> | ||||||
|  |                      <div class="column"> | ||||||
|  |                         <input | ||||||
|  |                            v-model="selectedCheckObj.name" | ||||||
|  |                            class="form-input" | ||||||
|  |                            type="text" | ||||||
|  |                         > | ||||||
|  |                      </div> | ||||||
|  |                   </div> | ||||||
|  |                   <div class="form-group"> | ||||||
|  |                      <label class="form-label col-3"> | ||||||
|  |                         {{ t('database.checkClause') }} | ||||||
|  |                      </label> | ||||||
|  |                      <div class="column"> | ||||||
|  |                         <textarea | ||||||
|  |                            v-model="selectedCheckObj.clause" | ||||||
|  |                            class="form-input" | ||||||
|  |                            style="resize: vertical;" | ||||||
|  |                            rows="5" | ||||||
|  |                         /> | ||||||
|  |                      </div> | ||||||
|  |                   </div> | ||||||
|  |                </form> | ||||||
|  |                <div v-if="!checksProxy.length" class="empty"> | ||||||
|  |                   <div class="empty-icon"> | ||||||
|  |                      <BaseIcon | ||||||
|  |                         class="mr-1" | ||||||
|  |                         icon-name="mdiCheckboxMarkedCircleOutline" | ||||||
|  |                         :size="48" | ||||||
|  |                      /> | ||||||
|  |                   </div> | ||||||
|  |                   <p class="empty-title h5"> | ||||||
|  |                      {{ t('database.thereAreNoTableChecks') }} | ||||||
|  |                   </p> | ||||||
|  |                   <div class="empty-action"> | ||||||
|  |                      <button class="btn btn-primary" @click="addCheck"> | ||||||
|  |                         {{ t('database.createNewCheck') }} | ||||||
|  |                      </button> | ||||||
|  |                   </div> | ||||||
|  |                </div> | ||||||
|  |             </div> | ||||||
|  |          </div> | ||||||
|  |       </template> | ||||||
|  |    </ConfirmModal> | ||||||
|  | </template> | ||||||
|  |  | ||||||
|  | <script setup lang="ts"> | ||||||
|  | import { TableCheck } from 'common/interfaces/antares'; | ||||||
|  | import { uidGen } from 'common/libs/uidGen'; | ||||||
|  | import { computed, onMounted, onUnmounted, Ref, ref } from 'vue'; | ||||||
|  | import { useI18n } from 'vue-i18n'; | ||||||
|  |  | ||||||
|  | import ConfirmModal from '@/components/BaseConfirmModal.vue'; | ||||||
|  | import BaseIcon from '@/components/BaseIcon.vue'; | ||||||
|  |  | ||||||
|  | const { t } = useI18n(); | ||||||
|  |  | ||||||
|  | const props = defineProps({ | ||||||
|  |    localChecks: Array, | ||||||
|  |    table: String, | ||||||
|  |    workspace: Object | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | const emit = defineEmits(['hide', 'checks-update']); | ||||||
|  |  | ||||||
|  | const checksPanel: Ref<HTMLDivElement> = ref(null); | ||||||
|  | const checksProxy: Ref<TableCheck[]> = ref([]); | ||||||
|  | const selectedCheckID = ref(''); | ||||||
|  | const modalInnerHeight = ref(400); | ||||||
|  |  | ||||||
|  | const selectedCheckObj = computed(() => checksProxy.value.find(index => index._antares_id === selectedCheckID.value)); | ||||||
|  | const isChanged = computed(() => JSON.stringify(props.localChecks) !== JSON.stringify(checksProxy.value)); | ||||||
|  |  | ||||||
|  | const confirmChecksChange = () => { | ||||||
|  |    const filteredChecks = checksProxy.value.filter(check => check.clause.trim().length); | ||||||
|  |    emit('checks-update', filteredChecks); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const selectCheck = (event: MouseEvent, id: string) => { | ||||||
|  |    // eslint-disable-next-line @typescript-eslint/no-explicit-any | ||||||
|  |    if (selectedCheckID.value !== id && !(event.target as any).classList.contains('remove-field')) | ||||||
|  |       selectedCheckID.value = id; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const getModalInnerHeight = () => { | ||||||
|  |    const modalBody = document.querySelector('.modal-body'); | ||||||
|  |    if (modalBody) | ||||||
|  |       modalInnerHeight.value = modalBody.clientHeight - (parseFloat(getComputedStyle(modalBody).paddingTop) + parseFloat(getComputedStyle(modalBody).paddingBottom)); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const addCheck = () => { | ||||||
|  |    const uid = uidGen(); | ||||||
|  |    checksProxy.value = [...checksProxy.value, { | ||||||
|  |       _antares_id: uid, | ||||||
|  |       name: `CHK_${uid.substring(0, 4)}`, | ||||||
|  |       clause: '' | ||||||
|  |    }]; | ||||||
|  |  | ||||||
|  |    if (checksProxy.value.length === 1) | ||||||
|  |       resetSelectedID(); | ||||||
|  |  | ||||||
|  |    setTimeout(() => { | ||||||
|  |       checksPanel.value.scrollTop = checksPanel.value.scrollHeight + 60; | ||||||
|  |       selectedCheckID.value = uid; | ||||||
|  |    }, 20); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const removeCheck = (id: string) => { | ||||||
|  |    checksProxy.value = checksProxy.value.filter(index => index._antares_id !== id); | ||||||
|  |  | ||||||
|  |    if (selectedCheckID.value === id && checksProxy.value.length) | ||||||
|  |       resetSelectedID(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const clearChanges = () => { | ||||||
|  |    checksProxy.value = JSON.parse(JSON.stringify(props.localChecks)); | ||||||
|  |    if (!checksProxy.value.some(index => index._antares_id === selectedCheckID.value)) | ||||||
|  |       resetSelectedID(); | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | const resetSelectedID = () => { | ||||||
|  |    selectedCheckID.value = checksProxy.value.length ? checksProxy.value[0]._antares_id : ''; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | onMounted(() => { | ||||||
|  |    checksProxy.value = JSON.parse(JSON.stringify(props.localChecks)); | ||||||
|  |  | ||||||
|  |    if (checksProxy.value.length) | ||||||
|  |       resetSelectedID(); | ||||||
|  |  | ||||||
|  |    getModalInnerHeight(); | ||||||
|  |    window.addEventListener('resize', getModalInnerHeight); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | onUnmounted(() => { | ||||||
|  |    window.removeEventListener('resize', getModalInnerHeight); | ||||||
|  | }); | ||||||
|  | </script> | ||||||
|  |  | ||||||
|  | <style lang="scss" scoped> | ||||||
|  | .tile { | ||||||
|  |   border-radius: $border-radius; | ||||||
|  |   opacity: 0.5; | ||||||
|  |   transition: background 0.2s; | ||||||
|  |   transition: opacity 0.2s; | ||||||
|  |  | ||||||
|  |   .tile-action { | ||||||
|  |     opacity: 0; | ||||||
|  |     transition: opacity 0.2s; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &:hover { | ||||||
|  |     .tile-action { | ||||||
|  |       opacity: 1; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   &.selected-element { | ||||||
|  |     opacity: 1; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .fields-list { | ||||||
|  |   max-height: 300px; | ||||||
|  |   overflow: auto; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | .remove-field svg { | ||||||
|  |   pointer-events: none; | ||||||
|  | } | ||||||
|  | </style> | ||||||
| @@ -126,6 +126,7 @@ export const enUS = { | |||||||
|       insert: 'Insert', |       insert: 'Insert', | ||||||
|       indexes: 'Indexes', |       indexes: 'Indexes', | ||||||
|       foreignKeys: 'Foreign keys', |       foreignKeys: 'Foreign keys', | ||||||
|  |       tableChecks: 'Table checks', | ||||||
|       length: 'Length', |       length: 'Length', | ||||||
|       unsigned: 'Unsigned', |       unsigned: 'Unsigned', | ||||||
|       default: 'Default', |       default: 'Default', | ||||||
| @@ -190,12 +191,15 @@ export const enUS = { | |||||||
|       addNewField: 'Add new field', |       addNewField: 'Add new field', | ||||||
|       manageIndexes: 'Manage indexes', |       manageIndexes: 'Manage indexes', | ||||||
|       manageForeignKeys: 'Manage foreign keys', |       manageForeignKeys: 'Manage foreign keys', | ||||||
|  |       manageTableChecks: 'Manage table checks', | ||||||
|       allowNull: 'Allow NULL', |       allowNull: 'Allow NULL', | ||||||
|       zeroFill: 'Zero fill', |       zeroFill: 'Zero fill', | ||||||
|       customValue: 'Custom value', |       customValue: 'Custom value', | ||||||
|       onUpdate: 'On update', |       onUpdate: 'On update', | ||||||
|       deleteField: 'Delete field', |       deleteField: 'Delete field', | ||||||
|       createNewIndex: 'Create new index', |       createNewIndex: 'Create new index', | ||||||
|  |       createNewCheck: 'Create new check', | ||||||
|  |       checkClause: 'Check clause', | ||||||
|       addToIndex: 'Add to index', |       addToIndex: 'Add to index', | ||||||
|       createNewTable: 'Create new table', |       createNewTable: 'Create new table', | ||||||
|       emptyTable: 'Empty table', |       emptyTable: 'Empty table', | ||||||
| @@ -205,6 +209,7 @@ export const enUS = { | |||||||
|       emptyConfirm: 'Do you confirm to empty', |       emptyConfirm: 'Do you confirm to empty', | ||||||
|       thereAreNoIndexes: 'There are no indexes', |       thereAreNoIndexes: 'There are no indexes', | ||||||
|       thereAreNoForeign: 'There are no foreign keys', |       thereAreNoForeign: 'There are no foreign keys', | ||||||
|  |       thereAreNoTableChecks: 'There are no table checks', | ||||||
|       createNewForeign: 'Create new foreign key', |       createNewForeign: 'Create new foreign key', | ||||||
|       referenceTable: 'Ref. table', |       referenceTable: 'Ref. table', | ||||||
|       referenceField: 'Ref. field', |       referenceField: 'Ref. field', | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -36,6 +36,10 @@ export default class { | |||||||
|       return ipcRenderer.invoke('get-table-indexes', unproxify(params)); |       return ipcRenderer.invoke('get-table-indexes', unproxify(params)); | ||||||
|    } |    } | ||||||
|  |  | ||||||
|  |    static getTableChecks (params: { uid: string; schema: string; table: string }): Promise<IpcResponse> { | ||||||
|  |       return ipcRenderer.invoke('get-table-checks', unproxify(params)); | ||||||
|  |    } | ||||||
|  |  | ||||||
|    static getTableDll (params: { uid: string; schema: string; table: string }): Promise<IpcResponse<string>> { |    static getTableDll (params: { uid: string; schema: string; table: string }): Promise<IpcResponse<string>> { | ||||||
|       return ipcRenderer.invoke('get-table-ddl', unproxify(params)); |       return ipcRenderer.invoke('get-table-ddl', unproxify(params)); | ||||||
|    } |    } | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ export interface QueryLog { | |||||||
| } | } | ||||||
|  |  | ||||||
| export interface DebugLog { | export interface DebugLog { | ||||||
|    level: 'log' | 'info' | 'warn' | 'error'; |    level: 'log' | 'info' | 'warn' | 'error' | string; | ||||||
|    process: 'renderer' | 'main' | 'worker'; |    process: 'renderer' | 'main' | 'worker'; | ||||||
|    message: string; |    message: string; | ||||||
|    date: Date; |    date: Date; | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
| import { uidGen } from 'common/libs/uidGen'; | import { uidGen } from 'common/libs/uidGen'; | ||||||
| import { defineStore } from 'pinia'; | import { defineStore } from 'pinia'; | ||||||
|  |  | ||||||
|  | import { useConsoleStore } from './console'; | ||||||
|  |  | ||||||
| export interface Notification { | export interface Notification { | ||||||
|    uid: string; |    uid: string; | ||||||
|    status: string; |    status: string; | ||||||
| @@ -15,6 +17,13 @@ export const useNotificationsStore = defineStore('notifications', { | |||||||
|       addNotification (payload: { status: string; message: string }) { |       addNotification (payload: { status: string; message: string }) { | ||||||
|          const notification: Notification = { uid: uidGen('N'), ...payload }; |          const notification: Notification = { uid: uidGen('N'), ...payload }; | ||||||
|          this.notifications.unshift(notification); |          this.notifications.unshift(notification); | ||||||
|  |  | ||||||
|  |          useConsoleStore().putLog('debug', { | ||||||
|  |             level: notification.status, | ||||||
|  |             process: 'renderer', | ||||||
|  |             message: notification.message, | ||||||
|  |             date: new Date() | ||||||
|  |          }); | ||||||
|       }, |       }, | ||||||
|       removeNotification (uid: string) { |       removeNotification (uid: string) { | ||||||
|          this.notifications = (this.notifications as Notification[]).filter(item => item.uid !== uid); |          this.notifications = (this.notifications as Notification[]).filter(item => item.uid !== uid); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user