@datagrok/bio 2.13.2 → 2.13.5

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 (107) hide show
  1. package/.eslintrc.json +1 -1
  2. package/CHANGELOG.md +26 -0
  3. package/detectors.js +52 -38
  4. package/dist/111.js +2 -0
  5. package/dist/111.js.map +1 -0
  6. package/dist/234.js +2 -0
  7. package/dist/234.js.map +1 -0
  8. package/dist/242.js +2 -0
  9. package/dist/242.js.map +1 -0
  10. package/dist/{286.js → 248.js} +1 -1
  11. package/dist/248.js.map +1 -0
  12. package/dist/284.js +3 -0
  13. package/dist/284.js.map +1 -0
  14. package/dist/317.js +2 -0
  15. package/dist/317.js.map +1 -0
  16. package/dist/589.js +2 -0
  17. package/dist/589.js.map +1 -0
  18. package/dist/603.js +2 -0
  19. package/dist/603.js.map +1 -0
  20. package/dist/682.js +2 -0
  21. package/dist/682.js.map +1 -0
  22. package/dist/705.js +2 -0
  23. package/dist/705.js.map +1 -0
  24. package/dist/{590.js → 731.js} +2 -2
  25. package/dist/731.js.map +1 -0
  26. package/dist/778.js +2 -0
  27. package/dist/778.js.map +1 -0
  28. package/dist/793.js +2 -0
  29. package/dist/793.js.map +1 -0
  30. package/dist/950.js +2 -0
  31. package/dist/950.js.map +1 -0
  32. package/dist/package-test.js +6 -7
  33. package/dist/package-test.js.map +1 -1
  34. package/dist/package.js +6 -7
  35. package/dist/package.js.map +1 -1
  36. package/files/cache_config.json +7 -0
  37. package/package.json +17 -23
  38. package/src/analysis/sequence-activity-cliffs.ts +1 -1
  39. package/src/function-edtiors/split-to-monomers-editor.ts +6 -7
  40. package/src/package-types.ts +19 -19
  41. package/src/package.ts +23 -16
  42. package/src/substructure-search/substructure-search.ts +9 -10
  43. package/src/tests/WebLogo-positions-test.ts +6 -6
  44. package/src/tests/activity-cliffs-tests.ts +5 -2
  45. package/src/tests/bio-tests.ts +6 -6
  46. package/src/tests/checkInputColumn-tests.ts +3 -3
  47. package/src/tests/converters-test.ts +1 -1
  48. package/src/tests/detectors-tests.ts +25 -13
  49. package/src/tests/fasta-export-tests.ts +2 -2
  50. package/src/tests/mm-distance-tests.ts +1 -1
  51. package/src/tests/msa-tests.ts +2 -2
  52. package/src/tests/renderers-test.ts +5 -5
  53. package/src/tests/scoring.ts +26 -5
  54. package/src/tests/seq-handler-get-region.ts +4 -4
  55. package/src/tests/sequence-space-test.ts +1 -1
  56. package/src/tests/substructure-filters-tests.ts +4 -1
  57. package/src/tests/to-atomic-level-tests.ts +1 -1
  58. package/src/utils/cell-renderer-consts.ts +3 -11
  59. package/src/utils/cell-renderer.ts +15 -17
  60. package/src/utils/context-menu.ts +1 -1
  61. package/src/utils/convert.ts +7 -4
  62. package/src/utils/get-region-func-editor.ts +11 -16
  63. package/src/utils/get-region.ts +5 -5
  64. package/src/utils/macromolecule-column-widget.ts +1 -1
  65. package/src/utils/monomer-lib/lib-manager.ts +20 -8
  66. package/src/utils/monomer-lib/library-file-manager/file-manager.ts +28 -24
  67. package/src/utils/monomer-lib/library-file-manager/file-validator.ts +2 -1
  68. package/src/utils/monomer-lib/library-file-manager/ui.ts +3 -6
  69. package/src/utils/multiple-sequence-alignment-ui.ts +10 -11
  70. package/src/utils/multiple-sequence-alignment.ts +2 -2
  71. package/src/utils/pepsea.ts +1 -1
  72. package/src/utils/save-as-fasta.ts +5 -5
  73. package/src/viewers/vd-regions-viewer.ts +2 -2
  74. package/src/widgets/bio-substructure-filter.ts +7 -7
  75. package/src/widgets/package-settings-editor-widget.ts +27 -27
  76. package/src/widgets/representations.ts +57 -61
  77. package/tsconfig.json +4 -4
  78. package/webpack.config.js +1 -1
  79. package/dist/23.js +0 -2
  80. package/dist/23.js.map +0 -1
  81. package/dist/231.js +0 -2
  82. package/dist/231.js.map +0 -1
  83. package/dist/282.js +0 -2
  84. package/dist/282.js.map +0 -1
  85. package/dist/286.js.map +0 -1
  86. package/dist/356.js +0 -2
  87. package/dist/356.js.map +0 -1
  88. package/dist/36.js +0 -2
  89. package/dist/36.js.map +0 -1
  90. package/dist/40.js +0 -2
  91. package/dist/40.js.map +0 -1
  92. package/dist/413.js +0 -2
  93. package/dist/413.js.map +0 -1
  94. package/dist/42.js +0 -2
  95. package/dist/42.js.map +0 -1
  96. package/dist/427.js +0 -2
  97. package/dist/427.js.map +0 -1
  98. package/dist/545.js +0 -3
  99. package/dist/545.js.map +0 -1
  100. package/dist/590.js.map +0 -1
  101. package/dist/65.js +0 -2
  102. package/dist/65.js.map +0 -1
  103. package/dist/796.js +0 -2
  104. package/dist/796.js.map +0 -1
  105. package/dist/package-test.js.LICENSE.txt +0 -1
  106. package/dist/package.js.LICENSE.txt +0 -1
  107. /package/dist/{545.js.LICENSE.txt → 284.js.LICENSE.txt} +0 -0
