@datagrok/hit-triage 1.2.1 → 1.3.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/CHANGELOG.md +4 -0
- 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/Hit Design/campaigns/DMT1-1/campaign.json +69 -1
- package/files/Hit Design/campaigns/DMT2-1/campaign.json +84 -1
- package/files/PeptiHit/campaigns/PHD-1/campaign.json +1 -0
- package/files/PeptiHit/campaigns/PHD-1/enriched_table.csv +10 -0
- package/files/PeptiHit/campaigns/PHD-2/campaign.json +1 -0
- package/files/PeptiHit/campaigns/PHD-2/enriched_table.csv +82 -0
- package/files/PeptiHit/templates/Peptide hits Demo.json +1 -0
- package/images/icons/pepti-hit-icon.png +0 -0
- package/package.json +4 -4
- package/src/app/accordeons/layout-input.ts +2 -2
- package/src/app/accordeons/new-hit-design-campaign-accordeon.ts +12 -2
- package/src/app/accordeons/new-hit-design-template-accordeon.ts +12 -11
- package/src/app/accordeons/new-template-accordeon.ts +6 -9
- package/src/app/base-view.ts +2 -2
- package/src/app/consts.ts +1 -1
- package/src/app/dialogs/functions-dialog.ts +3 -3
- package/src/app/hit-app-base.ts +6 -3
- package/src/app/hit-design-app.ts +194 -213
- package/src/app/hit-design-views/info-view.ts +39 -33
- package/src/app/hit-design-views/tiles-view.ts +6 -0
- package/src/app/hit-triage-app.ts +1 -1
- package/src/app/pepti-hit-app.ts +221 -0
- package/src/app/pepti-hits-views/info-view.ts +49 -0
- package/src/app/types.ts +5 -1
- package/src/package.ts +47 -22
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as grok from 'datagrok-api/grok';
|
|
2
2
|
import * as ui from 'datagrok-api/ui';
|
|
3
3
|
import * as DG from 'datagrok-api/dg';
|
|
4
|
-
import {HitDesignCampaign, HitDesignTemplate, HitTriageCampaignStatus, IFunctionArgs} from './types';
|
|
4
|
+
import {AppName, HitDesignCampaign, HitDesignTemplate, HitTriageCampaignStatus, IFunctionArgs} from './types';
|
|
5
5
|
import {HitDesignInfoView} from './hit-design-views/info-view';
|
|
6
6
|
import {CampaignIdKey, CampaignJsonName, CampaignTableName,
|
|
7
|
-
|
|
7
|
+
HTQueryPrefix, HTScriptPrefix, HitDesignCampaignIdKey,
|
|
8
8
|
HitDesignMolColName, TileCategoriesColName, ViDColName, i18n} from './consts';
|
|
9
9
|
import {calculateColumns, calculateSingleCellValues, getNewVid} from './utils/calculate-single-cell';
|
|
10
10
|
import '../../css/hit-triage.css';
|
|
@@ -19,41 +19,39 @@ import {Subscription} from 'rxjs';
|
|
|
19
19
|
import {filter} from 'rxjs/operators';
|
|
20
20
|
import {defaultPermissions, PermissionsDialog} from './dialogs/permissions-dialog';
|
|
21
21
|
|
|
22
|
-
export class HitDesignApp extends HitAppBase<
|
|
22
|
+
export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> extends HitAppBase<T> {
|
|
23
23
|
multiView: DG.MultiView;
|
|
24
|
-
|
|
25
|
-
private _infoView: HitDesignInfoView;
|
|
24
|
+
protected _infoView: HitDesignInfoView;
|
|
26
25
|
get infoView(): HitDesignInfoView {return this._infoView;}
|
|
27
|
-
|
|
26
|
+
protected _designView?: DG.TableView;
|
|
28
27
|
public _submitView?: HitDesignSubmitView;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
private _campaign?: HitDesignCampaign;
|
|
28
|
+
protected _designViewName = 'Design';
|
|
29
|
+
protected _filePath = `System.AppData/HitTriage/${this.appName}/campaigns`;
|
|
30
|
+
protected _campaignId?: string;
|
|
31
|
+
protected _molColName: string = HitDesignMolColName;
|
|
32
|
+
protected _campaign?: HitDesignCampaign;
|
|
35
33
|
public campaignProps: {[key: string]: any} = {};
|
|
36
|
-
private processedValues: string[] = [];
|
|
37
|
-
private _extraStageColsCount = 0;
|
|
38
34
|
|
|
39
|
-
|
|
35
|
+
protected currentDesignViewId?: string;
|
|
40
36
|
public mainView: DG.ViewBase;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
super(c);
|
|
45
|
-
this._infoView =
|
|
37
|
+
protected get version() {return this._campaign?.version ?? 0;};
|
|
38
|
+
constructor(c: DG.FuncCall, an: AppName = 'Hit Design',
|
|
39
|
+
infoViewConstructor: (app: HitDesignApp) => HitDesignInfoView = (app) => new HitDesignInfoView(app)) {
|
|
40
|
+
super(c, an);
|
|
41
|
+
this._infoView = infoViewConstructor(this);
|
|
46
42
|
this.multiView = new DG.MultiView({viewFactories: {[this._infoView.name]: () => this._infoView}});
|
|
47
43
|
this.multiView.tabs.onTabChanged.subscribe((_) => {
|
|
48
44
|
if (this.multiView.currentView instanceof HitBaseView)
|
|
49
|
-
(this.multiView.currentView as HitBaseView<
|
|
45
|
+
(this.multiView.currentView as HitBaseView<T, typeof this>).onActivated();
|
|
50
46
|
});
|
|
51
47
|
this.multiView.parentCall = c;
|
|
52
48
|
|
|
53
49
|
this.mainView = this.multiView;
|
|
54
|
-
|
|
50
|
+
this._initViewChangeSub();
|
|
51
|
+
}
|
|
55
52
|
|
|
56
|
-
|
|
53
|
+
_initViewChangeSub() {
|
|
54
|
+
this.multiView.subs.push(grok.events.onCurrentViewChanged.subscribe(async () => {
|
|
57
55
|
try {
|
|
58
56
|
if (grok.shell.v?.name === this.currentDesignViewId) {
|
|
59
57
|
grok.shell.windows.showHelp = false;
|
|
@@ -61,7 +59,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
61
59
|
this.setBaseUrl();
|
|
62
60
|
modifyUrl(CampaignIdKey, this._campaignId ?? this._campaign?.name ?? '');
|
|
63
61
|
|
|
64
|
-
const {sub} = addBreadCrumbsToRibbons(grok.shell.v,
|
|
62
|
+
const {sub} = addBreadCrumbsToRibbons(grok.shell.v, this.appName, grok.shell.v?.name, () => {
|
|
65
63
|
grok.shell.v = this.mainView;
|
|
66
64
|
this._designView?.close();
|
|
67
65
|
this._infoView.init();
|
|
@@ -71,18 +69,18 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
71
69
|
} catch (e) {
|
|
72
70
|
console.error(e);
|
|
73
71
|
}
|
|
74
|
-
});
|
|
72
|
+
}));
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
public async setTemplate(template:
|
|
75
|
+
public async setTemplate(template: T, campaignId?: string) {
|
|
78
76
|
if (!campaignId) {
|
|
79
77
|
this._designView?.dataFrame && grok.shell.closeTable(this._designView.dataFrame);
|
|
80
78
|
this._designView = undefined;
|
|
81
|
-
campaignId = await this.getNewCampaignName(
|
|
79
|
+
campaignId = await this.getNewCampaignName(`${this.appName}/campaigns`, template.key);
|
|
82
80
|
modifyUrl(HitDesignCampaignIdKey, campaignId);
|
|
83
|
-
this._filePath = `System.AppData/HitTriage/
|
|
81
|
+
this._filePath = `System.AppData/HitTriage/${this.appName}/campaigns/${campaignId}/${CampaignTableName}`;
|
|
84
82
|
} else {
|
|
85
|
-
const fileLoc =
|
|
83
|
+
const fileLoc = `System.AppData/HitTriage/${this.appName}/campaigns`;
|
|
86
84
|
this._filePath = this.campaign?.savePath ?? `${fileLoc}/${campaignId}/${CampaignTableName}`;
|
|
87
85
|
this.dataFrame = await grok.dapi.files.readCsv(this._filePath);
|
|
88
86
|
if (this._campaign?.columnSemTypes) {
|
|
@@ -108,7 +106,6 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
108
106
|
}
|
|
109
107
|
await this.dataFrame.meta.detectSemanticTypes();
|
|
110
108
|
this._molColName = this.dataFrame.columns.bySemType(DG.SEMTYPE.MOLECULE)?.name ?? HitDesignMolColName;
|
|
111
|
-
this._dfName = this.dataFrame.name ??= campaignId;
|
|
112
109
|
this._campaignId = campaignId;
|
|
113
110
|
this.template = template;
|
|
114
111
|
|
|
@@ -118,8 +115,6 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
118
115
|
await this.setCanEdit(this.campaign);
|
|
119
116
|
else
|
|
120
117
|
this.hasEditPermission = true; // if the campaign is new, obviously the user can edit it
|
|
121
|
-
|
|
122
|
-
this._extraStageColsCount = this.dataFrame!.rowCount - this.dataFrame.filter.trueCount;
|
|
123
118
|
const designV = this.designView;
|
|
124
119
|
this.currentDesignViewId = designV.name;
|
|
125
120
|
this.setBaseUrl();
|
|
@@ -169,34 +164,171 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
169
164
|
this.cacheDuplicateVIDs();
|
|
170
165
|
return this._duplicateVidCache;
|
|
171
166
|
}
|
|
172
|
-
private getDesignView(): DG.TableView {
|
|
173
|
-
const subs: Subscription[] = [];
|
|
174
|
-
const isNew = this.dataFrame!.col(this.molColName)?.toList().every((m) => !m && m === '');
|
|
175
|
-
const view = grok.shell.addTableView(this.dataFrame!);
|
|
176
|
-
this._designViewName = this.campaign?.name ?? this._designViewName;
|
|
177
|
-
view.name = this._designViewName;
|
|
178
|
-
this.processedValues = this.dataFrame!.getCol(this.molColName).toList();
|
|
179
167
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
168
|
+
async performSingleCellCalculations(newValueIdx: number, newValue?: string) {
|
|
169
|
+
const computeObj = this.template!.compute;
|
|
170
|
+
if (!newValue || newValue === '')
|
|
171
|
+
return;
|
|
184
172
|
|
|
185
|
-
|
|
173
|
+
const calcDf =
|
|
186
174
|
await calculateSingleCellValues(
|
|
187
175
|
newValue, computeObj.descriptors.args, computeObj.functions, computeObj.scripts, computeObj.queries);
|
|
188
176
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
this.dataFrame!.col(col.name)!.set(newValueIdx, col.get(0), false);
|
|
177
|
+
for (const col of calcDf.columns.toList()) {
|
|
178
|
+
if (col.name === HitDesignMolColName) continue;
|
|
179
|
+
if (!this.dataFrame!.columns.contains(col.name)) {
|
|
180
|
+
const newCol = this.dataFrame!.columns.addNew(col.name, col.type);
|
|
181
|
+
newCol.semType = col.semType;
|
|
196
182
|
}
|
|
183
|
+
this.dataFrame!.col(col.name)!.set(newValueIdx, col.get(0), false);
|
|
184
|
+
}
|
|
197
185
|
this.dataFrame!.fireValuesChanged();
|
|
198
186
|
this.saveCampaign(undefined, false);
|
|
199
|
-
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
protected initDesignViewRibbons(view: DG.TableView, subs: Subscription[]) {
|
|
190
|
+
const onRemoveSub = grok.events.onViewRemoved.subscribe((v) => {
|
|
191
|
+
if (v.id === view?.id) {
|
|
192
|
+
subs.forEach((s) => s.unsubscribe());
|
|
193
|
+
onRemoveSub.unsubscribe();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
const ribbons = view?.getRibbonPanels();
|
|
197
|
+
if (ribbons) {
|
|
198
|
+
const hasSubmit = checkRibbonsHaveSubmit(ribbons);
|
|
199
|
+
if (!hasSubmit) {
|
|
200
|
+
const getComputeDialog = async () => {
|
|
201
|
+
chemFunctionsDialog(this, async (resultMap) => {
|
|
202
|
+
const oldDescriptors = this.template!.compute.descriptors.args;
|
|
203
|
+
const oldFunctions = this.template!.compute.functions;
|
|
204
|
+
const oldScripts = this.template!.compute.scripts ?? [];
|
|
205
|
+
const oldQueries = this.template!.compute.queries ?? [];
|
|
206
|
+
const newDescriptors = resultMap.descriptors;
|
|
207
|
+
const newComputeObj = {
|
|
208
|
+
descriptors: {
|
|
209
|
+
enabled: !!resultMap?.descriptors?.length,
|
|
210
|
+
args: resultMap?.descriptors ?? [],
|
|
211
|
+
},
|
|
212
|
+
functions: Object.entries(resultMap?.externals ?? {}).map(([funcName, args]) => {
|
|
213
|
+
const splitFunc = funcName.split(':');
|
|
214
|
+
return ({
|
|
215
|
+
name: splitFunc[1],
|
|
216
|
+
package: splitFunc[0],
|
|
217
|
+
args: args,
|
|
218
|
+
});
|
|
219
|
+
}),
|
|
220
|
+
scripts: Object.entries(resultMap?.scripts ?? {})
|
|
221
|
+
.filter(([name, _]) => name.startsWith(HTScriptPrefix) && name.split(':').length === 3)
|
|
222
|
+
.map(([scriptId, args]) => {
|
|
223
|
+
const scriptNameParts = scriptId.split(':');
|
|
224
|
+
return ({
|
|
225
|
+
name: scriptNameParts[1] ?? '',
|
|
226
|
+
id: scriptNameParts[2] ?? '',
|
|
227
|
+
args: args,
|
|
228
|
+
});
|
|
229
|
+
}),
|
|
230
|
+
queries: Object.entries(resultMap?.queries ?? {})
|
|
231
|
+
.filter(([name, _]) => name.startsWith(HTQueryPrefix) && name.split(':').length === 3)
|
|
232
|
+
.map(([queryName, args]) => {
|
|
233
|
+
const queryNameParts = queryName.split(':');
|
|
234
|
+
return ({
|
|
235
|
+
name: queryNameParts[1] ?? '',
|
|
236
|
+
id: queryNameParts[2] ?? '',
|
|
237
|
+
args: args,
|
|
238
|
+
});
|
|
239
|
+
}),
|
|
240
|
+
};
|
|
241
|
+
this.template!.compute = newComputeObj;
|
|
242
|
+
this.campaign!.template = this.template;
|
|
243
|
+
const uncalculatedDescriptors = newDescriptors.filter((d) => !oldDescriptors.includes(d));
|
|
244
|
+
|
|
245
|
+
const newFunctions: {[_: string]: IFunctionArgs} = {};
|
|
246
|
+
Object.entries(resultMap?.externals ?? {})
|
|
247
|
+
.filter(([funcName, args]) => {
|
|
248
|
+
const oldFunc = oldFunctions.find((f) => `${f.package}:${f.name}` === funcName);
|
|
249
|
+
if (!oldFunc)
|
|
250
|
+
return true;
|
|
251
|
+
return !Object.entries(args).every(([key, value]) => oldFunc.args[key] === value);
|
|
252
|
+
}).forEach(([funcName, args]) => {newFunctions[funcName] = args;});
|
|
253
|
+
|
|
254
|
+
const newScripts: {[_: string]: IFunctionArgs} = {};
|
|
255
|
+
Object.entries(resultMap?.scripts ?? {})
|
|
256
|
+
.filter(([scriptName, args]) => {
|
|
257
|
+
const oldScript = oldScripts.find((f) => `${HTScriptPrefix}:${f.name}:${f.id}` === scriptName);
|
|
258
|
+
if (!oldScript)
|
|
259
|
+
return true;
|
|
260
|
+
return !Object.entries(args).every(([key, value]) => oldScript.args[key] === value);
|
|
261
|
+
}).forEach(([scriptName, args]) => {newScripts[scriptName] = args;});
|
|
262
|
+
|
|
263
|
+
const newQueries: {[_: string]: IFunctionArgs} = {};
|
|
264
|
+
Object.entries(resultMap?.queries ?? {})
|
|
265
|
+
.filter(([queryName, args]) => {
|
|
266
|
+
const oldQuery = oldQueries.find((f) => `${HTQueryPrefix}:${f.name}:${f.id}` === queryName);
|
|
267
|
+
if (!oldQuery)
|
|
268
|
+
return true;
|
|
269
|
+
return !Object.entries(args).every(([key, value]) => oldQuery.args[key] === value);
|
|
270
|
+
}).forEach(([queryName, args]) => {newQueries[queryName] = args;});
|
|
271
|
+
ui.setUpdateIndicator(view.grid.root, true);
|
|
272
|
+
try {
|
|
273
|
+
await calculateColumns({descriptors: uncalculatedDescriptors, externals: newFunctions,
|
|
274
|
+
scripts: newScripts, queries: newQueries}, this.dataFrame!, this.molColName!);
|
|
275
|
+
this.dataFrame!.fireValuesChanged();
|
|
276
|
+
} finally {
|
|
277
|
+
ui.setUpdateIndicator(view.grid.root, false);
|
|
278
|
+
this.saveCampaign(undefined, false);
|
|
279
|
+
}
|
|
280
|
+
}, () => null, this.campaign?.template!, true);
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const calculateRibbon = ui.iconFA('wrench', getComputeDialog, 'Calculate additional properties');
|
|
284
|
+
const addNewRowButton = ui.icons.add(() => {this.dataFrame?.rows.addNew(null, true);}, 'Add new row');
|
|
285
|
+
const permissionsButton = ui.iconFA('share', async () => {
|
|
286
|
+
await (new PermissionsDialog(this.campaign?.permissions)).show((res) => {
|
|
287
|
+
this.campaign!.permissions = res;
|
|
288
|
+
this.saveCampaign(undefined, true);
|
|
289
|
+
});
|
|
290
|
+
}, 'Edit campaign permissions');
|
|
291
|
+
const tilesButton = ui.bigButton('Progress tracker', () => {
|
|
292
|
+
getTilesViewDialog(this, () => this._designView ?? null);
|
|
293
|
+
});
|
|
294
|
+
|
|
295
|
+
const submitButton = ui.bigButton('Submit', () => {
|
|
296
|
+
const dialogContent = this._submitView?.render();
|
|
297
|
+
if (dialogContent) {
|
|
298
|
+
const dlg = ui.dialog('Submit');
|
|
299
|
+
dlg.add(dialogContent);
|
|
300
|
+
dlg.addButton('Save', ()=>{this.saveCampaign(); dlg.close();});
|
|
301
|
+
dlg.addButton('Submit', ()=>{this._submitView?.submit(); dlg.close();});
|
|
302
|
+
dlg.show();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
submitButton.classList.add('hit-design-submit-button');
|
|
306
|
+
const ribbonButtons: HTMLElement[] = [submitButton];
|
|
307
|
+
if (this.template?.stages?.length ?? 0 > 0)
|
|
308
|
+
ribbonButtons.unshift(tilesButton);
|
|
309
|
+
if (this.campaign && this.template && !this.campaign.template)
|
|
310
|
+
this.campaign.template = this.template;
|
|
311
|
+
|
|
312
|
+
if (this.hasEditPermission)
|
|
313
|
+
ribbonButtons.unshift(permissionsButton);
|
|
314
|
+
ribbonButtons.unshift(calculateRibbon);
|
|
315
|
+
ribbonButtons.unshift(addNewRowButton);
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
ribbons.push(ribbonButtons);
|
|
319
|
+
// remove project save button from the ribbon
|
|
320
|
+
view.setRibbonPanels(ribbons);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return view;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
protected getDesignView(): DG.TableView {
|
|
327
|
+
const subs: Subscription[] = [];
|
|
328
|
+
const isNew = this.dataFrame!.col(this.molColName)?.toList().every((m) => !m && m === '');
|
|
329
|
+
const view = grok.shell.addTableView(this.dataFrame!);
|
|
330
|
+
this._designViewName = this.campaign?.name ?? this._designViewName;
|
|
331
|
+
view.name = this._designViewName;
|
|
200
332
|
|
|
201
333
|
view._onAdded();
|
|
202
334
|
const layoutViewState = this._campaign?.layout ?? this.template?.layoutViewState;
|
|
@@ -216,7 +348,6 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
216
348
|
subs.push(this.dataFrame!.onRowsAdded.pipe(filter(() => !this.isJoining))
|
|
217
349
|
.subscribe(() => { // TODO, insertion of rows in the middle
|
|
218
350
|
try {
|
|
219
|
-
this.processedValues = this.dataFrame!.getCol(this.molColName).toList();
|
|
220
351
|
if (this.template!.stages?.length > 0) {
|
|
221
352
|
for (let i = 0; i < this.dataFrame!.rowCount; i++) {
|
|
222
353
|
const colVal = this.dataFrame!.col(TileCategoriesColName)!.get(i);
|
|
@@ -240,13 +371,6 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
240
371
|
//const lastCell = view.grid.cell(this.molColName, this.dataFrame!.rowCount - 1);
|
|
241
372
|
//view.grid.onCellValueEdited
|
|
242
373
|
}));
|
|
243
|
-
this.dataFrame && subs.push(this.dataFrame?.onRowsRemoved.subscribe(() => {
|
|
244
|
-
try {
|
|
245
|
-
this.processedValues = this.dataFrame!.getCol(this.molColName).toList();
|
|
246
|
-
} catch (e) {
|
|
247
|
-
console.error(e);
|
|
248
|
-
}
|
|
249
|
-
}));
|
|
250
374
|
subs.push(grok.events.onContextMenu.subscribe((args) => {
|
|
251
375
|
try {
|
|
252
376
|
const viewer: DG.Viewer = args?.args?.context;
|
|
@@ -266,18 +390,10 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
266
390
|
});
|
|
267
391
|
menu.item('Duplicate molecule', () => {
|
|
268
392
|
try {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
if (!cell)
|
|
274
|
-
continue;
|
|
275
|
-
if (cell.cell.value === '' || cell.cell.value === null)
|
|
276
|
-
lastCell = cell;
|
|
277
|
-
}
|
|
278
|
-
if (lastCell)
|
|
279
|
-
lastCell.cell.value = args?.args?.item?.cell?.value ?? '';
|
|
280
|
-
// grok.functions.call('Chem:editMoleculeCell', {cell: lastCell});
|
|
393
|
+
const row = this.dataFrame!.rows.addNew(null, true);
|
|
394
|
+
const cell = row.get(this.molColName);
|
|
395
|
+
if (cell != null && row.idx > -1)
|
|
396
|
+
this.dataFrame!.cell(row.idx, this.molColName).value = args?.args?.item?.cell?.value ?? '';
|
|
281
397
|
} catch (e) {
|
|
282
398
|
console.error(e);
|
|
283
399
|
}
|
|
@@ -288,7 +404,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
288
404
|
if (cellValue && (cellIndex ?? -1) > -1) {
|
|
289
405
|
menu.item('Re-Run Calculations', async () => {
|
|
290
406
|
try {
|
|
291
|
-
await performSingleCellCalculations(cellIndex, cellValue);
|
|
407
|
+
await this.performSingleCellCalculations(cellIndex, cellValue);
|
|
292
408
|
} catch (e) {
|
|
293
409
|
console.error(e);
|
|
294
410
|
}
|
|
@@ -352,7 +468,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
352
468
|
|
|
353
469
|
this.dataFrame!.col(ViDColName)!.set(newValueIdx, newVid, false);
|
|
354
470
|
|
|
355
|
-
performSingleCellCalculations(newValueIdx, newValue);
|
|
471
|
+
this.performSingleCellCalculations(newValueIdx, newValue);
|
|
356
472
|
} catch (e) {
|
|
357
473
|
console.error(e);
|
|
358
474
|
}
|
|
@@ -373,141 +489,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
373
489
|
}
|
|
374
490
|
} catch (e) {}
|
|
375
491
|
}));
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
const onRemoveSub = grok.events.onViewRemoved.subscribe((v) => {
|
|
379
|
-
if (v.id === view?.id) {
|
|
380
|
-
subs.forEach((s) => s.unsubscribe());
|
|
381
|
-
onRemoveSub.unsubscribe();
|
|
382
|
-
}
|
|
383
|
-
});
|
|
384
|
-
const ribbons = view?.getRibbonPanels();
|
|
385
|
-
if (ribbons) {
|
|
386
|
-
const hasSubmit = checkRibbonsHaveSubmit(ribbons);
|
|
387
|
-
if (!hasSubmit) {
|
|
388
|
-
const getComputeDialog = async () => {
|
|
389
|
-
chemFunctionsDialog(this, async (resultMap) => {
|
|
390
|
-
const oldDescriptors = this.template!.compute.descriptors.args;
|
|
391
|
-
const oldFunctions = this.template!.compute.functions;
|
|
392
|
-
const oldScripts = this.template!.compute.scripts ?? [];
|
|
393
|
-
const oldQueries = this.template!.compute.queries ?? [];
|
|
394
|
-
const newDescriptors = resultMap.descriptors;
|
|
395
|
-
const newComputeObj = {
|
|
396
|
-
descriptors: {
|
|
397
|
-
enabled: !!resultMap?.descriptors?.length,
|
|
398
|
-
args: resultMap?.descriptors ?? [],
|
|
399
|
-
},
|
|
400
|
-
functions: Object.entries(resultMap?.externals ?? {}).map(([funcName, args]) => {
|
|
401
|
-
const splitFunc = funcName.split(':');
|
|
402
|
-
return ({
|
|
403
|
-
name: splitFunc[1],
|
|
404
|
-
package: splitFunc[0],
|
|
405
|
-
args: args,
|
|
406
|
-
});
|
|
407
|
-
}),
|
|
408
|
-
scripts: Object.entries(resultMap?.scripts ?? {})
|
|
409
|
-
.filter(([name, _]) => name.startsWith(HTScriptPrefix) && name.split(':').length === 3)
|
|
410
|
-
.map(([scriptId, args]) => {
|
|
411
|
-
const scriptNameParts = scriptId.split(':');
|
|
412
|
-
return ({
|
|
413
|
-
name: scriptNameParts[1] ?? '',
|
|
414
|
-
id: scriptNameParts[2] ?? '',
|
|
415
|
-
args: args,
|
|
416
|
-
});
|
|
417
|
-
}),
|
|
418
|
-
queries: Object.entries(resultMap?.queries ?? {})
|
|
419
|
-
.filter(([name, _]) => name.startsWith(HTQueryPrefix) && name.split(':').length === 3)
|
|
420
|
-
.map(([queryName, args]) => {
|
|
421
|
-
const queryNameParts = queryName.split(':');
|
|
422
|
-
return ({
|
|
423
|
-
name: queryNameParts[1] ?? '',
|
|
424
|
-
id: queryNameParts[2] ?? '',
|
|
425
|
-
args: args,
|
|
426
|
-
});
|
|
427
|
-
}),
|
|
428
|
-
};
|
|
429
|
-
this.template!.compute = newComputeObj;
|
|
430
|
-
this.campaign!.template = this.template;
|
|
431
|
-
const uncalculatedDescriptors = newDescriptors.filter((d) => !oldDescriptors.includes(d));
|
|
432
|
-
|
|
433
|
-
const newFunctions: {[_: string]: IFunctionArgs} = {};
|
|
434
|
-
Object.entries(resultMap?.externals ?? {})
|
|
435
|
-
.filter(([funcName, args]) => {
|
|
436
|
-
const oldFunc = oldFunctions.find((f) => `${f.package}:${f.name}` === funcName);
|
|
437
|
-
if (!oldFunc)
|
|
438
|
-
return true;
|
|
439
|
-
return !Object.entries(args).every(([key, value]) => oldFunc.args[key] === value);
|
|
440
|
-
}).forEach(([funcName, args]) => {newFunctions[funcName] = args;});
|
|
441
|
-
|
|
442
|
-
const newScripts: {[_: string]: IFunctionArgs} = {};
|
|
443
|
-
Object.entries(resultMap?.scripts ?? {})
|
|
444
|
-
.filter(([scriptName, args]) => {
|
|
445
|
-
const oldScript = oldScripts.find((f) => `${HTScriptPrefix}:${f.name}:${f.id}` === scriptName);
|
|
446
|
-
if (!oldScript)
|
|
447
|
-
return true;
|
|
448
|
-
return !Object.entries(args).every(([key, value]) => oldScript.args[key] === value);
|
|
449
|
-
}).forEach(([scriptName, args]) => {newScripts[scriptName] = args;});
|
|
450
|
-
|
|
451
|
-
const newQueries: {[_: string]: IFunctionArgs} = {};
|
|
452
|
-
Object.entries(resultMap?.queries ?? {})
|
|
453
|
-
.filter(([queryName, args]) => {
|
|
454
|
-
const oldQuery = oldQueries.find((f) => `${HTQueryPrefix}:${f.name}:${f.id}` === queryName);
|
|
455
|
-
if (!oldQuery)
|
|
456
|
-
return true;
|
|
457
|
-
return !Object.entries(args).every(([key, value]) => oldQuery.args[key] === value);
|
|
458
|
-
}).forEach(([queryName, args]) => {newQueries[queryName] = args;});
|
|
459
|
-
ui.setUpdateIndicator(view.grid.root, true);
|
|
460
|
-
try {
|
|
461
|
-
await calculateColumns({descriptors: uncalculatedDescriptors, externals: newFunctions,
|
|
462
|
-
scripts: newScripts, queries: newQueries}, this.dataFrame!, this.molColName!);
|
|
463
|
-
this.dataFrame!.fireValuesChanged();
|
|
464
|
-
} finally {
|
|
465
|
-
ui.setUpdateIndicator(view.grid.root, false);
|
|
466
|
-
this.saveCampaign(undefined, false);
|
|
467
|
-
}
|
|
468
|
-
}, () => null, this.campaign?.template!, true);
|
|
469
|
-
};
|
|
470
|
-
|
|
471
|
-
const calculateRibbon = ui.iconFA('wrench', getComputeDialog, 'Calculate additional properties');
|
|
472
|
-
const addNewRowButton = ui.icons.add(() => {this.dataFrame?.rows.addNew(null, true);}, 'Add new row');
|
|
473
|
-
const permissionsButton = ui.iconFA('share', async () => {
|
|
474
|
-
await (new PermissionsDialog(this.campaign?.permissions)).show((res) => {
|
|
475
|
-
this.campaign!.permissions = res;
|
|
476
|
-
this.saveCampaign(undefined, true);
|
|
477
|
-
});
|
|
478
|
-
}, 'Edit campaign permissions');
|
|
479
|
-
const tilesButton = ui.bigButton('Progress tracker', () => {
|
|
480
|
-
getTilesViewDialog(this, () => this._designView ?? null);
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
const submitButton = ui.bigButton('Submit', () => {
|
|
484
|
-
const dialogContent = this._submitView?.render();
|
|
485
|
-
if (dialogContent) {
|
|
486
|
-
const dlg = ui.dialog('Submit');
|
|
487
|
-
dlg.add(dialogContent);
|
|
488
|
-
dlg.addButton('Save', ()=>{this.saveCampaign(); dlg.close();});
|
|
489
|
-
dlg.addButton('Submit', ()=>{this._submitView?.submit(); dlg.close();});
|
|
490
|
-
dlg.show();
|
|
491
|
-
}
|
|
492
|
-
});
|
|
493
|
-
submitButton.classList.add('hit-design-submit-button');
|
|
494
|
-
const ribbonButtons: HTMLElement[] = [submitButton];
|
|
495
|
-
if (this.template?.stages?.length ?? 0 > 0)
|
|
496
|
-
ribbonButtons.unshift(tilesButton);
|
|
497
|
-
if (this.campaign && this.template && !this.campaign.template)
|
|
498
|
-
this.campaign.template = this.template;
|
|
499
|
-
|
|
500
|
-
if (this.hasEditPermission)
|
|
501
|
-
ribbonButtons.unshift(permissionsButton);
|
|
502
|
-
ribbonButtons.unshift(calculateRibbon);
|
|
503
|
-
ribbonButtons.unshift(addNewRowButton);
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
ribbons.push(ribbonButtons);
|
|
507
|
-
// remove project save button from the ribbon
|
|
508
|
-
view.setRibbonPanels(ribbons);
|
|
509
|
-
}
|
|
510
|
-
}
|
|
492
|
+
this.initDesignViewRibbons(view, subs);
|
|
511
493
|
view.parentCall = this.parentCall;
|
|
512
494
|
return view;
|
|
513
495
|
}
|
|
@@ -605,7 +587,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
605
587
|
'Template': this.template?.name ?? 'Molecules',
|
|
606
588
|
'File path': getPathEditor(),
|
|
607
589
|
...campaignProps,
|
|
608
|
-
'Number of molecules': (this.dataFrame!.rowCount
|
|
590
|
+
'Number of molecules': (this.dataFrame!.rowCount).toString(),
|
|
609
591
|
'Enrichment methods': [this.template!.compute.descriptors.enabled ? 'descriptors' : '',
|
|
610
592
|
...this.template!.compute.functions.map((func) => func.name)].filter((f) => f && f.trim() !== '').join(', '),
|
|
611
593
|
};
|
|
@@ -633,7 +615,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
633
615
|
createDate: this.campaign?.createDate ?? toFormatedDateString(new Date()),
|
|
634
616
|
campaignFields: this.campaign?.campaignFields ?? this.campaignProps,
|
|
635
617
|
columnSemTypes,
|
|
636
|
-
rowCount: enrichedDf.
|
|
618
|
+
rowCount: enrichedDf.rowCount,
|
|
637
619
|
filteredRowCount: enrichedDf.filter.trueCount,
|
|
638
620
|
savePath: this._filePath,
|
|
639
621
|
columnTypes: colTypeMap,
|
|
@@ -646,7 +628,7 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
646
628
|
grok.shell.error('You do not have permission to modify this campaign');
|
|
647
629
|
return campaign;
|
|
648
630
|
}
|
|
649
|
-
const campaignPath =
|
|
631
|
+
const campaignPath = `${this.appName}/campaigns/${campaignId}/${CampaignJsonName}`;
|
|
650
632
|
// check if someone already saved the campaign
|
|
651
633
|
let resDf = enrichedDf;
|
|
652
634
|
|
|
@@ -669,7 +651,6 @@ export class HitDesignApp extends HitAppBase<HitDesignTemplate> {
|
|
|
669
651
|
const csvDf = DG.DataFrame.fromColumns(
|
|
670
652
|
resDf.columns.toList().filter((col) => !col.name.startsWith('~')),
|
|
671
653
|
).toCsv();
|
|
672
|
-
//await _package.files.writeAsText(`Hit Design/campaigns/${campaignId}/${CampaignTableName}`, csvDf);
|
|
673
654
|
await grok.dapi.files.writeAsText(this._filePath, csvDf);
|
|
674
655
|
const newLayout = this._designView!.saveLayout();
|
|
675
656
|
if (!newLayout)
|