mirror of
https://github.com/Fabio286/antares.git
synced 2025-06-05 21:59:22 +02:00
refactor: improvements to blob editor and code cleanup
This commit is contained in:
@ -29,13 +29,13 @@
|
||||
class="btn btn-primary mr-2"
|
||||
@click="confirmModal"
|
||||
>
|
||||
{{ $t('word.confirm') }}
|
||||
{{ confirmText || $t('word.confirm') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn btn-link"
|
||||
@click="hideModal"
|
||||
>
|
||||
{{ $t('word.cancel') }}
|
||||
{{ cancelText || $t('word.cancel') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -48,8 +48,11 @@ export default {
|
||||
props: {
|
||||
size: {
|
||||
type: String,
|
||||
default: 'small' // small, medium, large
|
||||
}
|
||||
validator: prop => ['small', 'medium', 'large'].includes(prop),
|
||||
default: 'small'
|
||||
},
|
||||
confirmText: String,
|
||||
cancelText: String
|
||||
},
|
||||
computed: {
|
||||
hasHeader () {
|
||||
|
@ -148,7 +148,7 @@
|
||||
<script>
|
||||
import { mapActions } from 'vuex';
|
||||
import Connection from '@/ipc-api/Connection';
|
||||
import { uidGen } from 'common/libs/utilities';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import ModalAskCredentials from '@/components/ModalAskCredentials';
|
||||
import BaseToast from '@/components/BaseToast';
|
||||
|
||||
|
@ -143,6 +143,9 @@ export default {
|
||||
}
|
||||
|
||||
this.isQuering = false;
|
||||
},
|
||||
reloadTable () {
|
||||
this.runQuery();// TODO: run last executed query
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -66,7 +66,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { uidGen } from 'common/libs/utilities';
|
||||
import { uidGen } from 'common/libs/uidGen';
|
||||
import BaseVirtualScroll from '@/components/BaseVirtualScroll';
|
||||
import WorkspaceQueryTableCell from '@/components/WorkspaceQueryTableCell';
|
||||
import TableContext from '@/components/WorkspaceQueryTableContext';
|
||||
|
@ -35,6 +35,7 @@
|
||||
</template>
|
||||
<ConfirmModal
|
||||
v-if="isTextareaEditor"
|
||||
:confirm-text="$t('word.update')"
|
||||
size="medium"
|
||||
@confirm="editOFF"
|
||||
@hide="hideEditorModal"
|
||||
@ -59,6 +60,7 @@
|
||||
</ConfirmModal>
|
||||
<ConfirmModal
|
||||
v-if="isBlobEditor"
|
||||
:confirm-text="$t('word.update')"
|
||||
@confirm="editOFF"
|
||||
@hide="hideEditorModal"
|
||||
>
|
||||
@ -67,19 +69,28 @@
|
||||
</template>
|
||||
<div :slot="'body'">
|
||||
<div class="mb-2">
|
||||
<div>
|
||||
<img
|
||||
v-if="isImage"
|
||||
:src="`data:${contentInfo.mime};base64, ${bufferToBase64(localContent)}`"
|
||||
class="img-responsive p-centered"
|
||||
>
|
||||
<div v-if="contentInfo.size" class="editor-buttons mt-2">
|
||||
<button class="btn btn-link btn-sm" @click="downloadFile">
|
||||
<span>{{ $t('word.download') }}</span>
|
||||
<i class="material-icons ml-1">file_download</i>
|
||||
</button>
|
||||
<transition name="jump-down">
|
||||
<div v-if="contentInfo.size">
|
||||
<img
|
||||
v-if="isImage"
|
||||
:src="`data:${contentInfo.mime};base64, ${bufferToBase64(localContent)}`"
|
||||
class="img-responsive p-centered bg-checkered"
|
||||
>
|
||||
<div v-else class="text-center">
|
||||
<i class="material-icons md-36">insert_drive_file</i>
|
||||
</div>
|
||||
<div class="editor-buttons mt-2">
|
||||
<button class="btn btn-link btn-sm" @click="downloadFile">
|
||||
<span>{{ $t('word.download') }}</span>
|
||||
<i class="material-icons ml-1">file_download</i>
|
||||
</button>
|
||||
<button class="btn btn-link btn-sm" @click="prepareToDelete">
|
||||
<span>{{ $t('word.delete') }}</span>
|
||||
<i class="material-icons ml-1">delete_forever</i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</transition>
|
||||
<div class="editor-field-info">
|
||||
<div>
|
||||
<b>{{ $t('word.size') }}</b>: {{ localContent.length | formatBytes }}<br>
|
||||
@ -103,8 +114,11 @@
|
||||
|
||||
<script>
|
||||
import moment from 'moment';
|
||||
import { mimeFromHex, formatBytes, bufferToBase64 } from 'common/libs/utilities';
|
||||
import { mimeFromHex } from 'common/libs/mimeFromHex';
|
||||
import { formatBytes } from 'common/libs/formatBytes';
|
||||
import { bufferToBase64 } from 'common/libs/bufferToBase64';
|
||||
import hexToBinary from 'common/libs/hexToBinary';
|
||||
import { TEXT, LONG_TEXT, NUMBER, DATE, TIME, DATETIME, BLOB, BIT } from 'common/fieldTypes';
|
||||
import { mask } from 'vue-the-mask';
|
||||
import ConfirmModal from '@/components/BaseConfirmModal';
|
||||
|
||||
@ -122,39 +136,31 @@ export default {
|
||||
typeFormat (val, type, precision) {
|
||||
if (!val) return val;
|
||||
|
||||
switch (type) {
|
||||
case 'char':
|
||||
case 'varchar':
|
||||
case 'text':
|
||||
case 'mediumtext':
|
||||
return val;
|
||||
case 'date': {
|
||||
return moment(val).isValid() ? moment(val).format('YYYY-MM-DD') : val;
|
||||
}
|
||||
case 'datetime':
|
||||
case 'timestamp': {
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < precision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
if (DATE.includes(type))
|
||||
return moment(val).isValid() ? moment(val).format('YYYY-MM-DD') : val;
|
||||
|
||||
return moment(val).isValid() ? moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`) : val;
|
||||
}
|
||||
case 'blob':
|
||||
case 'mediumblob':
|
||||
case 'longblob': {
|
||||
const buff = Buffer.from(val);
|
||||
if (!buff.length) return '';
|
||||
if (DATETIME.includes(type)) {
|
||||
let datePrecision = '';
|
||||
for (let i = 0; i < precision; i++)
|
||||
datePrecision += i === 0 ? '.S' : 'S';
|
||||
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`;
|
||||
}
|
||||
case 'bit': {
|
||||
const hex = Buffer.from(val).toString('hex');
|
||||
return hexToBinary(hex);
|
||||
}
|
||||
default:
|
||||
return val;
|
||||
return moment(val).isValid() ? moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`) : val;
|
||||
}
|
||||
|
||||
if (BLOB.includes(type)) {
|
||||
const buff = Buffer.from(val);
|
||||
if (!buff.length) return '';
|
||||
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
return `${mimeFromHex(hex).mime} (${formatBytes(buff.length)})`;
|
||||
}
|
||||
|
||||
if (BIT.includes(type)) {
|
||||
const hex = Buffer.from(val).toString('hex');
|
||||
return hexToBinary(hex);
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
},
|
||||
directives: {
|
||||
@ -171,6 +177,7 @@ export default {
|
||||
isInlineEditor: false,
|
||||
isTextareaEditor: false,
|
||||
isBlobEditor: false,
|
||||
willBeDeleted: false,
|
||||
localContent: null,
|
||||
contentInfo: {
|
||||
ext: '',
|
||||
@ -182,39 +189,35 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
inputProps () {
|
||||
switch (this.type) {
|
||||
case 'char':
|
||||
case 'varchar':
|
||||
case 'text':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
return { type: 'text', mask: false };
|
||||
case 'int':
|
||||
case 'tinyint':
|
||||
case 'smallint':
|
||||
case 'mediumint':
|
||||
case 'bigint':
|
||||
return { type: 'number', mask: false };
|
||||
case 'date':
|
||||
return { type: 'text', mask: '####-##-##' };
|
||||
case 'datetime':
|
||||
case 'timestamp': {
|
||||
let datetimeMask = '####-##-## ##:##:##';
|
||||
for (let i = 0; i < this.precision; i++)
|
||||
datetimeMask += i === 0 ? '.#' : '#';
|
||||
return { type: 'text', mask: datetimeMask };
|
||||
}
|
||||
case 'blob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
case 'bit':
|
||||
return { type: 'file', mask: false };
|
||||
default:
|
||||
return 'hidden';
|
||||
if ([...TEXT, ...LONG_TEXT].includes(this.type))
|
||||
return { type: 'text', mask: false };
|
||||
|
||||
if (NUMBER.includes(this.type))
|
||||
return { type: 'number', mask: false };
|
||||
|
||||
if (TIME.includes(this.type))
|
||||
return { type: 'number', mask: false };
|
||||
|
||||
if (DATE.includes(this.type))
|
||||
return { type: 'text', mask: '####-##-##' };
|
||||
|
||||
if (DATETIME.includes(this.type)) {
|
||||
let datetimeMask = '####-##-## ##:##:##';
|
||||
for (let i = 0; i < this.precision; i++)
|
||||
datetimeMask += i === 0 ? '.#' : '#';
|
||||
return { type: 'text', mask: datetimeMask };
|
||||
}
|
||||
|
||||
if (BLOB.includes(this.type))
|
||||
return { type: 'file', mask: false };
|
||||
|
||||
if (BIT.includes(this.type))
|
||||
return { type: 'text', mask: false };
|
||||
|
||||
return { type: 'text', mask: false };
|
||||
},
|
||||
isImage () {
|
||||
return ['gif', 'jpg', 'png'].includes(this.contentInfo.ext);
|
||||
return ['gif', 'jpg', 'png', 'bmp', 'ico', 'tif'].includes(this.contentInfo.ext);
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@ -225,47 +228,41 @@ export default {
|
||||
return bufferToBase64(val);
|
||||
},
|
||||
editON () {
|
||||
switch (this.type) {
|
||||
// Large text editor
|
||||
case 'text':
|
||||
case 'mediumtext':
|
||||
case 'longtext':
|
||||
this.isTextareaEditor = true;
|
||||
this.localContent = this.$options.filters.typeFormat(this.content, this.type);
|
||||
break;
|
||||
// File fields editor
|
||||
case 'blob':
|
||||
case 'mediumblob':
|
||||
case 'longblob':
|
||||
this.isBlobEditor = true;
|
||||
this.localContent = this.content ? this.content : '';
|
||||
this.fileToUpload = null;
|
||||
|
||||
if (this.content !== null) {
|
||||
const buff = Buffer.from(this.localContent);
|
||||
if (buff.length) {
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
const { ext, mime } = mimeFromHex(hex);
|
||||
this.contentInfo = {
|
||||
ext,
|
||||
mime,
|
||||
size: this.localContent.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
// Inline editable fields
|
||||
default:
|
||||
this.localContent = this.$options.filters.typeFormat(this.content, this.type);
|
||||
this.$nextTick(() => { // Focus on input
|
||||
this.$refs.cell.blur();
|
||||
|
||||
this.$nextTick(() => this.$refs.editField.focus());
|
||||
});
|
||||
this.isInlineEditor = true;
|
||||
break;
|
||||
if (LONG_TEXT.includes(this.type)) {
|
||||
this.isTextareaEditor = true;
|
||||
this.localContent = this.$options.filters.typeFormat(this.content, this.type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (BLOB.includes(this.type)) {
|
||||
this.isBlobEditor = true;
|
||||
this.localContent = this.content ? this.content : '';
|
||||
this.fileToUpload = null;
|
||||
this.willBeDeleted = false;
|
||||
|
||||
if (this.content !== null) {
|
||||
const buff = Buffer.from(this.localContent);
|
||||
if (buff.length) {
|
||||
const hex = buff.toString('hex').substring(0, 8).toUpperCase();
|
||||
const { ext, mime } = mimeFromHex(hex);
|
||||
this.contentInfo = {
|
||||
ext,
|
||||
mime,
|
||||
size: this.localContent.length
|
||||
};
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Inline editable fields
|
||||
this.localContent = this.$options.filters.typeFormat(this.content, this.type);
|
||||
this.$nextTick(() => { // Focus on input
|
||||
this.$refs.cell.blur();
|
||||
|
||||
this.$nextTick(() => this.$refs.editField.focus());
|
||||
});
|
||||
this.isInlineEditor = true;
|
||||
},
|
||||
editOFF () {
|
||||
this.isInlineEditor = false;
|
||||
@ -275,8 +272,14 @@ export default {
|
||||
content = this.localContent;
|
||||
}
|
||||
else { // Handle file upload
|
||||
if (!this.fileToUpload) return;
|
||||
content = this.fileToUpload.file.path;
|
||||
if (this.willBeDeleted) {
|
||||
content = '';
|
||||
this.willBeDeleted = false;
|
||||
}
|
||||
else {
|
||||
if (!this.fileToUpload) return;
|
||||
content = this.fileToUpload.file.path;
|
||||
}
|
||||
}
|
||||
|
||||
this.$emit('updateField', {
|
||||
@ -304,6 +307,16 @@ export default {
|
||||
if (!files.length) return;
|
||||
|
||||
this.fileToUpload = { name: files[0].name, file: files[0] };
|
||||
this.willBeDeleted = false;
|
||||
},
|
||||
prepareToDelete () {
|
||||
this.localContent = '';
|
||||
this.contentInfo = {
|
||||
ext: '',
|
||||
mime: '',
|
||||
size: null
|
||||
};
|
||||
this.willBeDeleted = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -338,7 +351,7 @@ export default {
|
||||
|
||||
.editor-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
justify-content: space-evenly;
|
||||
|
||||
.btn {
|
||||
display: flex;
|
||||
|
@ -6,7 +6,7 @@
|
||||
<button
|
||||
class="btn btn-link btn-sm"
|
||||
:class="{'loading':isQuering}"
|
||||
@click="getTableData"
|
||||
@click="reloadTable"
|
||||
>
|
||||
<span>{{ $t('word.refresh') }}</span>
|
||||
<i class="material-icons ml-1">refresh</i>
|
||||
@ -140,6 +140,9 @@ export default {
|
||||
}
|
||||
|
||||
this.isQuering = false;
|
||||
},
|
||||
reloadTable () {
|
||||
this.getTableData();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user