@@ -125,14 +125,14 @@ async function _testMSAOnColumn(
125
125
  const tgtCol = tgtDf.getCol('seq')!;
126
126
  const srcCol: DG.Column = srcDf.getCol('seq')!;
127
127
  expect(srcCol.semType, DG.SEMTYPE.MACROMOLECULE);
128
- expect(srcCol.getTag(DG.TAGS.UNITS), srcNotation);
128
+ expect(srcCol.meta.units, srcNotation);
129
129
  if (alphabet)
130
130
  expect(srcCol.getTag(bioTAGS.alphabet), alphabet);
131
131
 
132
132
  const msaSeqCol = await multipleSequenceAlignmentUI({col: srcCol, pepsea: {method: pepseaMethod}});
133
133
  expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
134
134
  expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
135
- expect(msaSeqCol.getTag(DG.TAGS.UNITS), tgtNotation);
135
+ expect(msaSeqCol.meta.units, tgtNotation);
136
136
  expect(msaSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ_MSA);
137
137
  if (alphabet)
138
138
  expect(msaSeqCol.getTag(bioTAGS.alphabet), alphabet);
@@ -103,7 +103,7 @@ category('renderers', () => {
103
103
  async function _rendererMacromoleculeDifference() {
104
104
  const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
105
105
  ['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
106
- seqDiffCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
106
+ seqDiffCol.meta.units = NOTATION.SEPARATOR;
107
107
  seqDiffCol.setTag(bioTAGS.separator, '/');
108
108
  seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
109
109
  seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
@@ -140,10 +140,10 @@ category('renderers', () => {
140
140
  expect(tv.grid.dataFrame.id, df.id);
141
141
 
142
142
  console.log('Bio: tests/renderers/afterMsa, src before test ' +
143
- `semType="${srcSeqCol!.semType}", units="${srcSeqCol!.getTag(DG.TAGS.UNITS)}", ` +
143
+ `semType="${srcSeqCol!.semType}", units="${srcSeqCol!.meta.units}", ` +
144
144
  `cell.renderer="${srcSeqCol!.getTag(DG.TAGS.CELL_RENDERER)}"`);
145
145
  expect(srcSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
146
- expect(srcSeqCol.getTag(DG.TAGS.UNITS), NOTATION.FASTA);
146
+ expect(srcSeqCol.meta.units, NOTATION.FASTA);
147
147
  expect(srcSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ);
148
148
  expect(srcSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
149
149
  expect(srcSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
@@ -153,7 +153,7 @@ category('renderers', () => {
153
153
  expect(tv.grid.dataFrame.id, df.id);
154
154
 
155
155
  expect(msaSeqCol.semType, DG.SEMTYPE.MACROMOLECULE);
156
- expect(msaSeqCol.getTag(DG.TAGS.UNITS), NOTATION.FASTA);
156
+ expect(msaSeqCol.meta.units, NOTATION.FASTA);
157
157
  expect(msaSeqCol.getTag(bioTAGS.aligned), ALIGNMENT.SEQ_MSA);
158
158
  expect(msaSeqCol.getTag(bioTAGS.alphabet), ALPHABET.PT);
159
159
  expect(msaSeqCol.getTag(DG.TAGS.CELL_RENDERER), 'sequence');
@@ -205,7 +205,7 @@ category('renderers', () => {
205
205
  /**/
206
206
  const seqDiffCol: DG.Column = DG.Column.fromStrings('SequencesDiff',
207
207
  ['meI/hHis/Aca/N/T/dK/Thr_PO3H2/Aca#D-Tyr_Et/Tyr_ab-dehydroMe/meN/E/N/dV']);
208
- seqDiffCol.setTag(DG.TAGS.UNITS, NOTATION.SEPARATOR);
208
+ seqDiffCol.meta.units = NOTATION.SEPARATOR;
209
209
  seqDiffCol.setTag(bioTAGS.separator, '/');
210
210
  seqDiffCol.setTag(bioTAGS.aligned, 'SEQ');
211
211
  seqDiffCol.setTag(bioTAGS.alphabet, 'UN');
@@ -2,7 +2,9 @@ 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 {category, test, expectFloat, before, after} from '@datagrok-libraries/utils/src/test';
5
+ import wu from 'wu';
6
+
7
+ import {category, test, expectFloat, before, after, expect} from '@datagrok-libraries/utils/src/test';
6
8
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
7
9
  import {IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
8
10
 
@@ -13,6 +15,7 @@ import {
13
15
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
14
16
 
15
17
  category('Scoring', () => {
18
+ /* eslint-disable max-len */
16
19
  const sequence = 'sequence';
17
20
  const expectedSimilarity = 'expected_similarity';
18
21
  const expectedIdentity = 'expected_identity';
@@ -22,11 +25,13 @@ PEPTIDE1{Aca.Orn.gGlu.Pqa.D-His_1Bn.dH.hHis.4Abz.D-Tic.D-Dap.Y.Iva.meS.F.P.F.D-1
22
25
  PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC}$$$$,0.68,0.53
23
26
  PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal]}$$$$V2.0,0.34,0.0`
24
27
  );
25
- /* eslint-enable max-len */
26
28
  const seqCol: DG.Column<string> = table.getCol(sequence);
27
- seqCol.setTag(DG.TAGS.UNITS, NOTATION.HELM);
29
+ seqCol.meta.units = NOTATION.HELM;
28
30
  seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
29
31
  const reference = seqCol.get(0)!;
32
+ const shortReference = 'PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva}$$$$';
33
+ const longReference = 'PEPTIDE1{Iva.Gly_allyl.gGlu.Pqa.D-Dip.dH.hHis.4Abz.D-aHyp.D-Dap.Y.Iva.I.Tyr_26diMe.P.Asu.meC.I.Tyr_26diMe.P.Asu.meC}$$$$';
34
+ /* eslint-enable max-len */
30
35
 
31
36
  let monomerLibHelper: IMonomerLibHelper;
32
37
  /** Backup actual user's monomer libraries settings */
@@ -49,15 +54,31 @@ PEPTIDE1{[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[1Nal].[
49
54
  test('Identity', async () => {
50
55
  const scoresCol = await sequenceIdentityScoring(table, seqCol, reference);
51
56
  for (let i = 0; i < scoresCol.length; i++) {
52
- expectFloat(scoresCol.get(i)!, table.get(expectedIdentity, i), 0.01,
57
+ const resScore = scoresCol.get(i)!;
58
+ const tgtScore = table.get(expectedIdentity, i);
59
+ expectFloat(resScore, tgtScore, 0.01,
53
60
  `Wrong identity score for sequence at position ${i}`);
54
61
  }
55
62
  });
56
63
 
64
+ test('Identity-shortReference', async () => {
65
+ const scoresCol = await sequenceIdentityScoring(table, seqCol, shortReference);
66
+ expect(wu.count(0).take(scoresCol.length).map((rowI) => scoresCol.get(rowI))
67
+ .every((v) => v != null && !isNaN(v)), true);
68
+ });
69
+
70
+ test('Identity-longReference', async () => {
71
+ const scoresCol = await sequenceIdentityScoring(table, seqCol, longReference);
72
+ expect(wu.count(0).take(scoresCol.length).map((rowI) => scoresCol.get(rowI))
73
+ .every((v) => v != null && !isNaN(v)), true);
74
+ });
75
+
57
76
  test('Similarity', async () => {
58
77
  const scoresCol = await sequenceSimilarityScoring(table, seqCol, reference);
59
78
  for (let i = 0; i < scoresCol.length; i++) {
60
- expectFloat(scoresCol.get(i)!, table.get(expectedSimilarity, i), 0.01,
79
+ const resScore = scoresCol.get(i)!;
80
+ const tgtScore = table.get(expectedSimilarity, i);
81
+ expectFloat(resScore, tgtScore, 0.01,
61
82
  `Wrong similarity score for sequence at position ${i}`);
62
83
  }
63
84
  });
@@ -82,8 +82,8 @@ PEPTIDE1{[Cys_SEt].T.*.*}$$$$`,
82
82
  const tgtDf = DG.DataFrame.fromCsv(testData.tgtCsv);
83
83
  const tgtSeqCol = tgtDf.getCol('seq');
84
84
 
85
- expect(srcSeqCol.getTag(DG.TAGS.UNITS), testData.units);
86
- expect(resSeqCol.getTag(DG.TAGS.UNITS), testData.units);
85
+ expect(srcSeqCol.meta.units, testData.units);
86
+ expect(resSeqCol.meta.units, testData.units);
87
87
  expect(srcSeqCol.getTag(TAGS.alphabet), testData.alphabet);
88
88
  expect(resSeqCol.getTag(TAGS.alphabet), testData.alphabet);
89
89
  expectArray(resSeqCol.toList(), tgtSeqCol.toList());
@@ -105,8 +105,8 @@ PEPTIDE1{[Cys_SEt].T.*.*}$$$$`,
105
105
  const tgtDf = DG.DataFrame.fromCsv(testData.tgtCsv);
106
106
  const tgtSeqCol = tgtDf.getCol('seq');
107
107
 
108
- expect(srcSeqCol.getTag(DG.TAGS.UNITS), testData.units);
109
- expect(resSeqCol.getTag(DG.TAGS.UNITS), testData.units);
108
+ expect(srcSeqCol.meta.units, testData.units);
109
+ expect(resSeqCol.meta.units, testData.units);
110
110
  expect(srcSeqCol.getTag(TAGS.alphabet), testData.alphabet);
111
111
  expect(resSeqCol.getTag(TAGS.alphabet), testData.alphabet);
112
112
  expectArray(resSeqCol.toList(), tgtSeqCol.toList());
@@ -21,7 +21,7 @@ category('sequenceSpace', async () => {
21
21
  await _testSequenceSpaceReturnsResult(testFastaDf, DimReductionMethods.UMAP, 'sequence');
22
22
  //grok.shell.closeTable(testFastaDf);
23
23
  //testFastaTableView.close();
24
- });
24
+ }, {benchmark: true});
25
25
 
26
26
  test('sequenceSpaceWithEmptyRows', async () => {
27
27
  testHelmWithEmptyRows = await readDataframe('tests/100_3_clustests_empty_vals.csv');
@@ -5,15 +5,16 @@ import * as DG from 'datagrok-api/dg';
5
5
  import $ from 'cash-dom';
6
6
  import wu from 'wu';
7
7
 
8
-
9
8
  import {after, before, category, test, expect, delay, testEvent, awaitCheck} from '@datagrok-libraries/utils/src/test';
10
9
  import {getMonomerLibHelper, IMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
11
10
  import {
12
11
  getUserLibSettings, setUserLibSettings, setUserLibSettingsForTests
13
12
  } from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
14
13
  import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
14
+ import {getHelmHelper, IHelmHelper} from '@datagrok-libraries/bio/src/helm/helm-helper';
15
15
 
16
16
  import {awaitGrid, readDataframe} from './utils';
17
+
17
18
  import {
18
19
  BioSubstructureFilter, FastaBioFilter, SeparatorBioFilter, SeparatorFilterProps
19
20
  } from '../widgets/bio-substructure-filter';
@@ -24,11 +25,13 @@ import {_package} from '../package-test';
24
25
 
25
26
 
26
27
  category('bio-substructure-filters', async () => {
28
+ let helmHelper: IHelmHelper;
27
29
  let monomerLibHelper: IMonomerLibHelper;
28
30
  /** Backup actual user's monomer libraries settings */
29
31
  let userLibSettings: UserLibSettings;
30
32
 
31
33
  before(async () => {
34
+ helmHelper = await getHelmHelper(); // init Helm package
32
35
  monomerLibHelper = await getMonomerLibHelper();
33
36
  userLibSettings = await getUserLibSettings();
34
37
 
@@ -205,7 +205,7 @@ PEPTIDE1{Lys_Boc.hHis.Aca.Cys_SEt.T.dK.Thr_PO3H2.Aca.Tyr_PO3H2.Thr_PO3H2.Aca.Tyr
205
205
  const srcDf = DG.DataFrame.fromCsv(srcCsv);
206
206
  const seqCol = srcDf.getCol('seq');
207
207
  seqCol.semType = DG.SEMTYPE.MACROMOLECULE;
208
- seqCol.setTag(DG.TAGS.UNITS, NOTATION.FASTA);
208
+ seqCol.meta.units = NOTATION.FASTA;
209
209
  seqCol.setTag(bioTAGS.alphabet, ALPHABET.PT);
210
210
  const sh = SeqHandler.forColumn(seqCol);
211
211
  const resCol = (await _testToAtomicLevel(srcDf, 'seq', monomerLibHelper))!;
@@ -2,33 +2,25 @@ 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
- export enum MonomerWidthMode {
6
- long = 'long',
7
- short = 'short',
8
- }
9
-
10
- export const enum Tags {
11
- RendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
12
- }
13
-
14
5
  export const rendererSettingsChangedState = {
15
6
  true: '1',
16
7
  false: '0',
17
8
  };
18
9
 
19
10
  export const enum Temps {
20
- monomerWidth = '.mm.cellRenderer.monomerWidth',
11
+ maxMonomerLength = '.mm.cellRenderer.maxMonomerLength',
21
12
  colorCode = '.mm.cellRenderer.colorCode',
22
13
  compareWithCurrent = '.mm.cellRenderer.compareWithCurrent',
23
14
  highlightDifference = '.mm.cellRenderer.highlightDifference',
24
15
  gapLength = '.mm.cellRenderer.gapLength',
25
16
  monomerPlacer = '.mm.cellRenderer.monomerPlacer',
17
+
18
+ rendererSettingsChanged = '.mm.cellRenderer.settingsChanged',
26
19
  }
27
20
 
28
21
  export const enum tempTAGS {
29
22
  referenceSequence = 'reference-sequence',
30
23
  currentWord = 'current-word',
31
- monomerWidthMode = 'monomer-width-mode',
32
24
  }
33
25
 
34
26
  // export const MacromoleculeCellRendererDefaults = new class {
@@ -25,8 +25,8 @@ import {alphabetPolymerTypes, IMonomerLib} from '@datagrok-libraries/bio/src/typ
25
25
  import {getGridCellRendererBack} from '@datagrok-libraries/bio/src/utils/cell-renderer-back-base';
26
26
 
27
27
  import {
28
- Temps as mmcrTemps, Tags as mmcrTags,
29
- tempTAGS, rendererSettingsChangedState, MonomerWidthMode
28
+ Temps as mmcrTemps,
29
+ tempTAGS, rendererSettingsChangedState, Temps
30
30
  } from '../utils/cell-renderer-consts';
31
31
  import * as C from './constants';
32
32
 
@@ -152,18 +152,16 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
152
152
 
153
153
  let gapLength = 0;
154
154
  const msaGapLength = 8;
155
- let maxLengthOfMonomer = 50; // in case of long monomer representation, do not limit max length
156
155
 
157
156
  // Cell renderer settings
158
- const tempMonomerWidth: string | null = tableColTemp[tempTAGS.monomerWidthMode];
159
- const monomerWidth: string = (tempMonomerWidth != null) ? tempMonomerWidth :
160
- (_package.properties?.MonomerWidthMode ?? MonomerWidthMode.short);
161
- if (monomerWidth === 'short') {
162
- // Renderer can start to work before Bio package initialized, in that time _package.properties is null.
163
- // TODO: Render function is available but package init method is not completed
164
- const tagMaxMonomerLength: number = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
165
- maxLengthOfMonomer =
166
- (!isNaN(tagMaxMonomerLength) ? tagMaxMonomerLength : _package.properties?.MaxMonomerLength) ?? 4;
157
+ let maxLengthOfMonomer: number = (_package.properties ? _package.properties.maxMonomerLength : 4) ?? 50;
158
+ if (mmcrTAGS.maxMonomerLength in tableCol.tags) {
159
+ const v = parseInt(tableCol.getTag(mmcrTAGS.maxMonomerLength));
160
+ maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
161
+ }
162
+ if (Temps.maxMonomerLength in tableColTemp) {
163
+ const v = tableColTemp[Temps.maxMonomerLength];
164
+ maxLengthOfMonomer = !isNaN(v) && v ? v : 50;
167
165
  }
168
166
 
169
167
  const [_gc, _tc, temp] =
@@ -184,7 +182,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
184
182
  g.save();
185
183
  try {
186
184
  if (
187
- tableCol.tags[mmcrTags.RendererSettingsChanged] === rendererSettingsChangedState.true ||
185
+ tableCol.temp[Temps.rendererSettingsChanged] === rendererSettingsChangedState.true ||
188
186
  seqColTemp.monomerLengthLimit != maxLengthOfMonomer
189
187
  ) {
190
188
  gapLength = tableColTemp[mmcrTemps.gapLength] as number ?? gapLength;
@@ -192,7 +190,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
192
190
  // particularly monomer representation and max width.
193
191
  seqColTemp.setMonomerLengthLimit(maxLengthOfMonomer);
194
192
  seqColTemp.setSeparatorWidth(seqColTemp.isMsa() ? msaGapLength : gapLength);
195
- tableCol.setTag(mmcrTags.RendererSettingsChanged, rendererSettingsChangedState.false);
193
+ tableCol.temp[Temps.rendererSettingsChanged] = rendererSettingsChangedState.false;
196
194
  }
197
195
 
198
196
  const [maxLengthWords, maxLengthWordsSum]: [number[], number[]] =
@@ -211,7 +209,7 @@ export class MacromoleculeSequenceCellRenderer extends DG.GridCellRenderer {
211
209
  g.textBaseline = 'top';
212
210
 
213
211
  //TODO: can this be replaced/merged with splitSequence?
214
- const units = tableCol.getTag(DG.TAGS.UNITS);
212
+ const units = tableCol.meta.units;
215
213
  const aligned: string = tableCol.getTag(bioTAGS.aligned);
216
214
 
217
215
  const palette = getPaletteByType(paletteType);
@@ -300,7 +298,7 @@ export class MacromoleculeDifferenceCellRenderer extends DG.GridCellRenderer {
300
298
  const tableCol = gridCell.tableColumn as DG.Column<string>;
301
299
  const s: string = cell.value ?? '';
302
300
  const separator = tableCol.tags[bioTAGS.separator];
303
- const units: string = tableCol.tags[DG.TAGS.UNITS];
301
+ const units: string = tableCol.meta.units!;
304
302
  w = getUpdatedWidth(grid, g, x, w, dpr);
305
303
  //TODO: can this be replaced/merged with splitSequence?
306
304
  const [s1, s2] = s.split('#');
@@ -347,7 +345,7 @@ export function drawMoleculeDifferenceOnCanvas(
347
345
  g.textBaseline = 'top';
348
346
 
349
347
  let palette: SeqPalette = UnknownSeqPalettes.Color;
350
- if (units != 'HELM')
348
+ if (units !== 'HELM')
351
349
  palette = getPaletteByType(units.substring(units.length - 2));
352
350
 
353
351
  const vShift = 7;
@@ -17,7 +17,7 @@ export function addCopyMenuUI(cell: DG.Cell, menu: DG.Menu): void {
17
17
  const srcCol = cell.column;
18
18
  const srcRowIdx = cell.rowIndex;
19
19
  const srcSh = SeqHandler.forColumn(srcCol);
20
- const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.DefaultSeparator : undefined;
20
+ const separator = tgtNotation === NOTATION.SEPARATOR ? _package.properties.defaultSeparator : undefined;
21
21
  const joiner = srcSh.getJoiner({notation: tgtNotation as NOTATION, separator});
22
22
  const srcSS = srcSh.getSplitted(srcRowIdx);
23
23
  const tgtSeq = joiner(srcSS);
@@ -52,7 +52,8 @@ export function convert(col?: DG.Column): void {
52
52
  separatorInput.value = '/'; // helm monomers can have - in the name like D-aThr;
53
53
  dialogHeader.textContent = 'Current notation: ' + currentNotation;
54
54
  filteredNotations = notations.filter((e) => e !== currentNotation);
55
- targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations, toggleSeparator);
55
+ targetNotationInput = ui.input.choice('Convert to', {value: filteredNotations[0], items: filteredNotations,
56
+ onValueChanged: toggleSeparator});
56
57
  toggleSeparator();
57
58
  convertDialog?.clear();
58
59
  convertDialog?.add(ui.div([
@@ -63,12 +64,13 @@ export function convert(col?: DG.Column): void {
63
64
  ]));
64
65
  };
65
66
 
66
- const targetColumnInput = ui.columnInput('Column', grok.shell.t, srcCol, toggleColumn);
67
+ const targetColumnInput = ui.input.column('Column', {table: grok.shell.t, value: srcCol,
68
+ onValueChanged: (input) => toggleColumn(input.value)});
67
69
 
68
70
  const separatorArray = ['-', '.', '/'];
69
71
  let filteredNotations = notations.filter((e) => e !== currentNotation);
70
72
 
71
- const separatorInput = ui.choiceInput('Separator', separatorArray[0], separatorArray);
73
+ const separatorInput = ui.input.choice('Separator', {value: separatorArray[0], items: separatorArray});
72
74
 
73
75
  // hide the separator input for non-SEPARATOR target notations
74
76
  const toggleSeparator = () => {
@@ -77,7 +79,8 @@ export function convert(col?: DG.Column): void {
77
79
  else
78
80
  $(separatorInput.root).show();
79
81
  };
80
- let targetNotationInput = ui.choiceInput('Convert to', filteredNotations[0], filteredNotations, toggleSeparator);
82
+ let targetNotationInput = ui.input.choice('Convert to', {value: filteredNotations[0], items: filteredNotations,
83
+ onValueChanged: toggleSeparator});
81
84
 
82
85
  // set correct visibility on init
83
86
  toggleSeparator();
@@ -37,25 +37,20 @@ export class GetRegionFuncEditor {
37
37
  ) {
38
38
  const getDesc = (paramName: string) => this.call.inputParams[paramName].property.description;
39
39
 
40
- this.inputs.table = ui.tableInput('Table',
41
- this.call.inputParams['table'].value ?? grok.shell.tv.dataFrame, undefined,
42
- () => {});
40
+ this.inputs.table = ui.input.table('Table', {value: this.call.inputParams['table'].value ?? grok.shell.tv.dataFrame});
43
41
 
44
42
  const seqColValue = this.call.inputParams['sequence'].value ??
45
43
  this.inputs.table.value!.columns.bySemType(DG.SEMTYPE.MACROMOLECULE);
46
- const seqColOptions = {filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE};
47
- this.inputs.sequence = ui.columnInput('Sequence', grok.shell.tv.dataFrame, seqColValue,
48
- this.sequenceInputChanged.bind(this), seqColOptions);
49
- this.inputs.start = ui.choiceInput(
50
- 'Start', undefined, [], this.startInputChanged.bind(this)) as unknown as DG.InputBase<string>;
51
- this.inputs.end = ui.choiceInput(
52
- 'End', undefined, [], this.endInputChanged.bind(this)) as unknown as DG.InputBase<string>;
53
-
54
- this.inputs.region = ui.choiceInput<SeqRegion>('Region', null as unknown as SeqRegion, [],
55
- this.regionInputChanged.bind(this)) as DG.InputBase<SeqRegion>;
56
-
57
- this.inputs.name = ui.stringInput('Column name', this.getDefaultName(),
58
- this.nameInputChanged.bind(this), {clearIcon: true});
44
+ this.inputs.sequence = ui.input.column('Sequence', {table: grok.shell.tv.dataFrame, value: seqColValue,
45
+ onValueChanged: this.sequenceInputChanged.bind(this), filter: (col: DG.Column) => col.semType === DG.SEMTYPE.MACROMOLECULE});
46
+ this.inputs.start = ui.input.choice('Start', {onValueChanged: this.startInputChanged.bind(this)}) as unknown as DG.InputBase<string>;
47
+ this.inputs.end = ui.input.choice('End', {onValueChanged: this.endInputChanged.bind(this)}) as unknown as DG.InputBase<string>;
48
+
49
+ this.inputs.region = ui.input.choice<SeqRegion>('Region', {value: null as unknown as SeqRegion, items: [],
50
+ onValueChanged: this.regionInputChanged.bind(this)}) as DG.InputBase<SeqRegion>;
51
+
52
+ this.inputs.name = ui.input.string('Column name', {value: this.getDefaultName(),
53
+ onValueChanged: this.nameInputChanged.bind(this), clearIcon: true});
59
54
  this.inputs.name.onInput(this.nameInputInput.bind(this)); // To catch clear event
60
55
 
61
56
  // tooltips
@@ -8,11 +8,11 @@ import {TaskBarProgressIndicator} from 'datagrok-api/dg';
8
8
  export function getRegionUI(col: DG.Column<string>): void {
9
9
  const sh = SeqHandler.forColumn(col);
10
10
 
11
- const nameInput = ui.stringInput('Name', '');
12
- const startPositionInput = ui.choiceInput('Start Position', sh.posList[0], sh.posList,
13
- () => { /* TODO: update name placeholder with getDefaultName() */ });
14
- const endPositionInput = ui.choiceInput('End Position', sh.posList[sh.posList.length], sh.posList,
15
- () => { /* TODO: update name placeholder with getDefaultName() */ });
11
+ const nameInput = ui.input.string('Name', {value: ''});
12
+ const startPositionInput = ui.input.choice('Start Position', {value: sh.posList[0], items: sh.posList,
13
+ onValueChanged: () => { /* TODO: update name placeholder with getDefaultName() */ }});
14
+ const endPositionInput = ui.input.choice('End Position', {value: sh.posList[sh.posList.length], items: sh.posList,
15
+ onValueChanged: () => { /* TODO: update name placeholder with getDefaultName() */ }});
16
16
 
17
17
  const getDefaultName = (): string => {
18
18
  return `${col.name}:${startPositionInput.value}-${endPositionInput.value}`;
@@ -25,7 +25,7 @@ export class MacromoleculeColumnWidget extends DG.Widget {
25
25
 
26
26
  async init(): Promise<void> {
27
27
  const sh = SeqHandler.forColumn(this.seqCol);
28
- const pkgTooltipWebLogo = _package.properties.TooltipWebLogo;
28
+ const pkgTooltipWebLogo = _package.properties.tooltipWebLogo;
29
29
  const colTooltipWebLogo = this.seqCol.getTag(wlTAGS.tooltipWebLogo);
30
30
 
31
31
  if (pkgTooltipWebLogo !== false && !['false', 'off', 'disable', 'disabled'].includes(colTooltipWebLogo)) {
@@ -4,6 +4,7 @@ import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
6
  import {delay} from '@datagrok-libraries/utils/src/test';
7
+ import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
7
8
  import {IMonomerLib} from '@datagrok-libraries/bio/src/types';
8
9
  import {
9
10
  getUserLibSettings, setUserLibSettings, LIB_PATH
@@ -49,7 +50,9 @@ export class MonomerLibManager implements IMonomerLibHelper {
49
50
  }
50
51
 
51
52
  /** Protect constructor to prevent multiple instantiation. */
52
- protected constructor() {}
53
+ protected constructor(
54
+ private readonly logger: ILogger,
55
+ ) {}
53
56
 
54
57
  /** Singleton monomer library
55
58
  * @return {MonomerLibManager} MonomerLibHelper instance
@@ -64,7 +67,8 @@ export class MonomerLibManager implements IMonomerLibHelper {
64
67
  async getFileManager(): Promise<MonomerLibFileManager> {
65
68
  if (this._fileManagerPromise === undefined) {
66
69
  this._fileManagerPromise = (async () => {
67
- const fileManager: MonomerLibFileManager = await MonomerLibFileManager.create(this, this._eventManager);
70
+ const fileManager: MonomerLibFileManager =
71
+ await MonomerLibFileManager.create(this, this._eventManager, this.logger);
68
72
  return fileManager;
69
73
  })();
70
74
  }
@@ -82,6 +86,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
82
86
  // WARNING: This function is not allowed to throw any exception,
83
87
  // because it will prevent further handling monomer library settings
84
88
  // through blocking this.loadLibrariesPromise
89
+ const pi = DG.TaskBarProgressIndicator.create('Loading monomers ...');
85
90
  try {
86
91
  const [libFileNameList, settings]: [string[], UserLibSettings] = await Promise.all([
87
92
  (await this.getFileManager()).getValidLibraryPaths(),
@@ -95,14 +100,19 @@ export class MonomerLibManager implements IMonomerLibHelper {
95
100
  return isFileIncluded && isExplicit;
96
101
  });
97
102
 
103
+ let completedLibCount: number = 0;
98
104
  const libs: IMonomerLib[] = await Promise.all(filteredLibFnList
99
105
  .map((libFileName) => {
100
106
  //TODO handle whether files are in place
101
- return this.readLibrary(LIB_PATH, libFileName).catch((err: any) => {
102
- const errMsg: string = `Loading monomers from '${libFileName}' error: ` +
103
- `${err instanceof Error ? err.message : err.toString()}`;
104
- return new MonomerLib({}, libFileName, errMsg);
105
- });
107
+ return this.readLibrary(LIB_PATH, libFileName)
108
+ .catch((err: any) => {
109
+ const errMsg: string = `Loading monomers from '${libFileName}' error: ` +
110
+ `${err instanceof Error ? err.message : err.toString()}`;
111
+ return new MonomerLib({}, libFileName, errMsg);
112
+ }).finally(() => {
113
+ pi.update(Math.round(100 * (++completedLibCount) / filteredLibFnList.length),
114
+ `Loading monomer libs ${completedLibCount}/${filteredLibFnList.length}`);
115
+ });
106
116
  }));
107
117
  this._monomerLib.updateLibs(libs, reload);
108
118
  } catch (err: any) {
@@ -112,6 +122,8 @@ export class MonomerLibManager implements IMonomerLibHelper {
112
122
 
113
123
  const errStack = err instanceof Error ? err.stack : undefined;
114
124
  _package.logger.error(errMsg, undefined, errStack);
125
+ } finally {
126
+ pi.close();
115
127
  }
116
128
  });
117
129
  }
@@ -149,7 +161,7 @@ export class MonomerLibManager implements IMonomerLibHelper {
149
161
  let res = window.$monomerLibHelperPromise;
150
162
  if (res === undefined) {
151
163
  res = window.$monomerLibHelperPromise = (async () => {
152
- const instance = new MonomerLibManager();
164
+ const instance = new MonomerLibManager(_package.logger);
153
165
  instance._eventManager = MonomerLibFileEventManager.getInstance();
154
166
  return instance;
155
167
  })();
@@ -6,6 +6,7 @@ import * as DG from 'datagrok-api/dg';
6
6
  import {JSONSchemaType} from 'ajv';
7
7
 
8
8
  import {IMonomerLib, Monomer} from '@datagrok-libraries/bio/src/types';
9
+ import {ILogger} from '@datagrok-libraries/bio/src/utils/logger';
9
10
  import {LIB_PATH} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
10
11
  import {
11
12
  HELM_REQUIRED_FIELD as REQ,
@@ -31,6 +32,7 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
31
32
  private readonly fileValidator: MonomerLibFileValidator,
32
33
  private readonly libHelper: IMonomerLibHelper,
33
34
  public readonly eventManager: MonomerLibFileEventManager,
35
+ private readonly logger: ILogger,
34
36
  ) {
35
37
  this.eventManager.updateValidLibraryFileListRequested$.subscribe(async () => {
36
38
  await this.updateValidLibraryList();
@@ -46,19 +48,20 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
46
48
 
47
49
  /** For internal use only, get {@link IMonomerLibHelper.getFileManager} */
48
50
  public static async create(
49
- libHelper: IMonomerLibHelper, eventManager: MonomerLibFileEventManager
51
+ libHelper: IMonomerLibHelper, eventManager: MonomerLibFileEventManager, logger: ILogger,
50
52
  ): Promise<MonomerLibFileManager> {
51
53
  const helmSchemaRaw = await grok.dapi.files.readAsText(HELM_JSON_SCHEMA_PATH);
52
54
  const helmSchema = JSON.parse(helmSchemaRaw) as JSONSchemaType<any>;
53
55
 
54
56
  const fileValidator = new MonomerLibFileValidator(helmSchema);
55
- return new MonomerLibFileManager(fileValidator, libHelper, eventManager);
57
+ return new MonomerLibFileManager(fileValidator, libHelper, eventManager, logger);
56
58
  }
57
59
 
58
60
  /** Add standard .json monomer library */
59
61
  async addLibraryFile(fileContent: string, fileName: string): Promise<void> {
60
62
  try {
61
- if (await this.libraryFileExists(fileName)) {
63
+ const alreadyFileExists = await grok.dapi.files.exists(LIB_PATH + `${fileName}`);
64
+ if (alreadyFileExists) {
62
65
  grok.shell.error(`File ${fileName} already exists`);
63
66
  return;
64
67
  }
@@ -122,21 +125,17 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
122
125
  return await this.eventManager.getValidLibraryPathsAsynchronously();
123
126
  }
124
127
 
125
- private async libraryFileExists(fileName: string): Promise<boolean> {
126
- return await grok.dapi.files.exists(LIB_PATH + `${fileName}`);
127
- }
128
-
129
128
  private async updateValidLibraryList(): Promise<void> {
130
129
  const logPrefix: string = `${this.toLog()}.updateValidLibraryList()`;
131
- _package.logger.debug(`${logPrefix}, start`);
132
- return this.filesPromise = this.filesPromise.then(async () => {
133
- _package.logger.debug(`${logPrefix}, IN`);
130
+ this.logger.debug(`${logPrefix}, start`);
131
+ this.filesPromise = this.filesPromise.then(async () => {
132
+ this.logger.debug(`${logPrefix}, IN`);
134
133
  const invalidFiles = [] as string[];
135
134
  // console.log(`files before validation:`, this.libraryEventManager.getValidFilesPathList());
136
135
  const filePaths = await this.getFilePathsAtDefaultLocation();
137
136
 
138
137
  if (!this.fileListHasChanged(filePaths)) {
139
- _package.logger.debug(`${logPrefix}, end, not changed`);
138
+ this.logger.debug(`${logPrefix}, end, not changed`);
140
139
  return;
141
140
  }
142
141
 
@@ -160,18 +159,19 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
160
159
  // console.log(`files after validation:`, this.libraryEventManager.getValidFilesPathList());
161
160
 
162
161
  if (validLibraryPaths.some((el) => !el.endsWith('.json')))
163
- _package.logger.warning(`Wrong validation: ${validLibraryPaths}`);
162
+ this.logger.warning(`Wrong validation: ${validLibraryPaths}`);
164
163
 
165
164
  if (invalidFiles.length > 0) {
166
165
  const message = `Invalid monomer library files in ${LIB_PATH}` +
167
166
  `, consider fixing or removing them: ${invalidFiles.join(', ')}`;
168
167
 
169
- _package.logger.warning(message);
168
+ this.logger.warning(message);
170
169
  // grok.shell.warning(message);
171
170
  }
172
- _package.logger.debug(`${logPrefix}, OUT`);
171
+ this.logger.debug(`${logPrefix}, OUT`);
173
172
  });
174
- _package.logger.debug(`${logPrefix}, end`);
173
+ this.logger.debug(`${logPrefix}, end`);
174
+ return this.filesPromise;
175
175
  }
176
176
 
177
177
  private fileListHasChanged(newList: string[]): boolean {
@@ -191,21 +191,25 @@ export class MonomerLibFileManager implements IMonomerLibFileManager {
191
191
 
192
192
  /** Get relative paths for files in LIB_PATH */
193
193
  private async getFilePathsAtDefaultLocation(): Promise<string[]> {
194
+ const logPrefix = `${this.toLog()}.getFilePathsAtDefaultLocation()`;
195
+ this.logger.debug(`${logPrefix}, start`);
194
196
  const list = await grok.dapi.files.list(LIB_PATH);
195
197
  const paths = list.map((fileInfo) => {
196
198
  return fileInfo.fullPath;
197
199
  });
198
200
 
199
- // console.log(`retreived paths:`, paths);
200
-
201
- // WARNING: an extra sanity check,
202
- // caused by unexpected behavior of grok.dapi.files.list() when it returns non-existent paths
201
+ const checkForUi = false;
203
202
  const existingPaths = [] as string[];
204
- for (const path of paths) {
205
- const exists = await grok.dapi.files.exists(path);
206
- if (exists)
207
- existingPaths.push(path);
208
- }
203
+ if (checkForUi) {
204
+ // WARNING: an extra sanity check,
205
+ // caused by unexpected behavior of grok.dapi.files.list() when it returns non-existent paths
206
+ for (const path of paths) {
207
+ const exists = await grok.dapi.files.exists(path);
208
+ if (exists)
209
+ existingPaths.push(path);
210
+ }
211
+ } else
212
+ existingPaths.push(...paths);
209
213
 
210
214
  return existingPaths.map((path) => {
211
215
  // Get relative path (to LIB_PATH)