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

Add concept sets search (mergeable) #2889

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
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
61 changes: 61 additions & 0 deletions js/components/advancedSearch/advancedSearch.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<!--search panel-->
<script type="text/html" id="vocabulary-domain-list">
<div class="checkboxListing row">
<!-- ko if: loading -->
<loading></loading>
<!-- /ko -->
<!-- ko if: domains().length === 0 && !loading() -->
<empty-state params="message: ko.i18n('search.noDomainsAvailable', 'No domains available')"></empty-state>
<!-- /ko -->
<div class="pull-right">
<button class="btn-link" data-bind="click: clearAll">
Clear all selected
</button>
</div>
<!-- ko foreach: domains() -->
<div class="col-sm-6">
<input
type="checkbox"
data-bind="value: DOMAIN_ID, event: { change: (e) => $parent.selectDomain(DOMAIN_ID) }"
> <span data-bind="text: DOMAIN_NAME"></span>
</div>
<!-- /ko -->
</div>
</script>

<!-- ko if: loading()-->
<loading></loading>
<!-- /ko -->
<!-- ko if: !loading()-->
<div class="advanced-options">
<form data-bind="submit: search">
<div class="input-group">
<input type="text" data-bind="textInput: querySearch,
css: classes({
element: 'input',
extra: 'form-control'
}),
placeholder: ko.i18n('cs.browser.searchQueryPlaceholder', 'Search by Concept ID, Concept Code, Concept Name'),
disable: loading()" />
<div class="input-group-btn">
<button type="submit" class="btn btn-primary" data-bind="title: ko.i18n('search.buttonTitle', 'Search'), disable: loading()"><i class="fa fa-search"></i></button>
<button class="btn btn-danger" data-bind="click: resetSearchConceptSets, title: ko.i18n('cs.browser.clearSearchCS', 'Clear search concept sets'), disable: loading()"><i class="fa fa-times"></i></button>
</div>
</div>
</form>
<div class="row">
<div data-bind="click: toggleAdvanced, text: ko.i18n('search.advancedOptions', 'Advanced Options')" class="pull-right btn btn-sm btn-link"></div>
</div>
<div data-bind="visible: showAdvanced">
<panel-list
params="
title: ko.i18n('search.domains', 'Domains'),
templateId: 'vocabulary-domain-list',
context: $data,
clearAll:clearAll,
selectElement: selectDomain,
panelCollapsable:panelCollapsable">
</panel-list>
</div>
</div>
<!-- /ko -->
99 changes: 99 additions & 0 deletions js/components/advancedSearch/advancedSearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
define([
'knockout',
'components/Component',
'utils/AutoBind',
'utils/CommonUtils',
'text!./advancedSearch.html',
'services/http',
'pages/vocabulary/const',
'./components/panelList',
], function (
ko,
Component,
AutoBind,
commonUtils,
view,
httpService,
constants,
) {
class AdvancedSearch extends AutoBind(Component) {
constructor(params) {
super(params);
this.querySearch = ko.observable('');
this.loading = ko.observable(false);
this.domains = ko.observable();
this.selectedDomains = new Set();
this.panelCollapsable = ko.observable(true);
this.searchConceptSets = params.searchConceptSets;
this.showSearch = params.showSearch;
this.showAdvanced = ko.observable(false);
this.refreshConceptSets = params.refreshConceptSets;
this.getDomains();

//subscriptions
this.showSearch.subscribe((newValue) => {
if(!newValue) {
this.panelCollapsable(true);
this.showAdvanced(false);
this.refreshConceptSets();
}
});
}

clearAll(data,event) {
event.stopPropagation();
$('.advanced-options input').attr('checked', false);
this.selectedDomains.clear();
}

selectDomain(id) {
this.selectedDomains.has(id)
? this.selectedDomains.delete(id)
: this.selectedDomains.add(id, true);
}

search() {
if (this.querySearch().trim().length < 2) {
return alert('Search must have at least 2 letters');
}
const searchParams = {
query: this.querySearch,
domainId: Array.from(this.selectedDomains)
};
this.showAdvanced(false);
this.panelCollapsable(true);
this.searchConceptSets(searchParams);

}

resetSearchConceptSets() {
$('.advanced-options input').attr('checked', false);
this.selectedDomains.clear();
this.querySearch('');
this.showAdvanced(false);
this.panelCollapsable(true);
this.refreshConceptSets();
}

getDomains() {
this.loading(true);
httpService.doGet(constants.apiPaths.domains())
.then(({ data }) => {
this.domains(data);
})
.catch(er => console.error('Error occured when loading domains', er))
.finally(() => {
this.loading(false);
});
}

toggleAdvanced() {
if(this.showAdvanced()) {
this.panelCollapsable(true);
}
this.showAdvanced(!this.showAdvanced());
}

}
return commonUtils.build('advanced-search', AdvancedSearch, view);
});
38 changes: 38 additions & 0 deletions js/components/advancedSearch/components/panel-list.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.panel {

&__header {
font-size: 1.4rem;
padding-left: 1rem;
padding-right: 1rem;
}

&__content {
padding: 1rem;
}
}

.panel-heading-collapsible {
display: flex;
justify-content: space-between;
cursor: pointer;
border-top-right-radius: 4px;
border-top-left-radius: 4px;
}
.active .icon-chevron:after {
/* symbol for "collapsed" panels */
font-family: 'Font Awesome 5 Free';
content: "\f078";
font-weight: 900;
}

.icon-chevron:after {
font-family: 'Font Awesome 5 Free';
content: "\f077";
font-weight: 900;

}

