mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-25 00:25:03 +08:00
Give Task classes formal attributes
just like Models
This commit is contained in:
parent
bb64766334
commit
a77b81181f
17 changed files with 166 additions and 100 deletions
|
@ -72,8 +72,6 @@ export default class MailsyncBridge {
|
|||
}
|
||||
|
||||
task.validate();
|
||||
|
||||
task.sequentialId = ++this._currentSequentialId;
|
||||
task.status = 'local';
|
||||
this.sendMessageToAccount(task.accountId, {type: 'task-queued', task: task});
|
||||
}
|
||||
|
|
|
@ -88,9 +88,6 @@ export default class Category extends Model {
|
|||
localStatus: Attributes.Object({
|
||||
modelKey: 'localStatus',
|
||||
}),
|
||||
_refcount: Attributes.Number({
|
||||
modelKey: '_refcount',
|
||||
}),
|
||||
});
|
||||
|
||||
static Types = {
|
||||
|
|
|
@ -168,10 +168,6 @@ export default class Message extends ModelWithMetadata {
|
|||
itemClass: Folder,
|
||||
}),
|
||||
|
||||
folderUID: Attributes.Number({
|
||||
modelKey: 'folderUID',
|
||||
}),
|
||||
|
||||
});
|
||||
|
||||
static naturalSortOrder() {
|
||||
|
|
|
@ -40,7 +40,7 @@ export default class Model {
|
|||
this.fromJSON(data);
|
||||
} else {
|
||||
for (const key of Object.keys(this.constructor.attributes)) {
|
||||
if (data[key]) {
|
||||
if (data[key] !== undefined) {
|
||||
this[key] = data[key];
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export default class Model {
|
|||
fromJSON(json) {
|
||||
for (const key of Object.keys(this.constructor.attributes)) {
|
||||
const attr = this.constructor.attributes[key];
|
||||
const attrValue = json[attr.jsonKey];
|
||||
const attrValue = json[attr.jsonKey || key];
|
||||
if (attrValue !== undefined) {
|
||||
this[key] = attr.fromJSON(attrValue);
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ export default class Model {
|
|||
if (attrValue === undefined) {
|
||||
continue;
|
||||
}
|
||||
json[attr.jsonKey] = attr.toJSON(attrValue);
|
||||
json[attr.jsonKey || key] = attr.toJSON(attrValue);
|
||||
}
|
||||
json.__cls = this.constructor.name
|
||||
return json;
|
||||
|
|
|
@ -30,7 +30,6 @@ class DraftFactory
|
|||
version: 0
|
||||
unread: false
|
||||
starred: false
|
||||
folderUID: 0
|
||||
headerMessageId: Utils.generateTempId() + "@" + require('os').hostname()
|
||||
from: [account.defaultMe()]
|
||||
date: (new Date)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import Category from '../models/category';
|
||||
import ChangeMailTask from './change-mail-task';
|
||||
import Attributes from '../attributes';
|
||||
import Folder from '../models/folder';
|
||||
|
||||
// Public: Create a new task to apply labels to a message or thread.
|
||||
//
|
||||
|
@ -14,11 +15,15 @@ import ChangeMailTask from './change-mail-task';
|
|||
//
|
||||
export default class ChangeFolderTask extends ChangeMailTask {
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.source = options.source
|
||||
this.taskDescription = options.taskDescription;
|
||||
this.folder = options.folder;
|
||||
static attributes = Object.assign({}, ChangeMailTask.attributes, {
|
||||
folder: Attributes.Object({
|
||||
modelKey: 'folder',
|
||||
ItemClass: Folder,
|
||||
}),
|
||||
});
|
||||
|
||||
constructor(data = {}) {
|
||||
super(data);
|
||||
}
|
||||
|
||||
label() {
|
||||
|
@ -33,10 +38,7 @@ export default class ChangeFolderTask extends ChangeMailTask {
|
|||
return this.taskDescription;
|
||||
}
|
||||
|
||||
let folderText = " to folder";
|
||||
if (this.folder instanceof Category) {
|
||||
folderText = ` to ${this.folder.displayName}`;
|
||||
}
|
||||
const folderText = ` to ${this.folder.displayName}`;
|
||||
|
||||
if (this.threadIds.length > 1) {
|
||||
return `Moved ${this.threadIds.length} threads${folderText}`;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Label from '../models/label';
|
||||
import Category from '../models/category';
|
||||
import ChangeMailTask from './change-mail-task';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
// Public: Create a new task to apply labels to a message or thread.
|
||||
//
|
||||
|
@ -9,14 +9,22 @@ import ChangeMailTask from './change-mail-task';
|
|||
// - labelsToRemove: An {Array} of {Category}s or {Category} ids to remove
|
||||
// - threads: An {Array} of {Thread}s or {Thread} ids
|
||||
// - messages: An {Array} of {Message}s or {Message} ids
|
||||
//
|
||||
export default class ChangeLabelsTask extends ChangeMailTask {
|
||||
|
||||
static attributes = Object.assign({}, ChangeMailTask.attributes, {
|
||||
labelsToAdd: Attributes.Collection({
|
||||
modelKey: 'labelsToAdd',
|
||||
ItemClass: Label,
|
||||
}),
|
||||
labelsToRemove: Attributes.Collection({
|
||||
modelKey: 'labelsToRemove',
|
||||
ItemClass: Label,
|
||||
}),
|
||||
});
|
||||
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.source = options.source
|
||||
this.labelsToAdd = options.labelsToAdd || [];
|
||||
this.labelsToRemove = options.labelsToRemove || [];
|
||||
this.taskDescription = options.taskDescription;
|
||||
}
|
||||
|
||||
label() {
|
||||
|
@ -35,35 +43,29 @@ export default class ChangeLabelsTask extends ChangeMailTask {
|
|||
|
||||
const removed = this.labelsToRemove[0];
|
||||
const added = this.labelsToAdd[0];
|
||||
const objectsAvailable = (added || removed) instanceof Category;
|
||||
|
||||
// Note: In the future, we could move this logic to the task
|
||||
// factory and pass the string in as this.taskDescription (ala Snooze), but
|
||||
// it's nice to have them declaratively based on the actual labels.
|
||||
if (objectsAvailable) {
|
||||
// Spam / trash interactions are always "moves" because they're the three
|
||||
// folders of Gmail. If another folder is involved, we need to decide to
|
||||
// return either "Moved to Bla" or "Added Bla".
|
||||
if (added && added.name === 'spam') {
|
||||
return `Marked${countString} as Spam`;
|
||||
} else if (removed && removed.name === 'spam') {
|
||||
return `Unmarked${countString} as Spam`;
|
||||
} else if (added && added.name === 'trash') {
|
||||
return `Trashed${countString}`;
|
||||
} else if (removed && removed.name === 'trash') {
|
||||
return `Removed${countString} from Trash`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 0 && this.labelsToRemove.find(l => l.role === 'inbox')) {
|
||||
return `Archived${countString}`;
|
||||
} else if (this.labelsToRemove.length === 0 && this.labelsToAdd.find(l => l.role === 'inbox')) {
|
||||
return `Unarchived${countString}`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 1 && this.labelsToRemove.length === 0) {
|
||||
return `Added ${added.displayName}${countString ? ' to' : ''}${countString}`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 0 && this.labelsToRemove.length === 1) {
|
||||
return `Removed ${removed.displayName}${countString ? ' from' : ''}${countString}`;
|
||||
}
|
||||
// Spam / trash interactions are always "moves" because they're the three
|
||||
// folders of Gmail. If another folder is involved, we need to decide to
|
||||
// return either "Moved to Bla" or "Added Bla".
|
||||
if (added && added.name === 'spam') {
|
||||
return `Marked${countString} as Spam`;
|
||||
} else if (removed && removed.name === 'spam') {
|
||||
return `Unmarked${countString} as Spam`;
|
||||
} else if (added && added.name === 'trash') {
|
||||
return `Trashed${countString}`;
|
||||
} else if (removed && removed.name === 'trash') {
|
||||
return `Removed${countString} from Trash`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 0 && this.labelsToRemove.find(l => l.role === 'inbox')) {
|
||||
return `Archived${countString}`;
|
||||
} else if (this.labelsToRemove.length === 0 && this.labelsToAdd.find(l => l.role === 'inbox')) {
|
||||
return `Unarchived${countString}`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 1 && this.labelsToRemove.length === 0) {
|
||||
return `Added ${added.displayName}${countString ? ' to' : ''}${countString}`;
|
||||
}
|
||||
if (this.labelsToAdd.length === 0 && this.labelsToRemove.length === 1) {
|
||||
return `Removed ${removed.displayName}${countString ? ' from' : ''}${countString}`;
|
||||
}
|
||||
return `Changed labels${countString ? ' on' : ''}${countString}`;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Task from './task';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
/*
|
||||
Public: The ChangeMailTask is a base class for all tasks that modify sets
|
||||
|
@ -20,8 +21,20 @@ requests. It does not call {ChangeMailTask::changesToModel}.
|
|||
*/
|
||||
export default class ChangeMailTask extends Task {
|
||||
|
||||
constructor({threads, thread, messages, message} = {}) {
|
||||
super();
|
||||
static attributes = Object.assign({}, ChangeMailTask.attributes, {
|
||||
taskDescription: Attributes.String({
|
||||
modelKey: 'taskDescription',
|
||||
}),
|
||||
threadIds: Attributes.Collection({
|
||||
modelKey: 'threadIds',
|
||||
}),
|
||||
messageIds: Attributes.Collection({
|
||||
modelKey: 'messageIds',
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({threads, thread, messages, message, ...rest} = {}) {
|
||||
super(rest);
|
||||
|
||||
const t = threads || [];
|
||||
if (thread) {
|
||||
|
|
|
@ -1,15 +1,22 @@
|
|||
/* eslint no-unused-vars: 0*/
|
||||
import _ from 'underscore';
|
||||
import Attributes from '../attributes';
|
||||
import Thread from '../models/thread';
|
||||
import Actions from '../actions'
|
||||
import DatabaseStore from '../stores/database-store';
|
||||
import ChangeMailTask from './change-mail-task';
|
||||
|
||||
export default class ChangeStarredTask extends ChangeMailTask {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.source = options.source;
|
||||
this.starred = options.starred;
|
||||
|
||||
static attributes = Object.assign({}, ChangeMailTask.attributes, {
|
||||
starred: Attributes.Boolean({
|
||||
modelKey: 'starred',
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({starred, ...rest} = {}) {
|
||||
super(rest);
|
||||
this.starred = starred;
|
||||
}
|
||||
|
||||
label() {
|
||||
|
|
|
@ -2,15 +2,25 @@
|
|||
import _ from 'underscore';
|
||||
import Thread from '../models/thread';
|
||||
import Actions from '../actions'
|
||||
import Attributes from '../attributes';
|
||||
import DatabaseStore from '../stores/database-store';
|
||||
import ChangeMailTask from './change-mail-task';
|
||||
|
||||
export default class ChangeUnreadTask extends ChangeMailTask {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
this.source = options.source;
|
||||
this.unread = options.unread;
|
||||
this._canBeUndone = options.canBeUndone;
|
||||
|
||||
static attributes = Object.assign({}, ChangeMailTask.attributes, {
|
||||
starred: Attributes.Boolean({
|
||||
modelKey: 'unread',
|
||||
}),
|
||||
_canBeUndone: Attributes.Boolean({
|
||||
modelKey: '_canBeUndone',
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({unread, canBeUndone, ...rest} = {}) {
|
||||
super(rest);
|
||||
this.unread = unread;
|
||||
this._canBeUndone = canBeUndone;
|
||||
}
|
||||
|
||||
label() {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import Task from './task';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
export default class DestroyCategoryTask extends Task {
|
||||
|
||||
constructor({path, accountId} = {}) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.accountId = accountId;
|
||||
}
|
||||
static attributes = Object.assign({}, Task.attributes, {
|
||||
path: Attributes.String({
|
||||
modelKey: 'path',
|
||||
}),
|
||||
});
|
||||
|
||||
label() {
|
||||
return `Deleting ${this.category.displayType()} ${this.category.displayName}`
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import Task from './task';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
export default class DestroyDraftTask extends Task {
|
||||
constructor(accountId, headerMessageId) {
|
||||
super();
|
||||
this.accountId = accountId;
|
||||
this.headerMessageId = headerMessageId;
|
||||
}
|
||||
|
||||
static attributes = Object.assign({}, Task.attributes, {
|
||||
headerMessageId: Attributes.String({
|
||||
modelKey: 'headerMessageId',
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ import AccountStore from '../stores/account-store';
|
|||
import Task from './task';
|
||||
import Actions from '../actions';
|
||||
import SoundRegistry from '../../registries/sound-registry';
|
||||
import Attributes from '../attributes';
|
||||
import Message from '../models/message';
|
||||
|
||||
const OPEN_TRACKING_ID = NylasEnv.packages.pluginIdFor('open-tracking')
|
||||
const LINK_TRACKING_ID = NylasEnv.packages.pluginIdFor('link-tracking')
|
||||
|
@ -10,12 +12,32 @@ const LINK_TRACKING_ID = NylasEnv.packages.pluginIdFor('link-tracking')
|
|||
|
||||
export default class SendDraftTask extends Task {
|
||||
|
||||
constructor(draft, {playSound = true, emitError = true, allowMultiSend = true} = {}) {
|
||||
super();
|
||||
this.draft = draft;
|
||||
static attributes = Object.assign({}, Task.attributes, {
|
||||
draft: Attributes.Object({
|
||||
modelKey: 'draft',
|
||||
itemClass: Message,
|
||||
}),
|
||||
headerMessageId: Attributes.String({
|
||||
modelKey: 'headerMessageId',
|
||||
}),
|
||||
emitError: Attributes.Boolean({
|
||||
modelKey: 'emitError',
|
||||
}),
|
||||
playSound: Attributes.Boolean({
|
||||
modelKey: 'playSound',
|
||||
}),
|
||||
allowMultiSend: Attributes.Boolean({
|
||||
modelKey: 'allowMultiSend',
|
||||
}),
|
||||
perRecipientBodies: Attributes.Collection({
|
||||
modelKey: 'perRecipientBodies',
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({draft, playSound = true, emitError = true, allowMultiSend = true, ...rest} = {}) {
|
||||
super(rest);
|
||||
this.accountId = (draft || {}).accountId;
|
||||
this.headerMessageId = (draft || {}).headerMessageId;
|
||||
|
||||
this.emitError = emitError
|
||||
this.playSound = playSound
|
||||
this.allowMultiSend = allowMultiSend
|
||||
|
|
|
@ -1,13 +1,25 @@
|
|||
import Task from './task';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
export default class SyncbackCategoryTask extends Task {
|
||||
|
||||
constructor({existingPath, path, accountId} = {}) {
|
||||
super()
|
||||
static attributes = Object.assign({}, Task.attributes, {
|
||||
path: Attributes.String({
|
||||
modelKey: 'path',
|
||||
}),
|
||||
existingPath: Attributes.String({
|
||||
modelKey: 'existingPath',
|
||||
}),
|
||||
created: Attributes.Object({
|
||||
modelKey: 'created',
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({existingPath, path, accountId, ...rest} = {}) {
|
||||
super(rest);
|
||||
this.existingPath = existingPath;
|
||||
this.path = path;
|
||||
this.accountId = accountId;
|
||||
this.created = null;
|
||||
}
|
||||
|
||||
label() {
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
import Task from './task';
|
||||
import Attributes from '../attributes';
|
||||
import Message from '../models/message';
|
||||
|
||||
export default class SyncbackDraftTask extends Task {
|
||||
constructor(draft) {
|
||||
super();
|
||||
|
||||
static attributes = Object.assign({}, Task.attributes, {
|
||||
headerMessageId: Attributes.String({
|
||||
modelKey: 'headerMessageId',
|
||||
}),
|
||||
draft: Attributes.Object({
|
||||
modelKey: 'draft',
|
||||
itemClass: Message,
|
||||
}),
|
||||
});
|
||||
|
||||
constructor({draft, ...rest} = {}) {
|
||||
super(rest);
|
||||
this.draft = draft;
|
||||
this.accountId = (draft || {}).accountId;
|
||||
this.headerMessageId = (draft || {}).headerMessageId;
|
||||
|
|
|
@ -15,14 +15,6 @@ export default class SyncbackMetadataTask extends SyncbackModelTask {
|
|||
return DatabaseObjectRegistry.get(this.modelClassName);
|
||||
}
|
||||
|
||||
isDependentOnTask(otherTask) {
|
||||
return (
|
||||
otherTask instanceof SyncbackMetadataTask &&
|
||||
otherTask.pluginId === this.pluginId &&
|
||||
otherTask.sequentialId < this.sequentialId
|
||||
)
|
||||
}
|
||||
|
||||
makeRequest = async (model) => {
|
||||
if (!model.serverId) {
|
||||
throw new Error(`Can't syncback metadata for a ${this.modelClassName} instance that doesn't have a serverId`)
|
||||
|
|
|
@ -27,6 +27,9 @@ export default class Task extends Model {
|
|||
queryable: true,
|
||||
modelKey: 'status',
|
||||
}),
|
||||
source: Attributes.String({
|
||||
modelKey: 'source',
|
||||
}),
|
||||
error: Attributes.Object({
|
||||
modelKey: 'error',
|
||||
}),
|
||||
|
@ -39,13 +42,10 @@ export default class Task extends Model {
|
|||
// `super`.
|
||||
//
|
||||
// On construction, all Tasks instances are given a unique `id`.
|
||||
constructor() {
|
||||
super();
|
||||
this.version = 1;
|
||||
this._rememberedToCallSuper = true;
|
||||
this.id = generateTempId();
|
||||
constructor(data) {
|
||||
super(data);
|
||||
this.id = this.id || generateTempId();
|
||||
this.accountId = null;
|
||||
this.sequentialId = null; // set when queued
|
||||
}
|
||||
|
||||
// Public: Override to raise exceptions if your task is missing required
|
||||
|
|
Loading…
Reference in a new issue