@datagrok/hit-triage 1.7.2 → 1.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@datagrok/hit-triage",
3
3
  "friendlyName": "Hit Triage",
4
- "version": "1.7.2",
4
+ "version": "1.7.4",
5
5
  "author": {
6
6
  "name": "Davit Rizhinashvili",
7
7
  "email": "drizhinashvili@datagrok.ai"
@@ -17,22 +17,23 @@
17
17
  },
18
18
  "dependencies": {
19
19
  "@datagrok-libraries/compute-utils": "^1.39.0",
20
- "@datagrok-libraries/utils": "^4.3.0",
20
+ "@datagrok-libraries/utils": "^4.5.7",
21
21
  "cash-dom": "^8.1.5",
22
22
  "css-loader": "^6.5.1",
23
23
  "datagrok-api": "^1.25.0",
24
+ "rxjs": "^6.5.5",
24
25
  "source-map-loader": "^4.0.1",
25
26
  "style-loader": "^3.3.1",
26
27
  "ts-loader": "^9.5.1",
27
- "rxjs": "^6.5.5",
28
+ "typeahead-standalone": "4.14.1",
28
29
  "typescript": "^5.6.3",
29
- "uuid": "^9.0.0",
30
- "typeahead-standalone": "4.14.1"
30
+ "uuid": "^9.0.0"
31
31
  },
32
32
  "devDependencies": {
33
33
  "@types/uuid": "^9.0.2",
34
34
  "@typescript-eslint/eslint-plugin": "^5.32.0",
35
35
  "@typescript-eslint/parser": "^5.32.0",
36
+ "datagrok-tools": "^4.14.10",
36
37
  "eslint": "^8.21.0",
37
38
  "eslint-config-google": "^0.14.0",
38
39
  "webpack": "^5.95.0",
@@ -45,7 +46,7 @@
45
46
  "debug-hittriage": "webpack && grok publish ",
46
47
  "release-hittriage": "grok publish --release",
47
48
  "build-hittriage": "webpack",
48
- "build": "webpack",
49
+ "build": "grok api && grok check --soft && webpack",
49
50
  "debug-hittriage-dev": "grok publish dev",
50
51
  "release-hittriage-dev": "grok publish dev --release",
51
52
  "debug-hittriage-public": "grok publish public",
@@ -91,4 +92,4 @@
91
92
  "friendlyName": "Default Campaign Folder"
92
93
  }
93
94
  ]
94
- }
95
+ }
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as DG from 'datagrok-api/dg';
2
3
  import * as ui from 'datagrok-api/ui';
3
4
  import * as grok from 'datagrok-api/grok';
@@ -10,6 +11,7 @@ import {getCampaignFieldEditors} from './new-template-accordeon';
10
11
  import {ItemType, ItemsGrid} from '@datagrok-libraries/utils/src/items-grid';
11
12
  import {HitAppBase} from '../hit-app-base';
12
13
  import {getLayoutInput} from './layout-input';
14
+ import {getFuncPackageNameSafe} from '../utils';
13
15
 
14
16
  export async function newHitDesignTemplateAccordeon(app: HitAppBase<any>,
15
17
  preset?: PeptiHitTemplate): Promise<INewTemplateResult<PeptiHitTemplate>> {
@@ -188,7 +190,7 @@ export async function newHitDesignTemplateAccordeon(app: HitAppBase<any>,
188
190
  });
189
191
  }),
190
192
  },
191
- ...(submitFunction ? {submit: {fName: submitFunction.name, package: submitFunction.package.name}} : {}),
193
+ ...(submitFunction ? {submit: {fName: submitFunction.name, package: getFuncPackageNameSafe(submitFunction)}} : {}),
192
194
  };
193
195
  await saveHitDesignTemplate(out, app.appName);
194
196
  grok.shell.info('Template created successfully');
@@ -1,3 +1,4 @@
1
+ /* eslint-disable max-len */
1
2
  import * as DG from 'datagrok-api/dg';
