From 7b405ef1d038c6413758028b93d0d3b0c32a4ac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sun, 10 Nov 2024 00:22:03 +0100 Subject: [PATCH] pl-fe: migrations off immutable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- packages/pl-fe/src/actions/lists.ts | 4 +- .../actions/push-notifications/registerer.ts | 4 +- .../pl-fe/src/components/sidebar-menu.tsx | 2 +- .../src/components/sidebar-navigation.tsx | 2 +- .../compose/components/privacy-dropdown.tsx | 4 +- .../src/features/list-timeline/index.tsx | 2 +- packages/pl-fe/src/features/lists/index.tsx | 4 +- .../components/scheduled-status.tsx | 2 +- .../list-adder-modal/components/list.tsx | 2 +- .../modals/list-adder-modal/index.tsx | 2 +- packages/pl-fe/src/reducers/filters.ts | 10 ++-- packages/pl-fe/src/reducers/instance.ts | 7 ++- packages/pl-fe/src/reducers/lists.ts | 28 ++++++----- .../pl-fe/src/reducers/push-notifications.ts | 48 +++++++++++-------- .../pl-fe/src/reducers/scheduled-statuses.ts | 23 +++++---- packages/pl-fe/src/selectors/index.ts | 11 ++--- 16 files changed, 81 insertions(+), 74 deletions(-) diff --git a/packages/pl-fe/src/actions/lists.ts b/packages/pl-fe/src/actions/lists.ts index 5c8625730..40c2e19a0 100644 --- a/packages/pl-fe/src/actions/lists.ts +++ b/packages/pl-fe/src/actions/lists.ts @@ -59,7 +59,7 @@ const LIST_ADDER_LISTS_FETCH_FAIL = 'LIST_ADDER_LISTS_FETCH_FAIL' as const; const fetchList = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; - if (getState().lists.get(listId)) { + if (getState().lists[listId]) { return; } @@ -124,7 +124,7 @@ const submitListEditor = (shouldReset?: boolean) => (dispatch: AppDispatch, getS const setupListEditor = (listId: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: LIST_EDITOR_SETUP, - list: getState().lists.get(String(listId)), + list: getState().lists[listId], }); dispatch(fetchListAccounts(listId)); diff --git a/packages/pl-fe/src/actions/push-notifications/registerer.ts b/packages/pl-fe/src/actions/push-notifications/registerer.ts index fa61047f6..ac19530a3 100644 --- a/packages/pl-fe/src/actions/push-notifications/registerer.ts +++ b/packages/pl-fe/src/actions/push-notifications/registerer.ts @@ -44,7 +44,7 @@ const unsubscribe = ({ registration, subscription }: { const sendSubscriptionToBackend = (subscription: PushSubscription, me: Me) => (dispatch: AppDispatch, getState: () => RootState) => { - const alerts = getState().push_notifications.alerts.toJS() as Record; + const alerts = getState().push_notifications.alerts; const params = { subscription, data: { alerts } }; if (me) { @@ -138,7 +138,7 @@ const register = () => const saveSettings = () => (dispatch: AppDispatch, getState: () => RootState) => { const state = getState().push_notifications; - const alerts = state.alerts.toJS(); + const alerts = state.alerts; const data = { alerts }; const me = getState().me; diff --git a/packages/pl-fe/src/components/sidebar-menu.tsx b/packages/pl-fe/src/components/sidebar-menu.tsx index 2ea086a02..928b57377 100644 --- a/packages/pl-fe/src/components/sidebar-menu.tsx +++ b/packages/pl-fe/src/components/sidebar-menu.tsx @@ -98,7 +98,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { const { settings } = useSettingsStore(); const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.length); const interactionRequestsCount = useInteractionRequestsCount().data || 0; - const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size); + const scheduledStatusCount = useAppSelector((state) => Object.keys(state.scheduled_statuses).length); const draftCount = useAppSelector((state) => Object.keys(state.draft_statuses).length); // const dashboardCount = useAppSelector((state) => state.admin.openReports.count() + state.admin.awaitingApproval.count()); const [sidebarVisible, setSidebarVisible] = useState(isSidebarOpen); diff --git a/packages/pl-fe/src/components/sidebar-navigation.tsx b/packages/pl-fe/src/components/sidebar-navigation.tsx index 33f4748ff..e24dfecb1 100644 --- a/packages/pl-fe/src/components/sidebar-navigation.tsx +++ b/packages/pl-fe/src/components/sidebar-navigation.tsx @@ -51,7 +51,7 @@ const SidebarNavigation = () => { const followRequestsCount = useAppSelector((state) => state.user_lists.follow_requests.items.length); const interactionRequestsCount = useInteractionRequestsCount().data || 0; const dashboardCount = useAppSelector((state) => state.admin.openReports.length + state.admin.awaitingApproval.length); - const scheduledStatusCount = useAppSelector((state) => state.scheduled_statuses.size); + const scheduledStatusCount = useAppSelector((state) => Object.keys(state.scheduled_statuses).length); const draftCount = useAppSelector((state) => Object.keys(state.draft_statuses).length); const restrictUnauth = instance.pleroma.metadata.restrict_unauthenticated; diff --git a/packages/pl-fe/src/features/compose/components/privacy-dropdown.tsx b/packages/pl-fe/src/features/compose/components/privacy-dropdown.tsx index 7504de03d..535388782 100644 --- a/packages/pl-fe/src/features/compose/components/privacy-dropdown.tsx +++ b/packages/pl-fe/src/features/compose/components/privacy-dropdown.tsx @@ -78,10 +78,10 @@ const getItems = (features: Features, lists: ReturnType, text: intl.formatMessage(messages.local_short), meta: intl.formatMessage(messages.local_long), } : undefined, - features.addressableLists && !lists.isEmpty() ? { + features.addressableLists && Object.keys(lists).length ? { icon: require('@tabler/icons/outline/list.svg'), value: '', - items: lists.toArray().map((list) => ({ + items: Object.values(lists).map((list) => ({ icon: require('@tabler/icons/outline/list.svg'), value: `list:${list.id}`, text: list.title, diff --git a/packages/pl-fe/src/features/list-timeline/index.tsx b/packages/pl-fe/src/features/list-timeline/index.tsx index 0b689d5fd..cb0a7a861 100644 --- a/packages/pl-fe/src/features/list-timeline/index.tsx +++ b/packages/pl-fe/src/features/list-timeline/index.tsx @@ -34,7 +34,7 @@ const ListTimeline: React.FC = () => { const isMobile = useIsMobile(); const { openModal } = useModalsStore(); - const list = useAppSelector((state) => state.lists.get(id)); + const list = useAppSelector((state) => state.lists[id]); useListStream(id); diff --git a/packages/pl-fe/src/features/lists/index.tsx b/packages/pl-fe/src/features/lists/index.tsx index 77e100f33..5bd42ab81 100644 --- a/packages/pl-fe/src/features/lists/index.tsx +++ b/packages/pl-fe/src/features/lists/index.tsx @@ -28,7 +28,7 @@ const getOrderedLists = createSelector([(state: RootState) => state.lists], list return lists; } - return lists.toList().filter((item): item is ListEntity => !!item).sort((a, b) => a.title.localeCompare(b.title)); + return Object.values(lists).filter((item): item is ListEntity => !!item).sort((a, b) => a.title.localeCompare(b.title)); }); const Lists: React.FC = () => { @@ -56,7 +56,7 @@ const Lists: React.FC = () => { - {lists.isEmpty() ? ( + {!Object.keys(lists).length ? ( {emptyMessage} diff --git a/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status.tsx b/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status.tsx index df705d84e..e0451620a 100644 --- a/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status.tsx +++ b/packages/pl-fe/src/features/scheduled-statuses/components/scheduled-status.tsx @@ -20,7 +20,7 @@ interface IScheduledStatus { const ScheduledStatus: React.FC = ({ statusId, ...other }) => { const status = useAppSelector((state) => { - const scheduledStatus = state.scheduled_statuses.get(statusId); + const scheduledStatus = state.scheduled_statuses[statusId]; if (!scheduledStatus) return null; return buildStatus(state, scheduledStatus); }); diff --git a/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/components/list.tsx b/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/components/list.tsx index a16ea838b..f3ad68cca 100644 --- a/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/components/list.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/components/list.tsx @@ -20,7 +20,7 @@ const List: React.FC = ({ listId }) => { const intl = useIntl(); const dispatch = useAppDispatch(); - const list = useAppSelector((state) => state.lists.get(listId)); + const list = useAppSelector((state) => state.lists[listId]); const added = useAppSelector((state) => state.listAdder.lists.items.includes(listId)); const onRemove = () => dispatch(removeFromListAdder(listId)); diff --git a/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/index.tsx b/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/index.tsx index 1e37e07d3..0e473e25f 100644 --- a/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/index.tsx +++ b/packages/pl-fe/src/features/ui/components/modals/list-adder-modal/index.tsx @@ -61,7 +61,7 @@ const ListAdderModal: React.FC = ({ accoun
- {listIds.map(ListId => )} + {listIds.map(listId => )}
); diff --git a/packages/pl-fe/src/reducers/filters.ts b/packages/pl-fe/src/reducers/filters.ts index 629a56cf8..11fbdc5be 100644 --- a/packages/pl-fe/src/reducers/filters.ts +++ b/packages/pl-fe/src/reducers/filters.ts @@ -1,18 +1,14 @@ -import { List as ImmutableList } from 'immutable'; - import { FILTERS_FETCH_SUCCESS } from '../actions/filters'; import type { Filter } from 'pl-api'; import type { AnyAction } from 'redux'; -type State = ImmutableList; +type State = Array; -const importFilters = (_state: State, filters: Array): State => ImmutableList(filters); - -const filters = (state: State = ImmutableList(), action: AnyAction): State => { +const filters = (state: State = [], action: AnyAction): State => { switch (action.type) { case FILTERS_FETCH_SUCCESS: - return importFilters(state, action.filters); + return action.filters; default: return state; } diff --git a/packages/pl-fe/src/reducers/instance.ts b/packages/pl-fe/src/reducers/instance.ts index 8dfd42ebd..f23b44462 100644 --- a/packages/pl-fe/src/reducers/instance.ts +++ b/packages/pl-fe/src/reducers/instance.ts @@ -1,4 +1,3 @@ -import { Map as ImmutableMap } from 'immutable'; import { create } from 'mutative'; import { type Instance, instanceSchema, PleromaConfig } from 'pl-api'; import * as v from 'valibot'; @@ -20,11 +19,11 @@ const preloadImport = (state: State, action: Record, path: string) return instance ? v.parse(instanceSchema, instance) : state; }; -const getConfigValue = (instanceConfig: ImmutableMap, key: string) => { +const getConfigValue = (instanceConfig: Array, key: string) => { const v = instanceConfig - .find(value => value.getIn(['tuple', 0]) === key); + .find(value => value?.tuple?.[0] === key); - return v ? v.getIn(['tuple', 1]) : undefined; + return v ? v?.tuple?.[1] : undefined; }; const importConfigs = (state: State, configs: PleromaConfig['configs']) => { diff --git a/packages/pl-fe/src/reducers/lists.ts b/packages/pl-fe/src/reducers/lists.ts index 2aca2f5d8..87c89646f 100644 --- a/packages/pl-fe/src/reducers/lists.ts +++ b/packages/pl-fe/src/reducers/lists.ts @@ -1,4 +1,4 @@ -import { Map as ImmutableMap } from 'immutable'; +import { create } from 'mutative'; import { LIST_FETCH_SUCCESS, @@ -12,18 +12,16 @@ import { import type { List } from 'pl-api'; import type { AnyAction } from 'redux'; -type State = ImmutableMap; +type State = Record; -const initialState: State = ImmutableMap(); +const initialState: State = {}; -const importList = (state: State, list: List) => state.set(list.id, list); +const importList = (state: State, list: List) => { + state[list.id] = list; +}; const importLists = (state: State, lists: Array) => { - lists.forEach(list => { - state = importList(state, list); - }); - - return state; + lists.forEach(list => importList(state, list)); }; const lists = (state: State = initialState, action: AnyAction) => { @@ -31,12 +29,18 @@ const lists = (state: State = initialState, action: AnyAction) => { case LIST_FETCH_SUCCESS: case LIST_CREATE_SUCCESS: case LIST_UPDATE_SUCCESS: - return importList(state, action.list); + return create(state, (draft) => { + importList(draft, action.list); + }); case LISTS_FETCH_SUCCESS: - return importLists(state, action.lists); + return create(state, (draft) => { + importLists(draft, action.lists); + }); case LIST_DELETE_SUCCESS: case LIST_FETCH_FAIL: - return state.set(action.listId, false); + return create(state, (draft) => { + draft[action.listId] = false; + }); default: return state; } diff --git a/packages/pl-fe/src/reducers/push-notifications.ts b/packages/pl-fe/src/reducers/push-notifications.ts index 0a05b476f..a28a7df08 100644 --- a/packages/pl-fe/src/reducers/push-notifications.ts +++ b/packages/pl-fe/src/reducers/push-notifications.ts @@ -1,44 +1,52 @@ -import { Map as ImmutableMap, Record as ImmutableRecord } from 'immutable'; +import { create } from 'mutative'; import { SET_BROWSER_SUPPORT, SET_SUBSCRIPTION, CLEAR_SUBSCRIPTION } from '../actions/push-notifications'; import type { SetterAction } from 'pl-fe/actions/push-notifications/setter'; -const SubscriptionRecord = ImmutableRecord({ - id: '', - endpoint: '', -}); +interface Subscription { + id: string; + endpoint: string; +} -const ReducerRecord = ImmutableRecord({ - subscription: null as Subscription | null, - alerts: ImmutableMap({ +interface State { + subscription: Subscription | null; + alerts: Record; + isSubscribed: boolean; + browserSupport: boolean; +} + +const initialState: State = { + subscription: null, + alerts: { follow: true, follow_request: true, favourite: true, reblog: true, mention: true, poll: true, - }), + }, isSubscribed: false, browserSupport: false, -}); +}; -type Subscription = ReturnType; - -const push_subscriptions = (state = ReducerRecord(), action: SetterAction) => { +const push_subscriptions = (state = initialState, action: SetterAction): State => { switch (action.type) { case SET_SUBSCRIPTION: - return state - .set('subscription', SubscriptionRecord({ + return create(state, (draft) => { + draft.subscription = { id: action.subscription.id, endpoint: action.subscription.endpoint, - })) - .set('alerts', ImmutableMap(action.subscription.alerts)) - .set('isSubscribed', true); + }; + draft.alerts = action.subscription.alerts; + draft.isSubscribed = true; + }); case SET_BROWSER_SUPPORT: - return state.set('browserSupport', action.value); + return create(state, (draft) => { + draft.browserSupport = action.value; + }); case CLEAR_SUBSCRIPTION: - return ReducerRecord(); + return initialState; default: return state; } diff --git a/packages/pl-fe/src/reducers/scheduled-statuses.ts b/packages/pl-fe/src/reducers/scheduled-statuses.ts index a61f5085f..0d7424bab 100644 --- a/packages/pl-fe/src/reducers/scheduled-statuses.ts +++ b/packages/pl-fe/src/reducers/scheduled-statuses.ts @@ -1,4 +1,4 @@ -import { Map as ImmutableMap } from 'immutable'; +import { create } from 'mutative'; import { STATUS_IMPORT, STATUSES_IMPORT, type ImporterAction } from 'pl-fe/actions/importer'; import { @@ -11,31 +11,34 @@ import { STATUS_CREATE_SUCCESS } from 'pl-fe/actions/statuses'; import type { Status, ScheduledStatus } from 'pl-api'; import type { AnyAction } from 'redux'; -type State = ImmutableMap; +type State = Record; -const initialState: State = ImmutableMap(); +const initialState: State = {}; const importStatus = (state: State, status: Status | ScheduledStatus) => { if (!status.scheduled_at) return state; - return state.set(status.id, status); + state[status.id] = status; }; -const importStatuses = (state: State, statuses: Array) => - state.withMutations(mutable => statuses.forEach(status => importStatus(mutable, status))); +const importStatuses = (state: State, statuses: Array) => { + statuses.forEach(status => importStatus(state, status)); +}; -const deleteStatus = (state: State, statusId: string) => state.delete(statusId); +const deleteStatus = (state: State, statusId: string) => { + delete state[statusId]; +}; const scheduled_statuses = (state: State = initialState, action: AnyAction | ImporterAction) => { switch (action.type) { case STATUS_IMPORT: case STATUS_CREATE_SUCCESS: - return importStatus(state, action.status); + return create(state, (draft) => importStatus(draft, action.status)); case STATUSES_IMPORT: case SCHEDULED_STATUSES_FETCH_SUCCESS: - return importStatuses(state, action.statuses); + return create(state, (draft) => importStatuses(draft, action.statuses)); case SCHEDULED_STATUS_CANCEL_REQUEST: case SCHEDULED_STATUS_CANCEL_SUCCESS: - return deleteStatus(state, action.statusId); + return create(state, (draft) => deleteStatus(draft, action.statusId)); default: return state; } diff --git a/packages/pl-fe/src/selectors/index.ts b/packages/pl-fe/src/selectors/index.ts index cdbce3e65..f9a6a13a6 100644 --- a/packages/pl-fe/src/selectors/index.ts +++ b/packages/pl-fe/src/selectors/index.ts @@ -1,7 +1,4 @@ -import { - List as ImmutableList, - OrderedSet as ImmutableOrderedSet, -} from 'immutable'; +import { OrderedSet as ImmutableOrderedSet } from 'immutable'; import { createSelector } from 'reselect'; // import { getLocale } from 'pl-fe/actions/settings'; @@ -80,8 +77,8 @@ const getFilters = (state: RootState, query: FilterContext) => const escapeRegExp = (string: string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -const regexFromFilters = (filters: ImmutableList) => { - if (filters.size === 0) return null; +const regexFromFilters = (filters: Array) => { + if (filters.length === 0) return null; return new RegExp(filters.map(filter => filter.keywords.map(keyword => { @@ -102,7 +99,7 @@ const regexFromFilters = (filters: ImmutableList) => { ).join('|'), 'i'); }; -const checkFiltered = (index: string, filters: ImmutableList) => +const checkFiltered = (index: string, filters: Array) => filters.reduce((result: Array, filter) => result.concat(filter.keywords.reduce((result: Array, keyword) => { let expr = escapeRegExp(keyword.keyword);