ListMixin use composition api

pull/4493/head
Angel Fernando Quiroz Campos 3 years ago
parent a4187fea4c
commit 40ca3cbc94
  1. 12
      assets/css/scss/molecules/_toolbar.scss
  2. 383
      assets/css/scss/organisms/_datatable.scss
  3. 59
      assets/vue/composables/datatableList.js
  4. 112
      assets/vue/mixins/list/index.js
  5. 34
      assets/vue/store/modules/crud.js
  6. 592
      assets/vue/views/documents/List.vue

@ -0,0 +1,12 @@
.p-toolbar {
@apply border-b border-solid border-gray-30 pb-4 mb-4;
&-group-left,
&-group-right {
@apply flex flex-row gap-2;
}
&-separator {
}
}

@ -0,0 +1,383 @@
.p-datatable {
&-header,
&-footer {
@apply bg-gray-10 text-gray-90 border-solid border-gray-30 p-3 text-caption-bold;
}
&-header {
@apply border-b;
}
&-footer {
@apply border-t;
}
.p-paginator {
@apply p-3 gap-3;
&-top,
&-bottom {
@apply border-0;
}
&-current {
@apply mr-auto;
}
&-pages {
@apply space-x-3;
}
&-rpp-options {
@apply ml-auto;
}
}
&-thead {
> tr {
> th {
@apply p-3 border-b border-solid border-gray-30 text-body-1-bold bg-gray-15 text-gray-90;
}
}
}
&-tbody {
> tr {
@apply focus:outline focus:outline-1 focus:outline-primary focus:-outline-offset-1;
> td {
@apply p-3 border-b border-solid border-gray-30 text-body-2 text-gray-90;
}
&.p-highlight {
@apply bg-support-1;
}
}
}
&-tfoot {
> tr {
> td {
@apply p-3 border-b border-solid border-gray-30 text-body-1-bold text-gray-90;
}
}
}
.p-sortable-column {
@apply outline-none
hover:text-primary;
&-icon {
@apply ml-2;
}
&.p-highlight {
@apply text-primary bg-support-1;
}
.p-sortable-column-badge {
@apply rounded-full ml-2 text-tiny-bold px-1.5 bg-white;
}
}
&.p-datatable-striped {
.p-datatable-tbody {
> tr {
@apply even:bg-gray-5;
}
}
}
&.p-datatable-sm {
.p-datatable-header,
.p-datatable-footer {
@apply p-2;
}
.p-datatable-thead > tr > th,
.p-datatable-tbody > tr > td,
.p-datatable-tfoot > tr > td {
@apply p-2;
}
}
&.p-datatable-lg {
.p-datatable-header,
.p-datatable-footer {
@apply p-4;
}
.p-datatable-thead > tr > th,
.p-datatable-tbody > tr > td,
.p-datatable-tfoot > tr > td {
@apply py-4;
}
}
}
$color_1: #71717A;
$color_2: #18181B;
$color_3: #3f3f46;
$background-color_1: #fafafa;
$border-color_1: transparent;
.p-datatable {
.p-datatable-tbody {
>tr {
>td {
.p-row-toggler {
width: 2rem;
height: 2rem;
color: $color_1;
border: 0 none;
background: transparent;
border-radius: 50%;
transition: none;
&:enabled {
&:hover {
color: $color_2;
border-color: $border-color_1;
background: #f4f4f5;
}
}
&:focus {
outline: 0 none;
outline-offset: 0;
box-shadow: 0 0 0 1px #6366F1;
}
}
.p-row-editor-init {
width: 2rem;
height: 2rem;
color: $color_1;
border: 0 none;
background: transparent;
border-radius: 50%;
transition: none;
&:enabled {
&:hover {
color: $color_2;
border-color: $border-color_1;
background: #f4f4f5;
}
}
&:focus {
outline: 0 none;
outline-offset: 0;
box-shadow: 0 0 0 1px #6366F1;
}
}
.p-row-editor-save {
width: 2rem;
height: 2rem;
color: $color_1;
border: 0 none;
background: transparent;
border-radius: 50%;
transition: none;
margin-right: 0.5rem;
&:enabled {
&:hover {
color: $color_2;
border-color: $border-color_1;
background: #f4f4f5;
}
}
&:focus {
outline: 0 none;
outline-offset: 0;
box-shadow: 0 0 0 1px #6366F1;
}
}
.p-row-editor-cancel {
width: 2rem;
height: 2rem;
color: $color_1;
border: 0 none;
background: transparent;
border-radius: 50%;
transition: none;
&:enabled {
&:hover {
color: $color_2;
border-color: $border-color_1;
background: #f4f4f5;
}
}
&:focus {
outline: 0 none;
outline-offset: 0;
box-shadow: 0 0 0 1px #6366F1;
}
}
>.p-column-title {
font-weight: 500;
}
}
}
>tr.p-datatable-dragpoint-top {
>td {
box-shadow: inset 0 2px 0 0 #EEF2FF;
box-shadow: inset 0 2px 0 0 #4F46E5;
}
}
>tr.p-datatable-dragpoint-bottom {
>td {
box-shadow: inset 0 -2px 0 0 #EEF2FF;
box-shadow: inset 0 -2px 0 0 #4F46E5;
}
}
}
.p-column-resizer-helper {
background: #4F46E5;
}
.p-datatable-scrollable-header {
background: #fafafa;
}
.p-datatable-scrollable-footer {
background: #fafafa;
}
.p-datatable-loading-icon {
font-size: 2rem;
}
}
.p-datatable.p-datatable-hoverable-rows {
.p-datatable-tbody {
>tr {
&:not(.p-highlight) {
&:hover {
background: #f4f4f5;
color: $color_3;
}
}
}
}
}
.p-datatable.p-datatable-scrollable {
>.p-datatable-wrapper {
>.p-datatable-table {
>.p-datatable-thead {
background-color: $background-color_1;
}
>.p-datatable-tfoot {
background-color: $background-color_1;
}
}
}
}
.p-datatable.p-datatable-gridlines {
.p-datatable-header {
border-width: 1px 1px 0 1px;
}
.p-datatable-footer {
border-width: 0 1px 1px 1px;
}
.p-paginator-top {
border-width: 0 1px 0 1px;
}
.p-paginator-bottom {
border-width: 0 1px 1px 1px;
}
.p-datatable-thead {
>tr {
>th {
border-width: 1px 1px 1px 1px;
}
}
}
.p-datatable-tbody {
>tr {
>td {
border-width: 1px;
}
}
}
.p-datatable-tfoot {
>tr {
>td {
border-width: 1px;
}
}
}
}
.p-datatable.p-datatable-gridlines.p-datatable-scrollable {
.p-datatable-thead {
>tr {
>th {
+ {
th {
border-left-width: 0;
}
}
}
}
}
.p-datatable-tbody {
>tr {
>td {
+ {
td {
border-left-width: 0;
}
}
}
+ {
tr {
>td {
border-top-width: 0;
}
}
}
&:first-child {
>td {
border-top-width: 0;
}
}
}
}
.p-datatable-tfoot {
>tr {
>td {
+ {
td {
border-left-width: 0;
}
}
}
}
}
}