2
3
  import * as ui from 'datagrok-api/ui';
3
4
  import * as grok from 'datagrok-api/grok';
@@ -10,6 +11,7 @@ import {chemFunctionsDialog} from '../dialogs/functions-dialog';
10
11
  import {ItemType, ItemsGrid} from '@datagrok-libraries/utils/src/items-grid';
11
12
  import {HitAppBase} from '../hit-app-base';
12
13
  import {getLayoutInput} from './layout-input';
14
+ import {getFuncPackageNameSafe} from '../utils';
13
15
 
14
16
 
15
17
  export async function createTemplateAccordeon(app: HitAppBase<any>,
@@ -165,7 +167,7 @@ export async function createTemplateAccordeon(app: HitAppBase<any>,
165
167
  });
166
168
  }),
167
169
  },
168
- ...(submitFunction ? {submit: {fName: submitFunction.name, package: submitFunction.package.name}} : {}),
170
+ ...(submitFunction ? {submit: {fName: submitFunction.name, package: getFuncPackageNameSafe(submitFunction)}} : {}),
169
171
  queryFunctionName: (ingestTypeInput.value === 'Query') ? dataSourceFunctionInput.value ?? undefined : undefined,
170
172
  };
171
173
  saveTemplate(out);
@@ -8,7 +8,7 @@ import {IChemFunctionsDialogResult, IComputeDialogResult, IDescriptorTree,
8
8
  import '../../../css/hit-triage.css';
9
9
  import {funcTypeNames, HTQueryPrefix, HTScriptPrefix} from '../consts';
10
10
  import {HitAppBase} from '../hit-app-base';
11
- import { FunctionOrdering, getReorderingInput, getSavedFunctionOrdering } from '../utils';
11
+ import {FunctionOrdering, getFuncPackageNameSafe, getReorderingInput, getSavedFunctionOrdering} from '../utils';
12
12
 
13
13
  export async function chemFunctionsDialog(app: HitAppBase<any>,
14
14
  onOk: (result: IComputeDialogResult) => void, onCancel: () => void,
@@ -48,34 +48,35 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
48
48
  const descriptorsGroupHost = ui.wait(async () => {
49
49
  try {
50
50
  // tree groups
51
- const descriptorsTree = (await grok.chem.descriptorsTree()) as IDescriptorTree;
52
- descriptorsGroup.root.classList.add('hit-triage-compute-dialog-descriptors-group');
53
-
54
- function createTreeGroup(name: string, treeNode: DG.TreeViewGroup): DG.TreeViewGroup {
55
- const res = treeNode.group(name, null, false);
56
- res.enableCheckBox(false);
57
- return res;
58
- };
59
-
60
- // const descriptorsGroup = createTreeGroup('Descriptors', tree);
61
- const keys = Object.keys(descriptorsTree);
62
- const preselectedDescriptors: string[] = template?.compute?.descriptors?.args ?? [];
63
- for (const groupName of keys) {
64
- const group = createTreeGroup(groupName, descriptorsGroup);
65
-
66
- for (const descriptor of descriptorsTree[groupName].descriptors) {
67
- const item = group.item(descriptor.name, descriptor);
68
- descriptorItems.push(item);
69
- item.enableCheckBox(preselectedDescriptors.includes(descriptor.name));
70
- }
71
- };
72
- return descriptorsGroup.root;
73
- } catch (e) {
74
- console.error(e);
75
- }
76
- return ui.divText('Failed to load descriptors');
77
- })
78
-
51
+ const descriptorsTree = (await grok.chem.descriptorsTree()) as IDescriptorTree;
52
+ descriptorsGroup.root.classList.add('hit-triage-compute-dialog-descriptors-group');
53
+
54
+ function createTreeGroup(name: string, treeNode: DG.TreeViewGroup): DG.TreeViewGroup {
55
+ const res = treeNode.group(name, null, false);
56
+ res.enableCheckBox(false);
57
+ return res;
58
+ };
59
+
60
+ // const descriptorsGroup = createTreeGroup('Descriptors', tree);
61
+ const keys = Object.keys(descriptorsTree);
62
+ const preselectedDescriptors: string[] = template?.compute?.descriptors?.args ?? [];
63
+ for (const groupName of keys) {
64
+ const group = createTreeGroup(groupName, descriptorsGroup);
65
+
66
+ for (const descriptor of descriptorsTree[groupName].descriptors) {
67
+ const item = group.item(descriptor.name, descriptor);
68
+ descriptorItems.push(item);
69
+ item.enableCheckBox(preselectedDescriptors.includes(descriptor.name));
70
+ }
71
+ };
72
+ return descriptorsGroup.root;
73
+ } catch (e) {
74
+ console.error(e);
75
+ }
76
+ return ui.divText('Failed to load descriptors');
77
+ });
78
+ descriptorsGroupHost.classList.add('oy-scroll');
79
+
79
80
  const descriptorsName = 'Descriptors';
