@microsoft/mgt
Version:
The Microsoft Graph Toolkit
1,175 lines • 43.6 kB
JavaScript
/**
* -------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
* See License in the project root for license information.
* -------------------------------------------------------------------------------------------
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { customElement, html, property } from 'lit-element';
import { classMap } from 'lit-html/directives/class-map';
import { repeat } from 'lit-html/directives/repeat';
import { Providers } from '../../Providers';
import { ProviderState } from '../../providers/IProvider';
import { getShortDateString } from '../../utils/Utils';
import { MgtTemplatedComponent } from '../templatedComponent';
import { PersonCardInteraction } from './../PersonCardInteraction';
import { styles } from './mgt-tasks-css';
import { PlannerTaskSource, TodoTaskSource } from './task-sources';
import '../mgt-person/mgt-person';
import '../sub-components/mgt-arrow-options/mgt-arrow-options';
import '../sub-components/mgt-dot-options/mgt-dot-options';
import '../sub-components/mgt-flyout/mgt-flyout';
/**
* Defines how a person card is shown when a user interacts with
* a person component
*
* @export
* @enum {number}
*/
export var TasksSource;
(function (TasksSource) {
/**
* Use Microsoft Planner
*/
TasksSource[TasksSource["planner"] = 0] = "planner";
/**
* Use Microsoft To-Do
*/
TasksSource[TasksSource["todo"] = 1] = "todo";
})(TasksSource || (TasksSource = {}));
// Strings and Resources for different task contexts
// tslint:disable-next-line: completed-docs
const TASK_RES = {
todo: {
BASE_SELF_ASSIGNED: 'All Tasks',
BUCKETS_SELF_ASSIGNED: 'All Tasks',
BUCKET_NOT_FOUND: 'Folder not found',
PLANS_SELF_ASSIGNED: 'All groups',
PLAN_NOT_FOUND: 'Group not found'
},
// tslint:disable-next-line: object-literal-sort-keys
planner: {
BASE_SELF_ASSIGNED: 'Assigned to Me',
BUCKETS_SELF_ASSIGNED: 'All Tasks',
BUCKET_NOT_FOUND: 'Bucket not found',
PLANS_SELF_ASSIGNED: 'All Plans',
PLAN_NOT_FOUND: 'Plan not found'
}
};
// tslint:disable-next-line: completed-docs
const plannerAssignment = {
'@odata.type': 'microsoft.graph.plannerAssignment',
orderHint: 'string !'
};
/**
* component enables the user to view, add, remove, complete, or edit tasks. It works with tasks in Microsoft Planner or Microsoft To-Do.
*
* @export
* @class MgtTasks
* @extends {MgtBaseComponent}
*/
let MgtTasks = class MgtTasks extends MgtTemplatedComponent {
constructor() {
super();
/**
* determines if tasks are un-editable
* @type {boolean}
*/
this.readOnly = false;
/**
* determines which task source is loaded, either planner or todo
* @type {string}
*/
this.dataSource = TasksSource.planner;
/**
* if set, the component will only show tasks from either this plan or group
* @type {string}
*/
this.targetId = null;
/**
* if set, the component will only show tasks from this bucket or folder
* @type {string}
*/
this.targetBucketId = null;
/**
* if set, the component will first show tasks from this plan or group
*
* @type {string}
* @memberof MgtTasks
*/
this.initialId = null;
/**
* if set, the component will first show tasks from this bucket or folder
*
* @type {string}
* @memberof MgtTasks
*/
this.initialBucketId = null;
/**
* sets whether the header is rendered
*
* @type {boolean}
* @memberof MgtTasks
*/
this.hideHeader = false;
/**
* allows developer to define specific group id
*/
this.groupId = null;
this._isNewTaskVisible = false;
this._newTaskBeingAdded = false;
this._newTaskName = '';
this._newTaskDueDate = null;
this._newTaskGroupId = '';
this._newTaskFolderId = '';
this._groups = [];
this._folders = [];
this._tasks = [];
this._hiddenTasks = [];
this._loadingTasks = [];
this._inTaskLoad = false;
this._hasDoneInitialLoad = false;
this._todoDefaultSet = false;
this.isPeoplePickerVisible = false;
this._me = null;
this.providerUpdateCallback = () => this.loadTasks();
this.handleWindowClick = () => this.hidePeoplePicker();
}
/**
* determines whether todo, or planner functionality for task component
*
* @readonly
* @memberof MgtTasks
*/
get res() {
switch (this.dataSource) {
case TasksSource.todo:
return TASK_RES.todo;
case TasksSource.planner:
default:
return TASK_RES.planner;
}
}
/**
* Array of styles to apply to the element. The styles should be defined
* using the `css` tag function.
*/
static get styles() {
return styles;
}
/**
* Get whether new task view is visible
*
* @memberof MgtTasks
*/
get isNewTaskVisible() {
return this._isNewTaskVisible;
}
/**
* Set whether new task is visible
*
* @memberof MgtTasks
*/
set isNewTaskVisible(value) {
this._isNewTaskVisible = value;
if (!value) {
this._newTaskDueDate = null;
this._newTaskName = '';
this._newTaskGroupId = '';
}
}
/**
* updates provider state
*
* @memberof MgtTasks
*/
connectedCallback() {
super.connectedCallback();
Providers.onProviderUpdated(this.providerUpdateCallback);
window.addEventListener('click', this.handleWindowClick);
}
/**
* removes updates on provider state
*
* @memberof MgtTasks
*/
disconnectedCallback() {
Providers.removeProviderUpdatedListener(this.providerUpdateCallback);
window.removeEventListener('click', this.handleWindowClick);
super.disconnectedCallback();
}
/**
* Synchronizes property values when attributes change.
*
* @param {*} name
* @param {*} oldValue
* @param {*} newValue
* @memberof MgtTasks
*/
attributeChangedCallback(name, oldVal, newVal) {
super.attributeChangedCallback(name, oldVal, newVal);
if (name === 'data-source') {
if (this.dataSource === TasksSource.planner) {
this._currentGroup = this.initialId;
this._currentFolder = this.initialBucketId;
}
else if (this.dataSource === TasksSource.todo) {
this._currentGroup = null;
this._currentFolder = this.initialId;
}
this._newTaskFolderId = '';
this._newTaskGroupId = '';
this._newTaskDueDate = null;
this._newTaskName = '';
this._newTaskBeingAdded = false;
this._tasks = [];
this._folders = [];
this._groups = [];
this._hasDoneInitialLoad = false;
this._inTaskLoad = false;
this._todoDefaultSet = false;
this.loadTasks();
}
}
/**
* Invoked when the element is first updated. Implement to perform one time
* work on the element after update.
*
* Setting properties inside this method will trigger the element to update
* again after this update cycle completes.
*
* * @param _changedProperties Map of changed properties with old values
*/
firstUpdated() {
if (this.initialId && !this._currentGroup) {
if (this.dataSource === TasksSource.planner) {
this._currentGroup = this.initialId;
}
else if (this.dataSource === TasksSource.todo) {
this._currentFolder = this.initialId;
}
}
if (this.dataSource === TasksSource.planner && this.initialBucketId && !this._currentFolder) {
this._currentFolder = this.initialBucketId;
}
this.loadTasks();
}
/**
* Invoked on each update to perform rendering tasks. This method must return
* a lit-html TemplateResult. Setting properties inside this method will *not*
* trigger the element to update.
*/
render() {
let tasks = this._tasks
.filter(task => this.isTaskInSelectedGroupFilter(task))
.filter(task => this.isTaskInSelectedFolderFilter(task))
.filter(task => !this._hiddenTasks.includes(task.id));
if (this.taskFilter) {
tasks = tasks.filter(task => this.taskFilter(task._raw));
}
const loadingTask = this._inTaskLoad && !this._hasDoneInitialLoad ? this.renderLoadingTask() : null;
let header;
if (!this.hideHeader) {
header = html `
<div class="Header">
<span class="PlannerTitle">
${this.renderPlanOptions()}
</span>
</div>
`;
}
return html `
${header}
<div class="Tasks">
${this._isNewTaskVisible ? this.renderNewTask() : null} ${loadingTask}
${repeat(tasks, task => task.id, task => this.renderTask(task))}
</div>
`;
}
/**
* loads tasks from dataSource
*
* @returns
* @memberof MgtTasks
*/
loadTasks() {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
const provider = Providers.globalProvider;
if (!provider || provider.state !== ProviderState.SignedIn) {
return;
}
this._inTaskLoad = true;
let meTask;
if (!this._me) {
meTask = provider.graph.getMe();
}
if (this.groupId && this.dataSource === TasksSource.planner) {
yield this._loadTasksForGroup(ts);
}
else if (this.targetId) {
if (this.dataSource === TasksSource.todo) {
yield this._loadTargetTodoTasks(ts);
}
else {
yield this._loadTargetPlannerTasks(ts);
}
}
else {
yield this._loadAllTasks(ts);
}
if (meTask) {
this._me = yield meTask;
}
this._inTaskLoad = false;
this._hasDoneInitialLoad = true;
});
}
_loadTargetTodoTasks(ts) {
return __awaiter(this, void 0, void 0, function* () {
const groups = yield ts.getTaskGroups();
const folders = (yield Promise.all(groups.map(group => ts.getTaskFoldersForTaskGroup(group.id)))).reduce((cur, ret) => [...cur, ...ret], []);
const tasks = (yield Promise.all(folders.map(folder => ts.getTasksForTaskFolder(folder.id, folder.parentId)))).reduce((cur, ret) => [...cur, ...ret], []);
this._tasks = tasks;
this._folders = folders;
this._groups = groups;
this._currentGroup = null;
});
}
_loadTargetPlannerTasks(ts) {
return __awaiter(this, void 0, void 0, function* () {
const group = yield ts.getTaskGroup(this.targetId);
let folders = yield ts.getTaskFoldersForTaskGroup(group.id);
if (this.targetBucketId) {
folders = folders.filter(folder => folder.id === this.targetBucketId);
}
const tasks = (yield Promise.all(folders.map(folder => ts.getTasksForTaskFolder(folder.id, folder.parentId)))).reduce((cur, ret) => [...cur, ...ret], []);
this._tasks = tasks;
this._folders = folders;
this._groups = [group];
});
}
_loadAllTasks(ts) {
return __awaiter(this, void 0, void 0, function* () {
const groups = yield ts.getTaskGroups();
const folders = (yield Promise.all(groups.map(group => ts.getTaskFoldersForTaskGroup(group.id)))).reduce((cur, ret) => [...cur, ...ret], []);
if (!this.initialId && this.dataSource === TasksSource.todo && !this._todoDefaultSet) {
this._todoDefaultSet = true;
const defaultFolder = folders.find(d => d._raw.isDefaultFolder);
if (defaultFolder) {
this._currentFolder = defaultFolder.id;
}
}
const tasks = (yield Promise.all(folders.map(folder => ts.getTasksForTaskFolder(folder.id, folder.parentId)))).reduce((cur, ret) => [...cur, ...ret], []);
this._tasks = tasks;
this._folders = folders;
this._groups = groups;
});
}
_loadTasksForGroup(ts) {
return __awaiter(this, void 0, void 0, function* () {
const groups = yield ts.getTaskGroupsForGroup(this.groupId);
const folders = (yield Promise.all(groups.map(group => ts.getTaskFoldersForTaskGroup(group.id)))).reduce((cur, ret) => [...cur, ...ret], []);
const tasks = (yield Promise.all(folders.map(folder => ts.getTasksForTaskFolder(folder.id, folder.parentId)))).reduce((cur, ret) => [...cur, ...ret], []);
this._tasks = tasks;
this._folders = folders;
this._groups = groups;
});
}
addTask(name, dueDate, topParentId, immediateParentId, assignments = {}) {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
const newTask = {
assignments,
dueDate,
immediateParentId,
name,
topParentId
};
this._newTaskBeingAdded = true;
yield ts.addTask(newTask);
yield this.loadTasks();
this._newTaskBeingAdded = false;
this.isNewTaskVisible = false;
});
}
completeTask(task) {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
this._loadingTasks = [...this._loadingTasks, task.id];
yield ts.setTaskComplete(task.id, task.eTag);
yield this.loadTasks();
this._loadingTasks = this._loadingTasks.filter(id => id !== task.id);
});
}
uncompleteTask(task) {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
this._loadingTasks = [...this._loadingTasks, task.id];
yield ts.setTaskIncomplete(task.id, task.eTag);
yield this.loadTasks();
this._loadingTasks = this._loadingTasks.filter(id => id !== task.id);
});
}
removeTask(task) {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
this._hiddenTasks = [...this._hiddenTasks, task.id];
yield ts.removeTask(task.id, task.eTag);
yield this.loadTasks();
this._hiddenTasks = this._hiddenTasks.filter(id => id !== task.id);
});
}
assignPeople(task, people) {
return __awaiter(this, void 0, void 0, function* () {
const ts = this.getTaskSource();
if (!ts) {
return;
}
// create previously selected people Object
let savedSelectedPeople = [];
if (task) {
if (task.assignments) {
savedSelectedPeople = Object.keys(task.assignments).sort();
}
}
const newPeopleIds = people.map(person => {
return person.id;
});
// new people from people picker
const isEqual = newPeopleIds.length === savedSelectedPeople.length &&
newPeopleIds.sort().every((value, index) => {
return value === savedSelectedPeople[index];
});
if (isEqual) {
return;
}
const peopleObj = {};
if (people.length === 0) {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < savedSelectedPeople.length; i++) {
peopleObj[savedSelectedPeople[i]] = null;
}
}
if (people) {
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < savedSelectedPeople.length; i++) {
// tslint:disable-next-line: prefer-for-of
for (let j = 0; j < people.length; j++) {
if (savedSelectedPeople[i] !== people[j].id) {
peopleObj[savedSelectedPeople[i]] = null;
break;
}
else {
peopleObj[savedSelectedPeople[i]] = plannerAssignment;
}
}
}
// tslint:disable-next-line: prefer-for-of
for (let i = 0; i < people.length; i++) {
peopleObj[people[i].id] = plannerAssignment;
}
}
if (task) {
this._loadingTasks = [...this._loadingTasks, task.id];
yield ts.assignPeopleToTask(task.id, peopleObj, task.eTag);
yield this.loadTasks();
this._loadingTasks = this._loadingTasks.filter(id => id !== task.id);
}
});
}
onAddTaskClick(e) {
const picker = this.getPeoplePicker(null);
const peopleObj = {};
if (picker) {
for (const person of picker.selectedPeople) {
if (picker.selectedPeople.length) {
peopleObj[person.id] = plannerAssignment;
}
}
}
if (!this._newTaskBeingAdded && this._newTaskName && (this._currentGroup || this._newTaskGroupId)) {
this.addTask(this._newTaskName, this._newTaskDueDate, !this._currentGroup ? this._newTaskGroupId : this._currentGroup, !this._currentFolder ? this._newTaskFolderId : this._currentFolder, peopleObj);
}
}
renderPlanOptions() {
const p = Providers.globalProvider;
if (!p || p.state !== ProviderState.SignedIn) {
return null;
}
if (this._inTaskLoad && !this._hasDoneInitialLoad) {
return html `
<span class="LoadingHeader"></span>
`;
}
const addButton = this.readOnly || this._isNewTaskVisible
? null
: html `
<span
class="AddBarItem NewTaskButton"
@click="${() => {
this.isNewTaskVisible = !this.isNewTaskVisible;
}}"
>
<span class="TaskIcon">\uE710</span>
<span>Add</span>
</span>
`;
if (this.dataSource === TasksSource.planner) {
const currentGroup = this._groups.find(d => d.id === this._currentGroup) || {
title: this.res.BASE_SELF_ASSIGNED
};
const groupOptions = {
[this.res.BASE_SELF_ASSIGNED]: e => {
this._currentGroup = null;
this._currentFolder = null;
}
};
for (const group of this._groups) {
groupOptions[group.title] = e => {
this._currentGroup = group.id;
this._currentFolder = null;
};
}
const groupSelect = html `
<mgt-arrow-options .options="${groupOptions}" .value="${currentGroup.title}"></mgt-arrow-options>
`;
const divider = !this._currentGroup
? null
: html `
<span class="TaskIcon Divider">/</span>
`;
const currentFolder = this._folders.find(d => d.id === this._currentFolder) || {
name: this.res.BUCKETS_SELF_ASSIGNED
};
const folderOptions = {
[this.res.BUCKETS_SELF_ASSIGNED]: e => {
this._currentFolder = null;
}
};
for (const folder of this._folders.filter(d => d.parentId === this._currentGroup)) {
folderOptions[folder.name] = e => {
this._currentFolder = folder.id;
};
}
const folderSelect = this.targetBucketId
? html `
<span class="PlanTitle">
${this._folders[0] && this._folders[0].name}
</span>
`
: html `
<mgt-arrow-options .options="${folderOptions}" .value="${currentFolder.name}"></mgt-arrow-options>
`;
return html `
<span class="TitleCont">
${groupSelect} ${divider} ${!this._currentGroup ? null : folderSelect}
</span>
${addButton}
`;
}
else {
const folder = this._folders.find(d => d.id === this.targetId) || { name: this.res.BUCKETS_SELF_ASSIGNED };
const currentFolder = this._folders.find(d => d.id === this._currentFolder) || {
name: this.res.BUCKETS_SELF_ASSIGNED
};
const folderOptions = {};
for (const d of this._folders) {
folderOptions[d.name] = () => {
this._currentFolder = d.id;
};
}
folderOptions[this.res.BUCKETS_SELF_ASSIGNED] = e => {
this._currentFolder = null;
};
const folderSelect = this.targetId
? html `
<span class="PlanTitle">
${folder.name}
</span>
`
: html `
<mgt-arrow-options .value="${currentFolder.name}" .options="${folderOptions}"></mgt-arrow-options>
`;
return html `
<span class="TitleCont">
${folderSelect}
</span>
${addButton}
`;
}
}
renderNewTask() {
const taskTitle = html `
<input
type="text"
placeholder="Task..."
.value="${this._newTaskName}"
label="new-taskName-input"
aria-label="new-taskName-input"
role="input"
@input="${(e) => {
this._newTaskName = e.target.value;
}}"
/>
`;
const groups = this._groups;
if (groups.length > 0 && !this._newTaskGroupId) {
this._newTaskGroupId = groups[0].id;
}
const group = this.dataSource === TasksSource.todo
? null
: this._currentGroup
? html `
<span class="TaskDetail TaskAssignee">
${this.renderPlannerIcon()}
<span>${this.getPlanTitle(this._currentGroup)}</span>
</span>
`
: html `
<span class="TaskDetail TaskAssignee">
${this.renderPlannerIcon()}
<select
.value="${this._newTaskGroupId}"
@change="${(e) => {
this._newTaskGroupId = e.target.value;
}}"
>
${this._groups.map(plan => html `
<option value="${plan.id}">${plan.title}</option>
`)}
</select>
</span>
`;
const folders = this._folders.filter(folder => (this._currentGroup && folder.parentId === this._currentGroup) ||
(!this._currentGroup && folder.parentId === this._newTaskGroupId));
if (folders.length > 0 && !this._newTaskFolderId) {
this._newTaskFolderId = folders[0].id;
}
const taskFolder = this._currentFolder
? html `
<span class="TaskDetail TaskBucket">
${this.renderBucketIcon()}
<span>${this.getFolderName(this._currentFolder)}</span>
</span>
`
: html `
<span class="TaskDetail TaskBucket">
${this.renderBucketIcon()}
<select
.value="${this._newTaskFolderId}"
@change="${(e) => {
this._newTaskFolderId = e.target.value;
}}"
>
${folders.map(folder => html `
<option value="${folder.id}">${folder.name}</option>
`)}
</select>
</span>
`;
const taskDue = html `
<span class="TaskDetail TaskDue">
${this.renderCalendarIcon()}
<input
type="date"
label="new-taskDate-input"
aria-label="new-taskDate-input"
role="input"
.value="${this.dateToInputValue(this._newTaskDueDate)}"
@change="${(e) => {
const value = e.target.value;
if (value) {
this._newTaskDueDate = new Date(value + 'T17:00');
}
else {
this._newTaskDueDate = null;
}
}}"
/>
</span>
`;
const taskPeople = this.dataSource === TasksSource.todo ? null : this.renderAssignedPeople(null);
const taskAdd = this._newTaskBeingAdded
? html `
<div class="TaskAddButtonContainer"></div>
`
: html `
<div class="TaskAddButtonContainer ${this._newTaskName === '' ? 'Disabled' : ''}">
<div class="TaskIcon TaskCancel" @click="${() => (this.isNewTaskVisible = false)}">
<span>Cancel</span>
</div>
<div class="TaskIcon TaskAdd" @click="${this.onAddTaskClick}">
<span>\uE710</span>
</div>
</div>
`;
return html `
<div class="Task NewTask Incomplete">
<div class="TaskContent">
<div class="TaskDetailsContainer">
<div class="TaskTitle">
${taskTitle}
</div>
<hr />
<div class="TaskDetails">
${group} ${taskFolder} ${taskPeople} ${taskDue}
</div>
</div>
</div>
${taskAdd}
</div>
`;
}
showPeoplePicker(task) {
if (this.isPeoplePickerVisible) {
const isCurrentTask = task === this._currentTask;
if (isCurrentTask) {
this.hidePeoplePicker();
return;
}
}
this._currentTask = task;
this.isPeoplePickerVisible = true;
// logic for already created tasks
const picker = this.getPeoplePicker(task);
const mgtPeople = this.getMgtPeople(task);
if (picker && mgtPeople) {
picker.selectedPeople = mgtPeople.people;
setTimeout(() => {
picker.focus();
}, 50);
}
}
hidePeoplePicker() {
const picker = this.getPeoplePicker(this._currentTask);
const mgtPeople = this.getMgtPeople(this._currentTask);
if (picker) {
mgtPeople.people = picker.selectedPeople;
this.assignPeople(this._currentTask, picker.selectedPeople);
}
this.isPeoplePickerVisible = false;
this._currentTask = null;
}
getPeoplePicker(task) {
const taskId = task ? task.id : 'newTask';
const picker = this.renderRoot.querySelector(`.picker-${taskId}`);
return picker;
}
getMgtPeople(task) {
const taskId = task ? task.id : 'newTask';
const mgtPeople = this.renderRoot.querySelector(`.people-${taskId}`);
return mgtPeople;
}
renderTask(task) {
const { name = 'Task', completed = false, dueDate } = task;
const isLoading = this._loadingTasks.includes(task.id);
const taskCheckClasses = {
Complete: !isLoading && completed,
Loading: isLoading,
TaskCheck: true,
TaskIcon: true
};
const taskCheckContent = isLoading
? html `
\uF16A
`
: completed
? html `
\uE73E
`
: null;
const taskCheck = html `
<span class=${classMap(taskCheckClasses)}>${taskCheckContent}</span>
`;
const groupTitle = this._currentGroup ? null : this.getPlanTitle(task.topParentId);
const folderTitle = this._currentFolder ? null : this.getFolderName(task.immediateParentId);
const context = { task: Object.assign(Object.assign({}, task._raw), { groupTitle, folderTitle }) };
const taskTemplate = this.renderTemplate('task', context, task.id);
if (taskTemplate) {
return taskTemplate;
}
let taskDetails = this.renderTemplate('task-details', context, `task-details-${task.id}`);
if (!taskDetails) {
const group = this.dataSource === TasksSource.todo || this._currentGroup
? null
: html `
<span class="TaskDetail TaskAssignee">
${this.renderPlannerIcon()}
<span>${this.getPlanTitle(task.topParentId)}</span>
</span>
`;
const folder = this._currentFolder
? null
: html `
<span class="TaskDetail TaskBucket">
${this.renderBucketIcon()}
<span>${this.getFolderName(task.immediateParentId)}</span>
</span>
`;
const taskDue = !dueDate
? null
: html `
<span class="TaskDetail TaskDue">
${this.renderCalendarIcon()}
<span>${getShortDateString(dueDate)}</span>
</span>
`;
const taskPeople = this.dataSource !== TasksSource.todo ? this.renderAssignedPeople(task) : null;
taskDetails = html `
<div class="TaskTitle">
${name}
</div>
<div class="TaskDetails">
${group} ${folder} ${taskPeople} ${taskDue}
</div>
`;
}
const taskOptions = this.readOnly
? null
: html `
<div class="TaskOptions">
<mgt-dot-options
.options="${{
'Delete Task': () => this.removeTask(task)
}}"
></mgt-dot-options>
</div>
`;
return html `
<div
class=${classMap({
Complete: completed,
Incomplete: !completed,
ReadOnly: this.readOnly,
Task: true
})}
>
<div
class="TaskContent"
@click=${() => {
this.handleTaskClick(task);
}}
>
<span
class=${classMap({
Complete: completed,
Incomplete: !completed,
TaskCheckContainer: true
})}
@click="${e => {
if (!this.readOnly) {
if (!task.completed) {
this.completeTask(task);
}
else {
this.uncompleteTask(task);
}
e.stopPropagation();
e.preventDefault();
}
}}"
>
${taskCheck}
</span>
<div class="TaskDetailsContainer">
${taskDetails}
</div>
</div>
${taskOptions}
</div>
`;
}
renderAssignedPeople(task) {
let assignedPeopleHTML = null;
const assignedPeople = task
? Object.keys(task.assignments).map(key => {
return key;
})
: [];
const noPeopleTemplate = html `
<template data-type="no-data">
<i class="login-icon ms-Icon ms-Icon--Contact"></i>
</template>
`;
const taskId = task ? task.id : 'newTask';
assignedPeopleHTML = html `
<mgt-people
class="people-${taskId}"
.userIds="${assignedPeople}"
.personCardInteraction=${this.isPeoplePickerVisible ? PersonCardInteraction.none : PersonCardInteraction.hover}
>${noPeopleTemplate}
</mgt-people>
`;
return html `
<mgt-flyout
class="TaskDetail TaskPeople"
@click=${(e) => {
this.showPeoplePicker(task);
e.stopPropagation();
}}
.isOpen=${this.isPeoplePickerVisible && task === this._currentTask}
>
${assignedPeopleHTML}
<div slot="flyout" class=${classMap({ Picker: true })}>
<mgt-people-picker
class="picker-${taskId}"
@click=${(e) => e.stopPropagation()}
></mgt-people-picker>
</div>
</mgt-flyout>
`;
}
handleTaskClick(task) {
if (task && !this.isPeoplePickerVisible) {
this.fireCustomEvent('taskClick', { task: task._raw });
}
}
renderLoadingTask() {
return html `
<div class="Task LoadingTask">
<div class="TaskContent">
<div class="TaskCheckContainer">
<div class="TaskCheck"></div>
</div>
<div class="TaskDetailsContainer">
<div class="TaskTitle"></div>
<div class="TaskDetails">
<span class="TaskDetail">
<div class="TaskDetailIcon"></div>
<div class="TaskDetailName"></div>
</span>
<span class="TaskDetail">
<div class="TaskDetailIcon"></div>
<div class="TaskDetailName"></div>
</span>
<span class="TaskDetail">
<div class="TaskDetailIcon"></div>
<div class="TaskDetailName"></div>
</span>
<span class="TaskDetail">
<div class="TaskDetailIcon"></div>
<div class="TaskDetailName"></div>
</span>
</div>
</div>
</div>
</div>
`;
}
renderPlannerIcon() {
return html `
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.223 1.156C6.98 1.26 6.769 1.404 6.586 1.586C6.403 1.768 6.261 1.98 6.157 2.223C6.052 2.465 6 2.724 6 3H2V17H14V3H10C10 2.724 9.948 2.465 9.844 2.223C9.74 1.98 9.596 1.768 9.414 1.586C9.231 1.404 9.02 1.26 8.777 1.156C8.535 1.053 8.276 1 8 1C7.723 1 7.465 1.053 7.223 1.156ZM5 4H7V3C7 2.86 7.026 2.729 7.078 2.609C7.13 2.49 7.202 2.385 7.293 2.293C7.384 2.202 7.49 2.131 7.609 2.079C7.73 2.026 7.859 2 8 2C8.14 2 8.271 2.026 8.39 2.079C8.511 2.131 8.616 2.202 8.707 2.293C8.798 2.385 8.87 2.49 8.922 2.609C8.974 2.729 9 2.86 9 3V4H11V5H5V4ZM12 6V4H13V16H3V4H4V6H12Z"
fill="#3C3C3C"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.35156 12.3517L5.49956 14.2037L4.14856 12.8517L4.85156 12.1487L5.49956 12.7967L6.64856 11.6487L7.35156 12.3517Z"
fill="#3C3C3C"
/>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M7.35156 8.35168L5.49956 10.2037L4.14856 8.85168L4.85156 8.14868L5.49956 8.79668L6.64856 7.64868L7.35156 8.35168Z"
fill="#3C3C3C"
/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 14H12.001V13H8V14Z" fill="#3C3C3C" />
<path fill-rule="evenodd" clip-rule="evenodd" d="M8 10H12.001V9H8V10Z" fill="#3C3C3C" />
</svg>
`;
}
renderBucketIcon() {
return html `
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M14 2H2V4H3H5H6H10H11H13H14V2ZM10 5H6V6H10V5ZM5 5H3V14H13V5H11V6C11 6.55228 10.5523 7 10 7H6C5.44772 7 5 6.55228 5 6V5ZM1 5H2V14V15H3H13H14V14V5H15V4V2V1H14H2H1V2V4V5Z"
fill="#3C3C3C"
/>
</svg>
`;
}
renderCalendarIcon() {
return html `
<svg width="20" height="18" viewBox="0 0 20 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M12 7H11V8H12V7ZM9 13H8V14H9V13ZM6 7H5V8H6V7ZM9 7H8V8H9V7ZM12 9H11V10H12V9ZM15 9H14V10H15V9ZM6 9H5V10H6V9ZM9 9H8V10H9V9ZM12 11H11V12H12V11ZM15 11H14V12H15V11ZM6 11H5V12H6V11ZM9 11H8V12H9V11ZM12 13H11V14H12V13ZM15 13H14V14H15V13ZM2 2V16H18V2H15V1H14V2H6V1H5V2H2ZM17 3V5H3V3H5V4H6V3H14V4H15V3H17ZM3 15V6H17V15H3Z"
fill="#3C3C3C"
/>
</svg>
`;
}
getTaskSource() {
const p = Providers.globalProvider;
if (!p || p.state !== ProviderState.SignedIn) {
return null;
}
if (this.dataSource === TasksSource.planner) {
return new PlannerTaskSource(p.graph);
}
else if (this.dataSource === TasksSource.todo) {
return new TodoTaskSource(p.graph);
}
else {
return null;
}
}
getPlanTitle(planId) {
if (!planId) {
return this.res.BASE_SELF_ASSIGNED;
}
else if (planId === this.res.PLANS_SELF_ASSIGNED) {
return this.res.PLANS_SELF_ASSIGNED;
}
else {
return (this._groups.find(plan => plan.id === planId) || {
title: this.res.PLAN_NOT_FOUND
}).title;
}
}
getFolderName(bucketId) {
if (!bucketId) {
return this.res.BUCKETS_SELF_ASSIGNED;
}
return (this._folders.find(buck => buck.id === bucketId) || {
name: this.res.BUCKET_NOT_FOUND
}).name;
}
isTaskInSelectedGroupFilter(task) {
return (task.topParentId === this._currentGroup ||
(!this._currentGroup && this.getTaskSource().isAssignedToMe(task, this._me.id)));
}
isTaskInSelectedFolderFilter(task) {
return task.immediateParentId === this._currentFolder || !this._currentFolder;
}
dateToInputValue(date) {
if (date) {
return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().split('T')[0];
}
return null;
}
};
__decorate([
property({ attribute: 'read-only', type: Boolean })
], MgtTasks.prototype, "readOnly", void 0);
__decorate([
property({
attribute: 'data-source',
converter: (value, type) => {
value = value.toLowerCase();
return TasksSource[value] || TasksSource.planner;
}
})
], MgtTasks.prototype, "dataSource", void 0);
__decorate([
property({ attribute: 'target-id', type: String })
], MgtTasks.prototype, "targetId", void 0);
__decorate([
property({ attribute: 'target-bucket-id', type: String })
], MgtTasks.prototype, "targetBucketId", void 0);
__decorate([
property({ attribute: 'initial-id', type: String })
], MgtTasks.prototype, "initialId", void 0);
__decorate([
property({ attribute: 'initial-bucket-id', type: String })
], MgtTasks.prototype, "initialBucketId", void 0);
__decorate([
property({ attribute: 'hide-header', type: Boolean })
], MgtTasks.prototype, "hideHeader", void 0);
__decorate([
property({ attribute: 'group-id', type: String })
], MgtTasks.prototype, "groupId", void 0);
__decorate([
property()
], MgtTasks.prototype, "_isNewTaskVisible", void 0);
__decorate([
property()
], MgtTasks.prototype, "_newTaskBeingAdded", void 0);
__decorate([
property()
], MgtTasks.prototype, "_newTaskName", void 0);
__decorate([
property()
], MgtTasks.prototype, "_newTaskDueDate", void 0);
__decorate([
property()
], MgtTasks.prototype, "_newTaskGroupId", void 0);
__decorate([
property()
], MgtTasks.prototype, "_newTaskFolderId", void 0);
__decorate([
property()
], MgtTasks.prototype, "_groups", void 0);
__decorate([
property()
], MgtTasks.prototype, "_folders", void 0);
__decorate([
property()
], MgtTasks.prototype, "_tasks", void 0);
__decorate([
property()
], MgtTasks.prototype, "_hiddenTasks", void 0);
__decorate([
property()
], MgtTasks.prototype, "_loadingTasks", void 0);
__decorate([
property()
], MgtTasks.prototype, "_inTaskLoad", void 0);
__decorate([
property()
], MgtTasks.prototype, "_hasDoneInitialLoad", void 0);
__decorate([
property()
], MgtTasks.prototype, "_todoDefaultSet", void 0);
__decorate([
property()
], MgtTasks.prototype, "_currentGroup", void 0);
__decorate([
property()
], MgtTasks.prototype, "_currentFolder", void 0);
__decorate([
property()
], MgtTasks.prototype, "_currentTask", void 0);
__decorate([
property()
], MgtTasks.prototype, "isPeoplePickerVisible", void 0);
MgtTasks = __decorate([
customElement('mgt-tasks')
], MgtTasks);
export { MgtTasks };
//# sourceMappingURL=mgt-tasks.js.map