@ -0,0 +1,59 @@
import { useStore } from 'vuex'
import { ref } from 'vue'
import { useRoute } from 'vue-router'
import { isEmpty } from 'lodash'
import { useCidReq } from './cidReq'
export function useDatatableList (servicePrefix) {
const moduleName = servicePrefix.toLowerCase()
const store = useStore()
const route = useRoute()
const { cid, sid, gid } = useCidReq()
const filters = ref({})
const expandedFilter = ref(false)
const options = ref({
sortBy: [],
sortDesc: false,
page: 1,
itemsPerPage: 5,
})
function onUpdateOptions ({ page, itemsPerPage, sortBy, sortDesc }) {
page = page || options.value.page
let params = { ...filters.value }
if (1 === filters.value.loadNode) {
console.log('params', route.params)
params['resourceNode.parent'] = route.params.node
}
if (itemsPerPage > 0) {
params = { ...params, itemsPerPage, page }
}
if (!isEmpty(sortBy)) {
params[`order[${sortBy}]`] = sortDesc ? 'desc' : 'asc'
}
let type = route.query.type
params = { ...params, cid, sid, gid, type, page }
store.dispatch(`${moduleName}/fetchAll`, params)
.then(() => options.value = { sortBy, sortDesc, itemsPerPage, page })
}
return {
filters,
expandedFilter,
options,
onUpdateOptions,
}
}

