mirror of
https://gitlab.com/bramw/baserow.git
synced 2024-11-21 23:37:55 +00:00
251 lines
7.4 KiB
Vue
251 lines
7.4 KiB
Vue
<template>
|
|
<div
|
|
class="notification-panel"
|
|
:class="{ 'visibility-hidden': !open }"
|
|
ph-autocapture="notifications"
|
|
>
|
|
<div class="notification-panel__head">
|
|
<div class="notification-panel__title">
|
|
{{ $t('notificationPanel.title') }}
|
|
</div>
|
|
<div v-show="totalCount > 0" class="notification-panel__actions">
|
|
<a
|
|
v-show="unreadCount > 0"
|
|
class="notification-panel__action"
|
|
@click="markAllAsRead"
|
|
>
|
|
{{ $t('notificationPanel.markAllAsRead') }}
|
|
</a>
|
|
<a
|
|
class="notification-panel__action"
|
|
@click="$refs.clearAllConfirmModal.show()"
|
|
>
|
|
{{ $t('notificationPanel.clearAll') }}
|
|
</a>
|
|
</div>
|
|
</div>
|
|
<div v-if="!loaded && loading" class="loading-absolute-center"></div>
|
|
<div v-else-if="totalCount === 0" class="notification-panel__empty">
|
|
<i class="notification-panel__empty-icon iconoir-bell-off"></i>
|
|
<div class="notification-panel__empty-title">
|
|
{{ $t('notificationPanel.noNotificationTitle') }}
|
|
</div>
|
|
<div class="notification-panel__empty-text">
|
|
{{ $t('notificationPanel.noNotification') }}
|
|
</div>
|
|
</div>
|
|
<div v-else class="notification-panel__body">
|
|
<div v-if="needRefresh" class="notification-panel__refresh-hint">
|
|
<div class="notification-panel__refresh-hint-text">
|
|
<span class="notification-panel__refresh-hint-icon"></span>
|
|
{{ $t('notificationPanel.newNotificationsAvailable') }}
|
|
</div>
|
|
<Button type="secondary" @click.prevent="initialLoad">
|
|
{{ $t('notificationPanel.refresh') }}
|
|
</Button>
|
|
</div>
|
|
<InfiniteScroll
|
|
ref="infiniteScroll"
|
|
:current-count="currentCount"
|
|
:max-count="totalCount"
|
|
:loading="loading"
|
|
:render-end="false"
|
|
@load-next-page="loadNextPage"
|
|
>
|
|
<template #default>
|
|
<div
|
|
v-for="(notification, index) in notifications"
|
|
:key="index"
|
|
class="notification-panel__notification"
|
|
:class="{
|
|
'notification-panel__notification--unread': !notification.read,
|
|
}"
|
|
>
|
|
<div class="notification-panel__notification-icon">
|
|
<component
|
|
:is="getNotificationIcon(notification)"
|
|
:notification="notification"
|
|
v-bind="getNotificationIconProps(notification)"
|
|
>
|
|
</component>
|
|
</div>
|
|
<div class="notification-panel__notification-content">
|
|
<component
|
|
:is="getNotificationContent(notification)"
|
|
:notification="notification"
|
|
:workspace="workspace"
|
|
@close-panel="hide"
|
|
>
|
|
</component>
|
|
<div class="notification-panel__notification-time">
|
|
{{ timeAgo(notification.created_on) }}
|
|
</div>
|
|
</div>
|
|
<div class="notification-panel__notification-status">
|
|
<span v-if="!notification.read"></span>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</InfiniteScroll>
|
|
</div>
|
|
<ClearAllNotificationsConfirmModal
|
|
ref="clearAllConfirmModal"
|
|
@confirm="
|
|
($event) => {
|
|
$event.preventDefault()
|
|
$event.stopPropagation()
|
|
clearAll()
|
|
}
|
|
"
|
|
@cancel="
|
|
($event) => {
|
|
$event.preventDefault()
|
|
$event.stopPropagation()
|
|
}
|
|
"
|
|
></ClearAllNotificationsConfirmModal>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import { mapGetters } from 'vuex'
|
|
import moment from '@baserow/modules/core/moment'
|
|
import { isElement, onClickOutside } from '@baserow/modules/core/utils/dom'
|
|
import { notifyIf } from '@baserow/modules/core/utils/error'
|
|
import InfiniteScroll from '@baserow/modules/core/components/helpers/InfiniteScroll'
|
|
import ClearAllNotificationsConfirmModal from '@baserow/modules/core/components/modals/ClearAllNotificationsConfirmModal'
|
|
import MoveToBody from '@baserow/modules/core/mixins/moveToBody'
|
|
|
|
export default {
|
|
name: 'NotificationPanel',
|
|
components: {
|
|
ClearAllNotificationsConfirmModal,
|
|
InfiniteScroll,
|
|
},
|
|
mixins: [MoveToBody],
|
|
data() {
|
|
return {
|
|
open: false,
|
|
needRefresh: false,
|
|
}
|
|
},
|
|
computed: {
|
|
...mapGetters({
|
|
workspaceId: 'notification/getWorkspaceId',
|
|
notifications: 'notification/getAll',
|
|
loading: 'notification/getLoading',
|
|
loaded: 'notification/getLoaded',
|
|
unreadCount: 'notification/getUnreadCount',
|
|
currentCount: 'notification/getCurrentCount',
|
|
totalCount: 'notification/getTotalCount',
|
|
}),
|
|
workspace() {
|
|
return this.$store.getters['workspace/get'](this.workspaceId)
|
|
},
|
|
},
|
|
watch: {
|
|
loaded(isLoaded) {
|
|
// On receiving many notifications, only the unread count is sent via web
|
|
// sockets and the 'loaded' state resets to false in the store. This
|
|
// watcher ensure to do the correct action if the panel is open and we
|
|
// receive new notifications.
|
|
|
|
if (isLoaded || !this.open) {
|
|
return
|
|
}
|
|
|
|
// If we have no notifications, we can safely load the initial set.
|
|
// Otherwise, we show a hint that new notifications are available.
|
|
if (this.totalCount === 0) {
|
|
this.initialLoad()
|
|
} else {
|
|
this.needRefresh = true
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
async initialLoad() {
|
|
this.needRefresh = false
|
|
try {
|
|
await this.$store.dispatch('notification/fetchAll', {
|
|
workspaceId: this.workspaceId,
|
|
})
|
|
} catch (e) {
|
|
notifyIf(e, 'application')
|
|
}
|
|
},
|
|
show(target) {
|
|
if (!this.loaded && !this.loading) {
|
|
this.initialLoad()
|
|
}
|
|
this.open = true
|
|
const opener = target
|
|
const removeOnClickOutsideHandler = onClickOutside(this.$el, (target) => {
|
|
if (
|
|
this.open &&
|
|
!isElement(opener, target) &&
|
|
!this.moveToBody.children.some((child) => {
|
|
return isElement(child.$el, target)
|
|
})
|
|
) {
|
|
this.hide()
|
|
}
|
|
})
|
|
this.$once('hidden', removeOnClickOutsideHandler)
|
|
this.$emit('shown')
|
|
},
|
|
hide() {
|
|
this.open = false
|
|
this.opener = null
|
|
this.$emit('hidden')
|
|
},
|
|
toggle(target) {
|
|
if (this.open) {
|
|
this.hide()
|
|
} else {
|
|
this.show(target)
|
|
}
|
|
},
|
|
async markAllAsRead() {
|
|
try {
|
|
await this.$store.dispatch('notification/markAllAsRead')
|
|
} catch (error) {
|
|
notifyIf(error, 'application')
|
|
}
|
|
},
|
|
async clearAll() {
|
|
try {
|
|
await this.$store.dispatch('notification/clearAll')
|
|
} catch (error) {
|
|
notifyIf(error, 'application')
|
|
}
|
|
},
|
|
getNotificationIcon(notification) {
|
|
return this.$registry
|
|
.get('notification', notification.type)
|
|
.getIconComponent()
|
|
},
|
|
getNotificationIconProps(notification) {
|
|
return this.$registry
|
|
.get('notification', notification.type)
|
|
.getIconComponentProps()
|
|
},
|
|
getNotificationContent(notification) {
|
|
return this.$registry
|
|
.get('notification', notification.type)
|
|
.getContentComponent()
|
|
},
|
|
timeAgo(timestamp) {
|
|
return moment.utc(timestamp).fromNow()
|
|
},
|
|
async loadNextPage() {
|
|
try {
|
|
await this.$store.dispatch('notification/fetchNextSetOfNotifications')
|
|
} catch (e) {
|
|
notifyIf(e, 'application')
|
|
}
|
|
},
|
|
},
|
|
}
|
|
</script>
|