From 7cf9503f8e3c06cee4af659f024b55d5d309c310 Mon Sep 17 00:00:00 2001 From: Venkata Nainala Date: Sun, 4 Oct 2026 11:37:00 +0200 Subject: [PATCH] Revert "Merge pull request #315 from NFDI4Chem/feat/highlight-peak-action-request" This reverts commit 2193ddf1ed0f5fa30e599631dc0c24a49e47cceb, reversing changes made to ffb97b53fa6c7d41f7ace7b70983ec8f18bad0c0. --- src/NMRiumWrapper.tsx | 50 +------ src/demo/NMRiumWrapperDemo.tsx | 26 ---- src/events/types.ts | 25 +--- src/highlight/highlightBridge.tsx | 69 --------- src/highlight/highlightCommands.ts | 30 ---- src/highlight/nmrium-highlight-original.d.ts | 33 ----- src/highlight/resolvePeak.ts | 147 ------------------- test-e2e/core.test.ts | 41 ------ tsconfig.json | 14 +- vite.config.ts | 49 +------ 10 files changed, 9 insertions(+), 475 deletions(-) delete mode 100644 src/highlight/highlightBridge.tsx delete mode 100644 src/highlight/highlightCommands.ts delete mode 100644 src/highlight/nmrium-highlight-original.d.ts delete mode 100644 src/highlight/resolvePeak.ts diff --git a/src/NMRiumWrapper.tsx b/src/NMRiumWrapper.tsx index ef25ca3..e3cc3fa 100644 --- a/src/NMRiumWrapper.tsx +++ b/src/NMRiumWrapper.tsx @@ -1,4 +1,4 @@ -import type { NMRiumChangeCb, NMRiumRefAPI, NMRiumState } from 'nmrium'; +import type { NMRiumChangeCb, NMRiumRefAPI } from 'nmrium'; import { NMRium } from 'nmrium'; import type { CSSProperties } from 'react'; import { useCallback, useEffect, useRef } from 'react'; @@ -7,9 +7,6 @@ import { RootLayout } from 'react-science/ui'; import { LoadingIndicator } from './Loadingindicator.js'; import { loadSpectraFromSource } from './data-source/loadSpectraFromSource.js'; import events from './events/event.js'; -import type { HighlightPeakParams } from './events/types.js'; -import { applyPeakHighlight } from './highlight/highlightCommands.js'; -import { resolveHighlightPeak } from './highlight/resolvePeak.js'; import { useLoadSpectra } from './hooks/useLoadSpectra.js'; import { usePreferences } from './hooks/usePreferences.js'; import { useWhiteList } from './hooks/useWhiteList.js'; @@ -21,20 +18,9 @@ const containerStyle: CSSProperties = { position: 'relative', }; -const ACCEPTED_ACTION_TYPES = - "'exportSpectraViewerAsBlob', 'selectTab', 'highlightPeak', or 'clearHighlight'"; - -function reportActionError(message: string) { - const error = new Error(message); - events.trigger('error', error); - // eslint-disable-next-line no-console - console.error(error); -} - export default function NMRiumWrapper() { const { allowedOrigins, isFetchAllowedOriginsPending } = useWhiteList(); const nmriumRef = useRef(null); - const latestStateRef = useRef(null); const { workspace, preferences, @@ -50,31 +36,9 @@ export default function NMRiumWrapper() { if (source === 'view' && state.data.actionType === 'SET_2D_LEVEL') { return; } - latestStateRef.current = state; events.trigger('data-change', { state, source }); }, []); - const handleHighlightPeak = useCallback( - (params: HighlightPeakParams) => { - const resolved = resolveHighlightPeak(latestStateRef.current, params); - if (!resolved.ok) { - reportActionError(resolved.message); - return; - } - - const nucleus = params.nucleus?.trim(); - if (nucleus) { - setActiveTab({ tab: nucleus.toUpperCase() }); - } - - applyPeakHighlight( - resolved.ids, - params.permanent === false ? 'show' : 'permanent', - ); - }, - [setActiveTab], - ); - useEffect(() => { if (!spectraSource) return; @@ -114,17 +78,9 @@ export default function NMRiumWrapper() { setActiveTab({ tab: tab.toUpperCase() }); break; } - case 'highlightPeak': { - handleHighlightPeak(request.params); - break; - } - case 'clearHighlight': { - applyPeakHighlight([], 'clear'); - break; - } default: { - reportActionError( - `ERROR! Property 'type' accepts only ${ACCEPTED_ACTION_TYPES}.`, + throw new Error( + `ERROR! Property 'type' accepts only 'exportViewerAsBlob'.`, ); } } diff --git a/src/demo/NMRiumWrapperDemo.tsx b/src/demo/NMRiumWrapperDemo.tsx index 8b81eb3..00388e3 100644 --- a/src/demo/NMRiumWrapperDemo.tsx +++ b/src/demo/NMRiumWrapperDemo.tsx @@ -105,32 +105,6 @@ export default function NMRiumWrapperDemo() { > Test Logger - - diff --git a/src/events/types.ts b/src/events/types.ts index 4344026..4227d51 100644 --- a/src/events/types.ts +++ b/src/events/types.ts @@ -28,22 +28,6 @@ type LoadData = activeTab?: string; }; -interface HighlightPeakParams { - /** Peak id from `spectrum.peaks.values[].id`. */ - id?: string; - /** Nucleus tab to activate before highlighting, for example `1H` or `13C`. */ - nucleus?: string; - /** Chemical shift in ppm. Used when `id` is omitted. */ - ppm?: number; - /** Maximum distance in ppm when matching by `nucleus` and `ppm`. Defaults to 0.05. */ - tolerance?: number; - /** - * `true` keeps the highlight until the next highlight or `clearHighlight`. - * `false` applies a temporary highlight. Defaults to `true`. - */ - permanent?: boolean; -} - type ActionRequest = | { type: 'exportSpectraViewerAsBlob'; @@ -51,13 +35,6 @@ type ActionRequest = | { type: 'selectTab'; params: { tab: string }; - } - | { - type: 'highlightPeak'; - params: HighlightPeakParams; - } - | { - type: 'clearHighlight'; }; interface ActionResponse { @@ -81,4 +58,4 @@ type EventData = T extends 'data-change' : T extends 'error' ? Error : never; -export type { EventData, EventType, HighlightPeakParams }; +export type { EventData, EventType }; diff --git a/src/highlight/highlightBridge.tsx b/src/highlight/highlightBridge.tsx deleted file mode 100644 index dff4ead..0000000 --- a/src/highlight/highlightBridge.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { - HighlightProvider as NmriumHighlightProvider, - useHighlightData, -} from 'nmrium-highlight-original'; -import type { PropsWithChildren } from 'react'; -import { useEffect, useRef } from 'react'; - -import { subscribePeakHighlight } from './highlightCommands.js'; - -export { - isHighlightEventSource, - useHighlight, - useHighlightData, -} from 'nmrium-highlight-original'; - -export { applyPeakHighlight } from './highlightCommands.js'; -export type { HighlightMode } from './highlightCommands.js'; - -function HighlightDispatcher() { - const { dispatch, highlight } = useHighlightData(); - const highlightedRef = useRef(highlight.highlighted); - - useEffect(() => { - highlightedRef.current = highlight.highlighted; - }, [highlight.highlighted]); - - useEffect(() => { - return subscribePeakHighlight(({ ids, mode }) => { - const previous = highlightedRef.current; - if (previous.length > 0) { - dispatch({ - type: 'HIDE', - payload: { convertedHighlights: previous }, - }); - } - dispatch({ type: 'UNSET_PERMANENT' }); - - if (mode === 'clear' || ids.length === 0) { - return; - } - - const sourceData = { - type: 'PEAK' as const, - extra: { id: ids[0] }, - }; - dispatch({ - type: 'SHOW', - payload: { convertedHighlights: ids, sourceData }, - }); - if (mode === 'permanent') { - dispatch({ - type: 'SET_PERMANENT', - payload: { convertedHighlights: ids }, - }); - } - }); - }, [dispatch]); - - return null; -} - -export function HighlightProvider(props: PropsWithChildren) { - return ( - - - {props.children} - - ); -} diff --git a/src/highlight/highlightCommands.ts b/src/highlight/highlightCommands.ts deleted file mode 100644 index 90cb1b6..0000000 --- a/src/highlight/highlightCommands.ts +++ /dev/null @@ -1,30 +0,0 @@ -export type HighlightMode = 'show' | 'permanent' | 'clear'; - -export interface HighlightCommand { - ids: string[]; - mode: HighlightMode; -} - -type HighlightListener = (command: HighlightCommand) => void; - -const listeners = new Set(); -let queuedCommand: HighlightCommand | null = null; - -export function applyPeakHighlight(ids: string[], mode: HighlightMode): void { - queuedCommand = { ids, mode }; - for (const listener of listeners) { - listener(queuedCommand); - } -} - -export function subscribePeakHighlight( - listener: HighlightListener, -): () => void { - listeners.add(listener); - if (queuedCommand) { - listener(queuedCommand); - } - return () => { - listeners.delete(listener); - }; -} diff --git a/src/highlight/nmrium-highlight-original.d.ts b/src/highlight/nmrium-highlight-original.d.ts deleted file mode 100644 index 4cdba8e..0000000 --- a/src/highlight/nmrium-highlight-original.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -declare module 'nmrium-highlight-original' { - import type { JSX, PropsWithChildren } from 'react'; - - export function isHighlightEventSource( - source: unknown, - ...types: string[] - ): boolean; - - export function HighlightProvider(props: PropsWithChildren): JSX.Element; - - export function useHighlightData(): { - highlight: { - highlighted: string[]; - highlightedPermanently: string[]; - }; - dispatch: (action: { - type: 'HIDE' | 'SHOW' | 'SET_PERMANENT' | 'UNSET_PERMANENT'; - payload?: { - convertedHighlights?: string[]; - sourceData?: { - type: 'PEAK'; - extra: { id: string; spectrumID?: string }; - } | null; - }; - }) => void; - remove: () => void; - }; - - export function useHighlight( - highlights: Array, - sourceData?: unknown, - ): unknown; -} diff --git a/src/highlight/resolvePeak.ts b/src/highlight/resolvePeak.ts deleted file mode 100644 index 4bb302b..0000000 --- a/src/highlight/resolvePeak.ts +++ /dev/null @@ -1,147 +0,0 @@ -import type { HighlightPeakParams } from '../events/types.js'; - -export const DEFAULT_HIGHLIGHT_TOLERANCE_PPM = 0.05; - -interface PeakLike { - id?: string; - x?: number; -} - -interface SpectrumLike { - id?: string; - info?: { nucleus?: string | string[] }; - peaks?: { values?: PeakLike[] }; -} - -export interface HighlightableState { - data?: { - spectra?: SpectrumLike[]; - }; -} - -export type ResolveHighlightResult = - | { ok: true; ids: string[] } - | { - ok: false; - reason: 'invalid' | 'not-loaded' | 'no-peaks' | 'no-match'; - message: string; - }; - -const ACCEPTED_PARAMS = - "Property 'params' requires 'id', or both 'nucleus' and 'ppm'."; - -function nucleusMatches(spectrum: SpectrumLike, nucleus: string): boolean { - const value = spectrum.info?.nucleus; - if (typeof value === 'string') { - return value.toUpperCase() === nucleus.toUpperCase(); - } - if (Array.isArray(value)) { - return value.some( - (entry) => - typeof entry === 'string' && - entry.toUpperCase() === nucleus.toUpperCase(), - ); - } - return false; -} - -function peakValues(spectrum: SpectrumLike): PeakLike[] { - const values = spectrum.peaks?.values; - return Array.isArray(values) ? values : []; -} - -export function resolveHighlightPeak( - state: HighlightableState | null | undefined, - params: HighlightPeakParams, -): ResolveHighlightResult { - const id = params.id?.trim(); - const nucleus = params.nucleus?.trim(); - const ppm = params.ppm; - const tolerance = params.tolerance ?? DEFAULT_HIGHLIGHT_TOLERANCE_PPM; - const hasPpm = typeof ppm === 'number' && Number.isFinite(ppm); - - if (!id && (!nucleus || !hasPpm)) { - return { ok: false, reason: 'invalid', message: ACCEPTED_PARAMS }; - } - - if (!Number.isFinite(tolerance) || tolerance < 0) { - return { - ok: false, - reason: 'invalid', - message: "Property 'tolerance' must be a non-negative number.", - }; - } - - const spectra = state?.data?.spectra; - if (!Array.isArray(spectra)) { - return { - ok: false, - reason: 'not-loaded', - message: 'No spectrum is loaded.', - }; - } - - if (id) { - let sawPeaks = false; - for (const spectrum of spectra) { - const values = peakValues(spectrum); - if (values.length > 0) { - sawPeaks = true; - } - const match = values.find((peak) => peak.id === id); - if (match?.id) { - return { ok: true, ids: [match.id] }; - } - } - if (!sawPeaks) { - return { - ok: false, - reason: 'no-peaks', - message: 'Peaks are not available yet.', - }; - } - return { - ok: false, - reason: 'no-match', - message: `No peak with id '${id}'.`, - }; - } - - const candidates = spectra.filter((spectrum) => - nucleusMatches(spectrum, nucleus ?? ''), - ); - let closest: { id: string; distance: number } | null = null; - let sawPeaks = false; - - for (const spectrum of candidates) { - for (const peak of peakValues(spectrum)) { - if (typeof peak.x !== 'number' || !peak.id) { - continue; - } - sawPeaks = true; - const distance = Math.abs(peak.x - (ppm ?? 0)); - if ( - distance <= tolerance && - (closest === null || distance < closest.distance) - ) { - closest = { id: peak.id, distance }; - } - } - } - - if (closest) { - return { ok: true, ids: [closest.id] }; - } - if (!sawPeaks) { - return { - ok: false, - reason: 'no-peaks', - message: 'Peaks are not available yet.', - }; - } - return { - ok: false, - reason: 'no-match', - message: `No ${nucleus} peak within ${tolerance} ppm of ${ppm}.`, - }; -} diff --git a/test-e2e/core.test.ts b/test-e2e/core.test.ts index 7504d8d..12ff66f 100644 --- a/test-e2e/core.test.ts +++ b/test-e2e/core.test.ts @@ -125,44 +125,3 @@ test('should load test-data.nmrium file', async ({ await nmrium.checkSpectraTabsIsVisible(['1H', '13C', '1H,1H', '1H,13C']) }); - -test('should highlight a peak via nmr-wrapper:action-request', async ({ - page, -}) => { - const nmrium = await NmriumWrapperPage.create(page); - - await nmrium.page.click('text=Test load from json'); - await expect(nmrium.page.locator('.tab-list-item >> text=13C')).toBeVisible(); - await expect(nmrium.page.locator('g.peaks path').first()).toBeVisible(); - - await page.evaluate(() => { - window.postMessage( - { - type: 'nmr-wrapper:action-request', - data: { - type: 'highlightPeak', - params: { nucleus: '13C', ppm: 77.95, tolerance: 0.05 }, - }, - }, - '*', - ); - }); - - await expect( - nmrium.page.locator('g.peaks path[stroke-width="3px"]'), - ).toHaveCount(1); - - await page.evaluate(() => { - window.postMessage( - { - type: 'nmr-wrapper:action-request', - data: { type: 'clearHighlight' }, - }, - '*', - ); - }); - - await expect( - nmrium.page.locator('g.peaks path[stroke-width="3px"]'), - ).toHaveCount(0); -}); diff --git a/tsconfig.json b/tsconfig.json index 360d209..14c824c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,11 +9,6 @@ "vite/client", "vite-plugin-pwa/client.d.ts" ], - "paths": { - "nmrium-highlight-original": [ - "./src/highlight/nmrium-highlight-original.d.ts" - ] - }, "outDir": "lib", "allowJs": false, "strict": true, @@ -21,7 +16,6 @@ "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "NodeNext", - "moduleResolution": "NodeNext", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, @@ -30,12 +24,12 @@ "sourceMap": true, "declaration": true, "declarationMap": true, - "skipLibCheck": true + "skipLibCheck": true, }, "include": [ "src", "test-e2e", "playwright.config.ts", - "vite.config.ts" - ] -} + "vite.config.ts", + ], +} \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 671f0a6..3f58be6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,49 +1,7 @@ -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - import react from '@vitejs/plugin-react'; -import type { Plugin } from 'vite'; import { defineConfig } from 'vite'; import { VitePWA, type Options } from 'vite-plugin-pwa'; -const rootDir = path.dirname(fileURLToPath(import.meta.url)); -const nmriumHighlightPath = path.resolve( - rootDir, - 'node_modules/nmrium/lib/component/highlight/index.js', -); -const highlightBridgePath = path.resolve( - rootDir, - 'src/highlight/highlightBridge.tsx', -); - -function nmriumHighlightBridgePlugin(): Plugin { - return { - name: 'nmrium-highlight-bridge', - enforce: 'pre', - resolveId(source, importer) { - if (source === 'nmrium-highlight-original') { - return `${nmriumHighlightPath}?original`; - } - - const isHighlightImport = - source === '../highlight/index.js' || - source === '../../highlight/index.js' || - source.endsWith('/highlight/index.js') || - source === nmriumHighlightPath; - - if (!isHighlightImport) { - return null; - } - - if (importer?.includes('highlightBridge')) { - return null; - } - - return highlightBridgePath; - }, - }; -} - const pwaSettings: Partial = { // cache all the imports // workbox: { @@ -124,11 +82,6 @@ export default () => { }, } }, - plugins: [nmriumHighlightBridgePlugin(), react(), VitePWA(pwaSettings)], - resolve: { - alias: { - 'nmrium-highlight-original': `${nmriumHighlightPath}?original`, - }, - }, + plugins: [react(), VitePWA(pwaSettings)], }); };