104 lines
3.9 KiB
TypeScript
104 lines
3.9 KiB
TypeScript
import { useState } from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
import { api } from '../api/client';
|
|
import { useAction } from '../lib/hooks';
|
|
import { useGateway } from '../lib/gateway';
|
|
import { useToast } from '../lib/toast';
|
|
import { num, when } from '../lib/format';
|
|
import { Banner, Button, Card, Confirm, Loading, PageHead, Tiles } from '../components/ui';
|
|
|
|
export function RecommendationsPage() {
|
|
const { status, error, loading, reload } = useGateway();
|
|
const { wrap } = useToast();
|
|
const { busy, run } = useAction();
|
|
const [confirming, setConfirming] = useState(false);
|
|
|
|
const forYou = status?.forYou;
|
|
const running = Boolean(status?.forYouRunning);
|
|
|
|
const act = (action: string, key: string, message: string) =>
|
|
run(key, async () => {
|
|
await wrap(() => api.post('/admin/api/for-you', { action }), message);
|
|
setConfirming(false);
|
|
await reload();
|
|
});
|
|
|
|
return (
|
|
<>
|
|
<PageHead title="For You" intro="The prepared pools personalised rows are drawn from." />
|
|
<Banner message={error} />
|
|
|
|
{loading ? (
|
|
<Loading rows={2} />
|
|
) : (
|
|
<>
|
|
<Tiles
|
|
tiles={[
|
|
{ label: 'Tracearr sessions', value: num(forYou?.tracearrSessions ?? 0), icon: 'play', tone: 'info' },
|
|
{ label: 'user profiles', value: num(forYou?.profiles ?? 0), icon: 'people', tone: 'note' },
|
|
{ label: 'ranked candidates', value: num(forYou?.candidates ?? 0), icon: 'sparkle', tone: 'note' },
|
|
{ label: 'last full import', value: when(forYou?.lastFullImport), small: true, icon: 'clock' },
|
|
]}
|
|
/>
|
|
|
|
<Card
|
|
title="Pool maintenance"
|
|
intro="Prepared pools refresh in the background; these are the manual versions of the same work. A rebuild is safe at any time — televisions read the last finished pool until a new one lands."
|
|
icon="sparkle"
|
|
tone="note"
|
|
footer={
|
|
<span className="hint">
|
|
{running ? 'For You maintenance running…' : 'Prepared pools normally refresh in the background.'}
|
|
</span>
|
|
}
|
|
>
|
|
<div className="row">
|
|
<Button
|
|
variant="primary"
|
|
icon="download"
|
|
disabled={running}
|
|
busy={busy === 'import'}
|
|
onClick={() => void act('incremental-import', 'import', 'Import started.')}
|
|
>
|
|
Import recent sessions
|
|
</Button>
|
|
<Button icon="database" disabled={running} onClick={() => setConfirming(true)}>
|
|
Full Tracearr backfill
|
|
</Button>
|
|
<Button
|
|
icon="sync"
|
|
disabled={running}
|
|
busy={busy === 'rebuild'}
|
|
onClick={() => void act('rebuild-all', 'rebuild', 'Rebuild started.')}
|
|
>
|
|
Rebuild all pools
|
|
</Button>
|
|
</div>
|
|
</Card>
|
|
|
|
<Card
|
|
title="Reading a person's scores"
|
|
intro="The inspector re-runs the shared weighted scorer over one person's prepared pool, after Emby permission and parental-control filtering, and shows every component and evidence reason behind the order."
|
|
icon="search"
|
|
tone="info"
|
|
actions={<Link to="/admin/inspector">Open the inspector</Link>}
|
|
>
|
|
<></>
|
|
</Card>
|
|
</>
|
|
)}
|
|
|
|
{confirming ? (
|
|
<Confirm
|
|
title="Backfill all Tracearr history?"
|
|
body="Every session is re-read and every active user's pool is rebuilt. It is safe at any time — televisions keep reading the last finished pool — but on a long history it takes a while."
|
|
confirmLabel="Backfill"
|
|
busy={busy === 'full'}
|
|
onConfirm={() => void act('full-import', 'full', 'Backfill started.')}
|
|
onCancel={() => setConfirming(false)}
|
|
/>
|
|
) : null}
|
|
</>
|
|
);
|
|
}
|