Skip to content

Commit 394fc82

Browse files
Faceted filtering based on selections
1 parent 5161170 commit 394fc82

File tree

3 files changed

+108
-27
lines changed

3 files changed

+108
-27
lines changed

lib/DataHarmonizer.js

+3
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ class DataHarmonizer {
627627
rowHeaders: true,
628628
copyPaste: true,
629629
contextMenu: ['remove_row', 'row_above', 'row_below'],
630+
outsideClickDeselects: false, // for maintaining selection between tabs
630631
manualColumnResize: true,
631632
//colWidths: [100], //Just fixes first column width
632633
minRows: 100,
@@ -639,6 +640,7 @@ class DataHarmonizer {
639640
indicators: true,
640641
columns: [],
641642
},
643+
filters: true,
642644
hiddenRows: {
643645
rows: [],
644646
},
@@ -782,6 +784,7 @@ class DataHarmonizer {
782784
}
783785
}.bind(self)
784786
);
787+
785788
}
786789

787790
addRowsToBottom(numRows) {

web/index.js

+99-21
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,12 @@ class AppConfig {
6868
}
6969

7070
class AppContext {
71+
7172
schema_tree = {};
7273
dhs = {};
7374
current_data_harmonizer_name = null;
7475
template = null;
76+
7577

7678
constructor(appConfig) {
7779
this.appConfig = appConfig;
@@ -138,21 +140,6 @@ class AppContext {
138140
);
139141
}
140142

141-
async propagateChangeToChildren(node_label, func = (id) => id) {
142-
const dependency_tree = await this.getDependencyTree();
143-
let current_node_label = node_label;
144-
let children_index = 0;
145-
do {
146-
func(dependency_tree[current_node_label].data);
147-
this.propagateData(
148-
dependency_tree[current_node_label].children[children_index]
149-
);
150-
children_index++;
151-
} while (
152-
dependency_tree[current_node_label].children.length > children_index
153-
);
154-
}
155-
156143
/**
157144
* Finds slots with suffixes shared across multiple prefixes in the given slot usage data.
158145
*
@@ -487,7 +474,6 @@ class AppContext {
487474
const _export_formats =
488475
exportFormats || (await context.getExportFormats(_template_name));
489476
const schema_tree = buildSchemaTree(schema);
490-
context.appConfig.template_path.split('/');
491477
context.setSchemaTree(schema_tree);
492478
data_harmonizers = makeDataHarmonizersFromSchemaTree(
493479
this,
@@ -579,6 +565,7 @@ function findSlotNamesForClass(schema, class_name) {
579565
* @returns {Object|null} The schema tree object, or null if no "Container" classes are found.
580566
*/
581567
function buildSchemaTree(schema) {
568+
582569
function updateChildrenAndSharedKeys(data) {
583570
// Use a deep clone to avoid mutating the original object
584571
const result = JSON.parse(JSON.stringify(data));
@@ -624,8 +611,7 @@ function buildSchemaTree(schema) {
624611
return result;
625612
}
626613

627-
// TODO: extend to actually create the schema_tree object here for single class schemas
628-
if (typeof schema.classes['Container'] !== 'undefined') {
614+
if (typeof schema.classes['Container'] === 'undefined') {
629615
const class_names = Object.keys(schema.classes).filter(
630616
(key) => key !== 'dh_interface'
631617
);
@@ -649,11 +635,15 @@ function buildSchemaTree(schema) {
649635
});
650636
}, {}),
651637
};
652-
}
638+
639+
};
640+
641+
console.log('has Container')
653642

654643
const classes = Object.keys(schema.classes).filter(
655-
(el) => el !== 'dh_interface'
644+
(el) => el !== 'dh_interface' && el !== 'Container'
656645
);
646+
657647
const tree_base = {
658648
Container: { tree_root: true, children: classes },
659649
};
@@ -669,7 +659,9 @@ function buildSchemaTree(schema) {
669659
return acc;
670660
}, tree_base);
671661

672-
return updateChildrenAndSharedKeys(pre_schema_tree);
662+
const schema_tree = updateChildrenAndSharedKeys(pre_schema_tree);
663+
console.log(schema_tree)
664+
return schema_tree;
673665
}
674666

