Skip to content

Commit

Permalink
[FEAT] filter search results by expert (#664)
Browse files Browse the repository at this point in the history
  • Loading branch information
UcDust authored Dec 5, 2024
1 parent 5458f09 commit 7cedab1
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 15 deletions.
11 changes: 11 additions & 0 deletions services/base-service/models/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,17 @@ const openapi = OpenAPI(
},
components: {
parameters: {
expert: {
in: "query",
name: "expert",
description: "Comma-separated search filter on experts",
required: false,
schema: {
type: "array"
},
style: "simple",
explode: false
},
expertId: {
name: 'expertId',
in: 'path',
Expand Down
5 changes: 4 additions & 1 deletion services/base-service/models/search/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ router.get(
search_valid_path(
{
description: "Returns matching search results for experts, including the number of matching works and grants",
parameters: ['p', 'page', 'size', 'type','status','availability'],
parameters: ['p', 'page', 'size', 'type','status','availability','expert'],
responses: {
"200": openapi.response('Search'),
"400": openapi.response('Invalid_request')
Expand All @@ -65,6 +65,9 @@ router.get(
if (req?.query.availability) {
params.availability = req.query.availability.split(',');
}
if (req?.query.expert) {
params.expert = req.query.expert.split(',');
}
if (req?.query.status) {
params.status = req.query.status.split(',');
}
Expand Down
21 changes: 21 additions & 0 deletions services/base-service/models/search/template/complete.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ template = {
}
}
{{/availability}}
{{#expert}}
,{ "terms": {
"@id": {{#toJson}}expert{{/toJson}}
}}
{{/expert}}
]
}
},
Expand All @@ -43,6 +48,22 @@ template = {
"must_not": [
{ "term": { "@type": "Expert" }}
]
{{#expert}}
,"must": {
"nested": {
"path": "@graph",
"query": {
"bool": {
"must": [
{ "exists": { "field": "@graph.@id" }},
{ "terms": {
"@graph.@id": {{#toJson}}expert{{/toJson}}
}}
]
}
}
}}
{{/expert}}
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export class SearchResultRow extends LitElement {
resultType : { type : String, attribute : 'result-type' },
hideCheckbox : { type : Boolean, attribute : 'hide-checkbox' },
hideSearchMatches : { type : Boolean, attribute : 'hide-search-matches' },
hideWorksMatches : { type : Boolean, attribute : 'hide-works-matches' },
};
}

Expand All @@ -27,7 +28,24 @@ export class SearchResultRow extends LitElement {
this.result = {};
this.resultType = '';
this.hideCheckbox = false;
this.hideSearchMatches = true; // bringing back search matches in next release
this.hideSearchMatches = false;
this.hideWorksMatches = true; // bringing back search matches in next release
}

/**
* @method _filterByGrants
* @description filter by grants
* @param {Object} e
*/
_filterByGrants(e) {
e.preventDefault();

this.dispatchEvent(new CustomEvent('filter-by-grants', {
detail: {
id: this.result.id,
name: this.result.name
}
}));
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ export default function render() {
padding-top: 0.4rem;
}
.search-result-matches a {
color: var(--color-aggie-blue-80);
}
.search-matches {
padding-right: .25rem;
}
Expand Down Expand Up @@ -99,11 +103,11 @@ export default function render() {
</div>
</div>
<div ?hidden="${this.result.subtitle.length === 0}" class="search-result-sub-text">${unsafeHTML(this.result.subtitle)}</div>
<div class="search-result-matches" ?hidden="${this.hideSearchMatches}">
<span class="search-matches">Search matches:</span>
<span>${this.result.numberOfGrants} grants</span>
<span class="dot-separator">.</span>
<span>${this.result.numberOfWorks} works</span>
<div class="search-result-matches" ?hidden="${this.hideSearchMatches || this.resultType !== 'expert'}">
<span ?hidden="${this.result.numberOfGrants === 0}" class="search-matches">Search matches:</span>
<span ?hidden="${this.result.numberOfGrants === 0}"><a href="" @click="${this._filterByGrants}">${this.result.numberOfGrants} grants</a></span>
<span class="dot-separator" ?hidden="${this.hideWorksMatches}">.</span>
<span ?hidden="${this.hideWorksMatches}">${this.result.numberOfWorks} works</span>
</div>
</div>
`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export default class AppSearch extends Mixin(LitElement)
type : { type : String },
status : { type : String },
showOpenTo : { type : Boolean },
filterByExpert : { type : Boolean },
filterByExpertId : { type : String },
filterByExpertName : { type : String }
}
}

Expand All @@ -61,6 +64,9 @@ export default class AppSearch extends Mixin(LitElement)
this.type = '';
this.status = '';
this.showOpenTo = false;
this.filterByExpert = false;
this.filterByExpertId = '';
this.filterByExpertName = '';

this.render = render.bind(this);
}
Expand Down Expand Up @@ -180,6 +186,34 @@ export default class AppSearch extends Mixin(LitElement)
this._onSearch({ detail: this.searchTerm }, true); // reset to first page
}

/**
* @method _filterByGrants
* @description filter by grants
* @param {Object} e
*/
_filterByGrants(e) {
// TODO eventually multiple experts could be supported, for now just one needed
// filter by grants for this expert
this.filterByExpertId = e.detail.id;
this.filterByExpertName = e.detail.name;
if( this.filterByExpertId && this.filterByExpertName ) {
this.filterByExpert = true;
this.addingFilter = true;
this._updateLocation();
}
}

/**
* @method _removeExpertFilter
* @description remove the expert filter
*/
_removeExpertFilter(e) {
this.filterByExpert = false;
this.filterByExpertId = '';
this.filterByExpertName = '';
this._updateLocation();
}

/**
* @method _onSearch
* @description called from the search box button is clicked or
Expand Down Expand Up @@ -214,22 +248,28 @@ export default class AppSearch extends Mixin(LitElement)
this.resultsPerPage,
availability,
this.AppStateModel.location.query.type,
this.AppStateModel.location.query.status
this.AppStateModel.location.query.status,
this.filterByExpertId
)
),
true
);
}

_updateLocation() {
if( this.addingFilter && this.filterByExpert ) {
this.type = 'grant';
this.addingFilter = false;
}

// url should be /search/<searchTerm> if no search filters, otherwise /search?=<searchTerm>&availability=collab,community,industry,media etc
let availability = [];
if( this.collabProjects ) availability.push('collab');
if( this.commPartner ) availability.push('community');
if( this.industProjects ) availability.push('industry');
if( this.mediaInterviews ) availability.push('media');

let hasQueryParams = availability.length || this.type.length; // TODO dates
let hasQueryParams = availability.length || this.type.length || this.filterByExpert || this.status.length;

let path = hasQueryParams ? '/search' : `/search/${encodeURIComponent(this.searchTerm)}`;
if( this.currentPage > 1 || this.resultsPerPage > 25 ) path += `/${this.currentPage}`;
Expand All @@ -239,6 +279,7 @@ export default class AppSearch extends Mixin(LitElement)
if( availability.length ) path += `&availability=${availability.join(',')}`;
if( this.type.length ) path += `&type=${this.type}`;
if( this.status.length ) path += `&status=${this.status}`;
if( this.filterByExpert ) path += `&expert=${this.filterByExpertId}`;

this.AppStateModel.setLocation(path);
}
Expand Down Expand Up @@ -337,7 +378,8 @@ export default class AppSearch extends Mixin(LitElement)
this.resultsPerPage,
availability,
this.AppStateModel.location.query.type,
this.AppStateModel.location.query.status
this.AppStateModel.location.query.status,
this.filterByExpertId
)
),
true
Expand Down Expand Up @@ -475,7 +517,7 @@ export default class AppSearch extends Mixin(LitElement)
}

_updateAvailableFilters() {
this.showOpenTo = !this.type || this.type === 'expert';
this.showOpenTo = this.type === 'expert';
// TODO others, dates hidden when viewing Experts
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,12 @@ return html`
.search-results-heading {
display: flex;
align-items: center;
height: 60px;
padding-top: .8rem;
/* height: 60px;
padding-top: .8rem; */
}
.search-content app-search-box {
padding-bottom: 0.8rem;
}
.search-container .open-to-heading h4 {
Expand Down Expand Up @@ -306,6 +310,52 @@ return html`
padding-bottom: 2rem;
}
.results-filtered-to {
display: flex;
align-items: center;
color: var(--color-aggie-blue);
font-size: 1.3rem;
font-style: italic;
font-weight: 700;
word-wrap: break-word;
}
.results-filtered-to span {
padding-right: 0.5rem;
}
.results-filtered-to p {
margin: 0;
}
.results-filtered-to button {
background-color: var(--color-aggie-blue-80);
color: white;
border-color: transparent;
padding: 0.25rem 1rem;
font-size: 1.1rem;
}
.results-filtered-to button:hover {
color: white;
}
.results-filtered-to button .close {
padding: 0 0 0 0.7rem;
}
.results-filtered-to button .close ucdlib-icon {
padding: 3px;
}
.results-filtered-to button:hover .close ucdlib-icon {
fill: var(--color-aggie-blue-80);
border-radius: 50%;
background-color: var(--color-aggie-blue-50);
/* transition: background-color 0.3s ease-in-out; */
/* transition: fill 0.3s ease-in-out; */
}
</style>
<div class="search-header">
Expand Down Expand Up @@ -415,6 +465,18 @@ return html`
</div>
</div>
<div class="results-filtered-to" ?hidden="${!this.filterByExpert}">
<span>Experts:</span>
<p>
<button class="btn btn--round" @click="${this._removeExpertFilter}">
${this.filterByExpertName}
<div class="close">
<ucdlib-icon icon="ucdlib-experts:fa-times"></ucdlib-icon>
</div>
</button>
</p>
</div>
<div class="search-results-heading">
<div class="results-count">${this.totalResultsCount != null ? this.totalResultsCount : this.resultsLoading} result${this.totalResultsCount === 1 ? '' : 's'} for "${this.searchTerm}"</div>
<div class="download">
Expand Down Expand Up @@ -446,7 +508,8 @@ return html`
<app-search-result-row
search-result="${result.position}"
.result=${result}
result-type="${result.resultType}">
result-type="${result.resultType}"
@filter-by-grants="${this._filterByGrants}">
</app-search-result-row>
<hr class="search-seperator">
`
Expand Down
5 changes: 4 additions & 1 deletion services/base-service/spa/client/public/lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -406,13 +406,16 @@ class Utils {
* @param {Number} size number of results per page, defaults to 25
* @param {Array} availability array of availability filters
* @param {String} type type of search, ie 'grant', 'expert'. if none set, returns all results
* @param {String} status status of search, ie 'active', 'completed'. if none set, returns all results
* @param {String} expertId expertId to filter grants/works to
*/
buildSearchQuery(searchTerm, page=1, size=25, availability=[], type, status) {
buildSearchQuery(searchTerm, page=1, size=25, availability=[], type, status, expertId) {
let searchQuery = `q=${searchTerm}&page=${page}&size=${size}`;

if( availability.length ) searchQuery += `&availability=${encodeURIComponent(availability.join(','))}`;
if( type ) searchQuery += `&type=${type}`;
if( status ) searchQuery += `&status=${status}`;
if( expertId ) searchQuery += `&expert=${encodeURIComponent(expertId)}`;

return searchQuery;
}
Expand Down

0 comments on commit 7cedab1

Please sign in to comment.