2020-06-26 18:14:16 +02:00
|
|
|
<template>
|
|
|
|
<div
|
|
|
|
v-if="field !== '_id'"
|
|
|
|
ref="cell"
|
2020-07-30 19:12:29 +02:00
|
|
|
class="td p-0"
|
2020-06-26 18:14:16 +02:00
|
|
|
tabindex="0"
|
2020-07-22 18:30:52 +02:00
|
|
|
@contextmenu.prevent="$emit('contextmenu', $event)"
|
2020-06-26 18:14:16 +02:00
|
|
|
>
|
|
|
|
<span
|
2020-07-30 19:12:29 +02:00
|
|
|
v-if="!isInlineEditor"
|
2020-06-26 18:14:16 +02:00
|
|
|
class="cell-content px-2"
|
2020-07-30 19:12:29 +02:00
|
|
|
:class="`${isNull(content)} type-${type}`"
|
2020-06-26 18:14:16 +02:00
|
|
|
@dblclick="editON"
|
2020-07-22 18:30:52 +02:00
|
|
|
>{{ content | typeFormat(type, precision) | cutText }}</span>
|
2020-07-05 16:06:56 +02:00
|
|
|
<template v-else>
|
|
|
|
<input
|
|
|
|
v-if="inputProps.mask"
|
|
|
|
ref="editField"
|
|
|
|
v-model="localContent"
|
|
|
|
v-mask="inputProps.mask"
|
|
|
|
:type="inputProps.type"
|
|
|
|
autofocus
|
|
|
|
class="editable-field px-2"
|
|
|
|
@blur="editOFF"
|
|
|
|
>
|
|
|
|
<input
|
|
|
|
v-else
|
|
|
|
ref="editField"
|
|
|
|
v-model="localContent"
|
|
|
|
:type="inputProps.type"
|
|
|
|
autofocus
|
|
|
|
class="editable-field px-2"
|
|
|
|
@blur="editOFF"
|
|
|
|
>
|
|
|
|
</template>
|
2020-07-30 19:12:29 +02:00
|
|
|
<ConfirmModal
|
|
|
|
v-if="isTextareaEditor"
|
|
|
|
size="medium"
|
|
|
|
@confirm="editOFF"
|
|
|
|
@hide="hideEditorModal"
|
|
|
|
>
|
|
|
|
<template :slot="'header'">
|
|
|
|
{{ $t('word.edit') }} "{{ field }}"
|
|
|
|
</template>
|
|
|
|
<div :slot="'body'">
|
|
|
|
<div class="mb-2">
|
|
|
|
<div>
|
|
|
|
<textarea
|
|
|
|
v-model="localContent"
|
|
|
|
class="form-input textarea-editor"
|
|
|
|
/>
|
|
|
|
</div>
|
2020-07-31 15:45:32 +02:00
|
|
|
<div class="editor-field-info">
|
|
|
|
<div><b>{{ $t('word.size') }}</b>: {{ localContent.length }}</div>
|
|
|
|
<div><b>{{ $t('word.type') }}</b>: {{ type.toUpperCase() }}</div>
|
2020-07-30 19:12:29 +02:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</ConfirmModal>
|
2020-06-26 18:14:16 +02:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
|
|
|
import moment from 'moment';
|
|
|
|
import { mimeFromHex, formatBytes } from 'common/libs/utilities';
|
|
|
|
import hexToBinary from 'common/libs/hexToBinary';
|
2020-07-02 19:17:25 +02:00
|
|
|
import { mask } from 'vue-the-mask';
|
2020-07-30 19:12:29 +02:00
|
|
|
import ConfirmModal from '@/components/BaseConfirmModal';
|
2020-06-26 18:14:16 +02:00
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'WorkspaceQueryTableCell',
|
2020-07-30 19:12:29 +02:00
|
|
|
components: {
|
|
|
|
ConfirmModal
|
|
|
|
},
|
2020-06-26 18:14:16 +02:00
|
|
|
filters: {
|
2020-07-22 18:30:52 +02:00
|
|
|
cutText (val) {
|
|
|
|
if (typeof val !== 'string') return val;
|
2020-07-24 13:26:56 +02:00
|
|
|
return val.length > 128 ? `${val.substring(0, 128)}[...]` : val;
|
2020-07-22 18:30:52 +02:00
|
|
|
},
|
2020-07-05 16:06:56 +02:00
|
|
|
typeFormat (val, type, precision) {
|
2020-06-26 18:14:16 +02:00
|
|
|
if (!val) return val;
|
|
|
|
|
|
|
|
switch (type) {
|
|
|
|
case 'char':
|
|
|
|
case 'varchar':
|
|
|
|
case 'text':
|
|
|
|
case 'mediumtext':
|
2020-07-22 18:30:52 +02:00
|
|
|
return val;
|
2020-07-02 19:17:25 +02:00
|
|
|
case 'date': {
|
|
|
|
return moment(val).isValid() ? moment(val).format('YYYY-MM-DD') : val;
|
|
|
|
}
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'datetime':
|
2020-07-02 19:17:25 +02:00
|
|
|
case 'timestamp': {
|
2020-07-05 16:06:56 +02:00
|
|
|
let datePrecision = '';
|
|
|
|
for (let i = 0; i < precision; i++)
|
|
|
|
datePrecision += i === 0 ? '.S' : 'S';
|
|
|
|
|
|
|
|
return moment(val).isValid() ? moment(val).format(`YYYY-MM-DD HH:mm:ss${datePrecision}`) : val;
|
2020-07-02 19:17:25 +02:00
|
|
|
}
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'blob':
|
|
|
|
case 'mediumblob':
|
|
|
|
case 'longblob': {
|
|
|
|
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)})`;
|
|
|
|
}
|
|
|
|
case 'bit': {
|
|
|
|
const hex = Buffer.from(val).toString('hex');
|
|
|
|
return hexToBinary(hex);
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2020-07-02 19:17:25 +02:00
|
|
|
directives: {
|
|
|
|
mask
|
|
|
|
},
|
2020-06-26 18:14:16 +02:00
|
|
|
props: {
|
|
|
|
type: String,
|
|
|
|
field: String,
|
2020-07-05 16:06:56 +02:00
|
|
|
precision: [Number, null],
|
2020-06-26 18:14:16 +02:00
|
|
|
content: [String, Number, Object, Date, Uint8Array]
|
|
|
|
},
|
|
|
|
data () {
|
|
|
|
return {
|
2020-07-30 19:12:29 +02:00
|
|
|
isInlineEditor: false,
|
|
|
|
isTextareaEditor: false,
|
|
|
|
localContent: null
|
2020-06-26 18:14:16 +02:00
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
2020-07-02 19:17:25 +02:00
|
|
|
inputProps () {
|
2020-06-26 18:14:16 +02:00
|
|
|
switch (this.type) {
|
|
|
|
case 'char':
|
|
|
|
case 'varchar':
|
|
|
|
case 'text':
|
|
|
|
case 'mediumtext':
|
2020-07-30 19:12:29 +02:00
|
|
|
case 'longtext':
|
2020-07-02 19:17:25 +02:00
|
|
|
return { type: 'text', mask: false };
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'int':
|
|
|
|
case 'tinyint':
|
|
|
|
case 'smallint':
|
|
|
|
case 'mediumint':
|
2020-07-30 19:12:29 +02:00
|
|
|
case 'bigint':
|
2020-07-02 19:17:25 +02:00
|
|
|
return { type: 'number', mask: false };
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'date':
|
2020-07-02 19:17:25 +02:00
|
|
|
return { type: 'text', mask: '####-##-##' };
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'datetime':
|
2020-07-05 16:06:56 +02:00
|
|
|
case 'timestamp': {
|
|
|
|
let datetimeMask = '####-##-## ##:##:##';
|
|
|
|
for (let i = 0; i < this.precision; i++)
|
|
|
|
datetimeMask += i === 0 ? '.#' : '#';
|
|
|
|
return { type: 'text', mask: datetimeMask };
|
|
|
|
}
|
2020-06-26 18:14:16 +02:00
|
|
|
case 'blob':
|
|
|
|
case 'mediumblob':
|
|
|
|
case 'longblob':
|
|
|
|
case 'bit':
|
2020-07-05 16:06:56 +02:00
|
|
|
return { type: 'file', mask: false };
|
2020-06-26 18:14:16 +02:00
|
|
|
default:
|
2020-06-28 15:31:16 +02:00
|
|
|
return 'hidden';
|
2020-06-26 18:14:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
isNull (value) {
|
|
|
|
return value === null ? ' is-null' : '';
|
|
|
|
},
|
|
|
|
editON () {
|
2020-07-05 16:06:56 +02:00
|
|
|
if (['file'].includes(this.inputProps.type)) return;// TODO: remove temporary file block
|
2020-07-30 19:12:29 +02:00
|
|
|
this.localContent = this.$options.filters.typeFormat(this.content, this.type);
|
2020-07-05 16:06:56 +02:00
|
|
|
|
2020-07-30 19:12:29 +02:00
|
|
|
switch (this.type) {
|
|
|
|
case 'text':
|
|
|
|
case 'mediumtext':
|
|
|
|
case 'longtext':
|
|
|
|
this.isTextareaEditor = true;
|
|
|
|
break;
|
2020-06-26 18:14:16 +02:00
|
|
|
|
2020-07-30 19:12:29 +02:00
|
|
|
default:// Inline editable fields
|
|
|
|
this.$nextTick(() => { // Focus on input
|
|
|
|
this.$refs.cell.blur();
|
|
|
|
|
|
|
|
this.$nextTick(() => this.$refs.editField.focus());
|
|
|
|
});
|
|
|
|
this.isInlineEditor = true;
|
|
|
|
break;
|
|
|
|
}
|
2020-06-26 18:14:16 +02:00
|
|
|
},
|
|
|
|
editOFF () {
|
2020-07-30 19:12:29 +02:00
|
|
|
this.isInlineEditor = false;
|
|
|
|
if (this.localContent === this.$options.filters.typeFormat(this.content, this.type)) return;// If not changed
|
2020-06-26 18:14:16 +02:00
|
|
|
|
2020-06-27 15:14:08 +02:00
|
|
|
const { field, type, localContent: content } = this;
|
|
|
|
this.$emit('updateField', { field, type, content });
|
2020-07-30 19:12:29 +02:00
|
|
|
},
|
|
|
|
hideEditorModal () {
|
|
|
|
this.isTextareaEditor = false;
|
2020-06-26 18:14:16 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss">
|
2020-07-31 18:16:28 +02:00
|
|
|
.editable-field {
|
|
|
|
margin: 0;
|
|
|
|
border: none;
|
|
|
|
line-height: 1;
|
|
|
|
width: 100%;
|
2020-06-26 18:14:16 +02:00
|
|
|
}
|
|
|
|
|
2020-07-31 18:16:28 +02:00
|
|
|
.cell-content {
|
|
|
|
display: block;
|
|
|
|
min-height: 0.8rem;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
white-space: nowrap;
|
|
|
|
overflow: hidden;
|
2020-06-26 18:14:16 +02:00
|
|
|
}
|
2020-07-30 19:12:29 +02:00
|
|
|
|
2020-07-31 18:16:28 +02:00
|
|
|
.textarea-editor {
|
|
|
|
height: 50vh !important;
|
2020-07-30 19:12:29 +02:00
|
|
|
}
|
2020-07-31 15:45:32 +02:00
|
|
|
|
2020-07-31 18:16:28 +02:00
|
|
|
.editor-field-info {
|
|
|
|
margin-top: 0.6rem;
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
2020-07-31 15:45:32 +02:00
|
|
|
}
|
2020-06-26 18:14:16 +02:00
|
|
|
</style>
|