@datagrok/bio 2.23.2 → 2.24.0
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/.eslintrc.json +0 -2
- package/CHANGELOG.md +5 -0
- package/README.md +1 -1
- package/dist/package-test.js +3 -3
- package/dist/package-test.js.map +1 -1
- package/dist/package.js +2 -2
- package/dist/package.js.map +1 -1
- package/package.json +2 -2
- package/src/package-types.ts +1 -1
- package/src/package.ts +9 -3
- package/src/tests/activity-cliffs-tests.ts +2 -2
- package/src/tests/monomer-libraries-tests.ts +8 -6
- package/src/tests/renderers-monomer-placer-tests.ts +1 -1
- package/src/tests/scoring.ts +1 -1
- package/src/tests/seq-handler-get-helm-tests.ts +1 -1
- package/src/tests/splitters-test.ts +2 -2
- package/src/tests/substructure-filters-tests.ts +11 -11
- package/src/tests/to-atomic-level-tests.ts +2 -2
- package/src/tests/to-atomic-level-ui-tests.ts +13 -14
- package/src/utils/cell-renderer.ts +1 -1
- package/src/utils/helm-to-molfile/converter/converter.ts +1 -1
- package/src/utils/helm-to-molfile/converter/mol-bonds.ts +1 -1
- package/src/utils/helm-to-molfile/converter/monomer-wrapper.ts +1 -1
- package/src/utils/helm-to-molfile/converter/polymer.ts +1 -1
- package/src/utils/helm-to-molfile/utils.ts +3 -2
- package/src/utils/monomer-cell-renderer-base.ts +1 -2
- package/src/utils/monomer-lib/consts.ts +1 -6
- package/src/utils/monomer-lib/lib-manager.ts +239 -112
- package/src/utils/monomer-lib/library-file-manager/monomers-lib-provider.ts +378 -0
- package/src/utils/monomer-lib/library-file-manager/ui.ts +119 -80
- package/src/utils/monomer-lib/monomer-colors.ts +37 -39
- package/src/utils/monomer-lib/monomer-lib-base.ts +3 -4
- package/src/utils/monomer-lib/monomer-lib.ts +7 -7
- package/src/utils/monomer-lib/monomer-manager/duplicate-monomer-manager.ts +3 -3
- package/src/utils/monomer-lib/monomer-manager/monomer-manager.ts +90 -81
- package/src/utils/monomer-lib/web-editor-monomer-of-library.ts +2 -1
- package/src/utils/seq-helper/seq-handler.ts +16 -3
- package/src/utils/seq-helper/seq-helper.ts +1 -2
- package/src/utils/sequence-to-mol.ts +1 -1
- package/src/viewers/web-logo-viewer.ts +1 -1
- package/src/widgets/composition-analysis-widget.ts +1 -1
- package/src/widgets/sequence-scrolling-widget.ts +1 -2
- package/test-console-output-1.log +672 -720
- package/test-record-1.mp4 +0 -0
- package/src/utils/monomer-lib/library-file-manager/custom-monomer-lib-handlers.ts +0 -41
- package/src/utils/monomer-lib/library-file-manager/event-manager.ts +0 -93
- package/src/utils/monomer-lib/library-file-manager/file-manager.ts +0 -317
- package/src/utils/monomer-lib/monomer-set.ts +0 -61
|
@@ -6,19 +6,21 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
|
|
7
7
|
import $ from 'cash-dom';
|
|
8
8
|
import {Subject} from 'rxjs';
|
|
9
|
-
import './style.css';
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
getUserLibSettings, setUserLibSettings
|
|
13
12
|
} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
14
13
|
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
15
|
-
import {
|
|
14
|
+
import {findProviderWithLibraryName,
|
|
15
|
+
getMonomerLibHelper, IMonomerLibHelper,
|
|
16
|
+
IMonomerLibProvider} from '@datagrok-libraries/bio/src/types/monomer-library';
|
|
16
17
|
|
|
17
|
-
import {MonomerLibFileEventManager} from './event-manager';
|
|
18
18
|
import {_package} from '../../../package';
|
|
19
19
|
import {MonomerManager} from '../monomer-manager/monomer-manager';
|
|
20
20
|
import {DuplicateMonomerManager} from '../monomer-manager/duplicate-monomer-manager';
|
|
21
21
|
import {MonomerLibManager} from '../lib-manager';
|
|
22
|
+
// @ts-ignore
|
|
23
|
+
import './style.css';
|
|
22
24
|
|
|
23
25
|
export async function showManageLibrariesDialog(): Promise<void> {
|
|
24
26
|
await DialogWrapper.showDialog();
|
|
@@ -38,8 +40,6 @@ export async function getMonomerLibraryManagerLink(): Promise<DG.Widget> {
|
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
class MonomerLibraryManagerWidget {
|
|
41
|
-
private _fileManager: IMonomerLibFileManager;
|
|
42
|
-
|
|
43
43
|
private _widget: DG.Widget;
|
|
44
44
|
public get widget(): DG.Widget { return this._widget; }
|
|
45
45
|
|
|
@@ -47,12 +47,14 @@ class MonomerLibraryManagerWidget {
|
|
|
47
47
|
|
|
48
48
|
private static instancePromise?: Promise<MonomerLibraryManagerWidget>;
|
|
49
49
|
|
|
50
|
+
private libHelper: IMonomerLibHelper;
|
|
51
|
+
|
|
50
52
|
static async getInstance(): Promise<MonomerLibraryManagerWidget> {
|
|
51
53
|
if (MonomerLibraryManagerWidget.instancePromise === undefined) {
|
|
52
54
|
MonomerLibraryManagerWidget.instancePromise = (async () => {
|
|
53
55
|
const instance = new MonomerLibraryManagerWidget();
|
|
54
56
|
const libHelper = await getMonomerLibHelper();
|
|
55
|
-
instance.
|
|
57
|
+
instance.libHelper = libHelper;
|
|
56
58
|
instance._widget = await instance.createWidget();
|
|
57
59
|
return instance;
|
|
58
60
|
})();
|
|
@@ -69,7 +71,7 @@ class MonomerLibraryManagerWidget {
|
|
|
69
71
|
const content = await this.getWidgetContent();
|
|
70
72
|
const monomerLibHelper = await getMonomerLibHelper();
|
|
71
73
|
// eslint-disable-next-line rxjs/no-ignored-subscription
|
|
72
|
-
monomerLibHelper.
|
|
74
|
+
monomerLibHelper.fileUploadRequested.subscribe(
|
|
73
75
|
() => this.promptToAddLibraryFiles()
|
|
74
76
|
);
|
|
75
77
|
return new DG.Widget(content);
|
|
@@ -89,17 +91,38 @@ class MonomerLibraryManagerWidget {
|
|
|
89
91
|
DG.Utils.openFile({
|
|
90
92
|
accept: '.json',
|
|
91
93
|
open: async (selectedFile) => {
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
const doAdd = async (provider: IMonomerLibProvider) => {
|
|
95
|
+
const content = await selectedFile.text();
|
|
96
|
+
const name = selectedFile.name;
|
|
97
|
+
const progressIndicator = DG.TaskBarProgressIndicator.create(`Adding ${name} as a monomer library`);
|
|
98
|
+
try {
|
|
99
|
+
await provider.addOrUpdateLibraryString(name, content);
|
|
97
100
|
// this.eventManager.updateLibrarySelectionStatus(name, true);
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
} catch (e) {
|
|
102
|
+
grok.shell.error(`File ${name} is not a valid monomer library, verify it is aligned to HELM JSON schema.`);
|
|
103
|
+
} finally {
|
|
104
|
+
progressIndicator.close();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const providers = await this.libHelper.getProviders();
|
|
108
|
+
if (providers.length === 0) {
|
|
109
|
+
grok.shell.error('No monomer library providers available to add the library.');
|
|
110
|
+
return;
|
|
102
111
|
}
|
|
112
|
+
if (providers.length === 1) {
|
|
113
|
+
await doAdd(providers[0]);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const dialog = ui.dialog('Select storage for new monomer library');
|
|
117
|
+
const providersInput =
|
|
118
|
+
ui.input.choice('Storage', {items: providers.map((p) => p.name), value: providers[0].name,
|
|
119
|
+
nullable: false, tooltipText: 'Storage provider for new monomer library'});
|
|
120
|
+
dialog
|
|
121
|
+
.add(providersInput)
|
|
122
|
+
.onOK(async () => {
|
|
123
|
+
const provider = providers.find((p) => p.name === providersInput.value)!; // should not be null
|
|
124
|
+
await doAdd(provider);
|
|
125
|
+
});
|
|
103
126
|
},
|
|
104
127
|
});
|
|
105
128
|
}
|
|
@@ -107,16 +130,11 @@ class MonomerLibraryManagerWidget {
|
|
|
107
130
|
|
|
108
131
|
class LibraryControlsManager {
|
|
109
132
|
private constructor(
|
|
110
|
-
private
|
|
133
|
+
private readonly libHelper: IMonomerLibHelper,
|
|
111
134
|
private readonly userLibSettings: UserLibSettings,
|
|
112
135
|
) {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
this.updateControlsForm();
|
|
116
|
-
});
|
|
117
|
-
// eslint-disable-next-line rxjs/no-ignored-subscription
|
|
118
|
-
this.fileManager.eventManager.librarySelectionRequested$.subscribe(([fileName, isSelected]) => {
|
|
119
|
-
this.updateLibrarySelectionStatus(isSelected, fileName);
|
|
136
|
+
this.libHelper.providersDataChanged.subscribe(async () => {
|
|
137
|
+
await this.updateControlsForm();
|
|
120
138
|
});
|
|
121
139
|
}
|
|
122
140
|
|
|
@@ -127,30 +145,28 @@ class LibraryControlsManager {
|
|
|
127
145
|
static async createControlsForm(): Promise<HTMLElement> {
|
|
128
146
|
const logPrefix = 'LibraryControlsForm.createControlsForm()';
|
|
129
147
|
_package.logger.debug(`${logPrefix}, start`);
|
|
130
|
-
const
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
]);
|
|
134
|
-
const manager = new LibraryControlsManager(fileManager, userLibSettings);
|
|
148
|
+
const userLibSettings = await getUserLibSettings();
|
|
149
|
+
const libHelper = await getMonomerLibHelper();
|
|
150
|
+
const manager = new LibraryControlsManager(libHelper, userLibSettings);
|
|
135
151
|
|
|
136
152
|
return manager._createControlsForm();
|
|
137
153
|
}
|
|
138
154
|
|
|
139
|
-
private _createControlsForm(): HTMLElement {
|
|
140
|
-
const libraryControls = this.createLibraryControls();
|
|
155
|
+
private async _createControlsForm(): Promise<HTMLElement> {
|
|
156
|
+
const libraryControls = await this.createLibraryControls();
|
|
141
157
|
const inputsForm = ui.wideForm(libraryControls, undefined);
|
|
142
158
|
$(inputsForm).addClass('monomer-lib-controls-form');
|
|
143
159
|
|
|
144
160
|
return inputsForm;
|
|
145
161
|
}
|
|
146
162
|
|
|
147
|
-
public updateControlsForm(): void {
|
|
148
|
-
const updatedForm = this._createControlsForm();
|
|
163
|
+
public async updateControlsForm(): Promise<void> {
|
|
164
|
+
const updatedForm = await this._createControlsForm();
|
|
149
165
|
$('.monomer-lib-controls-form').replaceWith(updatedForm);
|
|
150
166
|
}
|
|
151
167
|
|
|
152
|
-
private createLibraryControls(): DG.InputBase<boolean | null>[] {
|
|
153
|
-
const libFileNameList: string[] = this.
|
|
168
|
+
private async createLibraryControls(): Promise<DG.InputBase<boolean | null>[]> {
|
|
169
|
+
const libFileNameList: string[] = await this.libHelper.getAvaliableLibraryNames();
|
|
154
170
|
return libFileNameList.map((libFileName) => this.createLibInput(libFileName));
|
|
155
171
|
}
|
|
156
172
|
|
|
@@ -159,7 +175,7 @@ class LibraryControlsManager {
|
|
|
159
175
|
_package.logger.debug(`${logPrefix}, libFileName = '${libFileName}', start`);
|
|
160
176
|
const isMonomerLibrarySelected = !this.userLibSettings.exclude.includes(libFileName);
|
|
161
177
|
const libInput = ui.input.bool(libFileName, {value: isMonomerLibrarySelected, onValueChanged: () => {
|
|
162
|
-
|
|
178
|
+
updateLibrarySelectionStatus(libInput.value, libFileName);
|
|
163
179
|
}});
|
|
164
180
|
ui.tooltip.bind(libInput.root, `Include monomers from ${libFileName}`);
|
|
165
181
|
const deleteIcon = ui.iconFA('trash-alt', () => this.promptForLibraryDeletion(libFileName));
|
|
@@ -173,38 +189,19 @@ class LibraryControlsManager {
|
|
|
173
189
|
return libInput;
|
|
174
190
|
}
|
|
175
191
|
|
|
176
|
-
private async updateLibrarySelectionStatus(
|
|
177
|
-
isMonomerLibrarySelected: boolean,
|
|
178
|
-
libFileName: string
|
|
179
|
-
): Promise<void> {
|
|
180
|
-
this.updateLibrarySettings(isMonomerLibrarySelected, libFileName);
|
|
181
|
-
await setUserLibSettings(this.userLibSettings);
|
|
182
|
-
const monomerLibHelper = await getMonomerLibHelper();
|
|
183
|
-
await monomerLibHelper.loadMonomerLib(true);
|
|
184
|
-
grok.shell.info('Monomer library user settings saved');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private updateLibrarySettings(
|
|
188
|
-
isLibrarySelected: boolean | null,
|
|
189
|
-
libFileName: string,
|
|
190
|
-
): void {
|
|
191
|
-
if (isLibrarySelected) {
|
|
192
|
-
// Remove selected library from exclusion list
|
|
193
|
-
this.userLibSettings.exclude = this.userLibSettings.exclude.filter((libName) => libName !== libFileName);
|
|
194
|
-
} else if (!this.userLibSettings.exclude.includes(libFileName)) {
|
|
195
|
-
// Add unselected library to exclusion list
|
|
196
|
-
this.userLibSettings.exclude.push(libFileName);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
192
|
|
|
200
193
|
private promptForLibraryDeletion(fileName: string): void {
|
|
201
194
|
const dialog = ui.dialog('Warning');
|
|
202
|
-
dialog.add(ui.divText(`
|
|
195
|
+
dialog.add(ui.divText(`Are you sure you want to delete library "${fileName}"?`))
|
|
203
196
|
.onOK(async () => {
|
|
204
197
|
try {
|
|
205
198
|
const progressIndicator = DG.TaskBarProgressIndicator.create(`Deleting ${fileName} library`);
|
|
206
|
-
await
|
|
207
|
-
await this.
|
|
199
|
+
await updateLibrarySelectionStatus(false, fileName);
|
|
200
|
+
const provider = await findProviderWithLibraryName(await this.libHelper.getProviders(), fileName);
|
|
201
|
+
if (!provider)
|
|
202
|
+
throw new Error(`Cannot find provider for library ${fileName}`);
|
|
203
|
+
await provider.deleteLibrary(fileName);
|
|
204
|
+
// await this.fileManager.deleteLibraryFile(fileName);
|
|
208
205
|
progressIndicator.close();
|
|
209
206
|
} catch (e) {
|
|
210
207
|
console.error(e);
|
|
@@ -215,6 +212,33 @@ class LibraryControlsManager {
|
|
|
215
212
|
}
|
|
216
213
|
}
|
|
217
214
|
|
|
215
|
+
async function updateLibrarySelectionStatus(
|
|
216
|
+
isMonomerLibrarySelected: boolean,
|
|
217
|
+
libFileName: string
|
|
218
|
+
): Promise<void> {
|
|
219
|
+
const userLibSettings = await getUserLibSettings();
|
|
220
|
+
updateLibrarySettings(userLibSettings, isMonomerLibrarySelected, libFileName);
|
|
221
|
+
await setUserLibSettings(userLibSettings);
|
|
222
|
+
const monomerLibHelper = await getMonomerLibHelper();
|
|
223
|
+
await monomerLibHelper.loadMonomerLib(true);
|
|
224
|
+
grok.shell.info('Monomer library user settings saved');
|
|
225
|
+
monomerLibHelper.notifyLibrarySelectionChanged();
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function updateLibrarySettings(
|
|
229
|
+
userLibSettings: UserLibSettings,
|
|
230
|
+
isLibrarySelected: boolean | null,
|
|
231
|
+
libFileName: string,
|
|
232
|
+
): void {
|
|
233
|
+
if (isLibrarySelected) {
|
|
234
|
+
// Remove selected library from exclusion list
|
|
235
|
+
userLibSettings.exclude = userLibSettings.exclude.filter((libName) => libName !== libFileName);
|
|
236
|
+
} else if (!userLibSettings.exclude.includes(libFileName)) {
|
|
237
|
+
// Add unselected library to exclusion list
|
|
238
|
+
userLibSettings.exclude.push(libFileName);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
218
242
|
class DialogWrapper {
|
|
219
243
|
private constructor() { }
|
|
220
244
|
|
|
@@ -238,8 +262,8 @@ class DialogWrapper {
|
|
|
238
262
|
}
|
|
239
263
|
|
|
240
264
|
private async getDialog(): Promise<DG.Dialog> {
|
|
241
|
-
const eventManager = MonomerLibFileEventManager.getInstance();
|
|
242
265
|
const widget = (await MonomerLibraryManagerWidget.getInstance()).widget;
|
|
266
|
+
const libHelper = await getMonomerLibHelper();
|
|
243
267
|
const dialog = ui.dialog(
|
|
244
268
|
{
|
|
245
269
|
title: 'Manage monomer libraries',
|
|
@@ -250,7 +274,7 @@ class DialogWrapper {
|
|
|
250
274
|
dialog.clear();
|
|
251
275
|
dialog.addButton(
|
|
252
276
|
'Add',
|
|
253
|
-
() =>
|
|
277
|
+
() => libHelper.requestFileUpload(),
|
|
254
278
|
undefined,
|
|
255
279
|
'Upload new HELM monomer library'
|
|
256
280
|
);
|
|
@@ -264,17 +288,17 @@ class DialogWrapper {
|
|
|
264
288
|
}
|
|
265
289
|
|
|
266
290
|
class LibManagerView {
|
|
267
|
-
private constructor(
|
|
291
|
+
private constructor(
|
|
292
|
+
) {};
|
|
268
293
|
private static _instance: LibManagerView;
|
|
269
294
|
static viewName = 'Manage Monomer Libraries';
|
|
270
295
|
private _view: DG.View;
|
|
271
296
|
private _duplicateManager: DuplicateMonomerManager;
|
|
272
297
|
private libManager: MonomerLibManager;
|
|
273
298
|
private async getView(addView = true) {
|
|
274
|
-
const eventManager = MonomerLibFileEventManager.getInstance();
|
|
275
299
|
const widget = (await MonomerLibraryManagerWidget.getInstance()).widget;
|
|
276
300
|
const addButton = ui.bigButton('Add',
|
|
277
|
-
() =>
|
|
301
|
+
() => this.libManager.requestFileUpload(), 'Upload new HELM monomer library');
|
|
278
302
|
const mergeButton =
|
|
279
303
|
ui.bigButton('Merge', () => { this.mergeSelectedLibs(); }, 'Merge selected libraries into one');
|
|
280
304
|
|
|
@@ -349,7 +373,6 @@ class LibManagerView {
|
|
|
349
373
|
const libraryExistsError = 'Library with this name already exists';
|
|
350
374
|
const libManager = await MonomerLibManager.getInstance();
|
|
351
375
|
await libManager.awaitLoaded();
|
|
352
|
-
await libManager.loadLibrariesPromise;
|
|
353
376
|
if (!libManager.duplicatesHandled) {
|
|
354
377
|
grok.shell.warning(`Selected libraries contain repeating symbols with different monomers.
|
|
355
378
|
Please choose the correct monomer for each symbol using duplicate monomomer manager.`);
|
|
@@ -366,37 +389,53 @@ class LibManagerView {
|
|
|
366
389
|
dialog.getButton('Save')?.classList?.toggle('d4-disabled', !!res);
|
|
367
390
|
}
|
|
368
391
|
});
|
|
369
|
-
const validLibPaths =
|
|
392
|
+
const validLibPaths = await this.libManager.getAvaliableLibraryNames();
|
|
370
393
|
newFileNameInput.addValidator(validateInput);
|
|
371
|
-
function getFileNameInputValue() {
|
|
372
|
-
let fileName = newFileNameInput.value;
|
|
373
|
-
if (!fileName.endsWith('.json'))
|
|
374
|
-
fileName += '.json';
|
|
375
|
-
return fileName;
|
|
376
|
-
};
|
|
377
394
|
|
|
378
395
|
function validateInput(v: string) {
|
|
379
396
|
if (!v || !v.trim()) return 'Library name cannot be empty';
|
|
380
|
-
if (
|
|
397
|
+
if (validLibPaths.includes(v) || validLibPaths.includes(v + '.json'))
|
|
381
398
|
return libraryExistsError;
|
|
382
399
|
return null;
|
|
383
400
|
}
|
|
401
|
+
const providers = await this.libManager.getProviders();
|
|
402
|
+
if (providers.length === 0) {
|
|
403
|
+
grok.shell.error('No monomer library providers available to save the merged library.');
|
|
404
|
+
return; // I mean, this should not happen, but ....
|
|
405
|
+
}
|
|
406
|
+
const providersInput = ui.input.choice('Storage', {items: providers.map((p) => p.name), value: providers[0].name,
|
|
407
|
+
nullable: false, tooltipText: 'Storage provider for saving new monomer library'});
|
|
408
|
+
|
|
409
|
+
const getFileNameInputValue = () => {
|
|
410
|
+
let fileName = newFileNameInput.value.trim();
|
|
411
|
+
if (!fileName)
|
|
412
|
+
fileName = 'New';
|
|
413
|
+
if (!fileName.toLowerCase().endsWith('.json'))
|
|
414
|
+
fileName += '.json';
|
|
415
|
+
return fileName;
|
|
416
|
+
};
|
|
384
417
|
dialog
|
|
418
|
+
.add(providersInput)
|
|
385
419
|
.add(newFileNameInput)
|
|
386
420
|
.add(ui.divText(`Total monomers: ${libJSON.length}`))
|
|
387
421
|
.addButton('Download', () => { DG.Utils.download(getFileNameInputValue(), JSON.stringify(libJSON)); })
|
|
388
422
|
.addButton('Save', async () => {
|
|
423
|
+
if (!newFileNameInput.value || !newFileNameInput.value.trim() || !providersInput.value) {
|
|
424
|
+
providersInput.validate();
|
|
425
|
+
newFileNameInput.validate(); // this will force showing validation error
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
389
428
|
dialog.close();
|
|
390
|
-
const fileName =
|
|
429
|
+
const fileName = newFileNameInput.value!;
|
|
391
430
|
const content = JSON.stringify(libJSON);
|
|
392
|
-
const fileManager = await this.libManager.getFileManager();
|
|
393
431
|
this._view && ui.setUpdateIndicator(this._view.root, true);
|
|
394
432
|
try {
|
|
395
|
-
|
|
433
|
+
const provider = providers.find((p) => p.name === providersInput.value)!; // should not be null
|
|
434
|
+
await provider.addOrUpdateLibraryString(fileName, content); // we will reload after updating settings
|
|
396
435
|
const settings = await getUserLibSettings();
|
|
397
436
|
settings.exclude = validLibPaths; // exclude all previous libraries
|
|
398
437
|
await setUserLibSettings(settings);
|
|
399
|
-
await this.libManager.
|
|
438
|
+
await this.libManager.loadMonomerLib(true);
|
|
400
439
|
await MonomerLibraryManagerWidget.reloadWidget();
|
|
401
440
|
} catch (e) {
|
|
402
441
|
grok.shell.error(`Failed to save library ${fileName}. see console for details.`);
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import {HelmTypes} from '@datagrok-libraries/bio/src/helm/consts';
|
|
2
|
-
import {Helm} from '../helm-to-molfile/converter/helm';
|
|
3
|
-
import {HelmType} from '@datagrok-libraries/bio/src/helm/types';
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* MonomerColors class from HelmWebEditor for natural monomers
|
|
@@ -8,64 +6,64 @@ import {HelmType} from '@datagrok-libraries/bio/src/helm/types';
|
|
|
8
6
|
export const naturalMonomerColors = {
|
|
9
7
|
[HelmTypes.BASE]: {
|
|
10
8
|
// Chromatogram palette // HELMWebEditor monomerColors
|
|
11
|
-
A:
|
|
12
|
-
G:
|
|
13
|
-
T:
|
|
14
|
-
C:
|
|
15
|
-
U:
|
|
9
|
+
A: '#20E040', // "#A0A0FF",
|
|
10
|
+
G: '#040404', // "#FF7070",
|
|
11
|
+
T: '#FF8080', // "#A0FFA0",
|
|
12
|
+
C: '#2060FF', // "#FF8C4B",
|
|
13
|
+
U: '#FF8080', // "#FF8080"
|
|
16
14
|
},
|
|
17
15
|
|
|
18
16
|
[HelmTypes.NUCLEOTIDE]: {
|
|
19
17
|
// Chromatogram palette // HELMWebEditor monomerColors
|
|
20
|
-
A:
|
|
21
|
-
G:
|
|
22
|
-
T:
|
|
23
|
-
C:
|
|
24
|
-
U:
|
|
18
|
+
A: '#20E040', // "#A0A0FF",
|
|
19
|
+
G: '#040404', // "#FF7070",
|
|
20
|
+
T: '#FF8080', // "#A0FFA0",
|
|
21
|
+
C: '#2060FF', // "#FF8C4B",
|
|
22
|
+
U: '#FF8080', // "#FF8080"
|
|
25
23
|
},
|
|
26
24
|
|
|
27
25
|
[HelmTypes.LINKER]: {
|
|
28
|
-
P:
|
|
29
|
-
p:
|
|
26
|
+
P: '#9aa5e1',
|
|
27
|
+
p: '#9aa5e1'
|
|
30
28
|
},
|
|
31
29
|
|
|
32
30
|
[HelmTypes.SUGAR]: {
|
|
33
|
-
R:
|
|
34
|
-
r:
|
|
31
|
+
R: '#7a85c1',
|
|
32
|
+
r: '#7a85c1',
|
|
35
33
|
// TODO: deoxyribose
|
|
36
34
|
},
|
|
37
35
|
|
|
38
36
|
[HelmTypes.AA]: {
|
|
39
37
|
// GrokGroups palette // HELMWebEditor monomerColors
|
|
40
|
-
A:
|
|
41
|
-
R:
|
|
42
|
-
N:
|
|
43
|
-
D:
|
|
44
|
-
C:
|
|
45
|
-
E:
|
|
46
|
-
Q:
|
|
47
|
-
G:
|
|
48
|
-
H:
|
|
49
|
-
I:
|
|
50
|
-
L:
|
|
51
|
-
K:
|
|
52
|
-
M:
|
|
53
|
-
F:
|
|
54
|
-
P:
|
|
55
|
-
S:
|
|
56
|
-
T:
|
|
57
|
-
W:
|
|
58
|
-
Y:
|
|
59
|
-
V:
|
|
38
|
+
A: 'rgb(44,160,44)', // "#C8C8C8",
|
|
39
|
+
R: 'rgb(23,190,207)', // "#145AFF",
|
|
40
|
+
N: 'rgb(235,137,70)', // "#00DCDC",
|
|
41
|
+
D: 'rgb(31,119,180)', // "#E60A0A",
|
|
42
|
+
C: 'rgb(188,189,34)', // "#E6E600",
|
|
43
|
+
E: 'rgb(31, 120, 150)', // "#00DCDC",
|
|
44
|
+
Q: 'rgb(205, 111, 71)', // "#E60A0A",
|
|
45
|
+
G: 'rgb(214,39,40)', // "#EBEBEB",
|
|
46
|
+
H: 'rgb(158,218,229)', // "#8282D2",
|
|
47
|
+
I: 'rgb(23,103,57)', // "#0F820F",
|
|
48
|
+
L: 'rgb(30,110,96)', // "#0F820F",
|
|
49
|
+
K: 'rgb(108, 218, 229)', //"#145AFF",
|
|
50
|
+
M: 'rgb(60,131,95)', // "#E6E600",
|
|
51
|
+
F: 'rgb(24,110,79)', // "#3232AA",
|
|
52
|
+
P: 'rgb(255,152,150)', // "#DC9682",
|
|
53
|
+
S: 'rgb(255,187,120)', // "#FA9600",
|
|
54
|
+
T: 'rgb(245,167,100)', // "#FA9600",
|
|
55
|
+
W: 'rgb(182, 223, 138)', // "#B45AB4",
|
|
56
|
+
Y: 'rgb(152,223,138)', // "#3232AA",
|
|
57
|
+
V: 'rgb(74,160,74)', // "#0F820F",
|
|
60
58
|
},
|
|
61
59
|
|
|
62
60
|
[HelmTypes.CHEM]: {
|
|
63
|
-
R:
|
|
61
|
+
R: '#eeeeee',
|
|
64
62
|
},
|
|
65
63
|
|
|
66
64
|
[HelmTypes.BLOB]: {
|
|
67
|
-
B:
|
|
68
|
-
G:
|
|
65
|
+
B: '#999999',
|
|
66
|
+
G: '#e2e2e2'
|
|
69
67
|
}
|
|
70
68
|
};
|
|
71
69
|
|
|
@@ -6,7 +6,7 @@ import * as DG from 'datagrok-api/dg';
|
|
|
6
6
|
import wu from 'wu';
|
|
7
7
|
import {Observable, Subject} from 'rxjs';
|
|
8
8
|
|
|
9
|
-
import {IMonomerLibBase, Monomer, RGroup} from '@datagrok-libraries/bio/src/types/
|
|
9
|
+
import {IMonomerLibBase, Monomer, RGroup} from '@datagrok-libraries/bio/src/types/monomer-library';
|
|
10
10
|
import {HelmAtom, HelmType, IMonomerColors,
|
|
11
11
|
IWebEditorMonomer, MonomerType, PolymerType} from '@datagrok-libraries/bio/src/helm/types';
|
|
12
12
|
import {getMonomerHandleArgs} from '@datagrok-libraries/bio/src/helm/helm-helper';
|
|
@@ -23,6 +23,7 @@ import {LibraryWebEditorMonomer} from './web-editor-monomer-of-library';
|
|
|
23
23
|
import {naturalMonomerColors} from './monomer-colors';
|
|
24
24
|
|
|
25
25
|
import {_package} from '../../package';
|
|
26
|
+
import {MonomerLibData} from '@datagrok-libraries/bio/src/types/monomer-library';
|
|
26
27
|
|
|
27
28
|
const monomerRe = /[\w()]+/;
|
|
28
29
|
//** Do not mess with monomer symbol with parenthesis enclosed in square brackets */
|
|
@@ -34,8 +35,6 @@ const drawMoleculeCall = (s: string) => {
|
|
|
34
35
|
return canvas;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
|
-
export type MonomerLibDataType = { [polymerType: string]: { [monomerSymbol: string]: Monomer } };
|
|
38
|
-
|
|
39
38
|
const whiteColorV = new Vector([255.0, 255.0, 255.0]);
|
|
40
39
|
const blackColorV = new Vector([0.0, 0.0, 0.0]);
|
|
41
40
|
const maxTextColorVLen = vectorLength(whiteColorV) * 0.7;
|
|
@@ -50,7 +49,7 @@ export class MonomerLibBase implements IMonomerLibBase {
|
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
constructor(
|
|
53
|
-
protected _monomers:
|
|
52
|
+
protected _monomers: MonomerLibData,
|
|
54
53
|
public readonly source: string,
|
|
55
54
|
) {
|
|
56
55
|
this._isEmpty = !this._monomers || Object.keys(this._monomers).length === 0 ||
|
|
@@ -12,16 +12,17 @@ import {
|
|
|
12
12
|
MonomerSetType, PolymerType,
|
|
13
13
|
} from '@datagrok-libraries/bio/src/helm/types';
|
|
14
14
|
import {IMonomerLibBase, IMonomerLib, Monomer,
|
|
15
|
-
MonomerLibData, MonomerLibSummaryType} from '@datagrok-libraries/bio/src/types';
|
|
15
|
+
MonomerLibData, MonomerLibSummaryType} from '@datagrok-libraries/bio/src/types/monomer-library';
|
|
16
16
|
import {MolfileHandler} from '@datagrok-libraries/chem-meta/src/parsing-utils/molfile-handler';
|
|
17
17
|
import {helmTypeToPolymerType} from '@datagrok-libraries/bio/src/monomer-works/monomer-works';
|
|
18
18
|
import {getUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
19
19
|
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
20
20
|
|
|
21
|
-
import {MonomerLibBase
|
|
21
|
+
import {MonomerLibBase} from './monomer-lib-base';
|
|
22
22
|
|
|
23
23
|
import {_package} from '../../package';
|
|
24
24
|
|
|
25
|
+
//@ts-ignore
|
|
25
26
|
import '../../../css/cell-renderer.css';
|
|
26
27
|
|
|
27
28
|
/** Wrapper for monomers obtained from different sources. For managing monomere
|
|
@@ -38,7 +39,7 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
|
|
|
38
39
|
private duplicatesNotified: boolean = false;
|
|
39
40
|
|
|
40
41
|
constructor(
|
|
41
|
-
monomers:
|
|
42
|
+
monomers: MonomerLibData,
|
|
42
43
|
source: string,
|
|
43
44
|
public readonly error: string | undefined = undefined,
|
|
44
45
|
) {
|
|
@@ -158,7 +159,7 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
|
|
|
158
159
|
this._isEmpty = this.isEmpty && lib.isEmpty;
|
|
159
160
|
}
|
|
160
161
|
|
|
161
|
-
public updateLibs(libList: IMonomerLib[], reload: boolean = false): void {
|
|
162
|
+
public async updateLibs(libList: IMonomerLib[], reload: boolean = false): Promise<void> {
|
|
162
163
|
if (reload) {
|
|
163
164
|
this._monomers = {};
|
|
164
165
|
this._isEmpty = true;
|
|
@@ -167,9 +168,8 @@ export class MonomerLib extends MonomerLibBase implements IMonomerLib {
|
|
|
167
168
|
for (const lib of libList)
|
|
168
169
|
if (!lib.error) this._updateLibInt(lib);
|
|
169
170
|
if (Object.entries(this.duplicateMonomers).length > 0) {
|
|
170
|
-
getUserLibSettings()
|
|
171
|
-
|
|
172
|
-
});
|
|
171
|
+
const settings = await getUserLibSettings();
|
|
172
|
+
this.assignDuplicatePreferences(settings);
|
|
173
173
|
} else
|
|
174
174
|
this._duplicatesHandled = true;
|
|
175
175
|
|
|
@@ -3,11 +3,12 @@ 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 {Monomer} from '@datagrok-libraries/bio/src/types';
|
|
6
|
+
import {Monomer} from '@datagrok-libraries/bio/src/types/monomer-library';
|
|
7
7
|
import {UserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/types';
|
|
8
8
|
import {getUserLibSettings, setUserLibSettings} from '@datagrok-libraries/bio/src/monomer-works/lib-settings';
|
|
9
|
-
import '../../../../css/monomer-manager.css';
|
|
10
9
|
import {MonomerLibManager} from '../lib-manager';
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import '../../../../css/monomer-manager.css';
|
|
11
12
|
|
|
12
13
|
class MonomerCard {
|
|
13
14
|
root: HTMLElement = ui.divV([], {classes: 'monomer-card-root'});
|
|
@@ -109,7 +110,6 @@ export class DuplicateMonomerManager {
|
|
|
109
110
|
this.settings = await getUserLibSettings();
|
|
110
111
|
const libManager = await MonomerLibManager.getInstance();
|
|
111
112
|
await libManager.awaitLoaded();
|
|
112
|
-
await libManager.loadLibrariesPromise;
|
|
113
113
|
this.monomers = libManager.duplicateMonomers;
|
|
114
114
|
this.monomerCardRows = [];
|
|
115
115
|
for (const polymerType in this.monomers) {
|