Compare commits
2 Commits
40f818bd2c
...
6f234ebc48
| Author | SHA1 | Date | |
|---|---|---|---|
| 6f234ebc48 | |||
| 305743d752 |
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import { SyncStrategy, RegexReplacement, SyncState, ScheduleSettings, ScheduleMode } from '../types';
|
import { SyncStrategy, RegexReplacement, SyncState, ScheduleSettings, ScheduleMode } from '../types';
|
||||||
import {
|
import {
|
||||||
@@ -61,6 +62,25 @@ const STRATEGIES: StrategyOption[] = [
|
|||||||
|
|
||||||
const WEEK_DAYS = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
const WEEK_DAYS = ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
|
||||||
|
|
||||||
|
// Helper to determine the actual mode and settings that would be saved based on the current UI state
|
||||||
|
const deriveEffectiveSchedule = (schedule: ScheduleSettings, tab: ScheduleMode): ScheduleSettings => {
|
||||||
|
const derived = { ...schedule };
|
||||||
|
|
||||||
|
if (tab === ScheduleMode.CRON) {
|
||||||
|
derived.mode = derived.cronExpression.trim() !== '' ? ScheduleMode.CRON : ScheduleMode.DISABLED;
|
||||||
|
} else {
|
||||||
|
// For Daily/Weekly
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
|
||||||
interface StrategySelectorProps {
|
interface StrategySelectorProps {
|
||||||
currentStrategy: SyncStrategy;
|
currentStrategy: SyncStrategy;
|
||||||
onSelect: (strategy: SyncStrategy, label: string) => void;
|
onSelect: (strategy: SyncStrategy, label: string) => void;
|
||||||
@@ -123,10 +143,13 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
setIsRegexDirty(isDifferent);
|
setIsRegexDirty(isDifferent);
|
||||||
}, [localReplacements, savedRegexReplacements]);
|
}, [localReplacements, savedRegexReplacements]);
|
||||||
|
|
||||||
|
// Check dirty state for Schedule (including Active Tab changes)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const isDifferent = JSON.stringify(localSchedule) !== JSON.stringify(savedSchedule);
|
// We calculate what the "effective" schedule would be if we saved right now.
|
||||||
|
const effectiveLocal = deriveEffectiveSchedule(localSchedule, activeTab);
|
||||||
|
const isDifferent = JSON.stringify(effectiveLocal) !== JSON.stringify(savedSchedule);
|
||||||
setIsScheduleDirty(isDifferent);
|
setIsScheduleDirty(isDifferent);
|
||||||
}, [localSchedule, savedSchedule]);
|
}, [localSchedule, savedSchedule, activeTab]);
|
||||||
|
|
||||||
const selectedOption = STRATEGIES.find(s => s.value === currentStrategy) || STRATEGIES[0];
|
const selectedOption = STRATEGIES.find(s => s.value === currentStrategy) || STRATEGIES[0];
|
||||||
|
|
||||||
@@ -140,6 +163,11 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Determine if tabs have changed from the saved state
|
||||||
|
const initialTab = savedSchedule.mode === ScheduleMode.DISABLED ? ScheduleMode.CRON : savedSchedule.mode;
|
||||||
|
const hasTabChanged = activeTab !== initialTab;
|
||||||
|
const isScheduleActionable = isScheduleDirty || hasTabChanged;
|
||||||
|
|
||||||
const handleSelect = (strategy: StrategyOption) => {
|
const handleSelect = (strategy: StrategyOption) => {
|
||||||
if (isLocked) return;
|
if (isLocked) return;
|
||||||
onSelect(strategy.value, strategy.label);
|
onSelect(strategy.value, strategy.label);
|
||||||
@@ -196,37 +224,23 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
setLocalSchedule(JSON.parse(JSON.stringify(savedSchedule)));
|
setLocalSchedule(JSON.parse(JSON.stringify(savedSchedule)));
|
||||||
if (savedSchedule.mode !== ScheduleMode.DISABLED) {
|
if (savedSchedule.mode !== ScheduleMode.DISABLED) {
|
||||||
setActiveTab(savedSchedule.mode);
|
setActiveTab(savedSchedule.mode);
|
||||||
|
} else {
|
||||||
|
setActiveTab(ScheduleMode.CRON);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveScheduleClick = async () => {
|
const handleSaveScheduleClick = async () => {
|
||||||
if (isLocked) return;
|
if (isLocked) return;
|
||||||
|
|
||||||
let settingsToSave = { ...localSchedule };
|
// Determine the effective settings based on the current view (tab) and inputs
|
||||||
|
const settingsToSave = deriveEffectiveSchedule(localSchedule, activeTab);
|
||||||
// Logic to determine mode based on active Tab and checkbox state
|
|
||||||
if (activeTab === ScheduleMode.CRON) {
|
|
||||||
if (settingsToSave.cronExpression.trim() !== '') {
|
|
||||||
settingsToSave.mode = ScheduleMode.CRON;
|
|
||||||
} else {
|
|
||||||
// Empty cron -> disabled
|
|
||||||
settingsToSave.mode = ScheduleMode.DISABLED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For Daily/Weekly, enforce: Save commits what is seen in the active tab.
|
|
||||||
if (activeTab !== ScheduleMode.CRON) {
|
|
||||||
// If the mode matches the active tab, it's enabled. Otherwise disabled.
|
|
||||||
if (localSchedule.mode !== activeTab) {
|
|
||||||
settingsToSave.mode = ScheduleMode.DISABLED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call API
|
// Call API
|
||||||
const success = await onSaveSchedule(settingsToSave);
|
const success = await onSaveSchedule(settingsToSave);
|
||||||
if (success) {
|
if (success) {
|
||||||
setLocalSchedule(settingsToSave);
|
setLocalSchedule(settingsToSave);
|
||||||
setIsScheduleDirty(false);
|
// Dirty state is cleared by the useEffect prop update, or we can clear it optimistically here if needed,
|
||||||
|
// but useEffect [savedSchedule] handles it correctly.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -554,9 +568,9 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
<div className="flex items-center gap-2 justify-end pt-3 border-t border-white/5">
|
<div className="flex items-center gap-2 justify-end pt-3 border-t border-white/5">
|
||||||
<button
|
<button
|
||||||
onClick={handleResetSchedule}
|
onClick={handleResetSchedule}
|
||||||
disabled={!isScheduleDirty}
|
disabled={!isScheduleActionable}
|
||||||
className={`flex items-center justify-center space-x-1.5 px-3 py-1.5 rounded-md text-xs font-medium border transition-all
|
className={`flex items-center justify-center space-x-1.5 px-3 py-1.5 rounded-md text-xs font-medium border transition-all
|
||||||
${isScheduleDirty
|
${isScheduleActionable
|
||||||
? 'bg-gray-800 border-gray-600 text-gray-300 hover:bg-gray-700 hover:text-white'
|
? 'bg-gray-800 border-gray-600 text-gray-300 hover:bg-gray-700 hover:text-white'
|
||||||
: 'bg-transparent border-transparent text-gray-700 cursor-not-allowed'}`}
|
: 'bg-transparent border-transparent text-gray-700 cursor-not-allowed'}`}
|
||||||
>
|
>
|
||||||
@@ -565,9 +579,9 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={handleSaveScheduleClick}
|
onClick={handleSaveScheduleClick}
|
||||||
disabled={!isScheduleDirty}
|
disabled={!isScheduleActionable}
|
||||||
className={`flex items-center justify-center space-x-1.5 px-3 py-1.5 rounded-md text-xs font-bold border transition-all
|
className={`flex items-center justify-center space-x-1.5 px-3 py-1.5 rounded-md text-xs font-bold border transition-all
|
||||||
${isScheduleDirty
|
${isScheduleActionable
|
||||||
? 'bg-plex-orange border-plex-orange text-gray-900 hover:bg-yellow-500 shadow-lg shadow-plex-orange/10'
|
? 'bg-plex-orange border-plex-orange text-gray-900 hover:bg-yellow-500 shadow-lg shadow-plex-orange/10'
|
||||||
: 'bg-gray-800/30 border-gray-800/50 text-gray-600 cursor-not-allowed'}`}
|
: 'bg-gray-800/30 border-gray-800/50 text-gray-600 cursor-not-allowed'}`}
|
||||||
>
|
>
|
||||||
@@ -614,4 +628,4 @@ const StrategySelector: React.FC<StrategySelectorProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default StrategySelector;
|
export default StrategySelector;
|
||||||
|
|||||||
Reference in New Issue
Block a user