Add ability for admins to force grouped notifications in web UI (#31610)
This commit is contained in:
		
							parent
							
								
									da42e9d446
								
							
						
					
					
						commit
						c73868cd78
					
				| @ -2,6 +2,7 @@ import { debounce } from 'lodash'; | |||||||
| 
 | 
 | ||||||
| import type { MarkerJSON } from 'mastodon/api_types/markers'; | import type { MarkerJSON } from 'mastodon/api_types/markers'; | ||||||
| import { getAccessToken } from 'mastodon/initial_state'; | import { getAccessToken } from 'mastodon/initial_state'; | ||||||
|  | import { selectUseGroupedNotifications } from 'mastodon/selectors/settings'; | ||||||
| import type { AppDispatch, RootState } from 'mastodon/store'; | import type { AppDispatch, RootState } from 'mastodon/store'; | ||||||
| import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; | import { createAppAsyncThunk } from 'mastodon/store/typed_functions'; | ||||||
| 
 | 
 | ||||||
| @ -75,13 +76,8 @@ interface MarkerParam { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function getLastNotificationId(state: RootState): string | undefined { | 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
 |   // eslint-disable-next-line @typescript-eslint/no-unsafe-return
 | ||||||
|   return enableBeta |   return selectUseGroupedNotifications(state) | ||||||
|     ? state.notificationGroups.lastReadId |     ? state.notificationGroups.lastReadId | ||||||
|     : // @ts-expect-error state.notifications is not yet typed
 |     : // @ts-expect-error state.notifications is not yet typed
 | ||||||
|       // eslint-disable-next-line @typescript-eslint/no-unsafe-call
 |       // eslint-disable-next-line @typescript-eslint/no-unsafe-call
 | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import { selectUseGroupedNotifications } from 'mastodon/selectors/settings'; | ||||||
| import { createAppAsyncThunk } from 'mastodon/store'; | import { createAppAsyncThunk } from 'mastodon/store'; | ||||||
| 
 | 
 | ||||||
| import { fetchNotifications } from './notification_groups'; | import { fetchNotifications } from './notification_groups'; | ||||||
| @ -6,13 +7,8 @@ import { expandNotifications } from './notifications'; | |||||||
| export const initializeNotifications = createAppAsyncThunk( | export const initializeNotifications = createAppAsyncThunk( | ||||||
|   'notifications/initialize', |   'notifications/initialize', | ||||||
|   (_, { dispatch, getState }) => { |   (_, { dispatch, getState }) => { | ||||||
|     // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
 |     if (selectUseGroupedNotifications(getState())) | ||||||
|     const enableBeta = getState().settings.getIn( |       void dispatch(fetchNotifications()); | ||||||
|       ['notifications', 'groupingBeta'], |  | ||||||
|       false, |  | ||||||
|     ) as boolean; |  | ||||||
| 
 |  | ||||||
|     if (enableBeta) void dispatch(fetchNotifications()); |  | ||||||
|     else void dispatch(expandNotifications({})); |     else void dispatch(expandNotifications({})); | ||||||
|   }, |   }, | ||||||
| ); | ); | ||||||
|  | |||||||
| @ -1,5 +1,7 @@ | |||||||
| // @ts-check
 | // @ts-check
 | ||||||
| 
 | 
 | ||||||
|  | import { selectUseGroupedNotifications } from 'mastodon/selectors/settings'; | ||||||
|  | 
 | ||||||
| import { getLocale } from '../locales'; | import { getLocale } from '../locales'; | ||||||
| import { connectStream } from '../stream'; | import { connectStream } from '../stream'; | ||||||
| 
 | 
 | ||||||
| @ -103,7 +105,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti | |||||||
|           const notificationJSON = JSON.parse(data.payload); |           const notificationJSON = JSON.parse(data.payload); | ||||||
|           dispatch(updateNotifications(notificationJSON, messages, locale)); |           dispatch(updateNotifications(notificationJSON, messages, locale)); | ||||||
|           // TODO: remove this once the groups feature replaces the previous one
 |           // TODO: remove this once the groups feature replaces the previous one
 | ||||||
|           if(getState().settings.getIn(['notifications', 'groupingBeta'], false)) { |           if(selectUseGroupedNotifications(getState())) { | ||||||
|             dispatch(processNewNotificationForGroups(notificationJSON)); |             dispatch(processNewNotificationForGroups(notificationJSON)); | ||||||
|           } |           } | ||||||
|           break; |           break; | ||||||
| @ -112,7 +114,7 @@ export const connectTimelineStream = (timelineId, channelName, params = {}, opti | |||||||
|           const state = getState(); |           const state = getState(); | ||||||
|           if (state.notifications.top || !state.notifications.mounted) |           if (state.notifications.top || !state.notifications.mounted) | ||||||
|             dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); |             dispatch(expandNotifications({ forceLoad: true, maxId: undefined })); | ||||||
|           if(state.settings.getIn(['notifications', 'groupingBeta'], false)) { |           if (selectUseGroupedNotifications(state)) { | ||||||
|             dispatch(refreshStaleNotificationGroups()); |             dispatch(refreshStaleNotificationGroups()); | ||||||
|           } |           } | ||||||
|           break; |           break; | ||||||
| @ -145,7 +147,7 @@ async function refreshHomeTimelineAndNotification(dispatch, getState) { | |||||||
|   await dispatch(expandHomeTimeline({ maxId: undefined })); |   await dispatch(expandHomeTimeline({ maxId: undefined })); | ||||||
| 
 | 
 | ||||||
|   // TODO: remove this once the groups feature replaces the previous one
 |   // 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
 |     // TODO: polling for merged notifications
 | ||||||
|     try { |     try { | ||||||
|       await dispatch(pollRecentGroupNotifications()); |       await dispatch(pollRecentGroupNotifications()); | ||||||
|  | |||||||
| @ -6,6 +6,7 @@ import { FormattedMessage } from 'react-intl'; | |||||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||||
| 
 | 
 | ||||||
| import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; | import { identityContextPropShape, withIdentity } from 'mastodon/identity_context'; | ||||||
|  | import { forceGroupedNotifications } from 'mastodon/initial_state'; | ||||||
| import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions'; | import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions'; | ||||||
| 
 | 
 | ||||||
| import ClearColumnButton from './clear_column_button'; | import ClearColumnButton from './clear_column_button'; | ||||||
| @ -67,6 +68,7 @@ class ColumnSettings extends PureComponent { | |||||||
| 
 | 
 | ||||||
|         <PolicyControls /> |         <PolicyControls /> | ||||||
| 
 | 
 | ||||||
|  |         {!forceGroupedNotifications && ( | ||||||
|           <section role='group' aria-labelledby='notifications-beta'> |           <section role='group' aria-labelledby='notifications-beta'> | ||||||
|             <h3 id='notifications-beta'> |             <h3 id='notifications-beta'> | ||||||
|               <FormattedMessage id='notifications.column_settings.beta.category' defaultMessage='Experimental features' /> |               <FormattedMessage id='notifications.column_settings.beta.category' defaultMessage='Experimental features' /> | ||||||
| @ -76,6 +78,7 @@ class ColumnSettings extends PureComponent { | |||||||
|               <SettingToggle id='unread-notification-markers' prefix='notifications' settings={settings} settingPath={['groupingBeta']} onChange={onChange} label={groupingShowStr} /> |               <SettingToggle id='unread-notification-markers' prefix='notifications' settings={settings} settingPath={['groupingBeta']} onChange={onChange} label={groupingShowStr} /> | ||||||
|             </div> |             </div> | ||||||
|           </section> |           </section> | ||||||
|  |         )} | ||||||
| 
 | 
 | ||||||
|         <section role='group' aria-labelledby='notifications-unread-markers'> |         <section role='group' aria-labelledby='notifications-unread-markers'> | ||||||
|           <h3 id='notifications-unread-markers'> |           <h3 id='notifications-unread-markers'> | ||||||
|  | |||||||
| @ -1,9 +1,10 @@ | |||||||
| import Notifications from 'mastodon/features/notifications'; | import Notifications from 'mastodon/features/notifications'; | ||||||
| import Notifications_v2 from 'mastodon/features/notifications_v2'; | import Notifications_v2 from 'mastodon/features/notifications_v2'; | ||||||
|  | import { selectUseGroupedNotifications } from 'mastodon/selectors/settings'; | ||||||
| import { useAppSelector } from 'mastodon/store'; | import { useAppSelector } from 'mastodon/store'; | ||||||
| 
 | 
 | ||||||
| export const NotificationsWrapper = (props) => { | export const NotificationsWrapper = (props) => { | ||||||
|   const optedInGroupedNotifications = useAppSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); |   const optedInGroupedNotifications = useAppSelector(selectUseGroupedNotifications); | ||||||
| 
 | 
 | ||||||
|   return ( |   return ( | ||||||
|     optedInGroupedNotifications ? <Notifications_v2 {...props} /> : <Notifications {...props} /> |     optedInGroupedNotifications ? <Notifications_v2 {...props} /> : <Notifications {...props} /> | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ import { timelinePreview, trendsEnabled } from 'mastodon/initial_state'; | |||||||
| import { transientSingleColumn } from 'mastodon/is_mobile'; | import { transientSingleColumn } from 'mastodon/is_mobile'; | ||||||
| import { canManageReports, canViewAdminDashboard } from 'mastodon/permissions'; | import { canManageReports, canViewAdminDashboard } from 'mastodon/permissions'; | ||||||
| import { selectUnreadNotificationGroupsCount } from 'mastodon/selectors/notifications'; | import { selectUnreadNotificationGroupsCount } from 'mastodon/selectors/notifications'; | ||||||
|  | import { selectUseGroupedNotifications } from 'mastodon/selectors/settings'; | ||||||
| 
 | 
 | ||||||
| import ColumnLink from './column_link'; | import ColumnLink from './column_link'; | ||||||
| import DisabledAccountBanner from './disabled_account_banner'; | import DisabledAccountBanner from './disabled_account_banner'; | ||||||
| @ -64,7 +65,7 @@ const messages = defineMessages({ | |||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const NotificationsLink = () => { | const NotificationsLink = () => { | ||||||
|   const optedInGroupedNotifications = useSelector((state) => state.getIn(['settings', 'notifications', 'groupingBeta'], false)); |   const optedInGroupedNotifications = useSelector(selectUseGroupedNotifications); | ||||||
|   const count = useSelector(state => state.getIn(['notifications', 'unread'])); |   const count = useSelector(state => state.getIn(['notifications', 'unread'])); | ||||||
|   const intl = useIntl(); |   const intl = useIntl(); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -43,6 +43,7 @@ | |||||||
|  * @property {boolean=} use_pending_items |  * @property {boolean=} use_pending_items | ||||||
|  * @property {string} version |  * @property {string} version | ||||||
|  * @property {string} sso_redirect |  * @property {string} sso_redirect | ||||||
|  |  * @property {boolean} force_grouped_notifications | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -118,6 +119,7 @@ export const criticalUpdatesPending = initialState?.critical_updates_pending; | |||||||
| // @ts-expect-error
 | // @ts-expect-error
 | ||||||
| export const statusPageUrl = getMeta('status_page_url'); | export const statusPageUrl = getMeta('status_page_url'); | ||||||
| export const sso_redirect = getMeta('sso_redirect'); | export const sso_redirect = getMeta('sso_redirect'); | ||||||
|  | export const forceGroupedNotifications = getMeta('force_grouped_notifications'); | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * @returns {string | undefined} |  * @returns {string | undefined} | ||||||
|  | |||||||
| @ -1,3 +1,4 @@ | |||||||
|  | import { forceGroupedNotifications } from 'mastodon/initial_state'; | ||||||
| import type { RootState } from 'mastodon/store'; | import type { RootState } from 'mastodon/store'; | ||||||
| 
 | 
 | ||||||
| /* eslint-disable @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access */ | /* 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; |   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) => | export const selectSettingsNotificationsShowUnread = (state: RootState) => | ||||||
|   state.settings.getIn(['notifications', 'showUnread']) as boolean; |   state.settings.getIn(['notifications', 'showUnread']) as boolean; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -109,6 +109,7 @@ class InitialStateSerializer < ActiveModel::Serializer | |||||||
|       trends_as_landing_page: Setting.trends_as_landing_page, |       trends_as_landing_page: Setting.trends_as_landing_page, | ||||||
|       trends_enabled: Setting.trends, |       trends_enabled: Setting.trends, | ||||||
|       version: instance_presenter.version, |       version: instance_presenter.version, | ||||||
|  |       force_grouped_notifications: ENV['FORCE_GROUPED_NOTIFICATIONS'] == 'true', | ||||||
|     } |     } | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user