Skip to content

Commit

Permalink
Merge pull request #28688 from colemanw/searchKitTabs
Browse files Browse the repository at this point in the history
dev/user-interface#49  - SearchKit: improve tabbed interface
  • Loading branch information
aydun authored Dec 19, 2023
2 parents 6b5b424 + 8e597f9 commit b00a19f
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 186 deletions.
87 changes: 0 additions & 87 deletions ext/search_kit/ang/crmSearchAdmin/compose.html

This file was deleted.

8 changes: 8 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearch-conditions.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<fieldset class="api4-clause-fieldset crm-search-wheres">
<crm-search-clause clauses="$ctrl.savedSearch.api_params.where" format="string" op="AND" label="{{:: ts('Where') }}" fields="fieldsForWhere" allow-functions="true" ></crm-search-clause>
</fieldset>
<fieldset ng-if="$ctrl.paramExists('having')" class="api4-clause-fieldset crm-search-havings">
<crm-search-clause clauses="$ctrl.savedSearch.api_params.having" format="string" op="AND" label="{{:: ts('Having') }}" help="having" fields="fieldsForHaving" ></crm-search-clause>
</fieldset>


3 changes: 3 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearch-fields.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div class="crm-search-select-fields">
<crm-search-admin-fields></crm-search-admin-fields>
</div>
43 changes: 43 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearch-for.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<div class="form-inline">
<label for="crm-search-main-entity">{{:: ts('Search for') }}</label>
<input id="crm-search-main-entity" class="form-control huge collapsible-optgroups" ng-model="$ctrl.savedSearch.api_entity" crm-ui-select="::{allowClear: false, data: mainEntitySelect}" ng-disabled="$ctrl.savedSearch.id">
</div>
<div ng-if=":: $ctrl.paramExists('join')" class="crm-search-joins">
<fieldset ng-repeat="join in $ctrl.savedSearch.api_params.join" class="crm-search-join">
<div class="form-inline">
<select class="form-control" ng-model="join[1]" ng-change="$ctrl.changeJoinType(join)" ng-options="o.k as o.v for o in ::joinTypes" ></select>
<input id="crm-search-join-{{ $index }}" class="form-control huge" ng-model="join[0]" crm-ui-select="{placeholder: ' ', data: getJoinEntities}" disabled >
<button type="button" class="btn btn-xs btn-danger-outline" ng-click="$ctrl.removeJoin($index)" title="{{:: ts('Remove join') }}">
<i class="crm-i fa-trash" aria-hidden="true"></i>
</button>
</div>
<div class="api4-clause-fieldset">
<crm-search-clause clauses="join" format="json" skip="2 + getJoin(join[0]).conditions.length" op="AND" label="{{:: ts('If') }}" hide-label="true" placeholder="ts('Add Condition')" fields="fieldsForJoin(join[0])" ></crm-search-clause>
</div>
</fieldset>
<fieldset class="crm-search-join-add">
<div class="form-inline">
<select class="form-control" ng-model="controls.joinType" ng-options="o.k as o.v for o in ::joinTypes" ></select>
<input id="crm-search-add-join"
class="form-control crm-action-menu fa-plus"
crm-ui-select="{placeholder: ts('Entity'), data: getJoinEntities, dropdownCss: {width: '275px'}}"
on-crm-ui-select="$ctrl.addJoin(selection)">
</div>
</fieldset>
</div>
<fieldset ng-if=":: $ctrl.paramExists('groupBy')" class="crm-search-groupbys">
<div class="form-inline" ng-repeat="groupBy in $ctrl.savedSearch.api_params.groupBy" class="crm-search-groupby">
<label for="crm-search-groupBy-{{ $index }}">{{:: ts('Group By') }}</label>
<crm-search-function class="form-group" expr="$ctrl.savedSearch.api_params.groupBy[$index]" mode="groupBy"></crm-search-function>
<span ng-if="!$ctrl.hasFunction($ctrl.savedSearch.api_params.groupBy[$index])">
<input id="crm-search-groupBy-{{ $index }}" class="form-control huge" ng-model="$ctrl.savedSearch.api_params.groupBy[$index]" crm-ui-select="{placeholder: ' ', data: fieldsForGroupBy}" ng-change="changeGroupBy($index)" />
</span>
<hr>
</div>
<div class="form-inline crm-search-groupby-add">
<input id="crm-search-add-groupBy"
class="form-control crm-action-menu fa-plus"
crm-ui-select="{placeholder: ts('Group By'), data: fieldsForGroupBy, dropdownCss: {width: '300px'}}"
on-crm-ui-select="$ctrl.addParam('groupBy', selection)" >
</div>
</fieldset>
10 changes: 10 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearch-query.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<div>
<strong>API:</strong>
</div>
<pre>{{ $ctrl.debug.apiParams }}</pre>
<pre ng-if="$ctrl.debug.timeIndex">{{ ts('Request took %1 seconds.', {1: $ctrl.debug.timeIndex}) }}</pre>
<div ng-if="$ctrl.perm.viewDebugOutput">
<strong>SQL:</strong>
<pre ng-if="!$ctrl.debug.sql">{{:: ts('Run search to view SQL') }}</pre>
<pre ng-repeat="query in $ctrl.debug.sql">{{ query }}</pre>
</div>
9 changes: 9 additions & 0 deletions ext/search_kit/ang/crmSearchAdmin/crmSearch-settings.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<textarea class="form-control" placeholder="{{:: ts('Description (shown above default display)') }}" ng-model="$ctrl.savedSearch.description"></textarea>
<div class="form-group">
<label class="sr-only" for="expires_date">{{:: ts('Search Expiry Date') }}</label>
<div class="input-group">
<div class="input-group-addon"><i class="crm-i fa-calendar-times-o"></i></div>
<input id="expires_date" class="form-control" crm-ui-datepicker="{time: true}" ng-model="$ctrl.savedSearch.expires_date" placeholder="Expires">
</div>
</div>
<crm-search-admin-tags tag-ids="$ctrl.savedSearch.tag_id" class="btn-group btn-group-sm"></crm-search-admin-tags>
54 changes: 45 additions & 9 deletions ext/search_kit/ang/crmSearchAdmin/crmSearchAdmin.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,43 @@
this.displayTypes = _.indexBy(CRM.crmSearchAdmin.displayTypes, 'id');
this.searchDisplayPath = CRM.url('civicrm/search');
this.afformPath = CRM.url('civicrm/admin/afform');
this.debug = {};

