2021-05-26 08:52:11 +00:00
<!--
- @ copyright 2021 Christoph Wurst < christoph @ winzerhof -wurst .at >
-
- @ author 2021 Christoph Wurst < christoph @ winzerhof -wurst .at >
-
- @ license GNU AGPL version 3 or any later version
-
- This program is free software : you can redistribute it and / or modify
- it under the terms of the GNU Affero General Public License as
- published by the Free Software Foundation , either version 3 of the
- License , or ( at your option ) any later version .
-
- This program is distributed in the hope that it will be useful ,
- but WITHOUT ANY WARRANTY ; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
- GNU Affero General Public License for more details .
-
- You should have received a copy of the GNU Affero General Public License
- along with this program . If not , see < http : / / www.gnu.org / licenses / > .
-- >
< template >
2021-05-31 19:33:18 +00:00
< AppNavigationItem : title = "t('calendar', 'Trash bin')"
2021-05-26 08:52:11 +00:00
: pinned = "true"
icon = "icon-delete"
@ click . prevent = "onShow" >
< template # extra >
< Modal v -if = " showModal "
@ close = "showModal = false" >
< div class = "modal__content" >
2021-05-31 19:33:18 +00:00
< h2 > { { t ( 'calendar' , 'Trash bin' ) } } < / h2 >
2021-07-24 19:20:57 +00:00
< EmptyContent
v - if = "loading"
icon = "icon-loading"
class = "modal__content__loading" >
< template # desc >
{ { t ( 'calendar' , 'Loading deleted elements.' ) } }
< / template >
< / EmptyContent >
< EmptyContent
v - else - if = "!items.length"
class = "modal__content__empty"
icon = "icon-delete" >
< template # desc >
{ { t ( 'calendar' , 'You do not have any deleted elements.' ) } }
< / template >
< / EmptyContent >
< template v-else >
< table >
< tr >
< th class = "name" >
{ { t ( 'calendar' , 'Name' ) } }
< / th >
< th class = "deletedAt" >
{ { t ( 'calendar' , 'Deleted' ) } }
< / th >
< th > & nbsp ; < / th >
< / tr >
< tr v-for ="item in items" :key="item.url" >
< td >
< div class = "item" >
< div >
< div
class = "color-dot"
: style = "{ 'background-color': item.color }" / >
< / div >
2021-06-11 14:26:03 +00:00
2021-07-24 19:20:57 +00:00
< div >
< div > { { item . name } } < / div >
< div v-if ="item.subline" class="item-subline" >
{ { item . subline } }
< / div >
2021-06-11 14:26:03 +00:00
< / div >
< / div >
2021-07-24 19:20:57 +00:00
< / td >
< td class = "deletedAt" >
< Moment class = "timestamp" :timestamp ="item.deletedAt" / >
< / td >
< td >
< button @click ="restore(item)" >
{ { t ( 'calendar' , 'Restore' ) } }
< / button >
2021-05-31 19:33:18 +00:00
2021-07-24 19:20:57 +00:00
< Actions :force-menu ="true" >
< ActionButton
icon = "icon-delete"
@ click = "onDeletePermanently(item)" >
{ { t ( 'calendar' , 'Delete permanently' ) } }
< / ActionButton >
< / Actions >
< / td >
< / tr >
< / table >
< p v-if ="retentionDuration" class="footer" >
{ { n ( 'calendar' , 'Elements in the trash bin are deleted after {numDays} day' , 'Elements in the trash bin are deleted after {numDays} days' , retentionDuration , { numDays : retentionDuration } ) } }
< / p >
< / template >
2021-05-26 08:52:11 +00:00
< / div >
< / Modal >
< / template >
< / AppNavigationItem >
< / template >
< script >
import AppNavigationItem from '@nextcloud/vue/dist/Components/AppNavigationItem'
2021-05-31 19:33:18 +00:00
import Actions from '@nextcloud/vue/dist/Components/Actions'
import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
2021-05-26 08:52:11 +00:00
import Modal from '@nextcloud/vue/dist/Components/Modal'
2021-07-24 19:20:57 +00:00
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
2021-06-11 15:25:24 +00:00
import moment from '@nextcloud/moment'
2021-05-26 08:52:11 +00:00
import logger from '../../../utils/logger'
import { showError } from '@nextcloud/dialogs'
import { mapGetters } from 'vuex'
import Moment from './Moment'
2021-06-11 14:26:03 +00:00
import { uidToHexColor } from '../../../utils/color'
2021-05-26 08:52:11 +00:00
export default {
name : 'Trashbin' ,
components : {
AppNavigationItem ,
2021-07-24 19:20:57 +00:00
EmptyContent ,
2021-05-26 08:52:11 +00:00
Modal ,
Moment ,
2021-05-31 19:33:18 +00:00
Actions ,
ActionButton ,
2021-05-26 08:52:11 +00:00
} ,
data ( ) {
return {
showModal : false ,
2021-07-24 19:20:57 +00:00
loading : true ,
2021-05-26 08:52:11 +00:00
}
} ,
computed : {
... mapGetters ( [
'trashBin' ,
] ) ,
calendars ( ) {
return this . $store . getters . sortedDeletedCalendars
} ,
objects ( ) {
return this . $store . getters . deletedCalendarObjects
} ,
items ( ) {
const formattedCalendars = this . calendars . map ( calendar => ( {
calendar ,
type : 'calendar' ,
key : calendar . url ,
name : calendar . displayname ,
url : calendar . _url ,
deletedAt : calendar . _props [ '{http://nextcloud.com/ns}deleted-at' ] ,
2021-06-11 14:26:03 +00:00
color : calendar . color ? ? uidToHexColor ( calendar . displayname ) ,
2021-05-26 08:52:11 +00:00
} ) )
const formattedCalendarObjects = this . objects . map ( vobject => {
let eventSummary = t ( 'calendar' , 'Untitled event' )
try {
// TODO: there _has to be_ a less error prone way …
eventSummary = vobject . calendarComponent ? . _components ? . get ( 'VEVENT' ) [ 0 ] ? . _properties ? . get ( 'SUMMARY' ) [ 0 ] ? . value
} catch ( e ) {
// ignore
}
2021-06-11 15:25:24 +00:00
let subline = vobject . calendar . displayName
if ( vobject . isEvent ) {
const event = vobject ? . calendarComponent . getFirstComponent ( 'VEVENT' )
if ( event ? . startDate . jsDate && event ? . isAllDay ( ) ) {
subline += ' · ' + moment ( event . startDate . jsDate ) . format ( 'LL' )
} else if ( event ? . startDate . jsDate ) {
subline += ' · ' + moment ( event ? . startDate . jsDate ) . format ( 'LLL' )
}
}
2021-06-11 14:26:03 +00:00
const color = vobject . calendarComponent . getComponentIterator ( ) . next ( ) . value ? . color
? ? vobject . calendar . color
? ? uidToHexColor ( vobject . calendar . displayName )
2021-05-26 08:52:11 +00:00
return {
vobject ,
type : 'object' ,
key : vobject . id ,
2021-06-11 15:25:24 +00:00
name : eventSummary ,
subline ,
2021-05-26 08:52:11 +00:00
url : vobject . uri ,
deletedAt : vobject . dav . _props [ '{http://nextcloud.com/ns}deleted-at' ] ,
2021-06-11 14:26:03 +00:00
color ,
2021-05-26 08:52:11 +00:00
}
} )
return formattedCalendars . concat ( formattedCalendarObjects )
} ,
2021-05-31 20:08:13 +00:00
retentionDuration ( ) {
return Math . ceil (
2021-06-04 08:17:15 +00:00
this . trashBin . retentionDuration / ( 60 * 60 * 24 )
2021-05-31 20:08:13 +00:00
)
} ,
2021-05-26 08:52:11 +00:00
} ,
methods : {
async onShow ( ) {
this . showModal = true
2021-07-24 19:20:57 +00:00
this . loading = true
2021-05-26 08:52:11 +00:00
try {
await Promise . all ( [
this . $store . dispatch ( 'loadDeletedCalendars' ) ,
this . $store . dispatch ( 'loadDeletedCalendarObjects' ) ,
] )
2021-06-11 15:25:24 +00:00
logger . debug ( 'deleted calendars and objects loaded' , {
2021-05-26 08:52:11 +00:00
calendars : this . calendars ,
objects : this . objects ,
} )
} catch ( error ) {
logger . error ( 'could not load deleted calendars and objects' , {
error ,
} )
showError ( t ( 'calendar' , 'Could not load deleted calendars and objects' ) )
}
2021-07-24 19:20:57 +00:00
this . loading = false
2021-05-26 08:52:11 +00:00
} ,
2021-05-31 19:33:18 +00:00
async onDeletePermanently ( item ) {
logger . debug ( 'deleting ' + item . url + ' permanently' , item )
try {
switch ( item . type ) {
case 'calendar' :
await this . $store . dispatch ( 'deleteCalendarPermanently' , { calendar : item . calendar } )
break
case 'object' :
await this . $store . dispatch ( 'deleteCalendarObjectPermanently' , { vobject : item . vobject } )
break
}
} catch ( error ) {
logger . error ( 'could not restore ' + item . url , { error } )
showError ( t ( 'calendar' , 'Could not restore calendar or event' ) )
}
} ,
2021-05-26 08:52:11 +00:00
async restore ( item ) {
logger . debug ( 'restoring ' + item . url , item )
try {
switch ( item . type ) {
case 'calendar' :
await this . $store . dispatch ( 'restoreCalendar' , { calendar : item . calendar } )
this . $store . dispatch ( 'loadCollections' )
break
case 'object' :
await this . $store . dispatch ( 'restoreCalendarObject' , { vobject : item . vobject } )
break
}
} catch ( error ) {
logger . error ( 'could not restore ' + item . url , { error } )
showError ( t ( 'calendar' , 'Could not restore calendar or event' ) )
}
} ,
} ,
}
< / script >
< style lang = "scss" scoped >
. modal _ _content {
2021-06-11 12:32:48 +00:00
max - width : 40 vw ;
2021-05-26 08:52:11 +00:00
margin : 2 vw ;
2021-07-24 19:20:57 +00:00
& _ _loading ,
& _ _empty {
margin - top : 25 px ! important ;
}
2021-05-26 08:52:11 +00:00
}
2021-07-21 09:41:50 +00:00
: : v - deep . modal - wrapper . modal - container {
overflow - y : auto ;
overflow - x : auto ;
}
2021-05-26 08:52:11 +00:00
table {
width : 100 % ;
}
th , td {
padding : 4 px ;
}
th {
2021-06-11 12:42:53 +00:00
color : var ( -- color - text - maxcontrast )
2021-05-26 08:52:11 +00:00
}
2021-06-11 12:32:48 +00:00
. name {
// Take remaining width to prevent whitespace on the right side
width : 100 vw ;
}
2021-06-11 14:26:03 +00:00
. item {
display : flex ;
. item - subline {
color : var ( -- color - text - maxcontrast )
}
2021-06-11 15:25:24 +00:00
}
2021-05-26 08:52:11 +00:00
. deletedAt {
text - align : right ;
}
2021-05-31 20:08:13 +00:00
. footer {
color : var ( -- color - text - lighter ) ;
text - align : center ;
font - size : small ;
margin - top : 16 px ;
}
2021-06-11 14:26:03 +00:00
. color - dot {
display : inline - block ;
vertical - align : middle ;
width : 14 px ;
height : 14 px ;
margin - right : 14 px ;
border : none ;
border - radius : 50 % ;
}
2021-05-26 08:52:11 +00:00
< / style >