Task lists WIP

This commit is contained in:
John Livingston 2024-04-30 17:11:10 +02:00
parent ad090eaca4
commit ca026c2e10
No known key found for this signature in database
GPG Key ID: B17B5640CE66CDBC
10 changed files with 187 additions and 12 deletions

View File

@ -1,7 +1,7 @@
import { _converse, converse } from '../../../src/headless/core.js'
import { ChatRoomTaskLists } from './task-lists.js'
import { ChatRoomTaskList } from './task-list.js'
import { getHeadingButtons } from './utils.js'
import { getHeadingButtons, initOrDestroyChatRoomTaskLists } from './utils.js'
import './muc-task-lists-view.js' // FIXME: here or in another file?
import './modals/muc-task-lists.js' // FIXME: here or in another file?
@ -12,6 +12,22 @@ converse.plugins.add('livechat-converse-tasks', {
_converse.ChatRoomTaskLists = ChatRoomTaskLists
_converse.ChatRoomTaskList = ChatRoomTaskList
_converse.api.listen.on('chatRoomInitialized', muc => {
muc.session.on('change:connection_status', _session => {
// When joining a room, initializing the TaskLists object (if user has access),
// When disconnected from a room, destroying the Tasklists object:
initOrDestroyChatRoomTaskLists(muc)
})
// When the current user role changes, we must also delete or initilize the TaskLists object:
muc.occupants.on('change:role', occupant => {
if (occupant.get('jid') !== _converse.bare_jid) { // only for myself
return
}
initOrDestroyChatRoomTaskLists(muc)
})
})
// adding the "Tasks" button in the MUC heading buttons:
_converse.api.listen.on('getHeadingButtons', getHeadingButtons)
}

View File

@ -10,7 +10,8 @@ export default class mucTaskListsModal extends BaseModal {
}
getModalTitle () {
return __('Tasks')
// eslint-disable-next-line no-undef
return __(LOC_tasks)
}
}

View File

