diff --git a/Posterizarr.ps1 b/Posterizarr.ps1 index b1e7908a..b3a87853 100755 --- a/Posterizarr.ps1 +++ b/Posterizarr.ps1 @@ -53,7 +53,7 @@ for ($i = 0; $i -lt $ExtraArgs.Count; $i++) { } } -$CurrentScriptVersion = "2.2.13" +$CurrentScriptVersion = "2.2.14" $global:HeaderWritten = $false $ProgressPreference = 'SilentlyContinue' $env:PSMODULE_ANALYSIS_CACHE_PATH = $null @@ -5721,7 +5721,6 @@ function MassDownloadPlexArtwork { try { if ($($entry.RootFoldername)) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:posterurl = $null $global:ImageMagickError = $null $global:TMDBfallbackposterurl = $null @@ -5787,7 +5786,6 @@ function MassDownloadPlexArtwork { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -5914,7 +5912,6 @@ function MassDownloadPlexArtwork { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -6025,7 +6022,6 @@ function MassDownloadPlexArtwork { if ($($entry.RootFoldername)) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -6231,7 +6227,6 @@ function MassDownloadPlexArtwork { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -6339,7 +6334,6 @@ function MassDownloadPlexArtwork { $global:PlexSeasonUrls = $entry.PlexSeasonUrls -split ',' for ($i = 0; $i -lt $global:seasonNames.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:posterurl = $null $global:seasontmp = $null $global:IsFallback = $null @@ -6475,7 +6469,6 @@ function MassDownloadPlexArtwork { # Loop through each episode foreach ($episode in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -6510,7 +6503,6 @@ function MassDownloadPlexArtwork { $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -10058,7 +10050,6 @@ Elseif ($Tautulli) { } Else { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:posterurl = $null $global:ImageMagickError = $null $global:TextlessPoster = $null @@ -10144,7 +10135,6 @@ Elseif ($Tautulli) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -10770,7 +10760,6 @@ Elseif ($Tautulli) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -11371,7 +11360,6 @@ Elseif ($Tautulli) { Else { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid @@ -12066,7 +12054,6 @@ Elseif ($Tautulli) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -12639,7 +12626,6 @@ Elseif ($Tautulli) { $global:PlexSeasonUrls = $entry.PlexSeasonUrls -split ',' for ($i = 0; $i -lt $global:seasonNames.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:seasontmp = $null $global:posterurl = $null @@ -13362,7 +13348,6 @@ Elseif ($Tautulli) { # Loop through each episode foreach ($episode in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -13402,7 +13387,6 @@ Elseif ($Tautulli) { $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -14037,7 +14021,6 @@ Elseif ($Tautulli) { Else { for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -15665,7 +15648,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -16224,7 +16206,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -16763,7 +16744,6 @@ Elseif ($ArrTrigger) { Else { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid @@ -17390,7 +17370,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -17881,7 +17860,6 @@ Elseif ($ArrTrigger) { # Loop through each Season foreach ($season in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:seasontmp = $null $global:IsFallback = $null @@ -18506,7 +18484,6 @@ Elseif ($ArrTrigger) { # Loop through each episode foreach ($episode in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -18545,7 +18522,6 @@ Elseif ($ArrTrigger) { $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -19058,7 +19034,6 @@ Elseif ($ArrTrigger) { Else { for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -20053,7 +20028,6 @@ Elseif ($ArrTrigger) { } Else { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:posterurl = $null $global:ImageMagickError = $null $global:TextlessPoster = $null @@ -20139,7 +20113,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -20763,7 +20736,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -21363,7 +21335,6 @@ Elseif ($ArrTrigger) { Else { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid @@ -22058,7 +22029,6 @@ Elseif ($ArrTrigger) { if (($FileTestOnTrigger -eq 'false') -or (-not $directoryHashtable.ContainsKey("$hashtestpath"))) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -22631,7 +22601,6 @@ Elseif ($ArrTrigger) { $global:PlexSeasonUrls = $entry.PlexSeasonUrls -split ',' for ($i = 0; $i -lt $global:seasonNames.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:seasontmp = $null $global:posterurl = $null @@ -23353,7 +23322,6 @@ Elseif ($ArrTrigger) { # Loop through each episode foreach ($episode in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -23393,7 +23361,6 @@ Elseif ($ArrTrigger) { $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -24028,7 +23995,6 @@ Elseif ($ArrTrigger) { Else { for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -26807,7 +26773,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -27367,7 +27332,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -27905,7 +27869,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer Else { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid @@ -28533,7 +28496,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -29023,7 +28985,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer # Loop through each Season foreach ($season in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:seasontmp = $null $global:IsFallback = $null @@ -29662,7 +29623,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer # Loop through each episode foreach ($episode in $Episodedata) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -29701,7 +29661,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -30214,7 +30173,6 @@ Elseif ($OtherMediaServerUrl -and $OtherMediaServerApiKey -and $UseOtherMediaSer Else { for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null @@ -31570,7 +31528,6 @@ else { } Else { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:posterurl = $null $global:ImageMagickError = $null $global:TMDBfallbackposterurl = $null @@ -31657,7 +31614,6 @@ else { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -32342,7 +32298,6 @@ else { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -33007,7 +32962,6 @@ else { Else { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbsearched = $null $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid @@ -33774,7 +33728,6 @@ else { if (-not $directoryHashtable.ContainsKey("$hashtestpath")) { # Define Global Variables $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:tmdbid = $entry.tmdbid $global:tvdbid = $entry.tvdbid $global:imdbid = $entry.imdbid @@ -34409,7 +34362,6 @@ else { $global:PlexSeasonUrls = $entry.PlexSeasonUrls -split ',' for ($i = 0; $i -lt $global:seasonNames.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $Seasonpostersearchtext = $null $global:seasontmp = $null $global:TextlessPoster = $null @@ -35250,7 +35202,6 @@ else { $global:ImageMagickError = $null for ($i = 0; $i -lt $global:episode_numbers.Count; $i++) { $SkippingText = 'false' - $SkipAddOverlay = 'false' $global:AssetTextLang = $null $global:TMDBAssetTextLang = $null $global:FANARTAssetTextLang = $null diff --git a/Release.txt b/Release.txt index 3c3ae886..14f29673 100644 --- a/Release.txt +++ b/Release.txt @@ -1 +1 @@ -2.2.13 \ No newline at end of file +2.2.14 \ No newline at end of file diff --git a/webui/backend/main.py b/webui/backend/main.py index 58561b35..5afd50ec 100644 --- a/webui/backend/main.py +++ b/webui/backend/main.py @@ -922,9 +922,9 @@ def determine_media_type(filename: str, library_folder: str = None) -> str: # Guess from folder name if DB lookup failed if library_folder: folder_lower = library_folder.lower() - if any(k in folder_lower for k in ["show", "series", "tv", "serien", "anime"]): + if any(k in folder_lower for k in ["show", "series", "tv", "serien"]): return "Show Background" - if any(k in folder_lower for k in ["movie", "film", "kino", "4k"]): + if any(k in folder_lower for k in ["movie", "film", "kino"]): return "Movie Background" return "Background" @@ -941,9 +941,9 @@ def determine_media_type(filename: str, library_folder: str = None) -> str: # Guess from folder name if DB lookup failed if library_folder: folder_lower = library_folder.lower() - if any(k in folder_lower for k in ["show", "series", "tv", "serien", "anime"]): + if any(k in folder_lower for k in ["show", "series", "tv", "serien"]): return "Show" - if any(k in folder_lower for k in ["movie", "film", "kino", "4k"]): + if any(k in folder_lower for k in ["movie", "film", "kino"]): return "Movie" # Default to Movie for unrecognized images diff --git a/webui/frontend/src/components/AssetReplacer.jsx b/webui/frontend/src/components/AssetReplacer.jsx index 417477af..4e90be2f 100644 --- a/webui/frontend/src/components/AssetReplacer.jsx +++ b/webui/frontend/src/components/AssetReplacer.jsx @@ -93,7 +93,7 @@ function AssetReplacer({ asset, onClose, onSuccess }) { // Find library name - usually the top-level folder like "4K" or "TV" for (let i = 0; i < pathSegments.length; i++) { // Common library folder names - if (pathSegments[i].match(/^(4K|TV|Movies|Series|anime)$/i)) { + if (pathSegments[i].match(/^(4K|TV|Movies|Series|Anime)$/i)) { libraryName = pathSegments[i]; console.log(`Found library name: ${libraryName}`); break; @@ -265,11 +265,20 @@ function AssetReplacer({ asset, onClose, onSuccess }) { // Determine mediaType const backendAssetType = (asset.type || "").toLowerCase(); const dbType = (dbData?.Type || "").toLowerCase(); - const libName = (libraryName || "").toLowerCase(); - let mediaType = "movie"; // Default + const libName = (libraryName || "").toLowerCase(); // Corrected variable name - if ( - dbType.includes("show") || + let mediaType = "movie"; // Default fallback + + // 1. STRICT DATABASE CHECK (Primary Source of Trust) + if (dbType.includes("movie")) { + mediaType = "movie"; + console.log("MediaType strictly determined by DB: movie"); + } else if (dbType.includes("show") || dbType.includes("series")) { + mediaType = "tv"; + console.log("MediaType strictly determined by DB: tv"); + } + // 2. HEURISTIC FALLBACK (Only used if DB data is missing/inconclusive) + else if ( backendAssetType.includes("show") || backendAssetType.includes("season") || backendAssetType.includes("episode") || @@ -278,10 +287,12 @@ function AssetReplacer({ asset, onClose, onSuccess }) { libName.includes("tv") || libName.includes("show") || libName.includes("series") || - libName.includes("serier") || - libName.includes("anime") + libName.includes("serier") ) { mediaType = "tv"; + console.log(`MediaType determined by fallback heuristics: ${mediaType}`); + } else { + console.log(`Defaulting to: ${mediaType}`); } console.log(`Backend asset.type: '${backendAssetType}'`); diff --git a/webui/frontend/src/components/Dashboard.jsx b/webui/frontend/src/components/Dashboard.jsx index d8b757ef..b7a5a676 100644 --- a/webui/frontend/src/components/Dashboard.jsx +++ b/webui/frontend/src/components/Dashboard.jsx @@ -45,7 +45,6 @@ const isDev = import.meta.env.DEV; const getLogFileForMode = (mode) => { const safeMode = (mode || "").toLowerCase(); - const logMapping = { testing: "Testinglog.log", manual: "Manuallog.log", @@ -156,7 +155,6 @@ function Dashboard() { const [draggedItem, setDraggedItem] = useState(null); const hasInitiallyLoaded = useRef(false); - // --- FETCH LOGIC --- const fetchDashboardData = async (silent = false) => { if (!silent) setIsRefreshing(true); try { @@ -244,7 +242,6 @@ function Dashboard() { } catch(e){} } - // --- WEBSOCKET LOGIC --- const connectDashboardWebSocket = () => { if (wsRef.current) return; try { @@ -281,7 +278,6 @@ function Dashboard() { if (wsRef.current) { wsRef.current.close(); wsRef.current = null; setWsConnected(false); } }; - // --- EFFECTS --- useEffect(() => { startLoading("dashboard"); fetchDashboardData(false); @@ -324,7 +320,6 @@ function Dashboard() { }); }, [allLogs, autoScroll]); - // Handle manual scroll detection to disable autoscroll useEffect(() => { const logContainer = logContainerRef.current; if (!logContainer) return; @@ -334,13 +329,10 @@ function Dashboard() { const currentScrollTop = scrollTop; const isAtBottom = scrollHeight - scrollTop - clientHeight < 20; - // Detect upward scroll (user scrolling up manually) if (currentScrollTop < lastScrollTop.current - 5) { userHasScrolled.current = true; if (autoScroll) setAutoScroll(false); } - - // If user scrolls to bottom manually, enable autoScroll again if (isAtBottom && !autoScroll) { setAutoScroll(true); userHasScrolled.current = false; @@ -363,7 +355,6 @@ function Dashboard() { } catch (error) { showError(error.message); } finally { setLoading(false); } }; - // --- UTILS --- const saveVisibilitySettings = (settings) => { setVisibleCards(settings); localStorage.setItem("dashboard_visible_cards", JSON.stringify(settings)); @@ -408,7 +399,6 @@ function Dashboard() { return { raw: cleanedLine }; }; - // Restored helper from Old Dashboard const LogLevel = ({ level }) => { const levelLower = (level || "").toLowerCase().trim(); const colors = { @@ -438,14 +428,13 @@ function Dashboard() { return colors[levelLower] || colors.default; }; - // --- UNIFIED CONTROL DECK COMPONENT --- const UnifiedControlDeck = () => { if (!visibleCards.statusCards) return null; return (
- {/* SECTION 1: SCRIPT ENGINE (The Core) */} + {/* SECTION 1: SCRIPT ENGINE */}
@@ -476,48 +465,114 @@ function Dashboard() {
- {/* SECTION 2: SCHEDULER (The Clock) */} + {/* SECTION 2: SCHEDULER */}
-
-
- {t("dashboard.controlDeck.scheduler")} - - {schedulerStatus.enabled ? (schedulerStatus.running ? t("dashboard.controlDeck.active") : t("dashboard.controlDeck.standby")) : t("dashboard.controlDeck.disabled")} - -
+
+ {/* Clickable Header for Redirection */} + + + {t("dashboard.controlDeck.scheduler")} + +
+ + {schedulerStatus.enabled ? (schedulerStatus.running ? t("dashboard.controlDeck.active") : t("dashboard.controlDeck.standby")) : t("dashboard.controlDeck.disabled")} + + +
+
- +
-
+
-
- {schedulerStatus.enabled && schedulerStatus.next_run ? ( -
-
- {t("dashboard.controlDeck.nextRun")} - {new Date(schedulerStatus.next_run).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'})} -
- {/* Visual Timeline Bar */} -
-
-
+
+ {schedulerStatus.enabled && schedulerStatus.schedules?.length > 0 ? (() => { + const now = new Date(); + const currentMinutes = now.getHours() * 60 + now.getMinutes(); + const totalMinutesInDay = 24 * 60; + const progressPercent = (currentMinutes / totalMinutesInDay) * 100; + + return ( +
+
+ {t("dashboard.controlDeck.nextRun")} + + {schedulerStatus.next_run ? new Date(schedulerStatus.next_run).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}) : '--:--'} + +
+ + {/* Timeline Container */} +
+ {/* Background Progress (Current Time) */} +
+ + {/* Current Time Indicator Line */} +
+ + {/* Schedule Ticks */} + {schedulerStatus.schedules.map((s, idx) => { + const [hours, minutes] = s.time.split(':').map(Number); + const scheduleMinutes = hours * 60 + minutes; + const position = (scheduleMinutes / totalMinutesInDay) * 100; + const isPast = scheduleMinutes < currentMinutes; + + return ( +
+ {/* Custom Hover Tooltip - Removed the help cursor logic */} +
+
+
+ {s.time} +
+
{s.description}
+
+ {isPast ? t("dashboard.controlDeck.completed") || 'Completed' : t("dashboard.controlDeck.upcoming") || 'Upcoming'} +
+ {/* Small Arrow */} +
+
+
+ ); + })} +
+ +
+ Start +
+ {Math.round(progressPercent)}% + {t("dashboard.controlDeck.ofDay") || 'of Day'} +
+ End +
-
- ) : ( -
+ ); + })() : ( +
{t("dashboard.controlDeck.noSchedules")} -
+
)} -
+
- {/* SECTION 3: SYSTEM (The Hardware - FULL DETAILS RESTORED) */} + {/* SECTION 3: SYSTEM */}
{t("dashboard.controlDeck.systemInfo")} - - {/* OS Platform & Version */}
{systemInfo.platform} @@ -534,9 +589,7 @@ function Dashboard() {
-
- {/* CPU Info */}
{t("dashboard.controlDeck.cpu")} @@ -547,8 +600,6 @@ function Dashboard() { {systemInfo.cpu_model || t("dashboard.controlDeck.genericCpu")}
- - {/* RAM Info - Full details */}
@@ -572,7 +623,7 @@ function Dashboard() {
- {/* SECTION 4: CONFIG (The Brain) */} + {/* SECTION 4: CONFIG */}
@@ -595,7 +646,6 @@ function Dashboard() {
-
{(version.local || version.remote) && (
@@ -623,21 +673,15 @@ function Dashboard() { ); }; - - // --- RENDER MAIN LAYOUT --- const renderDashboardCards = () => { const cardComponents = { statusCards: , - runtimeStats: visibleCards.runtimeStats && ( ), - recentAssets: visibleCards.recentAssets && ( ), - - // --- RESTORED OLD LOG VIEWER --- logViewer: visibleCards.logViewer && (
{t("dashboard.liveLogFeed")} - {wsConnected && (
@@ -661,7 +704,6 @@ function Dashboard() {
)}
- {status.running && status.active_log && allLogs.length > 0 && (

{ if (logContainerRef.current) { - logContainerRef.current.scrollTop = - logContainerRef.current.scrollHeight; + logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight; } }, 100); } @@ -702,11 +742,7 @@ function Dashboard() { className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors ${ autoScroll ? "bg-theme-primary" : "bg-theme-hover" }`} - title={ - autoScroll - ? t("dashboard.autoScrollEnabled") - : t("dashboard.autoScrollDisabled") - } + title={autoScroll ? t("dashboard.autoScrollEnabled") : t("dashboard.autoScrollDisabled")} >

-
{status.running && allLogs && allLogs.length > 0 ? (
{allLogs.map((line, index) => { const parsed = parseLogLine(line); - - if (parsed.raw === null) { - return null; - } - + if (parsed.raw === null) return null; if (parsed.raw) { return (
); } - const logColor = getLogColor(parsed.level); - return (
- - [{parsed.timestamp}] - + [{parsed.timestamp}] - - |L.{parsed.lineNum}| - + |L.{parsed.lineNum}| {parsed.message}
); @@ -771,29 +790,20 @@ function Dashboard() { ) : (
-

- {t("dashboard.noLogs")} -

+

{t("dashboard.noLogs")}

- {status.running - ? t("dashboard.waitingForLogs") - : t("dashboard.startRunToSeeLogs")} + {status.running ? t("dashboard.waitingForLogs") : t("dashboard.startRunToSeeLogs")}

)}
-
- {t("dashboard.autoRefresh")}:{" "} - {wsConnected ? t("dashboard.live") : "1.5s"} + {t("dashboard.autoRefresh")}: {wsConnected ? t("dashboard.live") : "1.5s"} - {t("dashboard.lastEntries", { count: 25 })} •{" "} - {status.current_mode - ? getLogFileForMode(status.current_mode) - : status.active_log || t("dashboard.noActiveLog")} + {t("dashboard.lastEntries", { count: 25 })} • {status.current_mode ? getLogFileForMode(status.current_mode) : status.active_log || t("dashboard.noActiveLog")}
@@ -802,18 +812,14 @@ function Dashboard() { return cardOrder.map((key) => { const component = cardComponents[key]; - if (key === "statusCards" && status.running) { return ( {component} - {/* Active Run Banner - Placed specifically after statusCards so it appears above the logs in standard order */}
-
- -
+

{t("dashboard.banners.executionInProgress")}

{t("dashboard.banners.reviewLogs")}

@@ -829,21 +835,16 @@ function Dashboard() { return (
- {/* Hero Section */}
-
-

- {t("dashboard.title")} -

+

{t("dashboard.title")}

{t("dashboard.welcome")}. {t("dashboard.status")}: {status.running ? t("dashboard.controlDeck.active").toLowerCase() : t("dashboard.controlDeck.idle").toLowerCase()}.

-
{!status.running && ( @@ -851,19 +852,12 @@ function Dashboard() { {t("dashboard.runScript")} )} - -
- - {/* Already Running Alert */} {status.already_running_detected && (
@@ -876,15 +870,9 @@ function Dashboard() {
)} - - {/* Main Content Grid */} {renderDashboardCards()} - - setDeleteConfirm(false)} onConfirm={deleteRunningFile} title={t("dashboard.deleteConfirmTitle")} message={t("dashboard.deleteConfirmMessage")} confirmText={t("common.delete")} type="warning" /> - - {/* Settings Modal */} {showCardsModal && (
@@ -895,19 +883,10 @@ function Dashboard() {
{cardOrder.map((key, idx) => (
handleDragStart(e, idx)} onDragOver={(e) => handleDragOver(e, idx)} onDragEnd={handleDragEnd} className={`p-3 rounded-xl border border-theme bg-theme-card flex items-center justify-between hover:border-theme-primary/50 transition-all cursor-move ${draggedItem === idx ? "opacity-50" : ""}`}> -
- - {cardLabels[key]} -
+
{cardLabels[key]}
toggleCardVisibility(key)} className="w-5 h-5 accent-theme-primary rounded cursor-pointer" />
))} -
-
- {t("dashboard.hideScrollbars") || "Hide Scrollbars"} - -
-
@@ -918,5 +897,4 @@ function Dashboard() {
); } - export default Dashboard; \ No newline at end of file diff --git a/webui/frontend/src/components/RecentAssets.jsx b/webui/frontend/src/components/RecentAssets.jsx index f782d5f1..fa58bbb6 100644 --- a/webui/frontend/src/components/RecentAssets.jsx +++ b/webui/frontend/src/components/RecentAssets.jsx @@ -351,13 +351,26 @@ function RecentAssets({ refreshTrigger = 0 }) {
- + {/* Enhanced Slider with Badge */} +
+
+ + {t("dashboard.assets")} + + {/* Dynamic Badge */} + + {assetCount} + +
+ + +