nicolium: allow managing antenna accounts

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2026-02-21 22:01:28 +01:00
parent acf45b2be9
commit 2fe0f157d1
2 changed files with 144 additions and 2 deletions

View File

@ -259,6 +259,10 @@
"alt_text_modal.header": "Add alt text",
"alt_text_modal.saving_failed": "Failed to save alt text",
"announcements.title": "Announcements",
"antennas.account.add": "Add to antenna",
"antennas.account.excluded.add": "Add to excluded accounts",
"antennas.account.excluded.remove": "Remove from excluded accounts",
"antennas.account.remove": "Remove from antenna",
"antennas.create": "Create antenna",
"antennas.create.error": "Error creating antenna",
"antennas.create.save": "Create antenna",
@ -284,6 +288,7 @@
"antennas.edit.with_media_only": "Media only",
"antennas.edit.with_media_only.hint": "Only include posts with media attachments",
"antennas.manage_accounts": "Manage antenna accounts",
"antennas.manage_excluded_accounts": "Manage excluded accounts",
"antennas.new.create": "Add antenna",
"antennas.subheading": "Your antennas",
"app_create.name_label": "App name",
@ -914,6 +919,8 @@
"empty_column.aliases": "You haven't created any account alias yet.",
"empty_column.aliases.suggestions": "There are no account suggestions available for the provided term.",
"empty_column.antenna": "There is nothing in this antenna yet. When posts matching the criteria will be created, they will appear here.",
"empty_column.antenna_accounts": "There are no accounts in this antenna. Use search to find users to add.",
"empty_column.antenna_excluded_accounts": "There are no excluded accounts in this antenna. Use search to find users to exclude.",
"empty_column.antennas": "You don't have any antennas yet. When you create one, it will show up here.",
"empty_column.blocks": "You haven't blocked any users yet.",
"empty_column.bookmarks": "You don't have any bookmarks yet. When you add one, it will show up here.",

View File

