Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow toggling samples & regions in add things step UI #1378 #1343

Merged
merged 7 commits into from
Nov 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions arches_for_science/media/css/project.css
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,27 @@
padding-right: 5px;
}

.child-exclusion {
display: inline-flex;
flex-direction: row;
justify-content: center;
margin-left: 10px;
}

.child-exclusion .toggle-container {
padding-bottom: 0px;
display: inline-flex;
}

.child-exclusion .toggle-container .arches-toggle-sm {
margin: 0;
color: #888;
}

.child-exclusion .toggle-container .arches-toggle-subtitle {
display: none;
}

.object-search-step .search-results-footer {
height: 55px;
background-color: #f3f3f3;
Expand Down Expand Up @@ -177,6 +198,10 @@
cursor: pointer;
}

.wf-multi-tile-step-list .child {
margin-left: 20px;
}

.wf-multi-tile-btn-complete {
position: absolute;
bottom: 305px;
Expand All @@ -188,6 +213,7 @@
max-width: calc(100%);
white-space: nowrap;
overflow: hidden;
text-wrap: unset;
}

.wf-multi-tile-card-info-details dd {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ define([
params.dirty(dirty);
});

this.includeSamples = ko.observable(false);
this.includeAnalysisAreas = ko.observable(false);
this.childPhysicalThingValue = {
sample: '77d8cf19-ce9c-4e0a-bde1-9148d870e11c',
location: '7375a6fb-0bfb-4bcf-81a3-6180cdd26123',
analysis: '31d97bdd-f10f-4a26-958c-69cb5ab69af1',
};
this.physicalThingTypeNodeId = '8ddfe3ab-b31d-11e9-aff0-a4d18cec433a';
const sampleSubstring = '[Sample'; // for "[Sample of ..." and "[Sample Area of ..."
const regionSubstring = '[Region';

this.value.subscribe(function(a) {
a.forEach(function(action) {
if (action.status === 'added') {
Expand All @@ -101,6 +112,7 @@ define([
});
}
});
self.sortSelectedResources();
}, null, "arrayChange");

const loadExistingCollection = async function(){
Expand All @@ -124,6 +136,55 @@ define([
}
};

this.sortSelectedResources = () => {
// Sort alphabetically by display name, without regard to child physical things.
const sortedDisplayNames = self.selectedResources().map(
res => self.getStringValue(res.displayname)
).map(val => val.toLowerCase()).sort();

const resourceSortFn = (a, b) => {
const aIndex = sortedDisplayNames.indexOf(self.getStringValue(a.displayname).toLowerCase());
const bIndex = sortedDisplayNames.indexOf(self.getStringValue(b.displayname).toLowerCase());
if (aIndex < bIndex) {
return -1;
} else if (aIndex === bIndex) {
return 0;
}
return 1;
};
this.selectedResources().sort(resourceSortFn);

// Then, reorder child physical things under parents.
const sortedParents = this.selectedResources().filter(resource =>
!self.resourceIsSampleOrAnalysis(resource)
);
const childrenByParentResourceId = {};
for (const child of this.selectedResources().filter(r => !sortedParents.includes(r))) {
const parentResourceId = child.tiles.find(t => t.data['f8d5fe4c-b31d-11e9-9625-a4d18cec433a'])
.data['f8d5fe4c-b31d-11e9-9625-a4d18cec433a'][0].resourceId;
if (childrenByParentResourceId[parentResourceId] === undefined) {
childrenByParentResourceId[parentResourceId] = [child];
} else {
childrenByParentResourceId[parentResourceId].push(child);
}
}
var finalSort = [];
for (const parent of sortedParents) {
finalSort.push(parent);
if (childrenByParentResourceId[parent.resourceinstanceid]) {
finalSort = finalSort.concat(childrenByParentResourceId[parent.resourceinstanceid]);
delete childrenByParentResourceId[parent.resourceinstanceid];
}
}
// Tack on children of missing parents (unlikely, but possible)
for (const orphans of Object.values(childrenByParentResourceId)) {
if (orphans) {
finalSort = finalSort.concat(orphans);
}
}
this.selectedResources(finalSort);
};

this.initialize = function(){
if (params.value()) {
const cachedValue = ko.unwrap(params.value);
Expand Down Expand Up @@ -273,8 +334,11 @@ define([
self.termOptions = results;

const filteredResults = results.filter(function(result){
return result.context_label.includes("Physical Thing") ||
result.context_label.includes("Search Term");
return (
result.context_label.includes("Physical Thing") ||
result.context_label.includes("Search Term")
) && (self.includeSamples() || !result.text.includes(sampleSubstring))
&& (self.includeAnalysisAreas() || !result.text.includes(regionSubstring))
Comment on lines +340 to +341
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still found substring matching necessary to filter out children from the select2 widget, as I don't have access to concepts/tiles at that point. Open to other ideas.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could do something like this on the Arches side: https://github.com/archesproject/arches/pull/10216/files

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the graphid will help, because both samples and their parents will share the same graph id for physical thing. AFAICT I would need to drill in to the tile data along the lines of what I did in the middle of the long sort function added in this PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested it out, and this is all I get back with archesproject/arches#10216:

        {
            "context": "",
            "context_label": "Physical Thing - Name",
            "graphid": "9519cb4f-b25b-11e9-8c7b-a4d18cec433a",
            "id": 1,
            "text": "qwe [Sample of Alabastron (2003.192)]",
            "type": "term",
            "value": "qwe [Sample of Alabastron (2003.192)]"
        },
        {
            "context": "",
            "context_label": "Physical Thing - Name",
            "graphid": "9519cb4f-b25b-11e9-8c7b-a4d18cec433a",
            "id": 2,
            "text": "qwe [Sample Area of Alabastron (2003.192)]",
            "type": "term",
            "value": "qwe [Sample Area of Alabastron (2003.192)]"
        }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see - right, it's the distinction between types of physical things that is needed, not resource models.

});
return {
results: filteredResults,
Expand Down Expand Up @@ -307,7 +371,7 @@ define([

var getResultData = function(termFilter, pagingFilter) {
var filters = {};
// let's empty our termFilters
// let's empty term-filter and advanced-search
_.each(self.filters, function(_value, key) {
if (key !== 'paging-filter' && key !== 'search-results') {
delete self.filters[key];
Expand All @@ -319,6 +383,45 @@ define([
filters["term-filter"] = JSON.stringify([termFilter]);
}

const conceptFilters = [];
if (!self.includeSamples()) {
conceptFilters.push({
op: 'and',
[self.physicalThingTypeNodeId]: {
op: '!eq',
val: self.childPhysicalThingValue.sample,
},
});
conceptFilters.push({
op: 'and',
[self.physicalThingTypeNodeId]: {
op: '!eq',
val: self.childPhysicalThingValue.location,
},
});
}
if (!self.includeAnalysisAreas()) {
conceptFilters.push({
op: 'and',
[self.physicalThingTypeNodeId]: {
op: '!eq',
val: self.childPhysicalThingValue.analysis,
},
});
}
if (!self.includeAnalysisAreas() || !self.includeSamples()) {
conceptFilters.push({
op: 'or',
[self.physicalThingTypeNodeId]: {
op: 'null',
val: '',
},
});
}
if (conceptFilters.length) {
filters['advanced-search'] = JSON.stringify(conceptFilters);
}

if (pagingFilter) {
filters['paging-filter'] = pagingFilter;
self.filters['paging-filter'](pagingFilter);
Expand Down Expand Up @@ -376,6 +479,13 @@ define([
self.updateSearchResults(self.termFilter(), query['paging-filter']);
});

this.includeSamples.subscribe(function(val) {
self.updateSearchResults(self.termFilter());
});
this.includeAnalysisAreas.subscribe(function(val) {
self.updateSearchResults(self.termFilter());
});

this.initialize();

this.stripTags = (original) => {
Expand All @@ -388,6 +498,15 @@ define([
}
return value.find(str => str.language == arches.activeLanguage)?.value;
};

this.getChildPhysicalThingType = (resource) => {
return resource.tiles.find(tile => tile.data[self.physicalThingTypeNodeId] !== undefined)
?.data?.[this.physicalThingTypeNodeId]?.[0];
};

this.resourceIsSampleOrAnalysis = (resource) => {
return Object.values(self.childPhysicalThingValue).includes(self.getChildPhysicalThingType(resource));
};
}

ko.components.register('add-things-step', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ define([
}
}

const tilesBelongingToManifest = this.tilesBelongingToManifest(self.card.tiles(), self.canvases());
const tilesBelongingToManifest = this.tilesBelongingToManifest(self.card.tiles());
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated cleanup re #1304; this function no longer takes two args, missed it before merge.

tilesBelongingToManifest.forEach(tile => tile.samplingActivityResourceId = tile.samplingActivityResourceId ? tile.samplingActivityResourceId : ko.observable());
self.sampleLocationInstances(tilesBelongingToManifest);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,34 @@
<div class="workflow-search-count">
<div class="count-number" data-bind="text: totalResults()"></div><div>Physical Things</div>
</div>
<div class="child-exclusion">
<div
data-bind="
component: {
name: 'views/components/simple-switch',
params: {
value: includeSamples,
config: {
label: 'Include samples',
}
}
}
"
></div>
<div
data-bind="
component: {
name: 'views/components/simple-switch',
params: {
value: includeAnalysisAreas,
config: {
label: 'Include analysis areas',
}
}
}
"
></div>
</div>
</div>
<div class="workflow-search-results">
<div class="workflow-search-results-full-container">
Expand Down Expand Up @@ -48,7 +76,7 @@
</div>
<!--/ko -->
<!-- ko foreach: selectedResources -->
<div class="wf-multi-tile-step-card" >
<div class="wf-multi-tile-step-card" data-bind="css: { child: $parent.resourceIsSampleOrAnalysis($data) }">
<div class="wf-multi-tile-card-info">
<!-- <div class="workflow-step-icon complete"><span><i class="fa fa-hashtag"></i></span></div> -->
<div class="wf-multi-tile-card-info-details">
Expand Down
Loading