From 9126302b40b3a22c7a17594a4d83d5c5a084056d Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Thu, 15 Jan 2026 11:05:22 +0100 Subject: [PATCH 01/10] feat: add automatic atom labeling close #3908 --- package-lock.json | 8 +++---- package.json | 2 +- .../MoleculesPanel/MoleculePanelHeader.tsx | 23 ++++++++++++++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e600a3c4..8a01c20e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.9.0", + "openchemlib-utils": "^8.10.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", @@ -9621,9 +9621,9 @@ "peer": true }, "node_modules/openchemlib-utils": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.9.0.tgz", - "integrity": "sha512-eSKIXOK/ybOf1EoWEUaKeFxARimjd2BOBuiw7P+NaZFuPa0Xvg6HZ57DcJby0g/pJxF5f0m5ChPz4MGM/AVRwg==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.10.0.tgz", + "integrity": "sha512-a88tLw4rRjEdnGcruCoT7MyOviY5hD6ea/O0iw4QKdWJe/EK64dQq5/QASbdcHDLFth1MCzqJEliMIf37saYgQ==", "license": "MIT", "dependencies": { "atom-sorter": "^2.2.1", diff --git a/package.json b/package.json index 487fe4ddc..b730b80ba 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.9.0", + "openchemlib-utils": "^8.10.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", diff --git a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx index 2cc37f02f..7928fd546 100644 --- a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx +++ b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx @@ -1,4 +1,5 @@ import { Molecule } from 'openchemlib'; +import { autoLabel } from 'openchemlib-utils'; import type { ReactNode } from 'react'; import { useCallback } from 'react'; import { @@ -13,7 +14,7 @@ import { } from 'react-icons/fa'; import { FaMaximize, FaMinimize } from 'react-icons/fa6'; import { IoOpenOutline } from 'react-icons/io5'; -import { MdNumbers, MdOutlineLabelOff } from 'react-icons/md'; +import { MdFlashAuto, MdNumbers, MdOutlineLabelOff } from 'react-icons/md'; import { PanelHeader, Toolbar } from 'react-science/ui'; import type { @@ -312,6 +313,20 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { }); } + function autoLabels() { + const currentMolecule = molecules[currentIndex]; + + if (!currentMolecule) return; + const { id, label, molfile } = currentMolecule; + + const molecule = Molecule.fromMolfile(molfile); + autoLabel(molecule); + dispatch({ + type: 'SET_MOLECULE', + payload: { id, label, molfile: molecule.toMolfileV3() }, + }); + } + const hasMolecules = molecules && molecules.length > 0; const showCounter = hasMolecules && renderSource !== 'predictionPanel'; const moreMenu: ToolbarPopoverMenuItem[] = [ @@ -333,6 +348,12 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { disabled: !hasMolecules, onClick: () => clearCustomAtomLabels(), }, + { + icon: , + text: 'Auto label atoms', + disabled: !hasMolecules, + onClick: () => autoLabels(), + }, ]; const { handleChangeAtomAnnotation, isAnnotation } = From ff623c11c0f08c18583c3fade6ebb8df33dfb100 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Thu, 15 Jan 2026 13:27:00 +0100 Subject: [PATCH 02/10] feat: display auto-labeling database close #3908 fix: render structure with correct coordinates --- package-lock.json | 8 +- package.json | 2 +- .../modal/MoleculeAutoLabelsDatabaseModal.tsx | 117 ++++++++++++++++++ .../MoleculesPanel/MoleculePanelHeader.tsx | 14 +++ 4 files changed, 136 insertions(+), 5 deletions(-) create mode 100644 src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx diff --git a/package-lock.json b/package-lock.json index 8a01c20e1..eb36834e9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.10.0", + "openchemlib-utils": "^8.11.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", @@ -9621,9 +9621,9 @@ "peer": true }, "node_modules/openchemlib-utils": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.10.0.tgz", - "integrity": "sha512-a88tLw4rRjEdnGcruCoT7MyOviY5hD6ea/O0iw4QKdWJe/EK64dQq5/QASbdcHDLFth1MCzqJEliMIf37saYgQ==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.11.0.tgz", + "integrity": "sha512-uklqdZNSqotr/uVs3IOANPxtZWLyDZGy5uDYI0uizHvwckyrgAb1jNTw1Cy97fH3yTX075i/sfCWcwzAhXPeiQ==", "license": "MIT", "dependencies": { "atom-sorter": "^2.2.1", diff --git a/package.json b/package.json index b730b80ba..d57752a4b 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.10.0", + "openchemlib-utils": "^8.11.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx new file mode 100644 index 000000000..3bafe5421 --- /dev/null +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -0,0 +1,117 @@ +import { Dialog, DialogFooter } from '@blueprintjs/core'; +import styled from '@emotion/styled'; +import { autoLabelDatabase } from 'openchemlib-utils'; +import { MF } from 'react-mf'; +import { IdcodeSvgRenderer } from 'react-ocl'; + +import { StyledDialogBody } from '../elements/StyledDialogBody.js'; + +const ChemicalGrid = styled.div` + display: flex; + flex-wrap: wrap; + gap: 1.25rem; + justify-content: flex-start; + padding: 0 1rem; +`; + +const ChemicalCard = styled.div` + flex: 0 0 calc((100% - 2.5rem) / 3); + min-width: 200px; + border-radius: 8px; + overflow: hidden; + background: #fff; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: all 0.25s ease; + + &:hover { + box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + transform: translateY(-2px); + } +`; + +const CardLabel = styled.div` + padding: 0.75rem 1rem; + background: linear-gradient(180deg, #ffffff 0%, #f0f2f5 40%, #e2e6eb 100%); + border-bottom: 1px solid #d1d5db; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8); + + h3 { + margin: 0; + font-size: 0.95rem; + font-weight: 600; + color: #374151; + text-align: center; + text-transform: capitalize; + letter-spacing: 0.02em; + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + } +`; + +const StructureContainer = styled.div` + display: flex; + align-items: center; + justify-content: center; + padding: 0.5rem; + background: #fafafa; + border-bottom: 1px solid #eee; +`; + +const CardInfo = styled.div` + padding: 0.75rem 1rem; + display: flex; + justify-content: center; + align-items: center; + background: #fff; +`; + +const MolecularFormula = styled.div` + font-size: 0.9rem; + font-weight: 500; + color: #374151; +`; + +interface MoleculeAutoLabelsDatabaseModalProps { + onClose?: (element?: string) => void; +} + +export function MoleculeAutoLabelsDatabaseModal({ + onClose = () => null, +}: MoleculeAutoLabelsDatabaseModalProps) { + return ( + onClose()} + style={{ width: '90vw', maxWidth: 1000 }} + title="Auto label database" + > + + + {autoLabelDatabase.map((compound) => ( + + +

