@datagrok/hit-triage 1.4.2 → 1.4.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/.eslintrc.json +2 -1
- package/CHANGELOG.md +9 -0
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/files/Hit Triage/campaigns/HTD-1/campaign.json +81 -1
- package/files/Hit Triage/templates/HT Demo Template.json +28 -1
- package/files/cache_config.json +27 -0
- package/package.json +12 -3
- package/src/app/hit-app-base.ts +5 -2
- package/src/app/hit-design-app.ts +7 -18
- package/src/app/utils.ts +17 -2
- package/src/package.ts +3 -1
- package/src/packageSettingsEditor.ts +54 -2
|
@@ -1 +1,81 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "HTD-1",
|
|
3
|
+
"templateName": "HT Demo Template",
|
|
4
|
+
"filters": {},
|
|
5
|
+
"ingest": {
|
|
6
|
+
"type": "File",
|
|
7
|
+
"query": "System:AppData/HitTriage/Hit Triage/campaigns/HTD-1/enriched_table.csv",
|
|
8
|
+
"molColName": "smiles"
|
|
9
|
+
},
|
|
10
|
+
"status": "In Progress",
|
|
11
|
+
"createDate": "2024/10/17",
|
|
12
|
+
"campaignFields": {
|
|
13
|
+
"Chemist": "Davit",
|
|
14
|
+
"Deadline": {
|
|
15
|
+
"a": 1759953600000,
|
|
16
|
+
"b": false,
|
|
17
|
+
"date": "2025-10-08T20:00:00.000Z"
|
|
18
|
+
},
|
|
19
|
+
"Scaffold": "c1cc2ccccc2cc1"
|
|
20
|
+
},
|
|
21
|
+
"columnSemTypes": {
|
|
22
|
+
"smiles": "Molecule",
|
|
23
|
+
"LogD": null,
|
|
24
|
+
"MolWt": null,
|
|
25
|
+
"Mutagenicity": null,
|
|
26
|
+
"Tumorigenicity": null,
|
|
27
|
+
"Irritating effects": null,
|
|
28
|
+
"Reproductive effects": null,
|
|
29
|
+
"Selected hits": null,
|
|
30
|
+
"~smiles.Pattern": null,
|
|
31
|
+
"~smiles.canonicalSmiles": null
|
|
32
|
+
},
|
|
33
|
+
"rowCount": 100,
|
|
34
|
+
"filteredRowCount": 100,
|
|
35
|
+
"template": {
|
|
36
|
+
"name": "HT Demo Template",
|
|
37
|
+
"key": "HTD",
|
|
38
|
+
"campaignFields": [
|
|
39
|
+
{ "name": "Chemist", "type": "String", "required": true },
|
|
40
|
+
{ "name": "Deadline", "type": "Date", "required": false },
|
|
41
|
+
{ "name": "Scaffold", "type": "Molecule", "required": false }
|
|
42
|
+
],
|
|
43
|
+
"dataSourceType": "Query",
|
|
44
|
+
"compute": {
|
|
45
|
+
"descriptors": { "enabled": true, "args": ["MolWt"] },
|
|
46
|
+
"functions": [
|
|
47
|
+
{
|
|
48
|
+
"name": "addChemRisksColumns",
|
|
49
|
+
"package": "Chem",
|
|
50
|
+
"args": {
|
|
51
|
+
"mutagenicity": true,
|
|
52
|
+
"tumorigenicity": true,
|
|
53
|
+
"irritatingEffects": true,
|
|
54
|
+
"reproductiveEffects": true
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"scripts": [],
|
|
59
|
+
"queries": []
|
|
60
|
+
},
|
|
61
|
+
"queryFunctionName": "Demo Molecules variable"
|
|
62
|
+
},
|
|
63
|
+
"columnTypes": {
|
|
64
|
+
"smiles": "string",
|
|
65
|
+
"LogD": "qnum",
|
|
66
|
+
"MolWt": "double",
|
|
67
|
+
"Mutagenicity": "string",
|
|
68
|
+
"Tumorigenicity": "string",
|
|
69
|
+
"Irritating effects": "string",
|
|
70
|
+
"Reproductive effects": "string",
|
|
71
|
+
"Selected hits": "bool",
|
|
72
|
+
"~smiles.Pattern": "byte_array",
|
|
73
|
+
"~smiles.canonicalSmiles": "string"
|
|
74
|
+
},
|
|
75
|
+
"authorUserId": "e44f5f40-73f0-11ef-884d-c35bc9987eba",
|
|
76
|
+
"permissions": {
|
|
77
|
+
"view": ["a4b45840-9a50-11e6-9cc9-8546b8bf62e6"],
|
|
78
|
+
"edit": ["a4b45840-9a50-11e6-9cc9-8546b8bf62e6"]
|
|
79
|
+
},
|
|
80
|
+
"layout": "{\"containerType\":\"horizontal\",\"state\":{\"width\":1356,\"height\":869},\"children\":[{\"containerType\":\"panel\",\"state\":{\"width\":123,\"height\":869,\"element\":{\"id\":\"40cdc600-73f0-11ef-baec-5d0734bbb5b2\",\"type\":\"Filters\",\"look\":{\"#type\":\"FiltersLook\",\"filters\":[{\"type\":\"Chem:substructureFilter\",\"column\":\"smiles\",\"active\":true,\"columnName\":\"smiles\",\"molBlock\":\"\",\"searchType\":\"Contains\",\"simCutOff\":0.8,\"fp\":\"Morgan\",\"boolInput\":null},{\"type\":\"categorical\",\"column\":\"Mutagenicity\",\"active\":true,\"boolInput\":null},{\"type\":\"categorical\",\"column\":\"Tumorigenicity\",\"active\":true,\"boolInput\":null},{\"type\":\"categorical\",\"column\":\"Selected hits\",\"active\":true,\"boolInput\":null},{\"type\":\"categorical\",\"column\":\"Irritating effects\",\"active\":true,\"boolInput\":null},{\"type\":\"categorical\",\"column\":\"Reproductive effects\",\"active\":true,\"boolInput\":null},{\"type\":\"histogram\",\"column\":\"LogD\",\"active\":true,\"filterOutMissingValues\":false,\"showMissingValuesOnly\":false,\"showHistogram\":true,\"showSlider\":true,\"showMinMax\":false,\"boolInput\":null},{\"type\":\"histogram\",\"column\":\"MolWt\",\"active\":true,\"filterOutMissingValues\":false,\"showMissingValuesOnly\":false,\"showHistogram\":true,\"showSlider\":true,\"showMinMax\":false,\"boolInput\":null}]},\"title\":\"Filters\"}},\"children\":[]},{\"containerType\":\"vertical\",\"state\":{\"width\":652,\"height\":869},\"children\":[{\"containerType\":\"fill\",\"state\":{\"width\":652,\"height\":552,\"documentManager\":true},\"children\":[{\"containerType\":\"panel\",\"state\":{\"width\":652,\"height\":552,\"element\":{\"id\":\"40ce1420-73f0-11ef-e149-cfa7da300a5c\",\"type\":\"Grid\",\"look\":{\"#type\":\"GridLook\",\"showAddNewRowIcon\":true,\"addNewRowOnLastRowEdit\":true,\"rowHeight\":100,\"topLevelDefaultMenu\":true,\"allowColumnMenu\":true,\"columns\":[{\"width\":36,\"backgroundColor\":4294440951,\"customName\":\"\",\"cellType\":\"row header\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"width\":200,\"columnName\":\"smiles\",\"cellType\":\"Molecule\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"width\":59,\"columnName\":\"LogD\",\"cellType\":\"number\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"width\":63,\"columnName\":\"MolWt\",\"cellType\":\"number\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"isColorCoded\":true,\"width\":101,\"columnName\":\"Mutagenicity\",\"colorCodingType\":\"Categorical\",\"colorCodingCategorical\":{\"Unknown\":4278190080,\"None\":4278215680,\"Low\":4294944000,\"High\":4287299584},\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"isColorCoded\":true,\"width\":113,\"columnName\":\"Tumorigenicity\",\"colorCodingType\":\"Categorical\",\"colorCodingCategorical\":{\"Unknown\":4278190080,\"None\":4278215680,\"Low\":4294944000,\"High\":4287299584},\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"isColorCoded\":true,\"width\":120,\"columnName\":\"Irritating effects\",\"colorCodingType\":\"Categorical\",\"colorCodingCategorical\":{\"Unknown\":4278190080,\"None\":4278215680,\"Low\":4294944000,\"High\":4287299584},\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"isColorCoded\":true,\"width\":147,\"columnName\":\"Reproductive effects\",\"colorCodingType\":\"Categorical\",\"colorCodingCategorical\":{\"Unknown\":4278190080,\"None\":4278215680,\"Low\":4294944000,\"High\":4287299584},\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"width\":101,\"columnName\":\"Selected hits\",\"cellType\":\"bool\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"visible\":false,\"width\":0,\"columnName\":\"~smiles.Pattern\",\"headerCellStyle\":{\"textWrap\":\"words\"}},{\"visible\":false,\"width\":0,\"columnName\":\"~smiles.canonicalSmiles\",\"headerCellStyle\":{\"textWrap\":\"words\"}}]},\"title\":\"Variable Molecules number\",\"default\":true}},\"children\":[]}]},{\"containerType\":\"panel\",\"state\":{\"width\":652,\"height\":316,\"element\":{\"id\":\"40ce1420-73f0-11ef-907b-1f636b264a43\",\"type\":\"Histogram\",\"look\":{\"#type\":\"HistogramLook\",\"valueColumnName\":\"MolWt\",\"showXAxis\":true,\"showYAxis\":true,\"binWidthRatio\":0.9,\"marginLeft\":5,\"marginRight\":5},\"title\":\"Histogram\"}},\"children\":[]}]},{\"containerType\":\"vertical\",\"state\":{\"width\":579,\"height\":869},\"children\":[{\"containerType\":\"panel\",\"state\":{\"width\":579,\"height\":239,\"element\":{\"id\":\"40ce3b30-73f0-11ef-e099-e1bd6cccb6e9\",\"type\":\"Bar chart\",\"look\":{\"#type\":\"BarChartLook\",\"valueColumnName\":\"LogD\",\"valueAggrType\":\"count\",\"barSortType\":\"by value\",\"barSortOrder\":\"desc\",\"splitColumnName\":\"Mutagenicity\"},\"title\":\"Bar chart\"}},\"children\":[]},{\"containerType\":\"panel\",\"state\":{\"width\":579,\"height\":216,\"element\":{\"id\":\"40ce3b30-73f0-11ef-fda4-af559d0f6b59\",\"type\":\"Bar chart\",\"look\":{\"#type\":\"BarChartLook\",\"valueColumnName\":\"LogD\",\"valueAggrType\":\"count\",\"barSortType\":\"by value\",\"barSortOrder\":\"desc\",\"splitColumnName\":\"Irritating effects\"},\"title\":\"Bar chart\"}},\"children\":[]},{\"containerType\":\"panel\",\"state\":{\"width\":579,\"height\":216,\"element\":{\"id\":\"40ce3b30-73f0-11ef-8cd7-5f5c6c756235\",\"type\":\"Bar chart\",\"look\":{\"#type\":\"BarChartLook\",\"valueColumnName\":\"LogD\",\"valueAggrType\":\"count\",\"barSortType\":\"by value\",\"barSortOrder\":\"desc\",\"splitColumnName\":\"Reproductive effects\"},\"title\":\"Bar chart\"}},\"children\":[]},{\"containerType\":\"panel\",\"state\":{\"width\":579,\"height\":195,\"element\":{\"id\":\"40ce6240-73f0-11ef-d8da-27625309edf0\",\"type\":\"Bar chart\",\"look\":{\"#type\":\"BarChartLook\",\"valueColumnName\":\"LogD\",\"valueAggrType\":\"count\",\"barSortType\":\"by value\",\"barSortOrder\":\"desc\",\"splitColumnName\":\"Tumorigenicity\"},\"title\":\"Bar chart\"}},\"children\":[]}]}],\"floating\":[],\"tableId\":\"0a2b1c10-73f0-11ef-9a73-496ef3e6e002\",\"tableName\":\"Variable Molecules number\"}"
|
|
81
|
+
}
|
|
@@ -1 +1,28 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"name": "HT Demo Template",
|
|
3
|
+
"key": "HTD",
|
|
4
|
+
"campaignFields": [
|
|
5
|
+
{ "name": "Chemist", "type": "String", "required": true },
|
|
6
|
+
{ "name": "Deadline", "type": "Date", "required": false },
|
|
7
|
+
{ "name": "Scaffold", "type": "Molecule", "required": false }
|
|
8
|
+
],
|
|
9
|
+
"dataSourceType": "Query",
|
|
10
|
+
"compute": {
|
|
11
|
+
"descriptors": { "enabled": true, "args": ["MolWt"] },
|
|
12
|
+
"functions": [
|
|
13
|
+
{
|
|
14
|
+
"name": "addChemRisksColumns",
|
|
15
|
+
"package": "Chem",
|
|
16
|
+
"args": {
|
|
17
|
+
"mutagenicity": true,
|
|
18
|
+
"tumorigenicity": true,
|
|
19
|
+
"irritatingEffects": true,
|
|
20
|
+
"reproductiveEffects": true
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"scripts": [],
|
|
25
|
+
"queries": []
|
|
26
|
+
},
|
|
27
|
+
"queryFunctionName": "Demo Molecules variable"
|
|
28
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"path": "/Hit Design",
|
|
4
|
+
"invalidateOn": "0 * * * *",
|
|
5
|
+
"preflight": true
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"path": "/Hit Triage",
|
|
9
|
+
"invalidateOn": "0 * * * *",
|
|
10
|
+
"preflight": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"path": "/Hit Design/campaigns",
|
|
14
|
+
"invalidateOn": "0 * * * *",
|
|
15
|
+
"preflight": true
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"path": "/Hit Triage/campaigns",
|
|
19
|
+
"invalidateOn": "0 * * * *",
|
|
20
|
+
"preflight": true
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "/",
|
|
24
|
+
"invalidateOn": "0 * * * *",
|
|
25
|
+
"preflight": true
|
|
26
|
+
}
|
|
27
|
+
]
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@datagrok/hit-triage",
|
|
3
3
|
"friendlyName": "HitTriage",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.4",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Davit Rizhinashvili",
|
|
7
7
|
"email": "drizhinashvili@datagrok.ai"
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"properties": [
|
|
64
64
|
{
|
|
65
65
|
"name": "view",
|
|
66
|
-
"description": "
|
|
66
|
+
"description": "Default User Groups for new campaigns for the 'View' permission",
|
|
67
67
|
"propertyType": "string",
|
|
68
68
|
"defaultValue": "",
|
|
69
69
|
"inputType": "userGroups",
|
|
@@ -73,13 +73,22 @@
|
|
|
73
73
|
},
|
|
74
74
|
{
|
|
75
75
|
"name": "edit",
|
|
76
|
-
"description": "
|
|
76
|
+
"description": "Default User Groups for new campaigns for the 'Edit' permission",
|
|
77
77
|
"propertyType": "string",
|
|
78
78
|
"defaultValue": "",
|
|
79
79
|
"inputType": "userGroups",
|
|
80
80
|
"nullable": true,
|
|
81
81
|
"category": "DefaultUserGroupsSharing",
|
|
82
82
|
"friendlyName": "Edit"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"name": "defaultCampaignFolder",
|
|
86
|
+
"description": "Default storage folder for new campaigns",
|
|
87
|
+
"propertyType": "string",
|
|
88
|
+
"defaultValue": "System.AppData/HitTriage",
|
|
89
|
+
"nullable": true,
|
|
90
|
+
"category": "Storage",
|
|
91
|
+
"friendlyName": "Default Campaign Folder"
|
|
83
92
|
}
|
|
84
93
|
]
|
|
85
94
|
}
|
package/src/app/hit-app-base.ts
CHANGED
|
@@ -78,10 +78,13 @@ export abstract class HitAppBase<T> {
|
|
|
78
78
|
public async getNewCampaignName(folderName: string, templateKey: string) {
|
|
79
79
|
const templateCampaigns = (await _package.files.list(folderName))
|
|
80
80
|
.map((file) => file.name)
|
|
81
|
-
.filter((name) => name.startsWith(templateKey));
|
|
81
|
+
.filter((name) => name.startsWith(`${templateKey}-`) && !!parseInt(name.substring(templateKey.length + 1)));
|
|
82
82
|
if (templateCampaigns.length === 0)
|
|
83
83
|
return templateKey + '-1';
|
|
84
|
-
const postFixes = templateCampaigns
|
|
84
|
+
const postFixes = templateCampaigns
|
|
85
|
+
.map((c) => c.substring(templateKey.length + 1))
|
|
86
|
+
.filter(Boolean).map((c) => parseInt(c, 10))
|
|
87
|
+
.sort((a, b) => a - b);// sort in ascending order
|
|
85
88
|
return templateKey + '-' + ((postFixes[postFixes.length - 1] + 1).toString());
|
|
86
89
|
}
|
|
87
90
|
|
|
@@ -10,7 +10,7 @@ import {CampaignIdKey, CampaignJsonName, CampaignTableName,
|
|
|
10
10
|
import {calculateColumns, calculateCellValues, getNewVid} from './utils/calculate-single-cell';
|
|
11
11
|
import '../../css/hit-triage.css';
|
|
12
12
|
import {_package} from '../package';
|
|
13
|
-
import {addBreadCrumbsToRibbons, checkRibbonsHaveSubmit, editableTableField, modifyUrl, toFormatedDateString} from './utils';
|
|
13
|
+
import {addBreadCrumbsToRibbons, checkFileExists, checkRibbonsHaveSubmit, editableTableField, modifyUrl, toFormatedDateString} from './utils';
|
|
14
14
|
import {HitDesignSubmitView} from './hit-design-views/submit-view';
|
|
15
15
|
import {getTilesViewDialog} from './hit-design-views/tiles-view';
|
|
16
16
|
import {HitAppBase} from './hit-app-base';
|
|
@@ -19,7 +19,7 @@ import {chemFunctionsDialog} from './dialogs/functions-dialog';
|
|
|
19
19
|
import {Observable, Subscription} from 'rxjs';
|
|
20
20
|
import {filter} from 'rxjs/operators';
|
|
21
21
|
import {defaultPermissions, PermissionsDialog} from './dialogs/permissions-dialog';
|
|
22
|
-
import {getDefaultSharingSettings} from '../packageSettingsEditor';
|
|
22
|
+
import {getDefaultCampaignStorageSettings, getDefaultSharingSettings} from '../packageSettingsEditor';
|
|
23
23
|
|
|
24
24
|
export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> extends HitAppBase<T> {
|
|
25
25
|
multiView: DG.MultiView;
|
|
@@ -267,7 +267,10 @@ export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> exten
|
|
|
267
267
|
this._designView = undefined;
|
|
268
268
|
campaignId = await this.getNewCampaignName(`${this.appName}/campaigns`, template.key);
|
|
269
269
|
modifyUrl(HitDesignCampaignIdKey, campaignId);
|
|
270
|
-
|
|
270
|
+
let defaultFolderPath = await getDefaultCampaignStorageSettings();
|
|
271
|
+
if (!defaultFolderPath.endsWith('/'))
|
|
272
|
+
defaultFolderPath += '/';
|
|
273
|
+
this._filePath = `${defaultFolderPath}${this.appName}/campaigns/${campaignId}/${CampaignTableName}`;
|
|
271
274
|
} else {
|
|
272
275
|
const fileLoc = `System.AppData/HitTriage/${this.appName}/campaigns`;
|
|
273
276
|
this._filePath = this.campaign?.savePath ?? `${fileLoc}/${campaignId}/${CampaignTableName}`;
|
|
@@ -842,22 +845,8 @@ export class HitDesignApp<T extends HitDesignTemplate = HitDesignTemplate> exten
|
|
|
842
845
|
labelElement.remove();
|
|
843
846
|
newPathInput.root.style.width = '100%';
|
|
844
847
|
|
|
845
|
-
async function checkFolder() {
|
|
846
|
-
const newPath = newPathInput.value;
|
|
847
|
-
if (!newPath || newPath.trim() === '') {
|
|
848
|
-
grok.shell.error('Path can not be empty');
|
|
849
|
-
return false;
|
|
850
|
-
}
|
|
851
|
-
const exists = await grok.dapi.files.exists(newPath);
|
|
852
|
-
if (!exists) {
|
|
853
|
-
grok.shell.error('Given folder does not exist');
|
|
854
|
-
return false;
|
|
855
|
-
}
|
|
856
|
-
return true;
|
|
857
|
-
}
|
|
858
|
-
|
|
859
848
|
const saveButton = ui.button('Save', async () => {
|
|
860
|
-
const exists = await
|
|
849
|
+
const exists = await checkFileExists(newPathInput.value);
|
|
861
850
|
if (!exists)
|
|
862
851
|
return;
|
|
863
852
|
const newPath = newPathInput.value;
|
package/src/app/utils.ts
CHANGED
|
@@ -154,8 +154,10 @@ async function checkPermissions(authorId: string, groupIdList: string[]): Promis
|
|
|
154
154
|
const user = await grok.dapi.groups.getUser(group);
|
|
155
155
|
if (user?.id === userId)
|
|
156
156
|
return true;
|
|
157
|
-
} else if (userGroupId
|
|
158
|
-
if (group.members.some((memberGroup) => memberGroup.id === userGroupId))
|
|
157
|
+
} else if (userGroupId) {
|
|
158
|
+
if ((group.members?.length ?? 0) > 0 && group.members.some((memberGroup) => memberGroup.id === userGroupId))
|
|
159
|
+
return true;
|
|
160
|
+
if ((group.adminMembers?.length ?? 0) > 0 && group.adminMembers.some((memberGroup) => memberGroup.id === userGroupId))
|
|
159
161
|
return true;
|
|
160
162
|
}
|
|
161
163
|
}
|
|
@@ -323,6 +325,19 @@ export function editableTableField(field: HTMLElement, options?: EditableFieldOp
|
|
|
323
325
|
return container;
|
|
324
326
|
}
|
|
325
327
|
|
|
328
|
+
export async function checkFileExists(path: string) {
|
|
329
|
+
if (!path || path.trim() === '') {
|
|
330
|
+
grok.shell.error('Path can not be empty');
|
|
331
|
+
return false;
|
|
332
|
+
}
|
|
333
|
+
const exists = await grok.dapi.files.exists(path);
|
|
334
|
+
if (!exists) {
|
|
335
|
+
grok.shell.error('Given folder does not exist');
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
return true;
|
|
339
|
+
}
|
|
340
|
+
|
|
326
341
|
|
|
327
342
|
// //name: Demo Design with reinvent
|
|
328
343
|
// //input: int numberOfMolecules
|
package/src/package.ts
CHANGED
|
@@ -36,7 +36,9 @@ async function hitAppTB(treeNode: DG.TreeViewGroup, browseView: any, name: AppNa
|
|
|
36
36
|
const savePath = 'ingest' in camp ? camp.ingest.query : camp.savePath;
|
|
37
37
|
if (!savePath || !(await grok.dapi.files.exists(savePath)))
|
|
38
38
|
continue;
|
|
39
|
-
const
|
|
39
|
+
const templateName = camp.templateName ?? camp.template?.name;
|
|
40
|
+
const templateGroup = templateName ? treeNode.getOrCreateGroup(templateName) : treeNode;
|
|
41
|
+
const node = templateGroup.item(camp.friendlyName ?? camp.name);
|
|
40
42
|
node.onSelected.subscribe(async (_) => {
|
|
41
43
|
try {
|
|
42
44
|
const df = await grok.dapi.files.readCsv(savePath);
|
|
@@ -15,6 +15,9 @@ export type HTDefaultCampaignSharing = {
|
|
|
15
15
|
edit: DG.Group[];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
export const defaultCampaignStoragePropName = 'defaultCampaignFolder';
|
|
19
|
+
export const defaultCampaignStorage = 'System.AppData/HitTriage';
|
|
20
|
+
|
|
18
21
|
export async function parseUserGroupString(s: string | null) {
|
|
19
22
|
if (!s)
|
|
20
23
|
return [await grok.dapi.groups.find(DG.Group.defaultGroupsIds['All users'])].filter(Boolean);
|
|
@@ -29,7 +32,7 @@ export async function parseUserGroupString(s: string | null) {
|
|
|
29
32
|
|
|
30
33
|
export async function getDefaultSharingSettings(): Promise<HTDefaultCampaignSharing> {
|
|
31
34
|
try {
|
|
32
|
-
const ps = (await _package.getSettings()) as unknown as Map<string, any> | Record<string, any>;
|
|
35
|
+
const ps = (_package.settings ?? await _package.getSettings()) as unknown as Map<string, any> | Record<string, any>;
|
|
33
36
|
const settings: HTDefaultCampaignSharing = {view: [], edit: []};
|
|
34
37
|
if (!ps)
|
|
35
38
|
return settings;
|
|
@@ -48,6 +51,17 @@ export async function getDefaultSharingSettings(): Promise<HTDefaultCampaignShar
|
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
|
|
54
|
+
export async function getDefaultCampaignStorageSettings(): Promise<string> {
|
|
55
|
+
const ps = (_package.settings ?? await _package.getSettings()) as unknown as Map<string, any> | Record<string, any>;
|
|
56
|
+
if (!ps)
|
|
57
|
+
return defaultCampaignStorage;
|
|
58
|
+
const res = (ps instanceof Map ? ps.get(defaultCampaignStoragePropName) : ps[defaultCampaignStoragePropName]) ?? defaultCampaignStorage;
|
|
59
|
+
// check if it exists
|
|
60
|
+
if (!(await grok.dapi.files.exists(res)))
|
|
61
|
+
return defaultCampaignStorage;
|
|
62
|
+
return res;
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
|
|
52
66
|
export async function htPackageSettingsEditorWidget(propList: DG.Property[]): Promise<DG.Widget> {
|
|
53
67
|
const sharingProps = propList.filter((p) => p.category === defaultSharingGroupCategoryName);
|
|
@@ -65,7 +79,7 @@ export async function htPackageSettingsEditorWidget(propList: DG.Property[]): Pr
|
|
|
65
79
|
input.onInput.subscribe(() => {
|
|
66
80
|
try {
|
|
67
81
|
const stringValue = !input.value?.length ? '' : JSON.stringify(input.value.map((group) => group.id));
|
|
68
|
-
prop.set(null, stringValue);
|
|
82
|
+
prop.set(null, stringValue); //FYI for future devs: null is passed here because there is an setter override in the core, the temp prop is set in backend and it is saved when a save button is clicked
|
|
69
83
|
} catch (e) {
|
|
70
84
|
grok.shell.error('Error Setting group. Check console for more details');
|
|
71
85
|
console.error(e);
|
|
@@ -77,6 +91,44 @@ export async function htPackageSettingsEditorWidget(propList: DG.Property[]): Pr
|
|
|
77
91
|
// unfortunately, this hack is needed to make the form scrollable
|
|
78
92
|
const w = DG.Widget.fromRoot(ui.form(inputs, {style: {overflow: 'visible'}}));
|
|
79
93
|
w.root.prepend(ui.h1('Default Campaign Sharing', {style: {marginBottom: '6px', marginTop: '6px'}}));
|
|
94
|
+
|
|
95
|
+
const storageProp = propList.find((p) => p.name === defaultCampaignStoragePropName);
|
|
96
|
+
|
|
97
|
+
if (storageProp) {
|
|
98
|
+
const defaultTooltip = 'Default storage for newly created campaigns. For each app, folders will be created under their name. For example, for Hit Design, the campaign files will be saved under <b>"Your folder/Hit Design/campaigns/enriched_table.csv"</b>';
|
|
99
|
+
let curTooltip = defaultTooltip;
|
|
100
|
+
const curValue: string = storageProp.get(null) ?? defaultCampaignStorage;
|
|
101
|
+
const defaultStorageHeader = ui.h1('Default Campaign Storage', {style: {marginBottom: '6px', marginTop: '6px'}});
|
|
102
|
+
|
|
103
|
+
const storageInput = ui.input.string('Folder Path', {value: curValue});
|
|
104
|
+
ui.tooltip.bind(storageInput.input, () => curTooltip);
|
|
105
|
+
DG.debounce(storageInput.onChanged, 200).subscribe(async (_) => {
|
|
106
|
+
const value = storageInput.value;
|
|
107
|
+
try {
|
|
108
|
+
if (!value) {
|
|
109
|
+
storageProp.set(null, defaultCampaignStorage);
|
|
110
|
+
curTooltip = defaultTooltip + '<br><br> <b style="color: red">Cannot be empty.</b>';
|
|
111
|
+
storageInput.input.classList.add('d4-invalid');
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (!(await grok.dapi.files.exists(value))) {
|
|
115
|
+
storageProp.set(null, defaultCampaignStorage);
|
|
116
|
+
curTooltip = defaultTooltip + '<br><br> <b style="color: red">Folder does not exist.</b>';
|
|
117
|
+
storageInput.input.classList.add('d4-invalid');
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
storageProp.set(null, value);
|
|
121
|
+
curTooltip = defaultTooltip;
|
|
122
|
+
storageInput.input.classList.remove('d4-invalid');
|
|
123
|
+
|
|
124
|
+
} catch (e) {
|
|
125
|
+
grok.shell.error('Error Setting default storage. Check console for more details');
|
|
126
|
+
console.error(e);
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
w.root.appendChild(defaultStorageHeader);
|
|
130
|
+
w.root.appendChild(storageInput.root);
|
|
131
|
+
}
|
|
80
132
|
setTimeout(() => w.root.parentElement?.style && (w.root.parentElement.style.overflow = 'visible'), 200);
|
|
81
133
|
return w;
|
|
82
134
|
}
|