import { Classes, DialogFooter, Tab, Tabs } from '@blueprintjs/core'; import styled from '@emotion/styled'; import { yupResolver } from '@hookform/resolvers/yup'; import type { Workspace } from '@zakodium/nmrium-core'; import dlv from 'dlv'; import { useCallback, useEffect, useMemo, useRef } from 'react'; import { FormProvider, useForm, useFormContext, useWatch, } from 'react-hook-form'; import { FaBolt, FaCogs, FaPaste, FaRegCopy, FaWrench } from 'react-icons/fa'; import { Button, Toolbar, useOnOff } from 'react-science/ui'; import { ClipboardFallbackModal } from '../../../utils/clipboard/clipboardComponents.js'; import { useClipboard } from '../../../utils/clipboard/clipboardHooks.js'; import { usePreferences, useWorkspacesList, } from '../../context/PreferencesContext.js'; import { useToaster } from '../../context/ToasterContext.js'; import ActionButtons from '../../elements/ActionButtons.js'; import type { LabelStyle } from '../../elements/Label.js'; import Label from '../../elements/Label.js'; import { StandardDialog } from '../../elements/StandardDialog.tsx'; import { StyledDialogBody } from '../../elements/StyledDialogBody.js'; import type { DropDownListItem } from '../../elements/dropDownButton/DropDownButton.js'; import DropDownButton from '../../elements/dropDownButton/DropDownButton.js'; import useCheckExperimentalFeature from '../../hooks/useCheckExperimentalFeature.js'; import { useSaveSettings } from '../../hooks/useSaveSettings.js'; import { useWorkspaceAction } from '../../hooks/useWorkspaceAction.js'; import type { WorkspaceWithSource } from '../../reducer/preferences/preferencesReducer.js'; import { getPreferencesByWorkspace } from '../../reducer/preferences/utilities/getPreferencesByWorkspace.js'; import PredefinedWorkspaces from '../../workspaces/index.js'; import WorkspaceItem from './WorkspaceItem.js'; import DatabasesTabContent from './settings-tabs/DatabasesTabContent.js'; import DisplayTabContent from './settings-tabs/DisplayTabContent.js'; import { ExportTabContent } from './settings-tabs/ExportTabContent.js'; import { ExternalAPIsTabContent } from './settings-tabs/ExternalAPIsTabContent.js'; import GeneralTabContent from './settings-tabs/GeneralTabContent.js'; import ImportationFiltersTabContent from './settings-tabs/ImportationFiltersTabContent.js'; import InfoBlockTabContent from './settings-tabs/InfoBlockTabContent.js'; import NucleiTabContent from './settings-tabs/NucleiTabContent.js'; import OnLoadProcessingTabContent from './settings-tabs/OnLoadProcessingTabContent.js'; import SpectraColorsTabContent from './settings-tabs/SpectraColorsTabContent.js'; import ToolsTabContent from './settings-tabs/ToolsTabContent.js'; import { validation } from './settingsValidation.js'; import { GeneralSettingsDialog } from './tanstack_general_settings/general_settings.js'; export const Section = styled.div` border-bottom: 0.55px solid #f9f9f9; color: #2ca8ff; display: flex; font-size: 13px; margin-bottom: 10px; padding: 6px 2px; `; const StyledTabs = styled(Tabs)` height: 100%; div[role='tablist'] { gap: 0; } div[role='tabpanel'] { max-height: 100%; overflow: auto; padding: 0.8rem; width: 100%; } `; export const settingLabelStyle: LabelStyle = { container: { padding: '5px', borderBottom: '1px solid #f7f7f7', justifyContent: 'space-between', }, }; const StyledButton = styled(Button, { shouldForwardProp(propName) { return propName !== 'marginHorizontal'; }, })<{ marginHorizontal: number }>` margin: 0 ${(props) => props.marginHorizontal}px; `; function isRestButtonDisable( currentWorkspaceSetting: any, workspaceName: any, customWorkspaces: any, ) { if ( !(workspaceName in PredefinedWorkspaces) && !(workspaceName in customWorkspaces) ) { return true; } else { return ( JSON.stringify(currentWorkspaceSetting) === JSON.stringify(getPreferencesByWorkspace(workspaceName, customWorkspaces)) ); } } interface BasseGeneralModalProps { onCloseDialog: () => void; onSave: (values?: Partial) => void; } interface InnerGeneralSettingsModalProps extends BasseGeneralModalProps { height?: number; } interface GeneralSettingsModalProps { height?: number; } function GeneralSettingsModal(props: GeneralSettingsModalProps) { const { ...otherProps } = props; const [isOpenDialog, openDialog, closeDialog] = useOnOff(false); const [ isOpenGeneralSettingsDialog, openGeneralSettingsDialog, closeGeneralSettingsDialog, ] = useOnOff(false); const { saveSettings, SaveSettingsModal } = useSaveSettings(); // Boolean to check if we have to render the new general settings dialog const isExperimentalFeatures = useCheckExperimentalFeature(); return ( <> } /> {isExperimentalFeatures && ( } /> )} {isOpenDialog && ( )} {isOpenGeneralSettingsDialog && ( )} ); } function InnerGeneralSettingsModal(props: InnerGeneralSettingsModalProps) { const { height, onCloseDialog, onSave } = props; const { dispatch, current: currentWorkspace, originalWorkspaces, workspaces, ...preferences } = usePreferences(); const { addNewWorkspace, removeWorkspace, setActiveWorkspace } = useWorkspaceAction(); const baseWorkspaces = useWorkspacesList(); const workspaceName = preferences.workspace.current; const pastRef = useRef | null>(null); const methods = useForm({ defaultValues: currentWorkspace, resolver: yupResolver(validation), }); const { reset, getValues, watch } = methods; const workspacesList = useMemo(() => { return baseWorkspaces.concat([ { key: 'new', label: 'Custom workspace', } as any, ]); }, [baseWorkspaces]); function addWorkSpaceHandler(name: any) { addNewWorkspace(name, getValues()); } function deleteWorkSpaceHandler(key: any) { const isActiveWorkspace = removeWorkspace(key); if (!isActiveWorkspace) { return; } reset(workspaces.default); } function ChangeWorkspaceHandler(option: DropDownListItem) { setActiveWorkspace(option.key); reset(workspaces[option.key]); } function renderItem(item: any) { return ( ); } const setWorkspaceSetting = useCallback( (inputWorkspace: any) => { const parseWorkspaceName = Object.keys(inputWorkspace)[0]; if (preferences.workspace.current === parseWorkspaceName) { reset(inputWorkspace[parseWorkspaceName]); } else if (workspaces[parseWorkspaceName]) { pastRef.current = inputWorkspace; dispatch({ type: 'SET_WORKSPACE', payload: { workspace: parseWorkspaceName, workspaceSource: 'any', }, }); } }, [dispatch, preferences.workspace, workspaces, reset], ); const isExperimentalFeatures = watch('display.general.experimentalFeatures.display') || false; useEffect(() => { if (pastRef.current) { setWorkspaceSetting(pastRef.current); pastRef.current = null; } }, [setWorkspaceSetting]); return (
setWorkspaceSetting(workspaceSettings) } />
} /> } /> } /> } /> } /> } /> } /> } /> } /> {isExperimentalFeatures && ( } /> )} } />
); } function WorkSpaceActionsButtons(props: any) { const { readText, rawWriteWithType, shouldFallback, cleanShouldFallback, text, } = useClipboard(); const toaster = useToaster(); const { reset } = useFormContext(); const values = useWatch(); const isExperimentalFeatures = dlv( values, 'display.general.experimentalFeatures.display', false, ); const { originalWorkspaces, workspace: { current: workspaceName }, } = usePreferences(); function handleReset() { const workSpaceDisplayPreferences = getPreferencesByWorkspace( workspaceName, originalWorkspaces, ); reset(workSpaceDisplayPreferences); } function handlePasteWorkspace(text: string | null) { if (!text) return; try { const parseWorkspaces = JSON.parse(text); props.onPast(parseWorkspaces); } catch { toaster.show({ message: 'object parse error', intent: 'danger' }); } cleanShouldFallback(); } function handlePastWorkspaceAction() { void readText().then(handlePasteWorkspace); } function handleCopyWorkspace() { const data = { [workspaceName]: values }; void rawWriteWithType(JSON.stringify(data)).then(() => { toaster.show({ message: 'Workspace copied to clipboard', intent: 'success', }); }); } return (
{isExperimentalFeatures && ( <> )}
); } function DialogActionButtons(props: BasseGeneralModalProps) { const { onSave, onCloseDialog } = props; const { handleSubmit, formState: { isValid }, } = useFormContext(); const { dispatch } = usePreferences(); const values = useWatch(); function submitHandler(values: any) { onSave(values); onCloseDialog?.(); } function applyPreferencesHandler() { if (!isValid) { void handleSubmit(submitHandler)(); return; } dispatch({ type: 'APPLY_GENERAL_PREFERENCES', payload: { data: values as any, }, }); props.onCloseDialog?.(); } return (
handleSubmit(submitHandler)()} doneLabel="Apply and Save" onCancel={() => { props.onCloseDialog?.(); }} /> Apply
); } export default GeneralSettingsModal;