scinote-web/app/javascript/vue/shared/datatable/toolbar.vue

258 lines
7.8 KiB
Vue
Raw Normal View History

<template>
2023-11-24 18:08:28 +08:00
<div class="flex py-4 items-center justify-between">
<div class="flex flex-1 items-center gap-4">
2023-12-28 03:09:36 +08:00
<template v-for="action in toolbarActions.left" :key="action.label">
2024-01-11 02:56:01 +08:00
<a v-if="action.type === 'emit' || action.type === 'link'"
2023-12-28 03:09:36 +08:00
:class="action.buttonStyle"
:href="action.path"
@click="doAction(action, $event)">
<i :class="action.icon"></i>
{{ action.label }}
</a>
<MenuDropdown
v-if="action.type === 'menu'"
:listItems="action.menuItems"
:btnClasses="action.buttonStyle"
:btnText="action.label"
:btnIcon="action.icon"
:caret="true"
:position="'right'"
@dtEvent="handleEvent"
></MenuDropdown>
</template>
</div>
<div class="flex-none">
2023-12-12 19:17:38 +08:00
<div class="flex items-center gap-2">
2023-11-24 18:08:28 +08:00
<MenuDropdown
2023-12-28 03:09:36 +08:00
v-if="viewRenders"
2023-12-01 07:01:08 +08:00
:listItems="this.viewRendersMenu"
:btnClasses="'btn btn-light icon-btn'"
:btnText="i18n.t(`toolbar.${currentViewRender}_view`)"
:caret="true"
:position="'right'"
@setCardsView="$emit('setCardsView')"
@setTableView="$emit('setTableView')"
></MenuDropdown>
<MenuDropdown
v-if="archivedPageUrl"
:listItems="this.viewModesMenu"
2023-11-24 18:08:28 +08:00
:btnClasses="'btn btn-light icon-btn'"
:btnText="i18n.t(`projects.index.${currentViewMode}`)"
:caret="true"
:position="'right'"
></MenuDropdown>
</div>
</div>
<div class="flex flex-1 justify-end gap-2">
<a v-for="action in toolbarActions.right" :key="action.label"
:class="action.buttonStyle"
:href="action.path"
@click="doAction(action, $event)">
<i :class="action.icon"></i>
{{ action.label }}
</a>
<div class="sci-input-container-v2"
2023-12-11 16:18:22 +08:00
:class="{'w-48': showSearch, 'w-11': !showSearch}">
<input
ref="searchInput"
class="sci-input-field !pr-8"
type="text"
@focus="openSearch"
@blur="hideSearch"
:value="searchValue"
:placeholder="'Search...'"
@change="$emit('search:change', $event.target.value)"
/>
2023-12-28 03:09:36 +08:00
<i v-if="searchValue.length === 0" class="sn-icon sn-icon-search !m-2.5 !ml-auto right-0"></i>
<i v-else class="sn-icon sn-icon-close !m-2.5 !ml-auto right-0 cursor-pointer z-10"
@click="$emit('search:change', '')"></i>
</div>
<button
v-if="currentViewRender === 'table'"
@click="showColumnsModal = true"
:title="i18n.t('experiments.table.column_display_modal.title')"
class="btn btn-light icon-btn"
>
<i class="sn-icon sn-icon-reports"></i>
</button>
<FilterDropdown :filters="filters" @applyFilters="applyFilters" />
2024-01-12 00:42:17 +08:00
<GeneralDropdown v-if="currentViewRender === 'cards'" ref="dropdown" position="right">
<template v-slot:field>
<button class="btn btn-light icon-btn">
<i class="sn-icon sn-icon-sort-down"></i>
</button>
</template>
<template v-slot:flyout >
<div class="min-w-[12rem]">
<div v-for="col in sortableColumns"
class="flex whitespace-nowrap rounded px-3 py-2.5 hover:!text-sn-blue items-center h-11
hover:no-underline cursor-pointer hover:bg-sn-super-light-grey leading-5"
:key="col.field"
@click="$emit('sort', col.field, (order?.dir === 'asc' ? 'desc' : 'asc'))">
<span>{{ col.headerName }}</span>
<div v-if="order && order.column === col.field" class="ml-auto">
<i v-if="order.dir === 'asc'" class="sn-icon sn-icon-sort-up"></i>
<i v-else class="sn-icon sn-icon-sort-down"></i>
</div>
</div>
</div>
</template>
</GeneralDropdown>
</div>
2023-12-12 19:17:38 +08:00
<teleport to="body">
<ColumnsModal
:tableState="tableState"
: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"
2023-12-12 19:17:38 +08:00
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>
<script>
2023-12-11 16:18:22 +08:00
import MenuDropdown from '../menu_dropdown.vue';
2024-01-12 00:42:17 +08:00
import GeneralDropdown from '../general_dropdown.vue';
2023-11-24 18:08:28 +08:00
import FilterDropdown from '../filters/filter_dropdown.vue';
2023-12-12 19:17:38 +08:00
import ColumnsModal from './modals/columns.vue';
import ConfirmationModal from '../confirmation_modal.vue';
2023-11-24 18:08:28 +08:00
export default {
name: 'Toolbar',
props: {
toolbarActions: {
type: Object,
2023-12-12 19:17:38 +08:00
required: true
},
searchValue: {
2023-12-12 19:17:38 +08:00
type: String
2023-11-24 18:08:28 +08:00
},
activePageUrl: {
2023-12-12 19:17:38 +08:00
type: String
2023-11-24 18:08:28 +08:00
},
archivedPageUrl: {
2023-12-12 19:17:38 +08:00
type: String
2023-11-24 18:08:28 +08:00
},
currentViewMode: {
type: String,
2023-12-12 19:17:38 +08:00
default: 'active'
2023-11-24 18:08:28 +08:00
},
filters: {
type: Array,
2023-12-12 19:17:38 +08:00
default: () => []
2023-12-01 07:01:08 +08:00
},
viewRenders: {
2023-12-12 19:17:38 +08:00
required: true
2023-12-01 07:01:08 +08:00
},
currentViewRender: {
type: String,
2023-12-12 19:17:38 +08:00
required: true
},
columnDefs: {
type: Array,
required: true
2023-12-11 16:18:22 +08:00
},
2023-12-12 19:17:38 +08:00
tableState: {
type: Object
2024-01-12 00:42:17 +08:00
},
order: {
type: Object
2023-12-12 19:17:38 +08:00
}
2023-11-24 18:08:28 +08:00
},
components: {
MenuDropdown,
2023-12-11 16:18:22 +08:00
FilterDropdown,
2024-01-12 00:42:17 +08:00
ColumnsModal,
GeneralDropdown,
ConfirmationModal
2023-11-24 18:08:28 +08:00
},
computed: {
2023-12-01 07:01:08 +08:00
viewModesMenu() {
2023-11-24 18:08:28 +08:00
return [
2023-12-11 16:18:22 +08:00
{ text: this.i18n.t('projects.index.active'), url: this.activePageUrl },
2023-12-12 19:17:38 +08:00
{ text: this.i18n.t('projects.index.archived'), url: this.archivedPageUrl }
2023-12-11 16:18:22 +08:00
];
2023-12-01 07:01:08 +08:00
},
viewRendersMenu() {
return this.viewRenders.map((view) => {
2023-12-11 16:18:22 +08:00
const { type } = view;
2023-12-01 07:01:08 +08:00
switch (type) {
case 'cards':
2023-12-11 16:18:22 +08:00
return { text: this.i18n.t('toolbar.cards_view'), emit: 'setCardsView' };
2023-12-01 07:01:08 +08:00
case 'table':
2023-12-11 16:18:22 +08:00
return { text: this.i18n.t('toolbar.table_view'), emit: 'setTableView' };
2023-12-12 19:17:38 +08:00
case 'custom':
return { text: view.name, url: view.url };
2023-12-01 07:01:08 +08:00
default:
return view;
}
2023-12-11 16:18:22 +08:00
});
2024-01-12 00:42:17 +08:00
},
sortableColumns() {
return this.columnDefs.filter((column) => column.sortable);
2023-12-12 19:17:38 +08:00
}
},
data() {
return {
2023-12-11 16:18:22 +08:00
showSearch: false,
2023-12-12 19:17:38 +08:00
showColumnsModal: false
2023-12-11 16:18:22 +08:00
};
},
watch: {
searchValue() {
if (this.searchValue.length > 0) {
this.openSearch();
}
2023-12-12 19:17:38 +08:00
}
},
methods: {
openSearch() {
this.showSearch = true;
},
hideSearch() {
if (this.searchValue.length === 0) {
this.showSearch = false;
}
},
doAction(action, event) {
2023-12-11 16:18:22 +08:00
switch (action.type) {
case 'emit':
event.preventDefault();
this.$emit('toolbar:action', action);
break;
case 'link':
break;
2023-12-11 16:18:22 +08:00
default:
break;
}
2023-11-24 18:08:28 +08:00
},
applyFilters(filters) {
this.$emit('applyFilters', filters);
2023-12-28 03:09:36 +08:00
},
handleEvent(event) {
this.$emit('toolbar:action', { name: event });
},
async resetToDefault() {
const ok = await this.$refs.resetColumnModal.show();
if (ok) {
this.$emit('resetColumnsToDefault');
}
2023-12-12 19:17:38 +08:00
}
}
2023-12-11 16:18:22 +08:00
};
</script>