@ -1,112 +0,0 @@
import { useStore } from 'vuex';
import { computed, ref } from 'vue';
import { useRoute } from 'vue-router';
import { isEmpty } from 'lodash';
import { useCidReq } from '../../composables/cidReq';
export function useList (moduleName) {
const store = useStore();
const route = useRoute();
const { cid, sid, gid } = useCidReq();
const pagination = ref({
sortBy: 'resourceNode.title',
descending: false,
page: 1, // page to be displayed
rowsPerPage: 10, // maximum displayed rows
rowsNumber: 10, // max number of rows
});
const nextPage = ref(null);
const filters = ref({});
const filtration = ref({});
const expandedFilter = ref(false);
const options = ref({
sortBy: [],
sortDesc: [],
page: 1,
itemsPerPage: 10
});
const resetList = computed(() => store.state[`${moduleName}/resetList`]);
function onRequest (props) {
console.log('onRequest');
console.log(props);
const { page, rowsPerPage: itemsPerPage, sortBy, descending } = props.pagination;
nextPage.value = page;
if (isEmpty(nextPage)) {
nextPage.value = 1;
}
let params = {};
if (itemsPerPage > 0) {
params = { ...params, itemsPerPage, page };
}
if (sortBy) {
params[`order[${sortBy}]`] = descending ? 'desc' : 'asc';
}
if (route.params.node) {
params[`resourceNode.parent`] = route.params.node;
}
resetList.value = true;
store.dispatch(`${moduleName}/fetchAll`, params)
.then(() => {
pagination.value.sortBy = sortBy;
pagination.value.descending = descending;
pagination.value.rowsPerPage = itemsPerPage;
});
}
function onUpdateOptions ({ page, itemsPerPage, sortBy, sortDesc, totalItems }) {
console.log('ListMixin.js: onUpdateOptions');
resetList.value = true;
let params = { ...filters.value };
console.log(params);
if (1 === filters.value['loadNode']) {
params['resourceNode.parent'] = route.params.node;
}
if (itemsPerPage > 0) {
params = { ...params, itemsPerPage, page };
}
if (!isEmpty(sortBy)) {
params[`order[${sortBy}]`] = sortDesc ? 'desc' : 'asc';
}
let type = route.query.type;
params = { ...params, cid, sid, gid, type };
store.dispatch(`${moduleName}/fetchAll`, params)
.then(() => options.value = { sortBy, sortDesc, itemsPerPage, totalItems });
}
return {
pagination,
nextPage,
filters,
filtration,
expandedFilter,
options,
onRequest,
onUpdateOptions,
};
}

