mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-21 07:46:06 +08:00
Remove Category concept, part 1
This commit is contained in:
parent
1219182b0a
commit
73f82ec079
|
@ -1,2 +1,188 @@
|
|||
import Category from './category';
|
||||
export default Category;
|
||||
/* eslint global-require: 0 */
|
||||
import {FolderSyncProgressStore} from 'nylas-exports';
|
||||
import Model from './model';
|
||||
import Attributes from '../attributes';
|
||||
let AccountStore = null
|
||||
|
||||
// We look for a few standard categories and display them in the Mailboxes
|
||||
// portion of the left sidebar. Note that these may not all be present on
|
||||
// a particular account.
|
||||
const ToObject = (arr) => {
|
||||
return arr.reduce((o, v) => {
|
||||
o[v] = v;
|
||||
return o;
|
||||
}, {});
|
||||
}
|
||||
|
||||
const StandardCategories = ToObject([
|
||||
"inbox",
|
||||
"important",
|
||||
"sent",
|
||||
"drafts",
|
||||
"all",
|
||||
"spam",
|
||||
"archive",
|
||||
"trash",
|
||||
]);
|
||||
|
||||
const LockedCategories = ToObject([
|
||||
"sent",
|
||||
"drafts",
|
||||
"N1-Snoozed",
|
||||
]);
|
||||
|
||||
const HiddenCategories = ToObject([
|
||||
"sent",
|
||||
"drafts",
|
||||
"all",
|
||||
"archive",
|
||||
"starred",
|
||||
"important",
|
||||
"N1-Snoozed",
|
||||
]);
|
||||
|
||||
/**
|
||||
Private:
|
||||
This abstract class has only two concrete implementations:
|
||||
- `Folder`
|
||||
- `Label`
|
||||
|
||||
See the equivalent models for details.
|
||||
|
||||
Folders and Labels have different semantics. The `Category` class only exists to help DRY code where they happen to behave the same
|
||||
|
||||
## Attributes
|
||||
|
||||
`name`: {AttributeString} The internal name of the label or folder. Queryable.
|
||||
|
||||
`displayName`: {AttributeString} The display-friendly name of the label or folder. Queryable.
|
||||
|
||||
Section: Models
|
||||
*/
|
||||
export default class Folder extends Model {
|
||||
|
||||
get displayName() {
|
||||
if (this.path && this.path.startsWith('INBOX.')) {
|
||||
return this.path.substr(6);
|
||||
}
|
||||
if (this.path && this.path === 'INBOX') {
|
||||
return 'Inbox';
|
||||
}
|
||||
return this.path;
|
||||
}
|
||||
|
||||
get name() {
|
||||
return this.role;
|
||||
}
|
||||
|
||||
static attributes = Object.assign({}, Model.attributes, {
|
||||
role: Attributes.String({
|
||||
queryable: true,
|
||||
modelKey: 'role',
|
||||
}),
|
||||
path: Attributes.String({
|
||||
queryable: true,
|
||||
modelKey: 'path',
|
||||
}),
|
||||
imapName: Attributes.String({
|
||||
modelKey: 'imapName',
|
||||
jsonKey: 'imap_name',
|
||||
}),
|
||||
syncProgress: Attributes.Object({
|
||||
modelKey: 'syncProgress',
|
||||
jsonKey: 'sync_progress',
|
||||
}),
|
||||
});
|
||||
|
||||
static Types = {
|
||||
Standard: 'standard',
|
||||
Locked: 'locked',
|
||||
User: 'user',
|
||||
Hidden: 'hidden',
|
||||
}
|
||||
|
||||
static StandardCategoryNames = Object.keys(StandardCategories)
|
||||
static LockedCategoryNames = Object.keys(LockedCategories)
|
||||
static HiddenCategoryNames = Object.keys(HiddenCategories)
|
||||
|
||||
static categoriesSharedName(cats) {
|
||||
if (!cats || cats.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const name = cats[0].name
|
||||
if (!cats.every((cat) => cat.name === name)) {
|
||||
return null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static additionalSQLiteConfig = {
|
||||
setup: () => {
|
||||
return [
|
||||
// 'CREATE INDEX IF NOT EXISTS FolderNameIndex ON Folder(accountId,name)',
|
||||
// 'CREATE UNIQUE INDEX IF NOT EXISTS FolderClientIndex ON Folder(id)',
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
displayType() {
|
||||
return 'folder';
|
||||
}
|
||||
|
||||
hue() {
|
||||
if (!this.displayName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let hue = 0;
|
||||
for (let i = 0; i < this.displayName.length; i++) {
|
||||
hue += this.displayName.charCodeAt(i);
|
||||
}
|
||||
hue *= (396.0 / 512.0);
|
||||
return hue;
|
||||
}
|
||||
|
||||
isStandardCategory(forceShowImportant) {
|
||||
let showImportant = forceShowImportant;
|
||||
if (showImportant === undefined) {
|
||||
showImportant = NylasEnv.config.get('core.workspace.showImportant');
|
||||
}
|
||||
if (showImportant === true) {
|
||||
return !!StandardCategories[this.name];
|
||||
}
|
||||
return !!StandardCategories[this.name] && (this.name !== 'important');
|
||||
}
|
||||
|
||||
isLockedCategory() {
|
||||
return !!LockedCategories[this.name] || !!LockedCategories[this.displayName];
|
||||
}
|
||||
|
||||
isHiddenCategory() {
|
||||
return !!HiddenCategories[this.name] || !!HiddenCategories[this.displayName];
|
||||
}
|
||||
|
||||
isUserCategory() {
|
||||
return !this.isStandardCategory() && !this.isHiddenCategory();
|
||||
}
|
||||
|
||||
isInbox() {
|
||||
return this.name === 'inbox'
|
||||
}
|
||||
|
||||
isArchive() {
|
||||
return ['all', 'archive'].includes(this.name);
|
||||
}
|
||||
|
||||
isSyncComplete() {
|
||||
// We sync by folders, not labels. If the category is a label, or hasn't been
|
||||
// assigned an object type yet, just return based on the sync status for the
|
||||
// entire account.
|
||||
if (this.object !== 'folder') {
|
||||
return FolderSyncProgressStore.isSyncCompleteForAccount(this.accountId);
|
||||
}
|
||||
return FolderSyncProgressStore.isSyncCompleteForAccount(
|
||||
this.accountId,
|
||||
this.name || this.displayName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,187 @@
|
|||
import Category from './category';
|
||||
export default Category;
|
||||
/* eslint global-require: 0 */
|
||||
import {FolderSyncProgressStore} from 'nylas-exports';
|
||||
import Model from './model';
|
||||
import Attributes from '../attributes';
|
||||
let AccountStore = null
|
||||
|
||||
// We look for a few standard categories and display them in the Mailboxes
|
||||
// portion of the left sidebar. Note that these may not all be present on
|
||||
// a particular account.
|
||||
const ToObject = (arr) => {
|
||||
return arr.reduce((o, v) => {
|
||||
o[v] = v;
|
||||
return o;
|
||||
}, {});
|
||||
}
|
||||
|
||||
const StandardCategories = ToObject([
|
||||
"inbox",
|
||||
"important",
|
||||
"sent",
|
||||
"drafts",
|
||||
"all",
|
||||
"spam",
|
||||
"archive",
|
||||
"trash",
|
||||
]);
|
||||
|
||||
const LockedCategories = ToObject([
|
||||
"sent",
|
||||
"drafts",
|
||||
"N1-Snoozed",
|
||||
]);
|
||||
|
||||
const HiddenCategories = ToObject([
|
||||
"sent",
|
||||
"drafts",
|
||||
"all",
|
||||
"archive",
|
||||
"starred",
|
||||
"important",
|
||||
"N1-Snoozed",
|
||||
]);
|
||||
|
||||
/**
|
||||
Private:
|
||||
This abstract class has only two concrete implementations:
|
||||
- `Folder`
|
||||
- `Label`
|
||||
|
||||
See the equivalent models for details.
|
||||
|
||||
Folders and Labels have different semantics. The `Category` class only exists to help DRY code where they happen to behave the same
|
||||
|
||||
## Attributes
|
||||
|
||||
`name`: {AttributeString} The internal name of the label or folder. Queryable.
|
||||
|
||||
`displayName`: {AttributeString} The display-friendly name of the label or folder. Queryable.
|
||||
|
||||
Section: Models
|
||||
*/
|
||||
export default class Label extends Model {
|
||||
|
||||
static attributes = Object.assign({}, Model.attributes, {
|
||||
name: Attributes.String({
|
||||
queryable: true,
|
||||
modelKey: 'name',
|
||||
}),
|
||||
displayName: Attributes.String({
|
||||
queryable: true,
|
||||
modelKey: 'displayName',
|
||||
jsonKey: 'display_name',
|
||||
}),
|
||||
imapName: Attributes.String({
|
||||
modelKey: 'imapName',
|
||||
jsonKey: 'imap_name',
|
||||
}),
|
||||
syncProgress: Attributes.Object({
|
||||
modelKey: 'syncProgress',
|
||||
jsonKey: 'sync_progress',
|
||||
}),
|
||||
});
|
||||
|
||||
static Types = {
|
||||
Standard: 'standard',
|
||||
Locked: 'locked',
|
||||
User: 'user',
|
||||
Hidden: 'hidden',
|
||||
}
|
||||
|
||||
static StandardCategoryNames = Object.keys(StandardCategories)
|
||||
static LockedCategoryNames = Object.keys(LockedCategories)
|
||||
static HiddenCategoryNames = Object.keys(HiddenCategories)
|
||||
|
||||
static categoriesSharedName(cats) {
|
||||
if (!cats || cats.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const name = cats[0].name
|
||||
if (!cats.every((cat) => cat.name === name)) {
|
||||
return null;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static additionalSQLiteConfig = {
|
||||
setup: () => {
|
||||
return [
|
||||
// 'CREATE INDEX IF NOT EXISTS LabelNameIndex ON Label(accountId,name)',
|
||||
// 'CREATE UNIQUE INDEX IF NOT EXISTS LabelClientIndex ON Label(id)',
|
||||
];
|
||||
},
|
||||
};
|
||||
|
||||
fromJSON(json) {
|
||||
super.fromJSON(json);
|
||||
|
||||
if (this.displayName && this.displayName.startsWith('INBOX.')) {
|
||||
this.displayName = this.displayName.substr(6);
|
||||
}
|
||||
if (this.displayName && this.displayName === 'INBOX') {
|
||||
this.displayName = 'Inbox';
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
displayType() {
|
||||
return 'label';
|
||||
}
|
||||
|
||||
hue() {
|
||||
if (!this.displayName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
let hue = 0;
|
||||
for (let i = 0; i < this.displayName.length; i++) {
|
||||
hue += this.displayName.charCodeAt(i);
|
||||
}
|
||||
hue *= (396.0 / 512.0);
|
||||
return hue;
|
||||
}
|
||||
|
||||
isStandardCategory(forceShowImportant) {
|
||||
let showImportant = forceShowImportant;
|
||||
if (showImportant === undefined) {
|
||||
showImportant = NylasEnv.config.get('core.workspace.showImportant');
|
||||
}
|
||||
if (showImportant === true) {
|
||||
return !!StandardCategories[this.name];
|
||||
}
|
||||
return !!StandardCategories[this.name] && (this.name !== 'important');
|
||||
}
|
||||
|
||||
isLockedCategory() {
|
||||
return !!LockedCategories[this.name] || !!LockedCategories[this.displayName];
|
||||
}
|
||||
|
||||
isHiddenCategory() {
|
||||
return !!HiddenCategories[this.name] || !!HiddenCategories[this.displayName];
|
||||
}
|
||||
|
||||
isUserCategory() {
|
||||
return !this.isStandardCategory() && !this.isHiddenCategory();
|
||||
}
|
||||
|
||||
isInbox() {
|
||||
return this.name === 'inbox'
|
||||
}
|
||||
|
||||
isArchive() {
|
||||
return ['all', 'archive'].includes(this.name);
|
||||
}
|
||||
|
||||
isSyncComplete() {
|
||||
// We sync by folders, not labels. If the category is a label, or hasn't been
|
||||
// assigned an object type yet, just return based on the sync status for the
|
||||
// entire account.
|
||||
if (this.object !== 'folder') {
|
||||
return FolderSyncProgressStore.isSyncCompleteForAccount(this.accountId);
|
||||
}
|
||||
return FolderSyncProgressStore.isSyncCompleteForAccount(
|
||||
this.accountId,
|
||||
this.name || this.displayName
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import _ from 'underscore'
|
||||
import Message from './message'
|
||||
import Contact from './contact'
|
||||
import Category from './category'
|
||||
import Folder from './folder'
|
||||
import Label from './label'
|
||||
import Attributes from '../attributes'
|
||||
import DatabaseStore from '../stores/database-store'
|
||||
import ModelWithMetadata from './model-with-metadata'
|
||||
|
@ -64,16 +65,20 @@ class Thread extends ModelWithMetadata {
|
|||
modelKey: 'version',
|
||||
}),
|
||||
|
||||
categories: Attributes.Collection({
|
||||
folders: Attributes.Collection({
|
||||
queryable: true,
|
||||
modelKey: 'categories',
|
||||
modelKey: 'folders',
|
||||
joinOnField: 'id',
|
||||
joinQueryableBy: ['inAllMail', 'lastMessageReceivedTimestamp', 'lastMessageSentTimestamp', 'unread'],
|
||||
itemClass: Category,
|
||||
itemClass: Folder,
|
||||
}),
|
||||
|
||||
categoriesType: Attributes.String({
|
||||
modelKey: 'categoriesType',
|
||||
labels: Attributes.Collection({
|
||||
queryable: true,
|
||||
modelKey: 'labels',
|
||||
joinOnField: 'id',
|
||||
joinQueryableBy: ['inAllMail', 'lastMessageReceivedTimestamp', 'lastMessageSentTimestamp', 'unread'],
|
||||
itemClass: Label,
|
||||
}),
|
||||
|
||||
participants: Attributes.Collection({
|
||||
|
@ -188,35 +193,8 @@ class Thread extends ModelWithMetadata {
|
|||
})
|
||||
}
|
||||
|
||||
get labels() {
|
||||
return this.categories;
|
||||
}
|
||||
|
||||
set labels(labels) {
|
||||
this.categories = labels;
|
||||
}
|
||||
|
||||
get folders() {
|
||||
return this.categories;
|
||||
}
|
||||
|
||||
set folders(folders) {
|
||||
this.categories = folders;
|
||||
}
|
||||
|
||||
get inAllMail() {
|
||||
if (this.categoriesType === 'labels') {
|
||||
const inAllMail = _.any(this.categories, cat => cat.name === 'all')
|
||||
if (inAllMail) {
|
||||
return true;
|
||||
}
|
||||
const inTrashOrSpam = _.any(this.categories, cat => cat.name === 'trash' || cat.name === 'spam')
|
||||
if (!inTrashOrSpam) {
|
||||
return true;
|
||||
}
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return this.folders.find(f => f.role === 'all');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -229,17 +207,6 @@ class Thread extends ModelWithMetadata {
|
|||
fromJSON(json) {
|
||||
super.fromJSON(json)
|
||||
|
||||
if (json.folders) {
|
||||
this.categoriesType = 'folders'
|
||||
this.categories = Thread.attributes.categories.fromJSON(json.folders)
|
||||
}
|
||||
|
||||
if (json.labels && json.labels.length > 0) {
|
||||
this.categoriesType = 'labels'
|
||||
if (!this.categories) this.categories = [];
|
||||
this.categories = this.categories.concat(Thread.attributes.categories.fromJSON(json.labels))
|
||||
}
|
||||
|
||||
['participants'].forEach((attr) => {
|
||||
const value = this[attr]
|
||||
if (!(value && value instanceof Array)) {
|
||||
|
@ -296,14 +263,4 @@ class Thread extends ModelWithMetadata {
|
|||
}
|
||||
}
|
||||
|
||||
Object.defineProperty(Thread.attributes, "labels", {
|
||||
enumerable: false,
|
||||
get: () => Thread.attributes.categories,
|
||||
})
|
||||
|
||||
Object.defineProperty(Thread.attributes, "folders", {
|
||||
enumerable: false,
|
||||
get: () => Thread.attributes.categories,
|
||||
})
|
||||
|
||||
export default Thread;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Rx = require 'rx-lite'
|
||||
_ = require 'underscore'
|
||||
Category = require('../flux/models/category').default
|
||||
Folder = require('../flux/models/folder').default
|
||||
Label = require('../flux/models/label').default
|
||||
QuerySubscriptionPool = require('../flux/models/query-subscription-pool').default
|
||||
DatabaseStore = require('../flux/stores/database-store').default
|
||||
|
||||
|
@ -27,17 +28,32 @@ CategoryOperators =
|
|||
CategoryObservables =
|
||||
|
||||
forAllAccounts: =>
|
||||
observable = Rx.Observable.fromQuery(DatabaseStore.findAll(Category))
|
||||
_.extend(observable, CategoryOperators)
|
||||
observable
|
||||
folders = Rx.Observable.fromQuery(DatabaseStore.findAll(Folder))
|
||||
labels = Rx.Observable.fromQuery(DatabaseStore.findAll(Label))
|
||||
joined = Rx.Observable.combineLatest(folders, labels, (f, l) =>
|
||||
debugger
|
||||
[].concat(f, l)
|
||||
)
|
||||
_.extend(joined, CategoryOperators)
|
||||
joined
|
||||
|
||||
forAccount: (account) =>
|
||||
if account
|
||||
observable = Rx.Observable.fromQuery(DatabaseStore.findAll(Category).where(accountId: account.id))
|
||||
folders = Rx.Observable.fromQuery(DatabaseStore.findAll(Folder).where(accountId: account.id))
|
||||
labels = Rx.Observable.fromQuery(DatabaseStore.findAll(Label).where(accountId: account.id))
|
||||
joined = Rx.Observable.combineLatest(folders, labels, (f, l) =>
|
||||
debugger
|
||||
[].concat(f, l)
|
||||
)
|
||||
else
|
||||
observable = Rx.Observable.fromQuery(DatabaseStore.findAll(Category))
|
||||
_.extend(observable, CategoryOperators)
|
||||
observable
|
||||
folders = Rx.Observable.fromQuery(DatabaseStore.findAll(Folder))
|
||||
labels = Rx.Observable.fromQuery(DatabaseStore.findAll(Label))
|
||||
joined = Rx.Observable.combineLatest(folders, labels, (f, l) =>
|
||||
debugger
|
||||
[].concat(f, l)
|
||||
)
|
||||
_.extend(joined, CategoryOperators)
|
||||
joined
|
||||
|
||||
standard: (account) =>
|
||||
observable = Rx.Observable.fromConfig('core.workspace.showImportant')
|
||||
|
|
|
@ -13,6 +13,8 @@ UnreadQuerySubscription = require('./flux/models/unread-query-subscription').def
|
|||
Matcher = require('./flux/attributes/matcher').default
|
||||
Thread = require('./flux/models/thread').default
|
||||
Category = require('./flux/models/category').default
|
||||
Folder = require('./flux/models/folder').default
|
||||
Label = require('./flux/models/label').default
|
||||
Actions = require('./flux/actions').default
|
||||
ChangeUnreadTask = null
|
||||
|
||||
|
@ -268,9 +270,16 @@ class CategoryMailboxPerspective extends MailboxPerspective
|
|||
super(other) and _.isEqual(_.pluck(@categories(), 'id'), _.pluck(other.categories(), 'id'))
|
||||
|
||||
threads: =>
|
||||
folders = @categories().filter((c) => c instanceof Folder)
|
||||
labels = @categories().filter((c) => c instanceof Label)
|
||||
query = DatabaseStore.findAll(Thread)
|
||||
.where([Thread.attributes.categories.containsAny(_.pluck(@categories(), 'id'))])
|
||||
.limit(0)
|
||||
|
||||
if folders.length > 0
|
||||
query = query.where([Thread.attributes.folders.containsAny(_.pluck(folders, 'id'))])
|
||||
if labels.length > 0
|
||||
query = query.where([Thread.attributes.labels.containsAny(_.pluck(labels, 'id'))])
|
||||
|
||||
query = query.limit(0)
|
||||
|
||||
if @isSent()
|
||||
query.order(Thread.attributes.lastMessageSentTimestamp.descending())
|
||||
|
|
Loading…
Reference in a new issue