about summary refs log tree commit diff
path: root/app/javascript/flavours
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours')
-rw-r--r--app/javascript/flavours/glitch/actions/alerts.js27
-rw-r--r--app/javascript/flavours/glitch/actions/compose.js43
-rw-r--r--app/javascript/flavours/glitch/actions/lists.js4
-rw-r--r--app/javascript/flavours/glitch/actions/push_notifications/registerer.js15
-rw-r--r--app/javascript/flavours/glitch/actions/settings.js5
-rw-r--r--app/javascript/flavours/glitch/containers/compose_container.js3
-rw-r--r--app/javascript/flavours/glitch/containers/status_container.js6
-rw-r--r--app/javascript/flavours/glitch/features/composer/options/index.js1
-rw-r--r--app/javascript/flavours/glitch/features/getting_started/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/public_timeline/index.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/embed_modal.js3
-rw-r--r--app/javascript/flavours/glitch/features/ui/components/report_modal.js2
-rw-r--r--app/javascript/flavours/glitch/features/ui/index.js2
-rw-r--r--app/javascript/flavours/glitch/middleware/errors.js18
-rw-r--r--app/javascript/flavours/glitch/styles/accounts.scss4
-rw-r--r--app/javascript/flavours/glitch/styles/admin.scss7
-rw-r--r--app/javascript/flavours/glitch/styles/widgets.scss7
-rw-r--r--app/javascript/flavours/glitch/util/resize_image.js2
18 files changed, 106 insertions, 47 deletions
diff --git a/app/javascript/flavours/glitch/actions/alerts.js b/app/javascript/flavours/glitch/actions/alerts.js
index f37fdeeb6..50cd48a9e 100644
--- a/app/javascript/flavours/glitch/actions/alerts.js
+++ b/app/javascript/flavours/glitch/actions/alerts.js
@@ -1,3 +1,10 @@
+import { defineMessages } from 'react-intl';
+
+const messages = defineMessages({
+  unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
+  unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
+});
+
 export const ALERT_SHOW    = 'ALERT_SHOW';
 export const ALERT_DISMISS = 'ALERT_DISMISS';
 export const ALERT_CLEAR   = 'ALERT_CLEAR';
@@ -15,10 +22,28 @@ export function clearAlert() {
   };
 };
 
