Task lists WIP:
* front-end
This commit is contained in:
parent
9d5d59e9bc
commit
964b8854f6
@ -8,13 +8,15 @@ export default class MUCTaskListView extends CustomElement {
|
|||||||
return {
|
return {
|
||||||
model: { type: Object, attribute: true },
|
model: { type: Object, attribute: true },
|
||||||
collapsed: { type: Boolean, attribute: false },
|
collapsed: { type: Boolean, attribute: false },
|
||||||
edit: { type: Boolean, attribute: false }
|
edit: { type: Boolean, attribute: false },
|
||||||
|
add_task_form_opened: { type: Boolean, attribute: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async initialize () {
|
async initialize () {
|
||||||
this.collapsed = false
|
this.collapsed = false
|
||||||
this.edit = false
|
this.edit = false
|
||||||
|
this.add_task_form_opened = false
|
||||||
if (!this.model) {
|
if (!this.model) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -82,7 +84,7 @@ export default class MUCTaskListView extends CustomElement {
|
|||||||
this.edit = !this.edit
|
this.edit = !this.edit
|
||||||
if (this.edit) {
|
if (this.edit) {
|
||||||
await this.updateComplete
|
await this.updateComplete
|
||||||
const input = this.querySelector('input[name="name"]')
|
const input = this.querySelector('.task-list-name input[name="name"]')
|
||||||
if (input) {
|
if (input) {
|
||||||
input.focus()
|
input.focus()
|
||||||
// Placing cursor at the end:
|
// Placing cursor at the end:
|
||||||
@ -91,6 +93,46 @@ export default class MUCTaskListView extends CustomElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async openAddTaskForm () {
|
||||||
|
this.add_task_form_opened = true
|
||||||
|
await this.updateComplete
|
||||||
|
const input = this.querySelector('.task-list-add-task input[name="name"]')
|
||||||
|
if (input) {
|
||||||
|
input.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closeAddTaskForm () {
|
||||||
|
this.add_task_form_opened = false
|
||||||
|
}
|
||||||
|
|
||||||
|
async submitAddTask (ev) {
|
||||||
|
ev.preventDefault()
|
||||||
|
|
||||||
|
const name = ev.target.name.value.trim()
|
||||||
|
if ((name ?? '') === '') { return }
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.querySelectorAll('input[type=submit]').forEach(el => {
|
||||||
|
el.setAttribute('disabled', true)
|
||||||
|
el.classList.add('disabled')
|
||||||
|
})
|
||||||
|
|
||||||
|
await this.model.createTask({
|
||||||
|
name
|
||||||
|
})
|
||||||
|
|
||||||
|
this.closeAddTaskForm()
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
this.querySelectorAll('input[type=submit]').forEach(el => {
|
||||||
|
el.removeAttribute('disabled')
|
||||||
|
el.classList.remove('disabled')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
api.elements.define('livechat-converse-muc-task-list', MUCTaskListView)
|
api.elements.define('livechat-converse-muc-task-list', MUCTaskListView)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { CustomElement } from 'shared/components/element.js'
|
import { CustomElement } from 'shared/components/element.js'
|
||||||
import { api } from '@converse/headless/core'
|
import { api } from '@converse/headless/core'
|
||||||
import tplMucTask from './templates/muc-task'
|
import { tplMucTask } from './templates/muc-task'
|
||||||
|
|
||||||
export default class MUCTaskView extends CustomElement {
|
export default class MUCTaskView extends CustomElement {
|
||||||
static get properties () {
|
static get properties () {
|
||||||
|
@ -16,12 +16,25 @@
|
|||||||
column-gap: 0.25em;
|
column-gap: 0.25em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
button {
|
.task-list-toggle-tasks,
|
||||||
|
.task-list-action {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
padding-left: 0.25em;
|
||||||
|
padding-right: 0.25em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.task-list-name {
|
.task-list-name {
|
||||||
flex-grow: 2;
|
flex-grow: 2;
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row nowrap;
|
||||||
|
column-gap: 0.25em;
|
||||||
|
|
||||||
|
input[type="text"] {
|
||||||
|
flex-grow: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -29,5 +42,10 @@
|
|||||||
padding-left: 2em;
|
padding-left: 2em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.task-list-add-task {
|
||||||
|
padding: 0.25em 0.25em 0.25em 2em;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,27 @@ class ChatRoomTaskList extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async deleteItem () {
|
async deleteItem () {
|
||||||
return this.collection.chatroom.taskManager.deleteItem(this)
|
const tasks = this.getTasks()
|
||||||
|
return this.collection.chatroom.taskManager.deleteItems([...tasks, this])
|
||||||
|
}
|
||||||
|
|
||||||
|
async createTask (data) {
|
||||||
|
// Cloning data to avoid side effects:
|
||||||
|
data = Object.assign({}, data)
|
||||||
|
|
||||||
|
const name = data?.name
|
||||||
|
if (!name) { throw new Error('Missing name') }
|
||||||
|
|
||||||
|
data.list = this.get('id')
|
||||||
|
if (!data.order) {
|
||||||
|
data.order = 1 + Math.max(...this.getTasks().map(t => t.get('order') ?? 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Creating task ' + name + '...')
|
||||||
|
const chatroom = this.collection.chatroom
|
||||||
|
const tasksCollection = chatroom.tasks
|
||||||
|
await chatroom.taskManager.createItem(tasksCollection, data)
|
||||||
|
console.log('Task list ' + name + ' created.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,23 +1,28 @@
|
|||||||
import { html } from 'lit'
|
import { html } from 'lit'
|
||||||
import { repeat } from 'lit/directives/repeat.js'
|
import { repeat } from 'lit/directives/repeat.js'
|
||||||
import { __ } from 'i18n'
|
import { __ } from 'i18n'
|
||||||
|
import { tplMucAddTaskForm } from './muc-task'
|
||||||
|
|
||||||
export default function tplMucTaskList (el, tasklist) {
|
export default function tplMucTaskList (el, tasklist) {
|
||||||
const tasks = tasklist.getTasks()
|
const tasks = tasklist.getTasks()
|
||||||
// eslint-disable-next-line no-undef
|
// eslint-disable-next-line no-undef
|
||||||
const i18nDelete = __(LOC_task_list_delete)
|
const i18nDelete = __(LOC_task_list_delete)
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nCreateTask = __(LOC_task_create)
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nTaskListName = __(LOC_task_list_name)
|
||||||
return html`
|
return html`
|
||||||
<div class="task-list-description">
|
<div class="task-list-description">
|
||||||
${el.collapsed
|
${el.collapsed
|
||||||
? html`
|
? html`
|
||||||
<button @click=${el.toggleTasks}>
|
<button @click=${el.toggleTasks} class="task-list-toggle-tasks">
|
||||||
<converse-icon
|
<converse-icon
|
||||||
color="var(--muc-toolbar-btn-color)"
|
color="var(--muc-toolbar-btn-color)"
|
||||||
class="fa fa-angle-double-up"
|
class="fa fa-angle-double-up"
|
||||||
size="1em"></converse-icon>
|
size="1em"></converse-icon>
|
||||||
</button>`
|
</button>`
|
||||||
: html`
|
: html`
|
||||||
<button @click=${el.toggleTasks}>
|
<button @click=${el.toggleTasks} class="task-list-toggle-tasks">
|
||||||
<converse-icon
|
<converse-icon
|
||||||
color="var(--muc-toolbar-btn-color)"
|
color="var(--muc-toolbar-btn-color)"
|
||||||
class="fa fa-angle-double-down"
|
class="fa fa-angle-double-down"
|
||||||
@ -29,22 +34,31 @@ export default function tplMucTaskList (el, tasklist) {
|
|||||||
<div class="task-list-name">
|
<div class="task-list-name">
|
||||||
${tasklist.get('name')}
|
${tasklist.get('name')}
|
||||||
</div>
|
</div>
|
||||||
<a title="${__('Edit')}"
|
<button class="task-list-action" title="${i18nCreateTask}" @click=${el.openAddTaskForm}>
|
||||||
|
<converse-icon class="fa fa-plus" size="1em"></converse-icon>
|
||||||
|
</button>
|
||||||
|
<button class="task-list-action" title="${__('Edit')}"
|
||||||
@click=${el.toggleEdit}
|
@click=${el.toggleEdit}
|
||||||
>
|
>
|
||||||
<converse-icon class="fa fa-edit" size="1em"></converse-icon>
|
<converse-icon class="fa fa-edit" size="1em"></converse-icon>
|
||||||
</a>
|
</button>
|
||||||
<a title="${i18nDelete}"
|
<button class="task-list-action" title="${i18nDelete}"
|
||||||
@click=${el.deleteTaskList}
|
@click=${el.deleteTaskList}
|
||||||
>
|
>
|
||||||
<converse-icon class="fa fa-trash-alt" size="1em"></converse-icon>
|
<converse-icon class="fa fa-trash-alt" size="1em"></converse-icon>
|
||||||
</a>`
|
</button>`
|
||||||
: html`
|
: html`
|
||||||
<div class="task-list-name">
|
<div class="task-list-name">
|
||||||
<form @submit=${el.saveTaskList}>
|
<form @submit=${el.saveTaskList} class="converse-form">
|
||||||
<input type="text" name="name" autofocus value=${tasklist.get('name')} />
|
<input type="text" name="name"
|
||||||
|
placeholder="${__(i18nTaskListName)}"
|
||||||
|
class="form-control"
|
||||||
|
value="${tasklist.get('name')}"
|
||||||
|
/>
|
||||||
<input type="submit" class="btn btn-primary" value="${__('Ok')}" />
|
<input type="submit" class="btn btn-primary" value="${__('Ok')}" />
|
||||||
<input type="reset" class="btn btn-secondary" value="${__('Cancel')}" @click=${el.toggleEdit} />
|
<input type="button" class="btn btn-secondary button-cancel"
|
||||||
|
value="${__('Cancel')}" @click=${el.toggleEdit}
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
@ -56,5 +70,9 @@ export default function tplMucTaskList (el, tasklist) {
|
|||||||
return html`<livechat-converse-muc-task .model=${task}></livechat-converse-muc-task>`
|
return html`<livechat-converse-muc-task .model=${task}></livechat-converse-muc-task>`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</div>`
|
</div>
|
||||||
|
${!el.add_task_form_opened
|
||||||
|
? ''
|
||||||
|
: tplMucAddTaskForm(el, tasklist)
|
||||||
|
}`
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ export default function tplMucTaskLists (el, tasklists) {
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>
|
<label>
|
||||||
${i18nCreateTaskList}
|
${i18nCreateTaskList}
|
||||||
<input type="text" value="" name="name" placeholder="${i18nTaskListName}" />
|
<input type="text" value="" class="form-control" name="name" placeholder="${i18nTaskListName}" />
|
||||||
</label>
|
</label>
|
||||||
<input type="submit" value="${i18nAdd}" class="btn btn-primary" />
|
<input type="submit" value="${i18nAdd}" class="btn btn-primary" />
|
||||||
${!el.create_tasklist_error_message
|
${!el.create_tasklist_error_message
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { html } from 'lit'
|
import { html } from 'lit'
|
||||||
|
import { __ } from 'i18n'
|
||||||
|
|
||||||
export default function tplMucTask (task) {
|
export function tplMucTask (task) {
|
||||||
const done = task.get('done')
|
const done = task.get('done')
|
||||||
return html`
|
return html`
|
||||||
<div class="">
|
<div class="">
|
||||||
@ -15,3 +16,29 @@ export default function tplMucTask (task) {
|
|||||||
${task.get('name')}
|
${task.get('name')}
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tplMucAddTaskForm (tasklistEl, _tasklist) {
|
||||||
|
const i18nOk = __('Ok')
|
||||||
|
const i18nCancel = __('Cancel')
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nTaskName = __(LOC_task_name)
|
||||||
|
// eslint-disable-next-line no-undef
|
||||||
|
const i18nTaskDesc = __(LOC_task_description)
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<form class="task-list-add-task converse-form" @submit=${tasklistEl.submitAddTask}>
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<input type="text" name="name"
|
||||||
|
class="form-control" value=""
|
||||||
|
placeholder="${i18nTaskName}"
|
||||||
|
/>
|
||||||
|
<textarea class="form-control" name="description" placeholder="${i18nTaskDesc}"></textarea>
|
||||||
|
</fieldset>
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<input type="submit" class="btn btn-primary" value="${i18nOk}" />
|
||||||
|
<input type="button" class="btn btn-secondary button-cancel"
|
||||||
|
value="${i18nCancel}" @click=${tasklistEl.closeAddTaskForm}
|
||||||
|
/>
|
||||||
|
</fieldset>
|
||||||
|
</form>`
|
||||||
|
}
|
||||||
|
@ -61,7 +61,8 @@ function _initChatRoomTaskLists (mucModel) {
|
|||||||
xmlns: XMLNS_TASK,
|
xmlns: XMLNS_TASK,
|
||||||
collection: mucModel.tasks,
|
collection: mucModel.tasks,
|
||||||
fields: {
|
fields: {
|
||||||
name: String
|
name: String,
|
||||||
|
description: String
|
||||||
},
|
},
|
||||||
attributes: {
|
attributes: {
|
||||||
done: Boolean,
|
done: Boolean,
|
||||||
|
@ -120,6 +120,10 @@ export class PubSubManager {
|
|||||||
console.log(`Node ${this.node} created on ${this.roomJID}.`)
|
console.log(`Node ${this.node} created on ${this.roomJID}.`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteItems (items) {
|
||||||
|
await Promise.all[items.map(item => this.deleteItem(item))]
|
||||||
|
}
|
||||||
|
|
||||||
async deleteItem (item) {
|
async deleteItem (item) {
|
||||||
const id = item.get('id')
|
const id = item.get('id')
|
||||||
if (!id) {
|
if (!id) {
|
||||||
|
@ -21,7 +21,10 @@ const locKeys = [
|
|||||||
'task_list_create_error',
|
'task_list_create_error',
|
||||||
'task_list_name',
|
'task_list_name',
|
||||||
'task_list_delete',
|
'task_list_delete',
|
||||||
'task_list_delete_confirm'
|
'task_list_delete_confirm',
|
||||||
|
'task_create',
|
||||||
|
'task_name',
|
||||||
|
'task_description'
|
||||||
]
|
]
|
||||||
|
|
||||||
module.exports = locKeys
|
module.exports = locKeys
|
||||||
|
@ -441,3 +441,6 @@ task_list_create_error: 'Error when saving the task list'
|
|||||||
task_list_name: 'Task list name'
|
task_list_name: 'Task list name'
|
||||||
task_list_delete: 'Delete task list'
|
task_list_delete: 'Delete task list'
|
||||||
task_list_delete_confirm: 'Are you sure you want to delete this task list?'
|
task_list_delete_confirm: 'Are you sure you want to delete this task list?'
|
||||||
|
task_create: 'Create a new task'
|
||||||
|
task_name: 'Task name'
|
||||||
|
task_description: 'Description'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user