mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-30 00:16:02 +08:00
Build ContactBook concept to track which accounts have sync running
This commit is contained in:
parent
1f6aab1083
commit
96c6a64e46
19 changed files with 267 additions and 159 deletions
|
@ -110,7 +110,7 @@ export function registerMenuItems(accounts: Account[], sidebarAccountIds: string
|
|||
return;
|
||||
}
|
||||
|
||||
const idx = submenu.findIndex(({ type }) => type === 'separator');
|
||||
const idx = submenu.findIndex(({ id }) => id === 'account-shortcuts-separator');
|
||||
if (!(idx > 0)) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -31,7 +31,11 @@ class AddContactToolbarWithData extends React.Component<AddContactToolbarProps>
|
|||
tabIndex={-1}
|
||||
disabled={!enabled}
|
||||
className={`btn btn-toolbar btn-new-contact ${!enabled && 'btn-disabled'}`}
|
||||
title={localized('New contact in %@', acct ? acct.label : 'account')}
|
||||
title={
|
||||
acct
|
||||
? localized('New contact in %@', acct.label)
|
||||
: localized('Select an account to add a contact.')
|
||||
}
|
||||
onClick={enabled ? this.onAdd : undefined}
|
||||
>
|
||||
<Icons.NewPerson />
|
||||
|
|
|
@ -86,6 +86,7 @@ class ContactDetailToolbarWithData extends React.Component<ContactDetailToolbarP
|
|||
{perspective && perspective.type === 'group' && (
|
||||
<button
|
||||
tabIndex={-1}
|
||||
title={localized('Remove from Group')}
|
||||
className={`btn btn-toolbar ${actionSet.length === 0 && 'btn-disabled'}`}
|
||||
onClick={actionSet.length > 0 ? this._onRemoveFromSource : undefined}
|
||||
>
|
||||
|
@ -94,14 +95,15 @@ class ContactDetailToolbarWithData extends React.Component<ContactDetailToolbarP
|
|||
)}
|
||||
<button
|
||||
tabIndex={-1}
|
||||
className={`btn btn-toolbar ${actionSet.length === 0 && 'btn-disabled'}`}
|
||||
title={localized('Delete')}
|
||||
className={`btn btn-toolbar ${actionSet.length === 0 && 'btn-disabled'}`}
|
||||
onClick={actionSet.length > 0 ? this._onDelete : undefined}
|
||||
>
|
||||
<RetinaImg name="toolbar-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
|
||||
</button>
|
||||
<button
|
||||
tabIndex={-1}
|
||||
title={localized('Edit')}
|
||||
className={`btn btn-toolbar ${!editable && 'btn-disabled'}`}
|
||||
onClick={editable ? () => Store.setEditing(actionSet[0].id) : undefined}
|
||||
>
|
||||
|
|
|
@ -3,11 +3,13 @@ import {
|
|||
Account,
|
||||
AccountStore,
|
||||
ContactGroup,
|
||||
ContactBook,
|
||||
Rx,
|
||||
Actions,
|
||||
DestroyContactGroupTask,
|
||||
SyncbackContactGroupTask,
|
||||
ChangeContactGroupMembershipTask,
|
||||
localized,
|
||||
} from 'mailspring-exports';
|
||||
import { ContactsPerspective, Store } from './Store';
|
||||
import {
|
||||
|
@ -16,12 +18,14 @@ import {
|
|||
OutlineViewItem,
|
||||
ListensToFluxStore,
|
||||
ListensToObservable,
|
||||
IOutlineViewItem,
|
||||
} from 'mailspring-component-kit';
|
||||
import { isEqual } from 'underscore';
|
||||
|
||||
interface ContactsPerspectivesProps {
|
||||
accounts: Account[];
|
||||
groups: ContactGroup[];
|
||||
books: ContactBook[];
|
||||
findInMailDisabled: string[];
|
||||
selected: ContactsPerspective | null;
|
||||
onSelect: (item: ContactsPerspective | null) => void;
|
||||
|
@ -36,9 +40,115 @@ function perspectiveForGroup(g: ContactGroup): ContactsPerspective {
|
|||
};
|
||||
}
|
||||
|
||||
interface OutlineViewForAccountProps {
|
||||
account: Account;
|
||||
groups: ContactGroup[];
|
||||
books: ContactBook[];
|
||||
findInMailDisabled: boolean;
|
||||
selected: ContactsPerspective | null;
|
||||
onSelect: (item: ContactsPerspective | null) => void;
|
||||
}
|
||||
|
||||
const OutlineViewForAccount = ({
|
||||
account,
|
||||
groups,
|
||||
books,
|
||||
selected,
|
||||
onSelect,
|
||||
findInMailDisabled,
|
||||
}: OutlineViewForAccountProps) => {
|
||||
const items: IOutlineViewItem[] = [];
|
||||
|
||||
if (books.length) {
|
||||
items.push({
|
||||
id: 'all-contacts',
|
||||
name: localized('All Contacts'),
|
||||
iconName: 'person.png',
|
||||
children: [],
|
||||
selected: selected && selected.type === 'all',
|
||||
onSelect: () =>
|
||||
onSelect({ accountId: account.id, type: 'all', label: localized('All Contacts') }),
|
||||
shouldAcceptDrop: () => false,
|
||||
});
|
||||
|
||||
for (const group of groups) {
|
||||
const perspective = perspectiveForGroup(group);
|
||||
items.push({
|
||||
id: `${perspective.accountId}-${perspective.label}`,
|
||||
name: perspective.label,
|
||||
iconName: 'label.png',
|
||||
children: [],
|
||||
selected: isEqual(selected, perspective),
|
||||
onSelect: () => onSelect(perspective),
|
||||
onEdited: (item, value: string) => {
|
||||
Actions.queueTask(SyncbackContactGroupTask.forRenaming(group, value));
|
||||
},
|
||||
onDelete: () => {
|
||||
Actions.queueTask(DestroyContactGroupTask.forRemoving(group));
|
||||
},
|
||||
onDrop: (item, { dataTransfer }) => {
|
||||
const data = JSON.parse(dataTransfer.getData('mailspring-contacts-data'));
|
||||
const contacts = data.ids.map(i => Store.filteredContacts().find(c => c.id === i));
|
||||
Actions.queueTask(
|
||||
ChangeContactGroupMembershipTask.forMoving({
|
||||
direction: 'add',
|
||||
contacts,
|
||||
group,
|
||||
})
|
||||
);
|
||||
},
|
||||
shouldAcceptDrop: (item, { dataTransfer }) => {
|
||||
if (!dataTransfer.types.includes('mailspring-contacts-data')) {
|
||||
return false;
|
||||
}
|
||||
if (isEqual(selected, perspective)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can't inspect the drag payload until drop, so we use a dataTransfer
|
||||
// type to encode the account IDs of threads currently being dragged.
|
||||
const accountsType = dataTransfer.types.find(t => t.startsWith('mailspring-accounts='));
|
||||
const accountIds = (accountsType || '').replace('mailspring-accounts=', '').split(',');
|
||||
|
||||
return isEqual(accountIds, [perspective.accountId]);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
items.push({
|
||||
id: 'found-in-mail',
|
||||
name: localized('Found in Mail'),
|
||||
iconName: 'inbox.png',
|
||||
children: [],
|
||||
className: findInMailDisabled ? 'found-in-mail-disabled' : '',
|
||||
selected: selected && selected.type === 'found-in-mail',
|
||||
shouldAcceptDrop: () => false,
|
||||
onSelect: () =>
|
||||
onSelect({
|
||||
accountId: account.id,
|
||||
type: 'found-in-mail',
|
||||
label: `${localized('Found in Mail')} (${account.label})`,
|
||||
}),
|
||||
});
|
||||
|
||||
return (
|
||||
<OutlineView
|
||||
title={account.label}
|
||||
items={items}
|
||||
onItemCreated={
|
||||
books.length > 0
|
||||
? name => Actions.queueTask(SyncbackContactGroupTask.forCreating(account.id, name))
|
||||
: undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ContactsPerspectivesWithData: React.FunctionComponent<ContactsPerspectivesProps> = ({
|
||||
findInMailDisabled,
|
||||
groups,
|
||||
books,
|
||||
accounts,
|
||||
selected,
|
||||
onSelect,
|
||||
|
@ -57,87 +167,14 @@ const ContactsPerspectivesWithData: React.FunctionComponent<ContactsPerspectives
|
|||
/>
|
||||
</section>
|
||||
{accounts.map(a => (
|
||||
<OutlineView
|
||||
<OutlineViewForAccount
|
||||
key={a.id}
|
||||
title={a.label}
|
||||
onItemCreated={name => Actions.queueTask(SyncbackContactGroupTask.forCreating(a.id, name))}
|
||||
items={[
|
||||
{
|
||||
id: 'all-contacts',
|
||||
name: 'All Contacts',
|
||||
iconName: 'person.png',
|
||||
children: [],
|
||||
selected: selected && selected.accountId == a.id && selected.type === 'all',
|
||||
onSelect: () => onSelect({ accountId: a.id, type: 'all', label: 'All Contacts' }),
|
||||
shouldAcceptDrop: () => false,
|
||||
},
|
||||
...groups
|
||||
.filter(g => g.accountId === a.id)
|
||||
.map(group => {
|
||||
const perspective = perspectiveForGroup(group);
|
||||
return {
|
||||
id: `${perspective.accountId}-${perspective.label}`,
|
||||
name: perspective.label,
|
||||
iconName: 'label.png',
|
||||
children: [],
|
||||
selected: isEqual(selected, perspective),
|
||||
onSelect: () => onSelect(perspective),
|
||||
onEdited: (item, value: string) => {
|
||||
Actions.queueTask(SyncbackContactGroupTask.forRenaming(group, value));
|
||||
},
|
||||
onDelete: () => {
|
||||
Actions.queueTask(DestroyContactGroupTask.forRemoving(group));
|
||||
},
|
||||
onDrop: (item, { dataTransfer }) => {
|
||||
const data = JSON.parse(dataTransfer.getData('mailspring-contacts-data'));
|
||||
const contacts = data.ids.map(i =>
|
||||
Store.filteredContacts().find(c => c.id === i)
|
||||
);
|
||||
Actions.queueTask(
|
||||
ChangeContactGroupMembershipTask.forMoving({
|
||||
direction: 'add',
|
||||
contacts,
|
||||
group,
|
||||
})
|
||||
);
|
||||
},
|
||||
shouldAcceptDrop: (item, { dataTransfer }) => {
|
||||
if (!dataTransfer.types.includes('mailspring-contacts-data')) {
|
||||
return false;
|
||||
}
|
||||
if (isEqual(selected, perspective)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We can't inspect the drag payload until drop, so we use a dataTransfer
|
||||
// type to encode the account IDs of threads currently being dragged.
|
||||
const accountsType = dataTransfer.types.find(t =>
|
||||
t.startsWith('mailspring-accounts=')
|
||||
);
|
||||
const accountIds = (accountsType || '')
|
||||
.replace('mailspring-accounts=', '')
|
||||
.split(',');
|
||||
|
||||
return isEqual(accountIds, [perspective.accountId]);
|
||||
},
|
||||
};
|
||||
}),
|
||||
{
|
||||
id: 'found-in-mail',
|
||||
name: 'Found in Mail',
|
||||
iconName: 'inbox.png',
|
||||
children: [],
|
||||
className: findInMailDisabled.includes(a.id) ? 'found-in-mail-disabled' : '',
|
||||
selected: selected && selected.accountId == a.id && selected.type === 'found-in-mail',
|
||||
shouldAcceptDrop: () => false,
|
||||
onSelect: () =>
|
||||
onSelect({
|
||||
accountId: a.id,
|
||||
type: 'found-in-mail',
|
||||
label: `Found in Mail (${a.label})`,
|
||||
}),
|
||||
},
|
||||
]}
|
||||
account={a}
|
||||
findInMailDisabled={findInMailDisabled.includes(a.id)}
|
||||
books={books.filter(b => b.accountId === a.id)}
|
||||
groups={groups.filter(b => b.accountId === a.id)}
|
||||
selected={selected && selected.accountId === a.id ? selected : null}
|
||||
onSelect={onSelect}
|
||||
/>
|
||||
))}
|
||||
</ScrollRegion>
|
||||
|
@ -148,6 +185,7 @@ export const ContactPerspectivesList = ListensToObservable(
|
|||
stores: [AccountStore, Store],
|
||||
getStateFromStores: () => ({
|
||||
accounts: AccountStore.accounts(),
|
||||
books: Store.books(),
|
||||
groups: Store.groups(),
|
||||
selected: Store.perspective(),
|
||||
onSelect: s => Store.setPerspective(s),
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import Rx from 'rx-lite';
|
||||
import { DatabaseStore, Contact, ContactGroup, MutableQuerySubscription } from 'mailspring-exports';
|
||||
import {
|
||||
DatabaseStore,
|
||||
Contact,
|
||||
ContactGroup,
|
||||
ContactBook,
|
||||
MutableQuerySubscription,
|
||||
} from 'mailspring-exports';
|
||||
import MailspringStore from 'mailspring-store';
|
||||
import { ListTabular } from 'mailspring-component-kit';
|
||||
|
||||
|
@ -10,6 +16,7 @@ class ContactsWindowStore extends MailspringStore {
|
|||
_contacts: Contact[] = [];
|
||||
_contactsSubscription: MutableQuerySubscription<Contact>;
|
||||
_groups: ContactGroup[] = [];
|
||||
_books: ContactBook[] = [];
|
||||
_search: string = '';
|
||||
_filtered: Contact[] | null = null;
|
||||
_editing: string | 'new' | false = false;
|
||||
|
@ -24,6 +31,7 @@ class ContactsWindowStore extends MailspringStore {
|
|||
.where(Contact.attributes.refs.greaterThan(0))
|
||||
.where(Contact.attributes.hidden.equal(false));
|
||||
this._contactsSubscription = new MutableQuerySubscription<Contact>(contacts);
|
||||
|
||||
Rx.Observable.fromNamedQuerySubscription('contacts', this._contactsSubscription).subscribe(
|
||||
contacts => {
|
||||
this._contacts = contacts as Contact[];
|
||||
|
@ -32,14 +40,24 @@ class ContactsWindowStore extends MailspringStore {
|
|||
}
|
||||
);
|
||||
|
||||
const groups = Rx.Observable.fromQuery(DatabaseStore.findAll<ContactGroup>(ContactGroup));
|
||||
groups.subscribe(groups => {
|
||||
this._groups = groups;
|
||||
Rx.Observable.fromQuery(DatabaseStore.findAll<ContactGroup>(ContactGroup)).subscribe(
|
||||
groups => {
|
||||
this._groups = groups;
|
||||
this.trigger();
|
||||
}
|
||||
);
|
||||
|
||||
Rx.Observable.fromQuery(DatabaseStore.findAll<ContactBook>(ContactBook)).subscribe(books => {
|
||||
this._books = books;
|
||||
this.trigger();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
books() {
|
||||
return this._books;
|
||||
}
|
||||
|
||||
groups() {
|
||||
return this._groups;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import { FoundInMailEnabledBar } from './FoundInMailEnabledBar';
|
|||
|
||||
function adjustMenus() {
|
||||
const contactMenu: typeof AppEnv.menu.template[0] = {
|
||||
key: 'Contact',
|
||||
id: 'Contact',
|
||||
label: localized('Contact'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -32,10 +32,8 @@ function adjustMenus() {
|
|||
],
|
||||
};
|
||||
|
||||
const template = AppEnv.menu.template.filter(
|
||||
item => item.key !== 'Thread' && item.key !== 'View'
|
||||
);
|
||||
const editIndex = template.findIndex(item => item.key === 'Edit');
|
||||
const template = AppEnv.menu.template.filter(item => item.id !== 'Thread' && item.id !== 'View');
|
||||
const editIndex = template.findIndex(item => item.id === 'Edit');
|
||||
template.splice(editIndex + 1, 0, contactMenu);
|
||||
|
||||
AppEnv.menu.template = template;
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
"window:select-account-8": "mod+9",
|
||||
|
||||
"window:sync-mail-now": "f5",
|
||||
"application:show-main-window": "mod+0",
|
||||
|
||||
"contenteditable:underline": "mod+u",
|
||||
"contenteditable:bold": "mod+b",
|
||||
|
|
|
@ -3,7 +3,7 @@ const { localized } = require('../src/intl');
|
|||
module.exports = {
|
||||
menu: [
|
||||
{
|
||||
key: 'Mailspring',
|
||||
id: 'Mailspring',
|
||||
label: 'Mailspring',
|
||||
submenu: [
|
||||
{ label: localized('About Mailspring'), command: 'application:about' },
|
||||
|
@ -42,7 +42,7 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'File',
|
||||
id: 'File',
|
||||
label: localized('File'),
|
||||
submenu: [
|
||||
{ label: localized('Sync New Mail Now'), command: 'window:sync-mail-now' },
|
||||
|
@ -56,7 +56,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Edit',
|
||||
id: 'Edit',
|
||||
label: localized('Edit'),
|
||||
submenu: [
|
||||
{ label: localized('Undo'), command: 'core:undo' },
|
||||
|
@ -86,7 +86,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'View',
|
||||
id: 'View',
|
||||
label: localized('View'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -140,7 +140,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Thread',
|
||||
id: 'Thread',
|
||||
label: localized('Thread'),
|
||||
submenu: [
|
||||
{ label: localized('Reply'), command: 'core:reply' },
|
||||
|
@ -192,7 +192,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Developer',
|
||||
id: 'Developer',
|
||||
label: localized('Developer'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -202,7 +202,6 @@ module.exports = {
|
|||
},
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Calendar Preview'), command: 'application:show-calendar' },
|
||||
{ label: localized('Contacts Preview'), command: 'application:show-contacts' },
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Create a Plugin') + '...', command: 'window:create-package' },
|
||||
{ label: localized('Install a Plugin') + '...', command: 'window:install-package' },
|
||||
|
@ -221,13 +220,22 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'Window',
|
||||
id: 'Window',
|
||||
label: localized('Window'),
|
||||
submenu: [
|
||||
{ label: localized('Minimize'), command: 'application:minimize' },
|
||||
{ label: localized('Zoom'), command: 'application:zoom' },
|
||||
{ type: 'separator', id: 'window-list-separator' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: localized('Message Viewer'),
|
||||
command: 'application:show-main-window',
|
||||
},
|
||||
{
|
||||
label: localized('Contacts'),
|
||||
command: 'application:show-contacts',
|
||||
},
|
||||
{ type: 'separator', id: 'window-list-separator' },
|
||||
{ type: 'separator', id: 'account-shortcuts-separator' },
|
||||
{
|
||||
label: localized('Bring All to Front'),
|
||||
command: 'application:bring-all-windows-to-front',
|
||||
|
@ -236,7 +244,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Help',
|
||||
id: 'Help',
|
||||
label: localized('Help'),
|
||||
submenu: [
|
||||
{ label: localized('Mailspring Help'), command: 'application:view-help' },
|
||||
|
|
|
@ -3,7 +3,7 @@ const { localized } = require('../src/intl');
|
|||
module.exports = {
|
||||
menu: [
|
||||
{
|
||||
key: 'File',
|
||||
id: 'File',
|
||||
label: localized('File'),
|
||||
submenu: [
|
||||
{ label: localized('Sync New Mail Now'), command: 'window:sync-mail-now' },
|
||||
|
@ -24,7 +24,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Edit',
|
||||
id: 'Edit',
|
||||
label: localized('Edit'),
|
||||
submenu: [
|
||||
{ label: localized('Undo'), command: 'core:undo' },
|
||||
|
@ -58,7 +58,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'View',
|
||||
id: 'View',
|
||||
label: localized('View'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -110,7 +110,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Thread',
|
||||
id: 'Thread',
|
||||
label: localized('Thread'),
|
||||
submenu: [
|
||||
{ label: localized('Reply'), command: 'core:reply' },
|
||||
|
@ -161,7 +161,7 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'Developer',
|
||||
id: 'Developer',
|
||||
label: localized('Developer'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -171,7 +171,6 @@ module.exports = {
|
|||
},
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Calendar Preview'), command: 'application:show-calendar' },
|
||||
{ label: localized('Contacts Preview'), command: 'application:show-contacts' },
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Create a Plugin') + '...', command: 'window:create-package' },
|
||||
{ label: localized('Install a Plugin') + '...', command: 'window:install-package' },
|
||||
|
@ -189,16 +188,27 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'Window',
|
||||
id: 'Window',
|
||||
label: localized('Window'),
|
||||
submenu: [
|
||||
{ label: localized('Minimize'), command: 'application:minimize' },
|
||||
{ label: localized('Zoom'), command: 'application:zoom' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: localized('Message Viewer'),
|
||||
command: 'application:show-main-window',
|
||||
accelerator: 'CmdOrCtrl+0',
|
||||
},
|
||||
{
|
||||
label: localized('Contacts'),
|
||||
command: 'application:show-contacts',
|
||||
},
|
||||
{ type: 'separator', id: 'window-list-separator' },
|
||||
{ type: 'separator', id: 'account-shortcuts-separator' },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: 'Help',
|
||||
id: 'Help',
|
||||
label: localized('Help'),
|
||||
submenu: [
|
||||
{ label: 'VERSION', enabled: false },
|
||||
|
|
|
@ -3,7 +3,7 @@ const { localized } = require('../src/intl');
|
|||
module.exports = {
|
||||
menu: [
|
||||
{
|
||||
key: 'Edit',
|
||||
id: 'Edit',
|
||||
label: localized('Edit'),
|
||||
submenu: [
|
||||
{ label: localized('Undo'), command: 'core:undo' },
|
||||
|
@ -33,7 +33,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'View',
|
||||
id: 'View',
|
||||
label: localized('View'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ module.exports = {
|
|||
},
|
||||
|
||||
{
|
||||
key: 'Thread',
|
||||
id: 'Thread',
|
||||
label: localized('Thread'),
|
||||
submenu: [
|
||||
{ label: localized('Reply'), command: 'core:reply' },
|
||||
|
@ -138,7 +138,7 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'Developer',
|
||||
id: 'Developer',
|
||||
label: localized('Developer'),
|
||||
submenu: [
|
||||
{
|
||||
|
@ -148,7 +148,6 @@ module.exports = {
|
|||
},
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Calendar Preview'), command: 'application:show-calendar' },
|
||||
{ label: localized('Contacts Preview'), command: 'application:show-contacts' },
|
||||
{ type: 'separator' },
|
||||
{ label: localized('Create a Plugin') + '...', command: 'window:create-package' },
|
||||
{ label: localized('Install a Plugin') + '...', command: 'window:install-package' },
|
||||
|
@ -167,12 +166,23 @@ module.exports = {
|
|||
],
|
||||
},
|
||||
{
|
||||
key: 'Window',
|
||||
id: 'Window',
|
||||
label: localized('Window'),
|
||||
submenu: [
|
||||
{ label: localized('Minimize'), command: 'application:minimize' },
|
||||
{ label: localized('Zoom'), command: 'application:zoom' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: localized('Message Viewer'),
|
||||
command: 'application:show-main-window',
|
||||
accelerator: 'CmdOrCtrl+0',
|
||||
},
|
||||
{
|
||||
label: localized('Contacts'),
|
||||
command: 'application:show-contacts',
|
||||
},
|
||||
{ type: 'separator', id: 'window-list-separator' },
|
||||
{ type: 'separator', id: 'account-shortcuts-separator' },
|
||||
],
|
||||
},
|
||||
{ type: 'separator' },
|
||||
|
|
|
@ -154,24 +154,17 @@ export default class ApplicationMenu {
|
|||
}
|
||||
const idx = windowMenu.submenu.findIndex(({ id }) => id === 'window-list-separator');
|
||||
|
||||
let workShortcut = 'CmdOrCtrl+alt+w';
|
||||
if (process.platform === 'win32') {
|
||||
workShortcut = 'ctrl+shift+w';
|
||||
}
|
||||
|
||||
const accelerators = {
|
||||
default: 'CmdOrCtrl+0',
|
||||
work: workShortcut,
|
||||
};
|
||||
const windows = global.application.windowManager.getOpenWindows();
|
||||
const windowsItems = windows.map(w => ({
|
||||
label: w.loadSettings().title || 'Window',
|
||||
accelerator: accelerators[w.windowType],
|
||||
click() {
|
||||
w.show();
|
||||
w.focus();
|
||||
},
|
||||
}));
|
||||
const windowsItems = windows
|
||||
.filter(w => w.windowType !== 'default' && w.windowType !== 'contacts')
|
||||
.map(w => ({
|
||||
label: w.loadSettings().title || 'Window',
|
||||
click() {
|
||||
w.show();
|
||||
w.focus();
|
||||
},
|
||||
}));
|
||||
|
||||
return windowMenu.submenu.splice(idx, 0, { type: 'separator' }, ...windowsItems);
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ interface OutlineViewState {
|
|||
* @param {props.onCollapseToggled} props.onCollapseToggled
|
||||
* @class OutlineView
|
||||
*/
|
||||
class OutlineView extends Component<OutlineViewProps, OutlineViewState> {
|
||||
export class OutlineView extends Component<OutlineViewProps, OutlineViewState> {
|
||||
static displayName = 'OutlineView';
|
||||
|
||||
/*
|
||||
|
@ -232,5 +232,3 @@ class OutlineView extends Component<OutlineViewProps, OutlineViewState> {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default OutlineView;
|
||||
|
|
32
app/src/flux/models/contact-book.ts
Normal file
32
app/src/flux/models/contact-book.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* eslint global-require: 0 */
|
||||
import { Model, AttributeValues } from './model';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
export class ContactBook extends Model {
|
||||
static attributes = {
|
||||
...Model.attributes,
|
||||
|
||||
readonly: Attributes.String({
|
||||
modelKey: 'readonly',
|
||||
}),
|
||||
|
||||
source: Attributes.String({
|
||||
modelKey: 'source',
|
||||
}),
|
||||
};
|
||||
|
||||
readonly: boolean;
|
||||
source: 'carddav' | 'gpeople';
|
||||
|
||||
static sortOrderAttribute = () => {
|
||||
return ContactBook.attributes.id;
|
||||
};
|
||||
|
||||
static naturalSortOrder = () => {
|
||||
return ContactBook.sortOrderAttribute().ascending();
|
||||
};
|
||||
|
||||
constructor(data: AttributeValues<typeof ContactBook.attributes>) {
|
||||
super(data);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint global-require: 0 */
|
||||
import _str from 'underscore.string';
|
||||
import { Model, AttributeValues } from './model';
|
||||
import Attributes from '../attributes';
|
||||
|
||||
|
@ -12,6 +11,8 @@ export class ContactGroup extends Model {
|
|||
}),
|
||||
};
|
||||
|
||||
public name: string;
|
||||
|
||||
static sortOrderAttribute = () => {
|
||||
return ContactGroup.attributes.name;
|
||||
};
|
||||
|
@ -20,8 +21,6 @@ export class ContactGroup extends Model {
|
|||
return ContactGroup.sortOrderAttribute().ascending();
|
||||
};
|
||||
|
||||
public name: string;
|
||||
|
||||
constructor(data: AttributeValues<typeof ContactGroup.attributes>) {
|
||||
super(data);
|
||||
}
|
||||
|
|
2
app/src/global/mailspring-component-kit.d.ts
vendored
2
app/src/global/mailspring-component-kit.d.ts
vendored
|
@ -40,7 +40,7 @@ export * from '../components/disclosure-triangle';
|
|||
export const EditableList: typeof import('../components/editable-list').default;
|
||||
export const DropdownMenu: typeof import('../components/dropdown-menu').default;
|
||||
export const OutlineViewItem: typeof import('../components/outline-view-item').default;
|
||||
export const OutlineView: typeof import('../components/outline-view').default;
|
||||
export * from '../components/outline-view';
|
||||
export const DateInput: typeof import('../components/date-input').default;
|
||||
export const DatePicker: typeof import('../components/date-picker').default;
|
||||
export const TimePicker: typeof import('../components/time-picker').default;
|
||||
|
|
3
app/src/global/mailspring-exports.d.ts
vendored
3
app/src/global/mailspring-exports.d.ts
vendored
|
@ -44,6 +44,7 @@ export * from '../flux/models/thread';
|
|||
export * from '../flux/models/account';
|
||||
export * from '../flux/models/message';
|
||||
export * from '../flux/models/contact';
|
||||
export * from '../flux/models/contact-book';
|
||||
export * from '../flux/models/contact-group';
|
||||
export * from '../flux/models/category';
|
||||
export * from '../flux/models/calendar';
|
||||
|
@ -80,6 +81,8 @@ export * from '../flux/tasks/change-role-mapping-task';
|
|||
export * from '../flux/tasks/send-feature-usage-event-task';
|
||||
export * from '../flux/tasks/syncback-contact-task';
|
||||
export * from '../flux/tasks/destroy-contact-task';
|
||||
export * from '../flux/tasks/destroy-contactgroup-task';
|
||||
export * from '../flux/tasks/syncback-contactgroup-task';
|
||||
export * from '../flux/tasks/change-contactgroup-membership-task';
|
||||
|
||||
// Stores
|
||||
|
|
|
@ -81,6 +81,7 @@ lazyLoadAndRegisterModel(`Thread`, 'thread');
|
|||
lazyLoadAndRegisterModel(`Account`, 'account');
|
||||
lazyLoadAndRegisterModel(`Message`, 'message');
|
||||
lazyLoadAndRegisterModel(`Contact`, 'contact');
|
||||
lazyLoadAndRegisterModel(`ContactBook`, 'contact-book');
|
||||
lazyLoadAndRegisterModel(`ContactGroup`, 'contact-group');
|
||||
lazyLoadAndRegisterModel(`Category`, 'category');
|
||||
lazyLoadAndRegisterModel(`Calendar`, 'calendar');
|
||||
|
|
|
@ -8,24 +8,17 @@ import _ from 'underscore';
|
|||
|
||||
const ItemSpecificities = new WeakMap();
|
||||
|
||||
export type IMenuItem =
|
||||
| {
|
||||
label: string;
|
||||
submenu?: IMenuItem[];
|
||||
type?: string;
|
||||
export type IMenuItem = {
|
||||
label?: string;
|
||||
submenu?: IMenuItem[];
|
||||
type?: 'separator';
|
||||
|
||||
key?: string; //unlocalized label
|
||||
command?: string;
|
||||
enabled?: boolean;
|
||||
hideWhenDisabled?: boolean;
|
||||
visible?: boolean;
|
||||
}
|
||||
| {
|
||||
key?: string; //unlocalized label
|
||||
label?: string;
|
||||
submenu?: IMenuItem[];
|
||||
type: 'separator';
|
||||
};
|
||||
id?: string; //unlocalized label
|
||||
command?: string;
|
||||
enabled?: boolean;
|
||||
hideWhenDisabled?: boolean;
|
||||
visible?: boolean;
|
||||
};
|
||||
|
||||
export function merge(menu: IMenuItem[], item: IMenuItem, itemSpecificity?: number) {
|
||||
let matchingItem;
|
||||
|
|
2
mailsync
2
mailsync
|
@ -1 +1 @@
|
|||
Subproject commit e78951655f7bc194029c709549c0f5c1a29e9c85
|
||||
Subproject commit 8c3e2ad5ba07b19fd96fe18cbe589b8c05c72e8c
|
Loading…
Add table
Reference in a new issue