- добавлен Mantine theme provider и AppShell layout\n- сгенерирован Backend API клиент и добавлены infra/business хуки\n- добавлены таблица assets, detail/presets panels и create asset modal
97 lines
3.8 KiB
TypeScript
97 lines
3.8 KiB
TypeScript
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>
|
||
)
|
||
}
|