Skip to content

Commit

Permalink
#4427 - Macro: Store custom presets in browser local cache
Browse files Browse the repository at this point in the history
  • Loading branch information
ilya-asiyuk-epam committed Apr 23, 2024
1 parent b0f02b8 commit 2a39c23
Show file tree
Hide file tree
Showing 24 changed files with 390 additions and 94 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,26 @@ test.describe('RNA Library', () => {
await takePresetsScreenshot(page);
});

test('Add Custom preset to Presets section and display after page reload', async ({
page,
}) => {
await expandCollapseRnaBuilder(page);
await selectMonomer(page, Sugars.TwelveddR);
await selectMonomer(page, Bases.Adenine);
await selectMonomer(page, Phosphates.Test6Ph);
await page.getByTestId('add-to-presets-btn').click();
await page.getByTestId('12ddR(A)Test-6-Ph_A_12ddR_Test-6-Ph').click();
await expandCollapseRnaBuilder(page);
await takePresetsScreenshot(page);
await page.reload();
await waitForPageInit(page);
await turnOnMacromoleculesEditor(page);
await page.getByTestId('RNA-TAB').click();
await page.getByTestId('12ddR(A)Test-6-Ph_A_12ddR_Test-6-Ph').click();
await expandCollapseRnaBuilder(page);
await takePresetsScreenshot(page);
});

