From 435ff8e550fbcbf83e7eca1bccafe2817252e666 Mon Sep 17 00:00:00 2001 From: Claire Date: Tue, 27 Aug 2024 16:55:51 +0200 Subject: [PATCH] [Glitch] Add ability for admins to force grouped notifications in web UI Port c73868cd78592780cb9e0be6985fe2f34b7c91cd to glitch-soc Signed-off-by: Claire --- .../flavours/glitch/actions/markers.ts | 8 ++--- .../actions/notifications_migration.tsx | 10 ++---- .../flavours/glitch/actions/streaming.js | 8 +++-- .../components/column_settings.jsx | 19 ++++++----- .../glitch/features/notifications_wrapper.jsx | 3 +- .../features/ui/components/boost_modal.tsx | 32 ++++++++++++------- .../ui/components/navigation_panel.jsx | 3 +- .../flavours/glitch/initial_state.js | 2 ++ .../flavours/glitch/selectors/settings.ts | 5 +++ 9 files changed, 52 insertions(+), 38 deletions(-) diff --git a/app/javascript/flavours/glitch/actions/markers.ts b/app/javascript/flavours/glitch/actions/markers.ts index 861eae41ec..1c1fd60dcf 100644 --- a/app/javascript/flavours/glitch/actions/markers.ts +++ b/app/javascript/flavours/glitch/actions/markers.ts @@ -2,6 +2,7 @@ import { debounce } from 'lodash'; import type { MarkerJSON } from 'flavours/glitch/api_types/markers'; import { getAccessToken } from 'flavours/glitch/initial_state'; +import { selectUseGroupedNotifications } from 'flavours/glitch/selectors/settings'; import type { AppDispatch, RootState } from 'flavours/glitch/store'; import { createAppAsyncThunk } from 'flavours/glitch/store/typed_functions'; @@ -75,13 +76,8 @@ interface MarkerParam { } function getLastNotificationId(state: RootState): string | undefined { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access - const enableBeta = state.settings.getIn( - ['notifications', 'groupingBeta'], - false, - ) as boolean; // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return enableBeta + return selectUseGroupedNotifications(state) ? state.notificationGroups.lastReadId : // @ts-expect-error state.notifications is not yet typed // eslint-disable-next-line @typescript-eslint/no-unsafe-call diff --git a/app/javascript/flavours/glitch/actions/notifications_migration.tsx b/app/javascript/flavours/glitch/actions/notifications_migration.tsx index ac7727ecd1..6789dbf38c 100644 --- a/app/javascript/flavours/glitch/actions/notifications_migration.tsx +++ b/app/javascript/flavours/glitch/actions/notifications_migration.tsx @@ -1,3 +1,4 @@ +import { selectUseGroupedNotifications } from 'flavours/glitch/selectors/settings'; import { createAppAsyncThunk } from 'flavours/glitch/store'; import { fetchNotifications } from './notification_groups'; @@ -6,13 +7,8 @@ import { expandNotifications } from './notifications'; export const initializeNotifications = createAppAsyncThunk( 'notifications/initialize', (_, { dispatch, getState }) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access - const enableBeta = getState().settings.getIn( - ['notifications', 'groupingBeta'], - false, - ) as boolean; - - if (enableBeta) void dispatch(fetchNotifications()); + if (selectUseGroupedNotifications(getState())) + void dispatch(fetchNotifications()); else void dispatch(expandNotifications({})); }, ); diff --git a/app/javascript/flavours/glitch/actions/streaming.js b/app/javascript/flavours/glitch/actions/streaming.js index 49636d6212..3584a25625 100644 --- a/app/javascript/flavours/glitch/actions/streaming.js +++ b/app/javascript/flavours/glitch/actions/streaming.js @@ -1,5 +1,7 @@ // @ts-check +import { selectUseGroupedNotifications } from 'flavours/glitch/selectors/settings'; + import { getLocale } from '../locales'; import { connectStream } from '../stream'; @@ -103,7 +105,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti const notificationJSON = JSON.parse(data.payload); dispatch(updateNotifications(notificationJSON, messages, locale)); // TODO: remove this once the groups feature replaces the previous one - if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) { + if(selectUseGroupedNotifications(getState())) { dispatch(processNewNotificationForGroups(notificationJSON)); } break; @@ -112,7 +114,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti const state = getState(); if (state.notifications.top || !state.notifications.mounted) dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); - if(state.settings.getIn(['notifications', 'groupingBeta'], false)) { + if (selectUseGroupedNotifications(state)) { dispatch(refreshStaleNotificationGroups()); } break; @@ -145,7 +147,7 @@ async function refreshHomeTimelineAndNotification(dispatch, getState) { await dispatch(expandHomeTimeline({ maxId: undefined })); // TODO: remove this once the groups feature replaces the previous one - if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) { + if(selectUseGroupedNotifications(getState())) { // TODO: polling for merged notifications try { await dispatch(pollRecentGroupNotifications()); diff --git a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx index f98d09b500..3bd040eb51 100644 --- a/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx +++ b/app/javascript/flavours/glitch/features/notifications/components/column_settings.jsx @@ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context'; +import { forceGroupedNotifications } from 'flavours/glitch/initial_state'; import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'flavours/glitch/permissions'; import ClearColumnButton from './clear_column_button'; @@ -78,15 +79,17 @@ class ColumnSettings extends PureComponent { -
-

- -

+ {!forceGroupedNotifications && ( +
+

+ +

-
- -
-
+
+ +
+
+ )}

diff --git a/app/javascript/flavours/glitch/features/notifications_wrapper.jsx b/app/javascript/flavours/glitch/features/notifications_wrapper.jsx index 15ab3367cc..ab3eff889c 100644 --- a/app/javascript/flavours/glitch/features/notifications_wrapper.jsx +++ b/app/javascript/flavours/glitch/features/notifications_wrapper.jsx @@ -1,9 +1,10 @@ import Notifications from 'flavours/glitch/features/notifications'; import Notifications_v2 from 'flavours/glitch/features/notifications_v2'; +import { selectUseGroupedNotifications } from 'flavours/glitch/selectors/settings'; import { useAppSelector } from 'flavours/glitch/store'; export const NotificationsWrapper = (props) => { - const optedInGroupedNotifications = useAppSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); + const optedInGroupedNotifications = useAppSelector(selectUseGroupedNotifications); return ( optedInGroupedNotifications ? : diff --git a/app/javascript/flavours/glitch/features/ui/components/boost_modal.tsx b/app/javascript/flavours/glitch/features/ui/components/boost_modal.tsx index 38c7894c24..9d1cf8545f 100644 --- a/app/javascript/flavours/glitch/features/ui/components/boost_modal.tsx +++ b/app/javascript/flavours/glitch/features/ui/components/boost_modal.tsx @@ -24,7 +24,8 @@ export const BoostModal: React.FC<{ status: Status; onClose: () => void; onReblog: (status: Status, privacy: StatusVisibility) => void; -}> = ({ status, onReblog, onClose }) => { + missingMediaDescription?: boolean; +}> = ({ status, onReblog, onClose, missingMediaDescription }) => { const intl = useIntl(); const defaultPrivacy = useAppSelector( @@ -80,17 +81,24 @@ export const BoostModal: React.FC<{ )}

- - Shift+ - - ), - }} - /> + {missingMediaDescription ? ( + + ) : ( + + Shift+ + + ), + }} + /> + )}
diff --git a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx index 33c2db8278..905387caea 100644 --- a/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx +++ b/app/javascript/flavours/glitch/features/ui/components/navigation_panel.jsx @@ -36,6 +36,7 @@ import { timelinePreview, trendsEnabled } from 'flavours/glitch/initial_state'; import { transientSingleColumn } from 'flavours/glitch/is_mobile'; import { canManageReports, canViewAdminDashboard } from 'flavours/glitch/permissions'; import { selectUnreadNotificationGroupsCount } from 'flavours/glitch/selectors/notifications'; +import { selectUseGroupedNotifications } from 'flavours/glitch/selectors/settings'; import { preferencesLink } from 'flavours/glitch/utils/backend_links'; import ColumnLink from './column_link'; @@ -65,7 +66,7 @@ const messages = defineMessages({ }); const NotificationsLink = () => { - const optedInGroupedNotifications = useSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); + const optedInGroupedNotifications = useSelector(selectUseGroupedNotifications); const count = useSelector(state => state.getIn(['local_settings', 'notifications', 'tab_badge']) ? state.getIn(['notifications', 'unread']) : 0); const intl = useIntl(); diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index c5628f51ce..624f8bb101 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -46,6 +46,7 @@ * @property {boolean=} use_pending_items * @property {string} version * @property {string} sso_redirect + * @property {boolean} force_grouped_notifications * @property {string} status_page_url * @property {boolean} system_emoji_font * @property {string} default_content_type @@ -137,6 +138,7 @@ export const languages = initialState?.languages; export const criticalUpdatesPending = initialState?.critical_updates_pending; export const statusPageUrl = getMeta('status_page_url'); export const sso_redirect = getMeta('sso_redirect'); +export const forceGroupedNotifications = getMeta('force_grouped_notifications'); // Glitch-soc-specific settings export const maxFeedHashtags = (initialState && initialState.max_feed_hashtags) || 4; diff --git a/app/javascript/flavours/glitch/selectors/settings.ts b/app/javascript/flavours/glitch/selectors/settings.ts index 9a1a2c990b..c9cfd6dde5 100644 --- a/app/javascript/flavours/glitch/selectors/settings.ts +++ b/app/javascript/flavours/glitch/selectors/settings.ts @@ -1,3 +1,4 @@ +import { forceGroupedNotifications } from 'flavours/glitch/initial_state'; import type { RootState } from 'flavours/glitch/store'; /* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ @@ -25,6 +26,10 @@ export const selectSettingsNotificationsQuickFilterAdvanced = ( ) => state.settings.getIn(['notifications', 'quickFilter', 'advanced']) as boolean; +export const selectUseGroupedNotifications = (state: RootState) => + forceGroupedNotifications || + (state.settings.getIn(['notifications', 'groupingBeta']) as boolean); + export const selectSettingsNotificationsShowUnread = (state: RootState) => state.settings.getIn(['notifications', 'showUnread']) as boolean;