This commit is contained in:
bskjon 2025-03-19 18:48:38 +01:00
parent 01a5d21e69
commit a27e50f909
4 changed files with 133 additions and 38 deletions

View File

@ -4,6 +4,8 @@ import mu.KotlinLogging
import no.iktdev.mediaprocessing.shared.common.SharedConfig import no.iktdev.mediaprocessing.shared.common.SharedConfig
import no.iktdev.mediaprocessing.shared.common.contract.dto.ProcesserEventInfo import no.iktdev.mediaprocessing.shared.common.contract.dto.ProcesserEventInfo
import no.iktdev.mediaprocessing.shared.common.task.Task import no.iktdev.mediaprocessing.shared.common.task.Task
import no.iktdev.mediaprocessing.shared.common.tryPost
import no.iktdev.mediaprocessing.shared.common.trySend
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import org.springframework.messaging.simp.SimpMessagingTemplate import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
@ -20,37 +22,21 @@ class Reporter() {
fun encodeTaskAssigned(task: Task) { fun encodeTaskAssigned(task: Task) {
try { messageTemplate.trySend("/topic/encode/assigned", task)
messageTemplate.convertAndSend("/topic/encode/assigned", task)
} catch (e: Exception) {
//log.error { e.message }
}
} }
fun extractTaskAssigned(task: Task) { fun extractTaskAssigned(task: Task) {
try { messageTemplate.trySend("/topic/extract/assigned", task)
messageTemplate.convertAndSend("/topic/extract/assigned", task)
} catch (e: Exception) {
//log.error { e.message }
}
} }
fun sendEncodeProgress(progress: ProcesserEventInfo) { fun sendEncodeProgress(progress: ProcesserEventInfo) {
try { restTemplate.tryPost<String>(SharedConfig.uiUrl + "/encode/progress", progress)
restTemplate.postForEntity(SharedConfig.uiUrl + "/encode/progress", progress, String::class.java) messageTemplate.trySend("/topic/encode/progress", progress)
messageTemplate.convertAndSend("/topic/encode/progress", progress)
} catch (e: Exception) {
//log.error { e.message }
}
} }
fun sendExtractProgress(progress: ProcesserEventInfo) { fun sendExtractProgress(progress: ProcesserEventInfo) {
try { restTemplate.tryPost<String>(SharedConfig.uiUrl + "/extract/progress", progress)
restTemplate.postForEntity(SharedConfig.uiUrl + "/extract/progress", progress, String::class.java) messageTemplate.trySend("/topic/extract/progress", progress)
messageTemplate.convertAndSend("/topic/extract/progress", progress)
} catch (e: Exception) {
//log.error { e.message }
}
} }
} }

View File

@ -73,4 +73,21 @@ class ExplorerCore {
return getCursor(SharedConfig.inputRoot.absolutePath) return getCursor(SharedConfig.inputRoot.absolutePath)
} }
fun getRoots(): ExplorerCursor {
return ExplorerCursor(
name = "root",
path = "",
items = File.listRoots().map {
val attr = getAttr(it)
ExplorerItem(
path = it.absolutePath,
name = it.absolutePath,
extension = it.extension,
created = attr.created,
type = ExplorerItemType.FOLDER
)
},
)
}
} }

View File