test('Add Custom preset to Canvas', async ({ page }) => {
/*
Test case: #2507 - Add RNA monomers to canvas
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 11 additions & 1 deletion packages/ketcher-core/src/application/editor/tools/Tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,10 +70,20 @@ interface ToolEventHandler {

export interface IRnaPreset {
name?: string;
nameInList?: string;
base?: MonomerItemType;
sugar?: MonomerItemType;
phosphate?: MonomerItemType;
presetInList?: IRnaPreset;
default?: boolean;
favorite?: boolean;
editedName?: boolean;
}

export interface IRnaLabeledPreset
extends Omit<IRnaPreset, 'base' | 'sugar' | 'phosphate'> {
base?: string;
sugar?: string;
phosphate?: string;
}

export type LabeledNucleotideWithPositionInSequence = {
Expand Down
4 changes: 4 additions & 0 deletions packages/ketcher-core/src/domain/entities/Command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@ export class Command {
);
renderersManagers.runPostRenderMethods();
}

public clear() {
this.operations = [];
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import pick from 'lodash/pick';
import omit from 'lodash/omit';
import { AttachmentPointName, MonomerItemType } from 'domain/types';
import { Vec2 } from 'domain/entities/vec2';
import { Command } from 'domain/entities/Command';
Expand Down Expand Up @@ -53,7 +55,9 @@ import { ChainsCollection } from 'domain/entities/monomer-chains/ChainsCollectio
import { SequenceRenderer } from 'application/render/renderers/sequence/SequenceRenderer';
import { Nucleoside } from './Nucleoside';
import { Nucleotide } from './Nucleotide';
import { SequenceMode } from 'application/editor';
import { IRnaPreset, SequenceMode } from 'application/editor';
import { IRnaLabeledPreset } from 'application/editor/tools';
import { getRnaPartLibraryItem } from 'domain/helpers/rna';

const HORIZONTAL_DISTANCE_FROM_MONOMER = 25;
const VERTICAL_DISTANCE_FROM_MONOMER = 30;
Expand Down Expand Up @@ -890,7 +894,9 @@ export class DrawingEntitiesManager {
if (rnaBase && rnaBasePosition) {
monomersToAdd.push([rnaBase, rnaBasePosition]);
}
monomersToAdd.push([sugar, sugarPosition]);
if (sugar && sugarPosition) {
monomersToAdd.push([sugar, sugarPosition]);
}
if (phosphate && phosphatePosition) {
monomersToAdd.push([phosphate, phosphatePosition]);
}
Expand All @@ -912,6 +918,10 @@ export class DrawingEntitiesManager {
const attPointEnd = monomer.getValidSourcePoint(previousMonomer);

assert(attPointStart);
if (!attPointEnd) {
command.clear();
return;
}
assert(attPointEnd);

const operation = new PolymerBondFinishCreationOperation(
Expand All @@ -932,6 +942,53 @@ export class DrawingEntitiesManager {
return { command, monomers };
}

public createRnaPresetFromLabeledRnaPreset(preset: IRnaLabeledPreset) {
const editor = CoreEditor.provideEditorInstance();
const modifiedPreset: Partial<IRnaPreset> = omit(preset, [
'sugar',
'base',
'phosphate',
]);
const position = Coordinates.canvasToModel(new Vec2(0, 0));
let rnaBaseLibraryItem;
let phosphateLibraryItem;
let sugarLibraryItem;

if (preset.base) {
rnaBaseLibraryItem = getRnaPartLibraryItem(editor, preset.base);
rnaBaseLibraryItem && assert(rnaBaseLibraryItem);
}
if (preset.phosphate) {
phosphateLibraryItem = getRnaPartLibraryItem(editor, preset.phosphate);
phosphateLibraryItem && assert(phosphateLibraryItem);
}
if (preset.sugar) {
sugarLibraryItem = getRnaPartLibraryItem(editor, preset.sugar);
sugarLibraryItem && assert(sugarLibraryItem);
}

const { monomers } = editor.drawingEntitiesManager.addRnaPreset({
sugar: sugarLibraryItem,
sugarPosition: position,
rnaBase: rnaBaseLibraryItem,
rnaBasePosition: position,
phosphate: phosphateLibraryItem,
phosphatePosition: position,
});
for (const monomer of monomers) {
const props = pick(monomer.monomerItem, ['label', 'props', 'struct']);
if (monomer instanceof RNABase) {
modifiedPreset.base = { ...props };
} else if (monomer instanceof Sugar) {
modifiedPreset.sugar = { ...props };
} else if (monomer instanceof Phosphate) {
modifiedPreset.phosphate = { ...props };
}
}

return modifiedPreset;
}

private findChainByMonomer(
monomer: BaseMonomer,
monomerChain: BaseMonomer[] = [],
Expand Down
19 changes: 3 additions & 16 deletions packages/ketcher-macromolecules/src/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,15 +91,10 @@ import { calculatePreviewPosition } from 'helpers';
import { ErrorModal } from 'components/modal/Error';
import { EditorWrapper, TogglerComponentWrapper } from './styledComponents';
import { useLoading } from './hooks/useLoading';
import useSetRnaPresets from './hooks/useSetRnaPresets';
import { Loader } from 'components/Loader';
import { FullscreenButton } from 'components/FullscreenButton';
import { getDefaultPresets } from 'src/helpers/getDefaultPreset';
import {
setDefaultPresets,
setFavoritePresetsFromLocalStorage,
clearFavorites,
} from 'state/rna-builder';
import { IRnaPreset } from 'components/monomerLibrary/RnaBuilder/types';
import { clearFavorites } from 'state/rna-builder';
import { LayoutModeButton } from 'components/LayoutModeButton';
import { useContextMenu } from 'react-contexify';
import { CONTEXT_MENU_ID } from 'components/contextMenu/types';
Expand Down Expand Up @@ -191,15 +186,7 @@ function Editor({ theme, togglerComponent }: EditorProps) {
}
}, [editor, monomers]);

useEffect(() => {
const defaultPresets: IRnaPreset[] = getDefaultPresets(monomers);
dispatch(setDefaultPresets(defaultPresets));
dispatch(setFavoritePresetsFromLocalStorage());

return () => {
dispatch(clearFavorites());
};
}, [dispatch, monomers]);
useSetRnaPresets();

const dispatchShowPreview = useCallback(
(payload) => dispatch(showPreview(payload)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ describe('RNA ContextMenu', () => {
monomers: monomerData,
},
rnaBuilder: {
presets: mockedPresets,
presetsDefault: mockedPresets,
presetsCustom: [],
},
},
),
Expand All @@ -112,7 +113,8 @@ describe('RNA ContextMenu', () => {
monomers: monomerData,
},
rnaBuilder: {
presets: mockedPresets,
presetsDefault: mockedPresets,
presetsCustom: [],
},
},
),
Expand Down Expand Up @@ -141,7 +143,8 @@ describe('RNA ContextMenu', () => {
monomers: monomerData,
},
rnaBuilder: {
presets: mockedPresets,
presetsDefault: mockedPresets,
presetsCustom: [],
},
},
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,28 @@ describe('Delete component', () => {
},
name: 'A',
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const presetCustom: any = {
base: {
label: '25A',
},
phosphate: {
label: 'P',
},
sugar: {
label: 'R',
},
name: 'MyRna',
nameInList: 'MyRna',
};
it('should render correctly', () => {
expect(
render(
withThemeAndStoreProvider(<Delete {...mockProps} />, {
rnaBuilder: {
activePresetForContextMenu: { presetInList: preset, name: 'name' },
presets: [preset],
activePresetForContextMenu: { nameInList: 'name', name: 'name' },
presetsDefault: [preset],
presetsCustom: [],
},
}),
),
Expand All @@ -53,8 +68,9 @@ describe('Delete component', () => {
render(
withThemeAndStoreProvider(<Delete {...mockProps} />, {
rnaBuilder: {
activePresetForContextMenu: { presetInList: preset, name: 'name' },
presets: [preset],
activePresetForContextMenu: { nameInList: 'name', name: 'name' },
presetsDefault: [preset],
presetsCustom: [],
},
}),
);
Expand All @@ -67,8 +83,9 @@ describe('Delete component', () => {
render(
withThemeAndStoreProvider(<Delete {...mockProps} />, {
rnaBuilder: {
activePresetForContextMenu: { presetInList: preset, name: 'name' },
presets: [preset],
activePresetForContextMenu: { nameInList: 'name', name: 'name' },
presetsDefault: [preset],
presetsCustom: [presetCustom],
},
editor: {
editor: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { setSearchFilter } from 'state/library';
import { Icon } from 'ketcher-react';
import { IRnaPreset } from './RnaBuilder/types';
import {
selectPresets,
selectAllPresets,
setActivePreset,
setIsEditMode,
setUniqueNameError,
Expand All @@ -50,7 +50,7 @@ const MonomerLibrary = React.memo(() => {
const isDisabledTabsPanels =
isSequenceMode && !isSequenceEditInRNABuilderMode;

useAppSelector(selectPresets, (presets) => {
useAppSelector(selectAllPresets, (presets) => {
presetsRef.current = presets;
return true;
});
Expand All @@ -68,10 +68,11 @@ const MonomerLibrary = React.memo(() => {
return;
}

const nameToSet = presetWithSameName ? `${name}_Copy` : name;
const duplicatedPreset = {
...preset,
presetInList: undefined,
name: presetWithSameName ? `${name}_Copy` : name,
name: nameToSet,
nameInList: nameToSet,
default: false,
favorite: false,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,10 @@ export const RnaBuilder = ({ libraryName, duplicatePreset, editPreset }) => {
onClose={closeErrorModal}
>
<Modal.Content>
Preset with name "{uniqueNameError}" already exists. Please choose
another name.
<div style={{ padding: '12px' }}>
Preset with name "{uniqueNameError}" already exists. Please choose
another name.
</div>
</Modal.Content>
<Modal.Footer>
<StyledButton onClick={closeErrorModal}>Close</StyledButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const RnaEditor = ({ duplicatePreset }) => {

const expandEditor = () => {
setExpanded(!expanded);
if (!activePreset?.presetInList) {
if (!activePreset?.nameInList) {
dispatch(setIsEditMode(true));
}
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,11 @@ describe('Test Rna Editor Expanded component', () => {
{
rnaBuilder: {
activePreset: {
name: 'MyRna',
sugar: {
props: {
MonomerName: '',
},
},
phosphate: {
props: {
MonomerName: '',
},
},
base: {
props: {
MonomerName: '',
},
},
name: '',
nameInList: '',
sugar: undefined,
phosphate: undefined,
base: undefined,
},
},
},
Expand Down Expand Up @@ -74,6 +63,8 @@ describe('Test Rna Editor Expanded component', () => {
nodeIndexOverall: 1,
},
],
presetsDefault: [],
presetsCustom: [],
},
},
),
Expand Down Expand Up @@ -112,8 +103,10 @@ describe('Test Rna Editor Expanded component', () => {
MonomerName: '',
},
},
presetInList: {},
nameInList: 'MyRna',
},
presetsDefault: [],
presetsCustom: [],
},
},
),
Expand Down
Loading

0 comments on commit 2a39c23

Please sign in to comment.