mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-11-10 17:36:33 +08:00
Update columns manage modal [SCI-10090]
This commit is contained in:
parent
72b40a63a0
commit
f43718ea6d
4 changed files with 168 additions and 33 deletions
|
@ -11,31 +11,51 @@
|
|||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p class='modal-description'>
|
||||
{{ i18n.t("experiments.table.column_display_modal.description") }}
|
||||
</p>
|
||||
<div class="max-h-90 overflow-y-auto">
|
||||
<div
|
||||
v-for="column in columnDefs"
|
||||
:key="column.field"
|
||||
@click="toggleColumn(column, columnVisbile(column))"
|
||||
class="flex items-center gap-4 py-2.5 px-3"
|
||||
:class="{
|
||||
'cursor-pointer': column.field !== 'name',
|
||||
'hover:bg-sn-super-light-grey': column.field !== 'name'
|
||||
}"
|
||||
<Draggable
|
||||
v-model="columnsList"
|
||||
:forceFallback="true"
|
||||
:handle="'.element-grip'"
|
||||
item-key="field"
|
||||
@end="endReorder"
|
||||
>
|
||||
<div v-if="column.field === 'name'" class="w-6 h-6"></div>
|
||||
<template v-else>
|
||||
<i v-if="columnVisbile(column)"
|
||||
class="sn-icon sn-icon-visibility-show"></i>
|
||||
<i v-else
|
||||
class="sn-icon sn-icon-visibility-hide"></i>
|
||||
</template>
|
||||
<div class="truncate">{{ column.headerName }}</div>
|
||||
</div>
|
||||
<template #item="{element}">
|
||||
<div
|
||||
class="flex items-center gap-4 py-2.5 px-3 group/column"
|
||||
:class="{
|
||||
'hover:bg-sn-super-light-grey': element.field !== 'pinnedSeparator',
|
||||
'!py-2.5': element.field === 'pinnedSeparator',
|
||||
'text-sn-grey': (element.field !== 'pinnedSeparator' && !columnVisbile(element))
|
||||
}"
|
||||
>
|
||||
<div v-if="element.field == 'pinnedSeparator'" class="h-[1px] w-full bg-sn-sleepy-grey"></div>
|
||||
<template v-else>
|
||||
<div class="opacity-0 group-hover/column:!opacity-100 element-grip cursor-pointer">
|
||||
<i class="sn-icon sn-icon-drag"></i>
|
||||
</div>
|
||||
<div v-if="element.field === 'name'" class="w-6 h-6"></div>
|
||||
<template v-else>
|
||||
<i v-if="columnVisbile(element)" @click="toggleColumn(element, true)"
|
||||
class="sn-icon sn-icon-visibility-show cursor-pointer"></i>
|
||||
<i v-else @click="toggleColumn(element, false)"
|
||||
class="sn-icon sn-icon-visibility-hide cursor-pointer"></i>
|
||||
</template>
|
||||
<div class="truncate">{{ element.headerName }}</div>
|
||||
<div class="ml-auto cursor-pointer">
|
||||
<i v-if="columnPinned(element)" @click="unPinColumn(element)" class="sn-icon sn-icon-pinned"></i>
|
||||
<i v-else @click="pinColumn(element)" class="sn-icon sn-icon-pin"></i>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
</Draggable>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary mr-auto" @click="resetToDefault">
|
||||
{{ i18n.t('experiments.table.column_display_modal.reset_to_default') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -43,6 +63,7 @@
|
|||
|
||||
<script>
|
||||
import modalMixin from '../../modal_mixin';
|
||||
import Draggable from 'vuedraggable';
|
||||
|
||||
export default {
|
||||
name: 'NewModal',
|
||||
|
@ -50,28 +71,93 @@ export default {
|
|||
columnDefs: { type: Array, required: true },
|
||||
tableState: { type: Object }
|
||||
},
|
||||
components: {
|
||||
Draggable
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
currentTableState: {}
|
||||
currentTableState: {},
|
||||
columnsList: []
|
||||
};
|
||||
},
|
||||
created() {
|
||||
this.currentTableState = this.tableState;
|
||||
this.syncColumns();
|
||||
},
|
||||
watch: {
|
||||
tableState: {
|
||||
handler() {
|
||||
this.syncColumns();
|
||||
},
|
||||
deep: true
|
||||
}
|
||||
},
|
||||
mixins: [modalMixin],
|
||||
methods: {
|
||||
resetToDefault() {
|
||||
this.$emit('resetToDefault');
|
||||
this.close();
|
||||
},
|
||||
columnVisbile(column) {
|
||||
return !this.currentTableState.columnsState?.find((col) => col.colId === column.field).hide;
|
||||
},
|
||||
columnPinned(column) {
|
||||
return this.currentTableState.columnsState?.find((col) => col.colId === column.field).pinned;
|
||||
},
|
||||
toggleColumn(column, visible) {
|
||||
if (column.field === 'name') return;
|
||||
|
||||
this.currentTableState.columnsState.find((col) => col.colId === column.field).hide = visible;
|
||||
if (visible) {
|
||||
this.$emit('hideColumn', column);
|
||||
} else {
|
||||
this.$emit('showColumn', column);
|
||||
}
|
||||
},
|
||||
pinColumn(column) {
|
||||
this.$emit('pinColumn', column);
|
||||
},
|
||||
unPinColumn(column) {
|
||||
this.$emit('unPinColumn', column);
|
||||
},
|
||||
syncColumns() {
|
||||
this.currentTableState = this.tableState;
|
||||
this.currentTableState.columnsState.forEach((col, index) => {
|
||||
col.position = index;
|
||||
});
|
||||
|
||||
let columns = this.currentTableState.columnsState
|
||||
.sort((a, b) => {
|
||||
if (a.pinned === b.pinned) {
|
||||
return a.position - b.position;
|
||||
}
|
||||
return a.pinned ? -1 : 1;
|
||||
});
|
||||
|
||||
const pinnedAmount = columns.filter((col) => col.pinned).length;
|
||||
columns = columns
|
||||
.map((col) => this.columnDefs.find((c) => c.field === col.colId))
|
||||
.filter((col) => col);
|
||||
this.columnsList = [
|
||||
...columns.slice(0, pinnedAmount - 1),
|
||||
{ field: 'pinnedSeparator' },
|
||||
...columns.slice(pinnedAmount - 1)
|
||||
];
|
||||
},
|
||||
endReorder(event) {
|
||||
this.$nextTick(() => {
|
||||
const { newIndex } = event;
|
||||
const columnName = this.columnsList[newIndex].field;
|
||||
const separatorIndex = this.columnsList.findIndex((col) => col.field === 'pinnedSeparator');
|
||||
const reordedColumns = this.columnsList.filter((col) => col.field !== 'pinnedSeparator');
|
||||
|
||||
const columnsOrdered = reordedColumns.map((col) => col.field);
|
||||
this.$emit('reorderColumns', columnsOrdered);
|
||||
|
||||
if (newIndex <= separatorIndex) {
|
||||
this.pinColumn(this.columnDefs.find((col) => col.field === columnName));
|
||||
} else {
|
||||
this.unPinColumn(this.columnDefs.find((col) => col.field === columnName));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -21,6 +21,10 @@
|
|||
@sort="applyOrder"
|
||||
@hideColumn="hideColumn"
|
||||
@showColumn="showColumn"
|
||||
@pinColumn="pinColumn"
|
||||
@unPinColumn="unPinColumn"
|
||||
@reorderColumns="reorderColumns"
|
||||
@resetColumnsToDefault="resetColumnsToDefault"
|
||||
/>
|
||||
<div v-if="currentViewRender === 'cards'" ref="cardsContainer" @scroll="handleScroll"
|
||||
class="flex-grow basis-64 overflow-y-auto overflow-x-visible p-2 -ml-2">
|
||||
|
@ -168,7 +172,8 @@ export default {
|
|||
currentViewRender: 'table',
|
||||
cardCheckboxes: [],
|
||||
dataLoading: true,
|
||||
lastPage: false
|
||||
lastPage: false,
|
||||
tableState: null
|
||||
};
|
||||
},
|
||||
components: {
|
||||
|
@ -185,11 +190,6 @@ export default {
|
|||
perPageOptions() {
|
||||
return [10, 20, 50, 100].map((value) => ([value, `${value} ${this.i18n.t('datatable.rows')}`]));
|
||||
},
|
||||
tableState() {
|
||||
if (!localStorage.getItem(`datatable:${this.tableId}_columns_state`)) return null;
|
||||
|
||||
return JSON.parse(localStorage.getItem(`datatable:${this.tableId}_columns_state`));
|
||||
},
|
||||
actionsParams() {
|
||||
return {
|
||||
items: JSON.stringify(this.selectedRows.map((row) => ({ id: row.id, type: row.type })))
|
||||
|
@ -219,7 +219,8 @@ export default {
|
|||
suppressMovable: true,
|
||||
width: 48,
|
||||
minWidth: 48,
|
||||
resizable: false,
|
||||
maxWidth: 48,
|
||||
resizable: true,
|
||||
pinned: 'left',
|
||||
lockPosition: 'left'
|
||||
});
|
||||
|
@ -267,6 +268,10 @@ export default {
|
|||
}
|
||||
},
|
||||
created() {
|
||||
if (localStorage.getItem(`datatable:${this.tableId}_columns_state`)) {
|
||||
this.tableState = JSON.parse(localStorage.getItem(`datatable:${this.tableId}_columns_state`));
|
||||
}
|
||||
|
||||
if (this.tableState) {
|
||||
this.currentViewRender = this.tableState.currentViewRender || 'table';
|
||||
this.perPage = this.tableState.perPage || 20;
|
||||
|
@ -431,6 +436,7 @@ export default {
|
|||
perPage: this.perPage
|
||||
};
|
||||
localStorage.setItem(`datatable:${this.tableId}_columns_state`, JSON.stringify(tableState));
|
||||
this.tableState = tableState;
|
||||
},
|
||||
setSelectedRows() {
|
||||
this.selectedRows = this.gridApi.getSelectedRows();
|
||||
|
@ -466,6 +472,23 @@ export default {
|
|||
this.columnApi.setColumnVisible(column.field, true);
|
||||
this.saveTableState();
|
||||
},
|
||||
pinColumn(column) {
|
||||
this.columnApi.setColumnPinned(column.field, 'left');
|
||||
this.saveTableState();
|
||||
},
|
||||
unPinColumn(column) {
|
||||
this.columnApi.setColumnPinned(column.field, null);
|
||||
this.saveTableState();
|
||||
},
|
||||
reorderColumns(columns) {
|
||||
this.columnApi.moveColumns(columns, 1);
|
||||
this.saveTableState();
|
||||
},
|
||||
resetColumnsToDefault() {
|
||||
this.columnApi.resetColumnState();
|
||||
this.columnApi.autoSizeAllColumns();
|
||||
this.saveTableState();
|
||||
},
|
||||
getOrder(columnsState) {
|
||||
if (!columnsState) return null;
|
||||
|
||||
|
|
|
@ -105,9 +105,22 @@
|
|||
:columnDefs="columnDefs"
|
||||
@hideColumn="(column) => $emit('hideColumn', column)"
|
||||
@showColumn="(column) => $emit('showColumn', column)"
|
||||
@unPinColumn="(column) => $emit('unPinColumn', column)"
|
||||
@pinColumn="(column) => $emit('pinColumn', column)"
|
||||
@reorderColumns="(columns) => $emit('reorderColumns', columns)"
|
||||
@resetToDefault="resetToDefault"
|
||||
v-if="showColumnsModal"
|
||||
@close="showColumnsModal = false" />
|
||||
</teleport>
|
||||
<teleport to="body">
|
||||
<ConfirmationModal
|
||||
:title="i18n.t('experiments.table.column_display_modal.confirmation.title')"
|
||||
:description="i18n.t('experiments.table.column_display_modal.confirmation.description_html')"
|
||||
confirmClass="btn btn-primary"
|
||||
:confirmText="i18n.t('experiments.table.column_display_modal.confirmation.confirm')"
|
||||
ref="resetColumnModal"
|
||||
></ConfirmationModal>
|
||||
</teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -116,6 +129,7 @@ import MenuDropdown from '../menu_dropdown.vue';
|
|||
import GeneralDropdown from '../general_dropdown.vue';
|
||||
import FilterDropdown from '../filters/filter_dropdown.vue';
|
||||
import ColumnsModal from './modals/columns.vue';
|
||||
import ConfirmationModal from '../confirmation_modal.vue';
|
||||
|
||||
export default {
|
||||
name: 'Toolbar',
|
||||
|
@ -163,7 +177,8 @@ export default {
|
|||
MenuDropdown,
|
||||
FilterDropdown,
|
||||
ColumnsModal,
|
||||
GeneralDropdown
|
||||
GeneralDropdown,
|
||||
ConfirmationModal
|
||||
},
|
||||
computed: {
|
||||
viewModesMenu() {
|
||||
|
@ -230,6 +245,12 @@ export default {
|
|||
},
|
||||
handleEvent(event) {
|
||||
this.$emit('toolbar:action', { name: event });
|
||||
},
|
||||
async resetToDefault() {
|
||||
const ok = await this.$refs.resetColumnModal.show();
|
||||
if (ok) {
|
||||
this.$emit('resetColumnsToDefault');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1551,8 +1551,13 @@ en:
|
|||
success_flash: "Successfully moved task(s) to experiment %{experiment}."
|
||||
error_flash: "Failed to move task(s) to experiment %{experiment}."
|
||||
column_display_modal:
|
||||
title: 'Columns display'
|
||||
title: 'Manage columns'
|
||||
description: 'Click the eye buttons to hide or show columns in the table'
|
||||
reset_to_default: 'Reset to default'
|
||||
confirmation:
|
||||
title: 'Reset to defaults'
|
||||
description_html: 'With confirmation the order, width and visibility of columns will be set to the default values.<br><br><b>Are you sure you want to to reset to default?</b>'
|
||||
confirm: 'Reset'
|
||||
id: 'ID'
|
||||
task_name: 'Task name'
|
||||
due_date: 'Due date'
|
||||
|
|
Loading…
Reference in a new issue