@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import { UnixTimestamp } from '../features/UxTc'; import { UnixTimestamp } from '../features/UxTc';
import { Box, Button, Typography, useTheme } from '@mui/material'; import { Box, Button, IconButton, Typography, useTheme } from '@mui/material';
import { useDispatch, useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { RootState } from '../store'; import { RootState } from '../store';
import { TableCellCustomizer, TablePropetyConfig, TableRowActionEvents } from '../features/table/table'; import { TableCellCustomizer, TablePropetyConfig, TableRowActionEvents } from '../features/table/table';
@ -15,6 +15,7 @@ import { ExplorerItem, ExplorerCursor, ExplorerItemType } from '../../types';
import ContextMenu, { ContextMenuActionEvent, ContextMenuItem } from '../features/ContextMenu'; import ContextMenu, { ContextMenuActionEvent, ContextMenuItem } from '../features/ContextMenu';
import { canConvert, canEncode, canExtract } from '../../fileUtil'; import { canConvert, canEncode, canExtract } from '../../fileUtil';
import SimpleTable from '../features/table/sortableTable'; import SimpleTable from '../features/table/sortableTable';
import TagIcon from '@mui/icons-material/Tag';
const createTableCell: TableCellCustomizer<ExplorerItem> = (accessor, data) => { const createTableCell: TableCellCustomizer<ExplorerItem> = (accessor, data) => {
@ -46,20 +47,76 @@ const columns: Array<TablePropetyConfig> = [
function getPartFor(path: string, index: number): string | null { type Segment = {
if (path.match(/\//)) { name: string;
return path.split(/\//, index + 1).join("/"); absolutePath: string;
} else if (path.match(/\\/)) { };
return path.split(/\\/, index + 1).join("\\");
function isWindowsPath(path: string): boolean {
return /^[A-Za-z]:\\/.test(path);
} }
function getPartFor(path: string, index: number): string | null {
const separator = path.includes("/") ? "/" : "\\";
let parts: string[];
if (isWindowsPath(path)) {
parts = [path.slice(0, 3), ...path.slice(3).split(separator)];
} else if (path.startsWith(separator)) {
parts = [separator, ...path.slice(1).split(separator)];
} else {
parts = path.split(separator);
}
if (index < parts.length) {
// Unngå å legge til ekstra backslash for første element i Windows-path
if (isWindowsPath(path) && index === 0) {
return parts[0];
}
return parts.slice(0, index + 1).join(separator);
}
return null; return null;
} }
function getSegmentedNaviagatablePath(navigateTo: (path: string | null) => void, path: string | null): JSX.Element { function getSegments(absolutePath: string): Array<Segment> {
console.log(path); if (!absolutePath) return [];
const parts: Array<string> = path?.split(/\\|\//).map((value: string, index: number) => value.replaceAll(":", "")) ?? [];
const segments = parts.map((name: string, index: number) => { const isWindows = isWindowsPath(absolutePath);
console.log(name) const separator = isWindows ? "\\" : "/";
let parts: string[];
if (isWindows) {
parts = [absolutePath.slice(0, 3), ...absolutePath.slice(3).split(separator)];
} else if (absolutePath.startsWith(separator)) {
parts = [separator, ...absolutePath.slice(1).split(separator)];
} else {
parts = absolutePath.split(separator);
}
const segments = parts.map((value, index) => {
const name = isWindows && index === 0 ? value[0] : value;
return {
name: name.replaceAll(":", ""),
absolutePath: getPartFor(absolutePath, index)!
};
});
console.log({
segments: segments,
path: absolutePath
});
return segments.filter((segment) => segment.name !== "");
}
function getSegmentedNaviagatablePath(rootClick: () => void, navigateTo: (path: string | null) => void, path: string | null): JSX.Element {
const segments = getSegments(path!)
const utElements = segments.map((segment: Segment, index: number) => {
return ( return (
<Box key={index} sx={{ <Box key={index} sx={{
display: "flex", display: "flex",
@ -69,19 +126,33 @@ function getSegmentedNaviagatablePath(navigateTo: (path: string | null) => void,
<Button sx={{ <Button sx={{
borderRadius: 5, borderRadius: 5,
textTransform: 'none' textTransform: 'none'
}} onClick={() => navigateTo(getPartFor(path!, index))}> }} onClick={() => navigateTo(segment.absolutePath!)}>
<Typography>{name}</Typography> <Typography>{segment.name}</Typography>
</Button> </Button>
{index < parts.length - 1 && <IconForward fontSize="small" />} { segments.length > 1 && index < segments.length - 1 && <IconForward fontSize="small" />}
</Box> </Box>
) )
}); });
console.log(parts)
return ( return (
<Box display="flex"> <Box display="flex">
{segments} {isWindowsPath(path!) && (
<Box sx={{
display: "flex",
flexDirection: "row",
alignItems: "center"
}}>
<IconButton sx={{
borderRadius: 5,
textTransform: 'none'
}} onClick={() => rootClick()} >
<TagIcon />
</IconButton>
<IconForward fontSize="small" />
</Box>
)}
{utElements}
</Box> </Box>
) )
} }
@ -229,6 +300,12 @@ export default function ExplorePage() {
}) })
} }
const onRootClick = () => {
client?.publish({
destination: "/app/explorer/root"
})
}
useWsSubscription<ExplorerCursor>("/topic/explorer/go", (response) => { useWsSubscription<ExplorerCursor>("/topic/explorer/go", (response) => {
dispatch(updateItems(response)) dispatch(updateItems(response))
}); });
@ -275,7 +352,7 @@ export default function ExplorePage() {
borderRadius: 5, borderRadius: 5,
backgroundColor: muiTheme.palette.divider backgroundColor: muiTheme.palette.divider
}}> }}>
{getSegmentedNaviagatablePath(navigateTo, cursor?.path)} {getSegmentedNaviagatablePath(onRootClick, navigateTo, cursor?.path)}
</Box> </Box>
</Box> </Box>
</Box> </Box>

View File

@ -2,6 +2,9 @@ package no.iktdev.mediaprocessing.shared.common
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import mu.KotlinLogging import mu.KotlinLogging
import org.springframework.messaging.simp.SimpMessagingTemplate
import org.springframework.web.client.RestTemplate
import org.springframework.web.client.postForEntity
import java.io.File import java.io.File
import java.io.FileInputStream import java.io.FileInputStream
import java.io.RandomAccessFile import java.io.RandomAccessFile
@ -163,3 +166,15 @@ fun getChecksum(filePath: String): String {
} }
return sb.toString() return sb.toString()
} }
inline fun <reified T> RestTemplate.tryPost(url: String, data: Any, noinline onError: ((Exception) -> Unit)? = null) {
try {
this.postForEntity(url, data, T::class.java)
} catch (e: Exception) {
onError?.invoke(e)
}
}
fun SimpMessagingTemplate.trySend(destination: String, data: Any) {
this.convertAndSend(destination, data)
}