diff --git a/src/component/context/LoggerContext.tsx b/src/component/context/LoggerContext.tsx index c07c828103..32c80f31c0 100644 --- a/src/component/context/LoggerContext.tsx +++ b/src/component/context/LoggerContext.tsx @@ -35,6 +35,15 @@ interface LoggerProviderProps { children: ReactNode; } +export type LoggerType = + | 'fatal' + | 'error' + | 'warn' + | 'info' + | 'debug' + | 'trace' + | 'silent'; + export const LOGGER_LEVELS = { fatal: 60, error: 50, diff --git a/src/component/modal/setting/tanstack_general_settings/general_settings.tsx b/src/component/modal/setting/tanstack_general_settings/general_settings.tsx index e15394b41a..3089a177d2 100644 --- a/src/component/modal/setting/tanstack_general_settings/general_settings.tsx +++ b/src/component/modal/setting/tanstack_general_settings/general_settings.tsx @@ -1,6 +1,7 @@ import { Dialog as BPDialog } from '@blueprintjs/core'; import styled from '@emotion/styled'; import { revalidateLogic } from '@tanstack/react-form'; +import type { Workspace } from '@zakodium/nmrium-core'; import { Form, useForm } from 'react-science/ui'; import type { z } from 'zod/v4'; @@ -28,50 +29,38 @@ export type GeneralSettingsFormType = z.input; export function GeneralSettings(props: GeneralSettingsProps) { const { isOpen, close, height } = props; - const { current: currentWorkspace } = usePreferences(); + const { current: currentWorkspace, dispatch } = usePreferences(); const { saveSettings } = useSaveSettings(); - const defaultValues: z.input = { - general: { - dimmedSpectraOpacity: currentWorkspace.general.dimmedSpectraOpacity, - invertScroll: currentWorkspace.general.invertScroll, - invertActions: currentWorkspace.general.invert, - experimentalFeatures: - currentWorkspace.display.general?.experimentalFeatures?.display || - false, - }, - }; - const form = useForm({ - validators: { onDynamic: workspaceValidation }, + validators: { + onDynamic: workspaceValidation, + }, validationLogic: revalidateLogic({ mode: 'change' }), - defaultValues, + defaultValues: currentWorkspace as GeneralSettingsFormType, onSubmit: ({ value }) => { - const parsedValues = workspaceValidation.parse(value); + const safeParseResult = workspaceValidation.safeParse(value); + + if (!safeParseResult.success) { + throw new Error('Failed to parse workspace validation'); + } - saveSettings({ - display: { - general: { - experimentalFeatures: { - display: parsedValues.general.experimentalFeatures, - visible: true, - }, - }, - }, - general: { - invert: parsedValues.general.invertActions, - invertScroll: parsedValues.general.invertScroll, - dimmedSpectraOpacity: parsedValues.general.dimmedSpectraOpacity, - spectraRendering: 'auto', - verticalSplitterCloseThreshold: 0, - verticalSplitterPosition: '1px', - loggingLevel: 'info', - popupLoggingLevel: 'info', - }, - }); + saveSettings(value as Partial); + close(); }, }); + function onApply(values: GeneralSettingsFormType) { + dispatch({ + type: 'APPLY_General_PREFERENCES', + payload: { + data: values as Omit, + }, + }); + + close(); + } + return (
- - reset={form.reset} - currentValues={form.state.values} - /> + state.values}> + {(values) => ( + + )} + - +
); diff --git a/src/component/modal/setting/tanstack_general_settings/general_settings_dialog_footer.tsx b/src/component/modal/setting/tanstack_general_settings/general_settings_dialog_footer.tsx index 68d3e99bff..ceacd5e038 100644 --- a/src/component/modal/setting/tanstack_general_settings/general_settings_dialog_footer.tsx +++ b/src/component/modal/setting/tanstack_general_settings/general_settings_dialog_footer.tsx @@ -1,22 +1,45 @@ import { DialogFooter } from '@blueprintjs/core'; import styled from '@emotion/styled'; -import { withForm } from 'react-science/ui'; +import { Button, withForm } from 'react-science/ui'; +import type { GeneralSettingsFormType } from './general_settings.tsx'; import { defaultGeneralSettingsFormValues } from './validation.ts'; const Footer = styled.div` display: flex; - justify-content: flex-start; + justify-content: flex-end; + gap: 10px; `; export const GeneralSettingsDialogFooter = withForm({ + props: { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + onApply: (values: GeneralSettingsFormType) => { + /* empty */ + }, + onCancel: () => { + /* empty */ + }, + }, defaultValues: defaultGeneralSettingsFormValues, - render: ({ form }) => { + render: ({ form, onCancel, onApply }) => { return (
- Save + + + Apply and Save + + state.values}> + {(values) => ( + + )} +
diff --git a/src/component/modal/setting/tanstack_general_settings/tabs/general_tab.tsx b/src/component/modal/setting/tanstack_general_settings/tabs/general_tab.tsx index 2534029304..72e40c2b9d 100644 --- a/src/component/modal/setting/tanstack_general_settings/tabs/general_tab.tsx +++ b/src/component/modal/setting/tanstack_general_settings/tabs/general_tab.tsx @@ -1,7 +1,34 @@ +import { Tag } from '@blueprintjs/core'; import { withForm } from 'react-science/ui'; +import { LOGGER_LEVELS } from '../../../../context/LoggerContext.tsx'; +import type { SelectDefaultItem } from '../../../../elements/Select2.tsx'; import { defaultGeneralSettingsFormValues } from '../validation.ts'; +const SHAPE_RENDERING: SelectDefaultItem[] = [ + { + label: 'Auto', + value: 'auto', + }, + { + label: 'Optimize speed', + value: 'optimizeSpeed', + }, + { + label: 'Crisp edges', + value: 'crispEdges', + }, + { + label: 'Geometric precision', + value: 'geometricPrecision', + }, +]; + +const LOGS_LEVELS = Object.keys(LOGGER_LEVELS).map((level) => ({ + label: level.replace(/^\w/, (c) => c.toUpperCase()), + value: level, +})); + export const GeneralTab = withForm({ defaultValues: defaultGeneralSettingsFormValues, render: ({ form }) => { @@ -19,19 +46,48 @@ export const GeneralTab = withForm({ /> )} - + {(field) => } {(field) => } - - + {(field) => } + + + {(field) => ( + + )} + + + + + {(field) => } + + + {(field) => ( + + )} + + + + + {(field) => ( + px} + /> + )} + + ); }, diff --git a/src/component/modal/setting/tanstack_general_settings/validation.ts b/src/component/modal/setting/tanstack_general_settings/validation.ts index fb36f1dcb0..59be0abdf4 100644 --- a/src/component/modal/setting/tanstack_general_settings/validation.ts +++ b/src/component/modal/setting/tanstack_general_settings/validation.ts @@ -1,24 +1,69 @@ import { z } from 'zod/v4'; +import type { LoggerType } from '../../../context/LoggerContext.tsx'; + +const loggingLevel: LoggerType[] = [ + 'fatal', + 'error', + 'warn', + 'info', + 'debug', + 'trace', + 'silent', +]; + +const peaksLabelValidation = z.object({ + marginTop: z.coerce.number().int().min(0), +}); + const generalValidation = z.object({ dimmedSpectraOpacity: z.coerce.number().min(0).max(1), - invertActions: z.boolean(), + invert: z.boolean(), invertScroll: z.boolean(), - experimentalFeatures: z.boolean(), + spectraRendering: z.enum([ + 'auto', + 'optimizeSpeed', + 'crispEdges', + 'geometricPrecision', + ]), + popupLoggingLevel: z.enum(loggingLevel).optional(), + loggingLevel: z.enum(loggingLevel).optional(), +}); + +const displayValidation = z.object({ + general: z.object({ + experimentalFeatures: z.object({ + display: z.boolean(), + }), + }), }); export const workspaceValidation = z.object({ + peaksLabel: peaksLabelValidation, general: generalValidation, + display: displayValidation, }); // This object is used to define type not real values. Do not use it as values export const defaultGeneralSettingsFormValues: z.input< typeof workspaceValidation > = { + peaksLabel: { + marginTop: 0, + }, general: { dimmedSpectraOpacity: 0, - invertActions: false, + invert: false, invertScroll: false, - experimentalFeatures: false, + spectraRendering: 'auto', + loggingLevel: 'info', + popupLoggingLevel: 'info', + }, + display: { + general: { + experimentalFeatures: { + display: false, + }, + }, }, };