.advanced-panel {
margin: 10px 0;
border-radius: 4px;
}
19 changes: 19 additions & 0 deletions js/components/advancedSearch/components/panelList.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div data-bind="
css: classes({ extra: 'panel panel-primary advanced-panel' }),
collapsable: showText, collapseTargetClass: 'panel-body',
collapseOptions: { selectorClass: 'panel-heading', collapsabledClass: 'active'}">
<div data-bind=" click: toggleShow" class="panel-heading panel-heading-collapsible">
<div data-bind="text: title"></div>
<div>
<span class="icon-chevron"></span>
</div>
</div>
<div class="panel-body collapse">
<!-- ko template: { name: templateId, data: context } --><!-- /ko -->
</div>
</div>





29 changes: 29 additions & 0 deletions js/components/advancedSearch/components/panelList.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
define([
'knockout',
'text!./panelList.html',
'components/Component',
'utils/CommonUtils',
'less!./panel-list.less',
], function (
ko,
view,
Component,
commonUtils
) {
class PanelList extends Component {
constructor(params) {
super(params);
this.title = params.title;
this.templateId = params.templateId;
this.context = params.context;
this.selectElement = params.selectElement;
this.showText = params.panelCollapsable;
}

toggleShow() {
this.showText(!this.showText());
}
}

return commonUtils.build('panel-list', PanelList, view);
});
48 changes: 41 additions & 7 deletions js/components/circe/components/ConceptSetBrowser.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ define([
'services/AuthAPI',
'utils/DatatableUtils',
'utils/CommonUtils',
'services/ConceptSet',
'components/ac-access-denied',
'components/advancedSearch/advancedSearch',
'databindings',
'css!./style.css'
], function (ko, template, VocabularyProvider, appConfig, ConceptSet, authApi, datatableUtils, commonUtils) {
], function (ko, template, VocabularyProvider, appConfig, ConceptSet, authApi, datatableUtils, commonUtils, conceptSetService) {
function CohortConceptSetBrowser(params) {
var self = this;

Expand Down Expand Up @@ -59,7 +61,6 @@ define([
});
}


function setDisabledConceptSetButton(action) {
if (action && action()) {
return action()
Expand All @@ -68,6 +69,12 @@ define([
}
}

function prepareDataTable (results) {
datatableUtils.coalesceField(results, 'modifiedDate', 'createdDate');
datatableUtils.addTagGroupsToFacets(results, self.options.Facets);
datatableUtils.addTagGroupsToColumns(results, self.columns);
}

self.datatableUtils = datatableUtils;
self.criteriaContext = params.criteriaContext;
self.cohortConceptSets = params.cohortConceptSets;
Expand Down Expand Up @@ -96,12 +103,10 @@ define([

self.loadConceptSetsFromRepository = function (url) {
self.loading(true);

VocabularyProvider.getConceptSetList(url)
const sourceUrl = url ? url : self.selectedSource().url;
VocabularyProvider.getConceptSetList(sourceUrl)
.done(function (results) {
datatableUtils.coalesceField(results, 'modifiedDate', 'createdDate');
datatableUtils.addTagGroupsToFacets(results, self.options.Facets);
datatableUtils.addTagGroupsToColumns(results, self.columns);
prepareDataTable(results);
self.repositoryConceptSets(results);
self.loading(false);
})
Expand Down Expand Up @@ -179,6 +184,35 @@ define([
const { pageLength, lengthMenu } = commonUtils.getTableOptions('M');
this.pageLength = params.pageLength || pageLength;
this.lengthMenu = params.lengthMenu || lengthMenu;

// advanced search
this.showSearch = ko.observable(false);

self.checkSearchAvailable = async function () {
self.loading(true);
try {
const data = await conceptSetService.checkSearchAvailable();
self.showSearch(data);
} catch(e) {
throw new Error(e);
} finally {
self.loading(false);
}
};
self.searchConceptSets = async function (searchParams) {
self.loading(true);
try {
const data = await conceptSetService.searchConceptSets(searchParams);

prepareDataTable(data);
self.repositoryConceptSets(data);
} catch(e) {
throw new Error(e);
} finally {
self.loading(false);
}
};
self.checkSearchAvailable();
}

var component = {
Expand Down
10 changes: 8 additions & 2 deletions js/components/circe/components/ConceptSetBrowserTemplate.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@

<div data-bind="visible: !loading() && !isProcessing()">
<div class="conceptset-browser-panel" data-bind="visible: buttonActionEnabled">
<div class="btn btn-sm btn-primary new-concept-set"
data-bind="click: addConceptSet, css: {disabled: disableConceptSetButton}, text: buttonActionText"></div>
<button type="button" class="btn btn-sm btn-primary new-concept-set" data-bind="click: addConceptSet, css: {disabled: disableConceptSetButton}, text: buttonActionText"></button>
</div>
<advanced-search
data-bind="visible: showSearch"
params="
searchConceptSets:searchConceptSets,
refreshConceptSets:loadConceptSetsFromRepository,
showSearch:showSearch">
</advanced-search>
<faceted-datatable params="
dataTableId: repositoryConceptSetTableId,
orderColumn: 3,
Expand Down
8 changes: 2 additions & 6 deletions js/components/circe/components/style.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
.conceptset-browser-panel {
display: flex;
justify-content: flex-end;
margin: 10px 0 10px 0;
margin: 10px 0;
}

.conceptset-browser-panel div:last-child{
.conceptset-browser-panel button:last-child{
margin-left: 10px;
}

.conceptset-browser-panel .new-concept-set {
width: 175px;
}
Loading
Loading