scinote-web/app/javascript/vue/projects/list.vue

354 lines
12 KiB
Vue
Raw Normal View History

2023-11-10 20:34:36 +08:00
<template>
2023-12-01 07:01:08 +08:00
<DataTable :columnDefs="columnDefs"
tableId="ProjectList"
2023-12-01 07:01:08 +08:00
:dataUrl="dataSource"
:reloadingTable="reloadingTable"
:toolbarActions="toolbarActions"
:actionsUrl="actionsUrl"
:activePageUrl="activePageUrl"
:archivedPageUrl="archivedPageUrl"
:currentViewMode="currentViewMode"
2024-01-23 18:08:42 +08:00
scrollMode="infinite"
2023-12-01 07:01:08 +08:00
:filters="filters"
:viewRenders="viewRenders"
@tableReloaded="reloadingTable = false"
@comments="openComments"
@archive="archive"
@restore="restore"
@edit="edit"
@create="create"
@create_folder="createFolder"
@delete_folders="deleteFolder"
@export="exportProjects"
@move="move"
2023-12-05 03:59:16 +08:00
@access="access"
2023-12-01 07:01:08 +08:00
>
<template #card="data">
<ProjectCard :params="data.params" :dtComponent="data.dtComponent" ></ProjectCard>
</template>
</DataTable>
2023-12-11 16:18:22 +08:00
<a href="#" ref="commentButton" class="open-comments-sidebar hidden"
data-turbolinks="false" data-object-type="Project" data-object-id=""></a>
2023-12-01 07:01:08 +08:00
<ConfirmationModal
:title="i18n.t('projects.index.modal_delete_folders.title')"
:description="folderDeleteDescription"
2023-12-05 03:59:16 +08:00
confirmClass="btn btn-danger"
2023-12-01 07:01:08 +08:00
:confirmText="i18n.t('projects.index.modal_delete_folders.confirm_button')"
ref="deleteFolderModal"
></ConfirmationModal>
<ConfirmationModal
:title="i18n.t('projects.export_projects.modal_title')"
:description="exportDescription"
2023-12-05 03:59:16 +08:00
confirmClass="btn btn-primary"
2023-12-01 07:01:08 +08:00
:confirmText="i18n.t('projects.export_projects.export_button')"
ref="exportModal"
></ConfirmationModal>
<ExportLimitExceededModal v-if="exportLimitExceded" :description="exportDescription" @close="exportLimitExceded = false"/>
2023-12-11 16:18:22 +08:00
<EditProjectModal v-if="editProject" :userRolesUrl="userRolesUrl"
:project="editProject" @close="editProject = null" @update="updateTable(); updateNavigator()" />
2023-12-11 16:18:22 +08:00
<EditFolderModal v-if="editFolder" :folder="editFolder"
@close="editFolder = null" @update="updateTable(); updateNavigator()" />
2023-12-11 16:18:22 +08:00
<NewProjectModal v-if="newProject" :createUrl="createUrl"
:currentFolderId="currentFolderId" :userRolesUrl="userRolesUrl"
@close="newProject = false" @create="updateTable(); updateNavigator()" />
2023-12-11 16:18:22 +08:00
<NewFolderModal v-if="newFolder" :createFolderUrl="createFolderUrl"
:currentFolderId="currentFolderId" :viewMode="currentViewMode"
@close="newFolder = false" @create="updateTable(); updateNavigator()" />
2023-12-11 16:18:22 +08:00
<MoveModal v-if="objectsToMove" :moveToUrl="moveToUrl"
:selectedObjects="objectsToMove" :foldersTreeUrl="foldersTreeUrl"
@close="objectsToMove = null" @move="updateTable(); updateNavigator(true)" />
2023-12-11 16:18:22 +08:00
<AccessModal v-if="accessModalParams" :params="accessModalParams"
@close="accessModalParams = null" @refresh="this.reloadingTable = true" />
2023-11-10 20:34:36 +08:00
</template>
<script>
2023-12-11 16:18:22 +08:00
/* global HelperModule */
2023-11-10 20:34:36 +08:00
import axios from '../../packs/custom_axios.js';
2023-12-11 16:18:22 +08:00
import DataTable from '../shared/datatable/table.vue';
import UsersRenderer from './renderers/users.vue';
import NameRenderer from './renderers/name.vue';
import CommentsRenderer from '../shared/datatable/renderers/comments.vue';
2023-12-11 16:18:22 +08:00
import ProjectCard from './card.vue';
import ConfirmationModal from '../shared/confirmation_modal.vue';
import EditProjectModal from './modals/edit.vue';
import EditFolderModal from './modals/edit_folder.vue';
import NewProjectModal from './modals/new.vue';
import NewFolderModal from './modals/new_folder.vue';
import MoveModal from './modals/move.vue';
import AccessModal from '../shared/access_modal/modal.vue';
import ExportLimitExceededModal from './modals/export_limit_exceeded_modal.vue';
2023-11-10 20:34:36 +08:00
export default {
name: 'ProjectsList',
components: {
DataTable,
UsersRenderer,
NameRenderer,
2023-12-01 07:01:08 +08:00
ProjectCard,
ConfirmationModal,
EditProjectModal,
EditFolderModal,
NewProjectModal,
NewFolderModal,
2023-12-05 03:59:16 +08:00
MoveModal,
AccessModal,
ExportLimitExceededModal
2023-11-10 20:34:36 +08:00
},
props: {
2023-12-01 07:01:08 +08:00
dataSource: { type: String, required: true },
actionsUrl: { type: String, required: true },
createUrl: { type: String },
createFolderUrl: { type: String },
activePageUrl: { type: String },
archivedPageUrl: { type: String },
currentViewMode: { type: String, required: true },
usersFilterUrl: { type: String },
userRolesUrl: { type: String },
currentFolderId: { type: String },
foldersTreeUrl: { type: String },
2024-02-19 20:01:37 +08:00
moveToUrl: { type: String }
2023-11-10 20:34:36 +08:00
},
data() {
return {
2023-12-05 03:59:16 +08:00
accessModalParams: null,
2023-12-01 07:01:08 +08:00
newProject: false,
newFolder: false,
editProject: null,
editFolder: null,
objectsToMove: null,
2023-11-10 20:34:36 +08:00
reloadingTable: false,
exportLimitExceded: false,
2023-12-01 07:01:08 +08:00
folderDeleteDescription: '',
exportDescription: ''
2023-12-11 16:18:22 +08:00
};
2023-11-10 20:34:36 +08:00
},
computed: {
columnDefs() {
const columns = [{
field: 'name',
flex: 1,
headerName: this.i18n.t('projects.index.card.name'),
sortable: true,
cellRenderer: 'NameRenderer'
},
{
field: 'code',
headerName: this.i18n.t('projects.index.card.id'),
2024-02-20 17:37:17 +08:00
sortable: true
},
{
field: 'created_at',
headerName: this.i18n.t('projects.index.card.start_date'),
2024-02-20 17:37:17 +08:00
sortable: true
},
{
field: 'updated_at',
headerName: this.i18n.t('projects.index.card.updated_at'),
sortable: true
},
{
field: 'users',
headerName: this.i18n.t('projects.index.card.users'),
cellRenderer: 'UsersRenderer',
sortable: true,
minWidth: 210,
notSelectable: true
},
{
field: 'comments',
headerName: this.i18n.t('projects.index.card.comments'),
sortable: true,
cellRenderer: CommentsRenderer,
notSelectable: true
2024-02-20 17:37:17 +08:00
}];
if (this.currentViewMode === 'archived') {
columns.push({
field: 'archived_on',
headerName: this.i18n.t('projects.index.card.archived_date'),
sortable: true
});
}
return columns;
},
2023-12-01 07:01:08 +08:00
viewRenders() {
return [
2023-12-11 16:18:22 +08:00
{ type: 'table' },
2024-02-19 20:01:37 +08:00
{ type: 'cards' }
2023-12-11 16:18:22 +08:00
];
2023-12-01 07:01:08 +08:00
},
2023-11-10 20:34:36 +08:00
toolbarActions() {
2023-12-11 16:18:22 +08:00
const left = [];
2023-12-01 07:01:08 +08:00
if (this.createUrl && this.currentViewMode !== 'archived') {
2023-11-10 20:34:36 +08:00
left.push({
name: 'create',
icon: 'sn-icon sn-icon-new-task',
label: this.i18n.t('projects.index.new'),
type: 'emit',
path: this.createUrl,
2024-02-19 20:01:37 +08:00
buttonStyle: 'btn btn-primary'
2023-12-11 16:18:22 +08:00
});
2023-11-10 20:34:36 +08:00
}
if (this.createFolderUrl) {
left.push({
name: 'create_folder',
icon: 'sn-icon sn-icon-folder',
label: this.i18n.t('projects.index.new_folder'),
type: 'emit',
path: this.createFolderUrl,
2024-02-19 20:01:37 +08:00
buttonStyle: 'btn btn-light'
2023-12-11 16:18:22 +08:00
});
2023-11-10 20:34:36 +08:00
}
return {
2023-12-11 16:18:22 +08:00
left,
2024-02-19 20:01:37 +08:00
right: []
2023-12-11 16:18:22 +08:00
};
2023-11-24 18:08:28 +08:00
},
filters() {
2023-12-11 16:18:22 +08:00
const filters = [
{
key: 'query',
2024-02-19 20:01:37 +08:00
type: 'Text'
2023-12-11 16:18:22 +08:00
},
{
key: 'created_at',
type: 'DateRange',
2024-02-19 20:01:37 +08:00
label: this.i18n.t('filters_modal.created_on.label')
}
2023-12-11 16:18:22 +08:00
];
2023-11-24 18:08:28 +08:00
if (this.currentViewMode === 'archived') {
filters.push({
key: 'archived_at',
type: 'DateRange',
2024-02-19 20:01:37 +08:00
label: this.i18n.t('filters_modal.archived_on.label')
2023-12-11 16:18:22 +08:00
});
2023-11-24 18:08:28 +08:00
}
2023-12-01 07:01:08 +08:00
filters.push({
key: 'members',
type: 'Select',
optionsUrl: this.usersFilterUrl,
optionRenderer: this.usersFilterRenderer,
labelRenderer: this.usersFilterRenderer,
2023-12-11 16:18:22 +08:00
label: this.i18n.t('projects.index.filters_modal.members.label'),
2024-02-19 20:01:37 +08:00
placeholder: this.i18n.t('projects.index.filters_modal.members.placeholder')
2023-12-11 16:18:22 +08:00
});
2023-12-01 07:01:08 +08:00
2023-11-24 18:08:28 +08:00
filters.push({
key: 'folder_search',
type: 'Checkbox',
2024-02-19 20:01:37 +08:00
label: this.i18n.t('projects.index.filters_modal.folders.label')
2023-12-11 16:18:22 +08:00
});
2023-11-24 18:08:28 +08:00
2023-12-11 16:18:22 +08:00
return filters;
2023-12-12 19:17:38 +08:00
}
2023-11-10 20:34:36 +08:00
},
methods: {
2023-12-01 07:01:08 +08:00
usersFilterRenderer(option) {
return `<div class="flex items-center gap-2">
<img src="${option[2].avatar_url}" class="rounded-full w-6 h-6" />
<span title="${option[1]}" class="truncate">${option[1]}</span>
2023-12-11 16:18:22 +08:00
</div>`;
2023-12-01 07:01:08 +08:00
},
openComments(_params, rows) {
$(this.$refs.commentButton).data('objectId', rows[0].id);
2023-12-01 07:01:08 +08:00
this.$refs.commentButton.click();
},
2023-12-05 03:59:16 +08:00
access(event, rows) {
this.accessModalParams = {
object: rows[0],
2024-02-19 20:01:37 +08:00
roles_path: this.userRolesUrl
2023-12-11 16:18:22 +08:00
};
2023-12-05 03:59:16 +08:00
},
2023-12-01 07:01:08 +08:00
async archive(event, rows) {
axios.post(event.path, { project_ids: rows.map((row) => row.id) }).then((response) => {
this.reloadingTable = true;
HelperModule.flashAlertMsg(response.data.message, 'success');
this.updateNavigator(false);
}).catch((error) => {
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
});
2023-12-01 07:01:08 +08:00
},
restore(event, rows) {
axios.post(event.path, { project_ids: rows.map((row) => row.id) }).then((response) => {
2023-12-11 16:18:22 +08:00
this.reloadingTable = true;
2023-12-01 07:01:08 +08:00
HelperModule.flashAlertMsg(response.data.message, 'success');
this.updateNavigator(false);
2023-12-01 07:01:08 +08:00
}).catch((error) => {
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
});
},
edit(event, rows) {
if (rows[0].folder) {
2023-12-11 16:18:22 +08:00
[this.editFolder] = rows;
return;
2023-12-01 07:01:08 +08:00
}
2023-12-11 16:18:22 +08:00
[this.editProject] = rows;
2023-12-01 07:01:08 +08:00
},
create() {
this.newProject = true;
},
createFolder() {
this.newFolder = true;
},
updateTable() {
this.editProject = null;
this.editFolder = null;
this.newProject = false;
this.newFolder = false;
this.objectsToMove = null;
this.reloadingTable = true;
this.exportLimitExceded = false;
2023-12-01 07:01:08 +08:00
},
updateNavigator(withExpanedChildren = false) {
window.navigatorContainer.reloadNavigator(withExpanedChildren);
},
2023-12-01 07:01:08 +08:00
async deleteFolder(event, rows) {
2023-12-11 16:18:22 +08:00
const description = `
<p>${this.i18n.t('projects.index.modal_delete_folders.description_1_html', { number: rows.length })}</p>
<p>${this.i18n.t('projects.index.modal_delete_folders.description_2')}</p>`;
2023-12-01 07:01:08 +08:00
this.folderDeleteDescription = description;
const ok = await this.$refs.deleteFolderModal.show();
if (ok) {
axios.post(event.path, { project_folder_ids: rows.map((row) => row.id) }).then((response) => {
2023-12-11 16:18:22 +08:00
this.reloadingTable = true;
2023-12-01 07:01:08 +08:00
HelperModule.flashAlertMsg(response.data.message, 'success');
}).catch((error) => {
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
});
}
},
async exportProjects(event, rows) {
if (event.number_of_projects === 0) {
HelperModule.flashAlertMsg(this.i18n.t('projects.export_projects.zero_projects_flash'), 'danger');
} else if (event.number_of_request_left > 0) {
this.exportDescription = event.message;
const ok = await this.$refs.exportModal.show();
if (ok) {
axios.post(event.path, {
project_ids: rows.filter((row) => !row.folder).map((row) => row.id),
project_folder_ids: rows.filter((row) => row.folder).map((row) => row.id)
}).then((response) => {
this.reloadingTable = true;
HelperModule.flashAlertMsg(response.data.flash, 'success');
}).catch((error) => {
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
});
}
} else {
this.exportDescription = event.message;
this.exportLimitExceded = true;
2023-12-01 07:01:08 +08:00
}
},
move(event, rows) {
this.objectsToMove = rows;
2023-12-28 03:09:36 +08:00
}
}
2023-12-11 16:18:22 +08:00
};
2023-11-10 20:34:36 +08:00
</script>