-export function showAlert(title, message) {
+export function showAlert(title = messages.unexpectedTitle, message = messages.unexpectedMessage) {
   return {
     type: ALERT_SHOW,
     title,
     message,
   };
 };
+
+export function showAlertForError(error) {
+  if (error.response) {
+    const { data, status, statusText } = error.response;
+
+    let message = statusText;
+    let title   = `${status}`;
+
+    if (data.error) {
+      message = data.error;
+    }
+
+    return showAlert(title, message);
+  } else {
+    console.error(error);
+    return showAlert();
+  }
+}
diff --git a/app/javascript/flavours/glitch/actions/compose.js b/app/javascript/flavours/glitch/actions/compose.js
index 04e857713..0dd1766bc 100644
--- a/app/javascript/flavours/glitch/actions/compose.js
+++ b/app/javascript/flavours/glitch/actions/compose.js
@@ -1,5 +1,5 @@
 import api from 'flavours/glitch/util/api';
-import { CancelToken } from 'axios';
+import { CancelToken, isCancel } from 'axios';
 import { throttle } from 'lodash';
 import { search as emojiSearch } from 'flavours/glitch/util/emoji/emoji_mart_search_light';
 import { useEmoji } from './emojis';
@@ -8,6 +8,9 @@ import { recoverHashtags } from 'flavours/glitch/util/hashtag';
 import resizeImage from 'flavours/glitch/util/resize_image';
 
 import { updateTimeline } from './timelines';
+import { showAlertForError } from './alerts';
+import { showAlert } from './alerts';
+import { defineMessages } from 'react-intl';
 
 let cancelFetchComposeSuggestionsAccounts;
 
@@ -52,6 +55,10 @@ export const COMPOSE_UPLOAD_CHANGE_FAIL        = 'COMPOSE_UPLOAD_UPDATE_FAIL';
 
 export const COMPOSE_DOODLE_SET        = 'COMPOSE_DOODLE_SET';
 
+const messages = defineMessages({
+  uploadErrorLimit: { id: 'upload_error.limit', defaultMessage: 'File upload limit exceeded.' },
+});
+
 export function changeCompose(text) {
   return {
     type: COMPOSE_CHANGE,
@@ -207,20 +214,32 @@ export function doodleSet(options) {
 
 export function uploadCompose(files) {
   return function (dispatch, getState) {
-    if (getState().getIn(['compose', 'media_attachments']).size > 3) {
+    const uploadLimit = 4;
+    const media  = getState().getIn(['compose', 'media_attachments']);
+    const total = Array.from(files).reduce((a, v) => a + v.size, 0);
+    const progress = new Array(files.length).fill(0);
+
+    if (files.length + media.size > uploadLimit) {
+      dispatch(showAlert(undefined, messages.uploadErrorLimit));
       return;
     }
-
     dispatch(uploadComposeRequest());
 
-    resizeImage(files[0]).then(file => {
-      const data = new FormData();
-      data.append('file', file);
+    for (const [i, f] of Array.from(files).entries()) {
+      if (media.size + i > 3) break;
 
-      return api(getState).post('/api/v1/media', data, {
-        onUploadProgress: ({ loaded, total }) => dispatch(uploadComposeProgress(loaded, total)),
-      }).then(({ data }) => dispatch(uploadComposeSuccess(data)));
-    }).catch(error => dispatch(uploadComposeFail(error)));
+      resizeImage(f).then(file => {
+        const data = new FormData();
+        data.append('file', file);
+
+        return api(getState).post('/api/v1/media', data, {
+          onUploadProgress: function({ loaded }){
+            progress[i] = loaded;
+            dispatch(uploadComposeProgress(progress.reduce((a, v) => a + v, 0), total));
+          },
+        }).then(({ data }) => dispatch(uploadComposeSuccess(data)));
+      }).catch(error => dispatch(uploadComposeFail(error)));
+    };
   };
 };
 
@@ -320,6 +339,10 @@ const fetchComposeSuggestionsAccounts = throttle((dispatch, getState, token) =>
     },
   }).then(response => {
     dispatch(readyComposeSuggestionsAccounts(token, response.data));
+  }).catch(error => {
+    if (!isCancel(error)) {
+      dispatch(showAlertForError(error));
+    }
   });
 }, 200, { leading: true, trailing: true });
 
diff --git a/app/javascript/flavours/glitch/actions/lists.js b/app/javascript/flavours/glitch/actions/lists.js
index 7d94ee950..f29ca1e01 100644
--- a/app/javascript/flavours/glitch/actions/lists.js
+++ b/app/javascript/flavours/glitch/actions/lists.js
@@ -1,4 +1,5 @@
 import api from 'flavours/glitch/util/api';
+import { showAlertForError } from './alerts';
 
 export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
 export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
@@ -239,7 +240,8 @@ export const fetchListSuggestions = q => (dispatch, getState) => {
   };
 
   api(getState).get('/api/v1/accounts/search', { params })
-    .then(({ data }) => dispatch(fetchListSuggestionsReady(q, data)));
+    .then(({ data }) => dispatch(fetchListSuggestionsReady(q, data)))
+    .catch(error => dispatch(showAlertForError(error)));
 };
 
 export const fetchListSuggestionsReady = (query, accounts) => ({
diff --git a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
index 91f442415..8fdb239f7 100644
--- a/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
+++ b/app/javascript/flavours/glitch/actions/push_notifications/registerer.js
@@ -109,14 +109,11 @@ export function register () {
             pushNotificationsSetting.remove(me);
           }
 
-          try {
-            getRegistration()
-              .then(getPushSubscription)
-              .then(unsubscribe);
-          } catch (e) {
-
-          }
-        });
+          return getRegistration()
+            .then(getPushSubscription)
+            .then(unsubscribe);
+        })
+        .catch(console.warn);
     } else {
       console.warn('Your browser does not support Web Push Notifications.');
     }
@@ -137,6 +134,6 @@ export function saveSettings() {
       if (me) {
         pushNotificationsSetting.set(me, data);
       }
-    });
+    }).catch(console.warn);
   };
 }
diff --git a/app/javascript/flavours/glitch/actions/settings.js b/app/javascript/flavours/glitch/actions/settings.js
index 87b2ae76d..fb0bcc09c 100644
--- a/app/javascript/flavours/glitch/actions/settings.js
+++ b/app/javascript/flavours/glitch/actions/settings.js
@@ -1,5 +1,6 @@
 import api from 'flavours/glitch/util/api';
 import { debounce } from 'lodash';
+import { showAlertForError } from './alerts';
 
 export const SETTING_CHANGE = 'SETTING_CHANGE';
 export const SETTING_SAVE   = 'SETTING_SAVE';