{compound.label}

+
+ + + + + + + + - + {compound.mw.toFixed(2)} + + +
+ ))} +
+
+ +
+ ); +} diff --git a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx index 7928fd546..042031362 100644 --- a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx +++ b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx @@ -4,6 +4,7 @@ import type { ReactNode } from 'react'; import { useCallback } from 'react'; import { FaCopy, + FaDatabase, FaDownload, FaFileExport, FaFileImage, @@ -34,7 +35,9 @@ import { useToaster } from '../../context/ToasterContext.js'; import { useTopicMolecule } from '../../context/TopicMoleculeContext.js'; import type { ToolbarPopoverMenuItem } from '../../elements/ToolbarPopoverItem.js'; import { ToolbarPopoverItem } from '../../elements/ToolbarPopoverItem.js'; +import { useDialogToggle } from '../../hooks/useDialogToggle.ts'; import AboutPredictionModal from '../../modal/AboutPredictionModal.js'; +import { MoleculeAutoLabelsDatabaseModal } from '../../modal/MoleculeAutoLabelsDatabaseModal.tsx'; import PredictSpectraModal from '../../modal/PredictSpectraModal.js'; import { booleanToString } from '../../utility/booleanToString.ts'; import { @@ -140,6 +143,9 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { current: { defaultMoleculeSettings }, } = usePreferences(); const moleculeKey = molecules?.[currentIndex]?.id; + const { dialog, openDialog, closeDialog } = useDialogToggle({ + autoLabelDatabaseDialog: false, + }); const saveAsSVGHandler = useCallback(() => { if (!rootRef) return; exportAsSVG(`molSVG${currentIndex}`, { @@ -354,6 +360,11 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { disabled: !hasMolecules, onClick: () => autoLabels(), }, + { + icon: , + text: 'Display auto-labeling database', + onClick: () => openDialog('autoLabelDatabaseDialog'), + }, ]; const { handleChangeAtomAnnotation, isAnnotation } = @@ -364,6 +375,9 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { current={showCounter ? currentIndex + 1 : undefined} total={showCounter ? molecules.length : undefined} > + {dialog.autoLabelDatabaseDialog && ( + + )} {renderSource === 'predictionPanel' && } {renderSource === 'moleculePanel' && ( From 1cb5d66a53de7327fabd6088aca4f8b05f661cca Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Thu, 15 Jan 2026 15:07:20 +0100 Subject: [PATCH 03/10] feat: add search to labels database modal --- .../modal/MoleculeAutoLabelsDatabaseModal.tsx | 111 +++++++++++++----- 1 file changed, 81 insertions(+), 30 deletions(-) diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx index 3bafe5421..0a52afdd1 100644 --- a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -1,8 +1,10 @@ -import { Dialog, DialogFooter } from '@blueprintjs/core'; +import { Dialog, InputGroup } from '@blueprintjs/core'; import styled from '@emotion/styled'; import { autoLabelDatabase } from 'openchemlib-utils'; +import { useState } from 'react'; import { MF } from 'react-mf'; import { IdcodeSvgRenderer } from 'react-ocl'; +import { filter } from 'smart-array-filter'; import { StyledDialogBody } from '../elements/StyledDialogBody.js'; @@ -11,7 +13,8 @@ const ChemicalGrid = styled.div` flex-wrap: wrap; gap: 1.25rem; justify-content: flex-start; - padding: 0 1rem; + padding: 0.5rem 1rem; + flex: 1; `; const ChemicalCard = styled.div` @@ -70,6 +73,33 @@ const MolecularFormula = styled.div` color: #374151; `; +const SearchContainer = styled.div` + padding: 1.2rem; + margin-bottom: 1.5rem; + background-color: white; + border-bottom: 1px solid #e0e0e0; + position: sticky; + top: 0; + z-index: 1; +`; + +const SearchInput = styled(InputGroup)` + input { + background: #eceff7; + + &:focus { + background: #fff; + box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); + } + } +`; + +const NoResults = styled.p` + text-align: center; + color: #6b7280; + font-size: 1rem; + padding: 3rem; +`; interface MoleculeAutoLabelsDatabaseModalProps { onClose?: (element?: string) => void; } @@ -77,41 +107,62 @@ interface MoleculeAutoLabelsDatabaseModalProps { export function MoleculeAutoLabelsDatabaseModal({ onClose = () => null, }: MoleculeAutoLabelsDatabaseModalProps) { + const [keywords, setSearch] = useState(''); + + const filteredLabelDatabase = filter(autoLabelDatabase, { keywords }); + return ( onClose()} - style={{ width: '90vw', maxWidth: 1000 }} + style={{ width: '90vw', maxWidth: 1000, height: '80vh' }} title="Auto label database" > - - - {autoLabelDatabase.map((compound) => ( - - -

{compound.label}

-
- - - - - - - - - - {compound.mw.toFixed(2)} - - -
- ))} -
+ + + { + if (target.value !== undefined) { + setSearch(target.value); + } + }} + leftIcon="search" + type="search" + /> + + {filteredLabelDatabase.length === 0 ? ( + No results found for "{keywords}" + ) : ( + + {filteredLabelDatabase.map((compound) => ( + + +

{compound.label}

+
+ + + + + + + + - + {compound.mw.toFixed(2)} + + +
+ ))} +
+ )}
-
); } From eaad449daab29f62faf8265d564fb76473cf32d8 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Thu, 15 Jan 2026 15:31:03 +0100 Subject: [PATCH 04/10] feat: add molecule from the labeling database --- .../modal/MoleculeAutoLabelsDatabaseModal.tsx | 67 ++++++++++++++++--- .../reducer/actions/MoleculeActions.ts | 6 +- src/data/molecules/MoleculeManager.ts | 9 ++- 3 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx index 0a52afdd1..dd31198c5 100644 --- a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -1,13 +1,24 @@ import { Dialog, InputGroup } from '@blueprintjs/core'; import styled from '@emotion/styled'; +import { Molecule } from 'openchemlib'; import { autoLabelDatabase } from 'openchemlib-utils'; import { useState } from 'react'; import { MF } from 'react-mf'; import { IdcodeSvgRenderer } from 'react-ocl'; +import { Button } from 'react-science/ui'; import { filter } from 'smart-array-filter'; +import { useDispatch } from '../context/DispatchContext.tsx'; import { StyledDialogBody } from '../elements/StyledDialogBody.js'; +interface LabelDatabaseItem { + idCode: string; + coordinates: string; + mf: string; + mw: number; + label: string; +} + const ChemicalGrid = styled.div` display: flex; flex-wrap: wrap; @@ -17,26 +28,33 @@ const ChemicalGrid = styled.div` flex: 1; `; +const AddButton = styled(Button)` + position: absolute; + top: 0; + left: 0; +`; + const ChemicalCard = styled.div` + position: relative; flex: 0 0 calc((100% - 2.5rem) / 3); min-width: 200px; border-radius: 8px; overflow: hidden; background: #fff; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + box-shadow: 0 2px 8px rgb(0 0 0 / 8%); transition: all 0.25s ease; - + /* stylelint-disable nesting-selector-no-missing-scoping-root */ &:hover { - box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12); + box-shadow: 0 8px 24px rgb(0 0 0 / 12%); transform: translateY(-2px); } `; const CardLabel = styled.div` padding: 0.75rem 1rem; - background: linear-gradient(180deg, #ffffff 0%, #f0f2f5 40%, #e2e6eb 100%); + background: linear-gradient(180deg, #fff 0%, #f0f2f5 40%, #e2e6eb 100%); border-bottom: 1px solid #d1d5db; - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.8); + box-shadow: inset 0 1px 0 rgb(255 255 255 / 80%); h3 { margin: 0; @@ -46,7 +64,7 @@ const CardLabel = styled.div` text-align: center; text-transform: capitalize; letter-spacing: 0.02em; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); + text-shadow: 0 1px 0 rgb(255 255 255 / 50%); } `; @@ -67,10 +85,10 @@ const CardInfo = styled.div` background: #fff; `; -const MolecularFormula = styled.div` +const MolecularFormula = styled.div<{ color?: string }>` font-size: 0.9rem; font-weight: 500; - color: #374151; + color: ${({ color }) => color ?? '#374151'}; `; const SearchContainer = styled.div` @@ -89,7 +107,7 @@ const SearchInput = styled(InputGroup)` &:focus { background: #fff; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15); + box-shadow: 0 1px 4px rgb(0 0 0 / 15%); } } `; @@ -107,8 +125,23 @@ interface MoleculeAutoLabelsDatabaseModalProps { export function MoleculeAutoLabelsDatabaseModal({ onClose = () => null, }: MoleculeAutoLabelsDatabaseModalProps) { + const dispatch = useDispatch(); const [keywords, setSearch] = useState(''); + function handleAddMolecule(options: LabelDatabaseItem) { + const { idCode, label } = options; + const molecule = Molecule.fromIDCode(idCode); + + if (molecule.getAllAtoms() <= 0) { + return; + } + + dispatch({ + type: 'ADD_MOLECULE', + payload: { molfile: molecule.toMolfileV3(), label }, + }); + } + const filteredLabelDatabase = filter(autoLabelDatabase, { keywords }); return ( @@ -139,6 +172,22 @@ export function MoleculeAutoLabelsDatabaseModal({ {filteredLabelDatabase.map((compound) => ( + + Add + - + {compound.mw.toFixed(2)} + molecule + + ), + }} + onClick={() => handleAddMolecule(compound)} + />

{compound.label}

diff --git a/src/component/reducer/actions/MoleculeActions.ts b/src/component/reducer/actions/MoleculeActions.ts index 79d34a891..c3b89ca16 100644 --- a/src/component/reducer/actions/MoleculeActions.ts +++ b/src/component/reducer/actions/MoleculeActions.ts @@ -33,6 +33,7 @@ interface AddMoleculeProps { id?: string; floatMoleculeOnSave?: boolean; defaultMoleculeSettings?: MoleculeView; + label?: string; } type AddMoleculeAction = ActionType<'ADD_MOLECULE', AddMoleculeProps>; type AddMoleculesAction = ActionType< @@ -105,9 +106,10 @@ export type MoleculeActions = | ToggleMoleculeLabelAction; function addMolecule(draft: Draft, props: AddMoleculeProps) { - const { molfile, id, floatMoleculeOnSave, defaultMoleculeSettings } = props; + const { molfile, id, label, floatMoleculeOnSave, defaultMoleculeSettings } = + props; const isEmpty = draft.molecules.length === 0; - MoleculeManager.addMolfile(draft.molecules, molfile, id); + MoleculeManager.addMolfile(draft.molecules, molfile, { id, label }); /** * if it's the first creation of a molecule after the molecules list was empty, diff --git a/src/data/molecules/MoleculeManager.ts b/src/data/molecules/MoleculeManager.ts index 7237d1f45..47c6dcf12 100644 --- a/src/data/molecules/MoleculeManager.ts +++ b/src/data/molecules/MoleculeManager.ts @@ -35,11 +35,16 @@ export function fromJSON( return molecules; } +interface AddMolfileOptions { + id?: string; + label?: string; +} export function addMolfile( molecules: StateMoleculeExtended[], molfile: string, - id?: string, + options: AddMolfileOptions, ) { + const { id, label } = options; const reservedNumbers = extractLabelsNumbers(molecules); // try to parse molfile @@ -48,7 +53,7 @@ export function addMolfile( molecules.push( initMolecule({ molfile: molecule.toMolfileV3(), - label: `P${getLabelNumber(reservedNumbers)}`, + label: label ?? `P${getLabelNumber(reservedNumbers)}`, id, }), ); From 82f5821b63027db139ec564430bc979cc05dfbea Mon Sep 17 00:00:00 2001 From: Luc Patiny Date: Thu, 15 Jan 2026 19:56:54 +0100 Subject: [PATCH 05/10] fix: reuse coordinates when adding molecule and update react-ocl --- package-lock.json | 11 +++++++---- package.json | 2 +- .../modal/MoleculeAutoLabelsDatabaseModal.tsx | 4 ++-- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb36834e9..1e0748c10 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "react-icons": "^5.5.0", "react-inspector": "^9.0.0", "react-mf": "^3.1.1", - "react-ocl": "^8.4.0", + "react-ocl": "^8.5.0", "react-ocl-nmr": "^4.1.1", "react-plot": "^3.1.2", "react-rnd": "^10.5.2", @@ -10478,10 +10478,13 @@ } }, "node_modules/react-ocl": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/react-ocl/-/react-ocl-8.4.0.tgz", - "integrity": "sha512-HrKWK78u9XOeW9U6Qh869Z+ee1Kv0DsayrQeurkh+mTIkf4Gy/oeY31Q4WkzHV9Hcar44XH8d2jjEYyFCJVcJw==", + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/react-ocl/-/react-ocl-8.5.0.tgz", + "integrity": "sha512-IOgPuJCcGs36iiiWjVz1EuHzutlmFQak7H+YXEy0cjEodZeL7HWAqrjWzd1/uyKIpDL+Hkqzk8RNVyWt2j18xg==", "license": "MIT", + "dependencies": { + "@emotion/styled": "^11.14.1" + }, "peerDependencies": { "openchemlib": ">=8", "react": ">=18", diff --git a/package.json b/package.json index d57752a4b..61bbde420 100644 --- a/package.json +++ b/package.json @@ -109,7 +109,7 @@ "react-icons": "^5.5.0", "react-inspector": "^9.0.0", "react-mf": "^3.1.1", - "react-ocl": "^8.4.0", + "react-ocl": "^8.5.0", "react-ocl-nmr": "^4.1.1", "react-plot": "^3.1.2", "react-rnd": "^10.5.2", diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx index dd31198c5..cd572d6bf 100644 --- a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -129,8 +129,8 @@ export function MoleculeAutoLabelsDatabaseModal({ const [keywords, setSearch] = useState(''); function handleAddMolecule(options: LabelDatabaseItem) { - const { idCode, label } = options; - const molecule = Molecule.fromIDCode(idCode); + const { idCode, coordinates, label } = options; + const molecule = Molecule.fromIDCode(idCode, coordinates); if (molecule.getAllAtoms() <= 0) { return; From 29b9d18508f28e12bf932a6a274e80b5df5a456c Mon Sep 17 00:00:00 2001 From: Luc Patiny Date: Thu, 15 Jan 2026 20:19:35 +0100 Subject: [PATCH 06/10] chore: rename some properties --- .../modal/MoleculeAutoLabelsDatabaseModal.tsx | 4 ++-- .../MoleculesPanel/MoleculePanelHeader.tsx | 18 +++++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx index cd572d6bf..cc3ea88f3 100644 --- a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -149,13 +149,13 @@ export function MoleculeAutoLabelsDatabaseModal({ isOpen onClose={() => onClose()} style={{ width: '90vw', maxWidth: 1000, height: '80vh' }} - title="Auto label database" + title="Template database" > { if (target.value !== undefined) { diff --git a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx index 042031362..0a237c3ea 100644 --- a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx +++ b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx @@ -71,30 +71,30 @@ const MOL_EXPORT_MENU: Array> = [ }, { icon: , - text: 'Copy as molfile V3', + text: 'Copy as molfile V2', data: { - id: 'CopyAsMolfileV3', + id: 'CopyAsMolfileV2', }, }, { icon: , - text: 'Copy as molfile V2', + text: 'Copy as molfile V3', data: { - id: 'CopyAsMolfileV2', + id: 'CopyAsMolfileV3', }, }, { icon: , - text: 'Save as molfile V3', + text: 'Save as molfile V2', data: { - id: 'SaveAsMolfileV3', + id: 'SaveAsMolfileV2', }, }, { icon: , - text: 'Save as molfile V2', + text: 'Save as molfile V3', data: { - id: 'SaveAsMolfileV2', + id: 'SaveAsMolfileV3', }, }, { @@ -362,7 +362,7 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { }, { icon: , - text: 'Display auto-labeling database', + text: 'Template database', onClick: () => openDialog('autoLabelDatabaseDialog'), }, ]; From 65aebd403780fd80a4a238c6eef3f34cd473bbd4 Mon Sep 17 00:00:00 2001 From: Luc Patiny Date: Thu, 15 Jan 2026 21:20:46 +0100 Subject: [PATCH 07/10] chore: update template database --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1e0748c10..4d9db824f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.11.0", + "openchemlib-utils": "^8.12.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", @@ -9621,9 +9621,9 @@ "peer": true }, "node_modules/openchemlib-utils": { - "version": "8.11.0", - "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.11.0.tgz", - "integrity": "sha512-uklqdZNSqotr/uVs3IOANPxtZWLyDZGy5uDYI0uizHvwckyrgAb1jNTw1Cy97fH3yTX075i/sfCWcwzAhXPeiQ==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.12.0.tgz", + "integrity": "sha512-a6o1NLSaXevbYBOfWg9crpyEAHbXvKMvrHTiurV3DCCdlCQEyjq7O0l0QM+2NPgQ/96z9YnQhNms29US/mY2ew==", "license": "MIT", "dependencies": { "atom-sorter": "^2.2.1", diff --git a/package.json b/package.json index 61bbde420..626bf946f 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.11.0", + "openchemlib-utils": "^8.12.0", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", From c76b13ccb0454dd694c2366e1dae7f4e3e0479c2 Mon Sep 17 00:00:00 2001 From: Luc Patiny Date: Fri, 16 Jan 2026 08:35:04 +0100 Subject: [PATCH 08/10] chore: update openchemlib-utils --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d9db824f..0fdc8372b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.12.0", + "openchemlib-utils": "^8.12.1", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", @@ -9621,9 +9621,9 @@ "peer": true }, "node_modules/openchemlib-utils": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.12.0.tgz", - "integrity": "sha512-a6o1NLSaXevbYBOfWg9crpyEAHbXvKMvrHTiurV3DCCdlCQEyjq7O0l0QM+2NPgQ/96z9YnQhNms29US/mY2ew==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/openchemlib-utils/-/openchemlib-utils-8.12.1.tgz", + "integrity": "sha512-aQbEzLxunuRqwEVw6I98J9NL+Mxo3uASLbFjhsFe4ZuJZWN7G+s8tgmXO43+9kaNNeD8lAjcG6+EHNhwX+TV3w==", "license": "MIT", "dependencies": { "atom-sorter": "^2.2.1", diff --git a/package.json b/package.json index 626bf946f..fbff20b23 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "nmr-processing": "^22.1.0", "numeral": "^2.0.6", "openchemlib": "^9.18.2", - "openchemlib-utils": "^8.12.0", + "openchemlib-utils": "^8.12.1", "papaparse": "^5.5.3", "react-d3-utils": "^3.1.2", "react-dropzone": "^14.3.8", From 237a7cfcc4f9b0fd22f93c612b602300bd05a957 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Fri, 16 Jan 2026 09:03:47 +0100 Subject: [PATCH 09/10] refactor: automatically close the modal when a molecule is added from the template database --- src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx index cc3ea88f3..835c34ae1 100644 --- a/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx +++ b/src/component/modal/MoleculeAutoLabelsDatabaseModal.tsx @@ -140,6 +140,8 @@ export function MoleculeAutoLabelsDatabaseModal({ type: 'ADD_MOLECULE', payload: { molfile: molecule.toMolfileV3(), label }, }); + + onClose(); } const filteredLabelDatabase = filter(autoLabelDatabase, { keywords }); From 68c5c46ba63348e17ab1b585223d86f200f3d033 Mon Sep 17 00:00:00 2001 From: hamed musallam Date: Fri, 16 Jan 2026 09:17:11 +0100 Subject: [PATCH 10/10] refactor: add tooltip over 'Auto label atoms' --- src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx index 0a237c3ea..ef9b76da0 100644 --- a/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx +++ b/src/component/panels/MoleculesPanel/MoleculePanelHeader.tsx @@ -358,6 +358,12 @@ export default function MoleculePanelHeader(props: MoleculePanelHeaderProps) { icon: , text: 'Auto label atoms', disabled: !hasMolecules, + tooltip: { + title: 'Auto label atoms', + description: + 'Atoms are automatically labeled according to a predefined template database', + link: 'https://docs.nmrium.org/help/structure-labelling', + }, onClick: () => autoLabels(), }, {