@datagrok/sequence-translator 1.3.12 → 1.3.14
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/CHANGELOG.md +19 -1
- package/dist/package-test.js +1 -1
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +6 -6
- package/src/apps/common/view/components/colored-input/style.css +1 -0
- package/src/apps/structure/view/style.css +14 -19
- package/src/apps/structure/view/ui.ts +9 -25
- package/src/package.ts +6 -6
- package/src/polytool/pt-dialog.ts +3 -70
- package/src/polytool/pt-enumeration-helm-dialog.ts +366 -169
- package/src/polytool/pt-enumeration-helm.ts +41 -33
- package/src/polytool/pt-placeholders-input.ts +23 -9
- package/src/polytool/types.ts +2 -0
- package/src/tests/polytool-enumerate-tests.ts +41 -24
- package/src/utils/context-menu.ts +5 -3
- package/src/utils/err-info.ts +2 -1
- package/src/polytool/cyclized.ts +0 -56
|
@@ -2,23 +2,27 @@ import * as ui from 'datagrok-api/ui';
|
|
|
2
2
|
import * as grok from 'datagrok-api/grok';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
4
|
|
|
5
|
+
import $ from 'cash-dom';
|
|
5
6
|
import wu from 'wu';
|
|
6
|
-
import {Unsubscribable} from 'rxjs';
|
|
7
|
+
import {fromEvent, Unsubscribable} from 'rxjs';
|
|
7
8
|
|
|
8
9
|
import {NOTATION} from '@datagrok-libraries/bio/src/utils/macromolecule';
|
|
9
10
|
import {HelmAtom, HelmMol} from '@datagrok-libraries/helm-web-editor/src/types/org-helm';
|
|
10
11
|
import {getHelmHelper, HelmInputBase} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
12
|
+
import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/monomer-utils';
|
|
13
|
+
import {HelmType, ISeqMonomer} from '@datagrok-libraries/bio/src/helm/types';
|
|
14
|
+
import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
15
|
+
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
16
|
+
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
11
17
|
|
|
12
18
|
import {
|
|
13
|
-
PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes
|
|
19
|
+
PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes
|
|
14
20
|
} from './types';
|
|
15
|
-
|
|
16
|
-
import {PT_UI_DIALOG_ENUMERATION} from './const';
|
|
17
21
|
import {getLibrariesList} from './utils';
|
|
18
22
|
import {getPtEnumeratorHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
|
|
19
23
|
import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
|
|
20
|
-
import {Dialog} from 'datagrok-api/dg';
|
|
21
24
|
import {defaultErrorHandler} from '../utils/err-info';
|
|
25
|
+
import {PT_UI_DIALOG_ENUMERATION} from './const';
|
|
22
26
|
|
|
23
27
|
import {_package} from '../package';
|
|
24
28
|
|
|
@@ -27,192 +31,385 @@ type PolyToolEnumerateInputs = {
|
|
|
27
31
|
macromolecule: HelmInputBase;
|
|
28
32
|
placeholders: PolyToolPlaceholdersInput;
|
|
29
33
|
toAtomicLevel: DG.InputBase<boolean>;
|
|
34
|
+
keepOriginal: DG.InputBase<boolean>;
|
|
35
|
+
/** Trivial names source column */ trivialNameCol: DG.InputBase<DG.Column<string> | null>,
|
|
30
36
|
};
|
|
31
37
|
|
|
38
|
+
export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
39
|
+
const maxWidth = window.innerWidth;
|
|
40
|
+
const maxHeight = window.innerHeight;
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const resizeInputs = () => {
|
|
44
|
+
const dialogContentEl = $(dialog.root).find('div.d4-dialog-contents').get(0)! as HTMLElement;
|
|
45
|
+
const contentHeight = dialogContentEl.clientHeight;
|
|
46
|
+
|
|
47
|
+
const fitInputs: { [idx: number]: number } = {0: 1 /*, 3: 0.5*/};
|
|
48
|
+
const fitInputsSumHeight = Object.values(fitInputs).reduce((sum, h) => sum + h, 0);
|
|
49
|
+
|
|
50
|
+
const otherInputsHeight: number = wu.count(0).take(dialogContentEl.children.length)
|
|
51
|
+
.filter((i) => !(i in fitInputs))
|
|
52
|
+
.map((idx) => dialogContentEl.children[idx])
|
|
53
|
+
.filter((el) => el instanceof HTMLElement)
|
|
54
|
+
.map((el) => (el as HTMLElement).offsetHeight).reduce((sum, h) => sum + h, 0);
|
|
55
|
+
const remainFitHeight = contentHeight - otherInputsHeight - 38;
|
|
56
|
+
dialog.inputs.forEach((input, idx) => {
|
|
57
|
+
if (idx in fitInputs) {
|
|
58
|
+
const inputFitHeight = remainFitHeight * fitInputs[idx] / fitInputsSumHeight;
|
|
59
|
+
input.root.style.height = `${inputFitHeight}px`;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
const [dialog, inputs] = await getPolyToolEnumerateDialog(cell, resizeInputs);
|
|
32
64
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
public override show(options?: { modal?: boolean; resizable?: boolean; fullScreen?: boolean; center?: boolean; centerAt?: Element; x?: number; y?: number; width?: number; height?: number; backgroundColor?: string; showNextTo?: HTMLElement }): Dialog {
|
|
44
|
-
return super.show(options);
|
|
45
|
-
}
|
|
65
|
+
let isFirstShow = true;
|
|
66
|
+
ui.onSizeChanged(dialog.root).subscribe(() => {
|
|
67
|
+
if (isFirstShow) {
|
|
68
|
+
const dialogInputList = dialog.inputs;
|
|
69
|
+
const dialogRootCash = $(dialog.root);
|
|
70
|
+
const contentMaxHeight = maxHeight
|
|
71
|
+
- dialogRootCash.find('div.d4-dialog-header').get(0)!.offsetHeight
|
|
72
|
+
- dialogRootCash.find('div.d4-dialog-footer').get(0)!.offsetHeight;
|
|
46
73
|
|
|
47
|
-
|
|
48
|
-
const logPrefix = `ST: PT: HelmDialog()`;
|
|
74
|
+
// dialog.inputs2.macromolecule.root.style.backgroundColor = '#CCFFCC';
|
|
49
75
|
|
|
50
|
-
|
|
76
|
+
const dialogWidth = maxWidth * 0.7;
|
|
77
|
+
const dialogHeight = maxHeight * 0.7;
|
|
51
78
|
|
|
52
|
-
|
|
53
|
-
|
|
79
|
+
// Centered, but resizable dialog
|
|
80
|
+
dialog.root.style.width = `${Math.min(maxWidth, dialogWidth)}px`;
|
|
81
|
+
dialog.root.style.height = `${Math.min(maxHeight, dialogHeight)}px`;
|
|
82
|
+
dialog.root.style.left = `${Math.floor((maxWidth - dialog.root.offsetWidth) / 2)}px`;
|
|
83
|
+
dialog.root.style.top = `${Math.floor((maxHeight - dialog.root.offsetHeight) / 2)}px`;
|
|
54
84
|
|
|
55
|
-
|
|
56
|
-
|
|
85
|
+
isFirstShow = false;
|
|
86
|
+
}
|
|
57
87
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
'Enumerator type', {
|
|
61
|
-
value: PolyToolEnumeratorTypes.Single,
|
|
62
|
-
items: Object.values(PolyToolEnumeratorTypes)
|
|
63
|
-
}) as DG.ChoiceInput<PolyToolEnumeratorType>,
|
|
64
|
-
macromolecule: macromoleculeInput,
|
|
88
|
+
resizeInputs();
|
|
89
|
+
});
|
|
65
90
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
91
|
+
_package.logger.debug('PolyToolEnumerateHelmUI: dialog before show');
|
|
92
|
+
const res = dialog.show({width: Math.max(350, maxWidth * 0.7), /* center: true,*/ resizable: true});
|
|
93
|
+
_package.logger.debug('PolyToolEnumerateHelmUI: dialog after show');
|
|
94
|
+
const k = 42;
|
|
95
|
+
} catch (_err: any) {
|
|
96
|
+
grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
73
99
|
|
|
74
|
-
toAtomicLevel: ui.input.bool(
|
|
75
|
-
'To atomic level', {value: true}),
|
|
76
|
-
};
|
|
77
100
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
101
|
+
async function getPolyToolEnumerateDialog(
|
|
102
|
+
cell?: DG.Cell, resizeInputs?: () => void
|
|
103
|
+
): Promise<[DG.Dialog, PolyToolEnumerateInputs]> {
|
|
104
|
+
const logPrefix = `ST: PT: HelmDialog()`;
|
|
105
|
+
const monomerLib = (await getMonomerLibHelper()).getMonomerLib();
|
|
106
|
+
const seqHelper = await getSeqHelper();
|
|
107
|
+
|
|
108
|
+
const [libList, helmHelper] = await Promise.all([getLibrariesList(), getHelmHelper()]);
|
|
109
|
+
|
|
110
|
+
const helmValue = (cell && cell.rowIndex >= 0) ? cell.value : PT_HELM_EXAMPLE;
|
|
111
|
+
|
|
112
|
+
const macromoleculeInput = helmHelper.createHelmInput(
|
|
113
|
+
'Macromolecule', {value: helmValue, editable: false});
|
|
114
|
+
|
|
115
|
+
const createTrivialNameColInput = (cell?: DG.Cell): DG.InputBase<DG.Column<string> | null> => {
|
|
116
|
+
return ui.input.column(
|
|
117
|
+
'Trivial name', {
|
|
118
|
+
table: cell?.dataFrame,
|
|
119
|
+
filter: (col: DG.Column): boolean => {
|
|
120
|
+
return col.type === DG.COLUMN_TYPE.STRING && col != cell?.column; /* id */
|
|
121
|
+
},
|
|
122
|
+
onValueChanged: (): void => {
|
|
123
|
+
const valueCol = inputs.trivialNameCol.value;
|
|
124
|
+
let newSrcId: typeof srcId = null;
|
|
125
|
+
if (cell && valueCol) {
|
|
126
|
+
const originalId = valueCol.get(cell.rowIndex)!;
|
|
127
|
+
newSrcId = {value: originalId, colName: valueCol.name};
|
|
99
128
|
}
|
|
129
|
+
srcId = newSrcId;
|
|
130
|
+
trivialNameSampleDiv.textContent = srcId ? `Original ID: ${srcId.value}` : '';
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
let srcId: { value: string, colName: string } | null = null;
|
|
136
|
+
const trivialNameSampleDiv = ui.divText('', {style: {marginLeft: '8px', marginTop: '2px'}});
|
|
137
|
+
const warningsTextDiv = ui.divText('', {style: {color: 'red'}});
|
|
138
|
+
const inputs: PolyToolEnumerateInputs = {
|
|
139
|
+
enumeratorType: ui.input.choice<PolyToolEnumeratorType>(
|
|
140
|
+
'Enumerator type', {
|
|
141
|
+
value: PolyToolEnumeratorTypes.Single,
|
|
142
|
+
items: Object.values(PolyToolEnumeratorTypes)
|
|
143
|
+
}) as DG.ChoiceInput<PolyToolEnumeratorType>,
|
|
144
|
+
macromolecule: macromoleculeInput,
|
|
145
|
+
|
|
146
|
+
placeholders: await PolyToolPlaceholdersInput.create(
|
|
147
|
+
'Placeholders', {
|
|
148
|
+
showAddNewRowIcon: true,
|
|
149
|
+
showRemoveRowIcon: true,
|
|
150
|
+
showRowHeader: false,
|
|
151
|
+
showCellTooltip: false,
|
|
152
|
+
}/*, 2/**/),
|
|
153
|
+
toAtomicLevel: ui.input.bool(
|
|
154
|
+
'To atomic level', {value: false}),
|
|
155
|
+
keepOriginal: ui.input.bool(
|
|
156
|
+
'Keep original', {value: false}),
|
|
157
|
+
trivialNameCol: createTrivialNameColInput(cell),
|
|
158
|
+
// warnings: ui.input.textArea('' +
|
|
159
|
+
// 'Warnings', {value: ''}),
|
|
160
|
+
};
|
|
161
|
+
const elementList = [
|
|
162
|
+
inputs.toAtomicLevel,
|
|
163
|
+
inputs.placeholders
|
|
164
|
+
];
|
|
165
|
+
|
|
166
|
+
inputs.trivialNameCol.addOptions(trivialNameSampleDiv);
|
|
167
|
+
// inputs.warnings.readOnly = true;
|
|
168
|
+
|
|
169
|
+
let placeholdersValidity: string | null = null;
|
|
170
|
+
inputs.placeholders.addValidator((value: string): string | null => {
|
|
171
|
+
try {
|
|
172
|
+
const missedMonomerList: ISeqMonomer[] = [];
|
|
173
|
+
for (const [posVal, monomerSymbolList] of Object.entries(inputs.placeholders.placeholdersValue)) {
|
|
174
|
+
const pos = parseInt(posVal);
|
|
175
|
+
const a = inputs.macromolecule.molValue.atoms[pos];
|
|
176
|
+
const helmType: HelmType = a.biotype()!;
|
|
177
|
+
const polymerType = helmTypeToPolymerType(helmType);
|
|
178
|
+
for (const symbol of monomerSymbolList) {
|
|
179
|
+
const substituteMonomer = monomerLib.getMonomer(polymerType, symbol)!;
|
|
180
|
+
// TODO: Check substitution monomer is presented in the library
|
|
181
|
+
if (!substituteMonomer || !substituteMonomer.lib)
|
|
182
|
+
missedMonomerList.push({polymerType, symbol});
|
|
100
183
|
}
|
|
101
|
-
} catch (err: any) {
|
|
102
|
-
defaultErrorHandler(err, false);
|
|
103
184
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
185
|
+
|
|
186
|
+
const byType: { [polymerType: string]: string[] } = {};
|
|
187
|
+
for (const sm of missedMonomerList) {
|
|
188
|
+
let byTypeList = byType[sm.polymerType];
|
|
189
|
+
if (!byTypeList) byTypeList = byType[sm.polymerType] = [];
|
|
190
|
+
byTypeList.push(sm.symbol);
|
|
191
|
+
}
|
|
192
|
+
const byTypeStr: string = Object.entries(byType)
|
|
193
|
+
.map(([polymerType, symbolList]) => `${polymerType}: ${symbolList.join(', ')}`)
|
|
194
|
+
.join('\n');
|
|
195
|
+
placeholdersValidity = Object.keys(byTypeStr).length > 0 ?
|
|
196
|
+
`Placeholders contain missed monomers: ${byTypeStr}` : null;
|
|
197
|
+
} catch (err: any) {
|
|
198
|
+
const [errMsg, errStack] = defaultErrorHandler(err, false);
|
|
199
|
+
placeholdersValidity = errMsg;
|
|
200
|
+
}
|
|
201
|
+
setTimeout(() => { updateWarnings(); }, 0);
|
|
202
|
+
return placeholdersValidity;
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const subs: Unsubscribable[] = [];
|
|
206
|
+
const destroy = () => {
|
|
207
|
+
inputs.placeholders.detach();
|
|
208
|
+
for (const sub of subs) sub.unsubscribe();
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
subs.push(inputs.macromolecule.onMouseMove.subscribe((e: MouseEvent) => {
|
|
212
|
+
try {
|
|
213
|
+
_package.logger.debug(`${logPrefix}, placeholdersInput.onMouseMove()`);
|
|
214
|
+
|
|
215
|
+
const argsX = e.offsetX;
|
|
216
|
+
const argsY = e.offsetY;
|
|
217
|
+
const mol = inputs.macromolecule.molValue;
|
|
218
|
+
const hoveredAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
|
|
219
|
+
if (hoveredAtom) {
|
|
220
|
+
const hoveredAtomContIdx = hoveredAtom._parent.atoms.indexOf(hoveredAtom);
|
|
221
|
+
const hoveredAtomContIdxStr = (hoveredAtomContIdx + 1).toString();
|
|
222
|
+
const substitutingMonomers = inputs.placeholders.placeholdersValue[hoveredAtomContIdx];
|
|
223
|
+
|
|
224
|
+
if (substitutingMonomers) {
|
|
225
|
+
const cnt = ui.divText(substitutingMonomers.join(', '));
|
|
226
|
+
inputs.macromolecule.showTooltip(cnt, hoveredAtom);
|
|
227
|
+
e.preventDefault();
|
|
228
|
+
e.stopPropagation();
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
} catch (err: any) {
|
|
232
|
+
defaultErrorHandler(err, false);
|
|
233
|
+
}
|
|
234
|
+
}));
|
|
235
|
+
subs.push(inputs.macromolecule.onClick.subscribe((e: MouseEvent) => {
|
|
236
|
+
try {
|
|
237
|
+
_package.logger.debug(`${logPrefix}, placeholdersInput.onClick()`);
|
|
238
|
+
|
|
239
|
+
const argsX = e.offsetX;
|
|
240
|
+
const argsY = e.offsetY;
|
|
241
|
+
const mol = inputs.macromolecule.molValue;
|
|
242
|
+
const clickedAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
|
|
243
|
+
if (clickedAtom) {
|
|
244
|
+
const clickedAtomContIdx = clickedAtom._parent.atoms.indexOf(clickedAtom);
|
|
245
|
+
const clickedAtomContIdxStr = (clickedAtomContIdx + 1).toString();
|
|
246
|
+
|
|
247
|
+
const phDf = inputs.placeholders.grid.dataFrame;
|
|
248
|
+
const posList = phDf.columns.byName('Position').toList();
|
|
249
|
+
let rowIdx = posList.indexOf(clickedAtomContIdxStr);
|
|
250
|
+
if (rowIdx === -1) {
|
|
251
|
+
rowIdx = posList.findIndex((v) => isNaN(v));
|
|
120
252
|
if (rowIdx === -1) {
|
|
121
|
-
rowIdx =
|
|
122
|
-
if (rowIdx === -1)
|
|
123
|
-
rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
|
|
124
|
-
phDf.set('Position', rowIdx, clickedAtomContIdxStr);
|
|
125
|
-
// const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
|
|
253
|
+
rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
|
|
126
254
|
}
|
|
127
|
-
phDf.
|
|
128
|
-
//const
|
|
129
|
-
//const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
|
|
130
|
-
const k = 42;
|
|
255
|
+
phDf.set('Position', rowIdx, clickedAtomContIdxStr);
|
|
256
|
+
// const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
|
|
131
257
|
}
|
|
132
|
-
|
|
133
|
-
|
|
258
|
+
phDf.currentCell = phDf.cell(rowIdx, 'Monomers');
|
|
259
|
+
//const gridRowIdx = inputs.placeholders.grid.tableRowToGrid(rowIdx);
|
|
260
|
+
//const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
|
|
261
|
+
const k = 42;
|
|
134
262
|
}
|
|
263
|
+
} catch (err: any) {
|
|
264
|
+
defaultErrorHandler(err);
|
|
265
|
+
}
|
|
266
|
+
}));
|
|
267
|
+
subs.push(inputs.placeholders.grid.dataFrame.onDataChanged.subscribe(() => {
|
|
268
|
+
updateMolView();
|
|
269
|
+
}));
|
|
270
|
+
subs.push(fromEvent<KeyboardEvent>(inputs.placeholders.grid.root, 'keydown')
|
|
271
|
+
.subscribe((e: KeyboardEvent) => {
|
|
272
|
+
if (e.key === 'Enter') e.stopPropagation();
|
|
135
273
|
}));
|
|
136
|
-
subs.push(inputs.placeholders.grid.dataFrame.onDataChanged.subscribe(() => {
|
|
137
|
-
updateMolView();
|
|
138
|
-
}));
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// TODO: suspect
|
|
142
|
-
subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
|
|
143
|
-
if (resizeInputs) resizeInputs();
|
|
144
|
-
}));
|
|
145
|
-
|
|
146
|
-
// Displays the molecule from a current cell (monitors changes)
|
|
147
|
-
subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
|
|
148
|
-
const cell = grok.shell.tv.dataFrame.currentCell;
|
|
149
274
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
275
|
+
// TODO: suspect
|
|
276
|
+
subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
|
|
277
|
+
if (resizeInputs) resizeInputs();
|
|
278
|
+
}));
|
|
279
|
+
|
|
280
|
+
// Displays the molecule from a current cell (monitors changes)
|
|
281
|
+
subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
|
|
282
|
+
const cell = grok.shell.tv.dataFrame.currentCell;
|
|
283
|
+
|
|
284
|
+
if (cell.column.semType === DG.SEMTYPE.MACROMOLECULE && cell.column.meta.units === NOTATION.HELM)
|
|
285
|
+
inputs.macromolecule.stringValue = cell.value;
|
|
286
|
+
|
|
287
|
+
fillTrivialNameList(cell);
|
|
288
|
+
}));
|
|
289
|
+
|
|
290
|
+
inputs.macromolecule.root.style.setProperty('min-width', '250px', 'important');
|
|
291
|
+
// inputs.macromolecule.root.style.setProperty('max-height', '300px', 'important');
|
|
292
|
+
|
|
293
|
+
const updateMolView = () => {
|
|
294
|
+
const mol = inputs.macromolecule.molValue;
|
|
295
|
+
for (let aI = 0; aI < mol.atoms.length; aI++) {
|
|
296
|
+
const a = mol.atoms[aI];
|
|
297
|
+
a.highlighted = aI in inputs.placeholders.placeholdersValue;
|
|
298
|
+
}
|
|
299
|
+
inputs.macromolecule.redraw();
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const updateWarnings = () => {
|
|
303
|
+
const warnings = placeholdersValidity;
|
|
304
|
+
// const iw = inputs.warnings;
|
|
305
|
+
const w = warningsTextDiv;
|
|
306
|
+
if (!!warnings) {
|
|
307
|
+
// iw.value = warnings; // <- breaks dialog resize
|
|
308
|
+
// iw.enabled = true;
|
|
309
|
+
// iw.root.style.removeProperty('display');
|
|
310
|
+
|
|
311
|
+
w.innerText = warnings;
|
|
312
|
+
w.style.removeProperty('display');
|
|
313
|
+
} else {
|
|
314
|
+
// iw.value = ''; // <- breaks dialog resize
|
|
315
|
+
// iw.enabled = false;
|
|
316
|
+
// iw.root.style.setProperty('display', 'none');
|
|
317
|
+
|
|
318
|
+
w.innerText = '';
|
|
319
|
+
w.style.setProperty('display', 'none');
|
|
320
|
+
}
|
|
321
|
+
//resizeInputs();
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
const fillTrivialNameList = (cell: DG.Cell) => {
|
|
325
|
+
// const colList: DG.Column[] = [];
|
|
326
|
+
// const colCount: number = cell.dataFrame.columns.length;
|
|
327
|
+
//
|
|
328
|
+
// // TODO: by semType?
|
|
329
|
+
// for (let colI: number = 0; colI < colCount; ++colI) {
|
|
330
|
+
// const col = cell.dataFrame.columns.byIndex(colI);
|
|
331
|
+
// if (col.type === DG.COLUMN_TYPE.STRING) colList.push(col);
|
|
332
|
+
// }
|
|
333
|
+
|
|
334
|
+
// TODO: Change table column items in inputs.trivialName
|
|
335
|
+
inputs.trivialNameCol = createTrivialNameColInput(cell);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const execDialog = async (): Promise<void> => {
|
|
339
|
+
try {
|
|
340
|
+
const srcHelm = inputs.macromolecule.stringValue;
|
|
341
|
+
const helmSelections: number[] = wu.enumerate<HelmAtom>(inputs.macromolecule.molValue.atoms)
|
|
342
|
+
.filter(([a, aI]) => a.highlighted)
|
|
343
|
+
.map(([a, aI]) => aI).toArray();
|
|
344
|
+
if (srcHelm === undefined || srcHelm === '') {
|
|
345
|
+
grok.shell.warning('PolyTool: no molecule was provided');
|
|
346
|
+
} else /* if (helmSelections === undefined || helmSelections.length < 1) {
|
|
180
347
|
grok.shell.warning('PolyTool: no selection was provided');
|
|
181
348
|
} else /**/ {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
type: inputs.enumeratorType.value!,
|
|
186
|
-
placeholders: inputs.placeholders.placeholdersValue,
|
|
187
|
-
};
|
|
188
|
-
if (Object.keys(params.placeholders).length === 0) {
|
|
189
|
-
grok.shell.warning(`${PT_UI_DIALOG_ENUMERATION}: placeholders are empty`);
|
|
190
|
-
return;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const enumHelmList = getPtEnumeratorHelm(helmString, params);
|
|
194
|
-
const enumHelmCol = DG.Column.fromStrings('Enumerated', enumHelmList);
|
|
195
|
-
const enumeratorResDf = DG.DataFrame.fromColumns([enumHelmCol]);
|
|
196
|
-
|
|
197
|
-
if (inputs.toAtomicLevel.value) {
|
|
198
|
-
const enumMolCol = await grok.functions.call('Bio:getMolFromHelm', {
|
|
199
|
-
'df': enumeratorResDf,
|
|
200
|
-
'helmCol': enumHelmCol,
|
|
201
|
-
'chiralityEngine': true,
|
|
202
|
-
});
|
|
203
|
-
enumMolCol.name = enumeratorResDf.columns.getUnusedName(`molfile(${enumHelmCol.name})`);
|
|
204
|
-
enumMolCol.semType = DG.SEMTYPE.MOLECULE;
|
|
205
|
-
enumeratorResDf.columns.add(enumMolCol, true);
|
|
206
|
-
}
|
|
207
|
-
grok.shell.addTableView(enumeratorResDf);
|
|
208
|
-
}
|
|
209
|
-
} catch (err: any) {
|
|
210
|
-
defaultErrorHandler(err);
|
|
211
|
-
} finally {
|
|
212
|
-
destroy();
|
|
349
|
+
if (Object.keys(inputs.placeholders.placeholdersValue).length === 0) {
|
|
350
|
+
grok.shell.warning(`${PT_UI_DIALOG_ENUMERATION}: placeholders are empty`);
|
|
351
|
+
return;
|
|
213
352
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
353
|
+
await getHelmHelper(); // initializes JSDraw and org
|
|
354
|
+
const params: PolyToolEnumeratorParams = {
|
|
355
|
+
type: inputs.enumeratorType.value!,
|
|
356
|
+
placeholders: inputs.placeholders.placeholdersValue,
|
|
357
|
+
keepOriginal: inputs.keepOriginal.value,
|
|
358
|
+
};
|
|
359
|
+
const enumeratorResDf = await enumerateHelm(srcHelm, srcId, params, inputs.toAtomicLevel.value, seqHelper);
|
|
360
|
+
grok.shell.addTableView(enumeratorResDf);
|
|
361
|
+
}
|
|
362
|
+
} catch (err: any) {
|
|
363
|
+
defaultErrorHandler(err);
|
|
364
|
+
} finally {
|
|
365
|
+
destroy();
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
const dialog = ui.dialog({title: PT_UI_DIALOG_ENUMERATION, showFooter: true})
|
|
370
|
+
.add(inputs.macromolecule)
|
|
371
|
+
.add(inputs.placeholders)
|
|
372
|
+
.add(inputs.enumeratorType)
|
|
373
|
+
.add(inputs.trivialNameCol)
|
|
374
|
+
.add(inputs.toAtomicLevel)
|
|
375
|
+
.add(inputs.keepOriginal)
|
|
376
|
+
.add(warningsTextDiv)
|
|
377
|
+
// .addButton('Enumerate', () => {
|
|
378
|
+
// execDialog()
|
|
379
|
+
// .then(() => {});
|
|
380
|
+
// }, 0, 'Keeps the dialog open')
|
|
381
|
+
.onOK(() => {
|
|
382
|
+
execDialog()
|
|
383
|
+
.then(() => {destroy();});
|
|
384
|
+
})
|
|
385
|
+
.onCancel(() => { destroy(); });
|
|
386
|
+
return [dialog, inputs];
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
async function enumerateHelm(
|
|
390
|
+
srcHelm: string, srcId: { value: string, colName: string } | null, params: PolyToolEnumeratorParams,
|
|
391
|
+
toAtomicLevel: boolean, seqHelper: ISeqHelper,
|
|
392
|
+
): Promise<DG.DataFrame> {
|
|
393
|
+
await getHelmHelper(); // initializes JSDraw and org
|
|
394
|
+
|
|
395
|
+
const resList = getPtEnumeratorHelm(srcHelm, srcId?.value ?? '', params);
|
|
396
|
+
const enumHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Enumerated', resList.length)
|
|
397
|
+
.init((rowIdx: number) => resList[rowIdx][0]);
|
|
398
|
+
const enumeratorResDf = DG.DataFrame.fromColumns([enumHelmCol]);
|
|
399
|
+
|
|
400
|
+
if (toAtomicLevel) {
|
|
401
|
+
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
402
|
+
const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumHelmCol, true, true);
|
|
403
|
+
toAtomicLevelRes.molCol.semType = DG.SEMTYPE.MOLECULE;
|
|
404
|
+
enumeratorResDf.columns.add(toAtomicLevelRes.molCol, false);
|
|
405
|
+
enumeratorResDf.columns.add(toAtomicLevelRes.molHighlightCol, false);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (srcId) {
|
|
409
|
+
const enumIdCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, srcId.colName, resList.length)
|
|
410
|
+
.init((rowIdx: number) => resList[rowIdx][1]);
|
|
411
|
+
enumeratorResDf.columns.add(enumIdCol);
|
|
217
412
|
}
|
|
413
|
+
|
|
414
|
+
return enumeratorResDf;
|
|
218
415
|
}
|