From 22561b4daab512b5ef37856bcd2fe6618848e748 Mon Sep 17 00:00:00 2001 From: John Livingston Date: Tue, 30 Apr 2024 18:30:44 +0200 Subject: [PATCH] Task lists WIP --- conversejs/custom/plugins/tasks/index.js | 4 + .../plugins/tasks/modals/muc-task-lists.js | 2 +- .../plugins/tasks/muc-task-list-view.js | 25 +++++ .../plugins/tasks/muc-task-lists-view.js | 9 +- .../custom/plugins/tasks/muc-task-view.js | 25 +++++ conversejs/custom/plugins/tasks/task-list.js | 7 ++ conversejs/custom/plugins/tasks/task-lists.js | 6 +- conversejs/custom/plugins/tasks/task.js | 15 +++ conversejs/custom/plugins/tasks/tasks.js | 95 +++++++++++++++++++ .../plugins/tasks/templates/muc-task-list.js | 12 ++- .../plugins/tasks/templates/muc-task-lists.js | 5 +- .../plugins/tasks/templates/muc-task.js | 8 ++ conversejs/custom/plugins/tasks/utils.js | 2 + 13 files changed, 205 insertions(+), 10 deletions(-) create mode 100644 conversejs/custom/plugins/tasks/muc-task-list-view.js create mode 100644 conversejs/custom/plugins/tasks/muc-task-view.js create mode 100644 conversejs/custom/plugins/tasks/task.js create mode 100644 conversejs/custom/plugins/tasks/tasks.js create mode 100644 conversejs/custom/plugins/tasks/templates/muc-task.js diff --git a/conversejs/custom/plugins/tasks/index.js b/conversejs/custom/plugins/tasks/index.js index c47e4248..e5c2c587 100644 --- a/conversejs/custom/plugins/tasks/index.js +++ b/conversejs/custom/plugins/tasks/index.js @@ -1,7 +1,10 @@ import { _converse, converse } from '../../../src/headless/core.js' import { ChatRoomTaskLists } from './task-lists.js' import { ChatRoomTaskList } from './task-list.js' +import { ChatRoomTasks } from './tasks.js' import { getHeadingButtons, initOrDestroyChatRoomTaskLists } from './utils.js' +import './muc-task-view.js' // FIXME: here or in another file? +import './muc-task-list-view.js' // FIXME: here or in another file? import './muc-task-lists-view.js' // FIXME: here or in another file? import './modals/muc-task-lists.js' // FIXME: here or in another file? @@ -11,6 +14,7 @@ converse.plugins.add('livechat-converse-tasks', { initialize () { _converse.ChatRoomTaskLists = ChatRoomTaskLists _converse.ChatRoomTaskList = ChatRoomTaskList + _converse.ChatRoomTasks = ChatRoomTasks _converse.api.listen.on('chatRoomInitialized', muc => { muc.session.on('change:connection_status', _session => { diff --git a/conversejs/custom/plugins/tasks/modals/muc-task-lists.js b/conversejs/custom/plugins/tasks/modals/muc-task-lists.js index 4113be65..a0d1d488 100644 --- a/conversejs/custom/plugins/tasks/modals/muc-task-lists.js +++ b/conversejs/custom/plugins/tasks/modals/muc-task-lists.js @@ -6,7 +6,7 @@ import { __ } from 'i18n' export default class mucTaskListsModal extends BaseModal { renderModal () { const muc = this.model - return html`` + return html`` } getModalTitle () { diff --git a/conversejs/custom/plugins/tasks/muc-task-list-view.js b/conversejs/custom/plugins/tasks/muc-task-list-view.js new file mode 100644 index 00000000..6e6b10d3 --- /dev/null +++ b/conversejs/custom/plugins/tasks/muc-task-list-view.js @@ -0,0 +1,25 @@ +import { CustomElement } from 'shared/components/element.js' +import { api } from '@converse/headless/core' +import tplMucTaskList from './templates/muc-task-list' + +export default class MUCTaskListView extends CustomElement { + static get properties () { + return { + model: { type: Object, attribute: true } + } + } + + async initialize () { + if (!this.model) { + return + } + + this.listenTo(this.model, 'change', () => this.requestUpdate()) + } + + render () { + return tplMucTaskList(this.model) + } +} + +api.elements.define('livechat-converse-muc-task-list', MUCTaskListView) diff --git a/conversejs/custom/plugins/tasks/muc-task-lists-view.js b/conversejs/custom/plugins/tasks/muc-task-lists-view.js index 736c7d7d..0dc5de9c 100644 --- a/conversejs/custom/plugins/tasks/muc-task-lists-view.js +++ b/conversejs/custom/plugins/tasks/muc-task-lists-view.js @@ -1,23 +1,22 @@ import { CustomElement } from 'shared/components/element.js' -import { _converse, api } from '@converse/headless/core' +import { api } from '@converse/headless/core' import tplMucTaskLists from './templates/muc-task-lists' export default class MUCTaskListsView extends CustomElement { static get properties () { return { - jid: { type: String, attribute: true } + model: { type: Object, attribute: true } } } async initialize () { - this.model = _converse.chatboxes.get(this.getAttribute('jid')).tasklists - if (!this.model) { return } + // Adding or removing a new task list: we must update. this.listenTo(this.model, 'add', () => this.requestUpdate()) - this.listenTo(this.model, 'change', () => this.requestUpdate()) + this.listenTo(this.model, 'remove', () => this.requestUpdate()) } render () { diff --git a/conversejs/custom/plugins/tasks/muc-task-view.js b/conversejs/custom/plugins/tasks/muc-task-view.js new file mode 100644 index 00000000..c8ad8fc7 --- /dev/null +++ b/conversejs/custom/plugins/tasks/muc-task-view.js @@ -0,0 +1,25 @@ +import { CustomElement } from 'shared/components/element.js' +import { api } from '@converse/headless/core' +import tplMucTask from './templates/muc-task' + +export default class MUCTaskView extends CustomElement { + static get properties () { + return { + model: { type: Object, attribute: true } + } + } + + async initialize () { + if (!this.model) { + return + } + + this.listenTo(this.model, 'change', () => this.requestUpdate()) + } + + render () { + return tplMucTask(this.model) + } +} + +api.elements.define('livechat-converse-muc-task', MUCTaskView) diff --git a/conversejs/custom/plugins/tasks/task-list.js b/conversejs/custom/plugins/tasks/task-list.js index 3f0e1426..adfbdec6 100644 --- a/conversejs/custom/plugins/tasks/task-list.js +++ b/conversejs/custom/plugins/tasks/task-list.js @@ -8,6 +8,13 @@ import { Model } from '@converse/skeletor/src/model.js' */ class ChatRoomTaskList extends Model { idAttribute = 'id' + + getTasks () { + const taskListId = this.get('id') + return this.collection?.chatroom?.tasks?.filter({ + list: taskListId + }) ?? [] + } } export { diff --git a/conversejs/custom/plugins/tasks/task-lists.js b/conversejs/custom/plugins/tasks/task-lists.js index 76a9bbfc..5c0ef1fa 100644 --- a/conversejs/custom/plugins/tasks/task-lists.js +++ b/conversejs/custom/plugins/tasks/task-lists.js @@ -13,6 +13,7 @@ class ChatRoomTaskLists extends Collection { model = ChatRoomTaskList initialize (models, options) { + this.model = ChatRoomTaskList // don't know why, must do it again here super.initialize(arguments) this.chatroom = options.chatroom @@ -32,6 +33,9 @@ class ChatRoomTaskLists extends Collection { } create (attrs, options) { + if (attrs instanceof ChatRoomTaskList) { + return super.create(attrs, options) + } attrs.id ??= getUniqueId() return super.create(attrs, options) } @@ -47,7 +51,7 @@ class ChatRoomTaskLists extends Collection { name: 'Task List 1' }, { - // id: 'task-list-2', + id: 'task-list-2', name: 'Task List 2' } ] diff --git a/conversejs/custom/plugins/tasks/task.js b/conversejs/custom/plugins/tasks/task.js new file mode 100644 index 00000000..e081d3cd --- /dev/null +++ b/conversejs/custom/plugins/tasks/task.js @@ -0,0 +1,15 @@ +import { Model } from '@converse/skeletor/src/model.js' + +/** + * A chat room task. + * @class + * @namespace _converse.ChatRoomTask + * @memberof _converse + */ +class ChatRoomTask extends Model { + idAttribute = 'id' +} + +export { + ChatRoomTask +} diff --git a/conversejs/custom/plugins/tasks/tasks.js b/conversejs/custom/plugins/tasks/tasks.js new file mode 100644 index 00000000..94cd7284 --- /dev/null +++ b/conversejs/custom/plugins/tasks/tasks.js @@ -0,0 +1,95 @@ +import { Collection } from '@converse/skeletor/src/collection.js' +import { ChatRoomTask } from './task' +import { initStorage } from '@converse/headless/utils/storage.js' +import { getUniqueId } from '@converse/headless/utils/core.js' + +/** + * A list of {@link _converse.ChatRoomTask} instances, representing all tasks associated to a MUC. + * @class + * @namespace _converse.ChatRoomTasks + * @memberOf _converse + */ +class ChatRoomTasks extends Collection { + model = ChatRoomTask + comparator = 'order' + + initialize (models, options) { + this.model = ChatRoomTask // don't know why, must do it again here + super.initialize(arguments) + this.chatroom = options.chatroom + + const id = `converse-livechat-tasks-${this.chatroom.get('jid')}` + initStorage(this, id, 'session') + + this.on('change:order', () => this.sort()) + + this.fetchTasks().catch(console.error) + } + + create (attrs, options) { + if (attrs instanceof ChatRoomTask) { + return super.create(attrs, options) + } + attrs.id ??= getUniqueId() + return super.create(attrs, options) + } + + /** + * Requires Task lists from the server. + */ + async fetchTasks () { + // TODO: remove these test lines, and subscribe to pubsub. + const tasksData = [ + { + id: 'task-1', + name: 'Task 1.1', + list: 'task-list-1', + order: 1, + done: false + }, + { + id: 'task-2', + name: 'Task 1.2', + list: 'task-list-1', + order: 2, + done: true + }, + { + id: 'task-3', + name: 'Task 2.1', + list: 'task-list-2', + order: 1, + done: false + } + ] + + for (const item of tasksData) { + let id = item.id + + const task = id ? this.get(id) : undefined + if (task) { + task.save({ + name: item.name, + list: item.list, + order: item.order, + done: item.done + }) + return + } + + id ??= getUniqueId() + + this.create({ + id, + name: item.name, + list: item.list, + order: item.order, + done: item.done + }) + } + } +} + +export { + ChatRoomTasks +} diff --git a/conversejs/custom/plugins/tasks/templates/muc-task-list.js b/conversejs/custom/plugins/tasks/templates/muc-task-list.js index 0e39b483..1c0c983a 100644 --- a/conversejs/custom/plugins/tasks/templates/muc-task-list.js +++ b/conversejs/custom/plugins/tasks/templates/muc-task-list.js @@ -1,7 +1,17 @@ import { html } from 'lit' +import { repeat } from 'lit/directives/repeat.js' export default function tplMucTaskList (tasklist) { - return html`
+ const tasks = tasklist.getTasks() + return html` +
Tasklist: ${tasklist.get('name')} +
+
+ ${ + repeat(tasks, (task) => task.get('id'), (task) => { + return html`` + }) + }
` } diff --git a/conversejs/custom/plugins/tasks/templates/muc-task-lists.js b/conversejs/custom/plugins/tasks/templates/muc-task-lists.js index 27a0590f..178fc604 100644 --- a/conversejs/custom/plugins/tasks/templates/muc-task-lists.js +++ b/conversejs/custom/plugins/tasks/templates/muc-task-lists.js @@ -1,4 +1,3 @@ -import tplMucTaskList from './muc-task-list' import { html } from 'lit' import { repeat } from 'lit/directives/repeat.js' import { __ } from 'i18n' @@ -37,7 +36,9 @@ export default function tplMucTaskLists (tasklists) {
${ - repeat(tasklists, (tasklist) => tasklist.get('id'), (tasklist) => tplMucTaskList(tasklist)) + repeat(tasklists, (tasklist) => tasklist.get('id'), (tasklist) => { + return html`` + }) }
` } diff --git a/conversejs/custom/plugins/tasks/templates/muc-task.js b/conversejs/custom/plugins/tasks/templates/muc-task.js new file mode 100644 index 00000000..ff8f6d3b --- /dev/null +++ b/conversejs/custom/plugins/tasks/templates/muc-task.js @@ -0,0 +1,8 @@ +import { html } from 'lit' + +export default function tplMucTask (task) { + return html` +
+ Task: ${task.get('name')} +
` +} diff --git a/conversejs/custom/plugins/tasks/utils.js b/conversejs/custom/plugins/tasks/utils.js index 5546235d..1e1664bd 100644 --- a/conversejs/custom/plugins/tasks/utils.js +++ b/conversejs/custom/plugins/tasks/utils.js @@ -37,6 +37,7 @@ function _initChatRoomTaskLists (mucModel) { } mucModel.tasklists = new _converse.ChatRoomTaskLists(undefined, { chatroom: mucModel }) + mucModel.tasks = new _converse.ChatRoomTasks(undefined, { chatroom: mucModel }) } function _destroyChatRoomTaskLists (mucModel) { @@ -44,6 +45,7 @@ function _destroyChatRoomTaskLists (mucModel) { // mucModel.tasklists.unload() FIXME: add a method to unregister from the pubsub, and empty the tasklist. mucModel.tasklists = undefined + mucModel.tasks = undefined } export function initOrDestroyChatRoomTaskLists (mucModel) {