feat: big update 07.05.26

This commit is contained in:
2026-05-07 13:08:33 +03:00
parent 6af95bb449
commit d758dbffa6
39 changed files with 1233 additions and 814 deletions

View File

@@ -628,41 +628,57 @@ export const DevicesTable = observer(() => {
justifyContent: "center",
}}
>
{canWriteDevices && (
<button
onClick={(e) => {
e.stopPropagation();
navigate(`/vehicle/${row.vehicle_id}/edit`);
}}
title="Редактировать транспорт"
>
<Pencil size={16} />
</button>
{!isMaintenanceOnly && (
<>
{canWriteDevices && (
<button
onClick={(e) => {
e.stopPropagation();
navigate(`/vehicle/${row.vehicle_id}/edit`);
}}
title="Редактировать транспорт"
>
<Pencil size={16} />
</button>
)}
<button
onClick={(e) => {
e.stopPropagation();
handleReloadStatus();
}}
title="Перезапросить статус"
disabled={
!row.device_uuid || !devices.includes(row.device_uuid)
}
>
<RotateCcw size={16} />
</button>
<button
onClick={(e) => {
e.stopPropagation();
if (row.device_uuid) {
navigator.clipboard.writeText(row.device_uuid);
toast.success("UUID скопирован");
}
}}
title="Копировать UUID"
>
<Copy size={16} />
</button>
<button
onClick={(e) => {
e.stopPropagation();
if (row.device_uuid) {
setLogsModalDeviceUuid(row.device_uuid);
setLogsModalOpen(true);
}
}}
title="Логи устройства"
>
<ScrollText size={16} />
</button>
</>
)}
<button
onClick={(e) => {
e.stopPropagation();
handleReloadStatus();
}}
title="Перезапросить статус"
disabled={
!row.device_uuid || !devices.includes(row.device_uuid)
}
>
<RotateCcw size={16} />
</button>
<button
onClick={(e) => {
e.stopPropagation();
if (row.device_uuid) {
navigator.clipboard.writeText(row.device_uuid);
toast.success("UUID скопирован");
}
}}
title="Копировать UUID"
>
<Copy size={16} />
</button>
<button
onClick={(e) => {
e.stopPropagation();
@@ -674,18 +690,6 @@ export const DevicesTable = observer(() => {
>
<Wrench size={16} />
</button>
<button
onClick={(e) => {
e.stopPropagation();
if (row.device_uuid) {
setLogsModalDeviceUuid(row.device_uuid);
setLogsModalOpen(true);
}
}}
title="Логи устройства"
>
<ScrollText size={16} />
</button>
</Box>
);
},
@@ -714,9 +718,11 @@ export const DevicesTable = observer(() => {
const visibleColumns = useMemo(() => {
if (isMaintenanceOnly) {
return columns.filter((c) =>
["model", "tail_number", "maintenance_mode_on"].includes(c.field),
);
return columns
.filter((c) =>
["model", "tail_number", "maintenance_mode_on", "actions"].includes(c.field),
)
.map((c) => ({ ...c, flex: 1, width: undefined, minWidth: undefined }));
}
if (!canWriteDevices) {
return columns.filter(
@@ -729,20 +735,26 @@ export const DevicesTable = observer(() => {
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
await Promise.all([
getVehicles(),
getDevices(),
getSnapshots(),
getRoutes(),
]);
if (isMaintenanceOnly) {
await Promise.all([getVehicles(), getDevices()]);
} else {
await Promise.all([
getVehicles(),
getDevices(),
getSnapshots(),
getRoutes(),
]);
}
setIsLoading(false);
};
fetchData();
}, [getDevices, getSnapshots, getVehicles, getRoutes]);
}, [getDevices, getSnapshots, getVehicles, getRoutes, isMaintenanceOnly]);
useEffect(() => {
carrierStore.getCarriers("ru");
}, []);
if (!isMaintenanceOnly) {
carrierStore.getCarriers("ru");
}
}, [isMaintenanceOnly]);
const handleOpenSendSnapshotModal = () => {
if (!canWriteDevices) {

View File

@@ -120,7 +120,6 @@ export const ReactMarkdownEditor = ({
"table",
"horizontal-rule",
"preview",
"fullscreen",
"guide",
],
};

View File

@@ -243,149 +243,123 @@ export const LeftWidgetTab = observer(
flex: 1,
display: "flex",
flexDirection: "column",
maxWidth: "320px",
maxWidth: "316px",
gap: 0.5,
}}
>
<Paper
elevation={3}
<Box
sx={{
width: "100%",
minWidth: 320,
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
overflowY: "auto",
width: "316px",
display: "flex",
flexDirection: "column",
alignItems: "center",
borderRadius: "10px",
background:
"linear-gradient(114deg, rgba(255,255,255,0) 8.71%, rgba(255,255,255,0.16) 69.69%), #006F3A",
}}
>
<Box
sx={{
overflow: "hidden",
width: "100%",
minHeight: 100,
padding: "3px",
position: "relative",
display: "flex",
alignItems: "center",
justifyContent: "center",
"& img": {
borderTopLeftRadius: "10px",
borderTopRightRadius: "10px",
width: "100%",
height: "auto",
objectFit: "contain",
},
}}
>
{data.left.media.length > 0 ? (
<>
<MediaViewer
media={{
id: data.left.media[0].id,
media_type: data.left.media[0].media_type,
filename: data.left.media[0].filename,
}}
fullWidth
/>
{sight.common.watermark_lu && (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
sight.common.watermark_lu
}/download?token=${token}`}
alt="preview"
className="absolute top-4 left-4 z-10"
style={{
width: "30px",
height: "30px",
objectFit: "contain",
}}
/>
)}
{sight.common.watermark_rd && (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${
sight.common.watermark_rd
}/download?token=${token}`}
alt="preview"
className="absolute bottom-4 right-4 z-10"
style={{
width: "30px",
height: "30px",
objectFit: "contain",
}}
/>
)}
</>
) : (
<ImagePlus size={48} color="white" />
)}
</Box>
<Box
sx={{
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
color: "white",
margin: "5px 0px 5px 0px",
display: "flex",
flexDirection: "column",
gap: 1,
padding: 1,
}}
>
<Typography
variant="h5"
component="h2"
{data.left.media.length > 0 ? (
<Box
sx={{
position: "relative",
width: "312px",
height: "175px",
margin: "2px 0px 2px 0px",
borderRadius: "10px 10px 0 0",
overflow: "hidden",
flexShrink: 0,
"& img, & video": {
width: "100%",
height: "100%",
objectFit: "cover",
borderRadius: "10px 10px 0 0",
},
}}
>
<MediaViewer
media={{
id: data.left.media[0].id,
media_type: data.left.media[0].media_type,
filename: data.left.media[0].filename,
}}
fullWidth
/>
{sight.common.watermark_lu && (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${sight.common.watermark_lu}/download?token=${token}`}
alt="preview"
className="absolute top-4 left-4 z-10"
style={{ width: "30px", height: "30px", objectFit: "contain" }}
/>
)}
{sight.common.watermark_rd && (
<img
src={`${import.meta.env.VITE_KRBL_MEDIA}${sight.common.watermark_rd}/download?token=${token}`}
alt="preview"
className="absolute bottom-4 right-4 z-10"
style={{ width: "30px", height: "30px", objectFit: "contain" }}
/>
)}
</Box>
) : (
<Box sx={{ display: "flex", justifyContent: "center", alignItems: "center", height: "175px" }}>
<ImagePlus size={48} color="white" />
</Box>
)}
<Box sx={{ padding: "0px 10px 20px 10px", width: "100%" }}>
<Box
component="div"
sx={{
color: "#fff",
fontFamily: "Roboto",
fontSize: "20px",
fontWeight: 600,
lineHeight: "150%",
wordBreak: "break-word",
fontSize: "24px",
fontWeight: 700,
lineHeight: "120%",
}}
>
{data?.left?.heading || "Название информации"}
</Typography>
<Typography
variant="h6"
component="h2"
</Box>
<Box
component="div"
sx={{
marginTop: "2px",
color: "#fff",
fontFamily: "Roboto",
fontSize: "16px",
fontWeight: 400,
lineHeight: "150%",
wordBreak: "break-word",
fontSize: "18px",
lineHeight: "120%",
}}
>
{sight[language as Language].address}
</Typography>
</Box>
{data?.left?.body && (
<Box
sx={{
padding: 1,
maxHeight: "300px",
overflowY: "auto",
width: "100%",
"&::-webkit-scrollbar": {
display: "none",
},
"&": {
scrollbarWidth: "none",
},
background:
"#806c59 linear-gradient(90deg, rgba(255, 255, 255, 0.2) 12.5%, rgba(255, 255, 255, 0.2) 100%)",
flexGrow: 1,
}}
>
<ReactMarkdownComponent value={data?.left?.body} />
</Box>
)}
</Paper>
{data?.left?.body && (
<Box
sx={{
marginTop: "15px",
maxHeight: "200px",
overflowY: "auto",
"&::-webkit-scrollbar": { display: "none" },
scrollbarWidth: "none",
"& p, & li, & h1, & h2, & h3": {
color: "#fff !important",
fontFamily: "Roboto, sans-serif !important",
fontSize: "16px !important",
fontWeight: "300 !important",
lineHeight: "135% !important",
marginTop: "0 !important",
marginBottom: "0 !important",
},
}}
>
<ReactMarkdownComponent value={data?.left?.body} />
</Box>
)}
</Box>
</Box>
</Box>
</Box>
)}

View File

@@ -12,7 +12,7 @@
rgba(255, 255, 255, 0) 8.71%,
rgba(255, 255, 255, 0.16) 69.69%
),
#806c59;
#006f3a;
}
.sfp-sight-frame-media-stack {
@@ -22,7 +22,6 @@
width: calc(100% - 4px);
height: 300px;
overflow: hidden;
background: #111;
}
.sfp-sight-frame-media-item {
@@ -67,21 +66,21 @@
.sfp-sight-frame-title {
display: flex;
align-items: center;
padding: 7px 16px;
padding: 10px 20px;
width: 100%;
text-align: left;
font-family: "Roboto";
font-size: 24px;
font-weight: 600;
line-height: 120%;
border-bottom: 1px solid rgba(255, 255, 255, 0.8);
border-bottom: 1px solid var(--Glass-stroke, rgba(255, 255, 255, 0.8));
background:
linear-gradient(
180deg,
rgba(255, 255, 255, 0.22) 0%,
rgba(255, 255, 255, 0.04) 100%
),
rgba(179, 165, 152, 0.72);
rgba(0, 111, 58, 0.72);
box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset;
box-sizing: border-box;
color: white;
@@ -118,7 +117,7 @@
padding: 16px;
box-sizing: border-box;
max-height: calc(80vh - 354px);
min-height: 80px;
min-height: 0;
overflow-y: auto;
display: flex;
flex-direction: column;
@@ -156,6 +155,9 @@
.sfp-sight-frame-text h3,
.sfp-sight-frame-text li {
color: #fff;
font-size: 18px;
line-height: 150%;
font-family: "Roboto";
}
.sfp-sight-frame-menu {
@@ -173,7 +175,7 @@
rgba(255, 255, 255, 0.2) 0%,
rgba(255, 255, 255, 0) 100%
),
rgba(179, 165, 152, 0.4);
rgba(0, 111, 58, 0.4);
box-shadow: 4px 4px 12px 0px rgba(255, 255, 255, 0.12) inset;
backdrop-filter: blur(10px);
box-sizing: border-box;
@@ -265,3 +267,4 @@
.sfp-sight-frame-media-stack.three-d-view {
background-color: #111 !important;
}