feat(monorepo): restructure web components and update configurations
CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 27s
CI / web (push) Successful in 38s
CI / go (push) Successful in 2m36s
CI / bird2 (push) Successful in 15s
CI / release (push) Failing after 3m7s
CI / changes (push) Successful in 10s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 27s
CI / web (push) Successful in 38s
CI / go (push) Successful in 2m36s
CI / bird2 (push) Successful in 15s
CI / release (push) Failing after 3m7s
Refactored the project structure to support a monorepo setup, moving the web application to `apps/web/` and updating related configurations. Adjusted pre-commit hooks to use `pnpm` for linting and formatting. Updated CI workflows to reflect the new directory structure and dependencies. Removed legacy files and configurations from the previous `web/` directory, streamlining the project for better maintainability and clarity.
This commit is contained in:
@@ -0,0 +1,155 @@
|
||||
<script lang="ts">
|
||||
import type { AsEntry, BgpCommunity, DohProfile, ModuleRow } from '$lib/api/types.js';
|
||||
import { formatDateTime, moduleIntervalLabel } from '$lib/modules/display.js';
|
||||
import { dohPolicyRu } from '$lib/ui-labels.js';
|
||||
import {
|
||||
communityLabel,
|
||||
dohProfileLabel,
|
||||
moduleDohProfileIds
|
||||
} from '$lib/components/modules/module-helpers.js';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@evobgp/ui/components/card/index.js';
|
||||
import CardSkeleton from '$lib/components/patterns/feedback/card-skeleton.svelte';
|
||||
import { cn } from '$lib/utils.js';
|
||||
import ArrowDownUp from '@lucide/svelte/icons/arrow-down-up';
|
||||
import Timer from '@lucide/svelte/icons/timer';
|
||||
import ShieldCheck from '@lucide/svelte/icons/shield-check';
|
||||
import Network from '@lucide/svelte/icons/network';
|
||||
import RefreshCw from '@lucide/svelte/icons/refresh-cw';
|
||||
|
||||
type Props = {
|
||||
mod: ModuleRow | null;
|
||||
communities: BgpCommunity[];
|
||||
dohProfiles: DohProfile[];
|
||||
asEntries: AsEntry[];
|
||||
loading?: boolean;
|
||||
};
|
||||
|
||||
let { mod, communities, dohProfiles, asEntries, loading = false }: Props = $props();
|
||||
|
||||
const asPrefixTotal = $derived(
|
||||
asEntries.reduce((acc, entry) => acc + (entry.prefix_count ?? 0), 0)
|
||||
);
|
||||
|
||||
const statAccents = [
|
||||
{
|
||||
border: 'border-l-chart-3',
|
||||
bg: 'bg-chart-3/5',
|
||||
iconBg: 'bg-chart-3/15',
|
||||
iconText: 'text-chart-3'
|
||||
},
|
||||
{
|
||||
border: 'border-l-chart-5',
|
||||
bg: 'bg-chart-5/5',
|
||||
iconBg: 'bg-chart-5/15',
|
||||
iconText: 'text-chart-5'
|
||||
},
|
||||
{
|
||||
border: 'border-l-chart-4',
|
||||
bg: 'bg-chart-4/5',
|
||||
iconBg: 'bg-chart-4/15',
|
||||
iconText: 'text-chart-4'
|
||||
},
|
||||
{
|
||||
border: 'border-l-chart-2',
|
||||
bg: 'bg-chart-2/5',
|
||||
iconBg: 'bg-chart-2/15',
|
||||
iconText: 'text-chart-2'
|
||||
},
|
||||
{
|
||||
border: 'border-l-muted-foreground',
|
||||
bg: 'bg-muted/30',
|
||||
iconBg: 'bg-muted',
|
||||
iconText: 'text-muted-foreground'
|
||||
}
|
||||
] as const;
|
||||
|
||||
const kpiCards = $derived.by(() => {
|
||||
if (!mod) return [];
|
||||
const dohIds = moduleDohProfileIds(mod);
|
||||
return [
|
||||
{
|
||||
id: 'priority',
|
||||
label: 'Приоритет',
|
||||
value: String(mod.priority ?? 0),
|
||||
description: 'порядок в сборке ревизии',
|
||||
icon: ArrowDownUp,
|
||||
accent: statAccents[0]
|
||||
},
|
||||
{
|
||||
id: 'interval',
|
||||
label: 'Интервал',
|
||||
value: moduleIntervalLabel(mod),
|
||||
description: 'refresh_interval_sec / cron',
|
||||
icon: Timer,
|
||||
accent: statAccents[1],
|
||||
mono: true
|
||||
},
|
||||
{
|
||||
id: 'doh',
|
||||
label: 'DoH',
|
||||
value: mod.type === 'DOMAINS' ? dohPolicyRu(mod.doh_resolver_policy) : '—',
|
||||
description:
|
||||
mod.type === 'DOMAINS'
|
||||
? dohIds.length
|
||||
? dohIds.map((id) => dohProfileLabel(id, dohProfiles)).join('; ')
|
||||
: 'Системный DNS'
|
||||
: 'не применимо',
|
||||
icon: Network,
|
||||
accent: statAccents[2]
|
||||
},
|
||||
{
|
||||
id: 'community',
|
||||
label: 'Community по умолч.',
|
||||
value: communityLabel(mod.default_community_id, communities),
|
||||
description: 'для записей без своего community',
|
||||
icon: ShieldCheck,
|
||||
accent: statAccents[3]
|
||||
},
|
||||
{
|
||||
id: 'refreshed',
|
||||
label: 'Последнее обновление',
|
||||
value: formatDateTime(mod.last_refreshed_at),
|
||||
description:
|
||||
mod.type === 'AS_PREFIXES'
|
||||
? `ASN: ${asEntries.length}, префиксов: ${asPrefixTotal}`
|
||||
: 'время последнего refresh',
|
||||
icon: RefreshCw,
|
||||
accent: statAccents[4]
|
||||
}
|
||||
];
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2 xl:grid-cols-5">
|
||||
{#if loading}
|
||||
{#each Array(5) as _, i (i)}
|
||||
<CardSkeleton />
|
||||
{/each}
|
||||
{:else}
|
||||
{#each kpiCards as card (card.id)}
|
||||
{@const Icon = card.icon}
|
||||
{@const a = card.accent}
|
||||
<Card class={cn('overflow-hidden border-l-4 shadow-sm', a.border, a.bg)}>
|
||||
<CardHeader class="pb-2">
|
||||
<p class="flex items-center gap-1.5 text-xs text-muted-foreground">
|
||||
<span
|
||||
class={cn('flex size-7 shrink-0 items-center justify-center rounded-md', a.iconBg)}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<Icon class={cn('size-3.5', a.iconText)} />
|
||||
</span>
|
||||
{card.label}
|
||||
</p>
|
||||
<CardTitle
|
||||
class={cn('text-base font-semibold break-all', card.mono ? 'font-mono text-sm' : '')}
|
||||
>
|
||||
{card.value}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p class="line-clamp-2 text-xs text-muted-foreground">{card.description}</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
{/each}
|
||||
{/if}
|
||||
</div>
|
||||
Reference in New Issue
Block a user