feat: добавить рабочий dashboard admin
- добавлен Mantine theme provider и AppShell layout\n- сгенерирован Backend API клиент и добавлены infra/business хуки\n- добавлены таблица assets, detail/presets panels и create asset modal
This commit is contained in:
@@ -1,9 +1,20 @@
|
||||
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_CARDS, DASHBOARD_PIPELINE } from "./config/dashboard.config"
|
||||
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-приложения.
|
||||
*
|
||||
@@ -13,34 +24,73 @@ import type { DashboardScreenProps } from "./types/dashboard.type"
|
||||
*/
|
||||
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)}>
|
||||
<div className={styles.hero}>
|
||||
<p className={styles.eyebrow}>Image Platform Admin</p>
|
||||
<h1 className={styles.title}>Control plane для image delivery</h1>
|
||||
<p className={styles.lead}>
|
||||
Админка будет управлять allowed hosts, assets, source versions, presets и variant
|
||||
generation без прямого доступа к storage-слою.
|
||||
</p>
|
||||
</div>
|
||||
<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>
|
||||
|
||||
<div className={styles.grid} aria-label="Будущие разделы admin">
|
||||
{DASHBOARD_CARDS.map((card) => (
|
||||
<article className={styles.card} key={card.title}>
|
||||
<h2 className={styles.cardTitle}>{card.title}</h2>
|
||||
<p className={styles.cardDescription}>{card.description}</p>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
<Button className={styles.primaryAction} onClick={createAssetModal.open} radius="xl" size="md">
|
||||
Create asset
|
||||
</Button>
|
||||
</Group>
|
||||
</Paper>
|
||||
|
||||
<div className={styles.pipeline} aria-label="Пайплайн генерации изображений">
|
||||
{DASHBOARD_PIPELINE.map((step) => (
|
||||
<span className={styles.pipelineStep} key={step}>
|
||||
{step}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
<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>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user