From bf117ef04822d997d1816d85a4fbb9843d1f05f1 Mon Sep 17 00:00:00 2001 From: itoshi Date: Sun, 13 Jul 2025 20:26:45 +0300 Subject: [PATCH] feat: Add `preview_video` for sights --- src/pages/City/CityListPage/index.tsx | 1 - src/shared/const/index.ts | 1 + src/shared/modals/UploadMediaDialog/index.tsx | 36 +++- src/shared/store/DevicesStore/index.tsx | 1 + src/widgets/DevicesTable/index.tsx | 2 +- src/widgets/Layout/index.tsx | 1 - .../SightTabs/CreateInformationTab/index.tsx | 95 +++++++- .../SightTabs/InformationTab/index.tsx | 132 ++++++++++-- src/widgets/VideoPreviewCard/index.tsx | 203 ++++++++++++++++++ src/widgets/index.ts | 1 + tsconfig.tsbuildinfo | 2 +- 11 files changed, 437 insertions(+), 38 deletions(-) create mode 100644 src/widgets/VideoPreviewCard/index.tsx diff --git a/src/pages/City/CityListPage/index.tsx b/src/pages/City/CityListPage/index.tsx index cd3c288..64315bd 100644 --- a/src/pages/City/CityListPage/index.tsx +++ b/src/pages/City/CityListPage/index.tsx @@ -50,7 +50,6 @@ export const CityListPage = observer(() => { } setRows(newRows2 || []); - console.log(newRows2); }, [cities, countryStore.countries, language, isLoading]); const columns: GridColDef[] = [ diff --git a/src/shared/const/index.ts b/src/shared/const/index.ts index be30fa8..df008b1 100644 --- a/src/shared/const/index.ts +++ b/src/shared/const/index.ts @@ -17,6 +17,7 @@ export const MEDIA_TYPE_VALUES = { watermark_rd: 4, panorama: 5, model: 6, + video_preview: 2, }; export const RU_COUNTRIES = [ diff --git a/src/shared/modals/UploadMediaDialog/index.tsx b/src/shared/modals/UploadMediaDialog/index.tsx index 4dc4d47..7bd5eef 100644 --- a/src/shared/modals/UploadMediaDialog/index.tsx +++ b/src/shared/modals/UploadMediaDialog/index.tsx @@ -36,7 +36,13 @@ interface UploadMediaDialogProps { media_type: number; }) => void; afterUploadSight?: (id: string) => void; - hardcodeType?: "thumbnail" | "watermark_lu" | "watermark_rd" | "image" | null; + hardcodeType?: + | "thumbnail" + | "watermark_lu" + | "watermark_rd" + | "image" + | "video_preview" + | null; contextObjectName?: string; contextType?: | "sight" @@ -47,6 +53,7 @@ interface UploadMediaDialogProps { | "station"; isArticle?: boolean; articleName?: string; + initialFile?: File; // <--- добавлено } export const UploadMediaDialog = observer( @@ -60,6 +67,7 @@ export const UploadMediaDialog = observer( isArticle, articleName, + initialFile, // <--- добавлено }: UploadMediaDialogProps) => { const [isLoading, setIsLoading] = useState(false); const [error, setError] = useState(null); @@ -74,6 +82,17 @@ export const UploadMediaDialog = observer( [] ); + useEffect(() => { + if (initialFile) { + setMediaFile(initialFile); + setMediaFilename(initialFile.name); + setAvailableMediaTypes([2]); + setMediaType(2); + setMediaUrl(URL.createObjectURL(initialFile)); + setMediaName(initialFile.name.replace(/\.[^/.]+$/, "")); + } + }, [initialFile]); + useEffect(() => { if (fileToUpload) { setMediaFile(fileToUpload); @@ -226,6 +245,10 @@ export const UploadMediaDialog = observer( } } setSuccess(true); + // Закрываем модальное окно после успешного сохранения + setTimeout(() => { + handleClose(); + }, 1000); // Небольшая задержка, чтобы пользователь увидел сообщение об успехе } catch (err) { setError(err instanceof Error ? err.message : "Failed to save media"); } finally { @@ -333,10 +356,15 @@ export const UploadMediaDialog = observer( diff --git a/src/shared/store/DevicesStore/index.tsx b/src/shared/store/DevicesStore/index.tsx index ff165dc..7132096 100644 --- a/src/shared/store/DevicesStore/index.tsx +++ b/src/shared/store/DevicesStore/index.tsx @@ -12,6 +12,7 @@ class DevicesStore { getDevices = async () => { const response = await authInstance.get(`${API_URL}/devices/connected`); + runInAction(() => { this.devices = response.data; }); diff --git a/src/widgets/DevicesTable/index.tsx b/src/widgets/DevicesTable/index.tsx index 5e9962d..f119d37 100644 --- a/src/widgets/DevicesTable/index.tsx +++ b/src/widgets/DevicesTable/index.tsx @@ -174,6 +174,7 @@ export const DevicesTable = observer(() => { setSelectedDevice(uuid); // Sets the device in the store, useful for context elsewhere try { await authInstance.post(`/devices/${uuid}/request-status`); + await getVehicles(); await getDevices(); // Refresh devices to show updated status } catch (error) { console.error(`Error requesting status for device ${uuid}:`, error); @@ -398,7 +399,6 @@ export const DevicesTable = observer(() => { devices.find((device) => device === row.device_uuid) ) { await handleReloadStatus(row.device_uuid); - await getDevices(); toast.success("Статус устройства обновлен"); } else { toast.error("Нет связи с устройством"); diff --git a/src/widgets/Layout/index.tsx b/src/widgets/Layout/index.tsx index 0f218f3..1b4c982 100644 --- a/src/widgets/Layout/index.tsx +++ b/src/widgets/Layout/index.tsx @@ -59,7 +59,6 @@ export const Layout: React.FC = observer(({ children }) => {
{(() => { - console.log(authStore.payload); return ( <>

diff --git a/src/widgets/SightTabs/CreateInformationTab/index.tsx b/src/widgets/SightTabs/CreateInformationTab/index.tsx index 96bcf1e..106ef98 100644 --- a/src/widgets/SightTabs/CreateInformationTab/index.tsx +++ b/src/widgets/SightTabs/CreateInformationTab/index.tsx @@ -5,6 +5,10 @@ import { Autocomplete, MenuItem, Menu as MuiMenu, + Dialog, + DialogTitle, + DialogContent, + DialogActions, } from "@mui/material"; import { BackButton, @@ -20,7 +24,12 @@ import { UploadMediaDialog, MEDIA_TYPE_VALUES, } from "@shared"; -import { ImageUploadCard, LanguageSwitcher } from "@widgets"; +import { + ImageUploadCard, + LanguageSwitcher, + VideoPreviewCard, + MediaViewer, +} from "@widgets"; import { Save } from "lucide-react"; import { observer } from "mobx-react-lite"; @@ -45,13 +54,15 @@ export const CreateInformationTab = observer( // Menu state for each media button const [menuAnchorEl, setMenuAnchorEl] = useState(null); const [activeMenuType, setActiveMenuType] = useState< - "thumbnail" | "watermark_lu" | "watermark_rd" | null + "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null >(null); const [isAddMediaOpen, setIsAddMediaOpen] = useState(false); + const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); const [hardcodeType, setHardcodeType] = useState< - "thumbnail" | "watermark_lu" | "watermark_rd" | null + "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null >(null); + useEffect(() => {}, [hardcodeType]); // const handleMenuOpen = ( // event: React.MouseEvent, // type: "thumbnail" | "watermark_lu" | "watermark_rd" @@ -100,7 +111,7 @@ export const CreateInformationTab = observer( media_name?: string; media_type: number; }, - type: "thumbnail" | "watermark_lu" | "watermark_rd" + type: "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" ) => { handleChange({ [type]: media.id, @@ -108,6 +119,12 @@ export const CreateInformationTab = observer( setActiveMenuType(null); }; + const handleVideoPreviewClick = () => { + if (sight.video_preview && sight.video_preview !== "") { + setIsVideoPreviewOpen(true); + } + }; + return ( <> @@ -329,6 +346,29 @@ export const CreateInformationTab = observer( setHardcodeType("watermark_rd"); }} /> + + { + handleChange({ + video_preview: null, + }); + }} + onSelectVideoClick={(file) => { + if (file) { + // Если передан файл, открываем диалог загрузки медиа + createSightStore.setFileToUpload(file); + setActiveMenuType("video_preview"); + setIsUploadMediaOpen(true); + } else { + // Если файл не передан, открываем диалог выбора существующих медиа + setActiveMenuType("video_preview"); + setIsAddMediaOpen(true); + } + }} + /> @@ -390,7 +430,9 @@ export const CreateInformationTab = observer( setActiveMenuType(null); }} onSelectMedia={(media) => { - handleMediaSelect(media, activeMenuType ?? "thumbnail"); + if (activeMenuType) { + handleMediaSelect(media, activeMenuType); + } }} mediaType={ activeMenuType @@ -413,14 +455,49 @@ export const CreateInformationTab = observer( contextObjectName={sight[language].name} contextType="sight" afterUpload={(media) => { - handleChange({ - [activeMenuType ?? "thumbnail"]: media.id, - }); + if (activeMenuType === "video_preview") { + handleChange({ + video_preview: media.id, + }); + } else { + handleChange({ + [activeMenuType ?? "thumbnail"]: media.id, + }); + } setActiveMenuType(null); setIsUploadMediaOpen(false); }} - hardcodeType={hardcodeType} + hardcodeType={activeMenuType} + initialFile={createSightStore.fileToUpload || undefined} /> + + {/* Модальное окно предпросмотра видео */} + {sight.video_preview && sight.video_preview !== "" && ( +

setIsVideoPreviewOpen(false)} + maxWidth="md" + fullWidth + > + Предпросмотр видео + + + + + + + + + + )} ); } diff --git a/src/widgets/SightTabs/InformationTab/index.tsx b/src/widgets/SightTabs/InformationTab/index.tsx index 9331fd7..fbd2cb5 100644 --- a/src/widgets/SightTabs/InformationTab/index.tsx +++ b/src/widgets/SightTabs/InformationTab/index.tsx @@ -5,6 +5,10 @@ import { Autocomplete, MenuItem, Menu as MuiMenu, + Dialog, + DialogTitle, + DialogContent, + DialogActions, } from "@mui/material"; import { BackButton, @@ -20,7 +24,12 @@ import { UploadMediaDialog, MEDIA_TYPE_VALUES, } from "@shared"; -import { ImageUploadCard, LanguageSwitcher } from "@widgets"; +import { + ImageUploadCard, + LanguageSwitcher, + VideoPreviewCard, + MediaViewer, +} from "@widgets"; import { Save } from "lucide-react"; import { observer } from "mobx-react-lite"; @@ -45,13 +54,17 @@ export const InformationTab = observer( // Menu state for each media button const [menuAnchorEl, setMenuAnchorEl] = useState(null); const [activeMenuType, setActiveMenuType] = useState< - "thumbnail" | "watermark_lu" | "watermark_rd" | null + "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null >(null); const [isAddMediaOpen, setIsAddMediaOpen] = useState(false); + const [isVideoPreviewOpen, setIsVideoPreviewOpen] = useState(false); const [hardcodeType, setHardcodeType] = useState< - "thumbnail" | "watermark_lu" | "watermark_rd" | null + "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" | null >(null); const { cities } = cityStore; + + useEffect(() => {}, [hardcodeType]); + useEffect(() => { // Показывать только при инициализации (не менять при ошибках пользователя) if (sight.common.latitude !== 0 || sight.common.longitude !== 0) { @@ -74,22 +87,28 @@ export const InformationTab = observer( handleMenuClose(); }; - const handleMediaSelect = (media: { - id: string; - filename: string; - media_name?: string; - media_type: number; - }) => { - if (!activeMenuType) return; + const handleMediaSelect = ( + media: { + id: string; + filename: string; + media_name?: string; + media_type: number; + }, + type: "thumbnail" | "watermark_lu" | "watermark_rd" | "video_preview" + ) => { handleChange( language as Language, { - [activeMenuType ?? "thumbnail"]: media.id, + [type]: media.id, }, true ); + }; - setIsUploadMediaOpen(false); + const handleVideoPreviewClick = () => { + if (sight.common.video_preview && sight.common.video_preview !== "") { + setIsVideoPreviewOpen(true); + } }; const handleChange = ( @@ -337,6 +356,33 @@ export const InformationTab = observer( setHardcodeType("watermark_rd"); }} /> + + { + handleChange( + language as Language, + { + video_preview: null, + }, + true + ); + }} + onSelectVideoClick={(file) => { + if (file) { + // Если передан файл, открываем диалог загрузки медиа + editSightStore.setFileToUpload(file); + setActiveMenuType("video_preview"); + setIsUploadMediaOpen(true); + } else { + // Если файл не передан, открываем диалог выбора существующих медиа + setActiveMenuType("video_preview"); + setIsAddMediaOpen(true); + } + }} + /> @@ -395,8 +441,13 @@ export const InformationTab = observer( open={isAddMediaOpen} onClose={() => { setIsAddMediaOpen(false); + setActiveMenuType(null); + }} + onSelectMedia={(media) => { + if (activeMenuType) { + handleMediaSelect(media, activeMenuType); + } }} - onSelectMedia={handleMediaSelect} mediaType={ activeMenuType ? MEDIA_TYPE_VALUES[ @@ -412,23 +463,62 @@ export const InformationTab = observer( contextObjectName={sight[language].name} contextType="sight" afterUpload={(media) => { - handleChange( - language as Language, - { - [activeMenuType ?? "thumbnail"]: media.id, - }, - true - ); + if (activeMenuType === "video_preview") { + handleChange( + language as Language, + { + video_preview: media.id, + }, + true + ); + } else { + handleChange( + language as Language, + { + [activeMenuType ?? "thumbnail"]: media.id, + }, + true + ); + } setActiveMenuType(null); setIsUploadMediaOpen(false); }} - hardcodeType={hardcodeType} + hardcodeType={activeMenuType} + initialFile={editSightStore.fileToUpload || undefined} /> setIsPreviewMediaOpen(false)} mediaId={mediaId} /> + + {/* Модальное окно предпросмотра видео */} + {sight.common.video_preview && sight.common.video_preview !== "" && ( + setIsVideoPreviewOpen(false)} + maxWidth="md" + fullWidth + > + Предпросмотр видео + + + + + + + + + + )} ); } diff --git a/src/widgets/VideoPreviewCard/index.tsx b/src/widgets/VideoPreviewCard/index.tsx new file mode 100644 index 0000000..416ebad --- /dev/null +++ b/src/widgets/VideoPreviewCard/index.tsx @@ -0,0 +1,203 @@ +import React, { useRef, useState, DragEvent, useEffect } from "react"; +import { Paper, Box, Typography, Button, Tooltip } from "@mui/material"; +import { X, Info, Plus, Play } from "lucide-react"; + +import { toast } from "react-toastify"; + +interface VideoPreviewCardProps { + title: string; + videoId: string | null | undefined; + onVideoClick: () => void; + onDeleteVideoClick: () => void; + onSelectVideoClick: (file?: File) => void; + tooltipText?: string; +} + +export const VideoPreviewCard: React.FC = ({ + title, + videoId, + onVideoClick, + onDeleteVideoClick, + onSelectVideoClick, + tooltipText, +}) => { + const fileInputRef = useRef(null); + const [isDragOver, setIsDragOver] = useState(false); + const token = localStorage.getItem("token"); + + useEffect(() => {}, [isDragOver]); + // --- Click to select file --- + const handleZoneClick = () => { + // Trigger the hidden file input click + fileInputRef.current?.click(); + }; + + const handleFileInputChange = async ( + event: React.ChangeEvent + ) => { + const file = event.target.files?.[0]; + if (file) { + if (file.type.startsWith("video/")) { + // Открываем диалог загрузки медиа с файлом видео + onSelectVideoClick(file); + } else { + toast.error("Пожалуйста, выберите видео файл"); + } + } + // Reset the input value so selecting the same file again triggers change + event.target.value = ""; + }; + + // --- Drag and Drop Handlers --- + const handleDragOver = (event: DragEvent) => { + event.preventDefault(); // Crucial to allow a drop + event.stopPropagation(); + setIsDragOver(true); + }; + + const handleDragLeave = (event: DragEvent) => { + event.preventDefault(); + event.stopPropagation(); + setIsDragOver(false); + }; + + const handleDrop = async (event: DragEvent) => { + event.preventDefault(); // Crucial to allow a drop + event.stopPropagation(); + setIsDragOver(false); + + const files = event.dataTransfer.files; + if (files && files.length > 0) { + const file = files[0]; + if (file.type.startsWith("video/")) { + // Открываем диалог загрузки медиа с файлом видео + onSelectVideoClick(file); + } else { + toast.error("Пожалуйста, выберите видео файл"); + } + } + }; + + return ( + + + + {title} + + {tooltipText && ( + + + + )} + + + {videoId && ( + + )} + {videoId ? ( + + + ) : ( +
+
+

Перетащите файл

+
+ +

или

+ + {/* Hidden file input */} + +
+ )} +
+
+ ); +}; diff --git a/src/widgets/index.ts b/src/widgets/index.ts index d054c18..80952c2 100644 --- a/src/widgets/index.ts +++ b/src/widgets/index.ts @@ -12,6 +12,7 @@ export * from "./MediaArea"; export * from "./ModelViewer3D"; export * from "./MediaAreaForSight"; export * from "./ImageUploadCard"; +export * from "./VideoPreviewCard"; export * from "./LeaveAgree"; export * from "./DeleteModal"; export * from "./SnapshotRestore"; diff --git a/tsconfig.tsbuildinfo b/tsconfig.tsbuildinfo index 532c895..140a5a9 100644 --- a/tsconfig.tsbuildinfo +++ b/tsconfig.tsbuildinfo @@ -1 +1 @@ -{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/app/index.tsx","./src/app/router/index.tsx","./src/entities/index.ts","./src/entities/navigation/index.ts","./src/entities/navigation/model/index.ts","./src/entities/navigation/ui/index.tsx","./src/features/index.ts","./src/features/navigation/index.ts","./src/features/navigation/ui/index.tsx","./src/pages/index.ts","./src/pages/article/index.ts","./src/pages/article/articlecreatepage/index.tsx","./src/pages/article/articleeditpage/index.tsx","./src/pages/article/articlelistpage/index.tsx","./src/pages/article/articlepreviewpage/previewleftwidget.tsx","./src/pages/article/articlepreviewpage/previewrightwidget.tsx","./src/pages/article/articlepreviewpage/index.tsx","./src/pages/carrier/index.ts","./src/pages/carrier/carriercreatepage/index.tsx","./src/pages/carrier/carriereditpage/index.tsx","./src/pages/carrier/carrierlistpage/index.tsx","./src/pages/city/index.ts","./src/pages/city/citycreatepage/index.tsx","./src/pages/city/cityeditpage/index.tsx","./src/pages/city/citylistpage/index.tsx","./src/pages/city/citypreviewpage/index.tsx","./src/pages/country/index.ts","./src/pages/country/countryaddpage/index.tsx","./src/pages/country/countrycreatepage/index.tsx","./src/pages/country/countryeditpage/index.tsx","./src/pages/country/countrylistpage/index.tsx","./src/pages/country/countrypreviewpage/index.tsx","./src/pages/createsightpage/index.tsx","./src/pages/devicespage/index.tsx","./src/pages/editsightpage/index.tsx","./src/pages/loginpage/index.tsx","./src/pages/mainpage/index.tsx","./src/pages/mappage/index.tsx","./src/pages/mappage/mapstore.ts","./src/pages/media/index.ts","./src/pages/media/mediacreatepage/index.tsx","./src/pages/media/mediaeditpage/index.tsx","./src/pages/media/medialistpage/index.tsx","./src/pages/media/mediapreviewpage/index.tsx","./src/pages/route/linekedstations.tsx","./src/pages/route/index.ts","./src/pages/route/routecreatepage/index.tsx","./src/pages/route/routeeditpage/index.tsx","./src/pages/route/routelistpage/index.tsx","./src/pages/route/route-preview/constants.ts","./src/pages/route/route-preview/infinitecanvas.tsx","./src/pages/route/route-preview/leftsidebar.tsx","./src/pages/route/route-preview/mapdatacontext.tsx","./src/pages/route/route-preview/rightsidebar.tsx","./src/pages/route/route-preview/sight.tsx","./src/pages/route/route-preview/sightinfowidget.tsx","./src/pages/route/route-preview/station.tsx","./src/pages/route/route-preview/transformcontext.tsx","./src/pages/route/route-preview/travelpath.tsx","./src/pages/route/route-preview/widgets.tsx","./src/pages/route/route-preview/index.tsx","./src/pages/route/route-preview/types.ts","./src/pages/route/route-preview/utils.ts","./src/pages/sight/index.ts","./src/pages/sight/sightlistpage/index.tsx","./src/pages/sightpage/index.tsx","./src/pages/snapshot/index.ts","./src/pages/snapshot/snapshotcreatepage/index.tsx","./src/pages/snapshot/snapshotlistpage/index.tsx","./src/pages/station/linkedsights.tsx","./src/pages/station/index.ts","./src/pages/station/stationcreatepage/index.tsx","./src/pages/station/stationeditpage/index.tsx","./src/pages/station/stationlistpage/index.tsx","./src/pages/station/stationpreviewpage/index.tsx","./src/pages/user/index.ts","./src/pages/user/usercreatepage/index.tsx","./src/pages/user/usereditpage/index.tsx","./src/pages/user/userlistpage/index.tsx","./src/pages/vehicle/index.ts","./src/pages/vehicle/vehiclecreatepage/index.tsx","./src/pages/vehicle/vehicleeditpage/index.tsx","./src/pages/vehicle/vehiclelistpage/index.tsx","./src/pages/vehicle/vehiclepreviewpage/index.tsx","./src/shared/index.tsx","./src/shared/api/index.tsx","./src/shared/config/carriersvg.tsx","./src/shared/config/constants.tsx","./src/shared/config/index.ts","./src/shared/const/index.ts","./src/shared/lib/index.ts","./src/shared/lib/decodejwt/index.ts","./src/shared/lib/mui/theme.ts","./src/shared/modals/index.ts","./src/shared/modals/previewmediadialog/index.tsx","./src/shared/modals/selectarticledialog/index.tsx","./src/shared/modals/selectmediadialog/index.tsx","./src/shared/modals/uploadmediadialog/index.tsx","./src/shared/store/index.ts","./src/shared/store/articlesstore/index.tsx","./src/shared/store/authstore/index.tsx","./src/shared/store/carrierstore/index.tsx","./src/shared/store/citystore/index.ts","./src/shared/store/countrystore/index.ts","./src/shared/store/createsightstore/index.tsx","./src/shared/store/devicesstore/index.tsx","./src/shared/store/editsightstore/index.tsx","./src/shared/store/languagestore/index.tsx","./src/shared/store/mediastore/index.tsx","./src/shared/store/routestore/index.ts","./src/shared/store/sightsstore/index.tsx","./src/shared/store/snapshotstore/index.ts","./src/shared/store/stationsstore/index.ts","./src/shared/store/userstore/index.ts","./src/shared/store/vehiclestore/index.ts","./src/shared/ui/index.ts","./src/shared/ui/backbutton/index.tsx","./src/shared/ui/coordinatesinput/index.tsx","./src/shared/ui/input/index.tsx","./src/shared/ui/modal/index.tsx","./src/shared/ui/tabpanel/index.tsx","./src/widgets/index.ts","./src/widgets/createbutton/index.tsx","./src/widgets/deletemodal/index.tsx","./src/widgets/devicestable/index.tsx","./src/widgets/imageuploadcard/index.tsx","./src/widgets/languageswitcher/index.tsx","./src/widgets/layout/index.tsx","./src/widgets/layout/ui/appbar.tsx","./src/widgets/layout/ui/drawer.tsx","./src/widgets/layout/ui/drawerheader.tsx","./src/widgets/leaveagree/index.tsx","./src/widgets/mediaarea/index.tsx","./src/widgets/mediaareaforsight/index.tsx","./src/widgets/mediaviewer/threeview.tsx","./src/widgets/mediaviewer/index.tsx","./src/widgets/modelviewer3d/index.tsx","./src/widgets/reactmarkdown/index.tsx","./src/widgets/reactmarkdowneditor/index.tsx","./src/widgets/sightedit/index.tsx","./src/widgets/sightheader/index.ts","./src/widgets/sightheader/ui/index.tsx","./src/widgets/sighttabs/index.ts","./src/widgets/sighttabs/createinformationtab/mediauploadbox.tsx","./src/widgets/sighttabs/createinformationtab/index.tsx","./src/widgets/sighttabs/createlefttab/index.tsx","./src/widgets/sighttabs/createrighttab/index.tsx","./src/widgets/sighttabs/informationtab/index.tsx","./src/widgets/sighttabs/leftwidgettab/index.tsx","./src/widgets/sighttabs/rightwidgettab/index.tsx","./src/widgets/sightstable/index.tsx","./src/widgets/snapshotrestore/index.tsx","./src/widgets/modals/editstationmodal.tsx","./src/widgets/modals/index.ts","./src/widgets/modals/selectarticledialog/index.tsx"],"version":"5.8.3"} \ No newline at end of file +{"root":["./src/main.tsx","./src/vite-env.d.ts","./src/app/index.tsx","./src/app/router/index.tsx","./src/entities/index.ts","./src/entities/navigation/index.ts","./src/entities/navigation/model/index.ts","./src/entities/navigation/ui/index.tsx","./src/features/index.ts","./src/features/navigation/index.ts","./src/features/navigation/ui/index.tsx","./src/pages/index.ts","./src/pages/article/index.ts","./src/pages/article/articlecreatepage/index.tsx","./src/pages/article/articleeditpage/index.tsx","./src/pages/article/articlelistpage/index.tsx","./src/pages/article/articlepreviewpage/previewleftwidget.tsx","./src/pages/article/articlepreviewpage/previewrightwidget.tsx","./src/pages/article/articlepreviewpage/index.tsx","./src/pages/carrier/index.ts","./src/pages/carrier/carriercreatepage/index.tsx","./src/pages/carrier/carriereditpage/index.tsx","./src/pages/carrier/carrierlistpage/index.tsx","./src/pages/city/index.ts","./src/pages/city/citycreatepage/index.tsx","./src/pages/city/cityeditpage/index.tsx","./src/pages/city/citylistpage/index.tsx","./src/pages/city/citypreviewpage/index.tsx","./src/pages/country/index.ts","./src/pages/country/countryaddpage/index.tsx","./src/pages/country/countrycreatepage/index.tsx","./src/pages/country/countryeditpage/index.tsx","./src/pages/country/countrylistpage/index.tsx","./src/pages/country/countrypreviewpage/index.tsx","./src/pages/createsightpage/index.tsx","./src/pages/devicespage/index.tsx","./src/pages/editsightpage/index.tsx","./src/pages/loginpage/index.tsx","./src/pages/mainpage/index.tsx","./src/pages/mappage/index.tsx","./src/pages/mappage/mapstore.ts","./src/pages/media/index.ts","./src/pages/media/mediacreatepage/index.tsx","./src/pages/media/mediaeditpage/index.tsx","./src/pages/media/medialistpage/index.tsx","./src/pages/media/mediapreviewpage/index.tsx","./src/pages/route/linekedstations.tsx","./src/pages/route/index.ts","./src/pages/route/routecreatepage/index.tsx","./src/pages/route/routeeditpage/index.tsx","./src/pages/route/routelistpage/index.tsx","./src/pages/route/route-preview/constants.ts","./src/pages/route/route-preview/infinitecanvas.tsx","./src/pages/route/route-preview/leftsidebar.tsx","./src/pages/route/route-preview/mapdatacontext.tsx","./src/pages/route/route-preview/rightsidebar.tsx","./src/pages/route/route-preview/sight.tsx","./src/pages/route/route-preview/sightinfowidget.tsx","./src/pages/route/route-preview/station.tsx","./src/pages/route/route-preview/transformcontext.tsx","./src/pages/route/route-preview/travelpath.tsx","./src/pages/route/route-preview/widgets.tsx","./src/pages/route/route-preview/index.tsx","./src/pages/route/route-preview/types.ts","./src/pages/route/route-preview/utils.ts","./src/pages/sight/index.ts","./src/pages/sight/sightlistpage/index.tsx","./src/pages/sightpage/index.tsx","./src/pages/snapshot/index.ts","./src/pages/snapshot/snapshotcreatepage/index.tsx","./src/pages/snapshot/snapshotlistpage/index.tsx","./src/pages/station/linkedsights.tsx","./src/pages/station/index.ts","./src/pages/station/stationcreatepage/index.tsx","./src/pages/station/stationeditpage/index.tsx","./src/pages/station/stationlistpage/index.tsx","./src/pages/station/stationpreviewpage/index.tsx","./src/pages/user/index.ts","./src/pages/user/usercreatepage/index.tsx","./src/pages/user/usereditpage/index.tsx","./src/pages/user/userlistpage/index.tsx","./src/pages/vehicle/index.ts","./src/pages/vehicle/vehiclecreatepage/index.tsx","./src/pages/vehicle/vehicleeditpage/index.tsx","./src/pages/vehicle/vehiclelistpage/index.tsx","./src/pages/vehicle/vehiclepreviewpage/index.tsx","./src/shared/index.tsx","./src/shared/api/index.tsx","./src/shared/config/carriersvg.tsx","./src/shared/config/constants.tsx","./src/shared/config/index.ts","./src/shared/const/index.ts","./src/shared/lib/index.ts","./src/shared/lib/decodejwt/index.ts","./src/shared/lib/mui/theme.ts","./src/shared/modals/index.ts","./src/shared/modals/previewmediadialog/index.tsx","./src/shared/modals/selectarticledialog/index.tsx","./src/shared/modals/selectmediadialog/index.tsx","./src/shared/modals/uploadmediadialog/index.tsx","./src/shared/store/index.ts","./src/shared/store/articlesstore/index.tsx","./src/shared/store/authstore/index.tsx","./src/shared/store/carrierstore/index.tsx","./src/shared/store/citystore/index.ts","./src/shared/store/countrystore/index.ts","./src/shared/store/createsightstore/index.tsx","./src/shared/store/devicesstore/index.tsx","./src/shared/store/editsightstore/index.tsx","./src/shared/store/languagestore/index.tsx","./src/shared/store/mediastore/index.tsx","./src/shared/store/routestore/index.ts","./src/shared/store/sightsstore/index.tsx","./src/shared/store/snapshotstore/index.ts","./src/shared/store/stationsstore/index.ts","./src/shared/store/userstore/index.ts","./src/shared/store/vehiclestore/index.ts","./src/shared/ui/index.ts","./src/shared/ui/backbutton/index.tsx","./src/shared/ui/coordinatesinput/index.tsx","./src/shared/ui/input/index.tsx","./src/shared/ui/modal/index.tsx","./src/shared/ui/tabpanel/index.tsx","./src/widgets/index.ts","./src/widgets/createbutton/index.tsx","./src/widgets/deletemodal/index.tsx","./src/widgets/devicestable/index.tsx","./src/widgets/imageuploadcard/index.tsx","./src/widgets/languageswitcher/index.tsx","./src/widgets/layout/index.tsx","./src/widgets/layout/ui/appbar.tsx","./src/widgets/layout/ui/drawer.tsx","./src/widgets/layout/ui/drawerheader.tsx","./src/widgets/leaveagree/index.tsx","./src/widgets/mediaarea/index.tsx","./src/widgets/mediaareaforsight/index.tsx","./src/widgets/mediaviewer/threeview.tsx","./src/widgets/mediaviewer/index.tsx","./src/widgets/modelviewer3d/index.tsx","./src/widgets/reactmarkdown/index.tsx","./src/widgets/reactmarkdowneditor/index.tsx","./src/widgets/sightedit/index.tsx","./src/widgets/sightheader/index.ts","./src/widgets/sightheader/ui/index.tsx","./src/widgets/sighttabs/index.ts","./src/widgets/sighttabs/createinformationtab/mediauploadbox.tsx","./src/widgets/sighttabs/createinformationtab/index.tsx","./src/widgets/sighttabs/createlefttab/index.tsx","./src/widgets/sighttabs/createrighttab/index.tsx","./src/widgets/sighttabs/informationtab/index.tsx","./src/widgets/sighttabs/leftwidgettab/index.tsx","./src/widgets/sighttabs/rightwidgettab/index.tsx","./src/widgets/sightstable/index.tsx","./src/widgets/snapshotrestore/index.tsx","./src/widgets/videopreviewcard/index.tsx","./src/widgets/modals/editstationmodal.tsx","./src/widgets/modals/index.ts","./src/widgets/modals/selectarticledialog/index.tsx"],"version":"5.8.3"} \ No newline at end of file