PlexPlaylist_UI subtree merge

feat: Implement schedule settings and basic UI
feat: Display next sync schedule information

Merge commit '06e49be1f9c587f66cca97de97cf449b33b04a4b'
This commit is contained in:
2025-11-29 08:23:31 +09:00
5 changed files with 534 additions and 98 deletions
+28 -2
View File
@@ -1,5 +1,6 @@
import { Playlist, ServerType, ApiResponse, PlexServerConnection, PlexConnectionSettings, PlexLibrary, SyncStrategy, RegexReplacement } from '../types';
import { Playlist, ServerType, ApiResponse, PlexServerConnection, PlexConnectionSettings, PlexLibrary, SyncStrategy, RegexReplacement, ScheduleSettings, ScheduleMode } from '../types';
import { MOCK_LOCAL_PLAYLISTS, MOCK_CLOUD_PLAYLISTS } from './mockData';
const SIMULATE_DELAY_MS = 800;
@@ -135,6 +136,14 @@ const triggerSync = async (strategy: SyncStrategy, regexRules: RegexReplacement[
});
};
// Basic Cron validation helper
const validateCron = (expression: string): boolean => {
const parts = expression.trim().split(/\s+/);
if (parts.length !== 5) return false;
// A very naive check, real validation is more complex but this fits the mock requirement
return true;
};
export const apiService = {
getPlaylists: async (serverType: ServerType, signal?: AbortSignal): Promise<ApiResponse<Playlist[]>> => {
try {
@@ -191,5 +200,22 @@ export const apiService = {
} catch (error) {
return { data: null, status: 'error', message: 'Sync failed' };
}
},
saveScheduleSettings: async (settings: ScheduleSettings): Promise<ApiResponse<null>> => {
// Simulate API call
return new Promise((resolve) => {
setTimeout(() => {
// Validation only applies if the mode is CRON and user provided input
if (settings.mode === ScheduleMode.CRON && settings.cronExpression.trim() !== '') {
if (!validateCron(settings.cronExpression)) {
resolve({ data: null, status: 'error', message: 'Invalid Cron expression format' });
return;
}
}
resolve({ data: null, status: 'success', message: 'Schedule updated successfully' });
}, 500);
});
}
};
};