@datagrok/sequence-translator 1.0.12 → 1.0.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.0.12",
4
+ "version": "1.0.13",
5
5
  "author": {
6
6
  "name": "Vadym Kovadlo",
7
7
  "email": "vkovadlo@datagrok.ai"
@@ -13,7 +13,7 @@
13
13
  "directory": "packages/SequenceTranslator"
14
14
  },
15
15
  "dependencies": {
16
- "@datagrok-libraries/utils": "^1.11.1",
16
+ "@datagrok-libraries/utils": "^1.15.5",
17
17
  "@types/react": "^18.0.15",
18
18
  "datagrok-api": "^1.7.2",
19
19
  "datagrok-tools": "^4.1.2",
@@ -43,27 +43,35 @@ it('TEST', async () => {
43
43
  return new Promise<object>((resolve, reject) => {
44
44
  (<any>window).grok.functions.eval(targetPackage + ':test()').then((df: any) => {
45
45
  const cStatus = df.columns.byName('success');
46
+ const cSkipped = df.columns.byName('skipped');
46
47
  const cMessage = df.columns.byName('result');
47
48
  const cCat = df.columns.byName('category');
48
49
  const cName = df.columns.byName('name');
49
50
  const cTime = df.columns.byName('ms');
50
51
  let failed = false;
52
+ let skipReport = '';
51
53
  let passReport = '';
52
54
  let failReport = '';
53
55
  for (let i = 0; i < df.rowCount; i++) {
54
56
  if (cStatus.get(i)) {
55
- passReport += `Test result : Success : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
57
+ if (cSkipped.get(i)) {
58
+ skipReport += `Test result : Skipped : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
59
+ } else {
60
+ passReport += `Test result : Success : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
61
+ }
56
62
  } else {
57
63
  failed = true;
58
64
  failReport += `Test result : Failed : ${cTime.get(i)} : ${targetPackage}.${cCat.get(i)}.${cName.get(i)} : ${cMessage.get(i)}\n`;
59
65
  }
60
66
  }
61
- resolve({failReport, passReport, failed});
67
+ resolve({failReport, skipReport, passReport, failed});
62
68
  }).catch((e: any) => reject(e));
63
69
  });
64
70
  }, targetPackage);
65
71
  // @ts-ignore
66
72
  console.log(r.passReport);
67
73
  // @ts-ignore
74
+ console.log(r.skipReport);
75
+ // @ts-ignore
68
76
  expect(r.failed).checkOutput(false, r.failReport);
69
- }, 3600000);
77
+ }, 7200000);
File without changes
File without changes
@@ -0,0 +1,37 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+ import {sortByStringLengthInDescendingOrder} from '../helpers';
3
+ import {MODIFICATIONS} from '../structures-works/map';
4
+
5
+ export function saltMass(
6
+ saltNames: string[], molWeightCol: DG.Column, equivalentsCol: DG.Column, i: number, saltCol: DG.Column,
7
+ ): number {
8
+ const saltRowIndex = saltNames.indexOf(saltCol.get(i));
9
+ return (
10
+ saltRowIndex == -1 || molWeightCol.get(saltRowIndex) == DG.FLOAT_NULL || equivalentsCol.get(i) == DG.INT_NULL
11
+ ) ?
12
+ DG.FLOAT_NULL :
13
+ molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
14
+ }
15
+
16
+ export function saltMolWeigth(saltNamesList: string[], saltCol: DG.Column, molWeightCol: DG.Column, i: number): number {
17
+ const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
18
+ return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex);
19
+ }
20
+
21
+ export function batchMolWeight(compoundMolWeightCol: DG.Column, saltMassCol: DG.Column, i: number): number {
22
+ return (compoundMolWeightCol.getString(i) == '' || saltMassCol.getString(i) == '') ?
23
+ DG.FLOAT_NULL :
24
+ compoundMolWeightCol.get(i) + saltMassCol.get(i);
25
+ }
26
+
27
+ export function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
28
+ const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
29
+ let weight = 0;
30
+ let i = 0;
31
+ while (i < sequence.length) {
32
+ const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
33
+ weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
34
+ i += matchedCode.length;
35
+ }
36
+ return weight - 61.97;
37
+ }
@@ -0,0 +1,37 @@
1
+ export const SEQUENCE_TYPES = {
2
+ SENSE_STRAND: 'SS',
3
+ ANTISENSE_STRAND: 'AS',
4
+ DUPLEX: 'Duplex',
5
+ TRIPLEX: 'Triplex',
6
+ DIMER: 'Dimer',
7
+ };
8
+
9
+ export const COL_NAMES = {
10
+ CHEMISTRY: 'Chemistry',
11
+ NUMBER: 'Number',
12
+ TYPE: 'Type',
13
+ CHEMISTRY_NAME: 'Chemistry Name',
14
+ INTERNAL_COMPOUND_ID: 'Internal compound ID',
15
+ IDP: 'IDP',
16
+ SEQUENCE: 'Sequence',
17
+ COMPOUND_NAME: 'Compound Name',
18
+ COMPOUND_COMMENTS: 'Compound Comments',
19
+ SALT: 'Salt',
20
+ EQUIVALENTS: 'Equivalents',
21
+ PURITY: 'Purity',
22
+ COMPOUND_MOL_WEIGHT: 'Cpd MW',
23
+ SALT_MOL_WEIGHT: 'Salt MW',
24
+ SALT_MASS: 'Salt mass',
25
+ BATCH_MOL_WEIGHT: 'Batch MW',
26
+ SOURCE: 'Source',
27
+ ICD: 'ICD',
28
+ OWNER: 'Owner',
29
+ };
30
+
31
+ export const GENERATED_COL_NAMES = [
32
+ COL_NAMES.COMPOUND_NAME,
33
+ COL_NAMES.COMPOUND_COMMENTS,
34
+ COL_NAMES.COMPOUND_MOL_WEIGHT,
35
+ COL_NAMES.SALT_MASS,
36
+ COL_NAMES.BATCH_MOL_WEIGHT,
37
+ ];
@@ -3,90 +3,59 @@ import * as ui from 'datagrok-api/ui';
3
3
  import * as DG from 'datagrok-api/dg';
4
4
  import {siRnaBioSpringToGcrs, siRnaAxolabsToGcrs, gcrsToNucleotides, asoGapmersBioSpringToGcrs, gcrsToMermade12,
5
5
  siRnaNucleotidesToGcrs} from '../structures-works/converters';
6
- import {map, COL_NAMES, MODIFICATIONS} from '../structures-works/map';
6
+ import {weightsObj, SYNTHESIZERS} from '../structures-works/map';
7
+ import {SEQUENCE_TYPES, COL_NAMES, GENERATED_COL_NAMES} from './constants';
8
+ import {saltMass, saltMolWeigth, molecularWeight, batchMolWeight} from './calculations';
7
9
  import {isValidSequence} from '../structures-works/sequence-codes-tools';
8
10
  import {sequenceToMolV3000} from '../structures-works/from-monomers';
9
- import {linkV3000} from '../structures-works/mol-transformations';
11
+ import {linkStrandsV3000} from '../structures-works/mol-transformations';
12
+ import {stringify, download, removeEmptyRows, differenceOfTwoArrays} from '../helpers';
10
13
 
11
- import {SALTS_CSV} from '../salts';
12
- import {USERS_CSV} from '../users';
13
- import {ICDS} from '../ICDs';
14
- import {SOURCES} from '../sources';
15
- import {IDPS} from '../IDPs';
14
+ import {SALTS_CSV} from './salts';
15
+ import {USERS_CSV} from './users';
16
+ import {ICDS} from './ICDs';
17
+ import {SOURCES} from './sources';
18
+ import {IDPS} from './IDPs';
16
19
 
17
20
 
18
- function sortByStringLengthInDescendingOrder(array: string[]): string[] {
19
- return array.sort(function(a, b) {return b.length - a.length;});
21
+ function parseStrandsFromDuplexCell(s: string): {SS: string, AS: string} {
22
+ const arr = s.slice(3).split('\r\nAS ');
23
+ return {SS: arr[0], AS: arr[1]};
20
24
  }
21
25
 
22
- function stringify(items: string[]): string {
23
- return '["' + items.join('", "') + '"]';
26
+ function parseStrandsFromTriplexOrDimerCell(s: string): {SS: string, AS1: string, AS2: string} {
27
+ const arr1 = s.slice(3).split('\r\nAS1 ');
28
+ const arr2 = arr1[1].split('\r\nAS2 ');
29
+ return {SS: arr1[0], AS1: arr2[0], AS2: arr2[1]};
24
30
  }
25
31
 
26
- function saltMass(saltNames: string[], molWeightCol: DG.Column, equivalentsCol: DG.Column, i: number,
27
- saltCol: DG.Column) {
28
- const saltRowIndex = saltNames.indexOf(saltCol.get(i));
29
- return (
30
- saltRowIndex == -1 || molWeightCol.get(saltRowIndex) == DG.FLOAT_NULL || equivalentsCol.get(i) == DG.INT_NULL) ?
31
- DG.FLOAT_NULL :
32
- molWeightCol.get(saltRowIndex) * equivalentsCol.get(i);
33
- }
34
-
35
- function saltMolWeigth(saltNamesList: string[], saltCol: DG.Column, molWeightCol: DG.Column, i: number) {
36
- const saltRowIndex = saltNamesList.indexOf(saltCol.get(i));
37
- return (saltRowIndex == -1) ? DG.FLOAT_NULL : molWeightCol.get(saltRowIndex);
38
- }
39
-
40
- function batchMolWeight(compoundMolWeightCol: DG.Column, saltMassCol: DG.Column, i: number) {
41
- return (compoundMolWeightCol.getString(i) == '' || saltMassCol.getString(i) == '') ?
42
- DG.FLOAT_NULL :
43
- compoundMolWeightCol.get(i) + saltMassCol.get(i);
44
- }
45
-
46
- function molecularWeight(sequence: string, weightsObj: {[index: string]: number}): number {
47
- const codes = sortByStringLengthInDescendingOrder(Object.keys(weightsObj)).concat(Object.keys(MODIFICATIONS));
48
- let weight = 0;
49
- let i = 0;
50
- while (i < sequence.length) {
51
- const matchedCode = codes.find((s) => s == sequence.slice(i, i + s.length))!;
52
- weight += weightsObj[sequence.slice(i, i + matchedCode.length)];
53
- i += matchedCode.length;
32
+ async function saveTableAsSdFile(table: DG.DataFrame) {
33
+ if (GENERATED_COL_NAMES.some((colName) => !table.columns.contains(colName))) {
34
+ const absentColNames = differenceOfTwoArrays(GENERATED_COL_NAMES, table.columns.names()).join(`', '`);
35
+ grok.shell.warning(`File saved without columns '${absentColNames}'`);
54
36
  }
55
- return weight - 61.97;
56
- }
57
37
 
58
- function parseStrandsFromDuplexCell(s: string): string[] {
59
- return s.slice(3).split('\r\nAS ');
60
- }
38
+ const sequenceCol = table.getCol(COL_NAMES.SEQUENCE);
39
+ const typeCol = table.getCol(COL_NAMES.TYPE);
61
40
 
62
- async function saveTableAsSdFile(table: DG.DataFrame) {
63
- if (!table.columns.contains('Compound Name')) {
64
- grok.shell.warning(
65
- 'File saved without columns \'' +
66
- [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
67
- COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''),
68
- );
69
- }
70
- const structureColumn = table.getCol(COL_NAMES.SEQUENCE);
71
- const typeColumn = table.getCol(COL_NAMES.TYPE);
72
41
  let result = '';
73
42
  for (let i = 0; i < table.rowCount; i++) {
74
- const format = 'Janssen GCRS Codes'; //getFormat(structureColumn.get(i))!;
75
- if (typeColumn.get(i) == 'Duplex') {
76
- const array = parseStrandsFromDuplexCell(structureColumn.get(i));
77
- const as = sequenceToMolV3000(array[1], true, true, format) +
78
- '\n' + `> <Sequence>\nAnti Sense\n\n`;
79
- const ss = sequenceToMolV3000(array[0], false, true, format) +
80
- '\n' + `> <Sequence>\nSense Strand\n\n`;
81
- result += linkV3000([ss, as], true, true) + '\n\n';
82
- } else if (typeColumn.get(i) == 'SS') {
83
- const molSS = sequenceToMolV3000(structureColumn.get(i), false, true, format) +
84
- '\n' + `> <Sequence>\nSense Strand\n\n`;
85
- result += molSS;
86
- } else if (typeColumn.get(i) == 'AS') {
87
- const molAS = sequenceToMolV3000(structureColumn.get(i), true, true, format) +
88
- '\n' + `> <Sequence>\nAnti Sense\n\n`;
89
- result += molAS;
43
+ const format = SYNTHESIZERS.GCRS; //getFormat(sequenceCol.get(i))!;
44
+ if (typeCol.get(i) == SEQUENCE_TYPES.SENSE_STRAND)
45
+ result += `${sequenceToMolV3000(sequenceCol.get(i), false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
46
+ else if (typeCol.get(i) == SEQUENCE_TYPES.ANTISENSE_STRAND)
47
+ result += `${sequenceToMolV3000(sequenceCol.get(i), true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
48
+ else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
49
+ const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
50
+ const as = `${sequenceToMolV3000(obj.AS, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
51
+ const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
52
+ result += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as]}, true)}\n\n`;
53
+ } else if ([SEQUENCE_TYPES.TRIPLEX, SEQUENCE_TYPES.DIMER].includes(typeCol.get(i))) {
54
+ const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
55
+ const as1 = `${sequenceToMolV3000(obj.AS1, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
56
+ const as2 = `${sequenceToMolV3000(obj.AS2, true, true, format)}\n> <Sequence>\nAnti Sense\n\n`;
57
+ const ss = `${sequenceToMolV3000(obj.SS, false, true, format)}\n> <Sequence>\nSense Strand\n\n`;
58
+ result += `${linkStrandsV3000({senseStrands: [ss], antiStrands: [as1, as2]}, true)}\n\n`;
90
59
  }
91
60
 
92
61
  for (const col of table.columns) {
@@ -95,17 +64,16 @@ async function saveTableAsSdFile(table: DG.DataFrame) {
95
64
  }
96
65
  result += '$$$$\n';
97
66
  }
98
- const element = document.createElement('a');
99
- element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(result));
100
- element.setAttribute('download', table.name + '.sdf');
101
- element.click();
67
+ download(`${table.name}.sdf`, encodeURIComponent(result));
102
68
  }
103
69
 
104
70
  export function autostartOligoSdFileSubscription() {
105
71
  grok.events.onViewAdded.subscribe((v: any) => {
106
- if (v.type == 'TableView') {
72
+ if (v.type == DG.VIEW_TYPE.TABLE_VIEW) {
107
73
  if (v.dataFrame.columns.contains(COL_NAMES.TYPE))
108
74
  oligoSdFile(v.dataFrame);
75
+
76
+ // Should be removed after fixing bug https://github.com/datagrok-ai/public/issues/808
109
77
  grok.events.onContextMenu.subscribe((args) => {
110
78
  const seqCol = args.args.context.table.currentCol; // /^[fsACGUacgu]{6,}$/
111
79
  if (DG.Detector.sampleCategories(seqCol,
@@ -166,56 +134,56 @@ export function oligoSdFile(table: DG.DataFrame) {
166
134
  const sequenceCol = table.getCol(COL_NAMES.SEQUENCE);
167
135
  const saltCol = table.getCol(COL_NAMES.SALT);
168
136
  const equivalentsCol = table.getCol(COL_NAMES.EQUIVALENTS);
169
- const typeColumn = table.getCol(COL_NAMES.TYPE);
137
+ const typeCol = table.getCol(COL_NAMES.TYPE);
170
138
  const chemistryNameCol = table.getCol(COL_NAMES.CHEMISTRY_NAME);
171
139
 
172
140
  const molWeightCol = saltsDf.getCol('MOLWEIGHT');
173
141
  const saltNamesList = saltsDf.getCol('DISPLAY').toList();
174
142
 
143
+ let newDf: DG.DataFrame;
144
+ let addColumnsPressed = false;
145
+
175
146
  function addColumns(t: DG.DataFrame) {
176
- if (t.columns.contains(COL_NAMES.COMPOUND_NAME))
147
+ if (GENERATED_COL_NAMES.some((colName) => t.columns.contains(colName)))
177
148
  return grok.shell.error('Columns already exist');
178
149
 
179
- for (let i = t.rowCount - 1; i > -1; i--) {
180
- if (sequenceCol.get(i) == '')
181
- t.rows.removeAt(i, 1, false);
182
- }
150
+ t = removeEmptyRows(t, sequenceCol);
183
151
 
184
152
  t.columns.addNewString(COL_NAMES.COMPOUND_NAME).init((i: number) => {
185
- return (typeColumn.get(i) == 'Duplex') ? chemistryNameCol.get(i) : sequenceCol.get(i);
153
+ return ([SEQUENCE_TYPES.DUPLEX, SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) ?
154
+ chemistryNameCol.get(i) :
155
+ sequenceCol.get(i);
186
156
  });
187
157
 
188
158
  t.columns.addNewString(COL_NAMES.COMPOUND_COMMENTS).init((i: number) => {
189
- if (typeColumn.get(i) == 'Duplex') {
190
- const arr = parseStrandsFromDuplexCell(sequenceCol.get(i));
191
- return chemistryNameCol.get(i) + '; duplex of SS: ' + arr[0] + ' and AS: ' + arr[1];
159
+ if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i)))
160
+ return sequenceCol.get(i);
161
+ else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
162
+ const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
163
+ return `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS: ${obj.AS}`;
164
+ } else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
165
+ const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
166
+ return `${chemistryNameCol.get(i)}; duplex of SS: ${obj.SS} and AS1: ${obj.AS1} and AS2: ${obj.AS2}`;
192
167
  }
193
- return sequenceCol.get(i);
194
168
  });
195
169
 
196
- const weightsObj: {[code: string]: number} = {};
197
- for (const synthesizer of Object.keys(map)) {
198
- for (const technology of Object.keys(map[synthesizer])) {
199
- for (const code of Object.keys(map[synthesizer][technology]))
200
- weightsObj[code] = map[synthesizer][technology][code].weight!;
201
- }
202
- }
203
- for (const [key, value] of Object.entries(MODIFICATIONS))
204
- weightsObj[key] = value.molecularWeight;
205
-
206
- t.columns.addNewFloat(COL_NAMES.CPD_MW).init((i: number) => {
207
- if (typeColumn.get(i) == 'Duplex') {
208
- const arr = parseStrandsFromDuplexCell(sequenceCol.get(i));
209
- return (
210
- isValidSequence(arr[0], null).indexOfFirstNotValidChar == -1 &&
211
- isValidSequence(arr[1], null).indexOfFirstNotValidChar == -1
212
- ) ?
213
- molecularWeight(arr[0], weightsObj) + molecularWeight(arr[1], weightsObj) :
170
+ t.columns.addNewFloat(COL_NAMES.COMPOUND_MOL_WEIGHT).init((i: number) => {
171
+ if ([SEQUENCE_TYPES.SENSE_STRAND, SEQUENCE_TYPES.ANTISENSE_STRAND].includes(typeCol.get(i))) {
172
+ return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
173
+ molecularWeight(sequenceCol.get(i), weightsObj) :
174
+ DG.FLOAT_NULL;
175
+ } else if (typeCol.get(i) == SEQUENCE_TYPES.DUPLEX) {
176
+ const obj = parseStrandsFromDuplexCell(sequenceCol.get(i));
177
+ return (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
178
+ molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS, weightsObj) :
179
+ DG.FLOAT_NULL;
180
+ } else if ([SEQUENCE_TYPES.DIMER, SEQUENCE_TYPES.TRIPLEX].includes(typeCol.get(i))) {
181
+ const obj = parseStrandsFromTriplexOrDimerCell(sequenceCol.get(i));
182
+ return (Object.values(obj).every((seq) => isValidSequence(seq, null).indexOfFirstNotValidChar == -1)) ?
183
+ molecularWeight(obj.SS, weightsObj) + molecularWeight(obj.AS1, weightsObj) +
184
+ molecularWeight(obj.AS2, weightsObj) :
214
185
  DG.FLOAT_NULL;
215
186
  }
216
- return (isValidSequence(sequenceCol.get(i), null).indexOfFirstNotValidChar == -1) ?
217
- molecularWeight(sequenceCol.get(i), weightsObj) :
218
- DG.FLOAT_NULL;
219
187
  });
220
188
 
221
189
  t.columns.addNewFloat(COL_NAMES.SALT_MASS).init((i: number) =>
@@ -224,15 +192,24 @@ export function oligoSdFile(table: DG.DataFrame) {
224
192
  t.columns.addNewFloat(COL_NAMES.SALT_MOL_WEIGHT).init((i: number) =>
225
193
  saltMolWeigth(saltNamesList, saltCol, molWeightCol, i));
226
194
 
227
- t.columns.addNewFloat(COL_NAMES.BATCH_MW).init((i: number) =>
228
- batchMolWeight(t.getCol(COL_NAMES.CPD_MW), t.getCol(COL_NAMES.SALT_MASS), i));
195
+ const compoundMolWeightCol = t.getCol(COL_NAMES.COMPOUND_MOL_WEIGHT);
196
+ const saltMassCol = t.getCol(COL_NAMES.SALT_MASS);
197
+ t.columns.addNewFloat(COL_NAMES.BATCH_MOL_WEIGHT).init((i: number) =>
198
+ batchMolWeight(compoundMolWeightCol, saltMassCol, i));
229
199
 
200
+ grok.shell.getTableView(table.name).grid.columns.setOrder(Object.values(COL_NAMES));
230
201
  addColumnsPressed = true;
231
202
  return newDf = t;
232
203
  }
233
204
 
234
- let newDf: DG.DataFrame;
235
- let addColumnsPressed = false;
205
+ function updateCalculatedColumns(t: DG.DataFrame, i: number): void {
206
+ const smValue = saltMass(saltNamesList, molWeightCol, equivalentsCol, i, saltCol);
207
+ t.getCol(COL_NAMES.SALT_MASS).set(i, smValue, false);
208
+ const smwValue = saltMolWeigth(saltNamesList, saltCol, molWeightCol, i);
209
+ t.getCol(COL_NAMES.SALT_MOL_WEIGHT).set(i, smwValue, false);
210
+ const bmw = batchMolWeight(t.getCol(COL_NAMES.COMPOUND_MOL_WEIGHT), t.getCol(COL_NAMES.SALT_MASS), i);
211
+ t.getCol(COL_NAMES.BATCH_MOL_WEIGHT).set(i, bmw, false);
212
+ }
236
213
 
237
214
  const d = ui.div([
238
215
  ui.icons.edit(() => {
@@ -240,18 +217,15 @@ export function oligoSdFile(table: DG.DataFrame) {
240
217
  if (table.getCol(COL_NAMES.IDP).type != DG.COLUMN_TYPE.STRING)
241
218
  table.changeColumnType(COL_NAMES.IDP, DG.COLUMN_TYPE.STRING);
242
219
  d.append(
243
- ui.link('Add Columns', () => {
244
- addColumns(table);
245
- view.grid.columns.setOrder(Object.values(COL_NAMES));
246
- }, 'Add columns: \'' + [COL_NAMES.COMPOUND_NAME, COL_NAMES.COMPOUND_COMMENTS, COL_NAMES.CPD_MW,
247
- COL_NAMES.SALT_MASS, COL_NAMES.BATCH_MW].join('\', \''), '',
248
- ),
249
- ui.button('Save SD file', () => saveTableAsSdFile(addColumnsPressed ? newDf : table)),
220
+ ui.divH([
221
+ ui.icons.add(() => addColumns(table), `Add columns: '${GENERATED_COL_NAMES.join(`', '`)}'`),
222
+ ui.icons.save(() => saveTableAsSdFile(addColumnsPressed ? newDf : table), 'Save SD file'),
223
+ ]),
250
224
  );
251
225
 
252
226
  const view = grok.shell.getTableView(table.name);
253
-
254
- view.dataFrame.getCol(COL_NAMES.TYPE).setTag(DG.TAGS.CHOICES, '["AS", "SS", "Duplex"]');
227
+ view.grid.setOptions({rowHeight: 45});
228
+ view.dataFrame.getCol(COL_NAMES.TYPE).setTag(DG.TAGS.CHOICES, stringify(Object.values(SEQUENCE_TYPES)));
255
229
  view.dataFrame.getCol(COL_NAMES.OWNER).setTag(DG.TAGS.CHOICES, stringify(usersDf.columns.byIndex(0).toList()));
256
230
  view.dataFrame.getCol(COL_NAMES.SALT).setTag(DG.TAGS.CHOICES, stringify(saltsDf.columns.byIndex(0).toList()));
257
231
  view.dataFrame.getCol(COL_NAMES.SOURCE).setTag(DG.TAGS.CHOICES, stringify(sourcesDf.columns.byIndex(0).toList()));
@@ -275,15 +249,6 @@ export function oligoSdFile(table: DG.DataFrame) {
275
249
  if ([COL_NAMES.SALT, COL_NAMES.EQUIVALENTS, COL_NAMES.SALT_MOL_WEIGHT].includes(colName))
276
250
  updateCalculatedColumns(view.dataFrame, view.dataFrame.currentRowIdx);
277
251
  });
278
-
279
- function updateCalculatedColumns(t: DG.DataFrame, i: number): void {
280
- const smValue = saltMass(saltNamesList, molWeightCol, equivalentsCol, i, saltCol);
281
- t.getCol(COL_NAMES.SALT_MASS).set(i, smValue, false);
282
- const smwValue = saltMolWeigth(saltNamesList, saltCol, molWeightCol, i);
283
- t.getCol(COL_NAMES.SALT_MOL_WEIGHT).set(i, smwValue, false);
284
- const bmw = batchMolWeight(t.getCol(COL_NAMES.CPD_MW), t.getCol(COL_NAMES.SALT_MASS), i);
285
- t.getCol(COL_NAMES.BATCH_MW).set(i, bmw, false);
286
- }
287
252
  }),
288
253
  ]);
289
254
  grok.shell.v.setRibbonPanels([[d]]);
File without changes
File without changes
File without changes
package/src/helpers.ts ADDED
@@ -0,0 +1,28 @@
1
+ import * as DG from 'datagrok-api/dg';
2
+
3
+ export function sortByStringLengthInDescendingOrder(array: string[]): string[] {
4
+ return array.sort(function(a, b) {return b.length - a.length;});
5
+ }
6
+
7
+ export function stringify(items: string[]): string {
8
+ return '["' + items.join('", "') + '"]';
9
+ }
10
+
11
+ export function download(name: string, href: string): void {
12
+ const element = document.createElement('a');
13
+ element.setAttribute('href', 'data:text/plain;charset=utf-8,' + href);
14
+ element.setAttribute('download', name);
15
+ element.click();
16
+ }
17
+
18
+ export function removeEmptyRows(t: DG.DataFrame, colToCheck: DG.Column): DG.DataFrame {
19
+ for (let i = t.rowCount - 1; i > -1; i--) {
20
+ if (colToCheck.getString(i) == '')
21
+ t.rows.removeAt(i, 1, false);
22
+ }
23
+ return t;
24
+ }
25
+
26
+ export function differenceOfTwoArrays(a: string[], b: string[]): string[] {
27
+ return a.filter((x) => !b.includes(x));
28
+ }