diff --git a/ui/desktop/openapi.json b/ui/desktop/openapi.json index cae672126d9d..42d564fa3cfa 100644 --- a/ui/desktop/openapi.json +++ b/ui/desktop/openapi.json @@ -10,7 +10,7 @@ "license": { "name": "Apache-2.0" }, - "version": "1.0.28" + "version": "1.0.29" }, "paths": { "/agent/tools": { @@ -480,6 +480,12 @@ } } }, + "400": { + "description": "Invalid cron expression or recipe file" + }, + "409": { + "description": "Job ID already exists" + }, "500": { "description": "Internal server error" } diff --git a/ui/desktop/src/api/types.gen.ts b/ui/desktop/src/api/types.gen.ts index 424a469be070..767b32fa8846 100644 --- a/ui/desktop/src/api/types.gen.ts +++ b/ui/desktop/src/api/types.gen.ts @@ -910,6 +910,14 @@ export type CreateScheduleData = { }; export type CreateScheduleErrors = { + /** + * Invalid cron expression or recipe file + */ + 400: unknown; + /** + * Job ID already exists + */ + 409: unknown; /** * Internal server error */ diff --git a/ui/desktop/src/hooks/useDarkMode.ts b/ui/desktop/src/hooks/useDarkMode.ts new file mode 100644 index 000000000000..5ba59888c861 --- /dev/null +++ b/ui/desktop/src/hooks/useDarkMode.ts @@ -0,0 +1,42 @@ +import { useEffect, useState } from 'react'; + +export function useDarkMode(): boolean { + const [isDarkMode, setIsDarkMode] = useState(() => { + const html = document.documentElement; + return ( + html.classList.contains('dark') || window.matchMedia('(prefers-color-scheme: dark)').matches + ); + }); + + useEffect(() => { + const html = document.documentElement; + + const updateDarkMode = () => { + setIsDarkMode(html.classList.contains('dark')); + }; + + // Observe class attribute changes + const observer = new MutationObserver(() => updateDarkMode()); + observer.observe(html, { attributes: true, attributeFilter: ['class'] }); + + // Also handle system preference changes (if no dark class is set manually) + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + // eslint-disable-next-line no-undef + const handleMediaChange = (event: MediaQueryListEvent) => { + if (!html.classList.contains('dark') && !html.classList.contains('light')) { + setIsDarkMode(event.matches); + } + }; + mediaQuery.addEventListener('change', handleMediaChange); + + // Initial check + updateDarkMode(); + + return () => { + observer.disconnect(); + mediaQuery.removeEventListener('change', handleMediaChange); + }; + }, []); + + return isDarkMode; +}