@datagrok/sequence-translator 1.10.11 → 1.10.13

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.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/sequence-translator",
3
3
  "friendlyName": "Sequence Translator",
4
- "version": "1.10.11",
4
+ "version": "1.10.13",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -22,7 +22,7 @@
22
22
  }
23
23
  ],
24
24
  "dependencies": {
25
- "@datagrok-libraries/bio": "^5.62.1",
25
+ "@datagrok-libraries/bio": "^5.63.6",
26
26
  "@datagrok-libraries/chem-meta": "^1.2.8",
27
27
  "@datagrok-libraries/tutorials": "^1.6.1",
28
28
  "@datagrok-libraries/utils": "^4.6.5",
@@ -42,9 +42,9 @@
42
42
  "devDependencies": {
43
43
  "@datagrok-libraries/helm-web-editor": "^1.1.16",
44
44
  "@datagrok-libraries/js-draw-lite": "^0.0.10",
45
- "@datagrok/bio": "^2.24.0",
46
- "@datagrok/chem": "^1.13.0",
47
- "@datagrok/helm": "^2.7.0",
45
+ "@datagrok/bio": "^2.26.0",
46
+ "@datagrok/chem": "^1.17.0",
47
+ "@datagrok/helm": "^2.13.0",
48
48
  "@types/jquery": "^3.5.32",
49
49
  "@types/js-yaml": "^4.0.5",
50
50
  "@types/lodash": "^4.14.202",
@@ -1,6 +1,8 @@
1
1
  .st-colored-text-input > textarea {
2
2
  width: 100%;
3
- -webkit-text-fill-color: transparent;
3
+ color: transparent !important;
4
+ caret-color: var(--grey-6);
5
+ -webkit-text-fill-color: transparent !important;
4
6
  background-color: transparent;
5
7
  position: relative;
6
8
  z-index: 1;
@@ -2,11 +2,22 @@
2
2
 
3
3
  .st-structure-body {
4
4
  padding-right: 20px;
5
+ height: 100%;
6
+ display: flex;
7
+ flex-direction: column;
5
8
  }
6
9
 
7
10
  .st-structure-mol-img {
8
- margin-right: 30px;
9
- float: right;
11
+ flex: 1 1 0;
12
+ min-height: 100px;
13
+ min-width: 0;
14
+ transform: translateX(-50px);
15
+ overflow: hidden;
16
+ }
17
+
18
+ .st-structure-mol-img canvas {
19
+ max-width: 100% !important;
20
+ height: auto !important;
10
21
  }
11
22
 
12
23
  .st-structure-bool-button-block {
@@ -15,8 +26,9 @@
15
26
  }
16
27
 
17
28
  .st-structure-bottom {
18
- flex-direction: row-reverse;
29
+ flex: 1 1 0;
19
30
  padding-top: 20px;
31
+ min-height: 0;
20
32
  }
21
33
 
22
34
  .st-structure-clear-buttons {
@@ -52,7 +52,6 @@ class StructureAppLayout {
52
52
  );
53
53
  this.moleculeImgDiv = ui.block([]);
54
54
  $(this.moleculeImgDiv).addClass('st-structure-mol-img');
55
-
56
55
  DG.debounce<string>(this.onInput, 300).subscribe(async () => {
57
56
  await this.updateMoleculeImg();
58
57
  });
@@ -74,7 +73,7 @@ class StructureAppLayout {
74
73
  const tableLayout = this.getTableInput(th);
75
74
  const boolInputsAndButton = this.getBoolInputsAndButton();
76
75
  await this.updateMoleculeImg();
77
- const bottomDiv = ui.divH([boolInputsAndButton, this.moleculeImgDiv]);
76
+ const bottomDiv = ui.divH([this.moleculeImgDiv, boolInputsAndButton]);
78
77
  $(bottomDiv).addClass('st-structure-bottom');
79
78
 
80
79
  const layout = ui.divV([tableLayout, bottomDiv]);
@@ -186,13 +185,8 @@ class StructureAppLayout {
186
185
  const errStr = errorToConsole(err);
187
186
  console.error(errStr);
188
187
  }
189
- // todo: compute relative numbers
190
- const canvasWidth = 650;
191
- const canvasHeight = 150;
192
188
  const molImgObj = new MoleculeImage(molfile);
193
- await molImgObj.drawMolecule(this.moleculeImgDiv, canvasWidth, canvasHeight);
194
- // should the canvas be returned from the above function?
195
- $(this.moleculeImgDiv).find('canvas').css('float', 'inherit');
189
+ await molImgObj.drawMolecule(this.moleculeImgDiv, 650, 150);
196
190
  }
197
191
  }
198
192
 
@@ -56,8 +56,6 @@ class TranslatorAppLayout {
56
56
  }
57
57
  });
58
58
 
59
- $(this.formatChoiceInput.root.getElementsByTagName('select')[0]).css('width', '20%');
60
-
61
59
  this.sequenceInputBase = ui.input.textArea(
62
60
  '', {value: DEFAULT_AXOLABS_INPUT, onValueChanged: () => { this.onInput.next(); }}
63
61
  );
@@ -235,9 +233,13 @@ class TranslatorAppLayout {
235
233
  }
236
234
 
237
235
  private saveMolfile(): void {
238
- const result = (new SequenceToMolfileConverter(this.sequence, false,
239
- this.formatChoiceInput.value!)).convert() + '\n$$$$';
240
- download(this.sequence + '.sdf', encodeURIComponent(result));
236
+ try {
237
+ const result = (new SequenceToMolfileConverter(this.sequence, false,
238
+ this.formatChoiceInput.value!)).convert() + '\n$$$$';
239
+ download(this.sequence + '.sdf', encodeURIComponent(result));
240
+ } catch (e: any) {
241
+ grok.shell.warning('Unable to save SDF: ' + e.message);
242
+ }
241
243
  }
242
244
 
243
245
  private copySmiles(): void {
package/src/package.ts CHANGED
@@ -3,7 +3,7 @@ import * as grok from 'datagrok-api/grok';
3
3
  import * as ui from 'datagrok-api/ui';
4
4
  import * as DG from 'datagrok-api/dg';
5
5
 
6
- import {NOTATION, NOTATION_PROVIDER_CONSTRUCTOR_ROLE} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
6
+ import {BioTags, NOTATION, NOTATION_PROVIDER_CONSTRUCTOR_ROLE} from '@datagrok-libraries/bio/src/utils/macromolecule/consts';
7
7
  import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
8
8
 
9
9
  import {OligoToolkitPackage} from './apps/common/model/oligo-toolkit-package';
@@ -397,6 +397,8 @@ export class PackageFunctions {
397
397
  col.setTag('alphabet', 'UN');
398
398
  col.setTag('.alphabetIsMultichar', 'true');
399
399
  col.meta.units = NOTATION.CUSTOM;
400
+ if (separator && !col.tags[BioTags.separator])
401
+ col.tags[BioTags.separator] = separator;
400
402
  col.tags[PolyToolTags.dataRole] = 'template';
401
403
  col.temp[SeqTemps.notationProvider] = new CyclizedNotationProvider(separator, _package.helmHelper);
402
404
  }
@@ -36,9 +36,9 @@ export const PT_UI_LINEARIZE = 'Linearize';
36
36
  export const PT_UI_LINEARIZE_TT = 'Make representation linear if possible';
37
37
  export const PT_UI_USE_CHIRALITY = 'Chirality engine';
38
38
  export const PT_UI_HIGHLIGHT_MONOMERS = 'Highlight monomers';
39
- export const PT_UI_DIALOG_CONVERSION = 'Poly Tool Conversion';
40
- export const PT_UI_DIALOG_UNRULE = 'Poly Tool Unrule';
41
- export const PT_UI_DIALOG_ENUMERATION = 'Poly Tool Enumeration';
39
+ export const PT_UI_DIALOG_CONVERSION = 'PolyTool Conversion';
40
+ export const PT_UI_DIALOG_UNRULE = 'PolyTool Unrule';
41
+ export const PT_UI_DIALOG_ENUMERATION = 'PolyTool Enumeration';
42
42
  export const PT_UI_RULES_USED = 'Rules used';
43
43
 
44
44
  export const PT_ENUM_TYPE_TOOLTIPS: Record<string, string> = {
@@ -208,7 +208,14 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
208
208
  molInput.setMolFile(molfileValue);
209
209
 
210
210
  //const helmInput = helmHelper.createHelmInput('Macromolecule', {value: helmValue});
211
- const screenLibraryInput = ui.input.choice('Library to use', {value: null, items: libList});
211
+ const screenLibraryInput = ui.input.choice('Library to use', {
212
+ value: libList.length ? libList[0] : null,
213
+ items: libList,
214
+ nullable: false,
215
+ onValueChanged: () => {
216
+ dialog.getButton('OK').disabled = screenLibraryInput.value === null;
217
+ }
218
+ });
212
219
 
213
220
  molInput.root.setAttribute('style', `min-width:250px!important;`);
214
221
  molInput.root.setAttribute('style', `max-width:250px!important;`);
@@ -268,6 +275,7 @@ async function getPolyToolEnumerationChemDialog(cell?: DG.Cell): Promise<DG.Dial
268
275
  molInput.setMolFile(x.mol);
269
276
  screenLibraryInput.value = x.screenLibrary;
270
277
  });
278
+ dialog.getButton('OK').disabled = screenLibraryInput.value === null;
271
279
  return dialog;
272
280
  } catch (err: any) {
273
281
  destroy();
@@ -16,7 +16,6 @@ import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/m
16
16
  import {getSeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
17
17
  import '@datagrok-libraries/bio/src/types/input';
18
18
  import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
19
- import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
20
19
  import {SeqValueBase} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
21
20
  import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
22
21
  import {SeqTemps} from '@datagrok-libraries/bio/src/utils/macromolecule/seq-handler';
@@ -60,7 +59,8 @@ type PolyToolEnumerateInputs = {
60
59
  placeholders: PolyToolPlaceholdersInput;
61
60
  placeholdersBreadth: PolyToolPlaceholdersBreadthInput;
62
61
  enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
63
- trivialNameCol: InputColumnBase,
62
+ trivialName: DG.InputBase<string>,
63
+ appendToTable: DG.InputBase<DG.DataFrame | null>,
64
64
  keepOriginal: DG.InputBase<boolean>;
65
65
  toAtomicLevel: DG.InputBase<boolean>;
66
66
  generateHelm: DG.InputBase<boolean>;
@@ -75,7 +75,7 @@ type PolyToolEnumerateHelmSerialized = {
75
75
  placeholders: string;
76
76
  placeholdersBreadth: string;
77
77
  enumeratorType: PolyToolEnumeratorType;
78
- trivialNameCol: string;
78
+ trivialName: string;
79
79
  keepOriginal: boolean;
80
80
  toAtomicLevel: boolean;
81
81
  generateHelm: boolean;
@@ -170,7 +170,6 @@ async function getPolyToolEnumerateDialog(
170
170
  const libHelper = await getMonomerLibHelper();
171
171
  const monomerLib = libHelper.getMonomerLib();
172
172
  const seqHelper = await getSeqHelper();
173
- const emptyDf: DG.DataFrame = DG.DataFrame.fromColumns([]);
174
173
 
175
174
  const helmHelper = await getHelmHelper();
176
175
  const monomerLibFuncs = helmHelper.buildMonomersFuncsFromLib(monomerLib);
@@ -216,7 +215,6 @@ async function getPolyToolEnumerateDialog(
216
215
  let srcId: { value: string, colName: string } | null = null;
217
216
  let ruleFileList: string[];
218
217
  let ruleInputs: RuleInputs;
219
- const trivialNameSampleDiv = ui.divText('', {style: {marginLeft: '8px', marginTop: '2px'}});
220
218
  const warningsTextDiv = ui.divText('', {style: {color: 'red'}});
221
219
  const resultCountDiv = ui.divText('', {style: {
222
220
  fontSize: '11px', color: 'var(--grey-4)', marginTop: '2px', marginLeft: '4px', whiteSpace: 'nowrap',
@@ -291,22 +289,17 @@ async function getPolyToolEnumerateDialog(
291
289
  onValueChanged: (value: string[]) => { ruleFileList = value; }
292
290
  })).getForm()
293
291
  },
294
- trivialNameCol: ui.input.column2(
292
+ trivialName: ui.input.string(
295
293
  'Trivial name', {
296
- table: cell?.dataFrame,
297
- filter: (col: DG.Column): boolean => {
298
- return col.type === DG.COLUMN_TYPE.STRING && col != cell?.column; /* id */
299
- },
300
- onValueChanged: (): void => {
301
- const valueCol = inputs.trivialNameCol.value;
302
- let newSrcId: typeof srcId = null;
303
- if (cell && valueCol) {
304
- const originalId = valueCol.get(cell.rowIndex)!;
305
- newSrcId = {value: originalId, colName: valueCol.name};
306
- }
307
- srcId = newSrcId;
308
- trivialNameSampleDiv.textContent = srcId ? `Original ID: ${srcId.value}` : '';
294
+ value: '',
295
+ onValueChanged: (value: string): void => {
296
+ const trimmed = value?.trim();
297
+ srcId = trimmed ? {value: trimmed, colName: 'Trivial name'} : null;
309
298
  },
299
+ }),
300
+ appendToTable: ui.input.table(
301
+ 'Append to table', {
302
+ items: grok.shell.tables,
310
303
  nullable: true,
311
304
  }),
312
305
  };
@@ -319,7 +312,22 @@ async function getPolyToolEnumerateDialog(
319
312
  };
320
313
  updateEnumTypeTooltip();
321
314
 
322
- inputs.trivialNameCol.addOptions(trivialNameSampleDiv);
315
+ // Attach a "pick from column" icon button to the trivial name input
316
+ if (cell?.dataFrame) {
317
+ const colIcon = ui.iconFA('columns', (e: MouseEvent) => {
318
+ DG.Menu.popup()
319
+ .singleColumnSelector(cell.dataFrame, {
320
+ columnFilter: (col: DG.Column) => col.type === DG.COLUMN_TYPE.STRING && col !== cell.column,
321
+ onChange: (_grid, col: DG.Column, currentRowChanged: boolean) => {
322
+ if (currentRowChanged)
323
+ inputs.trivialName.value = col.get(cell.rowIndex) ?? '';
324
+ },
325
+ })
326
+ .show({x: e.clientX, y: e.clientY});
327
+ }, 'Pick trivial name from a column');
328
+ inputs.trivialName.addOptions(colIcon);
329
+ }
330
+ inputs.trivialName.root.style.maxWidth = '450px';
323
331
 
324
332
  // Wire up monomer cell double-click to open selection dialog
325
333
  inputs.placeholders.onMonomerCellEdit = async (position: number, currentMonomers: string[]) => {
@@ -634,14 +642,7 @@ async function getPolyToolEnumerateDialog(
634
642
  }
635
643
  };
636
644
 
637
- const fillTrivialNameList = (table?: DG.DataFrame) => {
638
- if (table) {
639
- inputs.trivialNameCol.setColumnInputTable(table);
640
- inputs.trivialNameCol.root.style.removeProperty('display');
641
- } else {
642
- inputs.trivialNameCol.setColumnInputTable(emptyDf);
643
- inputs.trivialNameCol.root.style.setProperty('display', 'none');
644
- }
645
+ const fillTrivialNameList = (_table?: DG.DataFrame) => {
645
646
  if (resizeInputs)
646
647
  resizeInputs();
647
648
  };
@@ -711,7 +712,13 @@ async function getPolyToolEnumerateDialog(
711
712
  rules: await ruleInputs.getActive()
712
713
  } : false,
713
714
  helmHelper);
714
- grok.shell.addTableView(enumeratorResDf);
715
+ const appendTarget = inputs.appendToTable.value;
716
+ if (appendTarget) {
717
+ appendTarget.append(enumeratorResDf, true);
718
+ appendTarget.meta.detectSemanticTypes();
719
+ } else {
720
+ grok.shell.addTableView(enumeratorResDf);
721
+ }
715
722
  }
716
723
  } catch (err: any) {
717
724
  defaultErrorHandler(err);
@@ -735,8 +742,9 @@ async function getPolyToolEnumerateDialog(
735
742
  {style: {width: '100%'}}))
736
743
  .add(ui.divH([
737
744
  ui.divV([
738
- inputs.trivialNameCol.root,
739
- inputs.keepOriginal.root],
745
+ inputs.trivialName.root,
746
+ inputs.keepOriginal.root,
747
+ inputs.appendToTable.root],
740
748
  {style: {width: '50%'}}),
741
749
  ui.divV([
742
750
  ui.divH([inputs.toAtomicLevel.root, inputs.generateHelm.root]),
@@ -767,7 +775,7 @@ async function getPolyToolEnumerateDialog(
767
775
  placeholders: inputs.placeholders.stringValue,
768
776
  enumeratorType: inputs.enumeratorType.value,
769
777
  placeholdersBreadth: inputs.placeholdersBreadth.stringValue,
770
- trivialNameCol: inputs.trivialNameCol.stringValue,
778
+ trivialName: inputs.trivialName.value,
771
779
  keepOriginal: inputs.keepOriginal.value,
772
780
  toAtomicLevel: inputs.toAtomicLevel.value,
773
781
  generateHelm: inputs.generateHelm.value,
@@ -781,7 +789,8 @@ async function getPolyToolEnumerateDialog(
781
789
  inputs.enumeratorType.value = x.enumeratorType ?? PolyToolEnumeratorTypes.Single;
782
790
  inputs.placeholders.stringValue = x.placeholders;
783
791
  inputs.placeholdersBreadth.stringValue = x.placeholdersBreadth;
784
- inputs.trivialNameCol.stringValue = x.trivialNameCol;
792
+ if (x.trivialName)
793
+ inputs.trivialName.value = x.trivialName;
785
794
  inputs.keepOriginal.value = x.keepOriginal ?? false;
786
795
  inputs.toAtomicLevel.value = x.toAtomicLevel ?? true;
787
796
  inputs.generateHelm.value = x.generateHelm ?? true;