@datagrok/sequence-translator 1.3.14 → 1.3.15
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 +23 -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/files/polytool-rules/rules_example.json +34 -34
- package/files/samples/cyclized.csv +6 -0
- package/package.json +9 -10
- package/src/apps/common/view/components/colored-input/colored-text-input.ts +2 -2
- package/src/apps/pattern/view/components/bulk-convert/column-input.ts +2 -2
- package/src/apps/pattern/view/components/bulk-convert/table-input.ts +8 -6
- package/src/apps/pattern/view/components/edit-block-controls.ts +5 -5
- package/src/apps/pattern/view/components/load-block-controls.ts +7 -3
- package/src/apps/pattern/view/components/numeric-label-visibility-controls.ts +1 -1
- package/src/apps/pattern/view/components/strand-editor/header-controls.ts +2 -2
- package/src/apps/pattern/view/components/strand-editor/strand-controls.ts +2 -2
- package/src/apps/pattern/view/components/terminal-modification-editor.ts +1 -1
- package/src/apps/structure/view/ui.ts +5 -5
- package/src/apps/translator/view/ui.ts +27 -18
- package/src/package-test.ts +1 -0
- package/src/package.ts +34 -12
- package/src/polytool/pt-conversion.ts +2 -33
- package/src/polytool/pt-convert-editor.ts +116 -0
- package/src/polytool/pt-dialog.ts +177 -97
- package/src/polytool/pt-enumeration-helm-dialog.ts +338 -282
- package/src/polytool/pt-enumeration-helm.ts +6 -2
- package/src/polytool/pt-placeholders-input.ts +1 -2
- package/src/polytool/utils.ts +0 -7
- package/src/tests/polytool-convert-tests.ts +99 -0
- package/src/tests/polytool-enumerate-tests.ts +21 -5
- package/src/utils/context-menu.ts +7 -10
|
@@ -13,13 +13,16 @@ import {getMonomerLibHelper} from '@datagrok-libraries/bio/src/monomer-works/mon
|
|
|
13
13
|
import {HelmType, ISeqMonomer} from '@datagrok-libraries/bio/src/helm/types';
|
|
14
14
|
import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
15
15
|
import {getSeqHelper, ISeqHelper} from '@datagrok-libraries/bio/src/utils/seq-helper';
|
|
16
|
+
import '@datagrok-libraries/bio/src/types/input';
|
|
16
17
|
import {errInfo} from '@datagrok-libraries/bio/src/utils/err-info';
|
|
18
|
+
import {InputColumnBase} from '@datagrok-libraries/bio/src/types/input';
|
|
19
|
+
import {SeqHandler} from '@datagrok-libraries/bio/src/utils/seq-handler';
|
|
17
20
|
|
|
18
21
|
import {
|
|
19
22
|
PolyToolEnumeratorParams, PolyToolEnumeratorType, PolyToolEnumeratorTypes
|
|
20
23
|
} from './types';
|
|
21
24
|
import {getLibrariesList} from './utils';
|
|
22
|
-
import {
|
|
25
|
+
import {doPolyToolEnumerateHelm, PT_HELM_EXAMPLE} from './pt-enumeration-helm';
|
|
23
26
|
import {PolyToolPlaceholdersInput} from './pt-placeholders-input';
|
|
24
27
|
import {defaultErrorHandler} from '../utils/err-info';
|
|
25
28
|
import {PT_UI_DIALOG_ENUMERATION} from './const';
|
|
@@ -27,12 +30,21 @@ import {PT_UI_DIALOG_ENUMERATION} from './const';
|
|
|
27
30
|
import {_package} from '../package';
|
|
28
31
|
|
|
29
32
|
type PolyToolEnumerateInputs = {
|
|
30
|
-
enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
|
|
31
33
|
macromolecule: HelmInputBase;
|
|
32
34
|
placeholders: PolyToolPlaceholdersInput;
|
|
35
|
+
enumeratorType: DG.ChoiceInput<PolyToolEnumeratorType>
|
|
36
|
+
trivialNameCol: InputColumnBase,
|
|
33
37
|
toAtomicLevel: DG.InputBase<boolean>;
|
|
34
38
|
keepOriginal: DG.InputBase<boolean>;
|
|
35
|
-
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
type PolyToolEnumerateSerialized = {
|
|
42
|
+
macromolecule: string;
|
|
43
|
+
placeholders: string;
|
|
44
|
+
enumeratorType: PolyToolEnumeratorType;
|
|
45
|
+
trivialNameCol: string;
|
|
46
|
+
toAtomicLevel: boolean;
|
|
47
|
+
keepOriginal: boolean;
|
|
36
48
|
};
|
|
37
49
|
|
|
38
50
|
export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
@@ -40,7 +52,10 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
|
40
52
|
const maxHeight = window.innerHeight;
|
|
41
53
|
|
|
42
54
|
try {
|
|
55
|
+
let dialog: DG.Dialog;
|
|
43
56
|
const resizeInputs = () => {
|
|
57
|
+
if (dialog == null) return;
|
|
58
|
+
|
|
44
59
|
const dialogContentEl = $(dialog.root).find('div.d4-dialog-contents').get(0)! as HTMLElement;
|
|
45
60
|
const contentHeight = dialogContentEl.clientHeight;
|
|
46
61
|
|
|
@@ -60,7 +75,7 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
|
60
75
|
}
|
|
61
76
|
});
|
|
62
77
|
};
|
|
63
|
-
|
|
78
|
+
dialog = await getPolyToolEnumerateDialog(cell, resizeInputs);
|
|
64
79
|
|
|
65
80
|
let isFirstShow = true;
|
|
66
81
|
ui.onSizeChanged(dialog.root).subscribe(() => {
|
|
@@ -87,329 +102,370 @@ export async function polyToolEnumerateHelmUI(cell?: DG.Cell): Promise<void> {
|
|
|
87
102
|
|
|
88
103
|
resizeInputs();
|
|
89
104
|
});
|
|
105
|
+
resizeInputs();
|
|
90
106
|
|
|
91
107
|
_package.logger.debug('PolyToolEnumerateHelmUI: dialog before show');
|
|
92
108
|
const res = dialog.show({width: Math.max(350, maxWidth * 0.7), /* center: true,*/ resizable: true});
|
|
93
109
|
_package.logger.debug('PolyToolEnumerateHelmUI: dialog after show');
|
|
94
|
-
|
|
95
|
-
|
|
110
|
+
} catch (err: any) {
|
|
111
|
+
const [errMsg, errStack] = errInfo(err);
|
|
96
112
|
grok.shell.warning('To run PolyTool Enumeration, sketch the macromolecule and select monomers to vary');
|
|
113
|
+
_package.logger.error(errMsg, undefined, errStack);
|
|
97
114
|
}
|
|
98
115
|
}
|
|
99
116
|
|
|
100
117
|
|
|
101
118
|
async function getPolyToolEnumerateDialog(
|
|
102
119
|
cell?: DG.Cell, resizeInputs?: () => void
|
|
103
|
-
): Promise<
|
|
120
|
+
): Promise<DG.Dialog> {
|
|
104
121
|
const logPrefix = `ST: PT: HelmDialog()`;
|
|
105
|
-
|
|
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};
|
|
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});
|
|
183
|
-
}
|
|
184
|
-
}
|
|
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
|
-
|
|
122
|
+
let inputs: PolyToolEnumerateInputs;
|
|
205
123
|
const subs: Unsubscribable[] = [];
|
|
206
124
|
const destroy = () => {
|
|
207
|
-
inputs.placeholders.detach();
|
|
208
125
|
for (const sub of subs) sub.unsubscribe();
|
|
126
|
+
inputs.placeholders.detach();
|
|
209
127
|
};
|
|
128
|
+
try {
|
|
129
|
+
const monomerLib = (await getMonomerLibHelper()).getMonomerLib();
|
|
130
|
+
const seqHelper = await getSeqHelper();
|
|
131
|
+
const emptyDf: DG.DataFrame = DG.DataFrame.fromColumns([]);
|
|
132
|
+
|
|
133
|
+
const [libList, helmHelper] = await Promise.all([getLibrariesList(), getHelmHelper()]);
|
|
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
|
+
inputs = {
|
|
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: helmHelper.createHelmInput(
|
|
145
|
+
'Macromolecule', {editable: false}),
|
|
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: ui.input.column2(
|
|
158
|
+
'Trivial name', {
|
|
159
|
+
table: cell?.dataFrame,
|
|
160
|
+
filter: (col: DG.Column): boolean => {
|
|
161
|
+
return col.type === DG.COLUMN_TYPE.STRING && col != cell?.column; /* id */
|
|
162
|
+
},
|
|
163
|
+
onValueChanged: (): void => {
|
|
164
|
+
const valueCol = inputs.trivialNameCol.value;
|
|
165
|
+
let newSrcId: typeof srcId = null;
|
|
166
|
+
if (cell && valueCol) {
|
|
167
|
+
const originalId = valueCol.get(cell.rowIndex)!;
|
|
168
|
+
newSrcId = {value: originalId, colName: valueCol.name};
|
|
169
|
+
}
|
|
170
|
+
srcId = newSrcId;
|
|
171
|
+
trivialNameSampleDiv.textContent = srcId ? `Original ID: ${srcId.value}` : '';
|
|
172
|
+
},
|
|
173
|
+
nullable: true,
|
|
174
|
+
}),
|
|
175
|
+
};
|
|
210
176
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
177
|
+
inputs.trivialNameCol.addOptions(trivialNameSampleDiv);
|
|
178
|
+
|
|
179
|
+
let placeholdersValidity: string | null = null;
|
|
180
|
+
inputs.placeholders.addValidator((value: string): string | null => {
|
|
181
|
+
const errors: string[] = [];
|
|
182
|
+
try {
|
|
183
|
+
const missedMonomerList: ISeqMonomer[] = [];
|
|
184
|
+
for (const [posVal, monomerSymbolList] of Object.entries(inputs.placeholders.placeholdersValue)) {
|
|
185
|
+
const pos = parseInt(posVal);
|
|
186
|
+
if (pos >= inputs.macromolecule.molValue.atoms.length) {
|
|
187
|
+
errors.push(`There is no monomer at position ${pos + 1}.`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const a = inputs.macromolecule.molValue.atoms[pos];
|
|
191
|
+
const helmType: HelmType = a.biotype()!;
|
|
192
|
+
const polymerType = helmTypeToPolymerType(helmType);
|
|
193
|
+
for (const symbol of monomerSymbolList) {
|
|
194
|
+
const substituteMonomer = monomerLib.getMonomer(polymerType, symbol)!;
|
|
195
|
+
// TODO: Check substitution monomer is presented in the library
|
|
196
|
+
if (!substituteMonomer || !substituteMonomer.lib)
|
|
197
|
+
missedMonomerList.push({polymerType, symbol});
|
|
198
|
+
}
|
|
199
|
+
}
|
|
214
200
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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();
|
|
201
|
+
const byType: { [polymerType: string]: string[] } = {};
|
|
202
|
+
for (const sm of missedMonomerList) {
|
|
203
|
+
let byTypeList = byType[sm.polymerType];
|
|
204
|
+
if (!byTypeList) byTypeList = byType[sm.polymerType] = [];
|
|
205
|
+
byTypeList.push(sm.symbol);
|
|
229
206
|
}
|
|
207
|
+
const byTypeStr: string = Object.entries(byType)
|
|
208
|
+
.map(([polymerType, symbolList]) => `${polymerType}: ${symbolList.join(', ')}`)
|
|
209
|
+
.join('\n');
|
|
210
|
+
if (Object.keys(byTypeStr).length > 0)
|
|
211
|
+
errors.push(`Placeholders contain missed monomers: ${byTypeStr}`);
|
|
212
|
+
placeholdersValidity = errors.length > 0 ? errors.join('\n') : null;
|
|
213
|
+
} catch (err: any) {
|
|
214
|
+
const [errMsg, errStack] = defaultErrorHandler(err, false);
|
|
215
|
+
placeholdersValidity = errMsg;
|
|
230
216
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
234
|
-
}));
|
|
235
|
-
subs.push(inputs.macromolecule.onClick.subscribe((e: MouseEvent) => {
|
|
236
|
-
try {
|
|
237
|
-
_package.logger.debug(`${logPrefix}, placeholdersInput.onClick()`);
|
|
217
|
+
setTimeout(() => { updateWarnings(); }, 0);
|
|
218
|
+
return placeholdersValidity;
|
|
219
|
+
});
|
|
238
220
|
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
const
|
|
245
|
-
const
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
221
|
+
subs.push(inputs.macromolecule.onMouseMove.subscribe((e: MouseEvent) => {
|
|
222
|
+
try {
|
|
223
|
+
_package.logger.debug(`${logPrefix}, placeholdersInput.onMouseMove()`);
|
|
224
|
+
|
|
225
|
+
const argsX = e.offsetX;
|
|
226
|
+
const argsY = e.offsetY;
|
|
227
|
+
const mol = inputs.macromolecule.molValue;
|
|
228
|
+
const hoveredAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
|
|
229
|
+
if (hoveredAtom) {
|
|
230
|
+
const hoveredAtomContIdx = hoveredAtom._parent.atoms.indexOf(hoveredAtom);
|
|
231
|
+
const hoveredAtomContIdxStr = (hoveredAtomContIdx + 1).toString();
|
|
232
|
+
const substitutingMonomers = inputs.placeholders.placeholdersValue[hoveredAtomContIdx];
|
|
233
|
+
|
|
234
|
+
if (substitutingMonomers) {
|
|
235
|
+
const cnt = ui.divText(substitutingMonomers.join(', '));
|
|
236
|
+
inputs.macromolecule.showTooltip(cnt, hoveredAtom);
|
|
237
|
+
e.preventDefault();
|
|
238
|
+
e.stopPropagation();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} catch (err: any) {
|
|
242
|
+
defaultErrorHandler(err, false);
|
|
243
|
+
}
|
|
244
|
+
}));
|
|
245
|
+
subs.push(inputs.macromolecule.onClick.subscribe((e: MouseEvent) => {
|
|
246
|
+
try {
|
|
247
|
+
_package.logger.debug(`${logPrefix}, placeholdersInput.onClick()`);
|
|
248
|
+
|
|
249
|
+
const argsX = e.offsetX;
|
|
250
|
+
const argsY = e.offsetY;
|
|
251
|
+
const mol = inputs.macromolecule.molValue;
|
|
252
|
+
const clickedAtom = helmHelper.getHoveredAtom(argsX, argsY, mol, inputs.macromolecule.root.clientHeight);
|
|
253
|
+
if (clickedAtom) {
|
|
254
|
+
const clickedAtomContIdx = clickedAtom._parent.atoms.indexOf(clickedAtom);
|
|
255
|
+
const clickedAtomContIdxStr = (clickedAtomContIdx + 1).toString();
|
|
256
|
+
|
|
257
|
+
const phDf = inputs.placeholders.grid.dataFrame;
|
|
258
|
+
const posList = phDf.columns.byName('Position').toList();
|
|
259
|
+
let rowIdx = posList.indexOf(clickedAtomContIdxStr);
|
|
252
260
|
if (rowIdx === -1) {
|
|
253
|
-
rowIdx =
|
|
261
|
+
rowIdx = posList.findIndex((v) => isNaN(v));
|
|
262
|
+
if (rowIdx === -1) {
|
|
263
|
+
rowIdx = phDf.rows.addNew([clickedAtomContIdxStr, '']).idx;
|
|
264
|
+
}
|
|
265
|
+
phDf.set('Position', rowIdx, clickedAtomContIdxStr);
|
|
266
|
+
// const tgtCell = inputs.placeholders.grid.cell('Monomers', rowIdx);
|
|
254
267
|
}
|
|
255
|
-
phDf.
|
|
256
|
-
//
|
|
268
|
+
phDf.currentCell = phDf.cell(rowIdx, 'Monomers');
|
|
269
|
+
//const gridRowIdx = inputs.placeholders.grid.tableRowToGrid(rowIdx);
|
|
270
|
+
//const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
|
|
271
|
+
const k = 42;
|
|
257
272
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
//const monomersGCell = inputs.placeholders.grid.cell('Monomers', gridRowIdx);
|
|
261
|
-
const k = 42;
|
|
273
|
+
} catch (err: any) {
|
|
274
|
+
defaultErrorHandler(err);
|
|
262
275
|
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
276
|
+
}));
|
|
277
|
+
subs.push(inputs.placeholders.grid.dataFrame.onDataChanged.subscribe(() => {
|
|
278
|
+
updateMolView();
|
|
279
|
+
}));
|
|
280
|
+
subs.push(fromEvent<KeyboardEvent>(inputs.placeholders.grid.root, 'keydown')
|
|
281
|
+
.subscribe((e: KeyboardEvent) => {
|
|
282
|
+
if (e.key === 'Enter') e.stopPropagation();
|
|
283
|
+
}));
|
|
284
|
+
|
|
285
|
+
// TODO: suspect
|
|
286
|
+
subs.push(ui.onSizeChanged(inputs.placeholders.root).subscribe(() => {
|
|
287
|
+
if (resizeInputs) resizeInputs();
|
|
273
288
|
}));
|
|
274
289
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
290
|
+
// Displays the molecule from a current cell (monitors changes)
|
|
291
|
+
subs.push(grok.events.onCurrentCellChanged.subscribe(() => {
|
|
292
|
+
const cell = grok.shell.tv.dataFrame.currentCell;
|
|
293
|
+
if (cell.column.semType !== DG.SEMTYPE.MACROMOLECULE) return;
|
|
279
294
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
const cell = grok.shell.tv.dataFrame.currentCell;
|
|
295
|
+
fillForCurrentCell(cell);
|
|
296
|
+
}));
|
|
283
297
|
|
|
284
|
-
|
|
285
|
-
|
|
298
|
+
inputs.macromolecule.root.style.setProperty('min-width', '250px', 'important');
|
|
299
|
+
// inputs.macromolecule.root.style.setProperty('max-height', '300px', 'important');
|
|
286
300
|
|
|
287
|
-
|
|
288
|
-
|
|
301
|
+
const updateMolView = () => {
|
|
302
|
+
const mol = inputs.macromolecule.molValue;
|
|
303
|
+
for (let aI = 0; aI < mol.atoms.length; aI++) {
|
|
304
|
+
const a = mol.atoms[aI];
|
|
305
|
+
a.highlighted = aI in inputs.placeholders.placeholdersValue;
|
|
306
|
+
}
|
|
307
|
+
inputs.macromolecule.redraw();
|
|
308
|
+
};
|
|
289
309
|
|
|
290
|
-
|
|
291
|
-
|
|
310
|
+
const updateWarnings = () => {
|
|
311
|
+
const warnings = placeholdersValidity;
|
|
312
|
+
// const iw = inputs.warnings;
|
|
313
|
+
const w = warningsTextDiv;
|
|
314
|
+
if (!!warnings) {
|
|
315
|
+
// iw.value = warnings; // <- breaks dialog resize
|
|
316
|
+
// iw.enabled = true;
|
|
317
|
+
// iw.root.style.removeProperty('display');
|
|
318
|
+
|
|
319
|
+
w.innerText = warnings;
|
|
320
|
+
w.style.removeProperty('display');
|
|
321
|
+
} else {
|
|
322
|
+
// iw.value = ''; // <- breaks dialog resize
|
|
323
|
+
// iw.enabled = false;
|
|
324
|
+
// iw.root.style.setProperty('display', 'none');
|
|
325
|
+
|
|
326
|
+
w.innerText = '';
|
|
327
|
+
w.style.setProperty('display', 'none');
|
|
328
|
+
}
|
|
329
|
+
//resizeInputs();
|
|
330
|
+
};
|
|
292
331
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
332
|
+
const fillTrivialNameList = (table?: DG.DataFrame) => {
|
|
333
|
+
// const colList: DG.Column[] = [];
|
|
334
|
+
// const colCount: number = cell.dataFrame.columns.length;
|
|
335
|
+
//
|
|
336
|
+
// // TODO: by semType?
|
|
337
|
+
// for (let colI: number = 0; colI < colCount; ++colI) {
|
|
338
|
+
// const col = cell.dataFrame.columns.byIndex(colI);
|
|
339
|
+
// if (col.type === DG.COLUMN_TYPE.STRING) colList.push(col);
|
|
340
|
+
// }
|
|
341
|
+
|
|
342
|
+
if (table) {
|
|
343
|
+
inputs.trivialNameCol.setColumnInputTable(table);
|
|
344
|
+
inputs.trivialNameCol.root.style.removeProperty('display');
|
|
345
|
+
} else {
|
|
346
|
+
inputs.trivialNameCol.setColumnInputTable(emptyDf);
|
|
347
|
+
inputs.trivialNameCol.root.style.setProperty('display', 'none');
|
|
348
|
+
}
|
|
349
|
+
if (resizeInputs) resizeInputs();
|
|
350
|
+
};
|
|
301
351
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
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
|
-
};
|
|
352
|
+
const fillForCurrentCell = async (cell?: DG.Cell): Promise<void> => {
|
|
353
|
+
let helmValue: string;
|
|
354
|
+
let table: DG.DataFrame | undefined = undefined;
|
|
355
|
+
if (cell && cell.rowIndex >= 0 && cell?.column.semType == DG.SEMTYPE.MACROMOLECULE) {
|
|
356
|
+
const sh = SeqHandler.forColumn(cell.column);
|
|
357
|
+
helmValue = await sh.getHelm(cell.rowIndex);
|
|
358
|
+
table = cell.dataFrame;
|
|
359
|
+
} else {
|
|
360
|
+
helmValue = PT_HELM_EXAMPLE;
|
|
361
|
+
}
|
|
323
362
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
};
|
|
363
|
+
inputs.macromolecule.stringValue = helmValue;
|
|
364
|
+
fillTrivialNameList(table);
|
|
365
|
+
};
|
|
337
366
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
367
|
+
await fillForCurrentCell(cell);
|
|
368
|
+
|
|
369
|
+
const exec = async (): Promise<void> => {
|
|
370
|
+
try {
|
|
371
|
+
const srcHelm = inputs.macromolecule.stringValue;
|
|
372
|
+
const helmSelections: number[] = wu.enumerate<HelmAtom>(inputs.macromolecule.molValue.atoms)
|
|
373
|
+
.filter(([a, aI]) => a.highlighted)
|
|
374
|
+
.map(([a, aI]) => aI).toArray();
|
|
375
|
+
if (srcHelm === undefined || srcHelm === '') {
|
|
376
|
+
grok.shell.warning('PolyTool: no molecule was provided');
|
|
377
|
+
} else /* if (helmSelections === undefined || helmSelections.length < 1) {
|
|
347
378
|
grok.shell.warning('PolyTool: no selection was provided');
|
|
348
379
|
} else /**/ {
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
380
|
+
if (Object.keys(inputs.placeholders.placeholdersValue).length === 0) {
|
|
381
|
+
grok.shell.warning(`${PT_UI_DIALOG_ENUMERATION}: placeholders are empty`);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
await getHelmHelper(); // initializes JSDraw and org
|
|
385
|
+
const params: PolyToolEnumeratorParams = {
|
|
386
|
+
type: inputs.enumeratorType.value!,
|
|
387
|
+
placeholders: inputs.placeholders.placeholdersValue,
|
|
388
|
+
keepOriginal: inputs.keepOriginal.value,
|
|
389
|
+
};
|
|
390
|
+
const enumeratorResDf = await polyToolEnumerateHelm(srcHelm, srcId, params, inputs.toAtomicLevel.value, seqHelper);
|
|
391
|
+
grok.shell.addTableView(enumeratorResDf);
|
|
352
392
|
}
|
|
353
|
-
|
|
354
|
-
|
|
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);
|
|
393
|
+
} catch (err: any) {
|
|
394
|
+
defaultErrorHandler(err);
|
|
361
395
|
}
|
|
362
|
-
}
|
|
363
|
-
defaultErrorHandler(err);
|
|
364
|
-
} finally {
|
|
365
|
-
destroy();
|
|
366
|
-
}
|
|
367
|
-
};
|
|
396
|
+
};
|
|
368
397
|
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
})
|
|
385
|
-
.
|
|
386
|
-
|
|
398
|
+
const dialog = ui.dialog({title: PT_UI_DIALOG_ENUMERATION, showFooter: true})
|
|
399
|
+
.add(inputs.macromolecule)
|
|
400
|
+
.add(inputs.placeholders)
|
|
401
|
+
.add(inputs.enumeratorType)
|
|
402
|
+
.add(inputs.trivialNameCol)
|
|
403
|
+
.add(inputs.toAtomicLevel)
|
|
404
|
+
.add(inputs.keepOriginal)
|
|
405
|
+
.add(warningsTextDiv)
|
|
406
|
+
// .addButton('Enumerate', () => {
|
|
407
|
+
// execDialog()
|
|
408
|
+
// .then(() => {});
|
|
409
|
+
// }, 0, 'Keeps the dialog open')
|
|
410
|
+
.onOK(() => { exec(); });
|
|
411
|
+
subs.push(dialog.onClose.subscribe(() => {
|
|
412
|
+
destroy();
|
|
413
|
+
}));
|
|
414
|
+
dialog.history(
|
|
415
|
+
/* getInput */ (): PolyToolEnumerateSerialized => {
|
|
416
|
+
return {
|
|
417
|
+
macromolecule: inputs.macromolecule.stringValue,
|
|
418
|
+
placeholders: inputs.placeholders.stringValue,
|
|
419
|
+
enumeratorType: inputs.enumeratorType.value,
|
|
420
|
+
trivialNameCol: inputs.trivialNameCol.stringValue,
|
|
421
|
+
toAtomicLevel: inputs.toAtomicLevel.value,
|
|
422
|
+
keepOriginal: inputs.keepOriginal.value,
|
|
423
|
+
};
|
|
424
|
+
},
|
|
425
|
+
/* applyInput */ (x: PolyToolEnumerateSerialized): void => {
|
|
426
|
+
inputs.macromolecule.stringValue = x.macromolecule;
|
|
427
|
+
inputs.placeholders.stringValue = x.placeholders;
|
|
428
|
+
inputs.enumeratorType.value = x.enumeratorType;
|
|
429
|
+
inputs.trivialNameCol.stringValue = x.trivialNameCol;
|
|
430
|
+
inputs.toAtomicLevel.value = x.toAtomicLevel;
|
|
431
|
+
inputs.keepOriginal.value = x.keepOriginal;
|
|
432
|
+
});
|
|
433
|
+
return dialog;
|
|
434
|
+
} catch (err: any) {
|
|
435
|
+
destroy(); // on failing to build a dialog
|
|
436
|
+
throw err;
|
|
437
|
+
}
|
|
387
438
|
}
|
|
388
439
|
|
|
389
|
-
async function
|
|
440
|
+
async function polyToolEnumerateHelm(
|
|
390
441
|
srcHelm: string, srcId: { value: string, colName: string } | null, params: PolyToolEnumeratorParams,
|
|
391
442
|
toAtomicLevel: boolean, seqHelper: ISeqHelper,
|
|
392
443
|
): Promise<DG.DataFrame> {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
444
|
+
const pi = DG.TaskBarProgressIndicator.create('PolyTool enumerating...');
|
|
445
|
+
try {
|
|
446
|
+
await getHelmHelper(); // initializes JSDraw and org
|
|
447
|
+
|
|
448
|
+
const resList = doPolyToolEnumerateHelm(srcHelm, srcId?.value ?? '', params);
|
|
449
|
+
const enumHelmCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, 'Enumerated', resList.length)
|
|
450
|
+
.init((rowIdx: number) => resList[rowIdx][0]);
|
|
451
|
+
const enumeratorResDf = DG.DataFrame.fromColumns([enumHelmCol]);
|
|
452
|
+
|
|
453
|
+
if (toAtomicLevel) {
|
|
454
|
+
const seqHelper: ISeqHelper = await getSeqHelper();
|
|
455
|
+
const toAtomicLevelRes = await seqHelper.helmToAtomicLevel(enumHelmCol, true, true);
|
|
456
|
+
toAtomicLevelRes.molCol.semType = DG.SEMTYPE.MOLECULE;
|
|
457
|
+
enumeratorResDf.columns.add(toAtomicLevelRes.molCol, false);
|
|
458
|
+
enumeratorResDf.columns.add(toAtomicLevelRes.molHighlightCol, false);
|
|
459
|
+
}
|
|
407
460
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
461
|
+
if (srcId) {
|
|
462
|
+
const enumIdCol = DG.Column.fromType(DG.COLUMN_TYPE.STRING, srcId.colName, resList.length)
|
|
463
|
+
.init((rowIdx: number) => resList[rowIdx][1]);
|
|
464
|
+
enumeratorResDf.columns.add(enumIdCol);
|
|
465
|
+
}
|
|
413
466
|
|
|
414
|
-
|
|
467
|
+
return enumeratorResDf;
|
|
468
|
+
} finally {
|
|
469
|
+
pi.close();
|
|
470
|
+
}
|
|
415
471
|
}
|