feat: Add snapshots
page
All checks were successful
release-tag / release-image (push) Successful in 2m23s
All checks were successful
release-tag / release-image (push) Successful in 2m23s
This commit is contained in:
721
src/App.tsx
721
src/App.tsx
@ -77,378 +77,397 @@ import { AdminOnly } from "./components/AdminOnly";
|
||||
|
||||
//import { LoadingProvider } from "@mt/utils";
|
||||
import { KBarProvider, RefineKbar } from "@refinedev/kbar";
|
||||
import { GitBranch } from "lucide-react";
|
||||
import { SnapshotList, SnapshotCreate, SnapshotShow } from "./pages/snapshot";
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<BrowserRouter>
|
||||
<ColorModeContextProvider>
|
||||
<CssBaseline />
|
||||
<GlobalStyles styles={{ html: { WebkitFontSmoothing: "auto" } }} />
|
||||
<RefineSnackbarProvider>
|
||||
<DevtoolsProvider>
|
||||
<Refine
|
||||
dataProvider={customDataProvider}
|
||||
notificationProvider={useNotificationProvider}
|
||||
routerProvider={routerBindings}
|
||||
authProvider={authProvider}
|
||||
i18nProvider={i18nProvider}
|
||||
resources={[
|
||||
{
|
||||
name: "country",
|
||||
list: "/country",
|
||||
create: "/country/create",
|
||||
edit: "/country/edit/:id",
|
||||
show: "/country/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Страны",
|
||||
icon: <CountryIcon />,
|
||||
},
|
||||
<BrowserRouter>
|
||||
<ColorModeContextProvider>
|
||||
<CssBaseline />
|
||||
<GlobalStyles styles={{ html: { WebkitFontSmoothing: "auto" } }} />
|
||||
<RefineSnackbarProvider>
|
||||
<DevtoolsProvider>
|
||||
<Refine
|
||||
dataProvider={customDataProvider}
|
||||
notificationProvider={useNotificationProvider}
|
||||
routerProvider={routerBindings}
|
||||
authProvider={authProvider}
|
||||
i18nProvider={i18nProvider}
|
||||
resources={[
|
||||
{
|
||||
name: "country",
|
||||
list: "/country",
|
||||
create: "/country/create",
|
||||
edit: "/country/edit/:id",
|
||||
show: "/country/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Страны",
|
||||
icon: <CountryIcon />,
|
||||
},
|
||||
{
|
||||
name: "city",
|
||||
list: "/city",
|
||||
create: "/city/create",
|
||||
edit: "/city/edit/:id",
|
||||
show: "/city/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Города",
|
||||
icon: <CityIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "city",
|
||||
list: "/city",
|
||||
create: "/city/create",
|
||||
edit: "/city/edit/:id",
|
||||
show: "/city/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Города",
|
||||
icon: <CityIcon />,
|
||||
},
|
||||
{
|
||||
name: "carrier",
|
||||
list: "/carrier",
|
||||
create: "/carrier/create",
|
||||
edit: "/carrier/edit/:id",
|
||||
show: "/carrier/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Перевозчики",
|
||||
icon: <CarrierIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "carrier",
|
||||
list: "/carrier",
|
||||
create: "/carrier/create",
|
||||
edit: "/carrier/edit/:id",
|
||||
show: "/carrier/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Перевозчики",
|
||||
icon: <CarrierIcon />,
|
||||
},
|
||||
{
|
||||
name: "media",
|
||||
list: "/media",
|
||||
create: "/media/create",
|
||||
edit: "/media/edit/:id",
|
||||
show: "/media/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Медиа",
|
||||
icon: <MediaIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "media",
|
||||
list: "/media",
|
||||
create: "/media/create",
|
||||
edit: "/media/edit/:id",
|
||||
show: "/media/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Медиа",
|
||||
icon: <MediaIcon />,
|
||||
},
|
||||
{
|
||||
name: "article",
|
||||
list: "/article",
|
||||
create: "/article/create",
|
||||
edit: "/article/edit/:id",
|
||||
show: "/article/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Статьи",
|
||||
icon: <ArticleIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "article",
|
||||
list: "/article",
|
||||
create: "/article/create",
|
||||
edit: "/article/edit/:id",
|
||||
show: "/article/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Статьи",
|
||||
icon: <ArticleIcon />,
|
||||
},
|
||||
{
|
||||
name: "sight",
|
||||
list: "/sight",
|
||||
create: "/sight/create",
|
||||
edit: "/sight/edit/:id",
|
||||
show: "/sight/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Достопримечательности",
|
||||
icon: <SightIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sight",
|
||||
list: "/sight",
|
||||
create: "/sight/create",
|
||||
edit: "/sight/edit/:id",
|
||||
show: "/sight/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Достопримечательности",
|
||||
icon: <SightIcon />,
|
||||
},
|
||||
{
|
||||
name: "station",
|
||||
list: "/station",
|
||||
create: "/station/create",
|
||||
edit: "/station/edit/:id",
|
||||
show: "/station/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Остановки",
|
||||
icon: <StationIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "station",
|
||||
list: "/station",
|
||||
create: "/station/create",
|
||||
edit: "/station/edit/:id",
|
||||
show: "/station/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Остановки",
|
||||
icon: <StationIcon />,
|
||||
},
|
||||
{
|
||||
name: "stationmodal",
|
||||
show: "/route/:id/station",
|
||||
edit: "/route/:id/station/",
|
||||
meta: {
|
||||
hide: true,
|
||||
canDelete: true,
|
||||
label: "Маршруты",
|
||||
icon: <RouteIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshots",
|
||||
list: "/snapshot",
|
||||
create: "/snapshot/create",
|
||||
|
||||
show: "/snapshot/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Снапшоты",
|
||||
icon: <GitBranch />,
|
||||
},
|
||||
{
|
||||
name: "vehicle",
|
||||
list: "/vehicle",
|
||||
create: "/vehicle/create",
|
||||
edit: "/vehicle/edit/:id",
|
||||
show: "/vehicle/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Транспорт",
|
||||
icon: <VehicleIcon />,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "vehicle",
|
||||
list: "/vehicle",
|
||||
create: "/vehicle/create",
|
||||
edit: "/vehicle/edit/:id",
|
||||
show: "/vehicle/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Транспорт",
|
||||
icon: <VehicleIcon />,
|
||||
},
|
||||
{
|
||||
name: "route",
|
||||
list: "/route",
|
||||
create: "/route/create",
|
||||
edit: "/route/edit/:id",
|
||||
show: "/route/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Маршруты",
|
||||
icon: <RouteIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "route",
|
||||
list: "/route",
|
||||
create: "/route/create",
|
||||
edit: "/route/edit/:id",
|
||||
show: "/route/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Маршруты",
|
||||
icon: <RouteIcon />,
|
||||
},
|
||||
{
|
||||
name: "route-preview",
|
||||
list: "/route",
|
||||
show: "/route/:id/station",
|
||||
meta: {
|
||||
hide: true,
|
||||
stations: "route/:id/station"
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "route-preview",
|
||||
list: "/route",
|
||||
show: "/route/:id/station",
|
||||
meta: {
|
||||
hide: true,
|
||||
stations: "route/:id/station",
|
||||
},
|
||||
{
|
||||
name: "user",
|
||||
list: "/user",
|
||||
create: "/user/create",
|
||||
edit: "/user/edit/:id",
|
||||
show: "/user/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Пользователи",
|
||||
icon: <UsersIcon />,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "user",
|
||||
list: "/user",
|
||||
create: "/user/create",
|
||||
edit: "/user/edit/:id",
|
||||
show: "/user/show/:id",
|
||||
meta: {
|
||||
canDelete: true,
|
||||
label: "Пользователи",
|
||||
icon: <UsersIcon />,
|
||||
},
|
||||
]}
|
||||
options={{
|
||||
syncWithLocation: true,
|
||||
warnWhenUnsavedChanges: true, // Включаем глобально
|
||||
useNewQueryKeys: true,
|
||||
projectId: "Wv044J-t53S3s-PcbJGe",
|
||||
}}
|
||||
>
|
||||
<KBarProvider>
|
||||
<Routes>
|
||||
<Route path="/route-preview">
|
||||
<Route path=":id" element={<RoutePreview />} />
|
||||
},
|
||||
]}
|
||||
options={{
|
||||
syncWithLocation: true,
|
||||
warnWhenUnsavedChanges: true, // Включаем глобально
|
||||
useNewQueryKeys: true,
|
||||
projectId: "Wv044J-t53S3s-PcbJGe",
|
||||
}}
|
||||
>
|
||||
<KBarProvider>
|
||||
<Routes>
|
||||
<Route path="/route-preview">
|
||||
<Route path=":id" element={<RoutePreview />} />
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
key="authenticated-inner"
|
||||
fallback={<CatchAllNavigate to="/login" />}
|
||||
>
|
||||
<ThemedLayoutV2 Header={Header} Title={SidebarTitle}>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route
|
||||
index
|
||||
element={<NavigateToResource resource="country" />}
|
||||
/>
|
||||
|
||||
<Route path="/country">
|
||||
<Route index element={<CountryList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CountryCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CountryEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<CountryShow />} />
|
||||
</Route>
|
||||
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
key="authenticated-inner"
|
||||
fallback={<CatchAllNavigate to="/login" />}
|
||||
>
|
||||
<ThemedLayoutV2 Header={Header} Title={SidebarTitle}>
|
||||
<Outlet />
|
||||
</ThemedLayoutV2>
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="/snapshot">
|
||||
<Route index element={<SnapshotList />} />
|
||||
<Route
|
||||
index
|
||||
element={<NavigateToResource resource="country" />}
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<SnapshotCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
|
||||
<Route path="/country">
|
||||
<Route index element={<CountryList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CountryCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CountryEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<CountryShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/city">
|
||||
<Route index element={<CityList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CityCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CityEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<CityShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/carrier">
|
||||
<Route index element={<CarrierList />} />
|
||||
<Route path="create" element={<CarrierCreate />} />
|
||||
<Route path="edit/:id" element={<CarrierEdit />} />
|
||||
<Route path="show/:id" element={<CarrierShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/media">
|
||||
<Route index element={<MediaList />} />
|
||||
<Route path="create" element={<MediaCreate />} />
|
||||
<Route path="edit/:id" element={<MediaEdit />} />
|
||||
<Route path="show/:id" element={<MediaShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/article">
|
||||
<Route index element={<ArticleList />} />
|
||||
<Route path="create" element={<ArticleCreate />} />
|
||||
<Route path="edit/:id" element={<ArticleEdit />} />
|
||||
<Route path="show/:id" element={<ArticleShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/sight">
|
||||
<Route index element={<SightList />} />
|
||||
<Route path="create" element={<SightCreate />} />
|
||||
<Route path="edit/:id" element={<SightEdit />} />
|
||||
<Route path="show/:id" element={<SightShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/station">
|
||||
<Route index element={<StationList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<StationCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<StationEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<StationShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/vehicle">
|
||||
<Route index element={<VehicleList />} />
|
||||
<Route path="create" element={<VehicleCreate />} />
|
||||
<Route path="edit/:id" element={<VehicleEdit />} />
|
||||
<Route path="show/:id" element={<VehicleShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/route">
|
||||
<Route index element={<RouteList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<RouteCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<RouteEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<RouteShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/user">
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserList />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="show/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserShow />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="*" element={<ErrorComponent />} />
|
||||
<Route path="show/:id" element={<SnapshotShow />} />
|
||||
</Route>
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
key="authenticated-outer"
|
||||
fallback={<Outlet />}
|
||||
>
|
||||
<NavigateToResource />
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="/login" element={<Login />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
<UnsavedChangesNotifier />
|
||||
<DocumentTitleHandler
|
||||
handler={() => {
|
||||
// const cleanedTitle = title.autoGeneratedTitle.split('|')[0].trim()
|
||||
// return `${cleanedTitle} — Белые ночи`
|
||||
return "Белые ночи";
|
||||
}}
|
||||
/>
|
||||
<RefineKbar />
|
||||
</KBarProvider>
|
||||
</Refine>
|
||||
<DevtoolsPanel />
|
||||
</DevtoolsProvider>
|
||||
</RefineSnackbarProvider>
|
||||
</ColorModeContextProvider>
|
||||
</BrowserRouter>
|
||||
<Route path="/city">
|
||||
<Route index element={<CityList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CityCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<CityEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<CityShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/carrier">
|
||||
<Route index element={<CarrierList />} />
|
||||
<Route path="create" element={<CarrierCreate />} />
|
||||
<Route path="edit/:id" element={<CarrierEdit />} />
|
||||
<Route path="show/:id" element={<CarrierShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/media">
|
||||
<Route index element={<MediaList />} />
|
||||
<Route path="create" element={<MediaCreate />} />
|
||||
<Route path="edit/:id" element={<MediaEdit />} />
|
||||
<Route path="show/:id" element={<MediaShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/article">
|
||||
<Route index element={<ArticleList />} />
|
||||
<Route path="create" element={<ArticleCreate />} />
|
||||
<Route path="edit/:id" element={<ArticleEdit />} />
|
||||
<Route path="show/:id" element={<ArticleShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/sight">
|
||||
<Route index element={<SightList />} />
|
||||
<Route path="create" element={<SightCreate />} />
|
||||
<Route path="edit/:id" element={<SightEdit />} />
|
||||
<Route path="show/:id" element={<SightShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/station">
|
||||
<Route index element={<StationList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<StationCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<StationEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<StationShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/vehicle">
|
||||
<Route index element={<VehicleList />} />
|
||||
<Route path="create" element={<VehicleCreate />} />
|
||||
<Route path="edit/:id" element={<VehicleEdit />} />
|
||||
<Route path="show/:id" element={<VehicleShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/route">
|
||||
<Route index element={<RouteList />} />
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<RouteCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<RouteEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route path="show/:id" element={<RouteShow />} />
|
||||
</Route>
|
||||
|
||||
<Route path="/user">
|
||||
<Route
|
||||
index
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserList />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="create"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserCreate />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="edit/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserEdit />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="show/:id"
|
||||
element={
|
||||
<AdminOnly>
|
||||
<UserShow />
|
||||
</AdminOnly>
|
||||
}
|
||||
/>
|
||||
</Route>
|
||||
|
||||
<Route path="*" element={<ErrorComponent />} />
|
||||
</Route>
|
||||
<Route
|
||||
element={
|
||||
<Authenticated
|
||||
key="authenticated-outer"
|
||||
fallback={<Outlet />}
|
||||
>
|
||||
<NavigateToResource />
|
||||
</Authenticated>
|
||||
}
|
||||
>
|
||||
<Route path="/login" element={<Login />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
|
||||
<UnsavedChangesNotifier />
|
||||
<DocumentTitleHandler
|
||||
handler={() => {
|
||||
// const cleanedTitle = title.autoGeneratedTitle.split('|')[0].trim()
|
||||
// return `${cleanedTitle} — Белые ночи`
|
||||
return "Белые ночи";
|
||||
}}
|
||||
/>
|
||||
<RefineKbar />
|
||||
</KBarProvider>
|
||||
</Refine>
|
||||
<DevtoolsPanel />
|
||||
</DevtoolsProvider>
|
||||
</RefineSnackbarProvider>
|
||||
</ColorModeContextProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,13 @@
|
||||
"show": "Показать станцию"
|
||||
}
|
||||
},
|
||||
"snapshots": {
|
||||
"titles": {
|
||||
"create": "Создать снапшот",
|
||||
"show": "Показать снапшот"
|
||||
}
|
||||
},
|
||||
|
||||
"vehicle": {
|
||||
"titles": {
|
||||
"create": "Создать транспорт",
|
||||
|
61
src/pages/snapshot/create.tsx
Normal file
61
src/pages/snapshot/create.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import { Box, TextField, Typography, Paper } from "@mui/material";
|
||||
import { Create } from "@refinedev/mui";
|
||||
import { useForm } from "@refinedev/react-hook-form";
|
||||
import { Controller, FieldValues } from "react-hook-form";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { MarkdownEditor } from "../../components/MarkdownEditor";
|
||||
import "easymde/dist/easymde.min.css";
|
||||
import { LanguageSelector } from "@ui";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import {
|
||||
EVERY_LANGUAGE,
|
||||
Languages,
|
||||
languageStore,
|
||||
META_LANGUAGE,
|
||||
} from "@stores";
|
||||
import rehypeRaw from "rehype-raw";
|
||||
|
||||
const MemoizedSimpleMDE = React.memo(MarkdownEditor);
|
||||
|
||||
export const SnapshotCreate = observer(() => {
|
||||
const {
|
||||
saveButtonProps,
|
||||
refineCore: { formLoading, onFinish },
|
||||
register,
|
||||
control,
|
||||
watch,
|
||||
formState: { errors },
|
||||
setValue,
|
||||
handleSubmit,
|
||||
} = useForm();
|
||||
|
||||
return (
|
||||
<Create isLoading={formLoading} saveButtonProps={saveButtonProps}>
|
||||
<Box sx={{ display: "flex", flex: 1, gap: 2 }}>
|
||||
{/* Форма создания */}
|
||||
<Box sx={{ display: "flex", flex: 1, flexDirection: "column", gap: 2 }}>
|
||||
<Box
|
||||
component="form"
|
||||
sx={{ flex: 1, display: "flex", flexDirection: "column" }}
|
||||
autoComplete="off"
|
||||
>
|
||||
<TextField
|
||||
{...register("Name", {
|
||||
required: "Это поле является обязательным",
|
||||
})}
|
||||
error={!!(errors as any)?.name}
|
||||
helperText={(errors as any)?.name?.message}
|
||||
margin="normal"
|
||||
fullWidth
|
||||
InputLabelProps={{ shrink: true }}
|
||||
type="text"
|
||||
label={"Название *"}
|
||||
name="Name"
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
</Create>
|
||||
);
|
||||
});
|
3
src/pages/snapshot/index.ts
Normal file
3
src/pages/snapshot/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from "./create";
|
||||
export * from "./list";
|
||||
export * from "./show";
|
109
src/pages/snapshot/list.tsx
Normal file
109
src/pages/snapshot/list.tsx
Normal file
@ -0,0 +1,109 @@
|
||||
import React from "react";
|
||||
import { type GridColDef } from "@mui/x-data-grid";
|
||||
import {
|
||||
DeleteButton,
|
||||
EditButton,
|
||||
List,
|
||||
ShowButton,
|
||||
useDataGrid,
|
||||
} from "@refinedev/mui";
|
||||
import { Stack } from "@mui/material";
|
||||
import { CustomDataGrid } from "@components";
|
||||
import { localeText } from "../../locales/ru/localeText";
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { useMany } from "@refinedev/core";
|
||||
|
||||
export const SnapshotList = observer(() => {
|
||||
const { dataGridProps } = useDataGrid({
|
||||
resource: "snapshots",
|
||||
hasPagination: false,
|
||||
});
|
||||
|
||||
// Получаем список уникальных ParentID
|
||||
const parentIds = React.useMemo(() => {
|
||||
return (
|
||||
dataGridProps?.rows
|
||||
?.map((row: any) => row.ParentID)
|
||||
.filter((id) => id !== null && id !== undefined)
|
||||
.filter((value, index, self) => self.indexOf(value) === index) || []
|
||||
);
|
||||
}, [dataGridProps?.rows]);
|
||||
|
||||
// Загружаем родительские снапшоты
|
||||
const { data: parentsData } = useMany({
|
||||
resource: "snapshots",
|
||||
ids: parentIds,
|
||||
queryOptions: {
|
||||
enabled: parentIds.length > 0,
|
||||
},
|
||||
});
|
||||
|
||||
// Создаем мапу ID → Name
|
||||
const parentNameMap = React.useMemo(() => {
|
||||
const map: Record<number, string> = {};
|
||||
parentsData?.data?.forEach((parent) => {
|
||||
map[parent.ID] = parent.Name;
|
||||
});
|
||||
return map;
|
||||
}, [parentsData]);
|
||||
|
||||
const columns = React.useMemo<GridColDef[]>(
|
||||
() => [
|
||||
{
|
||||
field: "Name",
|
||||
headerName: "Название",
|
||||
type: "string",
|
||||
minWidth: 150,
|
||||
flex: 1,
|
||||
align: "left",
|
||||
headerAlign: "left",
|
||||
},
|
||||
{
|
||||
field: "ParentID",
|
||||
headerName: "Родитель",
|
||||
minWidth: 150,
|
||||
flex: 1,
|
||||
renderCell: ({ value }) => parentNameMap[value] || "—",
|
||||
align: "left",
|
||||
headerAlign: "left",
|
||||
},
|
||||
{
|
||||
field: "actions",
|
||||
headerName: "Действия",
|
||||
minWidth: 150,
|
||||
display: "flex",
|
||||
align: "center",
|
||||
headerAlign: "center",
|
||||
sortable: false,
|
||||
filterable: false,
|
||||
disableColumnMenu: true,
|
||||
renderCell: function render({ row }) {
|
||||
return (
|
||||
<>
|
||||
<ShowButton hideText recordItemId={row.ID} />
|
||||
<DeleteButton
|
||||
hideText
|
||||
confirmTitle="Вы уверены?"
|
||||
recordItemId={row.ID}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[parentNameMap]
|
||||
);
|
||||
|
||||
return (
|
||||
<List>
|
||||
<Stack gap={2.5}>
|
||||
<CustomDataGrid
|
||||
{...dataGridProps}
|
||||
columns={columns}
|
||||
localeText={localeText}
|
||||
getRowId={(row: any) => row.ID}
|
||||
/>
|
||||
</Stack>
|
||||
</List>
|
||||
);
|
||||
});
|
26
src/pages/snapshot/show.tsx
Normal file
26
src/pages/snapshot/show.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { Stack, Typography } from "@mui/material";
|
||||
import { useShow } from "@refinedev/core";
|
||||
import { Show, TextFieldComponent } from "@refinedev/mui";
|
||||
|
||||
export const SnapshotShow = () => {
|
||||
const { query } = useShow({});
|
||||
const { data, isLoading } = query;
|
||||
const record = data?.data;
|
||||
|
||||
const fields = [{ label: "Название", data: "Name" }];
|
||||
|
||||
return (
|
||||
<Show isLoading={isLoading} canEdit={false}>
|
||||
<Stack gap={4}>
|
||||
{fields.map(({ label, data }) => (
|
||||
<Stack key={data} gap={1}>
|
||||
<Typography variant="body1" fontWeight="bold">
|
||||
{label}
|
||||
</Typography>
|
||||
<TextFieldComponent value={record?.[data]} />
|
||||
</Stack>
|
||||
))}
|
||||
</Stack>
|
||||
</Show>
|
||||
);
|
||||
};
|
Reference in New Issue
Block a user