@ -3,18 +3,35 @@ import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import List, { ListItem } from '@/components/list';
import Button from '@/components/ui/button';
import { CardHeader, CardTitle } from '@/components/ui/card';
import Form from '@/components/ui/form';
import FormActions from '@/components/ui/form-actions';
import FormGroup from '@/components/ui/form-group';
import Input from '@/components/ui/input';
import Modal from '@/components/ui/modal';
import Spinner from '@/components/ui/spinner';
import Stack from '@/components/ui/stack';
import Text from '@/components/ui/text';
import Toggle from '@/components/ui/toggle';
import { SelectDropdown } from '@/features/forms';
import { useAntenna, useCreateAntenna, useUpdateAntenna } from '@/queries/accounts/use-antennas';
import {
useAddAccountsToAntenna,
useAddExcludedAccountsToAntenna,
useAntenna,
useAntennaAccounts,
useAntennaExcludedAccounts,
useCreateAntenna,
useRemoveAccountsFromAntenna,
useRemoveExcludedAccountsFromAntenna,
useUpdateAntenna,
} from '@/queries/accounts/use-antennas';
import { useAccountSearch } from '@/queries/search/use-search-accounts';
import { useModalsActions } from '@/stores/modals';
import toast from '@/toast';
import Account from './list-editor-modal/components/account';
import Search from './list-editor-modal/components/search';
import type { BaseModalProps } from '@/features/ui/components/modal-root';
type Tab = 'info' | 'accounts' | 'excludedAccounts';
@ -24,6 +41,16 @@ const messages = defineMessages({
editSuccess: { id: 'antennas.edit.success', defaultMessage: 'Antenna updated successfully' },
createError: { id: 'antennas.create.error', defaultMessage: 'Error creating antenna' },
editError: { id: 'antennas.edit.error', defaultMessage: 'Error updating antenna' },
addToAntenna: { id: 'antennas.account.add', defaultMessage: 'Add to antenna' },
removeFromAntenna: { id: 'antennas.account.remove', defaultMessage: 'Remove from antenna' },
addExcludedToAntenna: {
id: 'antennas.account.excluded.add',
defaultMessage: 'Add to excluded accounts',
},
removeExcludedFromAntenna: {
id: 'antennas.account.excluded.remove',
defaultMessage: 'Remove from excluded accounts',
},
});
interface IAntennaAccountsForm {
@ -31,7 +58,104 @@ interface IAntennaAccountsForm {
excluded?: boolean;
}
const AntennaAccountsForm: React.FC<IAntennaAccountsForm> = () => null;
const AntennaAccountsForm: React.FC<IAntennaAccountsForm> = ({ antennaId, excluded = false }) => {
const intl = useIntl();
const [searchValue, setSearchValue] = useState('');
const { data: accountIds = [] } = useAntennaAccounts(antennaId);
const { data: excludedAccountIds = [] } = useAntennaExcludedAccounts(antennaId);
const { data: searchAccountIds = [] } = useAccountSearch(searchValue, {
following: true,
limit: 5,
});
const { mutate: addToAntenna } = useAddAccountsToAntenna(antennaId);
const { mutate: removeFromAntenna } = useRemoveAccountsFromAntenna(antennaId);
const { mutate: addToExcludedAntenna } = useAddExcludedAccountsToAntenna(antennaId);
const { mutate: removeFromExcludedAntenna } = useRemoveExcludedAccountsFromAntenna(antennaId);
const selectedAccountIds = excluded ? excludedAccountIds : accountIds;
const onAdd = (accountId: string) => {
if (excluded) {
addToExcludedAntenna([accountId]);
} else {
addToAntenna([accountId]);
}
};
const onRemove = (accountId: string) => {
if (excluded) {
removeFromExcludedAntenna([accountId]);
} else {
removeFromAntenna([accountId]);
}
};
return (
<Stack space={2}>
{selectedAccountIds.length > 0 ? (
<div>
<CardHeader>
<CardTitle
title={intl.formatMessage(
excluded ? messages.removeExcludedFromAntenna : messages.removeFromAntenna,
)}
/>
</CardHeader>
<div className='max-h-48 overflow-y-auto'>
{selectedAccountIds.map((accountId) => (
<Account
key={accountId}
accountId={accountId}
added={selectedAccountIds.includes(accountId)}
onAdd={onAdd}
onRemove={onRemove}
/>
))}
</div>
</div>
) : (
<Text theme='muted' size='sm'>
{excluded ? (
<FormattedMessage
id='empty_column.antenna_excluded_accounts'
defaultMessage='There are no excluded accounts in this antenna. Use search to find users to exclude.'
/>
) : (
<FormattedMessage
id='empty_column.antenna_accounts'
defaultMessage='There are no accounts in this antenna. Use search to find users to add.'
/>
)}
</Text>
)}
<div>
<CardHeader>
<CardTitle
title={intl.formatMessage(
excluded ? messages.addExcludedToAntenna : messages.addToAntenna,
)}
/>
</CardHeader>
<Search value={searchValue} onSubmit={setSearchValue} />
<div className='max-h-48 overflow-y-auto'>
{searchAccountIds.map((accountId) => (
<Account
key={accountId}
accountId={accountId}
added={selectedAccountIds.includes(accountId)}
onAdd={onAdd}
onRemove={onRemove}
/>
))}
</div>
</div>
</Stack>
);
};
interface IEditAntennaForm {
antennaId?: string;
@ -208,6 +332,17 @@ const EditAntennaForm: React.FC<IEditAntennaForm> = ({ antennaId, onTabChange })
onTabChange('accounts');
}}
/>
<ListItem
label={
<FormattedMessage
id='antennas.manage_excluded_accounts'
defaultMessage='Manage excluded accounts'
/>
}
onClick={() => {
onTabChange('excludedAccounts');
}}
/>
</>
)}
</List>