mirror of https://github.com/Fabio286/antares.git
feat: context menu option to duplicate a table row
This commit is contained in:
parent
78902639eb
commit
985e5d3527
|
@ -13,7 +13,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { computed, Ref, ref, watch } from 'vue';
|
||||
import { storeToRefs } from 'pinia';
|
||||
import Tables from '@/ipc-api/Tables';
|
||||
import { useNotificationsStore } from '@/stores/notifications';
|
||||
|
@ -40,7 +40,7 @@ const { getSelected: selectedWorkspace } = storeToRefs(workspacesStore);
|
|||
|
||||
const editField: Ref<HTMLSelectElement> = ref(null);
|
||||
const foreignList = ref([]);
|
||||
const currentValue = ref(props.modelValue);
|
||||
const currentValue = ref(null);
|
||||
|
||||
const isValidDefault = computed(() => {
|
||||
if (!foreignList.value.length) return true;
|
||||
|
@ -66,6 +66,10 @@ const cutText = (val: string) => {
|
|||
return val.length > 15 ? `${val.substring(0, 15)}...` : val;
|
||||
};
|
||||
|
||||
watch(() => props.modelValue, () => {
|
||||
currentValue.value = props.modelValue;
|
||||
});
|
||||
|
||||
let foreignDesc: string | false;
|
||||
const params = {
|
||||
uid: selectedWorkspace.value,
|
||||
|
|
|
@ -113,6 +113,8 @@ import BaseSelect from '@/components/BaseSelect.vue';
|
|||
const props = defineProps({
|
||||
tabUid: [String, Number],
|
||||
fields: Array as Prop<TableField[]>,
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
rowToDuplicate: Object as Prop<any>,
|
||||
keyUsage: Array as Prop<TableForeign[]>
|
||||
});
|
||||
|
||||
|
@ -284,44 +286,57 @@ onMounted(() => {
|
|||
|
||||
const rowObj: {[key: string]: unknown} = {};
|
||||
|
||||
for (const field of props.fields) {
|
||||
let fieldDefault;
|
||||
if (!props.rowToDuplicate) {
|
||||
// Set default values
|
||||
for (const field of props.fields) {
|
||||
let fieldDefault;
|
||||
|
||||
if (field.default === 'NULL') fieldDefault = null;
|
||||
else {
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', '');
|
||||
else if ([...TEXT, ...LONG_TEXT].includes(field.type)) {
|
||||
fieldDefault = field.default
|
||||
? field.default.includes('\'')
|
||||
? field.default.split('\'')[1]
|
||||
: 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}`);
|
||||
if (field.default === 'NULL') fieldDefault = null;
|
||||
else {
|
||||
if ([...NUMBER, ...FLOAT].includes(field.type))
|
||||
fieldDefault = !field.default || Number.isNaN(+field.default.replaceAll('\'', '')) ? null : +field.default.replaceAll('\'', '');
|
||||
else if ([...TEXT, ...LONG_TEXT].includes(field.type)) {
|
||||
fieldDefault = field.default
|
||||
? field.default.includes('\'')
|
||||
? field.default.split('\'')[1]
|
||||
: 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
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
else if (field.enumValues)
|
||||
fieldDefault = field.enumValues.replaceAll('\'', '').split(',');
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
}
|
||||
else if (field.enumValues)
|
||||
fieldDefault = field.enumValues.replaceAll('\'', '').split(',');
|
||||
else
|
||||
fieldDefault = field.default;
|
||||
|
||||
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];
|
||||
}
|
||||
}
|
||||
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 };
|
||||
|
|
|
@ -14,10 +14,12 @@
|
|||
:context-event="contextEvent"
|
||||
:selected-rows="selectedRows"
|
||||
:selected-cell="selectedCell"
|
||||
:mode="mode"
|
||||
@show-delete-modal="showDeleteConfirmModal"
|
||||
@set-null="setNull"
|
||||
@copy-cell="copyCell"
|
||||
@copy-row="copyRow"
|
||||
@duplicate-row="duplicateRow"
|
||||
@close-context="closeContext"
|
||||
/>
|
||||
<ul v-if="resultsWithRows.length > 1" class="tab tab-block result-tabs">
|
||||
|
@ -143,12 +145,17 @@ const { consoleHeight } = storeToRefs(consoleStore);
|
|||
const props = defineProps({
|
||||
results: Array as Prop<QueryResult[]>,
|
||||
connUid: String,
|
||||
mode: String,
|
||||
mode: String as Prop<'table' | 'query'>,
|
||||
isSelected: Boolean,
|
||||
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 tableWrapper: Ref<HTMLDivElement> = ref(null);
|
||||
|
@ -412,6 +419,13 @@ const copyRow = () => {
|
|||
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 { primary, id, field, table, content } = params;
|
||||
|
||||
|
|
|
@ -27,6 +27,15 @@
|
|||
</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
|
||||
v-if="selectedRows.length === 1 && selectedCell.isEditable"
|
||||
class="context-element"
|
||||
|
@ -49,6 +58,7 @@
|
|||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Prop } from 'vue';
|
||||
import BaseContextMenu from '@/components/BaseContextMenu.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
|
@ -57,10 +67,18 @@ const { t } = useI18n();
|
|||
defineProps({
|
||||
contextEvent: MouseEvent,
|
||||
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 = () => {
|
||||
emit('show-delete-modal');
|
||||
|
@ -84,4 +102,9 @@ const copyRow = () => {
|
|||
emit('copy-row');
|
||||
closeContext();
|
||||
};
|
||||
|
||||
const duplicateRow = () => {
|
||||
emit('duplicate-row');
|
||||
closeContext();
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -153,12 +153,14 @@
|
|||
:element-type="elementType"
|
||||
@update-field="updateField"
|
||||
@delete-selected="deleteSelected"
|
||||
@duplicate-row="showFakerModal"
|
||||
@hard-sort="hardSort"
|
||||
/>
|
||||
</div>
|
||||
<ModalFakerRows
|
||||
v-if="isFakerModal"
|
||||
:fields="fields"
|
||||
:row-to-duplicate="rowToDuplicate"
|
||||
:key-usage="keyUsage"
|
||||
:tab-uid="tabUid"
|
||||
@hide="hideFakerModal"
|
||||
|
@ -224,6 +226,7 @@ const filters = ref([]);
|
|||
const page = ref(1);
|
||||
const pageProxy = ref(1);
|
||||
const approximateCount = ref(0);
|
||||
const rowToDuplicate = ref(null);
|
||||
|
||||
const workspace = computed(() => {
|
||||
return getWorkspace(props.connection.uid);
|
||||
|
@ -329,13 +332,16 @@ const pageChange = (direction: 'prev' | 'next') => {
|
|||
page.value--;
|
||||
};
|
||||
|
||||
const showFakerModal = () => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const showFakerModal = (row?: any) => {
|
||||
if (isQuering.value) return;
|
||||
isFakerModal.value = true;
|
||||
rowToDuplicate.value = row;
|
||||
};
|
||||
|
||||
const hideFakerModal = () => {
|
||||
isFakerModal.value = false;
|
||||
rowToDuplicate.value = null;
|
||||
};
|
||||
|
||||
const onKey = (e: KeyboardEvent) => {
|
||||
|
|
Loading…
Reference in New Issue