mirror of https://github.com/Fabio286/antares.git
feat: index management
This commit is contained in:
parent
8ebc3bce92
commit
41505bde65
14
package.json
14
package.json
|
@ -4,7 +4,7 @@
|
||||||
"version": "0.0.9",
|
"version": "0.0.9",
|
||||||
"description": "A cross-platform easy to use SQL client.",
|
"description": "A cross-platform easy to use SQL client.",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "https://github.com/EStarium/antares.git",
|
"repository": "https://github.com/Fabio286/antares.git",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "cross-env NODE_ENV=development electron-webpack dev",
|
"dev": "cross-env NODE_ENV=development electron-webpack dev",
|
||||||
"compile": "electron-webpack",
|
"compile": "electron-webpack",
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
},
|
},
|
||||||
"author": "Fabio Di Stasio <fabio286@gmail.com>",
|
"author": "Fabio Di Stasio <fabio286@gmail.com>",
|
||||||
"build": {
|
"build": {
|
||||||
"appId": "com.estarium.antares",
|
"appId": "com.fabio286.antares",
|
||||||
"artifactName": "${productName}-${version}-${os}_${arch}.${ext}",
|
"artifactName": "${productName}-${version}-${os}_${arch}.${ext}",
|
||||||
"dmg": {
|
"dmg": {
|
||||||
"contents": [
|
"contents": [
|
||||||
|
@ -58,10 +58,10 @@
|
||||||
"pg": "^8.5.1",
|
"pg": "^8.5.1",
|
||||||
"source-map-support": "^0.5.16",
|
"source-map-support": "^0.5.16",
|
||||||
"spectre.css": "^0.5.9",
|
"spectre.css": "^0.5.9",
|
||||||
"vue-i18n": "^8.22.1",
|
"vue-i18n": "^8.22.2",
|
||||||
"vue-the-mask": "^0.11.1",
|
"vue-the-mask": "^0.11.1",
|
||||||
"vuedraggable": "^2.24.3",
|
"vuedraggable": "^2.24.3",
|
||||||
"vuex": "^3.5.1",
|
"vuex": "^3.6.0",
|
||||||
"vuex-persist": "^3.1.3"
|
"vuex-persist": "^3.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -72,8 +72,8 @@
|
||||||
"electron-devtools-installer": "^3.1.1",
|
"electron-devtools-installer": "^3.1.1",
|
||||||
"electron-webpack": "^2.8.2",
|
"electron-webpack": "^2.8.2",
|
||||||
"electron-webpack-vue": "^2.4.0",
|
"electron-webpack-vue": "^2.4.0",
|
||||||
"eslint": "^7.13.0",
|
"eslint": "^7.14.0",
|
||||||
"eslint-config-standard": "^16.0.1",
|
"eslint-config-standard": "^16.0.2",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
"eslint-plugin-node": "^11.1.0",
|
"eslint-plugin-node": "^11.1.0",
|
||||||
"eslint-plugin-promise": "^4.2.1",
|
"eslint-plugin-promise": "^4.2.1",
|
||||||
|
@ -82,7 +82,7 @@
|
||||||
"node-sass": "^5.0.0",
|
"node-sass": "^5.0.0",
|
||||||
"sass-loader": "^10.1.0",
|
"sass-loader": "^10.1.0",
|
||||||
"standard-version": "^9.0.0",
|
"standard-version": "^9.0.0",
|
||||||
"stylelint": "^13.7.2",
|
"stylelint": "^13.8.0",
|
||||||
"stylelint-config-standard": "^20.0.0",
|
"stylelint-config-standard": "^20.0.0",
|
||||||
"stylelint-scss": "^3.18.0",
|
"stylelint-scss": "^3.18.0",
|
||||||
"vue": "^2.6.12",
|
"vue": "^2.6.12",
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
module.exports = [
|
||||||
|
'PRIMARY',
|
||||||
|
'INDEX',
|
||||||
|
'UNIQUE',
|
||||||
|
'FULLTEXT'
|
||||||
|
];
|
|
@ -325,9 +325,12 @@ export class MySQLClient extends AntaresCore {
|
||||||
additions,
|
additions,
|
||||||
deletions,
|
deletions,
|
||||||
changes,
|
changes,
|
||||||
|
indexChanges,
|
||||||
options
|
options
|
||||||
} = params;
|
} = params;
|
||||||
|
|
||||||
|
console.log(params);
|
||||||
|
|
||||||
let sql = `ALTER TABLE \`${table}\` `;
|
let sql = `ALTER TABLE \`${table}\` `;
|
||||||
const alterColumns = [];
|
const alterColumns = [];
|
||||||
|
|
||||||
|
@ -337,7 +340,7 @@ export class MySQLClient extends AntaresCore {
|
||||||
if ('autoIncrement' in options) alterColumns.push(`AUTO_INCREMENT=${+options.autoIncrement}`);
|
if ('autoIncrement' in options) alterColumns.push(`AUTO_INCREMENT=${+options.autoIncrement}`);
|
||||||
if ('collation' in options) alterColumns.push(`COLLATE='${options.collation}'`);
|
if ('collation' in options) alterColumns.push(`COLLATE='${options.collation}'`);
|
||||||
|
|
||||||
// ADD
|
// ADD FIELDS
|
||||||
additions.forEach(addition => {
|
additions.forEach(addition => {
|
||||||
const length = addition.numLength || addition.charLength || addition.datePrecision;
|
const length = addition.numLength || addition.charLength || addition.datePrecision;
|
||||||
|
|
||||||
|
@ -354,7 +357,22 @@ export class MySQLClient extends AntaresCore {
|
||||||
${addition.after ? `AFTER \`${addition.after}\`` : 'FIRST'}`);
|
${addition.after ? `AFTER \`${addition.after}\`` : 'FIRST'}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// CHANGE
|
// ADD INDEX
|
||||||
|
indexChanges.additions.forEach(addition => {
|
||||||
|
const fields = addition.fields.map(field => `\`${field}\``).join(',');
|
||||||
|
let type = addition.type;
|
||||||
|
|
||||||
|
if (type === 'PRIMARY')
|
||||||
|
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
|
||||||
|
else {
|
||||||
|
if (type === 'UNIQUE')
|
||||||
|
type = 'UNIQUE INDEX';
|
||||||
|
|
||||||
|
alterColumns.push(`ADD ${type} \`${addition.name}\` (${fields})`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// CHANGE FIELDS
|
||||||
changes.forEach(change => {
|
changes.forEach(change => {
|
||||||
const length = change.numLength || change.charLength || change.datePrecision;
|
const length = change.numLength || change.charLength || change.datePrecision;
|
||||||
|
|
||||||
|
@ -371,11 +389,39 @@ export class MySQLClient extends AntaresCore {
|
||||||
${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`);
|
${change.after ? `AFTER \`${change.after}\`` : 'FIRST'}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
// DROP
|
// CHANGE INDEX
|
||||||
|
indexChanges.changes.forEach(change => {
|
||||||
|
if (change.oldType === 'PRIMARY')
|
||||||
|
alterColumns.push('DROP PRIMARY KEY');
|
||||||
|
else
|
||||||
|
alterColumns.push(`DROP INDEX \`${change.oldName}\``);
|
||||||
|
|
||||||
|
const fields = change.fields.map(field => `\`${field}\``).join(',');
|
||||||
|
let type = change.type;
|
||||||
|
|
||||||
|
if (type === 'PRIMARY')
|
||||||
|
alterColumns.push(`ADD PRIMARY KEY (${fields})`);
|
||||||
|
else {
|
||||||
|
if (type === 'UNIQUE')
|
||||||
|
type = 'UNIQUE INDEX';
|
||||||
|
|
||||||
|
alterColumns.push(`ADD ${type} \`${change.name}\` (${fields})`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// DROP FIELDS
|
||||||
deletions.forEach(deletion => {
|
deletions.forEach(deletion => {
|
||||||
alterColumns.push(`DROP COLUMN \`${deletion.name}\``);
|
alterColumns.push(`DROP COLUMN \`${deletion.name}\``);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// DROP INDEX
|
||||||
|
indexChanges.deletions.forEach(deletion => {
|
||||||
|
if (deletion.type === 'PRIMARY')
|
||||||
|
alterColumns.push('DROP PRIMARY KEY');
|
||||||
|
else
|
||||||
|
alterColumns.push(`DROP INDEX \`${deletion.name}\``);
|
||||||
|
});
|
||||||
|
|
||||||
sql += alterColumns.join(', ');
|
sql += alterColumns.join(', ');
|
||||||
|
|
||||||
// RENAME
|
// RENAME
|
||||||
|
|
|
@ -86,9 +86,8 @@ export default {
|
||||||
|
|
||||||
.context-container {
|
.context-container {
|
||||||
min-width: 100px;
|
min-width: 100px;
|
||||||
max-width: 150px;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
box-shadow: 0 0 1px 0 #000;
|
box-shadow: 0 0 2px 0 #000;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background: #1d1d1d;
|
background: #1d1d1d;
|
||||||
border-radius: 0.1rem;
|
border-radius: 0.1rem;
|
||||||
|
@ -103,9 +102,28 @@ export default {
|
||||||
padding: 0.1rem 0.3rem;
|
padding: 0.1rem 0.3rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.context-submenu {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
position: absolute;
|
||||||
|
left: 100%;
|
||||||
|
top: 0;
|
||||||
|
background: #1d1d1d;
|
||||||
|
box-shadow: 0 0 2px 0 #000;
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $primary-color;
|
background: $primary-color;
|
||||||
|
|
||||||
|
.context-submenu {
|
||||||
|
display: block;
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,11 @@
|
||||||
<div class="context-element">
|
<div class="context-element">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ $t('word.add') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-plus text-light pr-1" /> {{ $t('word.add') }}</span>
|
||||||
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
||||||
|
<div class="context-submenu">
|
||||||
|
<div class="context-element">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-table text-light pr-1" /> {{ $t('word.table') }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="context-element" @click="showEditModal">
|
<div class="context-element" @click="showEditModal">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-pencil text-light pr-1" /> {{ $t('word.edit') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-pencil text-light pr-1" /> {{ $t('word.edit') }}</span>
|
||||||
|
|
|
@ -0,0 +1,263 @@
|
||||||
|
<template>
|
||||||
|
<ConfirmModal
|
||||||
|
:confirm-text="$t('word.confirm')"
|
||||||
|
size="medium"
|
||||||
|
@confirm="confirmIndexesChange"
|
||||||
|
@hide="$emit('hide')"
|
||||||
|
>
|
||||||
|
<template :slot="'header'">
|
||||||
|
<div class="d-flex">
|
||||||
|
<i class="mdi mdi-24px mdi-key mdi-rotate-45 mr-1" /> {{ $t('word.indexes') }} "{{ table }}"
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<div :slot="'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="addIndex">
|
||||||
|
<span>{{ $t('word.add') }}</span>
|
||||||
|
<i class="mdi mdi-24px mdi-key-plus ml-1" />
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn btn-dark btn-sm d-flex ml-2 mr-0"
|
||||||
|
:title="$t('message.clearChanges')"
|
||||||
|
:disabled="!isChanged"
|
||||||
|
@click.prevent="clearChanges"
|
||||||
|
>
|
||||||
|
<span>{{ $t('word.clear') }}</span>
|
||||||
|
<i class="mdi mdi-24px mdi-delete-sweep ml-1" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div ref="indexesPanel" class="panel-body p-0 pr-1">
|
||||||
|
<div
|
||||||
|
v-for="index in indexesProxy"
|
||||||
|
:key="index._id"
|
||||||
|
class="tile tile-centered c-hand mb-1 p-1"
|
||||||
|
:class="{'selected-index': selectedIndexID === index._id}"
|
||||||
|
@click="selectIndex($event, index._id)"
|
||||||
|
>
|
||||||
|
<div class="tile-icon">
|
||||||
|
<div>
|
||||||
|
<i class="mdi mdi-key mdi-24px column-key" :class="`key-${index.type}`" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="tile-content">
|
||||||
|
<div class="tile-title">
|
||||||
|
{{ index.name }}
|
||||||
|
</div>
|
||||||
|
<small class="tile-subtitle text-gray">{{ index.type }} · {{ index.fields.length }} {{ $tc('word.field', index.fields.length) }}</small>
|
||||||
|
</div>
|
||||||
|
<div class="tile-action">
|
||||||
|
<button
|
||||||
|
class="btn btn-link remove-field p-0 mr-2"
|
||||||
|
:title="$t('word.delete')"
|
||||||
|
@click.prevent="removeIndex(index._id)"
|
||||||
|
>
|
||||||
|
<i class="mdi mdi-close" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="column col-7 pl-2 editor-col">
|
||||||
|
<form v-if="selectedIndexObj" :style="{ height: modalInnerHeight + 'px'}">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
{{ $t('word.name') }}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
v-model="selectedIndexObj.name"
|
||||||
|
class="form-input"
|
||||||
|
type="text"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
{{ $t('word.type') }}
|
||||||
|
</label>
|
||||||
|
<select v-model="selectedIndexObj.type" class="form-select">
|
||||||
|
<option
|
||||||
|
v-for="index in indexTypes"
|
||||||
|
:key="index"
|
||||||
|
:value="index"
|
||||||
|
:disabled="index === 'PRIMARY' && hasPrimary"
|
||||||
|
>
|
||||||
|
{{ index }}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="form-label">
|
||||||
|
{{ $tc('word.field', fields.length) }}
|
||||||
|
</label>
|
||||||
|
<div class="fields-list">
|
||||||
|
<label
|
||||||
|
v-for="(field, i) in fields"
|
||||||
|
:key="`${field.name}-${i}`"
|
||||||
|
class="form-checkbox m-0"
|
||||||
|
@click.prevent="toggleField(field.name)"
|
||||||
|
>
|
||||||
|
<input type="checkbox" :checked="selectedIndexObj.fields.some(f => f === field.name)">
|
||||||
|
<i class="form-icon" /> {{ field.name }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ConfirmModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { uidGen } from 'common/libs/uidGen';
|
||||||
|
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'WorkspacePropsIndexesModal',
|
||||||
|
components: {
|
||||||
|
ConfirmModal
|
||||||
|
},
|
||||||
|
props: {
|
||||||
|
localIndexes: Array,
|
||||||
|
table: String,
|
||||||
|
fields: Array,
|
||||||
|
workspace: Object,
|
||||||
|
indexTypes: Array
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
indexesProxy: [],
|
||||||
|
isOptionsChanging: false,
|
||||||
|
selectedIndexID: '',
|
||||||
|
modalInnerHeight: 400
|
||||||
|
};
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
selectedIndexObj () {
|
||||||
|
return this.indexesProxy.find(index => index._id === this.selectedIndexID);
|
||||||
|
},
|
||||||
|
isChanged () {
|
||||||
|
return JSON.stringify(this.localIndexes) !== JSON.stringify(this.indexesProxy);
|
||||||
|
},
|
||||||
|
hasPrimary () {
|
||||||
|
return this.indexesProxy.some(index => index.type === 'PRIMARY');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
this.indexesProxy = JSON.parse(JSON.stringify(this.localIndexes));
|
||||||
|
|
||||||
|
if (this.indexesProxy.length)
|
||||||
|
this.resetSelectedID();
|
||||||
|
|
||||||
|
this.getModalInnerHeight();
|
||||||
|
window.addEventListener('resize', this.getModalInnerHeight);
|
||||||
|
},
|
||||||
|
destroyed () {
|
||||||
|
window.removeEventListener('resize', this.getModalInnerHeight);
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
confirmIndexesChange () {
|
||||||
|
this.$emit('indexes-update', this.indexesProxy);
|
||||||
|
},
|
||||||
|
selectIndex (event, id) {
|
||||||
|
if (this.selectedIndexID !== id && !event.target.classList.contains('remove-field'))
|
||||||
|
this.selectedIndexID = id;
|
||||||
|
},
|
||||||
|
getModalInnerHeight () {
|
||||||
|
const modalBody = document.querySelector('.modal-body');
|
||||||
|
if (modalBody)
|
||||||
|
this.modalInnerHeight = modalBody.clientHeight - (parseFloat(getComputedStyle(modalBody).paddingTop) + parseFloat(getComputedStyle(modalBody).paddingBottom));
|
||||||
|
},
|
||||||
|
addIndex () {
|
||||||
|
this.indexesProxy = [...this.indexesProxy, {
|
||||||
|
_id: uidGen(),
|
||||||
|
name: 'NEW_INDEX',
|
||||||
|
fields: [],
|
||||||
|
type: 'INDEX',
|
||||||
|
comment: '',
|
||||||
|
indexType: 'BTREE',
|
||||||
|
indexComment: '',
|
||||||
|
cardinality: 0
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (this.indexesProxy.length === 1)
|
||||||
|
this.resetSelectedID();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
this.$refs.indexesPanel.scrollTop = this.$refs.indexesPanel.scrollHeight + 60;
|
||||||
|
}, 20);
|
||||||
|
},
|
||||||
|
removeIndex (id) {
|
||||||
|
this.indexesProxy = this.indexesProxy.filter(index => index._id !== id);
|
||||||
|
|
||||||
|
if (this.selectedIndexID === id && this.indexesProxy.length)
|
||||||
|
this.resetSelectedID();
|
||||||
|
},
|
||||||
|
clearChanges () {
|
||||||
|
this.indexesProxy = JSON.parse(JSON.stringify(this.localIndexes));
|
||||||
|
if (!this.indexesProxy.some(index => index._id === this.selectedIndexID))
|
||||||
|
this.resetSelectedID();
|
||||||
|
},
|
||||||
|
toggleField (field) {
|
||||||
|
this.indexesProxy = this.indexesProxy.map(index => {
|
||||||
|
if (index._id === this.selectedIndexID) {
|
||||||
|
if (index.fields.includes(field))
|
||||||
|
index.fields = index.fields.filter(f => f !== field);
|
||||||
|
else
|
||||||
|
index.fields.push(field);
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
resetSelectedID () {
|
||||||
|
this.selectedIndexID = this.indexesProxy[0]._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.tile {
|
||||||
|
border-radius: 2px;
|
||||||
|
opacity: 0.5;
|
||||||
|
transition: background 0.2s;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
|
||||||
|
.tile-action {
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $bg-color-light;
|
||||||
|
|
||||||
|
.tile-action {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected-index {
|
||||||
|
background: $bg-color-light;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-col {
|
||||||
|
border-left: 2px solid $bg-color-light;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fields-list {
|
||||||
|
max-height: 200px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remove-field .mdi {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -96,7 +96,6 @@ export default {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
localOptions: Object,
|
localOptions: Object,
|
||||||
tableOptions: Object,
|
|
||||||
table: String,
|
table: String,
|
||||||
workspace: Object
|
workspace: Object
|
||||||
},
|
},
|
||||||
|
|
|
@ -32,7 +32,11 @@
|
||||||
<span>{{ $t('word.add') }}</span>
|
<span>{{ $t('word.add') }}</span>
|
||||||
<i class="mdi mdi-24px mdi-playlist-plus ml-1" />
|
<i class="mdi mdi-24px mdi-playlist-plus ml-1" />
|
||||||
</button>
|
</button>
|
||||||
<button class="btn btn-dark btn-sm" :title="$t('message.manageIndexes')">
|
<button
|
||||||
|
class="btn btn-dark btn-sm"
|
||||||
|
:title="$t('message.manageIndexes')"
|
||||||
|
@click="showIntdexesModal"
|
||||||
|
>
|
||||||
<span>{{ $t('word.indexes') }}</span>
|
<span>{{ $t('word.indexes') }}</span>
|
||||||
<i class="mdi mdi-24px mdi-key mdi-rotate-45 ml-1" />
|
<i class="mdi mdi-24px mdi-key mdi-rotate-45 ml-1" />
|
||||||
</button>
|
</button>
|
||||||
|
@ -50,26 +54,38 @@
|
||||||
<div class="workspace-query-results column col-12">
|
<div class="workspace-query-results column col-12">
|
||||||
<WorkspacePropsTable
|
<WorkspacePropsTable
|
||||||
v-if="localFields"
|
v-if="localFields"
|
||||||
ref="queryTable"
|
ref="indexTable"
|
||||||
:fields="localFields"
|
:fields="localFields"
|
||||||
:indexes="localIndexes"
|
:indexes="localIndexes"
|
||||||
:tab-uid="tabUid"
|
:tab-uid="tabUid"
|
||||||
:conn-uid="connection.uid"
|
:conn-uid="connection.uid"
|
||||||
|
:index-types="workspace.indexTypes"
|
||||||
:table="table"
|
:table="table"
|
||||||
:schema="schema"
|
:schema="schema"
|
||||||
mode="table"
|
mode="table"
|
||||||
@remove-field="removeField"
|
@remove-field="removeField"
|
||||||
|
@add-new-index="addNewIndex"
|
||||||
|
@add-to-index="addToIndex"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<WorkspacePropsOptionsModal
|
<WorkspacePropsOptionsModal
|
||||||
v-if="isOptionsModal"
|
v-if="isOptionsModal"
|
||||||
:local-options="localOptions"
|
:local-options="localOptions"
|
||||||
:table-options="tableOptions"
|
|
||||||
:table="table"
|
:table="table"
|
||||||
:workspace="workspace"
|
:workspace="workspace"
|
||||||
@hide="hideOptionsModal"
|
@hide="hideOptionsModal"
|
||||||
@options-update="optionsUpdate"
|
@options-update="optionsUpdate"
|
||||||
/>
|
/>
|
||||||
|
<WorkspacePropsIndexesModal
|
||||||
|
v-if="isIndexesModal"
|
||||||
|
:local-indexes="localIndexes"
|
||||||
|
:table="table"
|
||||||
|
:fields="localFields"
|
||||||
|
:index-types="workspace.indexTypes"
|
||||||
|
:workspace="workspace"
|
||||||
|
@hide="hideIndexesModal"
|
||||||
|
@indexes-update="indexesUpdate"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -79,12 +95,14 @@ import { uidGen } from 'common/libs/uidGen';
|
||||||
import Tables from '@/ipc-api/Tables';
|
import Tables from '@/ipc-api/Tables';
|
||||||
import WorkspacePropsTable from '@/components/WorkspacePropsTable';
|
import WorkspacePropsTable from '@/components/WorkspacePropsTable';
|
||||||
import WorkspacePropsOptionsModal from '@/components/WorkspacePropsOptionsModal';
|
import WorkspacePropsOptionsModal from '@/components/WorkspacePropsOptionsModal';
|
||||||
|
import WorkspacePropsIndexesModal from '@/components/WorkspacePropsIndexesModal';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'WorkspacePropsTab',
|
name: 'WorkspacePropsTab',
|
||||||
components: {
|
components: {
|
||||||
WorkspacePropsTable,
|
WorkspacePropsTable,
|
||||||
WorkspacePropsOptionsModal
|
WorkspacePropsOptionsModal,
|
||||||
|
WorkspacePropsIndexesModal
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
connection: Object,
|
connection: Object,
|
||||||
|
@ -95,8 +113,8 @@ export default {
|
||||||
tabUid: 'prop',
|
tabUid: 'prop',
|
||||||
isQuering: false,
|
isQuering: false,
|
||||||
isSaving: false,
|
isSaving: false,
|
||||||
isAddModal: false,
|
|
||||||
isOptionsModal: false,
|
isOptionsModal: false,
|
||||||
|
isIndexesModal: false,
|
||||||
isOptionsChanging: false,
|
isOptionsChanging: false,
|
||||||
originalFields: [],
|
originalFields: [],
|
||||||
localFields: [],
|
localFields: [],
|
||||||
|
@ -105,7 +123,8 @@ export default {
|
||||||
originalIndexes: [],
|
originalIndexes: [],
|
||||||
localIndexes: [],
|
localIndexes: [],
|
||||||
localOptions: {},
|
localOptions: {},
|
||||||
lastTable: null
|
lastTable: null,
|
||||||
|
newFieldsCounter: 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -132,6 +151,7 @@ export default {
|
||||||
isChanged () {
|
isChanged () {
|
||||||
return JSON.stringify(this.originalFields) !== JSON.stringify(this.localFields) ||
|
return JSON.stringify(this.originalFields) !== JSON.stringify(this.localFields) ||
|
||||||
JSON.stringify(this.originalKeyUsage) !== JSON.stringify(this.localKeyUsage) ||
|
JSON.stringify(this.originalKeyUsage) !== JSON.stringify(this.localKeyUsage) ||
|
||||||
|
JSON.stringify(this.originalIndexes) !== JSON.stringify(this.localIndexes) ||
|
||||||
JSON.stringify(this.tableOptions) !== JSON.stringify(this.localOptions);
|
JSON.stringify(this.tableOptions) !== JSON.stringify(this.localOptions);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -156,6 +176,7 @@ export default {
|
||||||
}),
|
}),
|
||||||
async getFieldsData () {
|
async getFieldsData () {
|
||||||
if (!this.table) return;
|
if (!this.table) return;
|
||||||
|
this.newFieldsCounter = 0;
|
||||||
this.isQuering = true;
|
this.isQuering = true;
|
||||||
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
||||||
|
|
||||||
|
@ -184,8 +205,26 @@ export default {
|
||||||
const { status, response } = await Tables.getTableIndexes(params);
|
const { status, response } = await Tables.getTableIndexes(params);
|
||||||
|
|
||||||
if (status === 'success') {
|
if (status === 'success') {
|
||||||
this.originalIndexes = response;
|
const indexesObj = response.reduce((acc, curr) => {
|
||||||
this.localIndexes = JSON.parse(JSON.stringify(response));
|
acc[curr.name] = acc[curr.name] || [];
|
||||||
|
acc[curr.name].push(curr);
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
this.originalIndexes = Object.keys(indexesObj).map(index => {
|
||||||
|
return {
|
||||||
|
_id: uidGen(),
|
||||||
|
name: index,
|
||||||
|
fields: indexesObj[index].map(field => field.column),
|
||||||
|
type: indexesObj[index][0].type,
|
||||||
|
comment: indexesObj[index][0].comment,
|
||||||
|
indexType: indexesObj[index][0].indexType,
|
||||||
|
indexComment: indexesObj[index][0].indexComment,
|
||||||
|
cardinality: indexesObj[index][0].cardinality
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
this.localIndexes = JSON.parse(JSON.stringify(this.originalIndexes));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
this.addNotification({ status: 'error', message: response });
|
this.addNotification({ status: 'error', message: response });
|
||||||
|
@ -214,20 +253,21 @@ export default {
|
||||||
if (this.isSaving) return;
|
if (this.isSaving) return;
|
||||||
this.isSaving = true;
|
this.isSaving = true;
|
||||||
|
|
||||||
|
// FIELDS
|
||||||
const originalIDs = this.originalFields.reduce((acc, curr) => [...acc, curr._id], []);
|
const originalIDs = this.originalFields.reduce((acc, curr) => [...acc, curr._id], []);
|
||||||
const localIDs = this.localFields.reduce((acc, curr) => [...acc, curr._id], []);
|
const localIDs = this.localFields.reduce((acc, curr) => [...acc, curr._id], []);
|
||||||
|
|
||||||
// Additions
|
// Fields Additions
|
||||||
const additions = this.localFields.filter((field, i) => !originalIDs.includes(field._id)).map(field => {
|
const additions = this.localFields.filter((field, i) => !originalIDs.includes(field._id)).map(field => {
|
||||||
const lI = this.localFields.findIndex(localField => localField._id === field._id);
|
const lI = this.localFields.findIndex(localField => localField._id === field._id);
|
||||||
const after = lI > 0 ? this.localFields[lI - 1].name : false;
|
const after = lI > 0 ? this.localFields[lI - 1].name : false;
|
||||||
return { ...field, after };
|
return { ...field, after };
|
||||||
});
|
});
|
||||||
|
|
||||||
// Deletions
|
// Fields Deletions
|
||||||
const deletions = this.originalFields.filter(field => !localIDs.includes(field._id));
|
const deletions = this.originalFields.filter(field => !localIDs.includes(field._id));
|
||||||
|
|
||||||
// Changes
|
// Fields Changes
|
||||||
const changes = [];
|
const changes = [];
|
||||||
this.originalFields.forEach((originalField, oI) => {
|
this.originalFields.forEach((originalField, oI) => {
|
||||||
const lI = this.localFields.findIndex(localField => localField._id === originalField._id);
|
const lI = this.localFields.findIndex(localField => localField._id === originalField._id);
|
||||||
|
@ -247,6 +287,33 @@ export default {
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
// INDEXES
|
||||||
|
const indexChanges = {
|
||||||
|
additions: [],
|
||||||
|
changes: [],
|
||||||
|
deletions: []
|
||||||
|
};
|
||||||
|
const originalIndexIDs = this.originalIndexes.reduce((acc, curr) => [...acc, curr._id], []);
|
||||||
|
const localIndexIDs = this.localIndexes.reduce((acc, curr) => [...acc, curr._id], []);
|
||||||
|
|
||||||
|
// Index Additions
|
||||||
|
indexChanges.additions = this.localIndexes.filter(index => !originalIndexIDs.includes(index._id));
|
||||||
|
|
||||||
|
// Index Changes
|
||||||
|
this.originalIndexes.forEach(originalIndex => {
|
||||||
|
const lI = this.localIndexes.findIndex(localIndex => localIndex._id === originalIndex._id);
|
||||||
|
if (JSON.stringify(originalIndex) !== JSON.stringify(this.localIndexes[lI])) {
|
||||||
|
indexChanges.changes.push({
|
||||||
|
...this.localIndexes[lI],
|
||||||
|
oldName: originalIndex.name,
|
||||||
|
oldType: originalIndex.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Index Deletions
|
||||||
|
indexChanges.deletions = this.originalIndexes.filter(index => !localIndexIDs.includes(index._id));
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
uid: this.connection.uid,
|
uid: this.connection.uid,
|
||||||
schema: this.schema,
|
schema: this.schema,
|
||||||
|
@ -254,6 +321,7 @@ export default {
|
||||||
additions,
|
additions,
|
||||||
changes,
|
changes,
|
||||||
deletions,
|
deletions,
|
||||||
|
indexChanges,
|
||||||
options
|
options
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -272,16 +340,19 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isSaving = false;
|
this.isSaving = false;
|
||||||
|
this.newFieldsCounter = 0;
|
||||||
},
|
},
|
||||||
clearChanges () {
|
clearChanges () {
|
||||||
this.localFields = JSON.parse(JSON.stringify(this.originalFields));
|
this.localFields = JSON.parse(JSON.stringify(this.originalFields));
|
||||||
|
this.localIndexes = JSON.parse(JSON.stringify(this.originalIndexes));
|
||||||
this.localKeyUsage = JSON.parse(JSON.stringify(this.originalKeyUsage));
|
this.localKeyUsage = JSON.parse(JSON.stringify(this.originalKeyUsage));
|
||||||
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
this.localOptions = JSON.parse(JSON.stringify(this.tableOptions));
|
||||||
|
this.newFieldsCounter = 0;
|
||||||
},
|
},
|
||||||
addField () {
|
addField () {
|
||||||
this.localFields.push({
|
this.localFields.push({
|
||||||
_id: uidGen(),
|
_id: uidGen(),
|
||||||
name: '',
|
name: `${this.$tc('word.field', 1)}_${++this.newFieldsCounter}`,
|
||||||
key: '',
|
key: '',
|
||||||
type: 'int',
|
type: 'int',
|
||||||
schema: this.schema,
|
schema: this.schema,
|
||||||
|
@ -301,10 +372,33 @@ export default {
|
||||||
onUpdate: '',
|
onUpdate: '',
|
||||||
comment: ''
|
comment: ''
|
||||||
});
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
const scrollable = this.$refs.indexTable.$refs.tableWrapper;
|
||||||
|
scrollable.scrollTop = scrollable.scrollHeight + 30;
|
||||||
|
}, 20);
|
||||||
},
|
},
|
||||||
removeField (uid) {
|
removeField (uid) {
|
||||||
this.localFields = this.localFields.filter(field => field._id !== uid);
|
this.localFields = this.localFields.filter(field => field._id !== uid);
|
||||||
},
|
},
|
||||||
|
addNewIndex (payload) {
|
||||||
|
this.localIndexes = [...this.localIndexes, {
|
||||||
|
_id: uidGen(),
|
||||||
|
name: payload.index === 'PRIMARY' ? 'PRIMARY' : payload.field,
|
||||||
|
fields: [payload.field],
|
||||||
|
type: payload.index,
|
||||||
|
comment: '',
|
||||||
|
indexType: 'BTREE',
|
||||||
|
indexComment: '',
|
||||||
|
cardinality: 0
|
||||||
|
}];
|
||||||
|
},
|
||||||
|
addToIndex (payload) {
|
||||||
|
this.localIndexes = this.localIndexes.map(index => {
|
||||||
|
if (index._id === payload.index) index.fields.push(payload.field);
|
||||||
|
return index;
|
||||||
|
});
|
||||||
|
},
|
||||||
showOptionsModal () {
|
showOptionsModal () {
|
||||||
this.isOptionsModal = true;
|
this.isOptionsModal = true;
|
||||||
},
|
},
|
||||||
|
@ -313,6 +407,15 @@ export default {
|
||||||
},
|
},
|
||||||
optionsUpdate (options) {
|
optionsUpdate (options) {
|
||||||
this.localOptions = options;
|
this.localOptions = options;
|
||||||
|
},
|
||||||
|
showIntdexesModal () {
|
||||||
|
this.isIndexesModal = true;
|
||||||
|
},
|
||||||
|
hideIndexesModal () {
|
||||||
|
this.isIndexesModal = false;
|
||||||
|
},
|
||||||
|
indexesUpdate (indexes) {
|
||||||
|
this.localIndexes = indexes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,12 @@
|
||||||
v-if="isContext"
|
v-if="isContext"
|
||||||
:context-event="contextEvent"
|
:context-event="contextEvent"
|
||||||
:selected-field="selectedField"
|
:selected-field="selectedField"
|
||||||
|
:index-types="indexTypes"
|
||||||
|
:indexes="indexes"
|
||||||
@delete-selected="removeField"
|
@delete-selected="removeField"
|
||||||
@close-context="isContext = false"
|
@close-context="isContext = false"
|
||||||
|
@add-new-index="$emit('add-new-index', $event)"
|
||||||
|
@add-to-index="$emit('add-to-index', $event)"
|
||||||
/>
|
/>
|
||||||
<div ref="propTable" class="table table-hover">
|
<div ref="propTable" class="table table-hover">
|
||||||
<div class="thead">
|
<div class="thead">
|
||||||
|
@ -124,6 +128,7 @@ export default {
|
||||||
props: {
|
props: {
|
||||||
fields: Array,
|
fields: Array,
|
||||||
indexes: Array,
|
indexes: Array,
|
||||||
|
indexTypes: Array,
|
||||||
tabUid: [String, Number],
|
tabUid: [String, Number],
|
||||||
connUid: String,
|
connUid: String,
|
||||||
table: String,
|
table: String,
|
||||||
|
@ -133,7 +138,6 @@ export default {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
resultsSize: 1000,
|
resultsSize: 1000,
|
||||||
localResults: [],
|
|
||||||
isContext: false,
|
isContext: false,
|
||||||
contextEvent: null,
|
contextEvent: null,
|
||||||
selectedField: null,
|
selectedField: null,
|
||||||
|
@ -156,6 +160,14 @@ export default {
|
||||||
},
|
},
|
||||||
tabProperties () {
|
tabProperties () {
|
||||||
return this.getWorkspaceTab(this.tabUid);
|
return this.getWorkspaceTab(this.tabUid);
|
||||||
|
},
|
||||||
|
fieldsLength () {
|
||||||
|
return this.fields.length;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
fieldsLength () {
|
||||||
|
this.refreshScroller();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updated () {
|
updated () {
|
||||||
|
@ -184,22 +196,24 @@ export default {
|
||||||
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
const size = window.innerHeight - el.getBoundingClientRect().top - footer.offsetHeight;
|
||||||
this.resultsSize = size;
|
this.resultsSize = size;
|
||||||
}
|
}
|
||||||
// this.$refs.resultTable.updateWindow();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refreshScroller () {
|
refreshScroller () {
|
||||||
this.resizeResults();
|
this.resizeResults();
|
||||||
},
|
},
|
||||||
contextMenu (event, uid) {
|
contextMenu (event, uid) {
|
||||||
this.selectedField = uid;
|
this.selectedField = this.fields.find(field => field._id === uid);
|
||||||
this.contextEvent = event;
|
this.contextEvent = event;
|
||||||
this.isContext = true;
|
this.isContext = true;
|
||||||
},
|
},
|
||||||
removeField () {
|
removeField () {
|
||||||
this.$emit('remove-field', this.selectedField);
|
this.$emit('remove-field', this.selectedField._id);
|
||||||
},
|
},
|
||||||
getIndexes (field) {
|
getIndexes (field) {
|
||||||
return this.indexes.filter(index => index.column === field);
|
return this.indexes.reduce((acc, curr) => {
|
||||||
|
acc.push(...curr.fields.map(f => ({ name: f, type: curr.type })));
|
||||||
|
return acc;
|
||||||
|
}, []).filter(f => f.name === field);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -213,4 +227,8 @@ export default {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.vscroll {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -3,6 +3,36 @@
|
||||||
:context-event="contextEvent"
|
:context-event="contextEvent"
|
||||||
@close-context="closeContext"
|
@close-context="closeContext"
|
||||||
>
|
>
|
||||||
|
<div class="context-element">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-key-plus text-light pr-1" /> {{ $t('message.createNewIndex') }}</span>
|
||||||
|
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
||||||
|
<div class="context-submenu">
|
||||||
|
<div
|
||||||
|
v-for="index in indexTypes"
|
||||||
|
:key="index"
|
||||||
|
class="context-element"
|
||||||
|
:class="{'disabled': index === 'PRIMARY' && hasPrimary}"
|
||||||
|
@click="addNewIndex(index)"
|
||||||
|
>
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-key column-key pr-1" :class="`key-${index}`" /> {{ index }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="context-element">
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-key-arrow-right text-light pr-1" /> {{ $t('message.addToIndex') }}</span>
|
||||||
|
<i class="mdi mdi-18px mdi-chevron-right text-light pl-1" />
|
||||||
|
<div class="context-submenu">
|
||||||
|
<div
|
||||||
|
v-for="index in indexes"
|
||||||
|
:key="index.name"
|
||||||
|
class="context-element"
|
||||||
|
:class="{'disabled': index.fields.includes(selectedField.name)}"
|
||||||
|
@click="addToIndex(index._id)"
|
||||||
|
>
|
||||||
|
<span class="d-flex"><i class="mdi mdi-18px mdi-key column-key pr-1" :class="`key-${index.type}`" /> {{ index.name }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="context-element" @click="deleteField">
|
<div class="context-element" @click="deleteField">
|
||||||
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('message.deleteField') }}</span>
|
<span class="d-flex"><i class="mdi mdi-18px mdi-delete text-light pr-1" /> {{ $t('message.deleteField') }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,14 +49,14 @@ export default {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
contextEvent: MouseEvent,
|
contextEvent: MouseEvent,
|
||||||
selectedField: String
|
indexes: Array,
|
||||||
},
|
indexTypes: Array,
|
||||||
data () {
|
selectedField: Object
|
||||||
return {
|
|
||||||
isConfirmModal: false
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
hasPrimary () {
|
||||||
|
return this.indexes.some(index => index.type === 'PRIMARY');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeContext () {
|
closeContext () {
|
||||||
|
@ -35,7 +65,23 @@ export default {
|
||||||
deleteField () {
|
deleteField () {
|
||||||
this.$emit('delete-selected');
|
this.$emit('delete-selected');
|
||||||
this.closeContext();
|
this.closeContext();
|
||||||
|
},
|
||||||
|
addNewIndex (index) {
|
||||||
|
this.$emit('add-new-index', { field: this.selectedField.name, index });
|
||||||
|
this.closeContext();
|
||||||
|
},
|
||||||
|
addToIndex (index) {
|
||||||
|
this.$emit('add-to-index', { field: this.selectedField.name, index });
|
||||||
|
this.closeContext();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
filter: grayscale(100%);
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
<div class="td" tabindex="0">
|
<div class="td" tabindex="0">
|
||||||
<div class="text-center">
|
<div class="text-center">
|
||||||
<i
|
<i
|
||||||
v-for="index in indexes"
|
v-for="(index, i) in indexes"
|
||||||
:key="index.name"
|
:key="`${index.name}-${i}`"
|
||||||
:title="index.type"
|
:title="index.type"
|
||||||
class="d-inline-block mdi mdi-key column-key c-help"
|
class="d-inline-block mdi mdi-key column-key c-help"
|
||||||
:class="`key-${index.type}`"
|
:class="`key-${index.type}`"
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
<div v-if="results.length && results[0].rows">
|
<div v-if="results.length && results[0].rows">
|
||||||
{{ $t('word.results') }}: <b>{{ results[0].rows.length.toLocaleString() }}</b>
|
{{ $t('word.results') }}: <b>{{ results[0].rows.length.toLocaleString() }}</b>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="results.length && results[0].rows && results[0].rows.length < tableInfo.rows">
|
<div v-if="results.length && results[0].rows && tableInfo && results[0].rows.length < tableInfo.rows">
|
||||||
{{ $t('word.total') }}: <b>{{ tableInfo.rows.toLocaleString() }}</b> <small>({{ $t('word.approximately') }})</small>
|
{{ $t('word.total') }}: <b>{{ tableInfo.rows.toLocaleString() }}</b> <small>({{ $t('word.approximately') }})</small>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="workspace.breadcrumbs.database">
|
<div v-if="workspace.breadcrumbs.database">
|
||||||
|
|
|
@ -58,7 +58,8 @@ module.exports = {
|
||||||
engine: 'Engine',
|
engine: 'Engine',
|
||||||
field: 'Field | Fields',
|
field: 'Field | Fields',
|
||||||
approximately: 'Approximately',
|
approximately: 'Approximately',
|
||||||
total: 'Total'
|
total: 'Total',
|
||||||
|
table: 'Table'
|
||||||
},
|
},
|
||||||
message: {
|
message: {
|
||||||
appWelcome: 'Welcome to Antares SQL Client!',
|
appWelcome: 'Welcome to Antares SQL Client!',
|
||||||
|
|
|
@ -41,12 +41,13 @@ export default {
|
||||||
SELECT_WORKSPACE (state, uid) {
|
SELECT_WORKSPACE (state, uid) {
|
||||||
state.selected_workspace = uid;
|
state.selected_workspace = uid;
|
||||||
},
|
},
|
||||||
ADD_CONNECTED (state, { uid, client, dataTypes, structure }) {
|
ADD_CONNECTED (state, { uid, client, dataTypes, indexTypes, structure }) {
|
||||||
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid
|
state.workspaces = state.workspaces.map(workspace => workspace.uid === uid
|
||||||
? {
|
? {
|
||||||
...workspace,
|
...workspace,
|
||||||
client,
|
client,
|
||||||
dataTypes,
|
dataTypes,
|
||||||
|
indexTypes,
|
||||||
structure,
|
structure,
|
||||||
connected: true
|
connected: true
|
||||||
}
|
}
|
||||||
|
@ -187,17 +188,20 @@ export default {
|
||||||
dispatch('notifications/addNotification', { status, message: response }, { root: true });
|
dispatch('notifications/addNotification', { status, message: response }, { root: true });
|
||||||
else {
|
else {
|
||||||
let dataTypes = [];
|
let dataTypes = [];
|
||||||
|
let indexTypes = [];
|
||||||
|
|
||||||
switch (connection.client) {
|
switch (connection.client) {
|
||||||
case 'mysql':
|
case 'mysql':
|
||||||
case 'maria':
|
case 'maria':
|
||||||
dataTypes = require('common/data-types/mysql');
|
dataTypes = require('common/data-types/mysql');
|
||||||
|
indexTypes = require('common/index-types/mysql');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
commit('ADD_CONNECTED', {
|
commit('ADD_CONNECTED', {
|
||||||
uid: connection.uid,
|
uid: connection.uid,
|
||||||
client: connection.client,
|
client: connection.client,
|
||||||
dataTypes,
|
dataTypes,
|
||||||
|
indexTypes,
|
||||||
structure: response
|
structure: response
|
||||||
});
|
});
|
||||||
dispatch('refreshCollations', connection.uid);
|
dispatch('refreshCollations', connection.uid);
|
||||||
|
|
Loading…
Reference in New Issue