feat: Improved status display.
This commit is contained in:
+77
-43
@@ -15,7 +15,7 @@ import { SYNC_BANNER_PADDING_X, SYNC_BANNER_PADDING_Y, SYNC_BANNER_MIN_WIDTH } f
|
||||
import ServerPanel from './components/ServerPanel';
|
||||
import StrategySelector from './components/StrategySelector';
|
||||
import ConnectionModal from './components/ConnectionModal';
|
||||
import { ArrowLeftRight, ShieldCheck, X, Server, ServerOff, Clock, Eye, EyeOff, Type, Code2 } from 'lucide-react';
|
||||
import { ArrowLeftRight, ShieldCheck, X, Server, ServerOff, Clock, Eye, EyeOff, Type, Code2, Archive } from 'lucide-react';
|
||||
|
||||
interface Toast {
|
||||
id: number;
|
||||
@@ -519,7 +519,7 @@ const App: React.FC = () => {
|
||||
|
||||
const getScheduleDisplayInfo = () => {
|
||||
const result = {
|
||||
label: 'Schedule',
|
||||
label: 'Auto-Sync',
|
||||
value: 'Not configured',
|
||||
active: false,
|
||||
autoWatch: scheduleSettings.autoWatch
|
||||
@@ -531,13 +531,19 @@ const App: React.FC = () => {
|
||||
return result;
|
||||
}
|
||||
|
||||
let label = 'Schedule';
|
||||
if (scheduleSettings.mode === ScheduleMode.CRON) label = 'Cron Schedule';
|
||||
else if (scheduleSettings.mode === ScheduleMode.DAILY) label = 'Daily Schedule';
|
||||
else if (scheduleSettings.mode === ScheduleMode.WEEKLY) label = 'Weekly Schedule';
|
||||
let label = 'Auto-Sync';
|
||||
if (scheduleSettings.mode === ScheduleMode.CRON) label = 'Cron-Sync';
|
||||
else if (scheduleSettings.mode === ScheduleMode.DAILY) label = 'Daily-Sync';
|
||||
else if (scheduleSettings.mode === ScheduleMode.WEEKLY) label = 'Weekly-Sync';
|
||||
|
||||
result.label = label;
|
||||
result.value = nextRunTime ? `Next: ${nextRunTime}` : 'Calculating...';
|
||||
|
||||
if (scheduleSettings.mode === ScheduleMode.CRON && !scheduleSettings.cronExpression) {
|
||||
result.value = 'Not Set';
|
||||
} else {
|
||||
result.value = nextRunTime ? `${nextRunTime}` : 'Calculating...';
|
||||
}
|
||||
|
||||
result.active = true;
|
||||
return result;
|
||||
};
|
||||
@@ -549,13 +555,16 @@ const App: React.FC = () => {
|
||||
let count = 0;
|
||||
let modeLabel = '';
|
||||
let Icon = Type;
|
||||
let label = 'Mapping';
|
||||
|
||||
if (config.mode === PathMappingMode.SIMPLE) {
|
||||
modeLabel = 'Simple';
|
||||
label = 'Simple-Mapping';
|
||||
count = config.simple.length;
|
||||
Icon = Type;
|
||||
} else {
|
||||
modeLabel = 'Regex';
|
||||
label = 'Regex-Mapping';
|
||||
count = config.regex.localPre.length +
|
||||
config.regex.localPost.length +
|
||||
config.regex.remotePre.length +
|
||||
@@ -565,7 +574,7 @@ const App: React.FC = () => {
|
||||
|
||||
if (count === 0) {
|
||||
return {
|
||||
label: 'Path Mapping',
|
||||
label: 'Mapping',
|
||||
value: 'Not Set',
|
||||
active: false,
|
||||
Icon: Icon
|
||||
@@ -573,7 +582,7 @@ const App: React.FC = () => {
|
||||
}
|
||||
|
||||
return {
|
||||
label: 'Path Mapping',
|
||||
label: label,
|
||||
value: `${modeLabel} (${count})`,
|
||||
active: true,
|
||||
Icon: Icon
|
||||
@@ -582,6 +591,24 @@ const App: React.FC = () => {
|
||||
|
||||
const pathMappingInfo = getPathMappingDisplayInfo(pathMappingConfig);
|
||||
|
||||
// Helper: Calculate Backup Info
|
||||
const getBackupDisplayInfo = (settings: BackupSettings) => {
|
||||
if (!settings.enabled) {
|
||||
return {
|
||||
label: 'Backups',
|
||||
value: 'Disabled',
|
||||
active: false
|
||||
};
|
||||
}
|
||||
return {
|
||||
label: 'Backups',
|
||||
value: `Keep ${settings.retentionCount}`,
|
||||
active: true
|
||||
};
|
||||
};
|
||||
|
||||
const backupInfo = getBackupDisplayInfo(backupSettings);
|
||||
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col bg-gray-900 text-gray-100 font-sans overflow-hidden bg-[radial-gradient(ellipse_at_top,_var(--tw-gradient-stops))] from-gray-800 via-gray-900 to-black">
|
||||
|
||||
@@ -655,46 +682,53 @@ const App: React.FC = () => {
|
||||
|
||||
{/* Normal Toolbar Right */}
|
||||
<div className="flex items-center gap-4">
|
||||
{/* Path Mapping Info */}
|
||||
<div className="flex flex-col items-end hidden md:flex border-r border-gray-700/50 pr-4 mr-1">
|
||||
<span className="text-[10px] uppercase font-bold text-gray-500 tracking-wider">
|
||||
{pathMappingInfo.label}
|
||||
</span>
|
||||
<div className={`text-xs font-mono flex items-center gap-1.5 ${pathMappingInfo.active ? 'text-plex-orange' : 'text-gray-600'}`}>
|
||||
{pathMappingInfo.active && <pathMappingInfo.Icon size={12} />}
|
||||
<span>{pathMappingInfo.value}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Unified Status Dock */}
|
||||
<div className="hidden md:flex items-center bg-gray-900/40 border border-gray-700/50 rounded-lg p-1 mr-2 backdrop-blur-sm shadow-sm transition-all hover:bg-gray-900/60 hover:border-gray-600/50">
|
||||
|
||||
{/* Path Mapping Section */}
|
||||
<div className="flex flex-col px-3 py-0.5 border-r border-gray-700/30 w-[120px] group/item">
|
||||
<span className={`text-[9px] font-bold uppercase tracking-widest transition-colors ${pathMappingInfo.active ? 'text-plex-orange' : 'text-gray-500 group-hover/item:text-gray-400'}`}>{pathMappingInfo.label}</span>
|
||||
<div className={`flex items-center gap-1.5 text-xs font-medium ${pathMappingInfo.active ? 'text-blue-400' : 'text-gray-600'}`}>
|
||||
<pathMappingInfo.Icon size={12} strokeWidth={2.5} className="flex-shrink-0" />
|
||||
<span className="truncate">{pathMappingInfo.value === 'Not Set' ? 'None' : pathMappingInfo.value}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Schedule Info */}
|
||||
<div className="flex flex-col items-end mr-2 md:mr-0 hidden md:flex">
|
||||
<span className="text-[10px] uppercase font-bold text-gray-500 tracking-wider">
|
||||
{scheduleInfo.label}
|
||||
</span>
|
||||
<div className="text-xs font-mono flex items-center gap-1.5">
|
||||
{/* Schedule Part */}
|
||||
<div className={`flex items-center gap-1.5 ${scheduleInfo.active ? 'text-plex-orange' : 'text-gray-600'}`}>
|
||||
{scheduleInfo.active && <Clock size={12} />}
|
||||
<span>{scheduleInfo.value}</span>
|
||||
</div>
|
||||
{/* Backup Section */}
|
||||
<div className="flex flex-col px-3 py-0.5 border-r border-gray-700/30 w-[100px] group/item">
|
||||
<span className={`text-[9px] font-bold uppercase tracking-widest transition-colors ${backupInfo.active ? 'text-plex-orange' : 'text-gray-500 group-hover/item:text-gray-400'}`}>{backupInfo.label}</span>
|
||||
<div className={`flex items-center gap-1.5 text-xs font-medium ${backupInfo.active ? 'text-indigo-400' : 'text-gray-600'}`}>
|
||||
<Archive size={12} strokeWidth={2.5} className="flex-shrink-0" />
|
||||
<span className="truncate">{backupInfo.active ? backupInfo.value.replace('Keep ', 'Retain: ') : 'Disabled'}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Watch Part */}
|
||||
<span className="text-gray-700 mx-0.5">|</span>
|
||||
<div
|
||||
className={`flex items-center gap-1 ${scheduleInfo.autoWatch ? 'text-plex-orange' : 'text-gray-600'}`}
|
||||
title={scheduleInfo.autoWatch ? "Local Playlist Monitoring Enabled" : "Local Playlist Monitoring Disabled"}
|
||||
>
|
||||
{scheduleInfo.autoWatch ? <Eye size={12} /> : <EyeOff size={12} />}
|
||||
<span className="text-[10px] font-sans font-bold">WATCH</span>
|
||||
</div>
|
||||
</div>
|
||||
{/* Schedule Section */}
|
||||
<div className="flex flex-col px-3 py-0.5 w-[180px] group/item">
|
||||
<div className="flex items-center justify-between">
|
||||
<span className={`text-[9px] font-bold uppercase tracking-widest transition-colors ${scheduleInfo.active ? 'text-plex-orange' : 'text-gray-500 group-hover/item:text-gray-400'}`}>{scheduleInfo.label}</span>
|
||||
{/* Watch Indicator Badge */}
|
||||
<div
|
||||
className={`flex items-center gap-1 px-1 rounded-[2px] transition-colors ${scheduleInfo.autoWatch ? 'text-plex-orange bg-plex-orange/10' : 'text-gray-700 bg-gray-800'}`}
|
||||
title={scheduleInfo.autoWatch ? "Watch Mode: Active" : "Watch Mode: Disabled"}
|
||||
>
|
||||
{scheduleInfo.autoWatch ? <Eye size={9} /> : <EyeOff size={9} />}
|
||||
<span className="text-[8px] font-bold uppercase">Watch</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={`flex items-center gap-1.5 text-xs font-medium mt-0.5 ${scheduleInfo.active ? 'text-green-400' : 'text-gray-600'}`}>
|
||||
<Clock size={12} strokeWidth={2.5} className="flex-shrink-0" />
|
||||
<span className="truncate">{scheduleInfo.active ? scheduleInfo.value : 'Disabled'}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Connection Status Button */}
|
||||
<button
|
||||
<button
|
||||
onClick={() => setIsConnectionModalOpen(true)}
|
||||
className={`flex items-center justify-center w-9 h-9 rounded-full border transition-all duration-300 hover:scale-105 active:scale-95 shadow-md ${
|
||||
isConnected
|
||||
className={`flex items-center justify-center w-9 h-9 rounded-full border transition-all duration-300 hover:scale-105 active:scale-95 shadow-md
|
||||
${isConnected
|
||||
? "bg-green-500/10 border-green-500/50 text-green-400 hover:bg-green-500/20 hover:shadow-green-500/20"
|
||||
: "bg-red-500/10 border-red-500/50 text-red-400 hover:bg-red-500/20 hover:shadow-red-500/20"
|
||||
}`}
|
||||
|
||||
Reference in New Issue
Block a user