diff --git a/app/javascript/mastodon/actions/markers.ts b/app/javascript/mastodon/actions/markers.ts
index 77d91d9b9..521859f6c 100644
--- a/app/javascript/mastodon/actions/markers.ts
+++ b/app/javascript/mastodon/actions/markers.ts
@@ -2,6 +2,7 @@ import { debounce } from 'lodash';
import type { MarkerJSON } from 'mastodon/api_types/markers';
import { getAccessToken } from 'mastodon/initial_state';
+import { selectUseGroupedNotifications } from 'mastodon/selectors/settings';
import type { AppDispatch, RootState } from 'mastodon/store';
import { createAppAsyncThunk } from 'mastodon/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/mastodon/actions/notifications_migration.tsx b/app/javascript/mastodon/actions/notifications_migration.tsx
index c245dc756..0d4da765e 100644
--- a/app/javascript/mastodon/actions/notifications_migration.tsx
+++ b/app/javascript/mastodon/actions/notifications_migration.tsx
@@ -1,3 +1,4 @@
+import { selectUseGroupedNotifications } from 'mastodon/selectors/settings';
import { createAppAsyncThunk } from 'mastodon/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/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js
index 04f5e6b88..bfdd894b8 100644
--- a/app/javascript/mastodon/actions/streaming.js
+++ b/app/javascript/mastodon/actions/streaming.js
@@ -1,5 +1,7 @@
// @ts-check
+import { selectUseGroupedNotifications } from 'mastodon/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/mastodon/features/notifications/components/column_settings.jsx b/app/javascript/mastodon/features/notifications/components/column_settings.jsx
index 359f0fb12..ed2f4ada3 100644
--- a/app/javascript/mastodon/features/notifications/components/column_settings.jsx
+++ b/app/javascript/mastodon/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 'mastodon/identity_context';
+import { forceGroupedNotifications } from 'mastodon/initial_state';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
import ClearColumnButton from './clear_column_button';
@@ -67,15 +68,17 @@ class ColumnSettings extends PureComponent {
-
-
-
-
+ {!forceGroupedNotifications && (
+
+
+
+
+
+ )}
diff --git a/app/javascript/mastodon/features/notifications_wrapper.jsx b/app/javascript/mastodon/features/notifications_wrapper.jsx
index 057ed1b39..4b3efeb54 100644
--- a/app/javascript/mastodon/features/notifications_wrapper.jsx
+++ b/app/javascript/mastodon/features/notifications_wrapper.jsx
@@ -1,9 +1,10 @@
import Notifications from 'mastodon/features/notifications';
import Notifications_v2 from 'mastodon/features/notifications_v2';
+import { selectUseGroupedNotifications } from 'mastodon/selectors/settings';
import { useAppSelector } from 'mastodon/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/mastodon/features/ui/components/navigation_panel.jsx b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx
index d30ea0ac5..407276d12 100644
--- a/app/javascript/mastodon/features/ui/components/navigation_panel.jsx
+++ b/app/javascript/mastodon/features/ui/components/navigation_panel.jsx
@@ -37,6 +37,7 @@ import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
import { transientSingleColumn } from 'mastodon/is_mobile';
import { canManageReports, canViewAdminDashboard } from 'mastodon/permissions';
import { selectUnreadNotificationGroupsCount } from 'mastodon/selectors/notifications';
+import { selectUseGroupedNotifications } from 'mastodon/selectors/settings';
import ColumnLink from './column_link';
import DisabledAccountBanner from './disabled_account_banner';
@@ -64,7 +65,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(['notifications', 'unread']));
const intl = useIntl();
diff --git a/app/javascript/mastodon/initial_state.js b/app/javascript/mastodon/initial_state.js
index 60b35cb31..cf33b12dd 100644
--- a/app/javascript/mastodon/initial_state.js
+++ b/app/javascript/mastodon/initial_state.js
@@ -43,6 +43,7 @@
* @property {boolean=} use_pending_items
* @property {string} version
* @property {string} sso_redirect
+ * @property {boolean} force_grouped_notifications
*/
/**
@@ -118,6 +119,7 @@ export const criticalUpdatesPending = initialState?.critical_updates_pending;
// @ts-expect-error
export const statusPageUrl = getMeta('status_page_url');
export const sso_redirect = getMeta('sso_redirect');
+export const forceGroupedNotifications = getMeta('force_grouped_notifications');
/**
* @returns {string | undefined}
diff --git a/app/javascript/mastodon/selectors/settings.ts b/app/javascript/mastodon/selectors/settings.ts
index 93276c669..22e7c13b9 100644
--- a/app/javascript/mastodon/selectors/settings.ts
+++ b/app/javascript/mastodon/selectors/settings.ts
@@ -1,3 +1,4 @@
+import { forceGroupedNotifications } from 'mastodon/initial_state';
import type { RootState } from 'mastodon/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;
diff --git a/app/serializers/initial_state_serializer.rb b/app/serializers/initial_state_serializer.rb
index 13f332c95..25a352806 100644
--- a/app/serializers/initial_state_serializer.rb
+++ b/app/serializers/initial_state_serializer.rb
@@ -109,6 +109,7 @@ class InitialStateSerializer < ActiveModel::Serializer
trends_as_landing_page: Setting.trends_as_landing_page,
trends_enabled: Setting.trends,
version: instance_presenter.version,
+ force_grouped_notifications: ENV['FORCE_GROUPED_NOTIFICATIONS'] == 'true',
}
end