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

6383 dna antisense chains #6571

Merged
merged 10 commits into from
Feb 28, 2025
Original file line number Diff line number Diff line change
Expand Up @@ -663,7 +663,7 @@ test(`5. Check that backbones should be placed parallel to each other`, async ()
await selectAllStructuresOnCanvas(page);
await callContextMenuForMonomer(page, 0);
const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();
await createAntisenseStrandOption.click();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ for (const monomer of monomers.filter((m) => m.eligibleForAntisense)) {
await callContextMenuForMonomer(page, monomer.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -963,7 +963,7 @@ for (const monomer of monomers.filter(
await callContextMenuForMonomer(page, monomer.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();
const createAntisenseStrandOptionPresent =
(await createAntisenseStrandOption.count()) > 0;
Expand Down Expand Up @@ -2184,7 +2184,7 @@ for (const chain of chainWithExtraBondToBase) {
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();
const createAntisenseStrandOptionPresent =
(await createAntisenseStrandOption.count()) > 0;
Expand Down Expand Up @@ -2372,7 +2372,7 @@ for (const monomer1 of shortMonomerList) {
await callContextMenuForMonomer(page, monomer1.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

if (
Expand Down Expand Up @@ -2449,7 +2449,7 @@ test(`5. Check that all non R1-R2 connections of backbone monomers (except R3-R1
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2500,7 +2500,7 @@ test(`6. Check that every nucleotide (sugar and phosphate are part of the backbo
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2589,7 +2589,7 @@ test(`7. Check that every nucleoside (not a nucleotide, sugar is connected throu
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2637,7 +2637,7 @@ test(`8. Check that all other monomers in the backbone that are not a part of th
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2688,7 +2688,7 @@ test(`9. Check that the antisense chain should be "flipped" in relation to the s
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2824,7 +2824,7 @@ test(`13. Validate that creating, deleting, and modifying the antisense chain su
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2889,7 +2889,7 @@ test(`14. Validate that both sense and antisense strands can be exported correct
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2944,7 +2944,7 @@ test(`15. Ensure that switching between (Flex, Snake, Sequence) modes does not b
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -2988,7 +2988,7 @@ test(`16. Ensure that switching between macro and micro modes does not break the
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down Expand Up @@ -3031,7 +3031,7 @@ test(`17. Verify that copying the sense and antisense strand and pasting it with
await callContextMenuForMonomer(page, chain.monomerLocatorIndex);

const createAntisenseStrandOption = page
.getByTestId('create_antisense_chain')
.getByTestId('create_antisense_rna_chain')
.first();

// Checking presence of Create Antisense Strand option on the context menu and enabled
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,25 @@ test.describe('Sequence mode edit in RNA Builder', () => {
await waitForMonomerPreview(page);

// should see correct context menu title and available 'modify_in_rna_builder' button
await takeEditorScreenshot(page);
await takeEditorScreenshot(page, {
hideMonomerPreview: true,
});
await page.getByTestId('modify_in_rna_builder').click();
// should see uploaded nucleotide data to RNA Builder and disabled "Update" button
// should see disabled top bar's selectors
// should see disabled top undo/redo/open buttons
await moveMouseAway(page);
await takePageScreenshot(page);
await page.getByTestId(SUGAR).click();
// should see disabled and nondisabled sugars
await takeMonomerLibraryScreenshot(page);
await takeMonomerLibraryScreenshot(page, {
hideMonomerPreview: true,
});
await selectMonomer(page, Sugars._25R);
// should see updated sugar, updated title of preset and nondisabled "Update" button
await takeRNABuilderScreenshot(page);
await takeRNABuilderScreenshot(page, {
hideMonomerPreview: true,
});
await pressSaveButton(page);
// should see updated nucleotide in chain
// should see nondisabled top bar's selectors
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.
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.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess right screenshot is incorrect because tooltip cover all RNA Builder

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.
9 changes: 5 additions & 4 deletions packages/ketcher-core/src/application/editor/Editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ export class CoreEditor {
this.events.changeSequenceTypeEnterMode.add((mode: SequenceType) =>
this.onChangeSequenceTypeEnterMode(mode),
);
this.events.createAntisenseChain.add(() => {
this.onCreateAntisenseChain();
this.events.createAntisenseChain.add((isDnaAntisense: boolean) => {
this.onCreateAntisenseChain(isDnaAntisense);
});
this.events.copySelectedStructure.add(() => {
this.mode.onCopy();
Expand Down Expand Up @@ -428,8 +428,9 @@ export class CoreEditor {
this.sequenceTypeEnterMode = mode;
}

private onCreateAntisenseChain() {
const modelChanges = this.drawingEntitiesManager.createAntisenseChain();
private onCreateAntisenseChain(isDnaAntisense: boolean) {
const modelChanges =
this.drawingEntitiesManager.createAntisenseChain(isDnaAntisense);
const history = new EditorHistory(this);

this.renderersContainer.update(modelChanges);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1202,6 +1202,7 @@ export class SequenceMode extends BaseMode {
previousTwoStrandedNode?.antisenseNode instanceof
EmptySequenceNode
)),
false,
);

if (antisenseNodeCreationResult && currentTwoStrandedNode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2526,8 +2526,8 @@ export class DrawingEntitiesManager {
};
}

private static get antisenseChainBasesMap() {
return {
private static antisenseChainBasesMap(isDnaAntisense: boolean) {
const antisenseMap = {
[RnaDnaNaturalAnaloguesEnum.ADENINE]: RnaDnaNaturalAnaloguesEnum.URACIL,
[RnaDnaNaturalAnaloguesEnum.CYTOSINE]: RnaDnaNaturalAnaloguesEnum.GUANINE,
[RnaDnaNaturalAnaloguesEnum.GUANINE]: RnaDnaNaturalAnaloguesEnum.CYTOSINE,
Expand All @@ -2545,6 +2545,12 @@ export class DrawingEntitiesManager {
[StandardAmbiguousRnaBase.S]: StandardAmbiguousRnaBase.S,
[StandardAmbiguousRnaBase.V]: StandardAmbiguousRnaBase.B,
};
if (isDnaAntisense) {
antisenseMap[RnaDnaNaturalAnaloguesEnum.ADENINE] =
RnaDnaNaturalAnaloguesEnum.THYMINE;
}

return antisenseMap;
}

public markMonomerAsAntisense(monomer: BaseMonomer) {
Expand Down Expand Up @@ -2700,8 +2706,11 @@ export class DrawingEntitiesManager {
);
}

private static getAntisenseBaseLabel(rnaBase: RNABase | AmbiguousMonomer) {
return DrawingEntitiesManager.antisenseChainBasesMap[
private static getAntisenseBaseLabel(
rnaBase: RNABase | AmbiguousMonomer,
isDnaAntisense: boolean,
) {
return DrawingEntitiesManager.antisenseChainBasesMap(isDnaAntisense)[
rnaBase instanceof AmbiguousMonomer
? rnaBase.monomerItem.label
: rnaBase.monomerItem.props.MonomerNaturalAnalogCode
Expand All @@ -2711,23 +2720,27 @@ export class DrawingEntitiesManager {
public static createAntisenseNode(
node: Nucleoside | Nucleotide,
needAddPhosphate = false,
isDnaAntisense: boolean,
) {
const antisenseBaseLabel = DrawingEntitiesManager.getAntisenseBaseLabel(
node.rnaBase,
isDnaAntisense,
);

if (!antisenseBaseLabel) {
return;
}

const sugarName = isDnaAntisense
? RNA_DNA_NON_MODIFIED_PART.SUGAR_DNA
: RNA_DNA_NON_MODIFIED_PART.SUGAR_RNA;
return (needAddPhosphate ? Nucleotide : Nucleoside).createOnCanvas(
antisenseBaseLabel,
node.monomer.position.add(new Vec2(0, 3)),
RNA_DNA_NON_MODIFIED_PART.SUGAR_RNA,
sugarName,
);
}

public createAntisenseChain() {
public createAntisenseChain(isDnaAntisense: boolean) {
const editor = CoreEditor.provideEditorInstance();
const command = new Command();
const selectedMonomers = this.selectedEntities
Expand All @@ -2741,7 +2754,10 @@ export class DrawingEntitiesManager {
(node) =>
(node instanceof Nucleotide || node instanceof Nucleoside) &&
Boolean(
DrawingEntitiesManager.getAntisenseBaseLabel(node.rnaBase),
DrawingEntitiesManager.getAntisenseBaseLabel(
node.rnaBase,
isDnaAntisense,
),
) &&
node.monomer.selected,
),
Expand Down Expand Up @@ -2796,7 +2812,11 @@ export class DrawingEntitiesManager {

if (node instanceof Nucleotide || node instanceof Nucleoside) {
const antisenseNodeCreationResult =
DrawingEntitiesManager.createAntisenseNode(node, false);
DrawingEntitiesManager.createAntisenseNode(
node,
false,
isDnaAntisense,
);

if (!antisenseNodeCreationResult) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,24 @@ export const SelectedMonomersContextMenu = ({
title: 'Copy',
},
{
name: 'create_antisense_chain',
title: 'Create Antisense Strand',
name: 'create_antisense_rna_chain',
title: 'Create Antisense RNA Strand',
separator: false,
disabled: isAntisenseCreationDisabled(selectedMonomers),
hidden: ({ props }: { props?: { selectedMonomers?: BaseMonomer[] } }) => {
return !props?.selectedMonomers?.some((selectedMonomer) => {
return (
(selectedMonomer instanceof RNABase &&
getSugarFromRnaBase(selectedMonomer)) ||
(selectedMonomer instanceof Sugar &&
getRnaBaseFromSugar(selectedMonomer))
);
});
},
},
{
name: 'create_antisense_dna_chain',
title: 'Create Antisense DNA Strand',
separator: true,
disabled: isAntisenseCreationDisabled(selectedMonomers),
hidden: ({ props }: { props?: { selectedMonomers?: BaseMonomer[] } }) => {
Expand All @@ -55,8 +71,11 @@ export const SelectedMonomersContextMenu = ({
case 'copy':
editor.events.copySelectedStructure.dispatch();
break;
case 'create_antisense_chain':
editor.events.createAntisenseChain.dispatch();
case 'create_antisense_rna_chain':
editor.events.createAntisenseChain.dispatch(false);
break;
case 'create_antisense_dna_chain':
editor.events.createAntisenseChain.dispatch(true);
break;
case 'delete':
editor.events.deleteSelectedStructure.dispatch();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export const SequenceItemContextMenu = ({
{
name: SequenceItemContextMenuNames.createDnaAntisenseStrand,
title: 'Create DNA antisense strand',
disabled: true,
disabled: isAntisenseCreationDisabled(extractedBaseMonomers),
hidden: isAntisenseOptionHidden,
},
{
Expand Down Expand Up @@ -184,10 +184,10 @@ export const SequenceItemContextMenu = ({
editor.events.editSequence.dispatch(props.sequenceItemRenderer);
break;
case SequenceItemContextMenuNames.createRnaAntisenseStrand:
editor.events.createAntisenseChain.dispatch();
editor.events.createAntisenseChain.dispatch(false);
break;
case SequenceItemContextMenuNames.createDnaAntisenseStrand:
// TODO: implement createDnaAntisenseStrand
editor.events.createAntisenseChain.dispatch(true);
break;
default:
break;
Expand Down
Loading