Adds /[portSlug]/website-analytics dashboard page (pageviews, top pages, top referrers) and a per-port admin config UI for the Umami URL / website-ID / API token. Settings live in system_settings keyed per-port so a future second port has its own Umami account. Adds a website glance tile to the main dashboard, a server-side test-credentials endpoint, and a stable cache key for the active- visitor poll so React Query doesn't fragment the cache per range. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
import {
|
||
SettingsFormCard,
|
||
type SettingFieldDef,
|
||
} from '@/components/admin/shared/settings-form-card';
|
||
import { UmamiTestButton } from '@/components/admin/website-analytics/umami-test-button';
|
||
import { PageHeader } from '@/components/shared/page-header';
|
||
|
||
/**
|
||
* Per-port Umami credentials. We deliberately keep all three values
|
||
* port-scoped (per the operator decision) so different ports can point at
|
||
* different Umami instances if needed. The /website-analytics dashboard
|
||
* page reads these settings via the umami.service layer at request time.
|
||
*/
|
||
const FIELDS: SettingFieldDef[] = [
|
||
{
|
||
key: 'umami_api_url',
|
||
label: 'Umami API URL',
|
||
description:
|
||
'Base URL of the Umami instance, e.g. https://analytics.portnimara.com (no trailing slash, no /api).',
|
||
type: 'string',
|
||
placeholder: 'https://analytics.portnimara.com',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_api_token',
|
||
label: 'API token',
|
||
description:
|
||
'Long-lived API token if your Umami install supports one (Umami Cloud or v2 self-hosted with API keys enabled). Leave blank if you only have username/password - the service falls back to the JWT login flow using the credentials below. Stored in plain text in system_settings.',
|
||
type: 'password',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_username',
|
||
label: 'Username',
|
||
description: 'Self-hosted JWT fallback. Only used if API token is blank.',
|
||
type: 'string',
|
||
placeholder: 'admin',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_password',
|
||
label: 'Password',
|
||
description: 'Self-hosted JWT fallback. Only used if API token is blank.',
|
||
type: 'password',
|
||
defaultValue: '',
|
||
},
|
||
{
|
||
key: 'umami_website_id',
|
||
label: 'Website ID',
|
||
description:
|
||
'UUID of this port’s website inside Umami. Find it in Umami → Settings → Websites → Edit → Website ID.',
|
||
type: 'string',
|
||
placeholder: '00000000-0000-0000-0000-000000000000',
|
||
defaultValue: '',
|
||
},
|
||
];
|
||
|
||
export default function WebsiteAnalyticsSettingsPage() {
|
||
return (
|
||
<div className="space-y-6">
|
||
<PageHeader
|
||
title="Website analytics (Umami)"
|
||
description="Connect this port to its Umami website to display traffic, top pages, referrers, and conversion data on the Website Analytics dashboard."
|
||
/>
|
||
|
||
<SettingsFormCard
|
||
title="Umami connection"
|
||
description="Per-port credentials. Each port can point at its own Umami instance; or share one instance with different website IDs."
|
||
fields={FIELDS}
|
||
extra={<UmamiTestButton />}
|
||
/>
|
||
</div>
|
||
);
|
||
}
|