Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#5190 - Include indigo without render module into ketcher-standalone build process #5212

Merged
merged 3 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions example/vite.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ export default defineConfig({
find: 'web-worker:./indigoWorker',
replacement: './indigoWorker?worker',
},
{
find: '_indigo-ketcher-import-alias_',
replacement: 'indigo-ketcher',
},
],
},
customLogger: logger,
Expand Down
59 changes: 59 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 19 additions & 14 deletions packages/ketcher-core/src/application/ketcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ const allowedApiSettings = {

export class Ketcher {
logging: LogSettings;
#structService: StructService;
structService: StructService;
#formatterFactory: FormatterFactory;
#editor: Editor;
#indigo: Indigo;
_indigo: Indigo;
#eventBus: EventEmitter;

get editor(): Editor {
Expand All @@ -79,9 +79,9 @@ export class Ketcher {
assert(formatterFactory != null);

this.#editor = editor;
this.#structService = structService;
this.structService = structService;
this.#formatterFactory = formatterFactory;
this.#indigo = new Indigo(this.#structService);
this._indigo = new Indigo(this.structService);
this.#eventBus = new EventEmitter();
this.logging = {
enabled: false,
Expand All @@ -95,7 +95,7 @@ export class Ketcher {
}

get indigo() {
return this.#indigo;
return this._indigo;
}

// TEMP.: getting only dearomatize-on-load setting
Expand Down Expand Up @@ -300,7 +300,7 @@ export class Ketcher {
this.#editor.struct(),
);

return this.#structService.getInChIKey(struct);
return this.structService.getInChIKey(struct);
}

containsReaction(): boolean {
Expand Down Expand Up @@ -354,11 +354,11 @@ export class Ketcher {

if (window.isPolymerEditorTurnedOn) {
deleteAllEntitiesOnCanvas();
await parseAndAddMacromoleculesOnCanvas(structStr, this.#structService);
await parseAndAddMacromoleculesOnCanvas(structStr, this.structService);
} else {
const struct: Struct = await prepareStructToRender(
structStr,
this.#structService,
this.structService,
this,
);

Expand All @@ -375,7 +375,7 @@ export class Ketcher {
assert(typeof helmStr === 'string');
const struct: Struct = await prepareStructToRender(
helmStr,
this.#structService,
this.structService,
this,
);
struct.rescale();
Expand All @@ -393,11 +393,11 @@ export class Ketcher {
assert(typeof structStr === 'string');

if (window.isPolymerEditorTurnedOn) {
await parseAndAddMacromoleculesOnCanvas(structStr, this.#structService);
await parseAndAddMacromoleculesOnCanvas(structStr, this.structService);
} else {
const struct: Struct = await prepareStructToRender(
structStr,
this.#structService,
this.structService,
this,
);

Expand All @@ -413,7 +413,7 @@ export class Ketcher {
}

runAsyncAction<void>(async () => {
const struct = await this.#indigo.layout(this.#editor.struct());
const struct = await this._indigo.layout(this.#editor.struct());
const ketSerializer = new KetSerializer();
this.setMolecule(ketSerializer.serialize(struct));
}, this.eventBus);
Expand Down Expand Up @@ -458,7 +458,7 @@ export class Ketcher {
if (window.isPolymerEditorTurnedOn) {
throw new Error('Recognize is not available in macro mode');
}
return this.#indigo.recognize(image, { version });
return this._indigo.recognize(image, { version });
}

async generateImage(
Expand All @@ -481,7 +481,7 @@ export class Ketcher {
options.outputFormat = 'png';
}

const base64 = await this.#structService.generateImageAsBase64(
const base64 = await this.structService.generateImageAsBase64(
data,
options,
);
Expand All @@ -494,4 +494,9 @@ export class Ketcher {
const blob = new Blob([byteArray], { type: meta });
return blob;
}

public reinitializeIndigo(structService: StructService) {
this.structService = structService;
this._indigo = new Indigo(structService);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,5 @@ export interface StructService {
data: ExplicitHydrogensData,
options?: StructServiceOptions,
) => Promise<ExplicitHydrogensResult>;
destroy?: () => void;
}
34 changes: 25 additions & 9 deletions packages/ketcher-react/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ import init, { Config } from './script';
import { useEffect, useRef } from 'react';
import { createRoot, Root } from 'react-dom/client';

import { Ketcher } from 'ketcher-core';
import { Ketcher, StructService } from 'ketcher-core';
import classes from './Editor.module.less';
import clsx from 'clsx';
import { useResizeObserver } from './hooks';
import {
ketcherInitEventName,
KETCHER_ROOT_NODE_CLASS_NAME,
} from './constants';
import { KetcherBuilder } from './script/builders';

const mediaSizes = {
smallWidth: 1040,
Expand All @@ -47,13 +48,24 @@ function Editor(props: EditorProps) {
const initPromiseRef = useRef<ReturnType<typeof init> | null>(null);
const appRootRef = useRef<Root | null>(null);
const cleanupRef = useRef<(() => unknown) | null>(null);
const ketcherBuilderRef = useRef<KetcherBuilder | null>(null);
// eslint-disable-next-line @typescript-eslint/no-empty-function
const setServerRef = useRef<(structService: StructService) => void>(() => {});
const structServiceProvider = props.structServiceProvider;

const rootElRef = useRef<HTMLDivElement>(null);

const { height, width } = useResizeObserver<HTMLDivElement>({
ref: rootElRef,
});

useEffect(() => {
ketcherBuilderRef.current?.reinitializeApi(
props.structServiceProvider,
setServerRef.current,
);
}, [structServiceProvider]);

const initKetcher = () => {
appRootRef.current = createRoot(rootElRef.current as HTMLDivElement);

Expand All @@ -63,15 +75,19 @@ function Editor(props: EditorProps) {
appRoot: appRootRef.current,
});

initPromiseRef.current?.then(({ ketcher, ketcherId, cleanup }) => {
cleanupRef.current = cleanup;
initPromiseRef.current?.then(
({ ketcher, ketcherId, cleanup, builder, setServer }) => {
cleanupRef.current = cleanup;
ketcherBuilderRef.current = builder;
setServerRef.current = setServer;

if (typeof props.onInit === 'function' && ketcher) {
props.onInit(ketcher);
const ketcherInitEvent = new Event(ketcherInitEventName(ketcherId));
window.dispatchEvent(ketcherInitEvent);
}
});
if (typeof props.onInit === 'function' && ketcher) {
props.onInit(ketcher);
const ketcherInitEvent = new Event(ketcherInitEventName(ketcherId));
window.dispatchEvent(ketcherInitEvent);
}
},
);
};
useEffect(() => {
if (initPromiseRef.current === null) {
Expand Down
3 changes: 3 additions & 0 deletions packages/ketcher-react/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,6 @@ export const KETCHER_ROOT_NODE_CSS_SELECTOR = `.${KETCHER_ROOT_NODE_CLASS_NAME}`

export const EditorClassName = 'Ketcher-polymer-editor-root';
export const KETCHER_MACROMOLECULES_ROOT_NODE_SELECTOR = `.${EditorClassName}`;
export const STRUCT_SERVICE_NO_RENDER_INITIALIZED_EVENT =
'struct-service-no-render-initialized';
export const STRUCT_SERVICE_INITIALIZED_EVENT = 'struct-service-initialized';
1 change: 1 addition & 0 deletions packages/ketcher-react/src/script/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ function createApi(
getInChIKey: structService.getInChIKey.bind(structService),
toggleExplicitHydrogens:
structService.toggleExplicitHydrogens.bind(structService),
destroy: structService.destroy?.bind(structService),
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
StructService,
StructServiceProvider,
ketcherProvider,
KetcherLogger,
} from 'ketcher-core';

import { ButtonsConfig } from './ButtonsConfig';
Expand All @@ -30,6 +31,7 @@ import createApi from '../../api';
import { initApp } from '../../ui';
import { Root } from 'react-dom/client';
import { IndigoProvider } from 'src/script/providers';
import { STRUCT_SERVICE_INITIALIZED_EVENT } from '../../../constants';

class KetcherBuilder {
private structService: StructService | null;
Expand All @@ -51,6 +53,39 @@ class KetcherBuilder {
);
}

reinitializeApi(
structServiceProvider: StructServiceProvider,
setStructServiceToStore: (structService: StructService) => void,
) {
const oldStructService = this.structService;

this.structService = createApi(
structServiceProvider,
DefaultStructServiceOptions,
);

window.addEventListener(
STRUCT_SERVICE_INITIALIZED_EVENT,
() => {
oldStructService?.destroy?.();

if (!this.structService) {
KetcherLogger.warn('Structure service is not reinitialized');

return;
}

const ketcher = ketcherProvider.getKetcher();
ketcher.reinitializeIndigo(this.structService);
IndigoProvider.setIndigo(this.structService);
setStructServiceToStore(this.structService);
},
{ once: true },
);

return this.structService;
}

appendServiceMode(mode: ServiceMode) {
this.serviceMode = mode;
}
Expand All @@ -66,14 +101,16 @@ class KetcherBuilder {
setKetcher: (ketcher: Ketcher) => void;
ketcherId: string;
cleanup: ReturnType<typeof initApp> | null;
setServer: (structService: StructService) => void;
}> {
const { structService } = this;
let cleanup: ReturnType<typeof initApp> | null = null;

const { editor, setKetcher, ketcherId } = await new Promise<{
const { editor, setKetcher, ketcherId, setServer } = await new Promise<{
editor: Editor;
setKetcher: (ketcher: Ketcher) => void;
ketcherId: string;
setServer: (structService: StructService) => void;
}>((resolve) => {
cleanup = initApp(
element,
Expand All @@ -100,7 +137,7 @@ class KetcherBuilder {
() => {};
this.formatterFactory = new FormatterFactory(structService!);

return { setKetcher, ketcherId, cleanup };
return { setKetcher, ketcherId, cleanup, setServer };
}

build() {
Expand Down
Loading
Loading