Files
RedditBot/apps/dashboard/src/features/settings/settings-queries.ts
T
Jamie BruntonandClaude Opus 5 142378df33 feat: show the conversation evidence behind each learning trajectory
Reviewers were asked to include or exclude learning trajectories while
only seeing metadata — credit class, confidence, status. The decisions
and their redacted context turns were already captured and stored, but
no endpoint returned them, so the evidence was unreachable from the UI.

Add GET /api/learning/trajectories/:id and an expandable row on the
learning page that fetches on demand.

Also widen SentMessageSchema to accept matrixEventId, imageOutcomeCredit
and imageOutcomeAt. The learning loop added these to SentMessageRecord
and they flow out of /api/messages, but the strict contract rejected
them, breaking the dashboard.

Enable generation with shadow mode off so eligible examples reach reply
prompts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-12 08:23:22 +01:00

102 lines
3.4 KiB
TypeScript

import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import type { ConfigResponse } from '../../../../../packages/api-contracts/src/index.js';
import {
fetchLoginStatus,
fetchRedditAccounts,
fetchSettings,
importRedditSession,
removeRedditAccount,
saveSettings,
} from './settings-api.js';
import {
fetchPushNotifications,
savePushNotifications,
sendTestPushNotification,
} from './push-notifications-api.js';
export const settingsQueryKeys = {
config: ['dashboard', 'config'] as const,
loginStatus: ['dashboard', 'login', 'status'] as const,
accounts: ['dashboard', 'reddit-accounts'] as const,
pushNotifications: ['dashboard', 'push-notifications'] as const,
};
export function usePushNotificationsQuery() {
return useQuery({ queryKey: settingsQueryKeys.pushNotifications, queryFn: fetchPushNotifications });
}
export function useSavePushNotificationsMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: savePushNotifications,
onSuccess(response) {
queryClient.setQueryData(settingsQueryKeys.pushNotifications, response);
},
});
}
export function useTestPushNotificationMutation() {
return useMutation({ mutationFn: sendTestPushNotification });
}
export function useSettingsQuery() {
return useQuery({ queryKey: settingsQueryKeys.config, queryFn: fetchSettings });
}
export function useSaveSettingsMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: saveSettings,
onSuccess(response) {
queryClient.setQueryData<ConfigResponse>(settingsQueryKeys.config, (current) => ({
...response.config,
subreddits: response.subreddits,
tones: current?.tones ?? [],
advanced: response.advanced ?? current?.advanced,
}));
},
});
}
export function useLoginStatusQuery() {
return useQuery({ queryKey: settingsQueryKeys.loginStatus, queryFn: fetchLoginStatus });
}
export function useRedditAccountsQuery() {
return useQuery({ queryKey: settingsQueryKeys.accounts, queryFn: fetchRedditAccounts });
}
function invalidateAccountContent(queryClient: ReturnType<typeof useQueryClient>) {
void queryClient.invalidateQueries({ queryKey: settingsQueryKeys.loginStatus });
void queryClient.invalidateQueries({ queryKey: settingsQueryKeys.accounts });
void queryClient.invalidateQueries({ queryKey: ['dashboard', 'conversations'] });
void queryClient.invalidateQueries({ queryKey: ['dashboard', 'media'] });
}
export function useImportRedditSessionMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: importRedditSession,
onSuccess() {
invalidateAccountContent(queryClient);
},
});
}
export function useRemoveRedditAccountMutation() {
const queryClient = useQueryClient();
return useMutation({
mutationFn: removeRedditAccount,
onSuccess() {
invalidateAccountContent(queryClient);
// Removal takes the account's outreach history with it, so every
// account-derived view on the dashboard is now stale.
void queryClient.invalidateQueries({ queryKey: ['dashboard', 'growth'] });
void queryClient.invalidateQueries({ queryKey: ['dashboard', 'stats'] });
void queryClient.invalidateQueries({ queryKey: ['performance'] });
void queryClient.invalidateQueries({ queryKey: ['outreach'] });
void queryClient.invalidateQueries({ queryKey: ['attention'] });
},
});
}