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

Unit Filtering #527

Open
wants to merge 4 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
5 changes: 5 additions & 0 deletions client/app/app.scss
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,10 @@ input[type="radio"]:focus {
color: $color-brand-danger;
}

.text-white {
color: white;
}

.font-weight-semibold {
font-weight: $font-weight-semibold !important;
}
Expand Down Expand Up @@ -2051,4 +2055,5 @@ input:checked + .slider:before {
@import '../components/tree-select/tree-select.scss';
@import '../components/auto-complete/auto-complete.scss';
@import '../components/subscription-banner/subscription-banner.scss';
@import '../components/unit-filters/unit-filters.scss';
// endinject //
19 changes: 13 additions & 6 deletions client/app/marketplace/extension-request/extension-request.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,19 @@ <h5 class="heavyheader mb-3 mb-md-4">Overview</h5>
<li class="pd-y-4" ng-repeat="feature in vm.extension.features">{{feature}}</li>
</ul>
<hr>
<h5 class="heavyheader mb-3 mb-md-4">Pricing and Setup</h5>
<p>This enrichment is currently included with your subscription, <strong>free</strong> of any additional charges!<br>
Please request now to enable.</p>
<button ng-if="vm.currentPrincipal.isDepartmentAdmin" class="btn btn-info" ng-show="!vm.requested" ng-click="vm.request()"><i class="fa fa-plus mr-3" aria-hidden="true"></i>Request enrichment</button><br>
<p ng-if="!vm.currentPrincipal.isDepartmentAdmin" class="text-danger"> Only an admin can request this enrichment. Please contact your local department admin to request.</p>
<div ng-show="vm.requested" class="alert alert-success" role="alert">Thanks for the request! We'll let you know as soon as the enrichment is available.</div>
<span ng-if="vm.extension.type === 'FILTER'">
<h5 class="heavyheader mb-3 mb-md-4">Configuration</h5>
<p>Filters are free to use and are configured in your settings.</p>
<a ui-sref="site.user.settings({ '#': 'filtering' })" class="btn btn-info text-white">Go to Settings</a>
</span>
<span ng-if="vm.extension.type !== 'FILTER'">
<h5 class="heavyheader mb-3 mb-md-4">Pricing and Setup</h5>
<p>This enrichment is currently included with your subscription, <strong>free</strong> of any additional charges!<br>
Please request now to enable.</p>
<button ng-if="vm.currentPrincipal.isDepartmentAdmin" class="btn btn-info" ng-show="!vm.requested" ng-click="vm.request()"><i class="fa fa-plus mr-3" aria-hidden="true"></i>Request enrichment</button><br>
<p ng-if="!vm.currentPrincipal.isDepartmentAdmin" class="text-danger"> Only an admin can request this enrichment. Please contact your local department admin to request.</p>
<div ng-show="vm.requested" class="alert alert-success" role="alert">Thanks for the request! We'll let you know as soon as the enrichment is available.</div>
</span>
</div>
<div class="col-md-5 extension-preview">
<h5 class="heavyheader mb-3 mb-md-4">Screenshots</h5>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ <h4>{{vm.selectedCategory}}</h4>
<div class="extension-card-title">
<h5>{{extension.name}}</h5>
<div>
<span class="badge badge-success" ng-if="extension.type !== 'app'">ENRICHMENT</span>
<span class="badge badge-warning" ng-if="extension.type !== 'app' && extension.type === 'FILTER'">FILTER</span>
<span class="badge badge-success" ng-if="extension.type !== 'app' && extension.type !== 'FILTER'">ENRICHMENT</span>
<span class="badge badge-primary" ng-if="extension.type === 'app'">APPLICATION</span>
</div>
</div>
Expand Down
27 changes: 19 additions & 8 deletions client/app/reporting/reporting.routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

'use strict';

import UnitFilterFixture from '../../../server/fixtures/extensions/unitFilters';
import applyUnitFilters from '../../util/filters';

export default function routes($stateProvider) {
'ngInject';

Expand All @@ -15,11 +18,11 @@ export default function routes($stateProvider) {
'content@': {
template: require('./reporting-unit/reporting-unit.html'),
controller: 'ReportingUnitController',
controllerAs: 'vm'
controllerAs: 'vm',
},
},
data: {
roles: ['user']
roles: ['user'],
},
reloadOnSearch: false,
resolve: {
Expand All @@ -34,21 +37,29 @@ export default function routes($stateProvider) {
currentPrincipal(Principal) {
return Principal.identity(true);
},
units(Unit) {
return Unit.query().$promise;
units(Unit, ExtensionConfiguration) {
const getUnits = async () => {
const extensions = await ExtensionConfiguration.query({ name: UnitFilterFixture.name }).$promise;
const extension = extensions.find(ext => ext.Extension.name === UnitFilterFixture.name);
const units = await Unit.query().$promise;
const { included } = applyUnitFilters(units, extension);
return included;
};

return getUnits();
},
redirect(units, $window, $state, $stateParams) {
let selectedUnitId = $stateParams['#'];
if(selectedUnitId != null) {
return
if (selectedUnitId != null) {
return;
}

const isLargeScreen = ($window.innerWidth >= 992);
if(isLargeScreen) {
if (isLargeScreen) {
selectedUnitId = units[0].id;
$state.go('site.reporting.unit', { '#': selectedUnitId, time: $stateParams.time });
}
}
},
},
});
}
3 changes: 2 additions & 1 deletion client/app/user/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import userSettings from './user-settings';
import requestAccess from './request-access';
import gettingStarted from './getting-started';
import help from './help';
import unitFiltersComponent from '../../components/unit-filters/unit-filters.component';

export default angular.module('statEngineApp.user', [uiRouter, userHome, userSettings, requestAccess, gettingStarted, help])
export default angular.module('statEngineApp.user', [uiRouter, userHome, userSettings, requestAccess, gettingStarted, help, unitFiltersComponent])
.config(routing)
.name;
1 change: 0 additions & 1 deletion client/app/user/user-settings/user-settings.controller.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

// eslint-disable-next-line no-unused-vars
import parsleyjs from 'parsleyjs';
import { getErrors } from '../../../util/error';

export default class UserSettingsController {
Expand Down
27 changes: 26 additions & 1 deletion client/app/user/user-settings/user-settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ <h2 class="m-0">Settings</h2>
>
Password
</a>
<a
data-toggle="tab"
href="#nav-filtering"
role="tab"
id="nav-filtering-tab"
aria-controls="nav-filtering"
aria-selected="false"
ng-click="vm.handleTabClick('filtering')"
>
Filtering
</a>
</div>
</nav>
</div>
Expand Down Expand Up @@ -153,7 +164,8 @@ <h6 class="card-title">Email</h6>
</div>
</div>

<div class="tab-pane fade " id="nav-password" role="tabpanel" aria-labelledby="nav-password-tab">
<!-- Password -->
<div class="tab-pane fade" id="nav-password" role="tabpanel" aria-labelledby="nav-password-tab">
<div class="card mg-b-25 tab-pane" role="tabpanel">
<div class="card-header mb-3">
<h6 class="card-title">Password</h6>
Expand Down Expand Up @@ -209,5 +221,18 @@ <h6 class="card-title">Password</h6>
</div>
</div>
</div>

<!-- Filtering -->
<div class="tab-pane fade" id="nav-filtering" role="tabpanel" aria-labelledby="nav-filtering-tab">
<div class="card mg-b-25 tab-pane" role="tabpanel">
<div class="card-header mb-3">
<h6 class="card-title">Unit Filtering</h6>
</div>
<div class="card-body">
<unit-filters></unit-filters>
</div>
</div>
</div>

</div>
</div>
1 change: 1 addition & 0 deletions client/components/api/extension-configuration.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export default function ExtensionConfigurationResource($resource) {
return $resource('/api/extension-configurations/:id', {
id: '@id'
}, {
create: { method: 'POST', params: { name: "@name" }},
enable: { method: 'PUT' },
disable: { method: 'PUT' },
update: { method: 'PUT' },
Expand Down
93 changes: 93 additions & 0 deletions client/components/unit-filters/unit-filters.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
'use strict';

import angular from 'angular';
import UnitFilterFixture from '../../../server/fixtures/extensions/unitFilters';
import applyUnitFilters from '../../util/filters';

export class UnitFiltersComponent {
filterConfiguration;
units = [];
error;
success;

wildcards = '';
individuals = '';

included = [];
excluded = [];

/*@ngInject*/
constructor(ExtensionConfiguration, Unit) {
this.ExtensionConfiguration = ExtensionConfiguration;
this.Unit = Unit;
}

async $onInit() {
try {
const extensions = await this.ExtensionConfiguration.query({ name: UnitFilterFixture.name }).$promise;
const extension = extensions.find(ext => ext.Extension.name === UnitFilterFixture.name);
this.units = await this.Unit.query().$promise;

if (extension) {
this.filterConfiguration = extension;
} else {
this.filterConfiguration = await this.ExtensionConfiguration.create({ name: UnitFilterFixture.name }).$promise;
}

if (Object.keys(this.filterConfiguration.config_json).length > 0) {
this.applyFilters();
} else {
this.included = [...this.units];
}
} catch (err) {
this.error = err.message;
}
}

addFilter(term, type) {
if (term) {
if (!this.filterConfiguration.config_json[type]) {
this.filterConfiguration.config_json[type] = [];
}

if (!this.filterConfiguration.config_json[type].includes(term)) {
this.filterConfiguration.config_json[type] = [...this.filterConfiguration.config_json[type], term];
}

this[type] = '';
}

this.applyFilters();
}

removeFilter(term, type) {
this.filterConfiguration.config_json[type] = this.filterConfiguration.config_json[type].filter(item => item !== term);
this.applyFilters();
}

applyFilters() {
const { excluded, included } = applyUnitFilters(this.units, this.filterConfiguration);
this.excluded = excluded;
this.included = included;
}

async save() {
try {
const id = this.filterConfiguration._id;
await this.ExtensionConfiguration.update({ id, replace: true }, this.filterConfiguration.config_json);
this.success = 'Configuration successfully saved.';
} catch (err) {
console.log(err);
this.error = 'Configurations failed to save.';
}
}
}


export default angular.module('unitFilters', [])
.component('unitFilters', {
template: require('./unit-filters.html'),
controller: UnitFiltersComponent,
controllerAs: 'vm',
})
.name;
60 changes: 60 additions & 0 deletions client/components/unit-filters/unit-filters.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<div>
<p>
Add wildcard filters or individual filters to filter units from Stat Engine. These filters apply across the
application from email reports to unit reports. You can see which units will be filtered below.
</p>

<div class="row">
<div class="col-6">
<form class="form" name="wildcard-form" ng-submit="vm.addFilter(vm.wildcards, 'wildcards')" novalidate="novalidate">
<label>Wildcard:</label>
<div class="input-group mb-3">
<input type="text" name="wildcard" placeholder="ENGS_*" class="form-control" required="required"
ng-model="vm.wildcards" aria-label="Exclude wildcard">
</div>
<div class="mb-3" ng-if="vm.filterConfiguration.config_json.wildcards.length > 0">
<span ng-repeat="wildcard in vm.filterConfiguration.config_json.wildcards" class="badge badge-pill badge-danger">
{{ wildcard }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close" ng-click="vm.removeFilter(wildcard, 'wildcards')">
<span aria-hidden="true">&times;</span>
</button>
</span>

</div>
</form>
</div>
<div class="col-6">
<form class="form" name="individual-form" ng-submit="vm.addFilter(vm.individuals, 'individuals')" novalidate="novalidate">
<label>Individual:</label>
<div class="input-group mb-3">
<input type="text" name="individual" placeholder="ENG_1" class="form-control" required="required"
ng-model="vm.individuals" aria-label="Exclude individual">
</div>
<div class="mb-3" ng-if="vm.filterConfiguration.config_json.individuals.length > 0">
<span ng-repeat="individual in vm.filterConfiguration.config_json.individuals" class="badge badge-pill badge-danger">
{{ individual }}
<button type="button" class="close" data-dismiss="alert" aria-label="Close" ng-click="vm.removeFilter(individual, 'individuals')">
<span aria-hidden="true">&times;</span>
</button>
</span>
</div>
</form>
</div>
</div>

<p>Filter Results:</p>
<div class="unit-filtering">
<div class="alert alert-success mg-r-20">
<h6>Included</h6>
<span ng-repeat="unit in vm.included" class="badge badge-success mg-r-5">{{ unit.id }}</span>
</div>
<div class="alert alert-danger">
<h6>Excluded</h6>
<span ng-repeat="unit in vm.excluded" class="badge badge-danger mg-r-5">{{ unit.id }}</span>
</div>
</div>

<div class="alert alert-success" ng-if="vm.success">{{ vm.success }}</div>
<div class="alert alert-danger" ng-if="vm.error">{{ vm.error }}</div>
<button ng-click="vm.save()" class="btn btn-primary pull-right">Save</button>
</div>
18 changes: 18 additions & 0 deletions client/components/unit-filters/unit-filters.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.unit-filtering {
display: flex;
justify-content: space-around;

div {
width: 100%;
}
}

.badge {
margin-right: 5px;
.close {
margin-left: .25rem;
color: inherit;
font-size: 100%;
text-shadow: 0 1px 0 rgba(#000, .5);
}
}
Loading