diff --git a/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/Reporter.kt b/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/Reporter.kt index 47fe693a..b0e91843 100644 --- a/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/Reporter.kt +++ b/apps/processer/src/main/kotlin/no/iktdev/mediaprocessing/processer/Reporter.kt @@ -4,6 +4,8 @@ import mu.KotlinLogging import no.iktdev.mediaprocessing.shared.common.SharedConfig import no.iktdev.mediaprocessing.shared.common.contract.dto.ProcesserEventInfo 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.messaging.simp.SimpMessagingTemplate import org.springframework.stereotype.Service @@ -20,37 +22,21 @@ class Reporter() { fun encodeTaskAssigned(task: Task) { - try { - messageTemplate.convertAndSend("/topic/encode/assigned", task) - } catch (e: Exception) { - //log.error { e.message } - } + messageTemplate.trySend("/topic/encode/assigned", task) } fun extractTaskAssigned(task: Task) { - try { - messageTemplate.convertAndSend("/topic/extract/assigned", task) - } catch (e: Exception) { - //log.error { e.message } - } + messageTemplate.trySend("/topic/extract/assigned", task) } fun sendEncodeProgress(progress: ProcesserEventInfo) { - try { - restTemplate.postForEntity(SharedConfig.uiUrl + "/encode/progress", progress, String::class.java) - messageTemplate.convertAndSend("/topic/encode/progress", progress) - } catch (e: Exception) { - //log.error { e.message } - } + restTemplate.tryPost(SharedConfig.uiUrl + "/encode/progress", progress) + messageTemplate.trySend("/topic/encode/progress", progress) } fun sendExtractProgress(progress: ProcesserEventInfo) { - try { - restTemplate.postForEntity(SharedConfig.uiUrl + "/extract/progress", progress, String::class.java) - messageTemplate.convertAndSend("/topic/extract/progress", progress) - } catch (e: Exception) { - //log.error { e.message } - } + restTemplate.tryPost(SharedConfig.uiUrl + "/extract/progress", progress) + messageTemplate.trySend("/topic/extract/progress", progress) } } \ No newline at end of file diff --git a/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt b/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt index 14c82c64..99a7b017 100644 --- a/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt +++ b/apps/ui/src/main/kotlin/no/iktdev/mediaprocessing/ui/explorer/ExplorerCore.kt @@ -73,4 +73,21 @@ class ExplorerCore { 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 + ) + }, + ) + } + } \ No newline at end of file diff --git a/apps/ui/web/src/app/page/ExplorePage.tsx b/apps/ui/web/src/app/page/ExplorePage.tsx index 0b0880b4..53820ceb 100644 --- a/apps/ui/web/src/app/page/ExplorePage.tsx +++ b/apps/ui/web/src/app/page/ExplorePage.tsx @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; 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 { RootState } from '../store'; 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 { canConvert, canEncode, canExtract } from '../../fileUtil'; import SimpleTable from '../features/table/sortableTable'; +import TagIcon from '@mui/icons-material/Tag'; const createTableCell: TableCellCustomizer = (accessor, data) => { @@ -46,20 +47,76 @@ const columns: Array = [ +type Segment = { + name: string; + absolutePath: string; +}; + +function isWindowsPath(path: string): boolean { + return /^[A-Za-z]:\\/.test(path); +} + function getPartFor(path: string, index: number): string | null { - if (path.match(/\//)) { - return path.split(/\//, index + 1).join("/"); - } else if (path.match(/\\/)) { - return path.split(/\\/, index + 1).join("\\"); + 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; } -function getSegmentedNaviagatablePath(navigateTo: (path: string | null) => void, path: string | null): JSX.Element { - console.log(path); - const parts: Array = path?.split(/\\|\//).map((value: string, index: number) => value.replaceAll(":", "")) ?? []; - const segments = parts.map((name: string, index: number) => { - console.log(name) +function getSegments(absolutePath: string): Array { + if (!absolutePath) return []; + + const isWindows = isWindowsPath(absolutePath); + 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 ( void, - {index < parts.length - 1 && } + { segments.length > 1 && index < segments.length - 1 && } ) }); - console.log(parts) return ( - {segments} + {isWindowsPath(path!) && ( + + rootClick()} > + + + + + )} + {utElements} ) } @@ -229,6 +300,12 @@ export default function ExplorePage() { }) } + const onRootClick = () => { + client?.publish({ + destination: "/app/explorer/root" + }) + } + useWsSubscription("/topic/explorer/go", (response) => { dispatch(updateItems(response)) }); @@ -275,7 +352,7 @@ export default function ExplorePage() { borderRadius: 5, backgroundColor: muiTheme.palette.divider }}> - {getSegmentedNaviagatablePath(navigateTo, cursor?.path)} + {getSegmentedNaviagatablePath(onRootClick, navigateTo, cursor?.path)} diff --git a/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt b/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt index 0b0bdad7..1b219195 100644 --- a/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt +++ b/shared/common/src/main/kotlin/no/iktdev/mediaprocessing/shared/common/Utils.kt @@ -2,6 +2,9 @@ package no.iktdev.mediaprocessing.shared.common import kotlinx.coroutines.delay 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.FileInputStream import java.io.RandomAccessFile @@ -163,3 +166,15 @@ fun getChecksum(filePath: String): String { } return sb.toString() } + +inline fun 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) +} \ No newline at end of file