80
81
  const funcNamesMap: {[key: string]: string} = {[descriptorsName]: descriptorsName};
81
82
  // if compute is in dialog form, we need to show all the functions
@@ -118,7 +119,7 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
118
119
  funcNamesMap[f.friendlyName ?? f.name] = keyName;
119
120
  calculatedFunctions[keyName] = (template?.compute?.functions?.some(
120
121
  (f) => func.func.type === funcTypeNames.function &&
121
- f.name === func.func.name && f.package === func.func.package?.name) ||
122
+ f.name === func.func.name && f.package === getFuncPackageNameSafe(func.func)) ||
122
123
  template?.compute?.scripts?.some((s) => s.id === f.id) ||
123
124
  template?.compute?.queries?.some((s) => s.id === f.id)) ?? false;
124
125
  } catch (e) {
@@ -134,7 +135,7 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
134
135
  tc.root.style.minWidth = '350px';
135
136
  host.appendChild(tc.root);
136
137
  // add checkboxes to each hader
137
- function addCheckboxesToPaneHeaders () {
138
+ function addCheckboxesToPaneHeaders() {
138
139
  tc.panes.forEach((pane)=> {
139
140
  const functionCheck =
140
141
  ui.input.bool('', {value: calculatedFunctions[funcNamesMap[pane.name]], onValueChanged: (value) => {
@@ -155,16 +156,15 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
155
156
  let actOrder = order.order ?? Object.keys(tabControlArgs);
156
157
  if (actOrder.length === 0)
157
158
  actOrder = Object.keys(tabControlArgs);
158
-
159
+
159
160
  actOrder.forEach((n) => {
160
161
  if (tabControlArgs[n])
161
162
  tc.addPane(n, () => tabControlArgs[n]);
162
163
  });
163
164
  // after adding ordered panes, we also need to add new functions, not included in the order
164
165
  Object.keys(tabControlArgs).forEach((n) => {
165
- if (!actOrder.includes(n) && tabControlArgs[n] && !(order.hidden ?? []).includes(n)) {
166
+ if (!actOrder.includes(n) && tabControlArgs[n] && !(order.hidden ?? []).includes(n))
166
167
  tc.addPane(n, () => tabControlArgs[n]);
167
- }
168
168
  });
169
169
  // make sure that hidden functions are not checked;
170
170
  (order.hidden ?? []).forEach((n) => {
@@ -90,6 +90,10 @@ export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> exten
90
90
  this.saveCampaign(false);
91
91
  }
92
92
 
93
+ public get submitParams() {
94
+ return this.campaign?.template?.submit ?? this.template?.submit;
95
+ }
96
+
93
97
  private updateAllVids() {
94
98
  const molCol = this.dataFrame!.col(this.molColName);
95
99
  const vidCol = this.dataFrame!.col(ViDColName);
@@ -134,9 +138,8 @@ export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> exten
134
138
  this._infoView.init();
135
139
  sub.unsubscribe();
136
140
  });
137
- } else if (grok.shell.v === this.mainView) {
141
+ } else if (grok.shell.v === this.mainView)
138
142
  this.setBaseUrl();
139
- }
140
143
  } catch (e) {
141
144
  console.error(e);
142
145
  }
@@ -503,19 +506,7 @@ export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> exten
503
506
  });
504
507
 
505
508
  const submitButton = ui.bigButton('Submit...', () => {
506
- const dialogContent = this._submitView?.render();
507
- if (dialogContent) {
508
- const dlg = ui.dialog('Submit');
509
- dlg.add(dialogContent);
510
- dlg.addButton('Save', () => {
511
- this._campaign!.status = this._submitView!.getStatus();
512
- this.saveCampaign();
513
- dlg.close();
514
- });
515
- if (this.template?.submit?.fName && this.template?.submit?.package && DG.Func.find({name: this.template.submit.fName, package: this.template.submit.package})?.length > 0)
516
- dlg.addButton('Submit', ()=>{this._submitView?.submit(); dlg.close();});
517
- dlg.show();
518
- }
509
+ this._submitView?.render();
519
510
  });
520
511
 
521
512
  const designerFuncs = DG.Func.find({tags: [HitDesignerFunctionTag]}).filter((f) => f.outputs.length === 1 && f.outputs[0].propertyType === DG.TYPE.DATA_FRAME);
@@ -6,6 +6,8 @@ import {HitDesignApp} from '../hit-design-app';
6
6
  import {_package} from '../../package';
7
7
  import {HitDesignTemplate} from '../types';
8
8
  import {HitBaseView} from '../base-view';
9
+ import {HitTriageSubmitTag} from '../consts';
10
+ import {getFuncPackageNameSafe} from '../utils';
9
11
 
10
12
  export class HitDesignSubmitView extends HitBaseView<HitDesignTemplate, HitDesignApp> {
11
13
  private statusInput: DG.InputBase<string | undefined>;
@@ -46,7 +48,7 @@ export class HitDesignSubmitView extends HitBaseView<HitDesignTemplate, HitDesig
46
48
  return this.statusInput.value ?? this.app.campaign?.status ?? 'No Status';
47
49
  }
48
50
 
49
- render(): HTMLDivElement {
51
+ render() {
50
52
  this.statusInput.value = this.app.campaign?.status ?? '';
51
53
  ui.empty(this.content);
52
54
 
@@ -55,17 +57,62 @@ export class HitDesignSubmitView extends HitBaseView<HitDesignTemplate, HitDesig
55
57
  ui.div([ui.tableFromMap(this.app.getSummary())]),
56
58
  this.statusInput.root,
57
59
  ]);
58
- return this.content;
60
+
61
+
62
+ const dlg = ui.dialog('Submit');
63
+ dlg.add(this.content);
64
+ dlg.addButton('Save', () => {
65
+ this.app.campaign!.status = this.getStatus();
66
+ this.app.saveCampaign();
67
+ dlg.close();
68
+ });
69
+ //dlg.addButton('Submit', ()=>{this.submit(); dlg.close();}, undefined, 'Submit the campaign file to the specified function');
70
+ dlg.show();
71
+
72
+ const submitFunctions = DG.Func.find({tags: [HitTriageSubmitTag]});
73
+ const submitFunctionMap = submitFunctions.reduce((acc, fn) => {
74
+ acc[fn.friendlyName ?? fn.name] = fn;
75
+ return acc;
76
+ }, {} as Record<string, DG.Func>);
77
+ if (submitFunctions.length > 0) {
78
+ const chosenFunctionParams = this.app.submitParams;
79
+ const foundFunction = chosenFunctionParams ? submitFunctions.find((fn) => fn.name === chosenFunctionParams.fName && getFuncPackageNameSafe(fn) == chosenFunctionParams.package) : undefined;
80
+ const foundFunctionKey = foundFunction?.friendlyName ?? foundFunction?.name;
81
+ const submitFunctionInput = ui.input.choice('Submit function', {
82
+ value: foundFunctionKey,
83
+ items: [...Object.keys(submitFunctionMap)],
84
+ nullable: true,
85
+ });
86
+
87
+ submitFunctionInput.onChanged.subscribe(() => {
88
+ const selectedFunction = submitFunctionMap[submitFunctionInput.value ?? ''];
89
+ this.app.campaign!.template!.submit = selectedFunction ? {
90
+ fName: selectedFunction.name,
91
+ package: getFuncPackageNameSafe(selectedFunction),
92
+ } : undefined;
93
+ dlg.getButton('Submit')?.remove();
94
+ if (selectedFunction) {
95
+ dlg.addButton('Submit', () => {
96
+ this.submit();
97
+ dlg.close();
98
+ }, undefined, 'Submit the campaign file to the specified function');
99
+ }
100
+ });
101
+ submitFunctionInput.fireChanged();
102
+ this.content.appendChild(submitFunctionInput.root);
103
+ }
59
104
  }
60
105
 
61
106
  onActivated(): void {
62
- this.render();
63
107
  }
64
108
 
65
109
  async submit(): Promise<any> {
66
- const submitParams= this.app.template?.submit;
67
- if (!submitParams)
110
+ const submitParams= this.app.submitParams;
111
+ if (!submitParams) {
112
+ grok.shell.error('No submit function selected. Please select a function to submit the campaign.');
68
113
  return;
114
+ }
115
+
69
116
  const submitFn = DG.Func.find({name: submitParams.fName, package: submitParams.package})[0];
70
117
  if (!submitFn) {
71
118
  grok.shell.error(`Function ${submitParams.fName} not found.`);
@@ -63,6 +63,10 @@ export class HitTriageApp extends HitAppBase<HitTriageTemplate> {
63
63
  });
64
64
  }
65
65
 
66
+ public get submitParams() {
67
+ return this.campaign?.template?.submit ?? this.template?.submit;
68
+ }
69
+
66
70
  public async setTemplate(template: HitTriageTemplate, presetFilters?: {[key: string]: any}[],
67
71
  campaignId?: string, ingestProps?: HitTriageTemplateIngest) {
68
72
  this._pickView?.dataFrame && grok.shell.closeTable(this._pickView?.dataFrame);
@@ -27,7 +27,7 @@ export class SubmitView extends HitBaseView<HitTriageTemplate, HitTriageApp> {
27
27
  }
28
28
 
29
29
  public async submit(): Promise<any> {
30
- const submitParams= this.app.template?.submit;
30
+ const submitParams= this.app.submitParams;
31
31
  if (!submitParams)
32
32
  return;
33
33
  const submitFn = DG.Func.find({name: submitParams.fName, package: submitParams.package})[0];
package/src/app/types.ts CHANGED
@@ -98,7 +98,7 @@ export type HitTriageTemplateCompute = {
98
98
 
99
99
  export type HitTriageTemplateSubmit = {
100
100
  fName: string,
101
- package: string
101
+ package?: string | undefined
102
102
  };
103
103
 
104
104
  export type HitTriageCampaignStatus = string;
package/src/app/utils.ts CHANGED
@@ -156,7 +156,7 @@ export async function loadCampaigns<T extends AppName>(
156
156
  console.error(e);
157
157
  }
158
158
  return null;
159
- })
159
+ });
160
160
  await Promise.all(campaignPromises);
161
161
  return campaignNamesMap;
162
162
  }
