feat: context menu option to duplicate a table row

This commit is contained in:
Fabio Di Stasio 2022-07-19 17:48:51 +02:00
parent 78902639eb
commit 985e5d3527
5 changed files with 100 additions and 38 deletions

View File

@ -13,7 +13,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed, Ref, ref } from 'vue'; import { computed, Ref, ref, watch } from 'vue';
import { storeToRefs } from 'pinia'; import { storeToRefs } from 'pinia';
import Tables from '@/ipc-api/Tables'; import Tables from '@/ipc-api/Tables';
import { useNotificationsStore } from '@/stores/notifications'; import { useNotificationsStore } from '@/stores/notifications';
@ -40,7 +40,7 @@ const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
const editField: Ref<HTMLSelectElement> = ref(null); const editField: Ref<HTMLSelectElement> = ref(null);
const foreignList = ref([]); const foreignList = ref([]);
const currentValue = ref(props.modelValue); const currentValue = ref(null);
const isValidDefault = computed(() => { const isValidDefault = computed(() => {
if (!foreignList.value.length) return true; if (!foreignList.value.length) return true;
@ -66,6 +66,10 @@ const cutText = (val: string) => {
return val.length > 15 ? `${val.substring(0, 15)}...` : val; return val.length > 15 ? `${val.substring(0, 15)}...` : val;
}; };
watch(() => props.modelValue, () => {
currentValue.value = props.modelValue;
});
let foreignDesc: string | false; let foreignDesc: string | false;
const params = { const params = {
uid: selectedWorkspace.value, uid: selectedWorkspace.value,

View File

@ -113,6 +113,8 @@ import BaseSelect from '@/components/BaseSelect.vue';
const props = defineProps({ const props = defineProps({
tabUid: [String, Number], tabUid: [String, Number],
fields: Array as Prop<TableField[]>, fields: Array as Prop<TableField[]>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
rowToDuplicate: Object as Prop<any>,
keyUsage: Array as Prop<TableForeign[]> keyUsage: Array as Prop<TableForeign[]>
}); });
@ -284,44 +286,57 @@ onMounted(() => {
const rowObj: {[key: string]: unknown} = {}; const rowObj: {[key: string]: unknown} = {};
for (const field of props.fields) { if (!props.rowToDuplicate) {
let fieldDefault; // Set default values
for (const field of props.fields) {
let fieldDefault;
if (field.default === 'NULL') fieldDefault = null; if (field.default === 'NULL') fieldDefault = null;
else { else {
if ([...NUMBER, ...FLOAT].includes(field.type)) if ([...NUMBER, ...FLOAT].includes(field.type))
fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', ''); fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', '');
else if ([...TEXT, ...LONG_TEXT].includes(field.type)) { else if ([...TEXT, ...LONG_TEXT].includes(field.type)) {
fieldDefault = field.default fieldDefault = field.default
? field.default.includes('\'') ? field.default.includes('\'')
? field.default.split('\'')[1] ? field.default.split('\'')[1]
: field.default : field.default
: ''; : '';
}
else if ([...TIME, ...DATE].includes(field.type))
fieldDefault = field.default;
else if (BIT.includes(field.type))
fieldDefault = field.default?.replaceAll('\'', '').replaceAll('b', '');
else if (DATETIME.includes(field.type)) {
if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) {
let datePrecision = '';
for (let i = 0; i < field.datePrecision; i++)
datePrecision += i === 0 ? '.S' : 'S';
fieldDefault = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
} }
else if ([...TIME, ...DATE].includes(field.type))
fieldDefault = field.default;
else if (BIT.includes(field.type))
fieldDefault = field.default?.replaceAll('\'', '').replaceAll('b', '');
else if (DATETIME.includes(field.type)) {
if (field.default && ['current_timestamp', 'now()'].some(term => field.default.toLowerCase().includes(term))) {
let datePrecision = '';
for (let i = 0; i < field.datePrecision; i++)
datePrecision += i === 0 ? '.S' : 'S';
fieldDefault = moment().format(`YYYY-MM-DD HH:mm:ss${datePrecision}`);
}
else
fieldDefault = field.default;
}
else if (field.enumValues)
fieldDefault = field.enumValues.replaceAll('\'', '').split(',');
else else
fieldDefault = field.default; fieldDefault = field.default;
} }
else if (field.enumValues)
fieldDefault = field.enumValues.replaceAll('\'', '').split(','); rowObj[field.name] = { value: fieldDefault };
else
fieldDefault = field.default; if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields
fieldsToExclude.value = [...fieldsToExclude.value, field.name];
} }
}
else {
// Set values to duplicate
for (const field of props.fields) {
if (typeof props.rowToDuplicate[field.name] !== 'object')
rowObj[field.name] = { value: props.rowToDuplicate[field.name] };
rowObj[field.name] = { value: fieldDefault }; if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields
fieldsToExclude.value = [...fieldsToExclude.value, field.name];
if (field.autoIncrement || !!field.onUpdate)// Disable by default auto increment or "on update" fields }
fieldsToExclude.value = [...fieldsToExclude.value, field.name];
} }
localRow.value = { ...rowObj }; localRow.value = { ...rowObj };

View File

@ -14,10 +14,12 @@
:context-event="contextEvent" :context-event="contextEvent"
:selected-rows="selectedRows" :selected-rows="selectedRows"
:selected-cell="selectedCell" :selected-cell="selectedCell"
:mode="mode"
@show-delete-modal="showDeleteConfirmModal" @show-delete-modal="showDeleteConfirmModal"
@set-null="setNull" @set-null="setNull"
@copy-cell="copyCell" @copy-cell="copyCell"
@copy-row="copyRow" @copy-row="copyRow"
@duplicate-row="duplicateRow"
@close-context="closeContext" @close-context="closeContext"
/> />
<ul v-if="resultsWithRows.length > 1" class="tab tab-block result-tabs"> <ul v-if="resultsWithRows.length > 1" class="tab tab-block result-tabs">
@ -143,12 +145,17 @@ const { consoleHeight } = storeToRefs(consoleStore);
const props = defineProps({ const props = defineProps({
results: Array as Prop<QueryResult[]>, results: Array as Prop<QueryResult[]>,
connUid: String, connUid: String,
mode: String, mode: String as Prop<'table' | 'query'>,
isSelected: Boolean, isSelected: Boolean,
elementType: { type: String, default: 'table' } elementType: { type: String, default: 'table' }
}); });
const emit = defineEmits(['update-field', 'delete-selected', 'hard-sort']); const emit = defineEmits([
'update-field',
'delete-selected',
'hard-sort',
'duplicate-row'
]);
const resultTable: Ref<Component & {updateWindow: () => void}> = ref(null); const resultTable: Ref<Component & {updateWindow: () => void}> = ref(null);
const tableWrapper: Ref<HTMLDivElement> = ref(null); const tableWrapper: Ref<HTMLDivElement> = ref(null);
@ -412,6 +419,13 @@ const copyRow = () => {
navigator.clipboard.writeText(JSON.stringify(rowToCopy)); navigator.clipboard.writeText(JSON.stringify(rowToCopy));
}; };
const duplicateRow = () => {
const row = localResults.value.find((row: any) => selectedRows.value.includes(row._antares_id));
const rowToDuplicate = JSON.parse(JSON.stringify(row));
delete rowToDuplicate._antares_id;
emit('duplicate-row', rowToDuplicate);
};
const applyUpdate = (params: TableUpdateParams) => { const applyUpdate = (params: TableUpdateParams) => {
const { primary, id, field, table, content } = params; const { primary, id, field, table, content } = params;

View File

@ -27,6 +27,15 @@
</div> </div>
</div> </div>
</div> </div>
<div
v-if="selectedRows.length === 1 && selectedCell.isEditable && mode === 'table'"
class="context-element"
@click="duplicateRow"
>
<span class="d-flex">
<i class="mdi mdi-18px mdi-content-duplicate text-light pr-1" /> {{ t('word.duplicate') }}
</span>
</div>
<div <div
v-if="selectedRows.length === 1 && selectedCell.isEditable" v-if="selectedRows.length === 1 && selectedCell.isEditable"
class="context-element" class="context-element"
@ -49,6 +58,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { Prop } from 'vue';
import BaseContextMenu from '@/components/BaseContextMenu.vue'; import BaseContextMenu from '@/components/BaseContextMenu.vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
@ -57,10 +67,18 @@ const { t } = useI18n();
defineProps({ defineProps({
contextEvent: MouseEvent, contextEvent: MouseEvent,
selectedRows: Array, selectedRows: Array,
selectedCell: Object selectedCell: Object,
mode: String as Prop<'table' | 'query'>
}); });
const emit = defineEmits(['show-delete-modal', 'close-context', 'set-null', 'copy-cell', 'copy-row']); const emit = defineEmits([
'show-delete-modal',
'close-context',
'set-null',
'copy-cell',
'copy-row',
'duplicate-row'
]);
const showConfirmModal = () => { const showConfirmModal = () => {
emit('show-delete-modal'); emit('show-delete-modal');
@ -84,4 +102,9 @@ const copyRow = () => {
emit('copy-row'); emit('copy-row');
closeContext(); closeContext();
}; };
const duplicateRow = () => {
emit('duplicate-row');
closeContext();
};
</script> </script>

View File

@ -153,12 +153,14 @@
:element-type="elementType" :element-type="elementType"
@update-field="updateField" @update-field="updateField"
@delete-selected="deleteSelected" @delete-selected="deleteSelected"
@duplicate-row="showFakerModal"
@hard-sort="hardSort" @hard-sort="hardSort"
/> />
</div> </div>
<ModalFakerRows <ModalFakerRows
v-if="isFakerModal" v-if="isFakerModal"
:fields="fields" :fields="fields"
:row-to-duplicate="rowToDuplicate"
:key-usage="keyUsage" :key-usage="keyUsage"
:tab-uid="tabUid" :tab-uid="tabUid"
@hide="hideFakerModal" @hide="hideFakerModal"
@ -224,6 +226,7 @@ const filters = ref([]);
const page = ref(1); const page = ref(1);
const pageProxy = ref(1); const pageProxy = ref(1);
const approximateCount = ref(0); const approximateCount = ref(0);
const rowToDuplicate = ref(null);
const workspace = computed(() => { const workspace = computed(() => {
return getWorkspace(props.connection.uid); return getWorkspace(props.connection.uid);
@ -329,13 +332,16 @@ const pageChange = (direction: 'prev' | 'next') => {
page.value--; page.value--;
}; };
const showFakerModal = () => { // eslint-disable-next-line @typescript-eslint/no-explicit-any
const showFakerModal = (row?: any) => {
if (isQuering.value) return; if (isQuering.value) return;
isFakerModal.value = true; isFakerModal.value = true;
rowToDuplicate.value = row;
}; };
const hideFakerModal = () => { const hideFakerModal = () => {
isFakerModal.value = false; isFakerModal.value = false;
rowToDuplicate.value = null;
}; };
const onKey = (e: KeyboardEvent) => { const onKey = (e: KeyboardEvent) => {