@@ -23,7 +24,9 @@ const debouncedSave = debounce((dispatch, getState) => {
 
   const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
 
-  api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE }));
+  api(getState).put('/api/web/settings', { data })
+    .then(() => dispatch({ type: SETTING_SAVE }))
+    .catch(error => dispatch(showAlertForError(error)));
 }, 5000, { trailing: true });
 
 export function saveSettings() {
diff --git a/app/javascript/flavours/glitch/containers/compose_container.js b/app/javascript/flavours/glitch/containers/compose_container.js
index 60f6a9c9f..74c411b7c 100644
--- a/app/javascript/flavours/glitch/containers/compose_container.js
+++ b/app/javascript/flavours/glitch/containers/compose_container.js
@@ -7,6 +7,7 @@ import { IntlProvider, addLocaleData } from 'react-intl';
 import { getLocale } from 'mastodon/locales';
 import Compose from 'flavours/glitch/features/standalone/compose';
 import initialState from 'flavours/glitch/util/initial_state';
+import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
 
 const { localeData, messages } = getLocale();
 addLocaleData(localeData);
@@ -17,6 +18,8 @@ if (initialState) {
   store.dispatch(hydrateStore(initialState));
 }
 
+store.dispatch(fetchCustomEmojis());
+
 export default class TimelineContainer extends React.PureComponent {
 
   static propTypes = {
diff --git a/app/javascript/flavours/glitch/containers/status_container.js b/app/javascript/flavours/glitch/containers/status_container.js
index f28dce609..f783878b0 100644
--- a/app/javascript/flavours/glitch/containers/status_container.js
+++ b/app/javascript/flavours/glitch/containers/status_container.js
@@ -25,6 +25,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
 import { changeLocalSetting } from 'flavours/glitch/actions/local_settings';
 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
 import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
+import { showAlertForError } from '../actions/alerts';
 
 const messages = defineMessages({
   deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
@@ -134,7 +135,10 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
   },
 
   onEmbed (status) {
-    dispatch(openModal('EMBED', { url: status.get('url') }));
+    dispatch(openModal('EMBED', {
+      url: status.get('url'),
+      onError: error => dispatch(showAlertForError(error)),
+    }));
   },
 
   onDelete (status, history, withRedraft = false) {
diff --git a/app/javascript/flavours/glitch/features/composer/options/index.js b/app/javascript/flavours/glitch/features/composer/options/index.js
index 9fe3abc03..5b4a7444c 100644
--- a/app/javascript/flavours/glitch/features/composer/options/index.js
+++ b/app/javascript/flavours/glitch/features/composer/options/index.js
@@ -214,6 +214,7 @@ export default class ComposerOptions extends React.PureComponent {
           onChange={handleChangeFiles}
           ref={handleRefFileElement}
           type='file'
+          multiple
           {...hiddenComponent}
         />
         <Dropdown
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.js b/app/javascript/flavours/glitch/features/getting_started/index.js
index fe0dd506e..7b645c9d0 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.js
+++ b/app/javascript/flavours/glitch/features/getting_started/index.js
@@ -166,7 +166,7 @@ export default class GettingStarted extends ImmutablePureComponent {
           <div className='getting-started__footer'>
             <ul>
               {invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>}
-              <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this instance' /></a> · </li>
+              <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li>
               <li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li>
               <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li>
               <li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a></li>
diff --git a/app/javascript/flavours/glitch/features/public_timeline/index.js b/app/javascript/flavours/glitch/features/public_timeline/index.js
index 477d3b8c7..7fe472202 100644
--- a/app/javascript/flavours/glitch/features/public_timeline/index.js
+++ b/app/javascript/flavours/glitch/features/public_timeline/index.js
@@ -127,7 +127,7 @@ export default class PublicTimeline extends React.PureComponent {
           onLoadMore={this.handleLoadMore}
           trackScroll={!pinned}
           scrollKey={`public_timeline-${columnId}`}
-          emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other instances to fill it up' />}
+          emptyMessage={<FormattedMessage id='empty_column.public' defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up' />}
         />
       </Column>
     );
diff --git a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
index bf29b0da5..b1643df1c 100644
--- a/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/embed_modal.js
@@ -10,6 +10,7 @@ export default class EmbedModal extends ImmutablePureComponent {
   static propTypes = {
     url: PropTypes.string.isRequired,
     onClose: PropTypes.func.isRequired,
+    onError: PropTypes.func.isRequired,
     intl: PropTypes.object.isRequired,
   }
 
@@ -35,6 +36,8 @@ export default class EmbedModal extends ImmutablePureComponent {
       iframeDocument.body.style.margin = 0;
       this.iframe.width  = iframeDocument.body.scrollWidth;
       this.iframe.height = iframeDocument.body.scrollHeight;
+    }).catch(error => {
+      this.props.onError(error);
     });
   }
 
diff --git a/app/javascript/flavours/glitch/features/ui/components/report_modal.js b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
index a139394ac..8be1d5856 100644
--- a/app/javascript/flavours/glitch/features/ui/components/report_modal.js
+++ b/app/javascript/flavours/glitch/features/ui/components/report_modal.js
@@ -97,7 +97,7 @@ export default class ReportModal extends ImmutablePureComponent {
 
         <div className='report-modal__container'>
           <div className='report-modal__comment'>
-            <p><FormattedMessage id='report.hint' defaultMessage='The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:' /></p>
+            <p><FormattedMessage id='report.hint' defaultMessage='The report will be sent to your server moderators. You can provide an explanation of why you are reporting this account below:' /></p>
 
             <textarea
               className='setting-text light'
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index 602d93832..a19b3abf1 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -186,7 +186,7 @@ export default class UI extends React.Component {
     this.setState({ draggingOver: false });
     this.dragTargets = [];
 
-    if (e.dataTransfer && e.dataTransfer.files.length === 1) {
+    if (e.dataTransfer && e.dataTransfer.files.length >= 1) {
       this.props.dispatch(uploadCompose(e.dataTransfer.files));
     }
   }
diff --git a/app/javascript/flavours/glitch/middleware/errors.js b/app/javascript/flavours/glitch/middleware/errors.js
index f3dfc8b06..212c1f4ad 100644
--- a/app/javascript/flavours/glitch/middleware/errors.js
+++ b/app/javascript/flavours/glitch/middleware/errors.js
@@ -1,4 +1,4 @@
-import { showAlert } from 'flavours/glitch/actions/alerts';
+import { showAlertForError } from 'flavours/glitch/actions/alerts';
 
 const defaultFailSuffix = 'FAIL';
 
@@ -8,21 +8,7 @@ export default function errorsMiddleware() {
       const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
 
       if (action.type.match(isFail)) {
-        if (action.error.response) {
-          const { data, status, statusText } = action.error.response;
-
-          let message = statusText;
-          let title   = `${status}`;
-
-          if (data.error) {
-            message = data.error;
-          }
-
-          dispatch(showAlert(title, message));
-        } else {
-          console.error(action.error);
-          dispatch(showAlert('Oops!', 'An unexpected error occurred.'));
-        }
+        dispatch(showAlertForError(action.error));
       }
     }
 
diff --git a/app/javascript/flavours/glitch/styles/accounts.scss b/app/javascript/flavours/glitch/styles/accounts.scss
index 9c6518bea..d2ae83b2e 100644
--- a/app/javascript/flavours/glitch/styles/accounts.scss
+++ b/app/javascript/flavours/glitch/styles/accounts.scss
@@ -290,3 +290,7 @@
     border-bottom: 0;
   }
 }
+
+.directory__tag .trends__item__current {
+  width: auto;
+}
diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss
index 4e969601b..4dbbaa1e8 100644
--- a/app/javascript/flavours/glitch/styles/admin.scss
+++ b/app/javascript/flavours/glitch/styles/admin.scss
@@ -153,10 +153,15 @@ $content-width: 840px;
       font-weight: 500;
     }
 
-    .directory__tag a {
+    .directory__tag > a,
+    .directory__tag > div {
       box-shadow: none;
     }
 
+    .directory__tag .table-action-link .fa {
+      color: inherit;
+    }
+
     .directory__tag h4 {
       font-size: 18px;
       font-weight: 700;
diff --git a/app/javascript/flavours/glitch/styles/widgets.scss b/app/javascript/flavours/glitch/styles/widgets.scss
index c97337e4e..1eaf30c5b 100644
--- a/app/javascript/flavours/glitch/styles/widgets.scss
+++ b/app/javascript/flavours/glitch/styles/widgets.scss
@@ -269,7 +269,8 @@
     box-sizing: border-box;
     margin-bottom: 10px;
 
-    a {
+    & > a,
+    & > div {
       display: flex;
       align-items: center;
       justify-content: space-between;
@@ -279,7 +280,9 @@
       text-decoration: none;
       color: inherit;
       box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
+    }
 
+    & > a {
       &:hover,
       &:active,
       &:focus {
@@ -287,7 +290,7 @@
       }
     }
 
-    &.active a {
+    &.active > a {
       background: $ui-highlight-color;
       cursor: default;
     }
diff --git a/app/javascript/flavours/glitch/util/resize_image.js b/app/javascript/flavours/glitch/util/resize_image.js
index d1608094f..bbdbc865e 100644
--- a/app/javascript/flavours/glitch/util/resize_image.js
+++ b/app/javascript/flavours/glitch/util/resize_image.js
@@ -31,7 +31,7 @@ const loadImage = inputFile => new Promise((resolve, reject) => {
 });
 
 const getOrientation = (img, type = 'image/png') => new Promise(resolve => {
-  if (type !== 'image/jpeg') {
+  if (!['image/jpeg', 'image/webp'].includes(type)) {
     resolve(1);
     return;
   }