@datagrok/bio 2.12.16 → 2.12.18

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.
Files changed (38) hide show
  1. package/CHANGELOG.md +20 -2
  2. package/dist/79.js.map +1 -1
  3. package/dist/package-test.js +5 -5
  4. package/dist/package-test.js.map +1 -1
  5. package/dist/package.js +3 -3
  6. package/dist/package.js.map +1 -1
  7. package/package.json +6 -6
  8. package/src/package-test.ts +1 -1
  9. package/src/package.ts +38 -44
  10. package/src/tests/monomer-libraries-tests.ts +1 -4
  11. package/src/tests/renderers-monomer-placer-tests.ts +9 -8
  12. package/src/tests/renderers-test.ts +1 -1
  13. package/src/tests/scoring.ts +2 -2
  14. package/src/tests/substructure-filters-tests.ts +4 -2
  15. package/src/tests/to-atomic-level-tests.ts +1 -1
  16. package/src/tests/utils.ts +15 -0
  17. package/src/utils/cell-renderer.ts +45 -70
  18. package/src/utils/{poly-tool/cyclized.ts → cyclized.ts} +3 -7
  19. package/src/utils/helm-to-molfile/converter/converter.ts +10 -5
  20. package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +9 -9
  21. package/src/utils/helm-to-molfile/converter/polymer.ts +10 -3
  22. package/src/utils/monomer-cell-renderer.ts +18 -8
  23. package/src/utils/monomer-lib/lib-manager.ts +56 -18
  24. package/src/utils/monomer-lib/library-file-manager/event-manager.ts +15 -9
  25. package/src/utils/monomer-lib/library-file-manager/file-manager.ts +78 -59
  26. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +3 -1
  27. package/src/utils/monomer-lib/library-file-manager/ui.ts +52 -47
  28. package/src/utils/monomer-lib/monomer-lib.ts +91 -10
  29. package/src/utils/sequence-to-mol.ts +7 -7
  30. package/src/widgets/bio-substructure-filter-helm.ts +5 -4
  31. package/src/widgets/bio-substructure-filter.ts +2 -3
  32. package/webpack.config.js +3 -0
  33. package/src/utils/poly-tool/const.ts +0 -40
  34. package/src/utils/poly-tool/csv-to-json-monomer-lib-converter.ts +0 -40
  35. package/src/utils/poly-tool/monomer-lib-handler.ts +0 -115
  36. package/src/utils/poly-tool/transformation.ts +0 -320
  37. package/src/utils/poly-tool/ui.ts +0 -59
  38. package/src/utils/poly-tool/utils.ts +0 -20
@@ -4,16 +4,15 @@ import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import $ from 'cash-dom';
7
- import * as rxjs from 'rxjs';
7
+ import {Subject} from 'rxjs';
8
8
  import './style.css';
9
9
 
