Show webhooks/apprise summary

This commit is contained in:
Jack Kingsman
2026-03-06 18:19:14 -08:00
parent f60c656566
commit f82cadb4e1
2 changed files with 76 additions and 0 deletions

View File

@@ -48,6 +48,18 @@ function formatPrivateTopicSummary(config: Record<string, unknown>) {
return `${prefix}/dm:<pubkey>, ${prefix}/gm:<channel>, ${prefix}/raw/...`;
}
function formatAppriseTargets(urls: string | undefined, maxLength = 80) {
const targets = (urls || '')
.split('\n')
.map((line) => line.trim())
.filter(Boolean);
if (targets.length === 0) return 'No targets configured';
const joined = targets.join(', ');
if (joined.length <= maxLength) return joined;
return `${joined.slice(0, maxLength - 3)}...`;
}
const DEFAULT_BOT_CODE = `def bot(
sender_name: str | None,
sender_key: str | None,
@@ -1334,6 +1346,30 @@ export function SettingsFanoutSection({
</div>
</div>
)}
{cfg.type === 'webhook' && (
<div className="space-y-1 border-t border-input px-3 py-2 text-xs text-muted-foreground">
<div className="break-all">
URL:{' '}
<code>
{((cfg.config as Record<string, unknown>).url as string) || 'Not set'}
</code>
</div>
</div>
)}
{cfg.type === 'apprise' && (
<div className="space-y-1 border-t border-input px-3 py-2 text-xs text-muted-foreground">
<div className="break-all">
Targets:{' '}
<code>
{formatAppriseTargets(
(cfg.config as Record<string, unknown>).urls as string | undefined
)}
</code>
</div>
</div>
)}
</div>
);
})}

View File

@@ -461,4 +461,44 @@ describe('SettingsFanoutSection', () => {
screen.getByText('meshcore/dm:<pubkey>, meshcore/gm:<channel>, meshcore/raw/...')
).toBeInTheDocument();
});
it('webhook list shows destination URL', async () => {
const config: FanoutConfig = {
id: 'wh-1',
type: 'webhook',
name: 'Webhook',
enabled: true,
config: { url: 'https://example.com/hook', method: 'POST', headers: {} },
scope: { messages: 'all', raw_packets: 'none' },
sort_order: 0,
created_at: 1000,
};
mockedApi.getFanoutConfigs.mockResolvedValue([config]);
renderSection();
await waitFor(() => expect(screen.getByText('https://example.com/hook')).toBeInTheDocument());
});
it('apprise list shows compact target summary', async () => {
const config: FanoutConfig = {
id: 'ap-1',
type: 'apprise',
name: 'Apprise',
enabled: true,
config: {
urls: 'discord://abc\nmailto://one@example.com\nmailto://two@example.com',
preserve_identity: true,
include_path: true,
},
scope: { messages: 'all', raw_packets: 'none' },
sort_order: 0,
created_at: 1000,
};
mockedApi.getFanoutConfigs.mockResolvedValue([config]);
renderSection();
await waitFor(() =>
expect(screen.getByText(/discord:\/\/abc, mailto:\/\/one@example.com/)).toBeInTheDocument()
);
});
});