Skip to content

Commit 87dfb90

Browse files
committed
- fixed notifications
1 parent a6ee7e0 commit 87dfb90

5 files changed

Lines changed: 194 additions & 46 deletions

File tree

packages/ketcher-react/src/script/ui/views/components/MonomerCreationWizard/MonomerCreationWizard.tsx

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,25 @@ const getInitialWizardState = (
9595

9696
const initialWizardState: WizardState = getInitialWizardState();
9797

98+
const getAttachmentPointsText = (attachmentPoints: AttachmentPointName[]) =>
99+
attachmentPoints.join(', ');
100+
101+
const getEditAllPresetWarningMessage = (
102+
initialValues: MonomerCreationInitialValues,
103+
) =>
104+
`The edited version of the monomer must be the same monomer type and must have attachment point ${getAttachmentPointsText(
105+
initialValues.presetRequirements?.attachmentPoints ?? [],
106+
)}, because the monomer participates in a preset.`;
107+
108+
const getEditAllPresetErrorMessage = (
109+
initialValues: MonomerCreationInitialValues,
110+
) =>
111+
`The changes made to the monomer prevent it from participating in a preset. The monomer must be a ${
112+
initialValues.presetRequirements?.type
113+
} and contain ${getAttachmentPointsText(
114+
initialValues.presetRequirements?.attachmentPoints ?? [],
115+
)} attachment points.`;
116+
98117
/**
99118
* Builds initial wizard state seeded with values from an existing monomer
100119
* being edited. When `initialValues` is undefined returns the default empty
@@ -117,28 +136,22 @@ const getInitialWizardStateForEdit = (
117136
aliasHELM: initialValues.aliasHELM,
118137
aliasBILN: initialValues.aliasBILN,
119138
},
139+
...(initialValues.editMode === 'all' && initialValues.presetRequirements
140+
? {
141+
notifications: new Map([
142+
[
143+
'editAllPresetWarning',
144+
{
145+
type: 'warning',
146+
message: getEditAllPresetWarningMessage(initialValues),
147+
},
148+
],
149+
]),
150+
}
151+
: {}),
120152
};
121153
};
122154

123-
const getAttachmentPointsText = (attachmentPoints: AttachmentPointName[]) =>
124-
attachmentPoints.join(', ');
125-
126-
const getEditAllPresetWarningMessage = (
127-
initialValues: MonomerCreationInitialValues,
128-
) =>
129-
`The edited version of the monomer must be the same monomer type and must have attachment point ${getAttachmentPointsText(
130-
initialValues.presetRequirements?.attachmentPoints ?? [],
131-
)}, because the monomer participates in a preset.`;
132-
133-
const getEditAllPresetErrorMessage = (
134-
initialValues: MonomerCreationInitialValues,
135-
) =>
136-
`The changes made to the monomer prevent it from participating in a preset. The monomer must be a ${
137-
initialValues.presetRequirements?.type
138-
} and contain ${getAttachmentPointsText(
139-
initialValues.presetRequirements?.attachmentPoints ?? [],
140-
)} attachment points.`;
141-
142155
// BILN alias errors remain visible until the next submit attempt.
143156
const fieldsValidatedOnSubmit = new Set<WizardFormFieldId>(['aliasBILN']);
144157

@@ -818,30 +831,6 @@ const MonomerCreationWizardInternal = ({
818831
setHasActiveRnaPresetAtomValidationErrors,
819832
] = useState(false);
820833

821-
useEffect(() => {
822-
const initialValues = monomerCreationState.editInstanceInitialValues;
823-
824-
if (
825-
initialValues?.editMode !== 'all' ||
826-
!initialValues.presetRequirements
827-
) {
828-
return;
829-
}
830-
831-
wizardStateDispatch({
832-
type: 'SetNotifications',
833-
notifications: new Map([
834-
[
835-
'editAllPresetWarning',
836-
{
837-
type: 'warning',
838-
message: getEditAllPresetWarningMessage(initialValues),
839-
},
840-
],
841-
]),
842-
});
843-
}, [monomerCreationState.editInstanceInitialValues]);
844-
845834
const handleConnectionLeavingAtomChange = useCallback(
846835
(
847836
apName: AttachmentPointName,

packages/ketcher-react/src/script/ui/views/components/MonomerCreationWizard/MonomerCreationWizard.utils.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,4 +157,89 @@ describe('getEditAllInstancesInitialValues', () => {
157157
attachmentPoints: ['R1', 'R3'],
158158
});
159159
});
160+
161+
it.each([
162+
[KetMonomerClass.Base, 'Base', ['R1']],
163+
[KetMonomerClass.Sugar, 'Sugar', ['R1', 'R3']],
164+
[KetMonomerClass.Phosphate, 'Phosphate', ['R2']],
165+
] as const)(
166+
'collects default required attachment points for a %s in an RNA preset without explicit connections',
167+
(monomerClass, id, attachmentPoints) => {
168+
const values = getEditAllInstancesInitialValues(
169+
createMonomer({
170+
id,
171+
MonomerClass: monomerClass,
172+
MonomerCode: id,
173+
MonomerName: id,
174+
MonomerNaturalAnalogCode: id,
175+
Name: id,
176+
}),
177+
{
178+
root: {
179+
templates: [{ $ref: 'monomerGroupTemplate-A' }],
180+
},
181+
'monomerGroupTemplate-A': {
182+
type: 'monomerGroupTemplate',
183+
class: KetMonomerClass.RNA,
184+
templates: [
185+
{ $ref: 'monomerTemplate-Base' },
186+
{ $ref: 'monomerTemplate-Sugar' },
187+
{ $ref: 'monomerTemplate-Phosphate' },
188+
],
189+
},
190+
'monomerTemplate-Base': {
191+
class: KetMonomerClass.Base,
192+
},
193+
'monomerTemplate-Sugar': {
194+
class: KetMonomerClass.Sugar,
195+
},
196+
'monomerTemplate-Phosphate': {
197+
class: KetMonomerClass.Phosphate,
198+
},
199+
},
200+
);
201+
202+
expect(values.presetRequirements).toEqual({
203+
type: monomerClass,
204+
attachmentPoints,
205+
});
206+
},
207+
);
208+
209+
it('does not require sugar attachment points for default preset connections to absent components', () => {
210+
const values = getEditAllInstancesInitialValues(
211+
createMonomer({
212+
id: 'Sugar',
213+
MonomerClass: KetMonomerClass.Sugar,
214+
MonomerCode: 'Sugar',
215+
MonomerName: 'Sugar',
216+
MonomerNaturalAnalogCode: 'Sugar',
217+
Name: 'Sugar',
218+
}),
219+
{
220+
root: {
221+
templates: [{ $ref: 'monomerGroupTemplate-A' }],
222+
},
223+
'monomerGroupTemplate-A': {
224+
type: 'monomerGroupTemplate',
225+
class: KetMonomerClass.RNA,
226+
templates: [
227+
{ $ref: 'monomerTemplate-Base' },
228+
{ $ref: 'monomerTemplate-Sugar' },
229+
],
230+
},
231+
'monomerTemplate-Base': {
232+
class: KetMonomerClass.Base,
233+
},
234+
'monomerTemplate-Sugar': {
235+
class: KetMonomerClass.Sugar,
236+
},
237+
},
238+
);
239+
240+
expect(values.presetRequirements).toEqual({
241+
type: KetMonomerClass.Sugar,
242+
attachmentPoints: ['R3'],
243+
});
244+
});
160245
});

packages/ketcher-react/src/script/ui/views/components/MonomerCreationWizard/MonomerCreationWizard.utils.ts

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {
2-
type AttachmentPointName,
2+
AttachmentPointName,
33
type BaseMonomer,
44
getMonomerTemplateRefFromMonomerItem,
55
type MonomerCreationInitialValues,
@@ -68,16 +68,63 @@ type MonomersLibraryParsedJson = {
6868
[templateRef: string]: unknown;
6969
};
7070

71+
type RnaComponentTemplateRef = { $ref?: string; class?: string };
72+
73+
type MonomerTemplate = {
74+
class?: string;
75+
};
76+
7177
type RnaPresetTemplate = {
7278
type?: string;
7379
class?: string;
74-
templates?: Array<{ $ref?: string }>;
80+
templates?: RnaComponentTemplateRef[];
7581
connections?: Array<{
7682
endpoint1?: { templateId?: string; attachmentPointId?: string };
7783
endpoint2?: { templateId?: string; attachmentPointId?: string };
7884
}>;
7985
};
8086

87+
const getTemplateClass = (
88+
templateRef: RnaComponentTemplateRef,
89+
monomersLibraryParsedJson: MonomersLibraryParsedJson,
90+
) => {
91+
const template = monomersLibraryParsedJson[templateRef.$ref ?? ''] as
92+
| MonomerTemplate
93+
| undefined;
94+
95+
return templateRef.class ?? template?.class;
96+
};
97+
98+
const addDefaultRnaPresetAttachmentPoints = (
99+
componentTypes: Set<string | undefined>,
100+
editedMonomerType: KetMonomerClass,
101+
necessaryAttachmentPoints: Set<AttachmentPointName>,
102+
) => {
103+
if (
104+
editedMonomerType === KetMonomerClass.Base &&
105+
componentTypes.has(KetMonomerClass.Sugar)
106+
) {
107+
necessaryAttachmentPoints.add(AttachmentPointName.R1);
108+
}
109+
110+
if (editedMonomerType === KetMonomerClass.Sugar) {
111+
if (componentTypes.has(KetMonomerClass.Phosphate)) {
112+
necessaryAttachmentPoints.add(AttachmentPointName.R1);
113+
}
114+
115+
if (componentTypes.has(KetMonomerClass.Base)) {
116+
necessaryAttachmentPoints.add(AttachmentPointName.R3);
117+
}
118+
}
119+
120+
if (
121+
editedMonomerType === KetMonomerClass.Phosphate &&
122+
componentTypes.has(KetMonomerClass.Sugar)
123+
) {
124+
necessaryAttachmentPoints.add(AttachmentPointName.R2);
125+
}
126+
};
127+
81128
export const getEditAllInstancesInitialValues = (
82129
monomer: BaseMonomer,
83130
monomersLibraryParsedJson?: MonomersLibraryParsedJson | null,
@@ -113,7 +160,25 @@ export const getEditAllInstancesInitialValues = (
113160
return;
114161
}
115162

116-
template.connections?.forEach((connection) => {
163+
if (!template.connections?.length) {
164+
const componentTypes = new Set(
165+
template.templates?.map((presetMonomerRef) =>
166+
isEditedMonomerTemplate(presetMonomerRef.$ref)
167+
? initialValues.type
168+
: getTemplateClass(presetMonomerRef, monomersLibraryParsedJson),
169+
),
170+
);
171+
172+
addDefaultRnaPresetAttachmentPoints(
173+
componentTypes,
174+
initialValues.type,
175+
necessaryAttachmentPoints,
176+
);
177+
178+
return;
179+
}
180+
181+
template.connections.forEach((connection) => {
117182
[connection.endpoint1, connection.endpoint2].forEach((endpoint) => {
118183
const attachmentPointId = endpoint?.attachmentPointId;
119184
if (

packages/ketcher-react/src/script/ui/views/components/MonomerCreationWizard/components/Notification/Notification.module.less

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@
3636
}
3737
}
3838

39+
&.warning {
40+
background-color: #FFF4CC;
41+
42+
.notificationStrip {
43+
background-color: #FFB800;
44+
}
45+
}
46+
3947
&Icon {
4048
min-width: 18px;
4149
min-height: 18px;

packages/ketcher-react/src/script/ui/views/components/MonomerCreationWizard/components/Notification/Notification.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const Notification = ({ id, type, message, wizardStateDispatch }: Props) => {
3636
styles.notification,
3737
type === 'info' && styles.info,
3838
type === 'error' && styles.error,
39+
type === 'warning' && styles.warning,
3940
)}
4041
data-testid={`notification-${id}-message-banner`}
4142
>

0 commit comments

Comments
 (0)