10
10
  import {
11
11
  getUserLibSettings, setUserLibSettings
12
12
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
13
13
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
14
- import {MonomerLibManager} from '../lib-manager';
14
+ import {getMonomerLibHelper, IMonomerLibFileManager} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
15
15
 
16
- import {MonomerLibFileManager} from './file-manager';
17
16
  import {MonomerLibFileEventManager} from './event-manager';
18
17
 
19
18
  export async function showManageLibrariesDialog(): Promise<void> {
@@ -30,37 +29,39 @@ export async function getMonomerLibraryManagerLink(): Promise<DG.Widget> {
30
29
  }
31
30
 
32
31
  class MonomerLibraryManagerWidget {
33
- private constructor(
34
- private eventManager: MonomerLibFileEventManager
35
- ) { }
32
+ private _fileManager: IMonomerLibFileManager;
36
33
 
37
- private static _instance: MonomerLibraryManagerWidget;
34
+ private _widget: DG.Widget;
35
+ public get widget(): DG.Widget { return this._widget; }
38
36
 
39
- static async getContent(eventManager: MonomerLibFileEventManager): Promise<DG.Widget> {
40
- if (!MonomerLibraryManagerWidget._instance)
41
- MonomerLibraryManagerWidget._instance = new MonomerLibraryManagerWidget(eventManager);
37
+ private constructor() {}
42
38
 
43
- if (!MonomerLibraryManagerWidget._instance.widget)
44
- MonomerLibraryManagerWidget._instance.widget = await MonomerLibraryManagerWidget._instance.createWidget();
39
+ private static instancePromise?: Promise<MonomerLibraryManagerWidget>;
45
40
 
46
- return MonomerLibraryManagerWidget._instance.widget;
41
+ static async getInstance(): Promise<MonomerLibraryManagerWidget> {
42
+ if (MonomerLibraryManagerWidget.instancePromise === undefined) {
43
+ MonomerLibraryManagerWidget.instancePromise = (async () => {
44
+ const instance = new MonomerLibraryManagerWidget();
45
+ const libHelper = await getMonomerLibHelper();
46
+ instance._fileManager = await libHelper.getFileManager();
47
+ instance._widget = await instance.createWidget();
48
+ return instance;
49
+ })();
50
+ }
51
+ return MonomerLibraryManagerWidget.instancePromise;
47
52
  }
48
53
 
49
- private monomerLibFileManager: MonomerLibFileManager;
50
- private widget: DG.Widget | undefined;
51
-
52
54
  private async createWidget() {
53
- this.monomerLibFileManager = await MonomerLibFileManager.getInstance(this.eventManager);
54
55
  const content = await this.getWidgetContent();
55
- this.eventManager.addLibraryFileRequested$.subscribe(
56
+ const monomerLibHelper = await getMonomerLibHelper();
57
+ monomerLibHelper.eventManager.addLibraryFileRequested$.subscribe(
56
58
  async () => await this.promptToAddLibraryFiles()
57
59
  );
58
60
  return new DG.Widget(content);
59
61
  }
60
62
 
61
63
  private async getWidgetContent(): Promise<HTMLElement> {
62
- this.monomerLibFileManager = await MonomerLibFileManager.getInstance(this.eventManager);
63
- const libControlsForm = await LibraryControlsManager.createControlsForm(this.eventManager);
64
+ const libControlsForm = await LibraryControlsManager.createControlsForm();
64
65
  $(libControlsForm).addClass('monomer-lib-controls-form');
65
66
  const widgetContent = ui.divV([libControlsForm]);
66
67
  return widgetContent;
@@ -74,7 +75,7 @@ class MonomerLibraryManagerWidget {
74
75
  const name = selectedFile.name;
75
76
  const progressIndicator = DG.TaskBarProgressIndicator.create(`Adding ${name} as a monomer library`);
76
77
  try {
77
- await this.monomerLibFileManager.addLibraryFile(content, name);
78
+ await this._fileManager.addLibraryFile(content, name);
78
79
  // this.eventManager.updateLibrarySelectionStatus(name, true);
79
80
  } catch (e) {
80
81
  grok.shell.error(`File ${name} is not a valid monomer library, verify it is aligned to HELM JSON schema.`);
@@ -87,27 +88,30 @@ class MonomerLibraryManagerWidget {
87
88
  }
88
89
 
89
90
  class LibraryControlsManager {
90
- private constructor(private eventManager: MonomerLibFileEventManager) {
91
- this.eventManager.updateUIControlsRequested$.subscribe(
92
- async () => await this.updateControlsForm()
93
- );
94
- this.eventManager.librarySelectionRequested$.subscribe(
95
- async ([fileName, isSelected]) => await this.updateLibrarySelectionStatus(isSelected, fileName)
96
- );
91
+ private constructor(
92
+ private fileManager: IMonomerLibFileManager
93
+ ) {
94
+ this.fileManager.eventManager.updateUIControlsRequested$.subscribe(() => {
95
+ this.updateControlsForm();
96
+ });
97
+ this.fileManager.eventManager.librarySelectionRequested$.subscribe(async ([fileName, isSelected]) => {
98
+ await this.updateLibrarySelectionStatus(isSelected, fileName);
99
+ });
97
100
  }
98
- private monomerLibFileManager: MonomerLibFileManager;
101
+
99
102
  private userLibSettings: UserLibSettings;
100
103
 
101
- static async createControlsForm(eventManager: MonomerLibFileEventManager): Promise<HTMLElement> {
102
- const manager = new LibraryControlsManager(eventManager);
104
+ static async createControlsForm(): Promise<HTMLElement> {
105
+ const libHelper = await getMonomerLibHelper();
106
+ const fileManager = await libHelper.getFileManager();
107
+ const manager = new LibraryControlsManager(fileManager);
103
108
  await manager.initialize();
104
109
 
105
- return await manager._createControlsForm();
110
+ return manager._createControlsForm();
106
111
  }
107
112
 
108
- private async _createControlsForm(): Promise<HTMLElement> {
109
- this.monomerLibFileManager = await MonomerLibFileManager.getInstance(this.eventManager);
110
- const libraryControls = await this.createLibraryControls();
113
+ private _createControlsForm(): HTMLElement {
114
+ const libraryControls = this.createLibraryControls();
111
115
  const inputsForm = ui.form(libraryControls);
112
116
  $(inputsForm).addClass('monomer-lib-controls-form');
113
117
 
@@ -118,14 +122,13 @@ class LibraryControlsManager {
118
122
  this.userLibSettings = await getUserLibSettings();
119
123
  };
120
124
 
121
- private async updateControlsForm(): Promise<void> {
122
- const updatedForm = await this._createControlsForm();
125
+ private updateControlsForm(): void {
126
+ const updatedForm = this._createControlsForm();
123
127
  $('.monomer-lib-controls-form').replaceWith(updatedForm);
124
128
  }
125
129
 
126
- private async createLibraryControls(): Promise<DG.InputBase<boolean | null>[]> {
127
- const fileManager = await MonomerLibFileManager.getInstance(this.eventManager);
128
- const libFileNameList: string[] = fileManager.getValidLibraryPaths();
130
+ private createLibraryControls(): DG.InputBase<boolean | null>[] {
131
+ const libFileNameList: string[] = this.fileManager.getValidLibraryPaths();
129
132
  return libFileNameList.map((libFileName) => this.createLibInput(libFileName));
130
133
  }
131
134
 
@@ -134,8 +137,9 @@ class LibraryControlsManager {
134
137
  const libInput = ui.boolInput(
135
138
  libFileName,
136
139
  isMonomerLibrarySelected,
137
- (isSelected: boolean) => this.eventManager.updateLibrarySelectionStatus(libFileName, isSelected)
138
- );
140
+ (isSelected: boolean) => {
141
+ this.fileManager.eventManager.updateLibrarySelectionStatus(libFileName, isSelected);
142
+ });
139
143
  ui.tooltip.bind(libInput.root, `Include monomers from ${libFileName}`);
140
144
  const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName));
141
145
  ui.tooltip.bind(deleteIcon, `Delete ${libFileName}`);
@@ -149,7 +153,8 @@ class LibraryControlsManager {
149
153
  ): Promise<void> {
150
154
  this.updateLibrarySettings(isMonomerLibrarySelected, libFileName);
151
155
  await setUserLibSettings(this.userLibSettings);
152
- await MonomerLibManager.instance.loadLibraries(true);
156
+ const monomerLibHelper = await getMonomerLibHelper();
157
+ await monomerLibHelper.loadLibraries(true);
153
158
  grok.shell.info('Monomer library user settings saved');
154
159
  }
155
160
 
@@ -172,8 +177,8 @@ class LibraryControlsManager {
172
177
  .onOK(async () => {
173
178
  try {
174
179
  const progressIndicator = DG.TaskBarProgressIndicator.create(`Deleting ${fileName} library`);
175
- this.updateLibrarySelectionStatus(false, fileName);
176
- await this.monomerLibFileManager.deleteLibraryFile(fileName);
180
+ await this.updateLibrarySelectionStatus(false, fileName);
181
+ await this.fileManager.deleteLibraryFile(fileName);
177
182
  progressIndicator.close();
178
183
  } catch (e) {
179
184
  console.error(e);
@@ -189,7 +194,7 @@ class DialogWrapper {
189
194
 
190
195
  private static _instance: DialogWrapper;
191
196
  private dialog?: DG.Dialog;
192
- private closeDialogSubject$ = new rxjs.Subject<void>();
197
+ private closeDialogSubject$ = new Subject<void>();
193
198
 
194
199
  static async showDialog(): Promise<void> {
195
200
  if (!DialogWrapper._instance) {
@@ -207,7 +212,7 @@ class DialogWrapper {
207
212
 
208
213
  private async getDialog(): Promise<DG.Dialog> {
209
214
  const eventManager = MonomerLibFileEventManager.getInstance();
210
- const widget = await MonomerLibraryManagerWidget.getContent(eventManager);
215
+ const widget = (await MonomerLibraryManagerWidget.getInstance()).widget;
211
216
  const dialog = ui.dialog(
212
217
  {
213
218
  title: 'Manage monomer libraries',
@@ -1,10 +1,17 @@
1
1
  /* Do not change these import lines to match external modules in webpack configuration */
2
2
  import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
+ import * as DG from 'datagrok-api/dg';
4
5
 
6
+ import wu from 'wu';
5
7
  import {Observable, Subject} from 'rxjs';
6
8
 
7
- import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types/index';
9
+ import {
10
+ IMonomerLib, Monomer, MonomerLibSummaryType, MonomerType, PolymerType, RGroup
11
+ } from '@datagrok-libraries/bio/src/types';
12
+ import {
13
+ HELM_REQUIRED_FIELD as REQ, HELM_RGROUP_FIELDS as RGP
14
+ } from '@datagrok-libraries/bio/src/utils/const';
8
15
  import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
9
16
 
10
17
  import '../../../css/cell-renderer.css';
@@ -27,18 +34,57 @@ export class MonomerLib implements IMonomerLib {
27
34
  }
28
35
  }
29
36
 
30
- getMonomer(polymerType: string, monomerSymbol: string): Monomer | null {
37
+ /** Creates missing {@link Monomer} */
38
+ addMissingMonomer(polymerType: PolymerType, monomerSymbol: string): Monomer {
39
+ let mSet = this._monomers[polymerType];
40
+ if (!mSet)
41
+ mSet = this._monomers[polymerType] = {};
42
+ const m = mSet[monomerSymbol] = {
43
+ [REQ.SYMBOL]: monomerSymbol,
44
+ [REQ.NAME]: monomerSymbol,
45
+ [REQ.MOLFILE]: '',
46
+ [REQ.AUTHOR]: 'MISSING',
47
+ [REQ.ID]: -1,
48
+ [REQ.RGROUPS]:
49
+ wu.count(1).take(9).map((i) => {
50
+ return {
51
+ /* eslint-disable no-multi-spaces */
52
+ // Samples // PEPTIDE RNA
53
+ [RGP.CAP_GROUP_SMILES]: '', // '[*:1][H]' '[*:1][H]'
54
+ [RGP.ALTERNATE_ID]: '', // 'R1-H' 'R1-H'
55
+ [RGP.CAP_GROUP_NAME]: '', // 'H' 'H'
56
+ [RGP.LABEL]: `R${i.toString()}`, // 'R1' 'R1'
57
+ /* eslint-enable no-multi-spaces */
58
+ } as RGroup;
59
+ }).toArray(),
60
+ [REQ.SMILES]: '',
61
+ [REQ.POLYMER_TYPE]: polymerType,
62
+ [REQ.MONOMER_TYPE]: undefined as unknown as MonomerType, // TODO: Can we get monomerType from atom of POM
63
+ [REQ.CREATE_DATE]: null,
64
+ } as Monomer;
65
+ return m;
66
+ }
67
+
68
+ getMonomer(polymerType: PolymerType, argMonomerSymbol: string): Monomer | null {
69
+ // Adjust RNA's 'R' for ribose to 'r' and 'P' for phosphate to 'p' for case-sensitive monomer names.
70
+ // There are uppercase 'R' and 'P' at RNA samples in test data 'helm2.csv' but lowercase in HELMCoreLibrary.json
71
+ let monomerSymbol = argMonomerSymbol;
72
+ if (polymerType == 'RNA' && monomerSymbol == 'R')
73
+ monomerSymbol = 'r';
74
+ if (polymerType == 'RNA' && monomerSymbol == 'P')
75
+ monomerSymbol = 'p';
76
+
31
77
  if (polymerType in this._monomers! && monomerSymbol in this._monomers![polymerType])
32
78
  return this._monomers![polymerType][monomerSymbol];
33
79
  else
34
80
  return null;
35
81
  }
36
82
 
37
- getPolymerTypes(): string[] {
38
- return Object.keys(this._monomers);
83
+ getPolymerTypes(): PolymerType[] {
84
+ return Object.keys(this._monomers) as PolymerType[];
39
85
  }
40
86
 
41
- getMonomerMolsByPolymerType(polymerType: string): { [monomerSymbol: string]: string } {
87
+ getMonomerMolsByPolymerType(polymerType: PolymerType): { [monomerSymbol: string]: string } {
42
88
  const res: { [monomerSymbol: string]: string } = {};
43
89
 
44
90
  Object.keys(this._monomers[polymerType] ?? {}).forEach((monomerSymbol) => {
@@ -48,14 +94,14 @@ export class MonomerLib implements IMonomerLib {
48
94
  return res;
49
95
  }
50
96
 
51
- getMonomerSymbolsByType(polymerType: string): string[] {
97
+ getMonomerSymbolsByType(polymerType: PolymerType): string[] {
52
98
  return Object.keys(this._monomers[polymerType]);
53
99
  }
54
100
 
55
101
  /** Get a list of monomers with specified element attached to specified
56
102
  * R-group
57
103
  * WARNING: RGroup numbering starts from 1, not 0*/
58
- getMonomerSymbolsByRGroup(rGroupNumber: number, polymerType: string, element?: string): string[] {
104
+ getMonomerSymbolsByRGroup(rGroupNumber: number, polymerType: PolymerType, element?: string): string[] {
59
105
  const monomerSymbols = this.getMonomerSymbolsByType(polymerType);
60
106
  let monomers = monomerSymbols.map((sym) => this.getMonomer(polymerType, sym));
61
107
  monomers = monomers.filter((el) => el !== null);
@@ -116,7 +162,38 @@ export class MonomerLib implements IMonomerLib {
116
162
  this._onChanged.next();
117
163
  }
118
164
 
119
- getTooltip(polymerType: string, monomerSymbol: string): HTMLElement {
165
+ getSummaryObj(): MonomerLibSummaryType {
166
+ const res: MonomerLibSummaryType = {};
167
+ const ptList: PolymerType[] = this.getPolymerTypes();
168
+ for (const pt of ptList)
169
+ res[pt] = this.getMonomerSymbolsByType(pt).length;
170
+ return res;
171
+ }
172
+
173
+ getSummaryDf(): DG.DataFrame {
174
+ const ptList = this.getPolymerTypes();
175
+
176
+ const countList: number[] = new Array<number>(ptList.length);
177
+ for (const [pt, i] of wu.enumerate(ptList))
178
+ countList[i] = this.getMonomerSymbolsByType(pt).length;
179
+
180
+ const resDf: DG.DataFrame = DG.DataFrame.fromColumns([
181
+ DG.Column.fromStrings('polymerType', ptList),
182
+ DG.Column.fromList(DG.COLUMN_TYPE.INT, 'count', countList),
183
+ ]);
184
+ return resDf;
185
+ }
186
+
187
+ /** @deprecated Keep for backward compatibility */
188
+ getSummary(): string {
189
+ const monTypeList: PolymerType[] = this.getPolymerTypes();
190
+ const resStr: string = monTypeList.length == 0 ? 'empty' : monTypeList.map((monType) => {
191
+ return `${monType} ${this.getMonomerSymbolsByType(monType).length}`;
192
+ }).join('\n');
193
+ return resStr;
194
+ }
195
+
196
+ getTooltip(polymerType: PolymerType, monomerSymbol: string): HTMLElement {
120
197
  // getTooltip(monomer: Monomer): HTMLElement;
121
198
  // getTooltip(monomerOrPolymerType: string | Monomer, symbol?: string): HTMLElement {
122
199
  // let polymerType: string;
@@ -163,8 +240,12 @@ export class MonomerLib implements IMonomerLib {
163
240
  label('Source'),
164
241
  ui.divText(monomer.lib?.source ?? 'unknown', {classes: 'ui-input-text'}),
165
242
  ], {classes: 'ui-input-root'}));
166
- } else
167
- res.append(ui.divText('Monomer not found'));
243
+ } else {
244
+ res.append(ui.divV([
245
+ ui.divText(`Monomer '${monomerSymbol}' of type '${polymerType}' not found.`),
246
+ ui.divText('Open the Context Panel, then expand Manage Libraries'),
247
+ ]));
248
+ }
168
249
  return res;
169
250
  }
170
251
  }
@@ -4,14 +4,16 @@ import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {_toAtomicLevel} from '@datagrok-libraries/bio/src/monomer-works/to-atomic-level';
7
- import {helm2mol} from './helm-to-molfile/utils';
8
7
  import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
9
- import {checkInputColumnUI} from './check-input-column';
10
- import {getMonomerLibHelper} from '../package';
11
8
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
12
9
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
13
10
 
14
- export async function sequenceToMolfile(df: DG.DataFrame, macroMolecule: DG.Column, nonlinear: boolean): Promise<void> {
11
+ import {helm2mol} from './helm-to-molfile/utils';
12
+ import {checkInputColumnUI} from './check-input-column';
13
+
14
+ export async function sequenceToMolfile(
15
+ df: DG.DataFrame, macroMolecule: DG.Column, nonlinear: boolean, monomerLib: IMonomerLib
16
+ ): Promise<void> {
15
17
  if (DG.Func.find({package: 'Chem', name: 'getRdKitModule'}).length === 0) {
16
18
  grok.shell.warning('Transformation to atomic level requires package "Chem" installed.');
17
19
  return;
@@ -20,12 +22,10 @@ export async function sequenceToMolfile(df: DG.DataFrame, macroMolecule: DG.Colu
20
22
  const seqSh = SeqHandler.forColumn(macroMolecule);
21
23
  if (!seqSh.isHelm())
22
24
  macroMolecule = seqSh.convert(NOTATION.HELM);
23
- helm2mol(df, macroMolecule);
24
- return;
25
+ return helm2mol(df, macroMolecule);
25
26
  }
26
27
  if (!checkInputColumnUI(macroMolecule, 'To Atomic Level'))
27
28
  return;
28
- const monomerLib: IMonomerLib = getMonomerLibHelper().getBioLib();
29
29
  const atomicLevelRes = await _toAtomicLevel(df, macroMolecule, monomerLib);
30
30
  if (atomicLevelRes.col !== null) {
31
31
  df.columns.add(atomicLevelRes.col, true);
@@ -2,14 +2,15 @@ import * as grok from 'datagrok-api/grok';
2
2
  import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
 
5
+ import * as org from 'org';
5
6
  import $ from 'cash-dom';
6
- import {fromEvent, Observable, Subject, Unsubscribable} from 'rxjs';
7
+ import {fromEvent, Unsubscribable} from 'rxjs';
7
8
 
8
- import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
9
+ import {IHelmWebEditor} from '@datagrok-libraries/bio/src/helm/types';
9
10
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
10
11
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
11
12
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
12
- import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
13
+ import {delay} from '@datagrok-libraries/utils/src/test';
13
14
 
14
15
  import {updateDivInnerHTML} from '../utils/ui-utils';
15
16
  import {helmSubstructureSearch} from '../substructure-search/substructure-search';
@@ -54,7 +55,7 @@ export class HelmBioFilter extends BioFilterBase<BioFilterProps> /* implements I
54
55
  this.logger.warning('TEST: HelmBioFilter.init().sync() waitForElementInDom ready');
55
56
  this.updateFilterPanel();
56
57
  let webEditorHost: HTMLDivElement | null;
57
- let webEditorApp: IWebEditorApp | null;
58
+ let webEditorApp: org.helm.IWebEditorApp | null;
58
59
  // TODO: Unsubscribe 'click' and 'sizeChanged'
59
60
  this.viewSubs.push(fromEvent(this._filterPanel, 'click').subscribe(() => {
60
61
  webEditorHost = ui.div();
@@ -16,7 +16,6 @@ import {TAGS as bioTAGS, NOTATION} from '@datagrok-libraries/bio/src/utils/macro
16
16
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
17
17
  import {delay, testEvent} from '@datagrok-libraries/utils/src/test';
18
18
  import {getHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
19
- import {IHelmWebEditor, IWebEditorApp} from '@datagrok-libraries/bio/src/helm/types';
20
19
  import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
21
20
  import {IRenderer} from '@datagrok-libraries/bio/src/types/renderer';
22
21
  import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
@@ -274,12 +273,12 @@ export class BioSubstructureFilter extends DG.Filter implements IRenderer {
274
273
  async awaitRendered(timeout: number = 10000): Promise<void> {
275
274
  const callLog = `awaitRendered( ${timeout} )`;
276
275
  const logPrefix = `${this.filterToLog()}.${callLog}`;
277
- await delay(0);
276
+ await delay(10);
278
277
  await testEvent(this.onRendered, () => {
279
278
  this.logger.debug(`${logPrefix}, ` + '_onRendered event caught');
280
279
  }, () => {
281
280
  this.invalidate(callLog);
282
- }, timeout, `${logPrefix} ${timeout} timeout`);
281
+ }, timeout, `${logPrefix} timeout`);
283
282
 
284
283
  // Rethrow stored syncer error (for test purposes)
285
284
  const viewErrors = this.filterSyncer.resetErrors();
package/webpack.config.js CHANGED
@@ -41,6 +41,9 @@ module.exports = {
41
41
  'cash-dom': '$',
42
42
  'dayjs': 'dayjs',
43
43
  'wu': 'wu',
44
+ 'scil': 'scil',
45
+ 'org': 'org',
46
+ // 'JSDraw2': 'JSDraw2',
44
47
  },
45
48
  output: {
46
49
  filename: '[name].js',
@@ -1,40 +0,0 @@
1
- import {HELM_REQUIRED_FIELD} from '@datagrok-libraries/bio/src/utils/const';
2
-
3
- export const ALL_MONOMERS = '<All>';
4
-
5
- export const enum TRANSFORMATION_TYPE {
6
- CYCLIZATION = 'Cyclization',
7
- }
8
-
9
- export const enum CYCLIZATION_TYPE {
10
- NO = 'N-O',
11
- NCys = 'N-Cys',
12
- R3 = 'R3-R3',
13
- }
14
-
15
- export const helmFieldsToPolyToolInputFields = {
16
- [HELM_REQUIRED_FIELD.SYMBOL]: 'Short Name',
17
- [HELM_REQUIRED_FIELD.NAME]: 'Medium Name',
18
- [HELM_REQUIRED_FIELD.SMILES]: 'SMILES',
19
- };
20
-
21
- export const R_GROUP_BLOCK_DUMMY = [
22
- {
23
- 'capGroupSMILES': '[*:1][H]',
24
- 'alternateId': 'R1-H',
25
- 'capGroupName': 'H',
26
- 'label': 'R1'
27
- },
28
- {
29
- 'capGroupSMILES': 'O[*:2]',
30
- 'alternateId': 'R2-OH',
31
- 'capGroupName': 'OH',
32
- 'label': 'R2'
33
- },
34
- {
35
- 'capGroupSMILES': '[*:3][H]',
36
- 'alternateId': 'R3-H',
37
- 'capGroupName': 'H',
38
- 'label': 'R3'
39
- }
40
- ];
@@ -1,40 +0,0 @@
1
- import * as DG from 'datagrok-api/dg';
2
-
3
- import {PolyToolMonomerLibHandler} from './monomer-lib-handler';
4
-
5
- /** Handler of custom monomer libs for PolyTool */
6
- export class PolyToolCsvLibHandler {
7
- constructor(private fileName: string, private fileContent: string) {
8
- this.validateFileType();
9
- const df = DG.DataFrame.fromCsv(this.fileContent);
10
- const json = this.toJson(df);
11
- this.polyToolMonomerLib = new PolyToolMonomerLibHandler(json);
12
- this.validateContent();
13
- }
14
-
15
- private polyToolMonomerLib: PolyToolMonomerLibHandler;
16
-
17
- async getJson(): Promise<any> {
18
- const rawLibData = this.polyToolMonomerLib.getJsonMonomerLib();
19
- return rawLibData;
20
- }
21
-
22
- private toJson(df: DG.DataFrame): any[] {
23
- return Array.from({length: df.rowCount}, (_, idx) =>
24
- df.columns.names().reduce((entry: { [key: string]: any }, colName) => {
25
- entry[colName] = df.get(colName, idx);
26
- return entry;
27
- }, {})
28
- );
29
- }
30
-
31
- private validateFileType(): void {
32
- if (!this.fileName.endsWith('.csv'))
33
- throw new Error(`File ${this.fileName} is not an CSV file`);
34
- }
35
-
36
- private validateContent(): void {
37
- if (!this.polyToolMonomerLib.isValid())
38
- throw new Error('Invalid format of CSV monomer lib');
39
- }
40
- }
@@ -1,115 +0,0 @@
1
- /* Do not change these import lines to match external modules in webpack configuration */
2
- import * as grok from 'datagrok-api/grok';
3
- import * as ui from 'datagrok-api/ui';
4
- import * as DG from 'datagrok-api/dg';
5
-
6
- import {HELM_FIELDS, DUMMY_MONOMER} from '@datagrok-libraries/bio/src/utils/const';
7
- import {
8
- helmFieldsToPolyToolInputFields, R_GROUP_BLOCK_DUMMY
9
- } from './const';
10
- import {Monomer, RGroup} from '@datagrok-libraries/bio/src/types/index';
11
-
12
- export class PolyToolMonomerLibHandler {
13
- constructor(private rawLib: any[]) { }
14
-
15
- isValid(): boolean {
16
- return this.rawLib.every((entry) => {
17
- return typeof entry === 'object' &&
18
- Object.values(helmFieldsToPolyToolInputFields).every((field) => {
19
- return field in entry &&
20
- typeof entry[field] === 'string';
21
- });
22
- });
23
- }
24
-
25
- getJsonMonomerLib(): any {
26
- const resultLib: any[] = [];
27
- this.rawLib.forEach((rawMonomer) => {
28
- const monomer = this.prepareMonomer(rawMonomer);
29
- resultLib.push(monomer);
30
- });
31
- return resultLib;
32
- }
33
-
34
- private prepareMonomer(rawMonomer: any): Monomer {
35
- const monomer: Monomer = {...DUMMY_MONOMER};
36
-
37
- Object.entries(helmFieldsToPolyToolInputFields).forEach(([key, value]) => {
38
- const monomerSymbol = rawMonomer[value] as string;
39
- //@ts-ignore
40
- monomer[key] = monomerSymbol;
41
- });
42
-
43
- let key = HELM_FIELDS.SMILES;
44
- const rawSmiles = rawMonomer[helmFieldsToPolyToolInputFields[key]];
45
- const smilesHandler = new SmilesHandler(rawSmiles);
46
- const smiles = smilesHandler.getCappedSmiles();
47
- monomer[key] = smiles;
48
-
49
- key = HELM_FIELDS.RGROUPS;
50
- monomer[key] = RGroupHandler.getRGroups(smilesHandler.getNumberOfRGroups());
51
-
52
- key = HELM_FIELDS.MOLFILE;
53
- monomer[key] = new MolBlockHandler(smilesHandler.getSmilesWithRGroups()).getMolfile();
54
-
55
- return monomer;
56
- }
57
- }
58
-
59
- class SmilesHandler {
60
- constructor(rawSmiles: string) {
61
- const regex = /\[R(\d+)\]/g;
62
- let i = 0;
63
- this.smilesWithRGroups = rawSmiles.replace(regex, (_, capturedDigit) => { ++i; return `[${capturedDigit}*]`; });
64
- this.numberOfRGroups = i;
65
- }
66
-
67
- private numberOfRGroups: number;
68
- private smilesWithRGroups: string;
69
-
70
- getSmilesWithRGroups(): string {
71
- return this.smilesWithRGroups;
72
- }
73
-
74
- getCappedSmiles(): string {
75
- const smiles = this.capRGroups();
76
- return smiles;
77
- }
78
-
79
- getNumberOfRGroups(): number {
80
- return this.numberOfRGroups;
81
- }
82
-
83
- private capRGroups(): string {
84
- let result = this.smilesWithRGroups.replace('[1*]', '[H:1]');
85
- result = result.replace('[2*]', '[OH:2]');
86
- return result.replace('[3*]', '[H:3]');
87
- }
88
- }
89
-
90
- class RGroupHandler {
91
- private constructor() {};
92
-
93
- static getRGroups(numberOfRGroups: number): RGroup[] {
94
- return R_GROUP_BLOCK_DUMMY.slice(0, numberOfRGroups);
95
- }
96
- }
97
-
98
- class MolBlockHandler {
99
- constructor(private smilesWithRGroups: string) { }
100
-
101
- getMolfile(): string {
102
- let molfile = DG.chem.convert(this.smilesWithRGroups, DG.chem.Notation.Smiles, DG.chem.Notation.MolBlock);
103
- molfile = this.restoreRGPLine(molfile);
104
- molfile = this.fixRGroupSymbols(molfile);
105
- return molfile;
106
- }
107
-
108
- private restoreRGPLine(rawMolfile: string): string {
109
- return rawMolfile.replace('M ISO', 'M RGP');
110
- }
111
-
112
- private fixRGroupSymbols(molfile: string): string {
113
- return molfile.replace(/\bR\b/g, 'R#');
114
- }
115
- }