@@ -413,9 +413,8 @@ export function getReorderedFunctionTabArgs(args: {[key: string]: HTMLElement})
413
413
  orderedArgs[key] = args[key];
414
414
  }
415
415
  for (const key in args) {
416
- if (!orderedArgs[key] && !ordering.hidden.includes(key)) {
416
+ if (!orderedArgs[key] && !ordering.hidden.includes(key))
417
417
  orderedArgs[key] = args[key];
418
- }
419
418
  }
420
419
  return orderedArgs;
421
420
  }
@@ -452,7 +451,7 @@ export function getReorderingInput(functions: string[], onOk: (ordering: Functio
452
451
  if (child instanceof HTMLLabelElement)
453
452
  child.style.display = 'none';
454
453
  });
455
- },200);
454
+ }, 200);
456
455
  columnsEditor.root.style.justifyContent = 'end';
457
456
  columnsEditor.root.style.width = '40px';
458
457
  columnsEditor.root.style.height = '0px';
@@ -472,4 +471,12 @@ export function getReorderingInput(functions: string[], onOk: (ordering: Functio
472
471
  });
473
472
  editIcon.style.fontSize = '16px';
474
473
  return columnsEditor.root;
475
- }
474
+ }
475
+
476
+ export function getFuncPackageNameSafe(func: DG.Func): string | undefined {
477
+ try {
478
+ return func.package?.name;
479
+ } catch (e) {
480
+ return undefined;
481
+ }
482
+ }
@@ -0,0 +1,54 @@
1
+ import * as grok from 'datagrok-api/grok';
2
+ import * as DG from 'datagrok-api/dg';
3
+
4
+
5
+
6
+ export namespace Funcs {
7
+ export async function hitTriageAppTreeBrowser(treeNode: any, browseView: DG.View): Promise<any> {
8
+ return await grok.functions.call('HitTriage:HitTriageAppTreeBrowser', { treeNode, browseView });
9
+ }
10
+
11
+ export async function hitDesignAppTreeBrowser(treeNode: any, browseView: DG.View): Promise<any> {
12
+ return await grok.functions.call('HitTriage:HitDesignAppTreeBrowser', { treeNode, browseView });
13
+ }
14
+
15
+ export async function peptiHitAppTreeBrowser(treeNode: any, browseView: DG.View): Promise<any> {
16
+ return await grok.functions.call('HitTriage:PeptiHitAppTreeBrowser', { treeNode, browseView });
17
+ }
18
+
19
+ export async function hitTriageApp(): Promise<any> {
20
+ return await grok.functions.call('HitTriage:HitTriageApp', {});
21
+ }
22
+
23
+ export async function hitDesignApp(): Promise<any> {
24
+ return await grok.functions.call('HitTriage:HitDesignApp', {});
25
+ }
26
+
27
+ export async function peptiHitApp(): Promise<any> {
28
+ return await grok.functions.call('HitTriage:PeptiHitApp', {});
29
+ }
30
+
31
+ export async function demoFileIngest(): Promise<any> {
32
+ return await grok.functions.call('HitTriage:DemoFileIngest', {});
33
+ }
34
+
35
+ export async function demoFileIngest1(): Promise<any> {
36
+ return await grok.functions.call('HitTriage:DemoFileIngest1', {});
37
+ }
38
+
39
+ export async function demoFileIngest2(numberOfMolecules: number): Promise<any> {
40
+ return await grok.functions.call('HitTriage:DemoFileIngest2', { numberOfMolecules });
41
+ }
42
+
43
+ export async function demoFileSubmit(df: DG.DataFrame, molecules: string): Promise<any> {
44
+ return await grok.functions.call('HitTriage:DemoFileSubmit', { df, molecules });
45
+ }
46
+
47
+ export async function gasteigerCellRenderer(): Promise<any> {
48
+ return await grok.functions.call('HitTriage:GasteigerCellRenderer', {});
49
+ }
50
+
51
+ export async function htPackageSettingEditor(propList: any): Promise<any> {
52
+ return await grok.functions.call('HitTriage:HtPackageSettingEditor', { propList });
53
+ }
54
+ }