@datagrok/sequence-translator 1.4.7 → 1.4.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,8 +4,9 @@ import * as DG from 'datagrok-api/dg';
4
4
 
5
5
  import $ from 'cash-dom';
6
6
  import wu from 'wu';
7
- import {fromEvent, Unsubscribable} from 'rxjs';
8
- import {HelmAtom} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
7
+ import {Unsubscribable} from 'rxjs';
8
+
9
+ import {GetMonomerResType, HelmAtom, MonomerNumberingTypes} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
9
10
  import {getHelmHelper, HelmInputBase, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
11
  import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
11
12
  import {HelmType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
@@ -14,6 +15,8 @@ import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-he
14
15
  import '@datagrok-libraries/bio/src/types/input';
15
16
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
16
17
  import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
18
+ import {SeqValueBase} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
19
+ import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
17
20
 
18
21
  import {PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes} from './types';
19
22
  import {getLibrariesList} from './utils';
@@ -21,11 +24,18 @@ import {doPolyToolEnumerateHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
21
24
  import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
22
25
  import {defaultErrorHandler} from '../utils/err-info';
23
26
  import {PolyToolPlaceholdersBreadthInput} from './pt-placeholders-breadth-input';
24
- import {PT_UI_DIALOG_ENUMERATION} from './const';
27
+ import {PT_UI_DIALOG_ENUMERATION, PT_UI_GET_HELM, PT_UI_HIGHLIGHT_MONOMERS, PT_UI_RULES_USED, PT_UI_USE_CHIRALITY} from './const';
25
28
  import {PolyToolDataRole, PolyToolTags} from '../consts';
26
- import {Chain} from './pt-conversion';
29
+ import {RuleInputs, RULES_PATH, RULES_STORAGE_NAME} from './pt-rules';
30
+ import {Chain} from './conversion/pt-chain';
31
+ import {polyToolConvert} from './pt-dialog';
27
32
 
28
33
  import {_package, applyNotationProviderForCyclized} from '../package';
34
+ import {getUnusedColName} from '@datagrok-libraries/bio/src/monomer-works/utils';
35
+ import {buildMonomerHoverLink} from '@datagrok-libraries/bio/src/monomer-works/monomer-hover';
36
+ import {MmcrTemps} from '@datagrok-libraries/bio/src/utils/cell-renderer-consts';
37
+ import {getRdKitModule} from '@datagrok-libraries/bio/src/chem/rdkit-module';
38
+ import {PolymerTypes} from '@datagrok-libraries/bio/src/helm/consts';
29
39
 
30
40
  type PolyToolEnumerateInputs = {
31
41
  macromolecule: HelmInputBase;
@@ -35,7 +45,10 @@ type PolyToolEnumerateInputs = {
35
45
  trivialNameCol: InputColumnBase,
36
46
  keepOriginal: DG.InputBase<boolean>;
37
47
  toAtomicLevel: DG.InputBase<boolean>;
38
- toHarmonizedSequence: DG.InputBase<boolean>;
48
+ generateHelm: DG.InputBase<boolean>;
49
+ chiralityEngine: DG.InputBase<boolean>;
50
+ highlightMonomers: DG.InputBase<boolean>;
51
+ rules: { header: HTMLElement, form: HTMLDivElement },
39
52
  };
40
53
 
41
54
  type PolyToolEnumerateHelmSerialized = {
@@ -46,7 +59,10 @@ type PolyToolEnumerateHelmSerialized = {
46
59
  trivialNameCol: string;
47
60
  keepOriginal: boolean;
48
61
  toAtomicLevel: boolean;
49
- toHarmonizedSequence: boolean;
62
+ generateHelm: boolean;
63
+ chiralityEngine: boolean;
64
+ highlightMonomers: boolean;
65
+ rules: string[],
50
66
  };
51
67
 
52
68
  export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
@@ -72,26 +88,24 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
72
88
  .filter((el) => el instanceof HTMLElement)
73
89
  .map((el) => (el as HTMLElement).offsetHeight).reduce((sum, h) => sum + h, 0);
74
90
  const remainFitHeight = contentHeight - otherInputsHeight - 38;
75
- dialog.inputs.forEach((input, idx) => {
91
+ for (const idx of wu.count(0).take(dialogContentEl.children.length)) {
76
92
  if (idx in fitInputs) {
93
+ const el = dialogContentEl.children[idx] as HTMLElement;
77
94
  const inputFitHeight = remainFitHeight * fitInputs[idx] / fitInputsSumHeight;
78
- input.root.style.height = `${inputFitHeight}px`;
95
+ el.style.height = `${inputFitHeight}px`;
79
96
  }
80
- });
97
+ }
81
98
  };
82
99
  dialog = await getPolyToolEnumerateDialog(cell, resizeInputs);
83
100
 
84
101
  let isFirstShow = true;
85
102
  ui.onSizeChanged(dialog.root).subscribe(() => {
86
103
  if (isFirstShow) {
87
- const dialogInputList = dialog.inputs;
88
104
  const dialogRootCash = $(dialog.root);
89
105
  const contentMaxHeight = maxHeight -
90
106
  dialogRootCash.find('div.d4-dialog-header').get(0)!.offsetHeight -
91
107
  dialogRootCash.find('div.d4-dialog-footer').get(0)!.offsetHeight;
92
108
 
93
- // dialog.inputs2.macromolecule.root.style.backgroundColor = '#CCFFCC';
94
-
95
109
  const dialogWidth = maxWidth * 0.7;
96
110
  const dialogHeight = maxHeight * 0.7;
97
111
 
@@ -113,7 +127,7 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
113
127
  _package.logger.debug('PolyToolEnumerateHelmUI: dialog after show');
114
128
  } catch (err: any) {
115
129
  const [errMsg, errStack] = errInfo(err);
116
- grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
130
+ //grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
117
131
  _package.logger.error(errMsg, undefined, errStack);
118
132
  }
119
133
  }
@@ -129,18 +143,56 @@ async function getPolyToolEnumerateDialog(
129
143
  inputs.placeholders.detach();
130
144
  };
131
145
  try {
132
- const monomerLib = (await getMonomerLibHelper()).getMonomerLib();
146
+ const libHelper = await getMonomerLibHelper();
147
+ const monomerLib = libHelper.getMonomerLib();
133
148
  const seqHelper = await getSeqHelper();
134
149
  const emptyDf: DG.DataFrame = DG.DataFrame.fromColumns([]);
135
150
 
136
151
  const [libList, helmHelper] = await Promise.all([getLibrariesList(), getHelmHelper()]);
152
+ const monomerLibFuncs = helmHelper.buildMonomersFuncsFromLib(monomerLib);
153
+
154
+ const getValue = (cell?: DG.Cell): [SeqValueBase, PolyToolDataRole] => {
155
+ let resSeqValue: SeqValueBase;
156
+ let resDataRole: PolyToolDataRole;
157
+ if (cell && cell.rowIndex >= 0 && cell?.column.semType == DG.SEMTYPE.MACROMOLECULE) {
158
+ const sh = seqHelper.getSeqHandler(cell.column);
159
+ resSeqValue = sh.getValue(cell.rowIndex);
160
+ resDataRole = (resSeqValue.tags[PolyToolTags.dataRole] as PolyToolDataRole.template) ?? PolyToolDataRole.macromolecule;
161
+ } else {
162
+ const seqCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, 'seq', [PT_HELM_EXAMPLE]);
163
+ seqCol.meta.units = NOTATION.HELM;
164
+ const sh = seqHelper.getSeqHandler(seqCol);
165
+ resSeqValue = sh.getValue(0);
166
+ resDataRole = PolyToolDataRole.macromolecule;
167
+ }
168
+ return [resSeqValue, resDataRole];
169
+ };
170
+
171
+ let [seqValue, dataRole]: [SeqValueBase, PolyToolDataRole] = getValue(cell);
137
172
 
138
173
  let srcId: { value: string, colName: string } | null = null;
174
+ let ruleFileList: string[];
175
+ let ruleInputs: RuleInputs;
139
176
  const trivialNameSampleDiv = ui.divText('', {style: {marginLeft: '8px', marginTop: '2px'}});
140
177
  const warningsTextDiv = ui.divText('', {style: {color: 'red'}});
141
178
  inputs = {
142
179
  macromolecule: helmHelper.createHelmInput(
143
- 'Macromolecule', {editable: false}),
180
+ 'Macromolecule', {
181
+ editable: false,
182
+ editorOptions: {
183
+ drawOptions: {
184
+ monomerNumbering: MonomerNumberingTypes.continuous,
185
+ getMonomer: (a: HelmAtom | HelmType, name?: string): GetMonomerResType => {
186
+ const aa: HelmAtom = a as HelmAtom;
187
+ if (aa.T === 'ATOM') {
188
+ const canonicalSymbol = seqValue.getSplitted().getCanonical(aa.bio!.continuousId - 1);
189
+ return monomerLibFuncs.getMonomer(aa.bio!.type, canonicalSymbol);
190
+ } else
191
+ return monomerLibFuncs.getMonomer(a, name);
192
+ },
193
+ },
194
+ }
195
+ }),
144
196
  placeholders: await PolyToolPlaceholdersInput.create(
145
197
  'Placeholders', {
146
198
  showAddNewRowIcon: true,
@@ -163,9 +215,19 @@ async function getPolyToolEnumerateDialog(
163
215
  keepOriginal: ui.input.bool(
164
216
  'Keep original', {value: false}),
165
217
  toAtomicLevel: ui.input.bool(
166
- 'To atomic level', {value: false}),
167
- toHarmonizedSequence: ui.input.bool(
168
- 'To harmonized sequence', {value: false}),
218
+ 'To atomic level', {
219
+ value: false,
220
+ onValueChanged: (value, input) => { updateViewRules(); }
221
+ }),
222
+ generateHelm: ui.input.bool(PT_UI_GET_HELM, {value: true}),
223
+ chiralityEngine: ui.input.bool(PT_UI_USE_CHIRALITY, {value: false}),
224
+ highlightMonomers: ui.input.bool(PT_UI_HIGHLIGHT_MONOMERS, {value: false}),
225
+ rules: {
226
+ header: ui.inlineText([PT_UI_RULES_USED]),
227
+ form: await (ruleInputs = new RuleInputs(RULES_PATH, RULES_STORAGE_NAME, '.json', {
228
+ onValueChanged: (value: string[]) => { ruleFileList = value; }
229
+ })).getForm()
230
+ },
169
231
  trivialNameCol: ui.input.column2(
170
232
  'Trivial name', {
171
233
  table: cell?.dataFrame,
@@ -186,28 +248,33 @@ async function getPolyToolEnumerateDialog(
186
248
  }),
187
249
  };
188
250
 
189
- inputs.toHarmonizedSequence.root.style.display = 'none';
190
251
  inputs.trivialNameCol.addOptions(trivialNameSampleDiv);
191
252
 
192
253
  let placeholdersValidity: string | null = null;
193
254
  inputs.placeholders.addValidator((value: string): string | null => {
194
255
  const errors: string[] = [];
195
256
  try {
257
+ if (dataRole !== PolyToolDataRole.macromolecule)
258
+ return null;
259
+
196
260
  const missedMonomerList: { polymerType: PolymerType, symbol: string }[] = [];
197
261
  for (const ph of inputs.placeholders.placeholdersValue) {
198
262
  const pos = ph.position;
263
+ if (pos == null)
264
+ continue;
199
265
  if (pos >= inputs.macromolecule.molValue.atoms.length) {
200
266
  errors.push(`There is no monomer at position ${pos + 1}.`);
201
267
  continue;
202
268
  }
203
269
  const a = inputs.macromolecule.molValue.atoms[pos];
204
- const helmType: HelmType = a.biotype()!;
205
- const polymerType = helmTypeToPolymerType(helmType);
206
- for (const symbol of ph.monomers) {
207
- const substituteMonomer = monomerLib.getMonomer(polymerType, symbol)!;
208
- // TODO: Check substitution monomer is presented in the library
209
- if (!substituteMonomer || !substituteMonomer.lib)
210
- missedMonomerList.push({polymerType, symbol});
270
+ if (a) {
271
+ const helmType: HelmType = a.biotype()!;
272
+ const polymerType = helmTypeToPolymerType(helmType);
273
+ for (const symbol of ph.monomers) {
274
+ const substituteMonomer = monomerLib.getMonomer(polymerType, symbol)!;
275
+ if (!substituteMonomer || !substituteMonomer.lib)
276
+ missedMonomerList.push({polymerType, symbol});
277
+ }
211
278
  }
212
279
  }
213
280
 
@@ -231,6 +298,57 @@ async function getPolyToolEnumerateDialog(
231
298
  return placeholdersValidity;
232
299
  });
233
300
 
301
+ // inputs.placeholdersBreadth.addValidator((value: string): string | null => {
302
+ // const errors: string[] = [];
303
+ // try {
304
+ // if (dataRole !== PolyToolDataRole.macromolecule)
305
+ // return null;
306
+ //
307
+ // const missedMonomerList: { polymerType: PolymerType, symbol: string }[] = [];
308
+ // for (const ph of inputs.placeholdersBreadth.placeholdersBreadthValue) {
309
+ // const posErrors = [];
310
+ // if (ph.start == null || ph.end == null)
311
+ // continue;
312
+ // if (ph.start < 0)
313
+ // posErrors.push(`There is no monomer at start position ${ph.start + 1}.`);
314
+ // if (ph.start >= inputs.macromolecule.molValue.atoms.length)
315
+ // posErrors.push(`There is no monomer at start position ${ph.start + 1}.`);
316
+ // if (ph.end < 0)
317
+ // posErrors.push(`There is no monomer at end position ${ph.end + 1}.`);
318
+ // if (ph.end >= inputs.macromolecule.molValue.atoms.length)
319
+ // posErrors.push(`There is no monomer at end position ${ph.end + 1}.`);
320
+ // errors.push(...posErrors);
321
+ // if (posErrors.length > 0)
322
+ // continue;
323
+ //
324
+ // const polymerType = PolymerTypes.PEPTIDE;
325
+ // for (const symbol of ph.monomers) {
326
+ // const substituteMonomer = monomerLib.getMonomer(null, symbol)!;
327
+ // if (!substituteMonomer || !substituteMonomer.lib)
328
+ // missedMonomerList.push({polymerType, symbol});
329
+ // }
330
+ //
331
+ // const byType: { [polymerType: string]: string[] } = {};
332
+ // for (const sm of missedMonomerList) {
333
+ // let byTypeList = byType[sm.polymerType];
334
+ // if (!byTypeList) byTypeList = byType[sm.polymerType] = [];
335
+ // byTypeList.push(sm.symbol);
336
+ // }
337
+ // const byTypeStr: string = Object.entries(byType)
338
+ // .map(([polymerType, symbolList]) => `${polymerType}: ${symbolList.join(', ')}`)
339
+ // .join('\n');
340
+ // if (Object.keys(byTypeStr).length > 0)
341
+ // errors.push(`Placeholders contain missed monomers: ${byTypeStr}`);
342
+ // placeholdersValidity = errors.length > 0 ? errors.join('\n') : null;
343
+ // }
344
+ // } catch (err: any) {
345
+ // const [errMsg, errStack] = defaultErrorHandler(err, false);
346
+ // placeholdersValidity = errMsg;
347
+ // }
348
+ // setTimeout(() => { updateWarnings(); }, 0);
349
+ // return placeholdersValidity;
350
+ // });
351
+
234
352
  subs.push(inputs.macromolecule.onMouseMove.subscribe((e: MouseEvent) => {
235
353
  try {
236
354
  _package.logger.debug(`${logPrefix}, placeholdersInput.onMouseMove()`);
@@ -265,39 +383,19 @@ async function getPolyToolEnumerateDialog(
265
383
  const clickedAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
266
384
  if (clickedAtom) {
267
385
  const clickedAtomContIdx = clickedAtom._parent.atoms.indexOf(clickedAtom);
268
- const clickedAtomContIdxStr = (clickedAtomContIdx + 1).toString();
269
-
270
- const phDf = inputs.placeholders.grid.dataFrame;
271
- const posList = phDf.columns.byName('Position').toList();
272
- let rowIdx = posList.indexOf(clickedAtomContIdxStr);
273
- if (rowIdx === -1) {
274
- rowIdx = posList.findIndex((v) => isNaN(v));
275
- if (rowIdx === -1)
276
- rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
277
-
278
- phDf.set('Position', rowIdx, clickedAtomContIdxStr);
279
- // const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
280
- }
281
- phDf.currentCell = phDf.cell(rowIdx, 'Monomers');
282
- //const gridRowIdx = inputs.placeholders.grid.tableRowToGrid(rowIdx);
283
- //const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
284
- const k = 42;
386
+ const clickedAtomContIdxStr = String(clickedAtomContIdx + 1);
387
+ inputs.placeholders.addPosition(clickedAtomContIdx);
285
388
  }
286
389
  } catch (err: any) {
287
390
  defaultErrorHandler(err);
288
391
  }
289
392
  }));
290
- subs.push(inputs.placeholders.grid.dataFrame.onDataChanged.subscribe(() => {
291
- updateMolView();
292
- }));
293
- subs.push(fromEvent<KeyboardEvent>(inputs.placeholders.grid.root, 'keydown')
294
- .subscribe((e: KeyboardEvent) => {
295
- if (e.key === 'Enter') e.stopPropagation();
296
- }));
393
+ subs.push(inputs.placeholders.onChanged.subscribe(() => { updateViewMol(); }));
297
394
 
298
395
  // TODO: suspect
299
396
  subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
300
- if (resizeInputs) resizeInputs();
397
+ if (resizeInputs)
398
+ resizeInputs();
301
399
  }));
302
400
 
303
401
  // Displays the molecule from a current cell (monitors changes)
@@ -305,14 +403,15 @@ async function getPolyToolEnumerateDialog(
305
403
  const cell = grok.shell.tv.dataFrame.currentCell;
306
404
  if (cell.column.semType !== DG.SEMTYPE.MACROMOLECULE) return;
307
405
 
308
- fillForCurrentCell(cell);
406
+ [seqValue, dataRole] = getValue();
407
+ fillForCurrentCell(seqValue, dataRole, cell);
309
408
  }));
310
409
 
311
410
  inputs.macromolecule.root.style.setProperty('min-width', '250px', 'important');
312
411
  // inputs.macromolecule.root.style.setProperty('max-height', '300px', 'important');
313
412
 
314
- const phPosSet = new Set<number>(inputs.placeholders.placeholdersValue.map((ph) => ph.position));
315
- const updateMolView = () => {
413
+ const updateViewMol = () => {
414
+ const phPosSet = new Set<number>(inputs.placeholders.placeholdersValue.map((ph) => ph.position));
316
415
  const mol = inputs.macromolecule.molValue;
317
416
  for (let aI = 0; aI < mol.atoms.length; aI++) {
318
417
  const a = mol.atoms[aI];
@@ -321,6 +420,22 @@ async function getPolyToolEnumerateDialog(
321
420
  inputs.macromolecule.redraw();
322
421
  };
323
422
 
423
+ const updateViewRules = () => {
424
+ if (inputs.toAtomicLevel.value && dataRole === PolyToolDataRole.template) {
425
+ inputs.generateHelm.root.style.removeProperty('display');
426
+ inputs.chiralityEngine.root.style.removeProperty('display');
427
+ inputs.highlightMonomers.root.style.removeProperty('display');
428
+ inputs.rules.header.style.removeProperty('display');
429
+ inputs.rules.form.style.removeProperty('display');
430
+ } else {
431
+ inputs.generateHelm.root.style.display = inputs.chiralityEngine.root.style.display =
432
+ inputs.highlightMonomers.root.style.display = 'none';
433
+ inputs.rules.header.style.display = inputs.rules.form.style.display = 'none';
434
+ }
435
+ if (resizeInputs)
436
+ resizeInputs();
437
+ };
438
+
324
439
  const updateWarnings = () => {
325
440
  const warnings = placeholdersValidity;
326
441
  // const iw = inputs.warnings;
@@ -344,15 +459,6 @@ async function getPolyToolEnumerateDialog(
344
459
  };
345
460
 
346
461
  const fillTrivialNameList = (table?: DG.DataFrame) => {
347
- // const colList: DG.Column[] = [];
348
- // const colCount: number = cell.dataFrame.columns.length;
349
- //
350
- // // TODO: by semType?
351
- // for (let colI: number = 0; colI < colCount; ++colI) {
352
- // const col = cell.dataFrame.columns.byIndex(colI);
353
- // if (col.type === DG.COLUMN_TYPE.STRING) colList.push(col);
354
- // }
355
-
356
462
  if (table) {
357
463
  inputs.trivialNameCol.setColumnInputTable(table);
358
464
  inputs.trivialNameCol.root.style.removeProperty('display');
@@ -360,36 +466,18 @@ async function getPolyToolEnumerateDialog(
360
466
  inputs.trivialNameCol.setColumnInputTable(emptyDf);
361
467
  inputs.trivialNameCol.root.style.setProperty('display', 'none');
362
468
  }
363
- if (resizeInputs) resizeInputs();
469
+ if (resizeInputs)
470
+ resizeInputs();
364
471
  };
365
472
 
366
- const fillForCurrentCell = async (cell?: DG.Cell): Promise<PolyToolDataRole> => {
367
- let resDataRole;
368
- let helmValue: string;
369
- let table: DG.DataFrame | undefined = undefined;
370
- if (cell && cell.rowIndex >= 0 && cell?.column.semType == DG.SEMTYPE.MACROMOLECULE) {
371
- const sh = _package.seqHelper.getSeqHandler(cell.column);
372
- const mValue = await sh.getValue(cell.rowIndex);
373
- helmValue = mValue.value;
374
- table = cell.dataFrame;
375
- resDataRole = (mValue.tags[PolyToolTags.dataRole] as PolyToolDataRole.template) ?? PolyToolDataRole.macromolecule;
376
- } else {
377
- helmValue = PT_HELM_EXAMPLE;
378
- resDataRole = PolyToolDataRole.macromolecule;
379
- }
380
- inputs.macromolecule.stringValue = helmValue;
381
-
382
- if (resDataRole === PolyToolDataRole.template) {
383
- inputs.toAtomicLevel.root.style.display = 'none';
384
- } else {
385
- inputs.toAtomicLevel.root.style.removeProperty('display');
386
- }
387
-
473
+ const fillForCurrentCell = (mmValue: SeqValueBase, dataRole: PolyToolDataRole, cell?: DG.Cell): void => {
474
+ inputs.macromolecule.value = mmValue;
475
+ const table: DG.DataFrame | undefined = cell?.dataFrame;
388
476
  fillTrivialNameList(table);
389
- return resDataRole;
390
477
  };
391
478
 
392
- let dataRole: PolyToolDataRole = await fillForCurrentCell(cell);
479
+ fillForCurrentCell(seqValue, dataRole, cell);
480
+ updateViewRules();
393
481
 
394
482
  const exec = async (): Promise<void> => {
395
483
  try {
@@ -415,9 +503,15 @@ async function getPolyToolEnumerateDialog(
415
503
  breadthPlaceholders: inputs.placeholdersBreadth.placeholdersBreadthValue,
416
504
  keepOriginal: inputs.keepOriginal.value,
417
505
  };
418
- const toAtomicLevelV = inputs.toAtomicLevel.value && dataRole == PolyToolDataRole.macromolecule;
419
- const enumeratorResDf = await polyToolEnumerateHelm(srcHelm, dataRole, srcId, params,
420
- toAtomicLevelV, seqHelper, helmHelper);
506
+ const toAtomicLevelV: boolean = inputs.toAtomicLevel.value;
507
+ const enumeratorResDf = await polyToolEnumerateSeq(srcHelm, dataRole, srcId, params,
508
+ toAtomicLevelV ? {
509
+ generateHelm: inputs.generateHelm.value,
510
+ chiralityEngine: inputs.chiralityEngine.value,
511
+ highlightMonomers: inputs.highlightMonomers.value,
512
+ rules: await ruleInputs.getActive()
513
+ } : false,
514
+ helmHelper);
421
515
  grok.shell.addTableView(enumeratorResDf);
422
516
  }
423
517
  } catch (err: any) {
@@ -426,12 +520,27 @@ async function getPolyToolEnumerateDialog(
426
520
  };
427
521
 
428
522
  const dialog = ui.dialog({title: PT_UI_DIALOG_ENUMERATION, showFooter: true})
429
- .add(inputs.macromolecule)
430
- .add(inputs.placeholders)
431
- .add(inputs.enumeratorType)
432
- .add(inputs.placeholdersBreadth)
433
- .add(inputs.trivialNameCol)
434
- .add(ui.divH([inputs.keepOriginal.root, inputs.toAtomicLevel.root, inputs.toHarmonizedSequence.root],
523
+ .add(inputs.macromolecule.root)
524
+ .add(ui.divH([
525
+ ui.divV([
526
+ inputs.placeholders.root,
527
+ inputs.enumeratorType.root,],
528
+ {style: {width: '50%'}}
529
+ ),
530
+ ui.divV([
531
+ inputs.placeholdersBreadth.root],
532
+ {style: {width: '50%'}}),],
533
+ {style: {width: '100%'}}))
534
+ .add(ui.divH([
535
+ ui.divV([
536
+ inputs.trivialNameCol.root,
537
+ inputs.keepOriginal.root],
538
+ {style: {width: '50%'}}),
539
+ ui.divV([
540
+ ui.divH([inputs.toAtomicLevel.root, inputs.generateHelm.root]),
541
+ ui.divH([inputs.chiralityEngine.root, inputs.highlightMonomers.root]),
542
+ inputs.rules.header, inputs.rules.form],
543
+ {style: {width: '50%'}}),],
435
544
  {style: {width: '100%'}}))
436
545
  .add(warningsTextDiv)
437
546
  // .addButton('Enumerate', () => {
@@ -452,18 +561,24 @@ async function getPolyToolEnumerateDialog(
452
561
  trivialNameCol: inputs.trivialNameCol.stringValue,
453
562
  keepOriginal: inputs.keepOriginal.value,
454
563
  toAtomicLevel: inputs.toAtomicLevel.value,
455
- toHarmonizedSequence: inputs.toHarmonizedSequence.value,
564
+ generateHelm: inputs.generateHelm.value,
565
+ chiralityEngine: inputs.chiralityEngine.value,
566
+ highlightMonomers: inputs.highlightMonomers.value,
567
+ rules: ruleFileList,
456
568
  };
457
569
  },
458
570
  /* applyInput */ (x: PolyToolEnumerateHelmSerialized): void => {
459
571
  inputs.macromolecule.stringValue = x.macromolecule;
460
572
  inputs.placeholders.stringValue = x.placeholders;
461
- inputs.enumeratorType.value = x.enumeratorType;
573
+ inputs.enumeratorType.value = x.enumeratorType ?? PolyToolEnumeratorTypes.Single;
462
574
  inputs.placeholdersBreadth.stringValue = x.placeholdersBreadth;
463
575
  inputs.trivialNameCol.stringValue = x.trivialNameCol;
464
- inputs.keepOriginal.value = x.keepOriginal;
465
- inputs.toAtomicLevel.value = x.toAtomicLevel;
466
- inputs.toHarmonizedSequence.value = x.toHarmonizedSequence;
576
+ inputs.keepOriginal.value = x.keepOriginal ?? false;
577
+ inputs.toAtomicLevel.value = x.toAtomicLevel ?? true;
578
+ inputs.generateHelm.value = x.generateHelm ?? true;
579
+ inputs.chiralityEngine.value = x.chiralityEngine ?? false;
580
+ inputs.highlightMonomers.value = x.highlightMonomers ?? false;
581
+ ruleInputs.setActive(x.rules);
467
582
  });
468
583
  return dialog;
469
584
  } catch (err: any) {
@@ -476,13 +591,17 @@ async function getPolyToolEnumerateDialog(
476
591
  * @param {DG.SemanticValue} srcValue Source value to enumerate, either of data role
477
592
  * {@link PolyToolDataRole.template} or {@link PolyToolDataRole.macromolecule}
478
593
  * */
479
- async function polyToolEnumerateHelm(
594
+ async function polyToolEnumerateSeq(
480
595
  srcHelm: string, dataRole: PolyToolDataRole, srcId: { value: string, colName: string } | null,
481
- params: PolyToolEnumeratorParams, toAtomicLevel: boolean, seqHelper: ISeqHelper, helmHelper: IHelmHelper
596
+ params: PolyToolEnumeratorParams,
597
+ toAtomicLevel: { generateHelm: boolean, chiralityEngine: boolean, highlightMonomers: boolean, rules: string[] } | false,
598
+ helmHelper: IHelmHelper
482
599
  ): Promise<DG.DataFrame> {
483
600
  const pi = DG.TaskBarProgressIndicator.create('PolyTool enumerating...');
484
601
  try {
485
- await getHelmHelper(); // initializes JSDraw and org
602
+ const libHelper = await getMonomerLibHelper();
603
+ const rdKitModule = await getRdKitModule();
604
+ const monomerLib = libHelper.getMonomerLib(); // TODO: Get monomer lib from src SeqValueBase
486
605
 
487
606
  const resList = doPolyToolEnumerateHelm(srcHelm, srcId?.value ?? '', params);
488
607
  let enumCol: DG.Column<string>;
@@ -500,9 +619,9 @@ async function polyToolEnumerateHelm(
500
619
  templateList[rowIdx] = chain.getNotation();
501
620
  }
502
621
  enumCol = DG.Column.fromList(DG.COLUMN_TYPE.STRING, 'Enumerated', templateList);
503
- // enumCol.semType = DG.SEMTYPE.MACROMOLECULE;
504
- // enumCol.setTag(PolyToolTags.dataRole, PolyToolDataRole.template);
505
- // applyNotationProviderForCyclized(enumCol, '-');
622
+ enumCol.semType = DG.SEMTYPE.MACROMOLECULE;
623
+ enumCol.setTag(PolyToolTags.dataRole, PolyToolDataRole.template);
624
+ applyNotationProviderForCyclized(enumCol, '-');
506
625
  break;
507
626
  }
508
627
  }
@@ -512,10 +631,20 @@ async function polyToolEnumerateHelm(
512
631
  applyNotationProviderForCyclized(enumCol, '-');
513
632
  }
514
633
 
515
- if (toAtomicLevel && dataRole != PolyToolDataRole.template) {
516
- const seqHelper: ISeqHelper = await getSeqHelper();
517
- const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumCol, true, true);
518
- enumeratorResDf.columns.add(toAtomicLevelRes.molCol!, false);
634
+ if (toAtomicLevel) {
635
+ let resHelmCol: DG.Column<string>;
636
+ if (dataRole === PolyToolDataRole.macromolecule) {
637
+ resHelmCol = enumCol;
638
+ const talRes = await helmHelper.seqHelper.helmToAtomicLevel(resHelmCol,
639
+ toAtomicLevel.chiralityEngine, toAtomicLevel.highlightMonomers);
640
+ enumeratorResDf.columns.add(talRes.molCol!, false);
641
+ const resMolCol = talRes.molCol!;
642
+ buildMonomerHoverLink(resHelmCol, resMolCol, monomerLib, helmHelper.seqHelper, rdKitModule);
643
+ } else if (dataRole === PolyToolDataRole.template) {
644
+ const talRes = await polyToolConvert(enumCol,
645
+ toAtomicLevel.generateHelm, toAtomicLevel.chiralityEngine, toAtomicLevel.rules);
646
+ resHelmCol = talRes[0];
647
+ }
519
648
  }
520
649
 
521
650
  if (srcId) {
@@ -9,7 +9,7 @@ import {
9
9
  } from '@datagrok-libraries/bio/src/helm/types';
10
10
 
11
11
 
12
- import {Chain} from './pt-conversion';
12
+ import {Chain, PtBio} from './conversion/pt-chain';
13
13
  import {getAvailableMonomers} from './utils';
14
14
  import {PolyToolEnumeratorParams, PolyToolEnumeratorTypes, PolyToolPlaceholder, PolyToolBreadthPlaceholder} from './types';
15
15
 
@@ -76,7 +76,7 @@ function getPtEnumeratorBreadth(m: HelmMol, placeholdersBreadth: PolyToolBreadth
76
76
  export function doPolyToolEnumerateHelm(
77
77
  helm: string, id: string, params: PolyToolEnumeratorParams
78
78
  ): [ /* helm */ string, /* id */ string][] {
79
- const molHandler = new JSDraw2.MolHandler<HelmType, IHelmEditorOptions>();
79
+ const molHandler = new JSDraw2.MolHandler<HelmType, PtBio, IHelmEditorOptions>();
80
80
  const plugin = new org.helm.webeditor.Plugin(molHandler);
81
81
  org.helm.webeditor.IO.parseHelm(plugin, helm, new JSDraw2.Point(0, 0), undefined);
82
82
  const m = molHandler.m;