Skip to content

Commit 0b1e2fb

Browse files
committed
UI: show error on sample details
1 parent ed21a60 commit 0b1e2fb

File tree

2 files changed

+62
-9
lines changed

2 files changed

+62
-9
lines changed

app/javascript/src/apps/mydb/elements/details/samples/SampleDetails.js

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ export default class SampleDetails extends React.Component {
140140
saveInventoryAction: false,
141141
isChemicalEdited: false,
142142
currentUser,
143+
ketcherError: null
143144
};
144145

145146
this.enableComputedProps = MatrixCheck(currentUser.matrix, 'computedProp');
@@ -283,14 +284,27 @@ export default class SampleDetails extends React.Component {
283284
}
284285
}
285286

286-
handleStructureEditorSave(molfile, svgFile = null, config = null, editor = 'ketcher') {
287+
handleStructureEditorSave(molfile, svgFile = null, config = null, editor = 'ketcher', errorMessage = null) {
287288
const { sample } = this.state;
288289
sample.molfile = molfile;
289290
const smiles = (config && sample.molecule) ? config.smiles : null;
290-
sample.contains_residues = molfile.indexOf(' R# ') > -1;
291+
sample.contains_residues = molfile?.indexOf(' R# ') > -1;
291292
sample.formulaChanged = true;
292293
this.setState({ loadingMolecule: true });
293294

295+
if (errorMessage) {
296+
this.setState({ ketcherError: errorMessage }, () => {
297+
if (this.errorTimer) {
298+
clearTimeout(this.errorTimer);
299+
}
300+
this.setState({ ketcherError: errorMessage });
301+
this.errorTimer = setTimeout(() => {
302+
this.setState({ ketcherError: null });
303+
this.errorTimer = null;
304+
}, 5000);
305+
});
306+
}
307+
294308
const fetchError = (errorMessage) => {
295309
NotificationActions.add({
296310
title: 'Error on Sample creation',
@@ -1333,6 +1347,25 @@ export default class SampleDetails extends React.Component {
13331347
);
13341348
}
13351349

1350+
renderKetcherError() {
1351+
const ketcherError = this.state?.ketcherError;
1352+
if (!ketcherError) return null;
1353+
return (
1354+
<Alert
1355+
variant="danger"
1356+
show={ketcherError?.length > 0}
1357+
dismissible
1358+
onClose={() => this.setState({ ketcherSVGError: null })}
1359+
>
1360+
<strong>
1361+
Ketcher2 error:
1362+
{' '}
1363+
</strong>
1364+
<small className="text-muted">{ketcherError}</small>
1365+
</Alert>
1366+
);
1367+
}
1368+
13361369
render() {
13371370
const { sample } = this.state;
13381371
const { visible, isChemicalEdited } = this.state;
@@ -1425,6 +1458,7 @@ export default class SampleDetails extends React.Component {
14251458
{messageBlock}
14261459
</Card.Header>
14271460
<Card.Body>
1461+
{this.renderKetcherError()}
14281462
{this.sampleInfo(sample)}
14291463
<ElementDetailSortTab
14301464
type="sample"

app/javascript/src/components/structureEditor/StructureEditorModal.js

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ export default class StructureEditorModal extends React.Component {
228228
this.handleEditorSelection = this.handleEditorSelection.bind(this);
229229
this.resetEditor = this.resetEditor.bind(this);
230230
this.updateEditor = this.updateEditor.bind(this);
231+
this.generateSVGKet2 = this.generateSVGKet2.bind(this);
231232
}
232233

233234
componentDidMount() {
@@ -279,16 +280,22 @@ export default class StructureEditorModal extends React.Component {
279280
async handleSaveStructureKet2(structure, editor) {
280281
try {
281282
const molfile = await structure.editor.getMolfile('V2000');
282-
const imgfile = await structure.editor.generateImage(molfile, { outputFormat: 'svg' });
283-
const text = await imgfile.text();
284-
const updatedSvg = await transformSvgIdsAndReferences(text);
285-
this.handleStructureSave(molfile, updatedSvg, editor.id);
283+
const svg = await this.generateSVGKet2(structure, molfile);
284+
this.handleStructureSave(molfile, svg, editor.id);
286285
} catch (error) {
287-
console.error('Error saving structure:', error);
286+
// Attempt to at least get the molfile, even if SVG generation fails
287+
let molfile = null;
288+
try {
289+
molfile = await structure.editor.getMolfile('V2000');
290+
} catch (molfileError) {
291+
console.error('Error retrieving molfile after failure:', molfileError);
292+
}
293+
294+
this.handleStructureSave(molfile, null, editor.id, null, error.message);
288295
}
289296
}
290297

291-
handleStructureSave(molfile, svg, editorId, info = null) {
298+
handleStructureSave(molfile, svg, editorId, info = null, errorMessage = null) {
292299
const { hasChildren, hasParent, onSave } = this.props;
293300

294301
this.setState(
@@ -298,12 +305,24 @@ export default class StructureEditorModal extends React.Component {
298305
},
299306
() => {
300307
if (onSave) {
301-
onSave(molfile, svg, info, editorId);
308+
onSave(molfile, svg, info, editorId, errorMessage);
302309
}
303310
}
304311
);
305312
}
306313

314+
async generateSVGKet2(structure, molfile) {
315+
try {
316+
const imageFile = await structure.editor.generateImage(molfile, { outputFormat: 'svg' });
317+
const svgText = await imageFile.text();
318+
const transformedSvg = await transformSvgIdsAndReferences(svgText);
319+
return transformedSvg;
320+
} catch (error) {
321+
console.error('Error generating SVG:', error);
322+
throw new Error(`SVG generation failed: ${error.message}`);
323+
}
324+
}
325+
307326
initializeEditor() {
308327
const { editor, molfile } = this.state;
309328
if (editor) { editor.structureDef.molfile = molfile; }

0 commit comments

Comments
 (0)