mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-20 15:26:06 +08:00
Extend participant search to return / expand groups
This commit is contained in:
parent
3bded91307
commit
66dc60a731
|
@ -1,99 +1,107 @@
|
|||
# Mailspring SDK
|
||||
|
||||
* Mailspring SDK Guides
|
||||
* [Introduction](/README.md)
|
||||
* [Getting Started](/guides/GettingStarted.md)
|
||||
* [Getting Started Part 2](/guides/GettingStarted-2.md)
|
||||
* [Building a Package](/guides/PackageOverview.md)
|
||||
* [Interface Concepts](/guides/InterfaceConcepts.md)
|
||||
* [UI Components](/guides/React.md)
|
||||
* [Application Architecture](/guides/Architecture.md)
|
||||
* [Debugging Mailspring](/guides/Debugging.md)
|
||||
* [Accessing the Database](/guides/Database.md)
|
||||
* [Extending the Composer](/guides/ComposerExtensions.md)
|
||||
* [Writing Tests](/guides/WritingSpecs.md)
|
||||
* [Integration Testing](/guides/IntegrationTesting.md)
|
||||
* [Developing on Windows](/guides/Windows.md)
|
||||
* [FAQ](/guides/FAQ.md)
|
||||
- Mailspring SDK Guides
|
||||
- [Introduction](/README.md)
|
||||
- [Getting Started](/guides/GettingStarted.md)
|
||||
- [Getting Started Part 2](/guides/GettingStarted-2.md)
|
||||
- [Building a Package](/guides/PackageOverview.md)
|
||||
- [Interface Concepts](/guides/InterfaceConcepts.md)
|
||||
- [UI Components](/guides/React.md)
|
||||
- [Application Architecture](/guides/Architecture.md)
|
||||
- [Debugging Mailspring](/guides/Debugging.md)
|
||||
- [Accessing the Database](/guides/Database.md)
|
||||
- [Extending the Composer](/guides/ComposerExtensions.md)
|
||||
- [Writing Tests](/guides/WritingSpecs.md)
|
||||
- [Integration Testing](/guides/IntegrationTesting.md)
|
||||
- [Developing on Windows](/guides/Windows.md)
|
||||
- [FAQ](/guides/FAQ.md)
|
||||
|
||||
----
|
||||
---
|
||||
|
||||
### Full Class Reference
|
||||
|
||||
* General
|
||||
* [Actions](/classes/Actions.md)
|
||||
* [BufferedProcess](/classes/BufferedProcess.md)
|
||||
* [ChangeFolderTask](/classes/ChangeFolderTask.md)
|
||||
* [ChangeLabelsTask](/classes/ChangeLabelsTask.md)
|
||||
* [ChangeMailTask](/classes/ChangeMailTask.md)
|
||||
* [Color](/classes/Color.md)
|
||||
* [Config](/classes/Config.md)
|
||||
* [Contenteditable](/classes/Contenteditable.md)
|
||||
* [KeyCommandsRegion](/classes/KeyCommandsRegion.md)
|
||||
* [AppEnvConstructor](/classes/AppEnvConstructor.md)
|
||||
* [QueryResultSet](/classes/QueryResultSet.md)
|
||||
* [QuerySubscriptionPool](/classes/QuerySubscriptionPool.md)
|
||||
* [StyleManager](/classes/StyleManager.md)
|
||||
* [Task](/classes/Task.md)
|
||||
* [TaskQueueStatusStore](/classes/TaskQueueStatusStore.md)
|
||||
* [ThemeManager](/classes/ThemeManager.md)
|
||||
- General
|
||||
|
||||
* Component Kit
|
||||
* [EventedIFrame](/classes/EventedIFrame.md)
|
||||
* [Flexbox](/classes/Flexbox.md)
|
||||
* [InjectedComponent](/classes/InjectedComponent.md)
|
||||
* [InjectedComponentSet](/classes/InjectedComponentSet.md)
|
||||
* [Menu](/classes/Menu.md)
|
||||
* [MenuItem](/classes/MenuItem.md)
|
||||
* [MenuNameEmailItem](/classes/MenuNameEmailItem.md)
|
||||
* [MultiselectActionBar](/classes/MultiselectActionBar.md)
|
||||
* [MultiselectList](/classes/MultiselectList.md)
|
||||
* [ResizableRegion](/classes/ResizableRegion.md)
|
||||
* [RetinaImg](/classes/RetinaImg.md)
|
||||
* [Spinner](/classes/Spinner.md)
|
||||
- [Actions](/classes/Actions.md)
|
||||
- [BufferedProcess](/classes/BufferedProcess.md)
|
||||
- [ChangeFolderTask](/classes/ChangeFolderTask.md)
|
||||
- [ChangeLabelsTask](/classes/ChangeLabelsTask.md)
|
||||
- [ChangeMailTask](/classes/ChangeMailTask.md)
|
||||
- [Color](/classes/Color.md)
|
||||
- [Config](/classes/Config.md)
|
||||
- [Contenteditable](/classes/Contenteditable.md)
|
||||
- [KeyCommandsRegion](/classes/KeyCommandsRegion.md)
|
||||
- [AppEnvConstructor](/classes/AppEnvConstructor.md)
|
||||
- [QueryResultSet](/classes/QueryResultSet.md)
|
||||
- [QuerySubscriptionPool](/classes/QuerySubscriptionPool.md)
|
||||
- [StyleManager](/classes/StyleManager.md)
|
||||
- [Task](/classes/Task.md)
|
||||
- [TaskQueueStatusStore](/classes/TaskQueueStatusStore.md)
|
||||
- [ThemeManager](/classes/ThemeManager.md)
|
||||
|
||||
* Extensions
|
||||
* [ComposerExtension](/classes/ComposerExtension.md)
|
||||
* [ContenteditableExtension](/classes/ContenteditableExtension.md)
|
||||
* [DraftStoreExtension](/classes/DraftStoreExtension.md)
|
||||
* [MessageStoreExtension](/classes/MessageStoreExtension.md)
|
||||
* [MessageViewExtension](/classes/MessageViewExtension.md)
|
||||
- Component Kit
|
||||
|
||||
* Models
|
||||
* [Contact](/classes/Contact.md)
|
||||
* [Message](/classes/Message.md)
|
||||
* [Model](/classes/Model.md)
|
||||
* [Thread](/classes/Thread.md)
|
||||
- [EventedIFrame](/classes/EventedIFrame.md)
|
||||
- [Flexbox](/classes/Flexbox.md)
|
||||
- [InjectedComponent](/classes/InjectedComponent.md)
|
||||
- [InjectedComponentSet](/classes/InjectedComponentSet.md)
|
||||
- [Menu](/classes/Menu.md)
|
||||
- [MenuItem](/classes/MenuItem.md)
|
||||
- [MenuNameEmailContent](/classes/MenuNameEmailContent.md)
|
||||
- [MultiselectActionBar](/classes/MultiselectActionBar.md)
|
||||
- [MultiselectList](/classes/MultiselectList.md)
|
||||
- [ResizableRegion](/classes/ResizableRegion.md)
|
||||
- [RetinaImg](/classes/RetinaImg.md)
|
||||
- [Spinner](/classes/Spinner.md)
|
||||
|
||||
* Stores
|
||||
* [AccountStore](/classes/AccountStore.md)
|
||||
* [ComponentRegistry](/classes/ComponentRegistry.md)
|
||||
* [ContactStore](/classes/ContactStore.md)
|
||||
* [FocusedContentStore](/classes/FocusedContentStore.md)
|
||||
* [TaskQueue](/classes/TaskQueue.md)
|
||||
* [WorkspaceStore](/classes/WorkspaceStore.md)
|
||||
- Extensions
|
||||
|
||||
* Database
|
||||
* [Attribute](/classes/Attribute.md)
|
||||
* [AttributeBoolean](/classes/AttributeBoolean.md)
|
||||
* [AttributeCollection](/classes/AttributeCollection.md)
|
||||
* [AttributeDateTime](/classes/AttributeDateTime.md)
|
||||
* [AttributeJoinedData](/classes/AttributeJoinedData.md)
|
||||
* [AttributeNumber](/classes/AttributeNumber.md)
|
||||
* [AttributeObject](/classes/AttributeObject.md)
|
||||
* [AttributeServerId](/classes/AttributeServerId.md)
|
||||
* [AttributeString](/classes/AttributeString.md)
|
||||
* [DatabaseStore](/classes/DatabaseStore.md)
|
||||
* [Matcher](/classes/Matcher.md)
|
||||
* [ModelQuery](/classes/ModelQuery.md)
|
||||
* [SortOrder](/classes/SortOrder.md)
|
||||
- [ComposerExtension](/classes/ComposerExtension.md)
|
||||
- [ContenteditableExtension](/classes/ContenteditableExtension.md)
|
||||
- [DraftStoreExtension](/classes/DraftStoreExtension.md)
|
||||
- [MessageStoreExtension](/classes/MessageStoreExtension.md)
|
||||
- [MessageViewExtension](/classes/MessageViewExtension.md)
|
||||
|
||||
* Drafts
|
||||
* [DraftChangeSet](/classes/DraftChangeSet.md)
|
||||
* [DraftEditingSession](/classes/DraftEditingSession.md)
|
||||
* [DraftStore](/classes/DraftStore.md)
|
||||
- Models
|
||||
|
||||
* AppEnv
|
||||
* [PackageManager](/classes/PackageManager.md)
|
||||
- [Contact](/classes/Contact.md)
|
||||
- [Message](/classes/Message.md)
|
||||
- [Model](/classes/Model.md)
|
||||
- [Thread](/classes/Thread.md)
|
||||
|
||||
* Atom
|
||||
- Stores
|
||||
|
||||
- [AccountStore](/classes/AccountStore.md)
|
||||
- [ComponentRegistry](/classes/ComponentRegistry.md)
|
||||
- [ContactStore](/classes/ContactStore.md)
|
||||
- [FocusedContentStore](/classes/FocusedContentStore.md)
|
||||
- [TaskQueue](/classes/TaskQueue.md)
|
||||
- [WorkspaceStore](/classes/WorkspaceStore.md)
|
||||
|
||||
- Database
|
||||
|
||||
- [Attribute](/classes/Attribute.md)
|
||||
- [AttributeBoolean](/classes/AttributeBoolean.md)
|
||||
- [AttributeCollection](/classes/AttributeCollection.md)
|
||||
- [AttributeDateTime](/classes/AttributeDateTime.md)
|
||||
- [AttributeJoinedData](/classes/AttributeJoinedData.md)
|
||||
- [AttributeNumber](/classes/AttributeNumber.md)
|
||||
- [AttributeObject](/classes/AttributeObject.md)
|
||||
- [AttributeServerId](/classes/AttributeServerId.md)
|
||||
- [AttributeString](/classes/AttributeString.md)
|
||||
- [DatabaseStore](/classes/DatabaseStore.md)
|
||||
- [Matcher](/classes/Matcher.md)
|
||||
- [ModelQuery](/classes/ModelQuery.md)
|
||||
- [SortOrder](/classes/SortOrder.md)
|
||||
|
||||
- Drafts
|
||||
|
||||
- [DraftChangeSet](/classes/DraftChangeSet.md)
|
||||
- [DraftEditingSession](/classes/DraftEditingSession.md)
|
||||
- [DraftStore](/classes/DraftStore.md)
|
||||
|
||||
- AppEnv
|
||||
|
||||
- [PackageManager](/classes/PackageManager.md)
|
||||
|
||||
- Atom
|
||||
|
|
|
@ -49,7 +49,7 @@ export default class EventAttendeesInput extends React.Component<EventAttendeesI
|
|||
};
|
||||
|
||||
_completionNode = p => {
|
||||
return <Menu.NameEmailItem name={p.name} email={p.email} />;
|
||||
return <Menu.NameEmailContent name={p.name} email={p.email} />;
|
||||
};
|
||||
|
||||
_tokensForString = (string, options = {}) => {
|
||||
|
|
|
@ -12,7 +12,7 @@ export interface MenuItemProps {
|
|||
content?: any;
|
||||
}
|
||||
|
||||
export interface MenuNameEmailItemProps {
|
||||
export interface MenuNameEmailContentProps {
|
||||
name?: string;
|
||||
email?: string;
|
||||
}
|
||||
|
@ -82,11 +82,11 @@ Public: React component for a {Menu} item that displays a name and email address
|
|||
|
||||
Section: Component Kit
|
||||
*/
|
||||
class MenuNameEmailItem extends React.Component<MenuNameEmailItemProps> {
|
||||
static displayName = 'MenuNameEmailItem';
|
||||
class MenuNameEmailContent extends React.Component<MenuNameEmailContentProps> {
|
||||
static displayName = 'MenuNameEmailContent';
|
||||
|
||||
/*
|
||||
Public: React `props` supported by MenuNameEmailItem:
|
||||
Public: React `props` supported by MenuNameEmailContent:
|
||||
|
||||
- `name` (optional) The {String} name to be displayed.
|
||||
- `email` (optional) The {String} email address to be displayed.
|
||||
|
@ -142,7 +142,7 @@ export class Menu extends React.Component<MenuProps, MenuState> {
|
|||
static displayName = 'Menu';
|
||||
|
||||
static Item = MenuItem;
|
||||
static NameEmailItem = MenuNameEmailItem;
|
||||
static NameEmailContent = MenuNameEmailContent;
|
||||
|
||||
/*
|
||||
Public: React `props` supported by Menu:
|
||||
|
|
|
@ -9,6 +9,8 @@ import {
|
|||
RegExpUtils,
|
||||
Message,
|
||||
DraftEditingSession,
|
||||
ContactGroup,
|
||||
DatabaseStore,
|
||||
} from 'mailspring-exports';
|
||||
import { TokenizingTextField, Menu, InjectedComponentSet } from 'mailspring-component-kit';
|
||||
|
||||
|
@ -98,7 +100,11 @@ export default class ParticipantsTextField extends React.Component<ParticipantsT
|
|||
_completionNode = p => {
|
||||
const CustomComponent = p.customComponent;
|
||||
if (CustomComponent) return <CustomComponent token={p} />;
|
||||
return <Menu.NameEmailItem name={p.fullName()} email={p.email} key={p.id} />;
|
||||
if (p instanceof Contact) {
|
||||
return <Menu.NameEmailContent name={p.fullName()} email={p.email} key={p.id} />;
|
||||
} else if (p instanceof ContactGroup) {
|
||||
return p.name;
|
||||
}
|
||||
};
|
||||
|
||||
_tokensForString = async (string, options = {}) => {
|
||||
|
@ -157,10 +163,18 @@ export default class ParticipantsTextField extends React.Component<ParticipantsT
|
|||
tokensPromise = Promise.resolve(values);
|
||||
}
|
||||
|
||||
tokensPromise.then(tokens => {
|
||||
tokensPromise.then(async tokens => {
|
||||
// Safety check: remove anything from the incoming tokens that isn't
|
||||
// a Contact. We should never receive anything else in the tokens array.
|
||||
const contactTokens = tokens.filter(value => value instanceof Contact);
|
||||
const groupTokens = tokens.filter(value => value instanceof ContactGroup);
|
||||
|
||||
// convert the group tokens into contact tokens
|
||||
const contactsFromGroups = await DatabaseStore.findAll<Contact>(Contact, [
|
||||
Contact.attributes.contactGroups.containsAny(groupTokens.map(g => g.id)),
|
||||
]);
|
||||
|
||||
contactTokens.push(...contactsFromGroups);
|
||||
|
||||
const updates = {};
|
||||
for (const field of Object.keys(this.props.participants)) {
|
||||
|
@ -234,10 +248,15 @@ export default class ParticipantsTextField extends React.Component<ParticipantsT
|
|||
this._textfieldEl = el;
|
||||
}}
|
||||
tokens={this.props.participants[this.props.field]}
|
||||
tokenKey={p => p.email}
|
||||
tokenKey={p => p.email || p.id}
|
||||
tokenIsValid={p => ContactStore.isValidContact(p)}
|
||||
tokenRenderer={TokenRenderer}
|
||||
onRequestCompletions={input => ContactStore.searchContacts(input)}
|
||||
onRequestCompletions={async input =>
|
||||
(await Promise.all([
|
||||
ContactStore.searchContactGroups(input),
|
||||
ContactStore.searchContacts(input),
|
||||
])).flat()
|
||||
}
|
||||
shouldBreakOnKeydown={this._shouldBreakOnKeydown}
|
||||
onInputTrySubmit={this._onInputTrySubmit}
|
||||
completionNode={this._completionNode}
|
||||
|
|
|
@ -4,6 +4,7 @@ import RegExpUtils from '../../regexp-utils';
|
|||
import DatabaseStore from './database-store';
|
||||
import { AccountStore } from './account-store';
|
||||
import ComponentRegistry from '../../registries/component-registry';
|
||||
import { ContactGroup } from 'mailspring-exports';
|
||||
|
||||
/**
|
||||
Public: ContactStore provides convenience methods for searching contacts and
|
||||
|
@ -13,6 +14,17 @@ with additional actions.
|
|||
Section: Stores
|
||||
*/
|
||||
class ContactStore extends MailspringStore {
|
||||
async searchContactGroups(_search: string) {
|
||||
const search = _search.toLowerCase();
|
||||
|
||||
if (!search || search.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const groups = await DatabaseStore.findAll<ContactGroup>(ContactGroup);
|
||||
return groups.filter(g => g.name.toLowerCase().startsWith(search)).slice(0, 4);
|
||||
}
|
||||
|
||||
// Public: Search the user's contact list for the given search term.
|
||||
// This method compares the `search` string against each Contact's
|
||||
// `name` and `email`.
|
||||
|
@ -24,7 +36,7 @@ class ContactStore extends MailspringStore {
|
|||
//
|
||||
// Returns an {Array} of matching {Contact} models
|
||||
//
|
||||
searchContacts(_search, options: { limit?: number } = {}) {
|
||||
searchContacts(_search: string, options: { limit?: number } = {}) {
|
||||
const limit = Math.max(options.limit ? options.limit : 5, 0);
|
||||
const search = _search.toLowerCase();
|
||||
|
||||
|
|
Loading…
Reference in a new issue