diff --git a/src/component/panels/databasePanel/DatabasePanel.tsx b/src/component/panels/databasePanel/DatabasePanel.tsx
index 6eeb9df21..0f960ae40 100644
--- a/src/component/panels/databasePanel/DatabasePanel.tsx
+++ b/src/component/panels/databasePanel/DatabasePanel.tsx
@@ -11,7 +11,6 @@ import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useOnOff } from 'react-science/ui';
import { getSum } from '../../../data/data1d/Spectrum1D/SumManager.js';
-import { isSpectrum1D } from '../../../data/data1d/Spectrum1D/index.js';
import type {
InitiateDatabaseResult,
LocalDatabase,
@@ -100,6 +99,22 @@ function mapKeywordsToArray(searchKeywords: string, solvent: string) {
return values;
}
+function resolveSpectraURL(
+ rowData: {
+ baseURL: string;
+ jcampURL: string;
+ jcampFullURL: string;
+ },
+ isFullJcamp: boolean,
+): URL | null {
+ const { baseURL, jcampURL, jcampFullURL } = rowData;
+ const spectraURL = isFullJcamp ? jcampFullURL : jcampURL;
+
+ if (!spectraURL) return null;
+
+ return new URL(spectraURL, baseURL);
+}
+
function DatabasePanelInner({
nucleus,
selectedTool,
@@ -285,49 +300,44 @@ function DatabasePanelInner({
const core = useCore();
const resurrectHandler = useCallback(
- (rowData: any) => {
- const {
- index,
- baseURL,
- jcampURL: jcampRelativeURL,
- ocl,
- smiles,
- } = rowData;
+ (rowData: any, isFullJcamp = false) => {
+ const { index, ocl, smiles } = rowData;
const molfile = getMolfile({ ocl, smiles });
const databaseEntry = result.data[index];
- if (jcampRelativeURL) {
- const url = new URL(jcampRelativeURL, baseURL);
- setTimeout(async () => {
- const hideLoading = toaster.showLoading({
- message: `load jcamp in progress...`,
- });
+ const spectraURL = resolveSpectraURL(rowData, isFullJcamp);
- try {
- const {
- state: { data },
- } = await core.readFromWebSource({
- entries: [{ baseURL: url.origin, relativePath: url.pathname }],
- });
- const spectrum = data?.spectra?.[0] || null;
- if (spectrum && isSpectrum1D(spectrum)) {
- dispatch({
- type: 'RESURRECTING_SPECTRUM',
- payload: { source: 'jcamp', databaseEntry, spectrum, molfile },
- });
- }
- } catch {
- toaster.show({ message: 'Failed to load Jcamp', intent: 'danger' });
- } finally {
- hideLoading();
- }
- }, 0);
- } else {
+ if (!spectraURL) {
dispatch({
- type: 'RESURRECTING_SPECTRUM',
- payload: { source: 'rangesOrSignals', databaseEntry, molfile },
+ type: 'RESURRECTING_SPECTRUM_FROM_SIGNALS_OR_RANGES',
+ payload: { databaseEntry, molfile },
});
+ return;
}
+
+ setTimeout(async () => {
+ const hideLoading = toaster.showLoading({
+ message: `load jcamp in progress...`,
+ });
+
+ try {
+ const {
+ state: { data },
+ } = await core.readFromWebSource({
+ entries: [
+ { baseURL: spectraURL.origin, relativePath: spectraURL.pathname },
+ ],
+ });
+ dispatch({
+ type: 'RESURRECTING_SPECTRUM_FROM_JCAMP',
+ payload: { databaseEntry, spectra: data?.spectra || [], molfile },
+ });
+ } catch {
+ toaster.show({ message: 'Failed to load Jcamp', intent: 'danger' });
+ } finally {
+ hideLoading();
+ }
+ }, 0);
},
[core, dispatch, result.data, toaster],
);
diff --git a/src/component/panels/databasePanel/DatabaseTable.tsx b/src/component/panels/databasePanel/DatabaseTable.tsx
index e91485a0a..e29895a51 100644
--- a/src/component/panels/databasePanel/DatabaseTable.tsx
+++ b/src/component/panels/databasePanel/DatabaseTable.tsx
@@ -2,7 +2,7 @@ import { Classes } from '@blueprintjs/core';
import dlv from 'dlv';
import type { DatabaseNMREntry } from 'nmr-processing';
import type { CSSProperties } from 'react';
-import { memo, useMemo } from 'react';
+import { memo, useCallback, useMemo } from 'react';
import { ResponsiveChart } from 'react-d3-utils';
import { FaDownload, FaInfoCircle, FaMinus, FaPlus } from 'react-icons/fa';
import { IdcodeSvgRenderer, SmilesSvgRenderer } from 'react-ocl';
@@ -11,6 +11,7 @@ import type { CellProps } from 'react-table';
import type { PrepareDataResult } from '../../../data/data1d/database.js';
import { ColumnWrapper } from '../../elements/ColumnWrapper.js';
+import type { ContextMenuItem } from '../../elements/ContextMenuBluePrint.tsx';
import type { Column } from '../../elements/ReactTable/ReactTable.js';
import ReactTable from '../../elements/ReactTable/ReactTable.js';
import type { CustomColumn } from '../../elements/ReactTable/utility/addCustomColumn.js';
@@ -21,8 +22,17 @@ import { formatNumber } from '../../utility/formatNumber.js';
import { DatabaseInfo } from './DatabaseInfo.js';
+const contextMenu: ContextMenuItem[] = [
+ {
+ text: 'Add all spectra',
+ icon: ,
+ data: { id: 'addAllSpectra' },
+ disabled: (data) => !data.jcampFullURL,
+ },
+];
+
interface ToggleEvent {
- onAdd: (row: any) => void;
+ onAdd: (row: any, isFullJcamp: boolean) => void;
onRemove: (row: any) => void;
}
interface DatabaseTableProps extends ToggleEvent {
@@ -266,9 +276,25 @@ function DatabaseTable({
columns.sort((object1, object2) => object1.index - object2.index);
return columns;
}, [databasePreferences, initialColumns]);
+
+ const selectContextMenuHandler = useCallback(
+ (option: any, data: any) => {
+ const { id } = option;
+
+ if (id !== 'addAllSpectra') {
+ return;
+ }
+
+ onAdd(data, true);
+ },
+ [onAdd],
+ );
+
return (
({
@@ -304,7 +330,7 @@ function ToggleBtn(props: ToggleBtnProps) {
if (isAdded) {
onRemove(data);
} else {
- onAdd(data);
+ onAdd(data, false);
}
}}
>
diff --git a/src/component/reducer/Reducer.ts b/src/component/reducer/Reducer.ts
index 40d05bf6e..04032deeb 100644
--- a/src/component/reducer/Reducer.ts
+++ b/src/component/reducer/Reducer.ts
@@ -788,8 +788,13 @@ function innerSpectrumReducer(draft: Draft, action: Action) {
action,
);
- case 'RESURRECTING_SPECTRUM':
- return DatabaseActions.handleResurrectSpectrum(draft, action);
+ case 'RESURRECTING_SPECTRUM_FROM_SIGNALS_OR_RANGES':
+ return DatabaseActions.handleResurrectSpectrumFromRangesOrSignals(
+ draft,
+ action,
+ );
+ case 'RESURRECTING_SPECTRUM_FROM_JCAMP':
+ return DatabaseActions.handleResurrectSpectrumFromJCAMP(draft, action);
case 'TOGGLE_SIMILARITY_TREE':
return DatabaseActions.handleToggleSimilarityTree(draft);
diff --git a/src/component/reducer/actions/DatabaseActions.ts b/src/component/reducer/actions/DatabaseActions.ts
index 37ce99c87..82ba260aa 100644
--- a/src/component/reducer/actions/DatabaseActions.ts
+++ b/src/component/reducer/actions/DatabaseActions.ts
@@ -1,18 +1,22 @@
import type { Info1D } from '@zakodium/nmr-types';
-import type { Spectrum1D, Spectrum } from '@zakodium/nmrium-core';
+import type { Spectrum } from '@zakodium/nmrium-core';
import type { Draft } from 'immer';
import type { DatabaseNMREntry } from 'nmr-processing';
import {
- get1DColor,
+ initiateDatum1D,
isSpectrum1D,
mapRanges,
+ updateRangesRelativeValues,
} from '../../../data/data1d/Spectrum1D/index.js';
import {
resurrectSpectrumFromRanges,
resurrectSpectrumFromSignals,
} from '../../../data/data1d/Spectrum1D/ranges/resurrectSpectrum.js';
+import { initializeContoursLevels } from '../../../data/data2d/Spectrum2D/contours.ts';
+import { initiateDatum2D } from '../../../data/data2d/Spectrum2D/initiateDatum2D.ts';
import { filterDatabaseInfoEntry } from '../../utility/filterDatabaseInfoEntry.js';
+import { getSpectraByNucleus } from '../../utility/getSpectraByNucleus.ts';
import type { State } from '../Reducer.js';
import { setZoom } from '../helper/Zoom1DManager.js';
import zoomHistoryManager from '../helper/ZoomHistoryManager.js';
@@ -28,34 +32,103 @@ interface BaseResurrectSpectrum {
molfile?: string;
}
interface ResurrectSpectrumFromJCAMP extends BaseResurrectSpectrum {
- source: 'jcamp';
- spectrum: Spectrum1D;
+ spectra: Spectrum[];
}
-interface ResurrectSpectrumFromRangesOrSignals extends BaseResurrectSpectrum {
- source: 'rangesOrSignals';
-}
-
-type ResurrectSpectrum =
- | ResurrectSpectrumFromJCAMP
- | ResurrectSpectrumFromRangesOrSignals;
-type ResurrectSpectrumAction = ActionType<
- 'RESURRECTING_SPECTRUM',
- ResurrectSpectrum
+type ResurrectSpectrumFromRangesOrSignalsAction = ActionType<
+ 'RESURRECTING_SPECTRUM_FROM_SIGNALS_OR_RANGES',
+ BaseResurrectSpectrum
+>;
+type ResurrectSpectrumFromJCAMPAction = ActionType<
+ 'RESURRECTING_SPECTRUM_FROM_JCAMP',
+ ResurrectSpectrumFromJCAMP
>;
export type DatabaseActions =
| ActionType<'TOGGLE_SIMILARITY_TREE'>
- | ResurrectSpectrumAction;
+ | ResurrectSpectrumFromRangesOrSignalsAction
+ | ResurrectSpectrumFromJCAMPAction;
+
+function updateDomain(draft: Draft) {
+ setDomain(draft, { isYDomainShared: false });
+ changeSpectrumVerticalAlignment(draft, { verticalAlign: 'stack' });
+
+ const zoomHistory = zoomHistoryManager(
+ draft.zoom.history,
+ draft.view.spectra.activeTab,
+ );
+ const zoomValue = zoomHistory.getLast();
+ if (zoomValue) {
+ draft.xDomain = zoomValue.xDomain;
+ draft.yDomain = zoomValue.yDomain;
+ }
+}
-function handleResurrectSpectrum(
+function handleResurrectSpectrumFromJCAMP(
draft: Draft,
- action: ResurrectSpectrumAction,
+ action: ResurrectSpectrumFromJCAMPAction,
+) {
+ const { databaseEntry, spectra, molfile } = action.payload;
+ const { ranges, id: spectrumID, nucleus } = databaseEntry;
+
+ if (spectra.length === 0) return;
+
+ const containOneSpectrum = spectra.length === 1;
+ const spectra1D = [];
+
+ if (molfile) {
+ addMolecule(draft, { molfile, id: spectra[0].id });
+ }
+
+ for (const spectrum of spectra) {
+ const filterDatabaseEntryInfo = filterDatabaseInfoEntry(databaseEntry);
+ if (isSpectrum1D(spectrum)) {
+ const spectrum1D = initiateDatum1D(spectrum, {
+ usedColors: draft.usedColors,
+ });
+
+ if (spectrum.info.nucleus === nucleus) {
+ spectrum1D.ranges.values = mapRanges(ranges, spectrum);
+ updateRangesRelativeValues(spectrum1D);
+ }
+
+ if (containOneSpectrum) {
+ spectrum1D.id = spectrumID;
+ }
+
+ draft.data.push(spectrum1D);
+ spectra1D.push(spectrum1D);
+ } else {
+ const spectrum2d = initiateDatum2D(spectrum, {
+ usedColors: draft.usedColors,
+ });
+ spectrum2d.customInfo = filterDatabaseEntryInfo;
+ draft.view.spectraContourLevels[spectrum2d.id] =
+ initializeContoursLevels(spectrum2d);
+ draft.data.push(spectrum2d);
+ }
+ }
+
+ updateDomain(draft);
+
+ const active1DSpectra = getSpectraByNucleus(
+ draft.view.spectra.activeTab,
+ spectra1D,
+ );
+
+ for (const spectrum of active1DSpectra) {
+ setZoom(draft, { scale: 0.8, spectrumID: spectrum.id });
+ }
+}
+
+function handleResurrectSpectrumFromRangesOrSignals(
+ draft: Draft,
+ action: ResurrectSpectrumFromRangesOrSignalsAction,
) {
const {
spectra: { activeTab: nucleus },
} = draft.view;
- const { databaseEntry, source, molfile } = action.payload;
+ const { databaseEntry, molfile } = action.payload;
const {
ranges,
signals,
@@ -64,54 +137,35 @@ function handleResurrectSpectrum(
id: spectrumID,
} = databaseEntry;
- let resurrectedSpectrum: Spectrum | null | undefined = null;
-
- if (source === 'jcamp') {
- const { spectrum } = action.payload;
-
- resurrectedSpectrum = {
- ...spectrum,
- id: spectrumID,
- ranges: {
- ...spectrum.ranges,
- values: mapRanges(ranges, spectrum),
- },
- display: {
- ...spectrum.display,
- ...get1DColor(spectrum.display, { usedColors: draft.usedColors }),
- },
- };
+ let options: { from?: number; to?: number } = {};
+ let info: Partial = { solvent, name: names[0], nucleus };
+
+ const activeSpectrum = getSpectrum(draft) || draft.data[0];
+ if (isSpectrum1D(activeSpectrum)) {
+ const {
+ data: { x },
+ info: spectrumInfo,
+ } = activeSpectrum;
+ options = { from: x[0], to: x.at(-1) };
+ info = { ...spectrumInfo, ...info };
}
- if (source === 'rangesOrSignals') {
- const activeSpectrum = getSpectrum(draft) || draft.data[0];
- let options: { from?: number; to?: number } = {};
- let info: Partial = { solvent, name: names[0], nucleus };
-
- if (isSpectrum1D(activeSpectrum)) {
- const {
- data: { x },
- info: spectrumInfo,
- } = activeSpectrum;
- options = { from: x[0], to: x.at(-1) };
- info = { ...spectrumInfo, ...info };
- }
+ let resurrectedSpectrum: Spectrum | null | undefined = null;
- if (signals) {
- resurrectedSpectrum = resurrectSpectrumFromSignals(signals, {
- spectrumID,
- info,
- usedColors: draft.usedColors,
- ...options,
- });
- } else if (ranges) {
- resurrectedSpectrum = resurrectSpectrumFromRanges(ranges, {
- spectrumID,
- info,
- usedColors: draft.usedColors,
- ...options,
- });
- }
+ if (signals) {
+ resurrectedSpectrum = resurrectSpectrumFromSignals(signals, {
+ spectrumID,
+ info,
+ usedColors: draft.usedColors,
+ ...options,
+ });
+ } else if (ranges) {
+ resurrectedSpectrum = resurrectSpectrumFromRanges(ranges, {
+ spectrumID,
+ info,
+ usedColors: draft.usedColors,
+ ...options,
+ });
}
if (!resurrectedSpectrum) return;
@@ -121,25 +175,12 @@ function handleResurrectSpectrum(
draft.data.push(resurrectedSpectrum);
- setDomain(draft, { isYDomainShared: false });
- //rescale the vertical zoom
- setZoom(draft, { scale: 0.8, spectrumID: resurrectedSpectrum.id });
-
- changeSpectrumVerticalAlignment(draft, { verticalAlign: 'stack' });
+ updateDomain(draft);
- //keep the last horizontal zoom
- const zoomHistory = zoomHistoryManager(
- draft.zoom.history,
- draft.view.spectra.activeTab,
- );
- const zoomValue = zoomHistory.getLast();
- if (zoomValue) {
- draft.xDomain = zoomValue.xDomain;
- draft.yDomain = zoomValue.yDomain;
- }
+ setZoom(draft, { scale: 0.8, spectrumID: resurrectedSpectrum.id });
if (molfile) {
- addMolecule(draft, { molfile, id: spectrumID });
+ addMolecule(draft, { molfile, id: resurrectedSpectrum.id });
}
}
@@ -148,4 +189,8 @@ function handleToggleSimilarityTree(draft: Draft) {
!draft.view.spectra.showSimilarityTree;
}
-export { handleResurrectSpectrum, handleToggleSimilarityTree };
+export {
+ handleResurrectSpectrumFromJCAMP,
+ handleResurrectSpectrumFromRangesOrSignals,
+ handleToggleSimilarityTree,
+};