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>
|
</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,
|
||||||
|
|
|
@ -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 };
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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) => {
|
||||||
|
|
Loading…
Reference in New Issue