@ -1,5 +1,6 @@
import { CustomElement } from 'shared/components/element.js'
import { _converse, api } from '@converse/headless/core'
import tplMucTaskLists from './templates/muc-task-lists'
export default class MUCTaskListsView extends CustomElement {
static get properties () {
@ -9,11 +10,18 @@ export default class MUCTaskListsView extends CustomElement {
}
async initialize () {
this.model = _converse.chatboxes.get(this.getAttribute('jid'))
this.model = _converse.chatboxes.get(this.getAttribute('jid')).tasklists
if (!this.model) {
return
}
this.listenTo(this.model, 'add', () => this.requestUpdate())
this.listenTo(this.model, 'change', () => this.requestUpdate())
}
render () {
return ''
return tplMucTaskLists(this.model)
}
}

View File

@ -7,7 +7,7 @@ import { Model } from '@converse/skeletor/src/model.js'
* @memberof _converse
*/
class ChatRoomTaskList extends Model {
idAttribute = 'id'
}
export {

View File

@ -1,5 +1,7 @@
import { Collection } from '@converse/skeletor/src/collection.js'
import { ChatRoomTaskList } from './task-list'
import { initStorage } from '@converse/headless/utils/storage.js'
import { getUniqueId } from '@converse/headless/utils/core.js'
/**
* A list of {@link _converse.ChatRoomTaskList} instances, representing task lists associated to a MUC.
@ -9,6 +11,66 @@ import { ChatRoomTaskList } from './task-list'
*/
class ChatRoomTaskLists extends Collection {
model = ChatRoomTaskList
initialize (models, options) {
super.initialize(arguments)
this.chatroom = options.chatroom
const id = `converse-livechat-tasks-lists-${this.chatroom.get('jid')}`
initStorage(this, id, 'session')
this.on('change:name', () => this.sort())
this.fetchTasksLists().catch(console.error)
}
comparator (tasklist1, tasklist2) {
// Case insensitive on task list name.
const name1 = tasklist1.get('name').toLowerCase()
const name2 = tasklist2.get('name').toLowerCase()
return name1 < name2 ? -1 : name1 > name2 ? 1 : 0
}
create (attrs, options) {
attrs.id ??= getUniqueId()
return super.create(attrs, options)
}
/**
* Requires Task lists from the server.
*/
async fetchTasksLists () {
// TODO: remove these test lines, and subscribe to pubsub.
const taskListsData = [
{
id: 'task-list-1',
name: 'Task List 1'
},
{
// id: 'task-list-2',
name: 'Task List 2'
}
]
for (const item of taskListsData) {
let id = item.id
const tasklist = id ? this.get(id) : undefined
if (tasklist) {
tasklist.save({
name: item.name
})
return
}
id ??= getUniqueId()
this.create({
id,
name: item.name
})
}
}
}
export {

View File

@ -0,0 +1,7 @@
import { html } from 'lit'
export default function tplMucTaskList (tasklist) {
return html`<div class="">
Tasklist: ${tasklist.get('name')}
</div>`
}

View File

@ -0,0 +1,43 @@
import tplMucTaskList from './muc-task-list'
import { html } from 'lit'
import { repeat } from 'lit/directives/repeat.js'
import { __ } from 'i18n'
export default function tplMucTaskLists (tasklists) {
if (!tasklists) { // if user losed rights
return html`` // FIXME: add a message like "you dont have access"?
}
const i18nAdd = __('Add')
// eslint-disable-next-line no-undef
const i18nCreateTaskList = __(LOC_task_list_create)
// eslint-disable-next-line no-undef
const i18nTaskListName = __(LOC_task_list_name)
return html`
<form class="converse-form" @submit=${(ev) => {
ev.preventDefault()
const name = ev.target.name.value.trim()
if ((name ?? '') === '') { return }
ev.target.name.value = ''
tasklists.create({
name
})
}}
>
<div class="form-group">
<label>
${i18nCreateTaskList}
<input type="text" value="" name="name" placeholder="${i18nTaskListName}" />
</label>
<input type="submit" value="${i18nAdd}" class="btn btn-primary" />
</div>
</form>
<div class="">
${
repeat(tasklists, (tasklist) => tasklist.get('id'), (tasklist) => tplMucTaskList(tasklist))
}
</div>`
}

View File

@ -1,4 +1,4 @@
import { _converse, api } from '../../../src/headless/core.js'
import { converse, _converse, api } from '../../../src/headless/core.js'
import { __ } from 'i18n'
export function getHeadingButtons (view, buttons) {
@ -8,15 +8,14 @@ export function getHeadingButtons (view, buttons) {
return buttons
}
const myself = muc.getOwnOccupant()
if (!myself || !myself.isModerator()) {
// User must be moderator
if (!muc.tasklists) { // this is defined only if user has access (see initOrDestroyChatRoomTaskLists)
return buttons
}
// Adding a "Open task list" button.
buttons.unshift({
i18n_text: __('Tasks'),
// eslint-disable-next-line no-undef
i18n_text: __(LOC_tasks),
handler: async (ev) => {
ev.preventDefault()
ev.stopPropagation()
@ -30,3 +29,38 @@ export function getHeadingButtons (view, buttons) {
return buttons
}
function _initChatRoomTaskLists (mucModel) {
if (mucModel.tasklists) {
// already initiliazed
return
}
mucModel.tasklists = new _converse.ChatRoomTaskLists(undefined, { chatroom: mucModel })
}
function _destroyChatRoomTaskLists (mucModel) {
if (!mucModel.tasklists) { return }
// mucModel.tasklists.unload() FIXME: add a method to unregister from the pubsub, and empty the tasklist.
mucModel.tasklists = undefined
}
export function initOrDestroyChatRoomTaskLists (mucModel) {
if (mucModel.get('type') !== _converse.CHATROOMS_TYPE) {
// only on MUC.
return _destroyChatRoomTaskLists(mucModel)
}
if (mucModel.session.get('connection_status') !== converse.ROOMSTATUS.ENTERED) {
_destroyChatRoomTaskLists(mucModel)
}
const myself = mucModel.getOwnOccupant()
if (!myself || !myself.isModerator()) {
// User must be moderator
return _destroyChatRoomTaskLists(mucModel)
}
return _initChatRoomTaskLists(mucModel)
}

View File

@ -16,7 +16,9 @@ const locKeys = [
'login_remote_peertube_video_not_found_try_anyway_button',
'login_remote_peertube_video_open_failed',
'login_external_auth_alert_message',
'tasks'
'tasks',
'task_list_create',
'task_list_name'
]
module.exports = locKeys

View File

@ -435,4 +435,6 @@ login_remote_peertube_video_not_found_try_anyway_button: "Try anyway to open the
login_remote_peertube_video_open_failed: "Your browser has blocked the opening on the remote instance, please try to open manually this link:"
login_external_auth_alert_message: "Authentication failed"
tasks: Tasks
tasks: 'Tasks'
task_list_create: 'Create new task list:'
task_list_name: 'Task list name'