Skip to content

Commit

Permalink
Implement “permanently delete all” for Spam and Trash
Browse files Browse the repository at this point in the history
  • Loading branch information
bengotow committed Oct 13, 2017
1 parent cd9f751 commit b276962
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 86 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Mailspring Changelog

### 1.0.5 (Coming Soon)

Features:

- A new bar appears when you view the Trash and Spam folders allowing you to permanently delete messages.


### 1.0.4 (10/12/2017)

Features:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,18 @@ class SocialProfileLink extends React.Component {
class TextBlockWithAutolinkedElements extends React.Component {
static propTypes = {
className: PropTypes.string,
string: PropTypes.string,
text: PropTypes.string,
};

render() {
if (!this.props.string) {
if (!this.props.text) {
return false;
}

const nodes = [];
const hashtagOrMentionRegex = RegExpUtils.hashtagOrMentionRegex();

let remainder = this.props.string;
let remainder = this.props.text;
let match = null;
let count = 0;

Expand Down Expand Up @@ -123,14 +123,14 @@ class TextBlockWithAutolinkedElements extends React.Component {

class IconRow extends React.Component {
static propTypes = {
string: PropTypes.string,
node: PropTypes.node,
icon: PropTypes.string,
};

render() {
const { string, icon } = this.props;
const { node, icon } = this.props;

if (!string) {
if (!node) {
return false;
}
return (
Expand All @@ -141,7 +141,7 @@ class IconRow extends React.Component {
style={{ float: 'left' }}
/>
<span className="selectable" style={{ display: 'block', marginLeft: 25 }}>
{string}
{node}
</span>
</div>
);
Expand All @@ -150,21 +150,21 @@ class IconRow extends React.Component {

class LocationRow extends React.Component {
static propTypes = {
string: PropTypes.string,
location: PropTypes.string,
};

render() {
return (
<IconRow
icon="location"
string={
this.props.string && (
node={
this.props.location && (
<span>
{this.props.string}
{this.props.location}
{' ['}
<a className="plain" href={`https://maps.google.com/?q=${this.props.string}`}>
<a className="plain" href={`https://maps.google.com/?q=${this.props.v}`}>
View
</a>
</a>f
{']'}
</span>
)
Expand Down Expand Up @@ -335,11 +335,11 @@ export default class SidebarParticipantProfile extends React.Component {
)}

<div className="additional-info">
<TextBlockWithAutolinkedElements string={description} className="description" />
<LocationRow string={location} />
<TextBlockWithAutolinkedElements text={description} className="description" />
<LocationRow location={location} />
<IconRow
icon="timezone"
string={
node={
timeZone && (
<span>
{`${timeZone.replace('_', ' ')} - `}
Expand All @@ -352,14 +352,14 @@ export default class SidebarParticipantProfile extends React.Component {
)
}
/>
<IconRow icon="industry" string={category && (category.industry || category.sector)} />
<IconRow icon="industry" node={category && (category.industry || category.sector)} />
<IconRow
icon="holding"
string={{ private: 'Privately Held', public: `Stock Symbol ${ticker}` }[type]}
node={{ private: 'Privately Held', public: `Stock Symbol ${ticker}` }[type]}
/>
<IconRow icon="phone" string={phone} />
<IconRow icon="employees" string={employees} />
<IconRow icon="funding" string={funding} />
<IconRow icon="phone" node={phone} />
<IconRow icon="employees" node={employees} />
<IconRow icon="funding" node={funding} />

<div className="social-profiles-wrap">
<SocialProfileLink service="facebook" handle={facebook && facebook.handle} />
Expand Down Expand Up @@ -408,8 +408,8 @@ export default class SidebarParticipantProfile extends React.Component {
</div>

<div className="additional-info">
<TextBlockWithAutolinkedElements string={bio} className="bio" />
<LocationRow string={location} />
<TextBlockWithAutolinkedElements text={bio} className="bio" />
<LocationRow location={location} />
</div>
</div>
);
Expand Down
5 changes: 5 additions & 0 deletions app/internal_packages/thread-list/lib/main.es6
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ComponentRegistry, WorkspaceStore } from 'mailspring-exports';

import ThreadList from './thread-list';
import ThreadListToolbar from './thread-list-toolbar';
import ThreadListEmptyFolderBar from './thread-list-empty-folder-bar';
import MessageListToolbar from './message-list-toolbar';
import SelectedItemsStack from './selected-items-stack';

Expand All @@ -16,6 +17,10 @@ import {
} from './thread-toolbar-buttons';

export function activate() {
ComponentRegistry.register(ThreadListEmptyFolderBar, {
location: WorkspaceStore.Location.ThreadList,
});

ComponentRegistry.register(ThreadList, {
location: WorkspaceStore.Location.ThreadList,
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { ListensToFluxStore, RetinaImg } from 'mailspring-component-kit';
import {
Actions,
React,
Folder,
PropTypes,
TaskQueue,
ExpungeAllInFolderTask,
FocusedPerspectiveStore,
ThreadCountsStore,
} from 'mailspring-exports';

class ThreadListEmptyFolderBar extends React.Component {
static displayName = 'ThreadListEmptyFolderBar';

static propTypes = {
role: PropTypes.string,
folders: PropTypes.array,
count: PropTypes.number,
busy: PropTypes.bool,
};

_onClick = () => {
const { folders } = this.props;

Actions.queueTasks(
folders.map(
folder =>
new ExpungeAllInFolderTask({
accountId: folder.accountId,
folder,
})
)
);
};

render() {
const { role, count, busy } = this.props;
if (!role || count === 0) {
return false;
}
const term = role === 'trash' ? 'deleted' : role;

return (
<div className="thread-list-empty-folder-bar">
<div className="notice">
{`Showing ${(count / 1).toLocaleString()}
${count > 1 ? 'threads' : 'thread'}
with ${term} messages`}
</div>
{busy ? (
<div className="btn">
<RetinaImg
style={{ width: 16, height: 16 }}
name="inline-loading-spinner.gif"
mode={RetinaImg.Mode.ContentPreserve}
/>
</div>
) : (
<div className="btn" onClick={this._onClick}>{`Empty ${role} now`}</div>
)}
</div>
);
}
}

export default ListensToFluxStore(ThreadListEmptyFolderBar, {
stores: [TaskQueue, ThreadCountsStore, FocusedPerspectiveStore],
getStateFromStores: props => {
const p = FocusedPerspectiveStore.current();
const folders = (p && p.categories()) || [];

if (
!folders.length ||
!folders.every(c => c instanceof Folder && (c.role === 'trash' || c.role === 'spam'))
) {
return { role: null, folders: null };
}

return {
folders,
role: folders[0].role,
busy:
TaskQueue.findTasks(ExpungeAllInFolderTask).some(t =>
folders.map(f => f.accountId).includes(t.accountId)
) > 0,
count: folders.reduce(
(sum, { id }) => sum + ThreadCountsStore.totalCountForCategoryId(id),
0
),
};
},
});

0 comments on commit b276962

Please sign in to comment.