feat(core): initialize project skeleton with Electron + React + TypeScript
Set up the complete project foundation for ClawX, a graphical AI assistant: - Electron main process with IPC handlers, menu, tray, and gateway management - React renderer with routing, layout components, and page scaffolding - Zustand state management for gateway, settings, channels, skills, chat, and cron - shadcn/ui components with Tailwind CSS and CSS variable theming - Build tooling with Vite, electron-builder, and TypeScript configuration - Testing setup with Vitest and Playwright - Development configurations (ESLint, Prettier, gitignore, env example)
This commit is contained in:
100
src/stores/cron.ts
Normal file
100
src/stores/cron.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* Cron State Store
|
||||
* Manages scheduled task state
|
||||
*/
|
||||
import { create } from 'zustand';
|
||||
import type { CronJob, CronJobCreateInput, CronJobUpdateInput } from '../types/cron';
|
||||
|
||||
interface CronState {
|
||||
jobs: CronJob[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
|
||||
// Actions
|
||||
fetchJobs: () => Promise<void>;
|
||||
createJob: (input: CronJobCreateInput) => Promise<CronJob>;
|
||||
updateJob: (id: string, input: CronJobUpdateInput) => Promise<void>;
|
||||
deleteJob: (id: string) => Promise<void>;
|
||||
toggleJob: (id: string, enabled: boolean) => Promise<void>;
|
||||
triggerJob: (id: string) => Promise<void>;
|
||||
setJobs: (jobs: CronJob[]) => void;
|
||||
}
|
||||
|
||||
export const useCronStore = create<CronState>((set, get) => ({
|
||||
jobs: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
fetchJobs: async () => {
|
||||
set({ loading: true, error: null });
|
||||
|
||||
try {
|
||||
const result = await window.electron.ipcRenderer.invoke('cron:list') as CronJob[];
|
||||
set({ jobs: result, loading: false });
|
||||
} catch (error) {
|
||||
set({ error: String(error), loading: false });
|
||||
}
|
||||
},
|
||||
|
||||
createJob: async (input) => {
|
||||
try {
|
||||
const job = await window.electron.ipcRenderer.invoke('cron:create', input) as CronJob;
|
||||
set((state) => ({ jobs: [...state.jobs, job] }));
|
||||
return job;
|
||||
} catch (error) {
|
||||
console.error('Failed to create cron job:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
updateJob: async (id, input) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:update', id, input);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.map((job) =>
|
||||
job.id === id ? { ...job, ...input, updatedAt: new Date().toISOString() } : job
|
||||
),
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Failed to update cron job:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
deleteJob: async (id) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:delete', id);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.filter((job) => job.id !== id),
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Failed to delete cron job:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
toggleJob: async (id, enabled) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:toggle', id, enabled);
|
||||
set((state) => ({
|
||||
jobs: state.jobs.map((job) =>
|
||||
job.id === id ? { ...job, enabled } : job
|
||||
),
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Failed to toggle cron job:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
triggerJob: async (id) => {
|
||||
try {
|
||||
await window.electron.ipcRenderer.invoke('cron:trigger', id);
|
||||
} catch (error) {
|
||||
console.error('Failed to trigger cron job:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
setJobs: (jobs) => set({ jobs }),
|
||||
}));
|
||||
Reference in New Issue
Block a user