about summary refs log tree commit diff
path: root/app/javascript/mastodon/features/list_timeline/index.js
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-12-05 23:02:27 +0100
committerGitHub <noreply@github.com>2017-12-05 23:02:27 +0100
commite20895f251d28b3631b1f5768302517a5b687b04 (patch)
tree88e86cef53df51df32e964921d444c08f34dd3a5 /app/javascript/mastodon/features/list_timeline/index.js
parent12cea76634d8380e24c3b218b18955b551995e1e (diff)
Add list of lists component to web UI (#5811)
* Add list of lists component to web UI

* Add list adding

* Add list removing

* List editor modal

* Add API account search limited by following=true relation

* Rework list editor modal

* Remove mandatory pagination of GET /api/v1/lists/:id/accounts

* Adjust search input placeholder

* Fix rspec (#5890)

* i18n: (zh-CN) Add missing translations for #5811 (#5891)

* i18n: (zh-CN) yarn manage:translations -- zh-CN

* i18n: (zh-CN) Add missing translations for #5811

* Fix some issues

- Display loading/missing state for list timelines
- Order lists alphabetically in overview
- Fix async list editor reset
- Redirect to /lists after deleting unpinned list
- Redirect to / after pinning a list

* Remove dead list columns when a list is deleted or fetch returns 404
Diffstat (limited to 'app/javascript/mastodon/features/list_timeline/index.js')
-rw-r--r--app/javascript/mastodon/features/list_timeline/index.js72
1 files changed, 68 insertions, 4 deletions
diff --git a/app/javascript/mastodon/features/list_timeline/index.js b/app/javascript/mastodon/features/list_timeline/index.js
index 71f6e36a8..1dcd4de14 100644
--- a/app/javascript/mastodon/features/list_timeline/index.js
+++ b/app/javascript/mastodon/features/list_timeline/index.js
@@ -6,10 +6,18 @@ import StatusListContainer from '../ui/containers/status_list_container';
 import Column from '../../components/column';
 import ColumnHeader from '../../components/column_header';
 import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
-import { FormattedMessage } from 'react-intl';
+import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
 import { connectListStream } from '../../actions/streaming';
 import { refreshListTimeline, expandListTimeline } from '../../actions/timelines';
-import { fetchList } from '../../actions/lists';
+import { fetchList, deleteList } from '../../actions/lists';
+import { openModal } from '../../actions/modal';
+import MissingIndicator from '../../components/missing_indicator';
+import LoadingIndicator from '../../components/loading_indicator';
+
+const messages = defineMessages({
+  deleteMessage: { id: 'confirmations.delete_list.message', defaultMessage: 'Are you sure you want to permanently delete this list?' },
+  deleteConfirm: { id: 'confirmations.delete_list.confirm', defaultMessage: 'Delete' },
+});
 
 const mapStateToProps = (state, props) => ({
   list: state.getIn(['lists', props.params.id]),
@@ -17,15 +25,21 @@ const mapStateToProps = (state, props) => ({
 });
 
 @connect(mapStateToProps)
+@injectIntl
 export default class ListTimeline extends React.PureComponent {
 
+  static contextTypes = {
+    router: PropTypes.object,
+  };
+
   static propTypes = {
     params: PropTypes.object.isRequired,
     dispatch: PropTypes.func.isRequired,
     columnId: PropTypes.string,
     hasUnread: PropTypes.bool,
     multiColumn: PropTypes.bool,
-    list: ImmutablePropTypes.map,
+    list: PropTypes.oneOfType([ImmutablePropTypes.map, PropTypes.bool]),
+    intl: PropTypes.object.isRequired,
   };
 
   handlePin = () => {
@@ -35,6 +49,7 @@ export default class ListTimeline extends React.PureComponent {
       dispatch(removeColumn(columnId));
     } else {
       dispatch(addColumn('LIST', { id: this.props.params.id }));
+      this.context.router.history.push('/');
     }
   }
 
@@ -73,12 +88,49 @@ export default class ListTimeline extends React.PureComponent {
     this.props.dispatch(expandListTimeline(id));
   }
 
+  handleEditClick = () => {
+    this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id }));
+  }
+
+  handleDeleteClick = () => {
+    const { dispatch, columnId, intl } = this.props;
+    const { id } = this.props.params;
+
+    dispatch(openModal('CONFIRM', {
+      message: intl.formatMessage(messages.deleteMessage),
+      confirm: intl.formatMessage(messages.deleteConfirm),
+      onConfirm: () => {
+        dispatch(deleteList(id));
+
+        if (!!columnId) {
+          dispatch(removeColumn(columnId));
+        } else {
+          this.context.router.history.push('/lists');
+        }
+      },
+    }));
+  }
+
   render () {
     const { hasUnread, columnId, multiColumn, list } = this.props;
     const { id } = this.props.params;
     const pinned = !!columnId;
     const title  = list ? list.get('title') : id;
 
+    if (typeof list === 'undefined') {
+      return (
+        <Column>
+          <LoadingIndicator />
+        </Column>
+      );
+    } else if (list === false) {
+      return (
+        <Column>
+          <MissingIndicator />
+        </Column>
+      );
+    }
+
     return (
       <Column ref={this.setRef}>
         <ColumnHeader
@@ -90,7 +142,19 @@ export default class ListTimeline extends React.PureComponent {
           onClick={this.handleHeaderClick}
           pinned={pinned}
           multiColumn={multiColumn}
-        />
+        >
+          <div className='column-header__links'>
+            <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleEditClick}>
+              <i className='fa fa-pencil' /> <FormattedMessage id='lists.edit' defaultMessage='Edit list' />
+            </button>
+
+            <button className='text-btn column-header__setting-btn' tabIndex='0' onClick={this.handleDeleteClick}>
+              <i className='fa fa-trash' /> <FormattedMessage id='lists.delete' defaultMessage='Delete list' />
+            </button>
+          </div>
+
+          <hr />
+        </ColumnHeader>
 
         <StatusListContainer
           trackScroll={!pinned}