Files
image-platform/apps/admin/src/screens/dashboard/dashboard.screen.tsx
S.Gromov 6a018826f5 feat: добавить рабочий dashboard admin
- добавлен Mantine theme provider и AppShell layout\n- сгенерирован Backend API клиент и добавлены infra/business хуки\n- добавлены таблица assets, detail/presets panels и create asset modal
2026-05-05 15:02:55 +03:00

97 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Alert, Button, Group, Paper, Stack, Text, Title } from "@mantine/core"
import { useDisclosure } from "@mantine/hooks"
import cl from "clsx"
import { useState } from "react"
import { assetsFactory } from "business/assets"
import { DASHBOARD_PIPELINE } from "./config/dashboard.config"
import { AssetDetailPanel } from "./parts/asset-detail-panel"
import { AssetsTable } from "./parts/assets-table"
import { CreateAssetModal } from "./parts/create-asset-modal"
import { PresetsPanel } from "./parts/presets-panel"
import { SummaryCards } from "./parts/summary-cards"
import styles from "./styles/dashboard.module.css"
import type { DashboardScreenProps } from "./types/dashboard.type"
const assets = assetsFactory()
/**
* Стартовый dashboard admin-приложения.
*
* Используется для:
* - отображения стартового состояния admin MVP
* - обзора будущих разделов и пайплайна генерации
*/
export const DashboardScreen = (props: DashboardScreenProps) => {
const { className, ...rootAttrs } = props
const [selectedPublicId, setSelectedPublicId] = useState<string | null>(null)
const [isCreateAssetOpen, createAssetModal] = useDisclosure(false)
const dashboard = assets.useAssetsDashboard()
const createAsset = assets.useCreateAsset()
const effectivePublicId = selectedPublicId ?? dashboard.assets[0]?.publicId ?? null
const overview = assets.useAssetOverview(effectivePublicId)
return (
<section {...rootAttrs} className={cl(styles.root, className)}>
<Stack gap="lg">
<Paper className={styles.hero} p={{ base: "xl", md: 42 }} radius="xl" shadow="xs" withBorder>
<Group align="flex-end" justify="space-between" gap="xl">
<div className={styles.heroContent}>
<Text className={styles.eyebrow}>Image Platform Admin</Text>
<Title className={styles.title}>Control plane для image delivery</Title>
<Text className={styles.lead}>
Управление allowed hosts, assets, source versions, presets и variant generation без
прямого доступа к storage-слою.
</Text>
</div>
<Button className={styles.primaryAction} onClick={createAssetModal.open} radius="xl" size="md">
Create asset
</Button>
</Group>
</Paper>
<SummaryCards isLoading={dashboard.isLoading} summary={dashboard.summary} />
<Group gap="xs" role="list" aria-label="Пайплайн генерации изображений">
{DASHBOARD_PIPELINE.map((step) => (
<Text className={styles.pipelineStep} key={step} role="listitem">
{step}
</Text>
))}
</Group>
{dashboard.error ? (
<Alert color="red" radius="lg" title="Backend API недоступен">
Проверьте, что backend запущен на `localhost:3001`, а Vite proxy доступен по `/api`.
</Alert>
) : null}
<div className={styles.workbench}>
<AssetsTable
assets={dashboard.assets}
isLoading={dashboard.isLoading}
onSelect={setSelectedPublicId}
selectedPublicId={effectivePublicId}
/>
<AssetDetailPanel overview={overview} publicId={effectivePublicId} />
</div>
<PresetsPanel
allowedSourceHosts={dashboard.allowedSourceHosts}
custom={dashboard.custom}
isLoading={dashboard.isLoading}
presets={dashboard.presets}
/>
</Stack>
<CreateAssetModal
action={createAsset}
onClose={createAssetModal.close}
onCreated={setSelectedPublicId}
opened={isCreateAssetOpen}
/>
</section>
)
}