this.mainTabs = [
{
key: 'for',
title: ts('Search For'),
icon: 'fa-search',
},
{
key: 'conditions',
title: ts('Filter Conditions'),
icon: 'fa-filter',
},
{
key: 'fields',
title: ts('Select Fields'),
icon: 'fa-columns',
},
{
key: 'settings',
title: ts('Configure Settings'),
icon: 'fa-gears',
},
{
key: 'query',
title: ts('Query Info'),
icon: 'fa-info-circle',
},
];

$scope.controls = {tab: this.mainTabs[0].key, joinType: 'LEFT'};

this.selectedDisplay = function() {
// Could return the display but for now we don't need it
return $scope.controls.tab.startsWith('display_');
};

$scope.controls = {tab: 'compose', joinType: 'LEFT'};
$scope.joinTypes = [
{k: 'LEFT', v: ts('With (optional)')},
{k: 'INNER', v: ts('With (required)')},
Expand All @@ -38,6 +73,7 @@
$scope.getEntity = searchMeta.getEntity;
$scope.getField = searchMeta.getField;
this.perm = {
viewDebugOutput: CRM.checkPerm('view debug output'),
editGroups: CRM.checkPerm('edit groups')
};

Expand Down Expand Up @@ -472,17 +508,9 @@

// Deletes an item from an array param
this.clearParam = function(name, idx) {
if (name === 'select') {
// Function selectors use `ng-repeat` with `track by $index` so must be refreshed when splicing the array
ctrl.hideFuncitons();
}
ctrl.savedSearch.api_params[name].splice(idx, 1);
};

this.hideFuncitons = function() {
$scope.controls.showFunctions = false;
};

function onChangeSelect(newSelect, oldSelect) {
// When removing a column from SELECT, also remove from ORDER BY & HAVING
_.each(_.difference(oldSelect, newSelect), function(col) {
Expand Down Expand Up @@ -543,6 +571,14 @@
return {results: ctrl.getSelectFields()};
};

this.fieldsForSelect = function() {
return {
results: ctrl.getAllFields(':label', ['Field', 'Custom', 'Extra', 'Pseudo'], (key) => {
ctrl.savedSearch.api_params.select.includes(key);
})
};
};

this.getAllFields = function(suffix, allowedTypes, disabledIf, topJoin) {
disabledIf = disabledIf || _.noop;
allowedTypes = allowedTypes || ['Field', 'Custom', 'Extra', 'Filter'];
Expand Down
67 changes: 46 additions & 21 deletions ext/search_kit/ang/crmSearchAdmin/crmSearchAdmin.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,19 @@ <h1 crm-page-title>{{ $ctrl.entityTitle + ': ' + $ctrl.savedSearch.label }}</h1>
</div>

<form>
<div class="crm-flex-box">
<div class="nav-stacked">
<div class="crm-flex-box crm-search-admin-outer">
<div class="crm-flex-1">
<input id="crm-saved-search-label" class="form-control" ng-model="$ctrl.savedSearch.label" type="text" required placeholder="{{:: ts('Untitled Search') }}" ng-model-options="$ctrl.debounceMode">
</div>
<div class="crm-flex-4 form-inline">
<label for="crm-search-main-entity">{{:: ts('Search for') }}</label>
<input id="crm-search-main-entity" class="form-control huge collapsible-optgroups" ng-model="$ctrl.savedSearch.api_entity" crm-ui-select="::{allowClear: false, data: mainEntitySelect}" ng-disabled="$ctrl.savedSearch.id">
<div class="crm-flex-1 form-inline">
<div class="btn-group">
<button type="button" class="btn" ng-class="{'btn-primary': status === 'unsaved', 'btn-warning': status === 'saving', 'btn-success': status === 'saved'}" ng-disabled="status !== 'unsaved'" ng-click="$ctrl.save()">
<i class="crm-i" ng-class="{'fa-check': status !== 'saving', 'fa-spin fa-spinner': status === 'saving'}"></i>
<span ng-if="status === 'saved'">{{:: ts('Saved') }}</span>
<span ng-if="status === 'unsaved'">{{:: ts('Save') }}</span>
<span ng-if="status === 'saving'">{{:: ts('Saving...') }}</span>
</button>
</div>

<div class="form-group pull-right">

Expand Down Expand Up @@ -55,35 +61,54 @@ <h1 crm-page-title>{{ $ctrl.entityTitle + ': ' + $ctrl.savedSearch.label }}</h1>
</ul>
</div>

<div class="btn-group">
<button type="button" class="btn" ng-class="{'btn-primary': status === 'unsaved', 'btn-warning': status === 'saving', 'btn-success': status === 'saved'}" ng-disabled="status !== 'unsaved'" ng-click="$ctrl.save()">
<i class="crm-i" ng-class="{'fa-check': status !== 'saving', 'fa-spin fa-spinner': status === 'saving'}"></i>
<span ng-if="status === 'saved'">{{:: ts('Saved') }}</span>
<span ng-if="status === 'unsaved'">{{:: ts('Save') }}</span>
<span ng-if="status === 'saving'">{{:: ts('Saving...') }}</span>
<div class="btn-group crm-search-admin-links" ng-if="$ctrl.savedSearch.id">
<a ng-href="{{ $ctrl.searchDisplayPath + '#/display/' + $ctrl.savedSearch.name }}" target="_blank" class="btn btn-primary-outline" title="{{:: ts('View search results table') }}">
<i class="crm-i fa-external-link"></i>
{{:: ts('View Results') }}
</a>
<button type="button" ng-click="$ctrl.openDisplayMenu = true;" class="btn btn-primary-outline dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" ng-if=":: $ctrl.openDisplayMenu">
<li title="{{:: ts('View search results table') }}">
<a ng-href="{{ $ctrl.searchDisplayPath + '#/display/' + $ctrl.savedSearch.name }}" target="_blank">
<i class="crm-i fa-table"></i>
{{:: ts('Search results table') }}
</a>
</li>
<li ng-repeat="display in $ctrl.savedSearch.displays" ng-if="display.id" ng-class="{disabled: display.acl_bypass}" title="{{:: display.acl_bypass ? ts('Display has permissions disabled') : ts('View display') }}">
<a ng-href="{{ display.acl_bypass ? '' : $ctrl.searchDisplayPath + '#/display/' + $ctrl.savedSearch.name + '/' + display.name }}" target="_blank">
<i class="crm-i {{ display.acl_bypass ? 'fa-unlock' : $ctrl.displayTypes[display.type].icon }}"></i>
{{ display.label }}
</a>
</li>
</ul>
</div>

</div>

</div>
</div>
<div class="crm-flex-box">
<ul class="nav nav-pills nav-stacked" ng-include="'~/crmSearchAdmin/tabs.html'"></ul>
<div class="crm-flex-4" ng-switch="controls.tab">
<div ng-switch-when="compose">
<div ng-include="'~/crmSearchAdmin/compose.html'" class="crm-search-admin-relative"></div>
<crm-search-admin-results-table search="$ctrl.savedSearch"></crm-search-admin-results-table>
</div>
<div ng-switch-when="group">
<fieldset ng-include="'~/crmSearchAdmin/group.html'"></fieldset>

<div class="crm-flex-box crm-search-admin-outer">
<nav class="crm-search-admin-main-tabs">
<ul class="nav nav-pills nav-stacked" role="tablist" aria-orientation="vertical" ng-include="'~/crmSearchAdmin/tabs.html'"></ul>
</nav>
<div class="crm-flex-4 panel panel-default">
<div ng-if="!$ctrl.selectedDisplay()" class="panel-body" role="tabpanel">
<div ng-include="'~/crmSearchAdmin/crmSearch-' + controls.tab + '.html'" class="crm-search-admin-relative"></div>
</div>
<div ng-switch-default>
<div ng-if="$ctrl.selectedDisplay()" class="panel-body" role="tabpanel">
<div ng-repeat="display in $ctrl.savedSearch.displays" ng-if="controls.tab === ('display_' + $index)">
<crm-search-admin-display class="crm-search-admin-relative" display="display" saved-search="$ctrl.savedSearch"></crm-search-admin-display>
</div>
</div>
</div>
</div>

<div ng-if="!$ctrl.selectedDisplay()">
<crm-search-admin-results-table search="$ctrl.savedSearch" debug="$ctrl.debug"></crm-search-admin-results-table>
</div>

</form>
</div>
Loading

0 comments on commit b00a19f

Please sign in to comment.