Port UI changes from sample-front-end: toggle switches, Eye icon, Link icon

Co-authored-by: Koha9 <36852125+Koha9@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2025-12-04 07:13:19 +00:00
parent 1bb07d7f68
commit 7b14445387
2 changed files with 69 additions and 54 deletions
+64 -54
View File
@@ -16,10 +16,10 @@ import {
Calendar, Calendar,
Clock, Clock,
Repeat, Repeat,
CheckSquare,
Square,
Type, Type,
Code2 Code2,
Link,
Eye
} from 'lucide-react'; } from 'lucide-react';
// Generate a UUID for mapping rules // Generate a UUID for mapping rules
@@ -104,17 +104,12 @@ const MAPPING_THEME = {
const deriveEffectiveSchedule = (schedule: ScheduleSettings, tab: ScheduleMode): ScheduleSettings => { const deriveEffectiveSchedule = (schedule: ScheduleSettings, tab: ScheduleMode): ScheduleSettings => {
const derived = { ...schedule }; const derived = { ...schedule };
if (tab === ScheduleMode.CRON) { // Unified logic: If the mode matches the tab, we keep it (Enabled).
derived.mode = derived.cronExpression.trim() !== '' ? ScheduleMode.CRON : ScheduleMode.DISABLED; // If the mode doesn't match (e.g. it was DISABLED), then in the context of this tab, it remains Disabled until the user toggles the switch.
if (derived.mode === tab) {
derived.mode = tab;
} else { } else {
// For Daily/Weekly derived.mode = ScheduleMode.DISABLED;
// If the mode matches the tab, we keep it (Enabled).
// If the mode doesn't match (e.g. it was CRON or DISABLED), then in the context of this tab, it is effectively Disabled until the user checks the box.
if (derived.mode === tab) {
derived.mode = tab;
} else {
derived.mode = ScheduleMode.DISABLED;
}
} }
return derived; return derived;
}; };
@@ -200,7 +195,7 @@ const MappingGroupEditor: React.FC<MappingGroupEditorProps> = ({
onChange={(e) => handleUpdate(rule.id, 'search', e.target.value)} onChange={(e) => handleUpdate(rule.id, 'search', e.target.value)}
className={`flex-1 min-w-0 border rounded px-1.5 py-1 text-xs focus:outline-none transition-colors ${leftInputClass || defaultInputStyle}`} className={`flex-1 min-w-0 border rounded px-1.5 py-1 text-xs focus:outline-none transition-colors ${leftInputClass || defaultInputStyle}`}
/> />
<ArrowRightCircle size={10} className="text-gray-600 flex-none opacity-50" /> <Link size={12} className="text-gray-600 flex-none opacity-50" />
<input <input
type="text" type="text"
placeholder={rightPlaceholder} placeholder={rightPlaceholder}
@@ -634,35 +629,49 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
{/* Tab Content */} {/* Tab Content */}
<div className="mb-4 min-h-[50px]"> <div className="mb-4 min-h-[50px]">
{activeScheduleTab === ScheduleMode.CRON && ( {activeScheduleTab === ScheduleMode.CRON && (
<div className="space-y-2 animate-in fade-in duration-200"> <div className="flex flex-col animate-in fade-in duration-200">
<div className="flex items-center space-x-2"> {/* Top Row: Label + Switch */}
<span className="text-gray-500 font-mono text-xs">Cron:</span> <div className="flex items-center justify-between mb-3 px-1">
<input <span className="text-xs text-gray-400 font-medium">Enable Cron Schedule</span>
type="text" <button
value={localSchedule.cronExpression} onClick={() => toggleScheduleEnable(ScheduleMode.CRON)}
onChange={(e) => handleUpdateSchedule('cronExpression', e.target.value)} className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-plex-orange focus:ring-offset-2 focus:ring-offset-gray-900 ${localSchedule.mode === ScheduleMode.CRON ? 'bg-plex-orange' : 'bg-gray-700'}`}
placeholder="0 0 * * *" >
className="flex-1 bg-gray-800 border border-gray-700 rounded-md px-2.5 py-1.5 text-xs text-gray-200 font-mono focus:border-plex-orange focus:outline-none focus:ring-1 focus:ring-plex-orange placeholder-gray-600" <span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSchedule.mode === ScheduleMode.CRON ? 'translate-x-6' : 'translate-x-1'}`} />
/> </button>
</div>
{/* Content */}
<div className={`space-y-2 transition-opacity duration-200 ${localSchedule.mode !== ScheduleMode.CRON ? 'opacity-50 pointer-events-none' : ''}`}>
<div className="flex items-center space-x-2">
<span className="text-gray-500 font-mono text-xs">Cron:</span>
<input
type="text"
value={localSchedule.cronExpression}
onChange={(e) => handleUpdateSchedule('cronExpression', e.target.value)}
placeholder="0 0 * * *"
disabled={localSchedule.mode !== ScheduleMode.CRON}
className="flex-1 bg-gray-800 border border-gray-700 rounded-md px-2.5 py-1.5 text-xs text-gray-200 font-mono focus:border-plex-orange focus:outline-none focus:ring-1 focus:ring-plex-orange placeholder-gray-600"
/>
</div>
<p className="text-[10px] text-gray-500">
Unix-cron format.
</p>
</div> </div>
<p className="text-[10px] text-gray-500">
Unix-cron format. Leave empty to disable schedule.
</p>
</div> </div>
)} )}
{activeScheduleTab === ScheduleMode.DAILY && ( {activeScheduleTab === ScheduleMode.DAILY && (
<div className="flex flex-col animate-in fade-in duration-200"> <div className="flex flex-col animate-in fade-in duration-200">
{/* Top Row: Checkbox + Label */} {/* Top Row: Label + Switch */}
<div className="flex items-center justify-start space-x-2 mb-2"> <div className="flex items-center justify-between mb-3 px-1">
<span className="text-xs text-gray-400 font-medium">Enable Daily Run</span>
<button <button
onClick={() => toggleScheduleEnable(ScheduleMode.DAILY)} onClick={() => toggleScheduleEnable(ScheduleMode.DAILY)}
className={`transition-colors flex-none ${localSchedule.mode === ScheduleMode.DAILY ? 'text-plex-orange' : 'text-gray-500 hover:text-gray-400'}`} className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-plex-orange focus:ring-offset-2 focus:ring-offset-gray-900 ${localSchedule.mode === ScheduleMode.DAILY ? 'bg-plex-orange' : 'bg-gray-700'}`}
title={localSchedule.mode === ScheduleMode.DAILY ? "Schedule Enabled" : "Schedule Disabled"}
> >
{localSchedule.mode === ScheduleMode.DAILY ? <CheckSquare size={16} /> : <Square size={16} />} <span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSchedule.mode === ScheduleMode.DAILY ? 'translate-x-6' : 'translate-x-1'}`} />
</button> </button>
<label className="text-xs text-gray-400 font-medium">Run daily at:</label>
</div> </div>
{/* Bottom Row: Centered Native Time Input */} {/* Bottom Row: Centered Native Time Input */}
@@ -680,16 +689,15 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
{activeScheduleTab === ScheduleMode.WEEKLY && ( {activeScheduleTab === ScheduleMode.WEEKLY && (
<div className="flex flex-col animate-in fade-in duration-200"> <div className="flex flex-col animate-in fade-in duration-200">
{/* Top Row: Checkbox + Label */} {/* Top Row: Label + Switch */}
<div className="flex items-center justify-start space-x-2 mb-2"> <div className="flex items-center justify-between mb-3 px-1">
<button <span className="text-xs text-gray-400 font-medium">Enable Weekly Run</span>
<button
onClick={() => toggleScheduleEnable(ScheduleMode.WEEKLY)} onClick={() => toggleScheduleEnable(ScheduleMode.WEEKLY)}
className={`transition-colors flex-none ${localSchedule.mode === ScheduleMode.WEEKLY ? 'text-plex-orange' : 'text-gray-500 hover:text-gray-400'}`} className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-plex-orange focus:ring-offset-2 focus:ring-offset-gray-900 ${localSchedule.mode === ScheduleMode.WEEKLY ? 'bg-plex-orange' : 'bg-gray-700'}`}
title={localSchedule.mode === ScheduleMode.WEEKLY ? "Schedule Enabled" : "Schedule Disabled"} >
> <span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSchedule.mode === ScheduleMode.WEEKLY ? 'translate-x-6' : 'translate-x-1'}`} />
{localSchedule.mode === ScheduleMode.WEEKLY ? <CheckSquare size={16} /> : <Square size={16} />} </button>
</button>
<label className="text-xs text-gray-400 font-medium">Run on days:</label>
</div> </div>
{/* Middle Row: Full Width Capsules */} {/* Middle Row: Full Width Capsules */}
@@ -728,20 +736,22 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
)} )}
</div> </div>
{/* Auto Watch Checkbox */} {/* Auto Watch Switch */}
<div className="flex items-center mb-4 px-1"> <div className="flex items-center justify-between mb-4 mt-2 px-1">
<div className="flex items-center space-x-2">
<div className="p-1.5 rounded-lg bg-orange-500/10 border border-orange-500/20 text-orange-400">
<Eye size={16} />
</div>
<div className="flex flex-col">
<span className="text-sm font-medium text-gray-200">Watch Local Changes</span>
<span className="text-[10px] text-gray-500">Auto-sync when local playlist updates</span>
</div>
</div>
<button <button
onClick={() => handleUpdateSchedule('autoWatch', !localSchedule.autoWatch)} onClick={() => handleUpdateSchedule('autoWatch', !localSchedule.autoWatch)}
className="flex items-center space-x-2 group" className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-plex-orange focus:ring-offset-2 focus:ring-offset-gray-900 ${localSchedule.autoWatch ? 'bg-plex-orange' : 'bg-gray-700'}`}
> >
{localSchedule.autoWatch ? ( <span className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${localSchedule.autoWatch ? 'translate-x-6' : 'translate-x-1'}`} />
<CheckSquare size={16} className="text-plex-orange" />
) : (
<Square size={16} className="text-gray-600 group-hover:text-gray-400" />
)}
<span className={`text-xs ${localSchedule.autoWatch ? 'text-gray-200' : 'text-gray-500 group-hover:text-gray-400'}`}>
Watch for local playlist changes
</span>
</button> </button>
</div> </div>
+5
View File
@@ -58,6 +58,11 @@ export interface PathMappingConfig {
regex: PathMappingRules; regex: PathMappingRules;
} }
export interface BackupSettings {
enabled: boolean;
retentionCount: number;
}
export interface RegexReplacement { export interface RegexReplacement {
id: string; id: string;
pattern: string; pattern: string;