From 3f20ae89a8838dfdb53ec90ac3e39436b5d2e771 Mon Sep 17 00:00:00 2001 From: konrad Date: Sun, 14 Feb 2021 19:18:51 +0000 Subject: [PATCH] Subscriptions and notifications for namespaces, tasks and lists (#410) Co-authored-by: kolaente Reviewed-on: https://kolaente.dev/vikunja/frontend/pulls/410 Co-authored-by: konrad Co-committed-by: konrad --- .../list/list-settings-dropdown.vue | 18 +++ src/components/misc/subscription.vue | 121 ++++++++++++++++++ .../namespace/namespace-settings-dropdown.vue | 18 +++ src/main.js | 5 +- src/models/list.js | 6 + src/models/namespace.js | 7 + src/models/subscription.js | 20 +++ src/models/task.js | 6 + src/services/subscription.js | 15 +++ src/views/tasks/TaskDetailView.vue | 8 ++ 10 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 src/components/misc/subscription.vue create mode 100644 src/models/subscription.js create mode 100644 src/services/subscription.js diff --git a/src/components/list/list-settings-dropdown.vue b/src/components/list/list-settings-dropdown.vue index c560efef..72af3814 100644 --- a/src/components/list/list-settings-dropdown.vue +++ b/src/components/list/list-settings-dropdown.vue @@ -54,6 +54,14 @@ > Archive + 0 diff --git a/src/components/misc/subscription.vue b/src/components/misc/subscription.vue new file mode 100644 index 00000000..d59a491c --- /dev/null +++ b/src/components/misc/subscription.vue @@ -0,0 +1,121 @@ + + + diff --git a/src/components/namespace/namespace-settings-dropdown.vue b/src/components/namespace/namespace-settings-dropdown.vue index 70125cec..a647ed71 100644 --- a/src/components/namespace/namespace-settings-dropdown.vue +++ b/src/components/namespace/namespace-settings-dropdown.vue @@ -33,6 +33,14 @@ > Archive + import Dropdown from '@/components/misc/dropdown' import DropdownItem from '@/components/misc/dropdown-item' +import TaskSubscription from '@/components/misc/subscription' export default { name: 'namespace-settings-dropdown', + data() { + return { + subscription: null, + } + }, components: { DropdownItem, Dropdown, + TaskSubscription, }, props: { namespace: { required: true, }, }, + mounted() { + this.subscription = this.namespace.subscription + }, } diff --git a/src/main.js b/src/main.js index 75829e37..9f8a92bc 100644 --- a/src/main.js +++ b/src/main.js @@ -61,8 +61,9 @@ import { faArchive, faShareAlt, faImage, + faBell, } from '@fortawesome/free-solid-svg-icons' -import {faCalendarAlt, faClock, faComments, faSave, faStar, faTimesCircle, faSun} from '@fortawesome/free-regular-svg-icons' +import {faCalendarAlt, faClock, faComments, faSave, faStar, faTimesCircle, faSun, faBellSlash} from '@fortawesome/free-regular-svg-icons' import {FontAwesomeIcon} from '@fortawesome/vue-fontawesome' // PWA import './registerServiceWorker' @@ -152,6 +153,8 @@ library.add(faEllipsisH) library.add(faArchive) library.add(faShareAlt) library.add(faImage) +library.add(faBell) +library.add(faBellSlash) Vue.component('icon', FontAwesomeIcon) diff --git a/src/models/list.js b/src/models/list.js index cbae65cf..e098a600 100644 --- a/src/models/list.js +++ b/src/models/list.js @@ -2,6 +2,7 @@ import AbstractModel from './abstractModel' import TaskModel from './task' import UserModel from './user' import {getSavedFilterIdFromListId} from '@/helpers/savedFilter' +import SubscriptionModel from '@/models/subscription' export default class ListModel extends AbstractModel { @@ -19,6 +20,10 @@ export default class ListModel extends AbstractModel { this.owner = new UserModel(this.owner) + if(typeof this.subscription !== 'undefined' && this.subscription !== null) { + this.subscription = new SubscriptionModel(this.subscription) + } + this.created = new Date(this.created) this.updated = new Date(this.updated) } @@ -37,6 +42,7 @@ export default class ListModel extends AbstractModel { identifier: '', backgroundInformation: null, isFavorite: false, + subscription: null, created: null, updated: null, diff --git a/src/models/namespace.js b/src/models/namespace.js index 92869202..88c049aa 100644 --- a/src/models/namespace.js +++ b/src/models/namespace.js @@ -1,6 +1,7 @@ import AbstractModel from './abstractModel' import ListModel from './list' import UserModel from './user' +import SubscriptionModel from '@/models/subscription' export default class NamespaceModel extends AbstractModel { constructor(data) { @@ -13,8 +14,13 @@ export default class NamespaceModel extends AbstractModel { this.lists = this.lists.map(l => { return new ListModel(l) }) + this.owner = new UserModel(this.owner) + if(typeof this.subscription !== 'undefined' && this.subscription !== null) { + this.subscription = new SubscriptionModel(this.subscription) + } + this.created = new Date(this.created) this.updated = new Date(this.updated) } @@ -29,6 +35,7 @@ export default class NamespaceModel extends AbstractModel { lists: [], isArchived: false, hexColor: '', + subscription: null, created: null, updated: null, diff --git a/src/models/subscription.js b/src/models/subscription.js new file mode 100644 index 00000000..68d0be85 --- /dev/null +++ b/src/models/subscription.js @@ -0,0 +1,20 @@ +import AbstractModel from '@/models/abstractModel' +import UserModel from '@/models/user' + +export default class SubscriptionModel extends AbstractModel { + constructor(data) { + super(data) + this.user = new UserModel(this.user) + this.created = new Date(this.created) + } + + defaults() { + return { + id: 0, + entity: '', + entityId: 0, + created: null, + user: {}, + } + } +} diff --git a/src/models/task.js b/src/models/task.js index 091f58b7..d6385d50 100644 --- a/src/models/task.js +++ b/src/models/task.js @@ -2,6 +2,7 @@ import AbstractModel from './abstractModel' import UserModel from './user' import LabelModel from './label' import AttachmentModel from './attachment' +import SubscriptionModel from '@/models/subscription' const parseDate = date => { if (date && !date.startsWith('0001')) { @@ -75,6 +76,10 @@ export default class TaskModel extends AbstractModel { this.identifier = '' } + if(typeof this.subscription !== 'undefined' && this.subscription !== null) { + this.subscription = new SubscriptionModel(this.subscription) + } + this.created = new Date(this.created) this.updated = new Date(this.updated) } @@ -104,6 +109,7 @@ export default class TaskModel extends AbstractModel { identifier: '', index: 0, isFavorite: false, + subscription: null, createdBy: UserModel, created: null, diff --git a/src/services/subscription.js b/src/services/subscription.js new file mode 100644 index 00000000..20c79c09 --- /dev/null +++ b/src/services/subscription.js @@ -0,0 +1,15 @@ +import AbstractService from '@/services/abstractService' +import SubscriptionModel from '@/models/subscription' + +export default class SubscriptionService extends AbstractService { + constructor() { + super({ + create: '/subscriptions/{entity}/{entityId}', + delete: '/subscriptions/{entity}/{entityId}', + }) + } + + modelFactory(data) { + return new SubscriptionModel(data) + } +} \ No newline at end of file diff --git a/src/views/tasks/TaskDetailView.vue b/src/views/tasks/TaskDetailView.vue index ca300e1a..cb838f0a 100644 --- a/src/views/tasks/TaskDetailView.vue +++ b/src/views/tasks/TaskDetailView.vue @@ -255,6 +255,12 @@ > {{ task.done ? 'Mark as undone' : 'Done!' }} +