675667
/**
@@ -908,13 +900,19 @@ function setupSharedColumn(data_harmonizer, shared_key_name, callback) {
908900
*/
909901
function makeSharedKeyHandler(data_harmonizer, schema_tree_node) {
910902
const makeUpdateHandler = (shared_key_spec) => {
903+
911904
const updateSchemaNodeChildrenCallback = (
912905
changes,
913906
source,
914907
old_value,
915908
new_value
916909
) => {
910+
917911
schema_tree_node.children.forEach((cls_key) => {
912+
913+
// lift this out to a more general function?
914+
915+
// transformation handler: what to do when a cell with a shared key is updated
918916
transformMultivaluedColumn(
919917
data_harmonizers[cls_key],
920918
shared_key_spec,
@@ -923,15 +921,19 @@ function makeSharedKeyHandler(data_harmonizer, schema_tree_node) {
923921
old_value,
924922
new_value
925923
);
924+
926925
// TODO does this need to recur to get more than ~2 depths of recursion in hierarchy?
927926
// visitSchemaTree(schema_tree, (schema_tree_node) => {
928927
// schema_tree_node.children.forEach(cls_key => {
929928
// visitSchemaTree(schema_tree, () => transformMultivaluedColumn(data_harmonizers[cls_key], shared_key_name, changes, source, old_value, new_value), cls_key)
930929
// })
931930
// }, cls_key);
931+
932932
});
933933
};
934+
934935
return updateSchemaNodeChildrenCallback;
936+
935937
};
936938

937939
schema_tree_node.shared_keys.forEach((shared_key_spec) => {
@@ -977,6 +979,82 @@ function attachPropagationEventHandlersToDataHarmonizers(
977979
}
978980
}
979981
});
982+
983+
984+
function stripDiv(html) {
985+
const div = document.createElement("div");
986+
div.innerHTML = html;
987+
return (div.innerText);
988+
}
989+
990+
Object.values(data_harmonizers).forEach(dh => {
991+
992+
dh.hot.addHook('afterSelection', (row, col) => {
993+
const valueToMatch = dh.hot.getDataAtCell(row, col);
994+
995+
// get value at cell
996+
// filter other data harmonizer at cell
997+
schema_tree[dh.class_assignment].children.forEach(child_name => {
998+
const shared_key_name = schema_tree[dh.class_assignment].shared_keys.filter(el => el.related_concept === child_name)[0].name;
999+
visitSchemaTree(
1000+
schema_tree,
1001+
(schema_tree_node) => {
1002+
1003+
const hot = data_harmonizers[schema_tree_node.name].hot;
1004+
const columnHeaders = hot.getColHeader();
1005+
const columnName = shared_key_name; // shared_key based on event selection ~ replace columnIndex with event data?
1006+
const columnIndex = columnHeaders.map(stripDiv).findIndex(header => header === columnName);
1007+
1008+
if (columnIndex === -1) {
1009+
console.error('Column name not found');
1010+
return;
1011+
}
1012+
const plugin = hot.getPlugin('filters');
1013+
// Add a condition where the column value equals the specified value
1014+
plugin.clearConditions(columnIndex); // change valueToMatch per new selection in the column
1015+
plugin.addCondition(columnIndex, 'eq', [valueToMatch]);
1016+
plugin.filter();
1017+
1018+
},
1019+
child_name)
1020+
})
1021+
});
1022+
1023+
dh.hot.addHook('afterDeselect', () => {
1024+
1025+
// get value at cell
1026+
// filter other data harmonizer at cell
1027+
schema_tree[dh.class_assignment].children.forEach(child_name => {
1028+
1029+
const shared_key_name = schema_tree[dh.class_assignment].shared_keys.filter(el => el.related_concept === child_name)[0].name;
1030+
1031+
visitSchemaTree(
1032+
schema_tree,
1033+
(schema_tree_node) => {
1034+
1035+
const hot = data_harmonizers[schema_tree_node.name].hot;
1036+
const columnHeaders = hot.getColHeader();
1037+
const columnName = shared_key_name; // shared_key based on event selection ~ replace columnIndex with event data?
1038+
const columnIndex = columnHeaders.map(stripDiv).findIndex(header => header === columnName);
1039+
1040+
if (columnIndex === -1) {
1041+
console.error('Column name not found');
1042+
return;
1043+
}
1044+
1045+
const plugin = hot.getPlugin('filters');
1046+
plugin.clearConditions(columnIndex);
1047+
plugin.filter();
1048+
1049+
},
1050+
child_name)
1051+
1052+
})
1053+
});
1054+
// TODO: preserve memory of selection between tabs! in DH? => using outsideClickDeselects: false, // for maintaining selection between tabs
1055+
1056+
})
1057+
9801058
return data_harmonizers;
9811059
}
9821060

web/templates/menu.json

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11

22
{
3-
"test": {
4-
"TEST": {
5-
"name": "TEST",
3+
"grdi": {
4+
"GRDI_Sample": {
5+
"name": "GRDI_Sample",
66
"status": "published",
77
"display": true
88
}
99
},
10-
"grdi": {
11-
"GRDI_Sample": {
12-
"name": "GRDI_Sample",
10+
"test": {
11+
"TEST": {
12+
"name": "TEST",
1313
"status": "published",
1414
"display": true
1515
}

0 commit comments

Comments
 (0)