@datagrok/hit-triage 1.7.0 → 1.7.2
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/README_HD.md +5 -1
- package/dist/package.js +1 -1
- package/dist/package.js.map +1 -1
- package/package.json +1 -1
- package/src/app/consts.ts +1 -0
- package/src/app/dialogs/functions-dialog.ts +47 -14
- package/src/app/utils.ts +114 -1
package/package.json
CHANGED
package/src/app/consts.ts
CHANGED
|
@@ -8,6 +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
12
|
|
|
12
13
|
export async function chemFunctionsDialog(app: HitAppBase<any>,
|
|
13
14
|
onOk: (result: IComputeDialogResult) => void, onCancel: () => void,
|
|
@@ -133,19 +134,48 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
|
|
|
133
134
|
tc.root.style.minWidth = '350px';
|
|
134
135
|
host.appendChild(tc.root);
|
|
135
136
|
// add checkboxes to each hader
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
calculatedFunctions[funcNamesMap[pane.name]]
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
137
|
+
function addCheckboxesToPaneHeaders () {
|
|
138
|
+
tc.panes.forEach((pane)=> {
|
|
139
|
+
const functionCheck =
|
|
140
|
+
ui.input.bool('', {value: calculatedFunctions[funcNamesMap[pane.name]], onValueChanged: (value) => {
|
|
141
|
+
calculatedFunctions[funcNamesMap[pane.name]] = !!value;
|
|
142
|
+
if (!value)
|
|
143
|
+
$(pane.content).find('input')?.attr('disabled', 'true');
|
|
144
|
+
else
|
|
145
|
+
$(pane.content).find('input')?.removeAttr('disabled');
|
|
146
|
+
}});
|
|
147
|
+
functionCheck.setTooltip('Toggle calculation of this function');
|
|
148
|
+
pane.header.appendChild(functionCheck.root);
|
|
149
|
+
pane.header.classList.add('hit-triage-compute-dialog-pane-header');
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function initTabs(order: FunctionOrdering) {
|
|
154
|
+
tc.clear();
|
|
155
|
+
let actOrder = order.order ?? Object.keys(tabControlArgs);
|
|
156
|
+
if (actOrder.length === 0)
|
|
157
|
+
actOrder = Object.keys(tabControlArgs);
|
|
158
|
+
|
|
159
|
+
actOrder.forEach((n) => {
|
|
160
|
+
if (tabControlArgs[n])
|
|
161
|
+
tc.addPane(n, () => tabControlArgs[n]);
|
|
162
|
+
});
|
|
163
|
+
// after adding ordered panes, we also need to add new functions, not included in the order
|
|
164
|
+
Object.keys(tabControlArgs).forEach((n) => {
|
|
165
|
+
if (!actOrder.includes(n) && tabControlArgs[n] && !(order.hidden ?? []).includes(n)) {
|
|
166
|
+
tc.addPane(n, () => tabControlArgs[n]);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
// make sure that hidden functions are not checked;
|
|
170
|
+
(order.hidden ?? []).forEach((n) => {
|
|
171
|
+
calculatedFunctions[funcNamesMap[n]] = false;
|
|
172
|
+
});
|
|
173
|
+
addCheckboxesToPaneHeaders();
|
|
174
|
+
if (tc.panes.length > 0)
|
|
175
|
+
tc.currentPane = tc.panes[0];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
initTabs(getSavedFunctionOrdering());
|
|
149
179
|
function onOkProxy() {
|
|
150
180
|
const res: IComputeDialogResult = {descriptors: [], externals: {}, scripts: {}, queries: {}};
|
|
151
181
|
res.descriptors = calculatedFunctions[descriptorsName] ?
|
|
@@ -182,12 +212,15 @@ export async function chemFunctionsDialog(app: HitAppBase<any>,
|
|
|
182
212
|
onOk(res);
|
|
183
213
|
}
|
|
184
214
|
|
|
215
|
+
tc.root.appendChild(getReorderingInput(Object.keys(tabControlArgs), (newOrder) => {
|
|
216
|
+
initTabs(newOrder);
|
|
217
|
+
}));
|
|
185
218
|
if (dialog) {
|
|
186
219
|
ui.dialog('Compute')
|
|
187
220
|
.add(host)
|
|
188
221
|
.onOK(() => onOkProxy())
|
|
189
222
|
.onCancel(onCancel)
|
|
190
|
-
.show();
|
|
223
|
+
.show({resizable: true});
|
|
191
224
|
}
|
|
192
225
|
|
|
193
226
|
return {
|
package/src/app/utils.ts
CHANGED
|
@@ -3,7 +3,7 @@ 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
|
import {Subscription} from 'rxjs';
|
|
6
|
-
import {CampaignGroupingType, CampaignJsonName, ComputeQueryMolColName, HDCampaignsGroupingLSKey, i18n} from './consts';
|
|
6
|
+
import {CampaignGroupingType, CampaignJsonName, ComputeQueryMolColName, HDCampaignsGroupingLSKey, HTFunctionOrderingLSKey, i18n} from './consts';
|
|
7
7
|
import {AppName, CampaignsType, HitDesignCampaign, HitTriageCampaign, TriagePermissions} from './types';
|
|
8
8
|
import {_package} from '../package';
|
|
9
9
|
|
|
@@ -11,6 +11,24 @@ export const toFormatedDateString = (d: Date): string => {
|
|
|
11
11
|
return `${d.getFullYear()}/${d.getMonth() + 1}/${d.getDate()}`;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Modifies the current URL by updating or adding a query parameter with the specified key and value.
|
|
16
|
+
* Updates the browser's history state without reloading the page.
|
|
17
|
+
*
|
|
18
|
+
* @param key - The query parameter key to be added or updated in the URL.
|
|
19
|
+
* @param value - The value to be assigned to the specified query parameter key.
|
|
20
|
+
*
|
|
21
|
+
* @remarks
|
|
22
|
+
* This function uses the `history.replaceState` method to update the URL and browser history state.
|
|
23
|
+
* It ensures that the base URL remains unchanged and appends the query parameter.
|
|
24
|
+
* If `history.replaceState` is not supported, the function will not modify the URL.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* modifyUrl('page', '2');
|
|
29
|
+
* // Updates the URL to something like: http://example.com/?page=2
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
14
32
|
export function modifyUrl(key: string, value: string) {
|
|
15
33
|
const title = document.title;
|
|
16
34
|
const url = window.location.href.split('?')[0] + '?' + key + '=' + value;
|
|
@@ -360,3 +378,98 @@ export function timeoutOneTimeEventListener(element: HTMLElement, eventName: str
|
|
|
360
378
|
// df.name = 'Reinvent Design';
|
|
361
379
|
// return df;
|
|
362
380
|
// }
|
|
381
|
+
|
|
382
|
+
// #region Function ordering
|
|
383
|
+
|
|
384
|
+
export type FunctionOrdering = {
|
|
385
|
+
order: string[],
|
|
386
|
+
hidden: string[]
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function getSavedFunctionOrdering(): FunctionOrdering {
|
|
390
|
+
const orderingString = getLocalStorageValue<string>(HTFunctionOrderingLSKey) ?? '{}';
|
|
391
|
+
try {
|
|
392
|
+
const orderingP = JSON.parse(orderingString);
|
|
393
|
+
const ordering: FunctionOrdering = {
|
|
394
|
+
order: orderingP?.order ?? [],
|
|
395
|
+
hidden: orderingP?.hidden ?? [],
|
|
396
|
+
};
|
|
397
|
+
return ordering;
|
|
398
|
+
} catch (e) {
|
|
399
|
+
console.error('error parsing function ordering', e);
|
|
400
|
+
}
|
|
401
|
+
return {order: [], hidden: []};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
export function setSavedFunctionOrdering(ordering: FunctionOrdering) {
|
|
405
|
+
setLocalStorageValue(HTFunctionOrderingLSKey, JSON.stringify(ordering));
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export function getReorderedFunctionTabArgs(args: {[key: string]: HTMLElement}) {
|
|
409
|
+
const ordering = getSavedFunctionOrdering();
|
|
410
|
+
const orderedArgs: {[key: string]: HTMLElement} = {};
|
|
411
|
+
for (const key of ordering.order) {
|
|
412
|
+
if (args[key])
|
|
413
|
+
orderedArgs[key] = args[key];
|
|
414
|
+
}
|
|
415
|
+
for (const key in args) {
|
|
416
|
+
if (!orderedArgs[key] && !ordering.hidden.includes(key)) {
|
|
417
|
+
orderedArgs[key] = args[key];
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
return orderedArgs;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
export function getReorderingInput(functions: string[], onOk: (ordering: FunctionOrdering) => void) {
|
|
424
|
+
const order = getSavedFunctionOrdering();
|
|
425
|
+
const dataFrame = DG.DataFrame.fromColumns(functions.map((f) => DG.Column.fromStrings(f, [f])));
|
|
426
|
+
dataFrame.columns.setOrder(order.order ?? []);
|
|
427
|
+
const columnsEditor = ui.input.columns('reorder', {table: dataFrame, value: dataFrame.columns.toList().filter((c) => !order.hidden.includes(c.name))});
|
|
428
|
+
columnsEditor.onChanged.subscribe(() => {
|
|
429
|
+
try {
|
|
430
|
+
const chosenColumns = columnsEditor.value.map((c) => c.name);
|
|
431
|
+
const hiddenColumns = functions.filter((f) => !chosenColumns.includes(f));
|
|
432
|
+
const newOrdering = {
|
|
433
|
+
order: columnsEditor.value.map((c) => c.name),
|
|
434
|
+
hidden: hiddenColumns,
|
|
435
|
+
};
|
|
436
|
+
dataFrame.columns.setOrder(newOrdering.order);
|
|
437
|
+
setSavedFunctionOrdering(newOrdering);
|
|
438
|
+
onOk(newOrdering);
|
|
439
|
+
} catch (e) {
|
|
440
|
+
console.error(e);
|
|
441
|
+
}
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
const children = Array.from(columnsEditor.root.children) as HTMLElement[];
|
|
445
|
+
setTimeout(() => {
|
|
446
|
+
children.forEach((child) => {
|
|
447
|
+
child.style.maxWidth = '0px';
|
|
448
|
+
child.style.overflow = 'hidden';
|
|
449
|
+
child.style.padding = '0px';
|
|
450
|
+
child.style.paddingRight = '0px';
|
|
451
|
+
child.style.visibility = 'hidden';
|
|
452
|
+
if (child instanceof HTMLLabelElement)
|
|
453
|
+
child.style.display = 'none';
|
|
454
|
+
});
|
|
455
|
+
},200);
|
|
456
|
+
columnsEditor.root.style.justifyContent = 'end';
|
|
457
|
+
columnsEditor.root.style.width = '40px';
|
|
458
|
+
columnsEditor.root.style.height = '0px';
|
|
459
|
+
columnsEditor.root.style.overflow = 'visible';
|
|
460
|
+
columnsEditor.root.style.padding = '0px';
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
const editIcon = ui.icons.edit(() => {
|
|
464
|
+
children.forEach((child) => {
|
|
465
|
+
child.click();
|
|
466
|
+
});
|
|
467
|
+
}, 'Order or hide functions');
|
|
468
|
+
|
|
469
|
+
columnsEditor.addOptions(editIcon);
|
|
470
|
+
(Array.from(columnsEditor.root.children) as HTMLElement[]).forEach((child) => {
|
|
471
|
+
child.style.borderBottom = 'unset';
|
|
472
|
+
});
|
|
473
|
+
editIcon.style.fontSize = '16px';
|
|
474
|
+
return columnsEditor.root;
|
|
475
|
+
}
|