From 4c92f581c484771b3b01050e4583f535176e3c7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 4 Mar 2023 12:43:27 +0100 Subject: [PATCH] Allow creating v2 filters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- app/soapbox/actions/filters.ts | 97 +++++++++---- app/soapbox/components/sidebar-menu.tsx | 2 +- .../components/ui/streamfield/streamfield.tsx | 5 +- app/soapbox/features/filters/index.tsx | 127 ++++++++++++++---- .../features/ui/components/link-footer.tsx | 2 +- .../modals/edit-announcement-modal.tsx | 2 +- app/soapbox/features/ui/index.tsx | 2 +- app/soapbox/locales/en.json | 10 +- app/soapbox/normalizers/filter-v1.ts | 24 ---- app/soapbox/normalizers/filter.ts | 12 +- app/soapbox/normalizers/index.ts | 1 - app/soapbox/reducers/filters.ts | 17 ++- app/soapbox/selectors/index.ts | 78 +++++++---- app/soapbox/types/entities.ts | 3 - 14 files changed, 257 insertions(+), 125 deletions(-) delete mode 100644 app/soapbox/normalizers/filter-v1.ts diff --git a/app/soapbox/actions/filters.ts b/app/soapbox/actions/filters.ts index 6d6f82736..c94259e7b 100644 --- a/app/soapbox/actions/filters.ts +++ b/app/soapbox/actions/filters.ts @@ -8,13 +8,9 @@ import api from '../api'; import type { AppDispatch, RootState } from 'soapbox/store'; -const FILTERS_V1_FETCH_REQUEST = 'FILTERS_V1_FETCH_REQUEST'; -const FILTERS_V1_FETCH_SUCCESS = 'FILTERS_V1_FETCH_SUCCESS'; -const FILTERS_V1_FETCH_FAIL = 'FILTERS_V1_FETCH_FAIL'; - -const FILTERS_V2_FETCH_REQUEST = 'FILTERS_V2_FETCH_REQUEST'; -const FILTERS_V2_FETCH_SUCCESS = 'FILTERS_V2_FETCH_SUCCESS'; -const FILTERS_V2_FETCH_FAIL = 'FILTERS_V2_FETCH_FAIL'; +const FILTERS_FETCH_REQUEST = 'FILTERS_FETCH_REQUEST'; +const FILTERS_FETCH_SUCCESS = 'FILTERS_FETCH_SUCCESS'; +const FILTERS_FETCH_FAIL = 'FILTERS_FETCH_FAIL'; const FILTERS_CREATE_REQUEST = 'FILTERS_CREATE_REQUEST'; const FILTERS_CREATE_SUCCESS = 'FILTERS_CREATE_SUCCESS'; @@ -29,22 +25,24 @@ const messages = defineMessages({ removed: { id: 'filters.removed', defaultMessage: 'Filter deleted.' }, }); +type FilterKeywords = { keyword: string, whole_word: boolean }[]; + const fetchFiltersV1 = () => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ - type: FILTERS_V1_FETCH_REQUEST, + type: FILTERS_FETCH_REQUEST, skipLoading: true, }); api(getState) .get('/api/v1/filters') .then(({ data }) => dispatch({ - type: FILTERS_V1_FETCH_SUCCESS, + type: FILTERS_FETCH_SUCCESS, filters: data, skipLoading: true, })) .catch(err => dispatch({ - type: FILTERS_V1_FETCH_FAIL, + type: FILTERS_FETCH_FAIL, err, skipLoading: true, skipAlert: true, @@ -54,26 +52,26 @@ const fetchFiltersV1 = () => const fetchFiltersV2 = () => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ - type: FILTERS_V2_FETCH_REQUEST, + type: FILTERS_FETCH_REQUEST, skipLoading: true, }); api(getState) .get('/api/v2/filters') .then(({ data }) => dispatch({ - type: FILTERS_V2_FETCH_SUCCESS, + type: FILTERS_FETCH_SUCCESS, filters: data, skipLoading: true, })) .catch(err => dispatch({ - type: FILTERS_V2_FETCH_FAIL, + type: FILTERS_FETCH_FAIL, err, skipLoading: true, skipAlert: true, })); }; -const fetchFilters = () => +const fetchFilters = (fromFiltersPage = false) => (dispatch: AppDispatch, getState: () => RootState) => { if (!isLoggedIn(getState)) return; @@ -81,19 +79,19 @@ const fetchFilters = () => const instance = state.instance; const features = getFeatures(instance); - if (features.filtersV2) return dispatch(fetchFiltersV2()); + if (features.filtersV2 && fromFiltersPage) return dispatch(fetchFiltersV2()); if (features.filters) return dispatch(fetchFiltersV1()); }; -const createFilter = (phrase: string, expires_at: string, context: Array, whole_word: boolean, irreversible: boolean) => +const createFilterV1 = (title: string, expires_at: string, context: Array, hide: boolean, keywords: FilterKeywords) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: FILTERS_CREATE_REQUEST }); return api(getState).post('/api/v1/filters', { - phrase, + phrase: keywords[0].keyword, context, - irreversible, - whole_word, + irreversible: hide, + whole_word: keywords[0].whole_word, expires_at, }).then(response => { dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data }); @@ -103,7 +101,35 @@ const createFilter = (phrase: string, expires_at: string, context: Array }); }; -const deleteFilter = (id: string) => +const createFilterV2 = (title: string, expires_at: string, context: Array, hide: boolean, keywords_attributes: FilterKeywords) => + (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: FILTERS_CREATE_REQUEST }); + return api(getState).post('/api/v2/filters', { + title, + context, + filter_action: hide ? 'hide' : 'warn', + expires_at, + keywords_attributes, + }).then(response => { + dispatch({ type: FILTERS_CREATE_SUCCESS, filter: response.data }); + toast.success(messages.added); + }).catch(error => { + dispatch({ type: FILTERS_CREATE_FAIL, error }); + }); + }; + +const createFilter = (title: string, expires_at: string, context: Array, hide: boolean, keywords: FilterKeywords) => + (dispatch: AppDispatch, getState: () => RootState) => { + const state = getState(); + const instance = state.instance; + const features = getFeatures(instance); + + if (features.filtersV2) return dispatch(createFilterV2(title, expires_at, context, hide, keywords)); + + return dispatch(createFilterV1(title, expires_at, context, hide, keywords)); + }; + +const deleteFilterV1 = (id: string) => (dispatch: AppDispatch, getState: () => RootState) => { dispatch({ type: FILTERS_DELETE_REQUEST }); return api(getState).delete(`/api/v1/filters/${id}`).then(response => { @@ -114,13 +140,32 @@ const deleteFilter = (id: string) => }); }; +const deleteFilterV2 = (id: string) => + (dispatch: AppDispatch, getState: () => RootState) => { + dispatch({ type: FILTERS_DELETE_REQUEST }); + return api(getState).delete(`/api/v2/filters/${id}`).then(response => { + dispatch({ type: FILTERS_DELETE_SUCCESS, filter: response.data }); + toast.success(messages.removed); + }).catch(error => { + dispatch({ type: FILTERS_DELETE_FAIL, error }); + }); + }; + +const deleteFilter = (id: string) => + (dispatch: AppDispatch, getState: () => RootState) => { + const state = getState(); + const instance = state.instance; + const features = getFeatures(instance); + + if (features.filtersV2) return dispatch(deleteFilterV2(id)); + + return dispatch(deleteFilterV1(id)); + }; + export { - FILTERS_V1_FETCH_REQUEST, - FILTERS_V1_FETCH_SUCCESS, - FILTERS_V1_FETCH_FAIL, - FILTERS_V2_FETCH_REQUEST, - FILTERS_V2_FETCH_SUCCESS, - FILTERS_V2_FETCH_FAIL, + FILTERS_FETCH_REQUEST, + FILTERS_FETCH_SUCCESS, + FILTERS_FETCH_FAIL, FILTERS_CREATE_REQUEST, FILTERS_CREATE_SUCCESS, FILTERS_CREATE_FAIL, diff --git a/app/soapbox/components/sidebar-menu.tsx b/app/soapbox/components/sidebar-menu.tsx index ffe3a0e98..ffd737dbb 100644 --- a/app/soapbox/components/sidebar-menu.tsx +++ b/app/soapbox/components/sidebar-menu.tsx @@ -296,7 +296,7 @@ const SidebarMenu: React.FC = (): JSX.Element | null => { /> )} - {features.filters && ( + {(features.filters || features.filtersV2) && ( void /** Input to render for each value. */ component: StreamfieldComponent + /** Minimum number of allowed inputs. */ + minItems?: number /** Maximum number of allowed inputs. */ maxItems?: number } @@ -47,6 +49,7 @@ const Streamfield: React.FC = ({ onChange, component: Component, maxItems = Infinity, + minItems = 0, }) => { const intl = useIntl(); @@ -70,7 +73,7 @@ const Streamfield: React.FC = ({ {values.map((value, i) => ( - {onRemoveItem && ( + {values.length > minItems && onRemoveItem && ( = ({ value, onChange }) => { + const intl = useIntl(); + + const handleChange = (key: string): React.ChangeEventHandler => + e => { + // console.log({ ...value, [key]: e.currentTarget[e.currentTarget.type === 'checkbox' ? 'checked' : 'value'] }); + onChange({ ...value, [key]: e.currentTarget[e.currentTarget.type === 'checkbox' ? 'checked' : 'value'] }); + }; + + return ( + + + + + + + + + + + ); +}; + const Filters = () => { const intl = useIntl(); const dispatch = useAppDispatch(); + const features = useFeatures(); const filters = useAppSelector((state) => state.filters); - const [phrase, setPhrase] = useState(''); + const [title, setTitle] = useState(''); const [expiresAt] = useState(''); const [homeTimeline, setHomeTimeline] = useState(true); const [publicTimeline, setPublicTimeline] = useState(false); const [notifications, setNotifications] = useState(false); const [conversations, setConversations] = useState(false); - const [irreversible, setIrreversible] = useState(false); - const [wholeWord, setWholeWord] = useState(true); + const [accounts, setAccounts] = useState(false); + const [hide, setHide] = useState(false); + const [keywords, setKeywords] = useState<{ keyword: string, whole_word: boolean }[]>([{ keyword: '', whole_word: false }]); // const handleSelectChange = e => { // this.setState({ [e.target.name]: e.target.value }); @@ -80,9 +129,12 @@ const Filters = () => { if (conversations) { context.push('thread'); } + if (accounts) { + context.push('account'); + } - dispatch(createFilter(phrase, expiresAt, context, wholeWord, irreversible)).then(() => { - return dispatch(fetchFilters()); + dispatch(createFilter(title, expiresAt, context, hide, keywords)).then(() => { + return dispatch(fetchFilters(true)); }).catch(error => { toast.error(intl.formatMessage(messages.create_error)); }); @@ -90,14 +142,20 @@ const Filters = () => { const handleFilterDelete = (id: string) => () => { dispatch(deleteFilter(id)).then(() => { - return dispatch(fetchFilters()); + return dispatch(fetchFilters(true)); }).catch(() => { toast.error(intl.formatMessage(messages.delete_error)); }); }; + const handleChangeKeyword = (keywords: { keyword: string, whole_word: boolean }[]) => setKeywords(keywords); + + const handleAddKeyword = () => setKeywords(keywords => [...keywords, { keyword: '', whole_word: false }]); + + const handleRemoveKeyword = (i: number) => setKeywords(keywords => keywords.filter((_, index) => index !== i)); + useEffect(() => { - dispatch(fetchFilters()); + dispatch(fetchFilters(true)); }, []); const emptyMessage = ; @@ -108,12 +166,13 @@ const Filters = () => {
- + setPhrase(target.value)} + name='title' + value={title} + onChange={({ target }) => setTitle(target.value)} /> {/* @@ -162,20 +221,29 @@ const Filters = () => { onChange={({ target }) => setConversations(target.checked)} /> + {features.filtersV2 && ( + + setAccounts(target.checked)} + /> + + )} setIrreversible(target.checked)} + name='hide' + checked={hide} + onChange={({ target }) => setHide(target.checked)} /> - @@ -184,9 +252,20 @@ const Filters = () => { checked={wholeWord} onChange={({ target }) => setWholeWord(target.checked)} /> - + */} + + @@ -207,7 +286,7 @@ const Filters = () => { {' '} - {filter.phrase} + {filter.keywords.map(keyword => keyword.keyword).join(', ')} @@ -215,7 +294,7 @@ const Filters = () => { {filter.context.map(context => contexts[context] ? intl.formatMessage(contexts[context]) : context).join(', ')} - + {/* {filter.irreversible ? : } @@ -224,7 +303,7 @@ const Filters = () => { - )} + )} */} { )} - {features.filters && ( + {(features.filters || features.filtersV2) && ( )} {features.federating && ( diff --git a/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx b/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx index 2a7fdf65c..183519817 100644 --- a/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx +++ b/app/soapbox/features/ui/components/modals/edit-announcement-modal.tsx @@ -96,7 +96,7 @@ const EditAnnouncementModal: React.FC = ({ onClose }) => />)} - + = ({ children }) => {features.federating && } - {features.filters && } + {(features.filters || features.filtersV2) && } diff --git a/app/soapbox/locales/en.json b/app/soapbox/locales/en.json index dc55b1f83..944bca267 100644 --- a/app/soapbox/locales/en.json +++ b/app/soapbox/locales/en.json @@ -321,6 +321,7 @@ "column.favourites": "Likes", "column.federation_restrictions": "Federation Restrictions", "column.filters": "Muted words", + "column.filters.accounts": "Accounts", "column.filters.add_new": "Add New Filter", "column.filters.conversations": "Conversations", "column.filters.create_error": "Error adding filter", @@ -330,12 +331,17 @@ "column.filters.drop_hint": "Filtered posts will disappear irreversibly, even if filter is later removed", "column.filters.expires": "Expire after", "column.filters.expires_hint": "Expiration dates are not currently supported", + "column.filters.hide_header": "Hide completely", + "column.filters.hide_hint": "Completely hide the filtered content, instead of showing a warning", "column.filters.home_timeline": "Home timeline", "column.filters.keyword": "Keyword or phrase", + "column.filters.keywords": "Keywords or phrases", "column.filters.notifications": "Notifications", "column.filters.public_timeline": "Public timeline", "column.filters.subheading_add_new": "Add New Filter", "column.filters.subheading_filters": "Current Filters", + "column.filters.title": "Title", + "column.filters.whole_word": "Whole word", "column.filters.whole_word_header": "Whole word", "column.filters.whole_word_hint": "When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word", "column.follow_requests": "Follow requests", @@ -731,10 +737,7 @@ "filters.context_header": "Filter contexts", "filters.context_hint": "One or multiple contexts where the filter should apply", "filters.filters_list_context_label": "Filter contexts:", - "filters.filters_list_drop": "Drop", - "filters.filters_list_hide": "Hide", "filters.filters_list_phrase_label": "Keyword or phrase:", - "filters.filters_list_whole-word": "Whole word", "filters.removed": "Filter deleted.", "followRecommendations.heading": "Suggested Profiles", "follow_request.authorize": "Authorize", @@ -1384,6 +1387,7 @@ "status.sensitive_warning": "Sensitive content", "status.sensitive_warning.subtitle": "This content may not be suitable for all audiences.", "status.share": "Share", + "status.show_filter_reason": "Show anyway", "status.show_less_all": "Show less for all", "status.show_more_all": "Show more for all", "status.show_original": "Show original", diff --git a/app/soapbox/normalizers/filter-v1.ts b/app/soapbox/normalizers/filter-v1.ts deleted file mode 100644 index ef454db1e..000000000 --- a/app/soapbox/normalizers/filter-v1.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Filter normalizer: - * Converts API filters into our internal format. - * @see {@link https://docs.joinmastodon.org/entities/V1_Filter/} - */ -import { List as ImmutableList, Map as ImmutableMap, Record as ImmutableRecord, fromJS } from 'immutable'; - -import type { ContextType } from './filter'; - -// https://docs.joinmastodon.org/entities/V1_Filter/ -export const FilterV1Record = ImmutableRecord({ - id: '', - phrase: '', - context: ImmutableList(), - whole_word: false, - expires_at: '', - irreversible: false, -}); - -export const normalizeFilterV1 = (filter: Record) => { - return FilterV1Record( - ImmutableMap(fromJS(filter)), - ); -}; diff --git a/app/soapbox/normalizers/filter.ts b/app/soapbox/normalizers/filter.ts index 24329945b..d3eaab237 100644 --- a/app/soapbox/normalizers/filter.ts +++ b/app/soapbox/normalizers/filter.ts @@ -10,7 +10,7 @@ import { FilterKeyword, FilterStatus } from 'soapbox/types/entities'; import { normalizeFilterKeyword } from './filter-keyword'; import { normalizeFilterStatus } from './filter-status'; -export type ContextType = 'home' | 'public' | 'notifications' | 'thread'; +export type ContextType = 'home' | 'public' | 'notifications' | 'thread' | 'account'; export type FilterActionType = 'warn' | 'hide'; // https://docs.joinmastodon.org/entities/filter/ @@ -24,6 +24,15 @@ export const FilterRecord = ImmutableRecord({ statuses: ImmutableList(), }); +const normalizeFilterV1 = (filter: ImmutableMap) => + filter + .set('title', filter.get('phrase')) + .set('keywords', ImmutableList([ImmutableMap({ + keyword: filter.get('phrase'), + whole_word: filter.get('whole_word'), + })])) + .set('filter_action', filter.get('irreversible') ? 'hide' : 'warn'); + const normalizeKeywords = (filter: ImmutableMap) => filter.update('keywords', ImmutableList(), keywords => keywords.map(normalizeFilterKeyword), @@ -37,6 +46,7 @@ const normalizeStatuses = (filter: ImmutableMap) => export const normalizeFilter = (filter: Record) => FilterRecord( ImmutableMap(fromJS(filter)).withMutations(filter => { + if (filter.has('phrase')) normalizeFilterV1(filter); normalizeKeywords(filter); normalizeStatuses(filter); }), diff --git a/app/soapbox/normalizers/index.ts b/app/soapbox/normalizers/index.ts index b0dd89088..66daaae27 100644 --- a/app/soapbox/normalizers/index.ts +++ b/app/soapbox/normalizers/index.ts @@ -12,7 +12,6 @@ export { EmojiReactionRecord } from './emoji-reaction'; export { FilterRecord, normalizeFilter } from './filter'; export { FilterKeywordRecord, normalizeFilterKeyword } from './filter-keyword'; export { FilterStatusRecord, normalizeFilterStatus } from './filter-status'; -export { FilterV1Record, normalizeFilterV1 } from './filter-v1'; export { GroupRecord, normalizeGroup } from './group'; export { GroupRelationshipRecord, normalizeGroupRelationship } from './group-relationship'; export { HistoryRecord, normalizeHistory } from './history'; diff --git a/app/soapbox/reducers/filters.ts b/app/soapbox/reducers/filters.ts index 9aaff191c..8520b57a4 100644 --- a/app/soapbox/reducers/filters.ts +++ b/app/soapbox/reducers/filters.ts @@ -1,22 +1,21 @@ import { List as ImmutableList } from 'immutable'; -import { normalizeFilterV1 } from 'soapbox/normalizers'; +import { normalizeFilter } from 'soapbox/normalizers'; -import { FILTERS_V1_FETCH_SUCCESS } from '../actions/filters'; +import { FILTERS_FETCH_SUCCESS } from '../actions/filters'; import type { AnyAction } from 'redux'; -import type { APIEntity, FilterV1 as FilterV1Entity } from 'soapbox/types/entities'; +import type { APIEntity, Filter as FilterEntity } from 'soapbox/types/entities'; -type State = ImmutableList; +type State = ImmutableList; -const importFiltersV1 = (_state: State, filters: APIEntity[]): State => { - return ImmutableList(filters.map((filter) => normalizeFilterV1(filter))); -}; +const importFilters = (_state: State, filters: APIEntity[]): State => + ImmutableList(filters.map((filter) => normalizeFilter(filter))); export default function filters(state: State = ImmutableList(), action: AnyAction): State { switch (action.type) { - case FILTERS_V1_FETCH_SUCCESS: - return importFiltersV1(state, action.filters); + case FILTERS_FETCH_SUCCESS: + return importFilters(state, action.filters); default: return state; } diff --git a/app/soapbox/selectors/index.ts b/app/soapbox/selectors/index.ts index ec5da2d82..12cb4df08 100644 --- a/app/soapbox/selectors/index.ts +++ b/app/soapbox/selectors/index.ts @@ -16,7 +16,7 @@ import { shouldFilter } from 'soapbox/utils/timelines'; import type { ContextType } from 'soapbox/normalizers/filter'; import type { ReducerChat } from 'soapbox/reducers/chats'; import type { RootState } from 'soapbox/store'; -import type { FilterV1 as FilterV1Entity, Notification } from 'soapbox/types/entities'; +import type { Filter as FilterEntity, Notification } from 'soapbox/types/entities'; const normalizeId = (id: any): string => typeof id === 'string' ? id : ''; @@ -115,45 +115,65 @@ export const getFilters = (state: RootState, query: FilterContext) => { const escapeRegExp = (string: string) => string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string -export const regexFromFilters = (filters: ImmutableList) => { +export const regexFromFilters = (filters: ImmutableList) => { if (filters.size === 0) return null; - return new RegExp(filters.map(filter => { - let expr = escapeRegExp(filter.phrase); + return new RegExp(filters.map(filter => + filter.keywords.map(keyword => { + let expr = escapeRegExp(keyword.keyword); - if (filter.whole_word) { - if (/^[\w]/.test(expr)) { - expr = `\\b${expr}`; + if (keyword.whole_word) { + if (/^[\w]/.test(expr)) { + expr = `\\b${expr}`; + } + + if (/[\w]$/.test(expr)) { + expr = `${expr}\\b`; + } } - if (/[\w]$/.test(expr)) { - expr = `${expr}\\b`; - } - } - - return expr; - }).join('|'), 'i'); + return expr; + }).join('|'), + ).join('|'), 'i'); }; -const checkFiltered = (index: string, filters: ImmutableList) => - filters.reduce((result, filter) => { - let expr = escapeRegExp(filter.phrase); +const checkFiltered = (index: string, filters: ImmutableList) => + filters.reduce((result, filter) => + result.concat(filter.keywords.reduce((result, keyword) => { + let expr = escapeRegExp(keyword.keyword); - if (filter.whole_word) { - if (/^[\w]/.test(expr)) { - expr = `\\b${expr}`; + if (keyword.whole_word) { + if (/^[\w]/.test(expr)) { + expr = `\\b${expr}`; + } + + if (/[\w]$/.test(expr)) { + expr = `${expr}\\b`; + } } - if (/[\w]$/.test(expr)) { - expr = `${expr}\\b`; - } - } + const regex = new RegExp(expr); - const regex = new RegExp(expr); + if (regex.test(index)) return result.concat(filter.title); + return result; + }, ImmutableList())), ImmutableList()); +// const results = +// let expr = escapeRegExp(filter.phrase); - if (regex.test(index)) return result.push(filter.phrase); - return result; - }, ImmutableList()); +// if (filter.whole_word) { +// if (/^[\w]/.test(expr)) { +// expr = `\\b${expr}`; +// } + +// if (/[\w]$/.test(expr)) { +// expr = `${expr}\\b`; +// } +// } + +// const regex = new RegExp(expr); + +// if (regex.test(index)) return result.join(filter.phrase); +// return result; type APIStatus = { id: string, username?: string }; @@ -194,7 +214,7 @@ export const makeGetStatus = () => { // @ts-ignore map.set('group', group || null); - if (features.filters && (accountReblog || accountBase).id !== me) { + if ((features.filters || features.filtersV2) && (accountReblog || accountBase).id !== me) { const filtered = checkFiltered(statusReblog?.search_index || statusBase.search_index, filters); map.set('filtered', filtered); diff --git a/app/soapbox/types/entities.ts b/app/soapbox/types/entities.ts index 30c94684e..bf717e805 100644 --- a/app/soapbox/types/entities.ts +++ b/app/soapbox/types/entities.ts @@ -14,7 +14,6 @@ import { FilterRecord, FilterKeywordRecord, FilterStatusRecord, - FilterV1Record, GroupRecord, GroupRelationshipRecord, HistoryRecord, @@ -49,7 +48,6 @@ type Field = ReturnType; type Filter = ReturnType; type FilterKeyword = ReturnType; type FilterStatus = ReturnType; -type FilterV1 = ReturnType; type Group = ReturnType; type GroupRelationship = ReturnType; type History = ReturnType; @@ -97,7 +95,6 @@ export { Filter, FilterKeyword, FilterStatus, - FilterV1, Group, GroupRelationship, History,