@ -20,6 +20,7 @@ const initialState = () => ({
resourceNode: null, resourceNode: null,
course: null, course: null,
session: null, session: null,
recents: [],
}); });
const handleError = (commit, e) => { const handleError = (commit, e) => {
@ -58,6 +59,7 @@ export const ACTIONS = {
SET_UPDATED: 'SET_UPDATED', SET_UPDATED: 'SET_UPDATED',
SET_VIEW: 'SET_VIEW', SET_VIEW: 'SET_VIEW',
SET_VIOLATIONS: 'SET_VIOLATIONS', SET_VIOLATIONS: 'SET_VIOLATIONS',
SET_RECENTS: 'SET_RECENTS',
TOGGLE_LOADING: 'TOGGLE_LOADING', TOGGLE_LOADING: 'TOGGLE_LOADING',
ADD_RESOURCE_NODE: 'ADD_RESOURCE_NODE', ADD_RESOURCE_NODE: 'ADD_RESOURCE_NODE',
ADD_COURSE: 'ADD_COURSE', ADD_COURSE: 'ADD_COURSE',
@ -131,21 +133,17 @@ export default function makeCrudModule({
delMultiple: ({ commit }, items) => { delMultiple: ({ commit }, items) => {
commit(ACTIONS.TOGGLE_LOADING); commit(ACTIONS.TOGGLE_LOADING);
const promises = items.map(async item => { const promises = items.map(async item => {
const result = await service.del(item).then(() => { const result = await service.del(item);
//commit(ACTIONS.TOGGLE_LOADING);
commit(ACTIONS.SET_DELETED_MULTIPLE, item); commit(ACTIONS.SET_DELETED_MULTIPLE, item);
});
return result; return result;
}); });
const result = Promise.all(promises); return Promise.all(promises)
.then(() => {
if (result) { commit(ACTIONS.TOGGLE_LOADING);
commit(ACTIONS.TOGGLE_LOADING); });
}
return result;
}, },
findAll: ({ commit, state }, params) => { findAll: ({ commit, state }, params) => {
if (!service) throw new Error('No service specified!'); if (!service) throw new Error('No service specified!');
@ -176,6 +174,7 @@ export default function makeCrudModule({
commit(ACTIONS.TOGGLE_LOADING); commit(ACTIONS.TOGGLE_LOADING);
commit(ACTIONS.SET_TOTAL_ITEMS, retrieved['hydra:totalItems']); commit(ACTIONS.SET_TOTAL_ITEMS, retrieved['hydra:totalItems']);
commit(ACTIONS.SET_VIEW, retrieved['hydra:view']); commit(ACTIONS.SET_VIEW, retrieved['hydra:view']);
commit(ACTIONS.SET_RECENTS, retrieved['hydra:member']);
if (true === state.resetList) { if (true === state.resetList) {
commit(ACTIONS.RESET_LIST); commit(ACTIONS.RESET_LIST);
} }
@ -383,6 +382,18 @@ export default function makeCrudModule({
getSession: (state) => { getSession: (state) => {
return state.session; return state.session;
}, },
getDeleted (state) {
return state.deleted;
},
getTotalItems: (state) => {
return state.totalItems;
},
getRecents: (state) => {
return state.recents;
},
isLoading (state) {
return state.isLoading;
}
}, },
mutations: { mutations: {
updateField, updateField,
@ -420,6 +431,7 @@ export default function makeCrudModule({
} }
state.allIds.push(item['@id']); state.allIds.push(item['@id']);
}, },
[ACTIONS.SET_RECENTS]: (state, items) => state.recents = items,
[ACTIONS.RESET_CREATE]: state => { [ACTIONS.RESET_CREATE]: state => {
Object.assign(state, { Object.assign(state, {
isLoading: false, isLoading: false,

@ -1,40 +1,39 @@
<template> <template>
<div <Toolbar v-if="isAuthenticated && isCurrentTeacher">
v-if="isAuthenticated && isCurrentTeacher" <template #start>
class="flex flex-row gap-2 mb-3" <Button
> :label="t('New folder')"
<Button class="p-button-plain p-button-outlined"
class="btn btn--primary" icon="mdi mdi-folder-plus"
icon="mdi mdi-folder-plus" @click="openNew"
:label="t('New folder')" />
@click="openNew" <Button
/> :label="t('New document')"
<Button class="p-button-plain p-button-outlined"
class="btn btn--primary" icon="mdi mdi-file-plus"
:label="t('New document')" @click="goToNewDocument"
icon="mdi mdi-file-plus" />
@click="addDocumentHandler()" <Button
/> :label="t('Upload')"
<Button class="p-button-plain p-button-outlined"
class="btn btn--primary" icon="mdi mdi-file-upload"
:label="t('Upload')" @click="goToUploadFile"
icon="mdi mdi-file-upload" />
@click="uploadDocumentHandler()" <!--
/> <Button label="{{ $t('Download') }}" class="btn btn--primary" @click="downloadDocumentHandler()" :disabled="!selectedItems || !selectedItems.length">
<!-- <v-icon icon="mdi-file-download"/>
<Button label="{{ $t('Download') }}" class="btn btn--primary" @click="downloadDocumentHandler()" :disabled="!selectedItems || !selectedItems.length"> {{ $t('Download') }}
<v-icon icon="mdi-file-download"/> </Button>
{{ $t('Download') }} -->
</Button> <Button
--> :disabled="!selectedItems || !selectedItems.length"
<Button :label="t('Delete selected')"
:disabled="!selectedItems || !selectedItems.length" class="p-button-danger p-button-outlined"
class="btn btn--danger " icon="mdi mdi-delete"
:label="t('Delete selected')" @click="confirmDeleteMultiple"
icon="mdi mdi-delete" />
@click="confirmDeleteMultiple" </template>
/> </Toolbar>
</div>
<DataTable <DataTable
v-model:filters="filters" v-model:filters="filters"
@ -43,16 +42,16 @@
:lazy="true" :lazy="true"
:loading="isLoading" :loading="isLoading"
:paginator="true" :paginator="true"
:rows="10" :rows="options.itemsPerPage"
:rows-per-page-options="[5, 10, 20, 50]" :rows-per-page-options="[5, 10, 20, 50]"
:total-records="totalItems" :total-records="totalItems"
:value="items" :value="items"
class="p-datatable-sm"
current-page-report-template="Showing {first} to {last} of {totalRecords}" current-page-report-template="Showing {first} to {last} of {totalRecords}"
data-key="iid" data-key="iid"
filter-display="menu" filter-display="menu"
paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown" paginator-template="CurrentPageReport FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink RowsPerPageDropdown"
responsive-layout="scroll" responsive-layout="scroll"
striped-rows
@page="onPage($event)" @page="onPage($event)"
@sort="sortingChanged($event)" @sort="sortingChanged($event)"
> >
@ -60,7 +59,6 @@
v-if="isCurrentTeacher" v-if="isCurrentTeacher"
:exportable="false" :exportable="false"
selection-mode="multiple" selection-mode="multiple"
header-style="width: 3rem"
/> />
<Column <Column
@ -75,10 +73,10 @@
<div v-else> <div v-else>
<Button <Button
v-if="slotProps.data" v-if="slotProps.data"
:label="slotProps.data.resourceNode.title"
class="p-button-text p-button-plain" class="p-button-text p-button-plain"
icon="mdi mdi-folder" icon="mdi mdi-folder"
:label="slotProps.data.resourceNode.title" @click="btnFolderOnClick(slotProps.data)"
@click="handleClick(slotProps.data)"
/> />
</div> </div>
</template> </template>
@ -102,36 +100,38 @@
field="resourceNode.updatedAt" field="resourceNode.updatedAt"
> >
<template #body="slotProps"> <template #body="slotProps">
{{ $filters.relativeDatetime(slotProps.data.resourceNode.updatedAt) }} {{ useRelativeDatetime(slotProps.data.resourceNode.updatedAt) }}
</template> </template>
</Column> </Column>
<Column :exportable="false"> <Column
:exportable="false"
>
<template #body="slotProps"> <template #body="slotProps">
<div class="flex flex-row gap-2"> <div class="flex flex-row justify-end gap-2">
<Button <Button
class="p-button-icon-only" class="p-button-icon-only p-button-plain p-button-outlined p-button-sm"
icon="mdi mdi-information" icon="mdi mdi-information"
@click="showHandler(slotProps.data)" @click="btnShowInformationOnClick(slotProps.data)"
/> />
<Button <Button
v-if="isAuthenticated && isCurrentTeacher" v-if="isAuthenticated && isCurrentTeacher"
class="p-button-icon-only"
:icon="RESOURCE_LINK_PUBLISHED === slotProps.data.resourceLinkListFromEntity[0].visibility ? 'mdi mdi-eye' : (RESOURCE_LINK_DRAFT === slotProps.data.resourceLinkListFromEntity[0].visibility ? 'mdi mdi-eye-off' : '')" :icon="RESOURCE_LINK_PUBLISHED === slotProps.data.resourceLinkListFromEntity[0].visibility ? 'mdi mdi-eye' : (RESOURCE_LINK_DRAFT === slotProps.data.resourceLinkListFromEntity[0].visibility ? 'mdi mdi-eye-off' : '')"
@click="changeVisibilityHandler(slotProps.data, slotProps)" class="p-button-icon-only p-button-plain p-button-outlined p-button-sm"
@click="btnChangeVisibilityOnClick(slotProps.data)"
/> />
<Button <Button
v-if="isAuthenticated && isCurrentTeacher" v-if="isAuthenticated && isCurrentTeacher"
class="p-button-icon-only" class="p-button-icon-only p-button-plain p-button-outlined p-button-sm"
icon="mdi mdi-pencil" icon="mdi mdi-pencil"
@click="editHandler(slotProps.data)" @click="btnEditOnClick(slotProps.data)"
/> />
<Button <Button
v-if="isAuthenticated && isCurrentTeacher" v-if="isAuthenticated && isCurrentTeacher"
class="p-button-icon-only" class="p-button-icon-only p-button-danger p-button-outlined p-button-sm"
icon="mdi mdi-delete" icon="mdi mdi-delete"
@click="confirmDeleteItem(slotProps.data)" @click="confirmDeleteItem(slotProps.data)"
/> />
@ -147,27 +147,26 @@
:style="{width: '450px'}" :style="{width: '450px'}"
class="p-fluid" class="p-fluid"
> >
<div class="form__field"> <div class="p-float-label">
<div class="p-float-label"> <InputText
<InputText id="title"
id="title" v-model.trim="item.title"
v-model.trim="item.title" :class="{ 'p-invalid': submitted && !item.title }"
:class="{'p-invalid': submitted && !item.title}" autocomplete="off"
autocomplete="off" autofocus
autofocus name="name"
required="true" required="true"
/> />
<label <label
v-t="'Name'" v-t="'Name'"
for="name" for="name"
/>
</div>
<small
v-if="submitted && !item.title"
v-t="'Title is required'"
class="p-error"
/> />
</div> </div>
<small
v-if="submitted && !item.title"
v-t="'Title is required'"
class="p-error"
/>
<template #footer> <template #footer>
<Button <Button
@ -188,7 +187,7 @@
<Dialog <Dialog
v-model:visible="deleteItemDialog" v-model:visible="deleteItemDialog"
:modal="true" :modal="true"
:style="{width: '450px'}" :style="{ width: '450px' }"
header="Confirm" header="Confirm"
> >
<div class="confirmation-content"> <div class="confirmation-content">
@ -217,7 +216,7 @@
<Dialog <Dialog
v-model:visible="deleteMultipleDialog" v-model:visible="deleteMultipleDialog"
:modal="true" :modal="true"
:style="{width: '450px'}" :style="{ width: '450px' }"
header="Confirm" header="Confirm"
> >
<div class="confirmation-content"> <div class="confirmation-content">
@ -244,245 +243,264 @@
</Dialog> </Dialog>
</template> </template>
<script> <script setup>
import { mapActions, mapGetters, useStore } from 'vuex'; import { useStore } from 'vuex'
import { mapFields } from 'vuex-map-fields'; import ResourceFileLink from '../../components/documents/ResourceFileLink.vue'
import ListMixin from '../../mixins/ListMixin'; import { RESOURCE_LINK_DRAFT, RESOURCE_LINK_PUBLISHED } from '../../components/resource_links/visibility'
import ResourceFileLink from '../../components/documents/ResourceFileLink.vue'; import { isEmpty } from 'lodash'
import { RESOURCE_LINK_DRAFT, RESOURCE_LINK_PUBLISHED } from '../../components/resource_links/visibility'; import { useRoute, useRouter } from 'vue-router'
import { isEmpty } from 'lodash'; import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'; import Toolbar from 'primevue/toolbar'
import { useI18n } from 'vue-i18n'; import Dialog from 'primevue/dialog'
import Dialog from 'primevue/dialog'; import { computed, inject, onMounted, ref, watch } from 'vue'
import { computed, inject, ref } from 'vue'; import { useCidReq } from '../../composables/cidReq'
import { useCidReq } from '../../composables/cidReq'; import { useDatatableList } from '../../composables/datatableList'
import { useList } from '../../mixins/list'; import { useRelativeDatetime } from '../../composables/formatDate'
import axios from 'axios'
export default {
name: 'DocumentsList',
servicePrefix: 'Documents',
components: {
ResourceFileLink,
Dialog,
},
mixins: [ListMixin],
setup () {
const store = useStore();
const route = useRoute();
const { t } = useI18n();
const {
pagination,
filters,
options,
onRequest,
onUpdateOptions
} = useList('documents');
const flashMessageList = inject('flashMessageList');
const { cid, sid, gid } = useCidReq();
// Set resource node.
let nodeId = route.params.node;
if (isEmpty(nodeId)) {
nodeId = route.query.node;
}
store.dispatch('course/findCourse', { id: `/api/courses/${cid}` }); const store = useStore()
store.dispatch('resourcenode/findResourceNode', { id: `/api/resource_nodes/${nodeId}` }); const route = useRoute()
const router = useRouter()
const { t } = useI18n()
if (sid) { const { filters, options, onUpdateOptions } = useDatatableList('Documents')
store.dispatch('session/findSession', { id: `/api/sessions/${sid}` });
}
const item = ref({}); const flashMessageList = inject('flashMessageList')
const itemDialog = ref(false); const { cid, sid, gid } = useCidReq()
const deleteItemDialog = ref(false);
const deleteMultipleDialog = ref(false);
const isBusy = ref(false); store.dispatch('course/findCourse', { id: `/api/courses/${cid}` })
const submitted = ref(false); if (sid) {
store.dispatch('session/findSession', { id: `/api/sessions/${sid}` })
}
filters.loadNode = 1; const item = ref({})
const selected = ref([]); const itemDialog = ref(false)
const selectedItems = ref([]); const deleteItemDialog = ref(false)
const deleteMultipleDialog = ref(false)
const isAuthenticated = computed(() => store.getters['security/isAuthenticated']); const submitted = ref(false)
const isAdmin = computed(() => store.getters['security/isAdmin']);
const isCurrentTeacher = computed(() => store.getters['security/isCurrentTeacher']);
const resourceNode = computed(() => store.getters['resourcenode/getResourceNode']); filters.value.loadNode = 1
const items = computed(() => store.getters['documents/list']); const selectedItems = ref([])
const isLoading = computed(() => store.getters['documents/isLoading']);
function openNew () { const isAuthenticated = computed(() => store.getters['security/isAuthenticated'])
item.value = {}; const isCurrentTeacher = computed(() => store.getters['security/isCurrentTeacher'])
submitted.value = false;
itemDialog.value = true;
}
function hideDialog () { const items = computed(() => store.getters['documents/getRecents'])
itemDialog.value = false; const isLoading = computed(() => store.getters['documents/isLoading'])
submitted.value = false;
} const totalItems = computed(() => store.getters['documents/getTotalItems'])
onMounted(() => {
filters.value.loadNode = 1
// Set resource node.
let nodeId = route.params.node
if (isEmpty(nodeId)) {
nodeId = route.query.node
}
store.dispatch('resourcenode/findResourceNode', { id: `/api/resource_nodes/${nodeId}` });
function saveItem () { onUpdateOptions(options.value)
submitted.value = true; });
if (item.value.title.trim()) { watch(
if (!item.value.id) { () => route.params,
item.value.filetype = 'folder'; () => {
item.value.parentResourceNodeId = route.params.node; const nodeId = route.params.node
item.value.resourceLinkList = JSON.stringify([{
gid, const finderParams = { id: `/api/resource_nodes/${nodeId}`, cid, sid, gid };
sid,
cid, store.dispatch('resourcenode/findResourceNode', finderParams);
visibility: RESOURCE_LINK_PUBLISHED, // visible by default
}]); if ('DocumentsList' === route.name) {
onUpdateOptions(options.value);
store.dispatch('documents/createWithFormData', item.value) }
.then(() => flashMessageList.value.push({ }
);
function openNew () {
item.value = {}
submitted.value = false
itemDialog.value = true
}
function hideDialog () {
itemDialog.value = false
submitted.value = false
}
function saveItem () {
submitted.value = true
if (item.value.title?.trim()) {
if (!item.value.id) {
item.value.filetype = 'folder'
item.value.parentResourceNodeId = route.params.node
item.value.resourceLinkList = JSON.stringify([{
gid,
sid,
cid,
visibility: RESOURCE_LINK_PUBLISHED, // visible by default
}])
store.dispatch('documents/createWithFormData', item.value)
.then(() => {
flashMessageList.value.push({
severity: 'success', severity: 'success',
detail: t('Saved') detail: t('Saved')
})); })
}
itemDialog.value = false;
item.value = {};
}
}
function confirmDeleteMultiple () { onUpdateOptions(options.value)
deleteMultipleDialog.value = true; })
} }
itemDialog.value = false
item.value = {}
}
}
function confirmDeleteMultiple () {
deleteMultipleDialog.value = true
}
function confirmDeleteItem (newItem) {
item.value = newItem
deleteItemDialog.value = true
}
function deleteMultipleItems () {
store.dispatch('documents/delMultiple', selectedItems.value)
.then(() => {
deleteMultipleDialog.value = false
selectedItems.value = []
})
onUpdateOptions(options.value)
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Products Deleted', life: 3000});*/
}
function deleteItemButton () {
store.dispatch('documents/del', item.value)
.then(() => {
deleteItemDialog.value = false
item.value = {}
})
//this.items = this.items.filter(val => val.iid !== this.item.iid);
onUpdateOptions(options.value)
}
function onPage (event) {
options.value = {
itemsPerPage: event.rows,
page: event.page + 1,
sortBy: event.sortField,
sortDesc: event.sortOrder === -1
}
function confirmDeleteItem (newItem) { onUpdateOptions(options.value)
item.value = newItem; }
deleteItemDialog.value = true;
}
function deleteMultipleItems () { function sortingChanged (event) {
store.dispatch('documents/delMultiple', selectedItems) options.value.sortBy = event.sortField
.then(() => { options.value.sortDesc = event.sortOrder === -1
deleteMultipleDialog.value = false;
selectedItems.value = [];
});
onRequest({
pagination: pagination,
});
//this.$toast.add({severity:'success', summary: 'Successful', detail: 'Products Deleted', life: 3000});*/
}
function deleteItemButton () { onUpdateOptions(options.value)
store.dispatch('documents/del', item.value) }
.then(() => {
deleteItemDialog.value = false;
item.value = {};
})
//this.items = this.items.filter(val => val.iid !== this.item.iid);
//this.onUpdateOptions(options.value);
}
function onPage (event) { function goToNewDocument () {
options.value = { router.push({
itemsPerPage: event.rows, name: 'DocumentsCreateFile',
page: event.page + 1, query: route.query,
sortBy: event.sortField, })
sortDesc: event.sortOrder === -1 }
};
onUpdateOptions(options.value); function goToUploadFile () {
router.push({
name: 'DocumentsUploadFile',
query: route.query
})
}
function btnFolderOnClick (item) {
const folderParams = route.query;
const resourceId = item.resourceNode.id;
if (!resourceId) {
return;
}
filters.value['resourceNode.parent'] = resourceId;
router.push({
name: 'DocumentsList',
params: { node: resourceId },
query: folderParams,
});
}
function btnShowInformationOnClick (item) {
const folderParams = route.query;
if (item) {
folderParams.id = item['@id'];
}
router.push({
name: 'DocumentsShow',
params: folderParams,
query: folderParams
});
}
function btnChangeVisibilityOnClick (item) {
const folderParams = route.query;
folderParams.id = item['@id'];
axios
.put(item['@id'] + '/toggle_visibility')
.then(response => {
item.resourceLinkListFromEntity = response.data.resourceLinkListFromEntity;
})
;
}
function btnEditOnClick (item) {
const folderParams = route.query;
folderParams.id = item['@id'];
if ('folder' === item.filetype || isEmpty(item.filetype)) {
router.push({
name: 'DocumentsUpdate',
params: { id: item['@id'] },
query: folderParams,
});
return;
}
if ('file' === item.filetype) {
folderParams.getFile = true;
if (item.resourceNode.resourceFile
&& item.resourceNode.resourceFile.mimeType
&& 'text/html' === item.resourceNode.resourceFile.mimeType
) {
//folderParams.getFile = true;
} }
return { router.push({
RESOURCE_LINK_PUBLISHED, name: 'DocumentsUpdateFile',
RESOURCE_LINK_DRAFT, params: { id: item['@id'] },
query: folderParams
isAuthenticated, });
isAdmin,
isCurrentTeacher,
resourceNode,
items,
isLoading,
openNew,
hideDialog,
saveItem,
confirmDeleteItem,
confirmDeleteMultiple,
deleteMultipleItems,
deleteItemButton,
onPage,
sortBy: 'title',
sortDesc: false,
selected,
isBusy,
options,
selectedItems,
// prime vue
itemDialog,
deleteItemDialog,
deleteMultipleDialog,
item,
filters,
submitted,
t,
};
},
computed: {
// From crud.js list function
...mapGetters('resourcenode', {
resourceNode: 'getResourceNode'
}),
//...getters
// From ListMixin
...mapFields('documents', {
deletedResource: 'deleted',
error: 'error',
resetList: 'resetList',
totalItems: 'totalItems',
view: 'view'
}),
},
mounted () {
this.filters['loadNode'] = 1;
this.onUpdateOptions(this.options);
},
methods: {
sortingChanged (event) {
console.log('sortingChanged');
console.log(event);
this.options.sortBy = event.sortField;
this.options.sortDesc = event.sortOrder === -1;
this.onUpdateOptions(this.options);
// ctx.sortBy ==> Field key for sorting by (or null for no sorting)
// ctx.sortDesc ==> true if sorting descending, false otherwise
},
editItem (item) {
this.item = { ...item };
this.itemDialog = true;
},
//...actions,
// From ListMixin
...mapActions('documents', {
getPage: 'fetchAll',
deleteItem: 'del',
}),
...mapActions('resourcenode', {
findResourceNode: 'findResourceNode',
}),
} }
}; }
</script> </script>

Loading…
Cancel
Save