Skip to content
This repository has been archived by the owner on May 7, 2021. It is now read-only.

Commit

Permalink
feat(query): Query Builder (#2806)
Browse files Browse the repository at this point in the history
* fix(query): string enclouser added to query values

- an optional quotation enclosure is added for the values in query
- area.name: "new area" and area.name: new area are same

* feat(query): query suggestion service added

* feat(query): query suggestion added to the component

* fix(query): iteration added to the suggestion

* fix(query): remove suggestions on blur

* fix(query): sugestion replace function added

* fix(query): add dropdown for suggestions

* fix(query): add delay to query suggestion

* fix(query): suggestion on click replace the text added

* fix(query): dont close dropdown on blur

* fix(query): fix replace suggestions

* fix(query): add css for dropdown-item

* fix(query): new fields added to the suggestion

* fix(angular/cdk): add angular cdk to package.json

* fix(list): add dropdown list component for Highlight interface from cdk

* fix(query): add a11y using ActiveDescendantKeyManager on suggestion dropdown

* fix(query): fixed unit test for query

* fix(query): add support for left and right arrow keys to suggest query fields

* fix(less): generic class fixed

* fix(tests): fix failing  functional tests

* fix(query): fix `expression change error`, focus on input after pressing enter

* fix(query): remove unused imports and refactor code

* fix(query): clear the activeItem from dropdown on Enter

* chore(refactor): use constants from query-keys instead of public instances from filterService
  • Loading branch information
sahil143 authored and joshuawilson committed Dec 14, 2018
1 parent 175951b commit 01316ba
Show file tree
Hide file tree
Showing 30 changed files with 929 additions and 174 deletions.
11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"npm": ">= 5.3.0"
},
"dependencies": {
"@angular/cdk": "^6.4.7",
"lodash": "^4.17.4",
"moment": "^2.18.1",
"mydatepicker": "^2.1.0",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { AuthenticationService } from 'ngx-login-client';

import { GroupTypeQuery, GroupTypeUI } from '../../models/group-types.model';
import { FilterService } from '../../services/filter.service';
import { AND, EQUAL } from '../../services/query-keys';

// ngrx stuff
import { select, Store } from '@ngrx/store';
Expand Down Expand Up @@ -76,10 +77,10 @@ export class GroupTypesComponent implements OnInit, OnDestroy {
fnBuildQueryParam(witGroup) {
//Query for work item type group
const type_query = this.filterService.queryBuilder(
'typegroup.name', this.filterService.equal_notation, witGroup.name
'typegroup.name', EQUAL, witGroup.name
);
const first_join = this.filterService.queryJoiner(
{}, this.filterService.and_notation, type_query
{}, AND, type_query
);
//second_join gives json object
return this.filterService.jsonToQuery(first_join);
Expand All @@ -88,11 +89,11 @@ export class GroupTypesComponent implements OnInit, OnDestroy {

fnBuildQueryParamForBoard(witGroup) {
const type_query = this.filterService.queryBuilder(
'boardContextId', this.filterService.equal_notation, witGroup.id
'boardContextId', EQUAL, witGroup.id
);
// join query with typeQuery
const second_join = this.filterService.queryJoiner(
{}, this.filterService.and_notation, type_query
{}, AND, type_query
);
return this.filterService.jsonToQuery(second_join);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {

import { AuthenticationService } from 'ngx-login-client';

import { AND, EQUAL } from '../../services/query-keys';
import { GroupTypeUI } from './../../models/group-types.model';
import { IterationUI } from './../../models/iteration.model';
import { FilterService } from './../../services/filter.service';
Expand Down Expand Up @@ -52,25 +53,25 @@ export class IterationListEntryComponent implements OnInit {

constructURL(iterationId: string) {
//Query for work item type group
const type_query = this.filterService.queryBuilder('typegroup.name', this.filterService.equal_notation, this.witGroup.name);
const type_query = this.filterService.queryBuilder('typegroup.name', EQUAL, this.witGroup.name);
//Query for iteration
const iteration_query = this.filterService.queryBuilder('iteration', this.filterService.equal_notation, iterationId);
const iteration_query = this.filterService.queryBuilder('iteration', EQUAL, iterationId);
//Join type and space query
const first_join = this.filterService.queryJoiner({}, this.filterService.and_notation, type_query);
const second_join = this.filterService.queryJoiner(first_join, this.filterService.and_notation, iteration_query);
const first_join = this.filterService.queryJoiner({}, AND, type_query);
const second_join = this.filterService.queryJoiner(first_join, AND, iteration_query);
//this.setGroupType(witGroup);
//second_join gives json object
return this.filterService.jsonToQuery(second_join);
}

constructURLforBoard(iterationId: string) {
//Query for work item type group
const type_query = this.filterService.queryBuilder('boardContextId', this.filterService.equal_notation, this.witGroup.id);
const type_query = this.filterService.queryBuilder('boardContextId', EQUAL, this.witGroup.id);
//Query for iteration
const iteration_query = this.filterService.queryBuilder('iteration', this.filterService.equal_notation, iterationId);
const iteration_query = this.filterService.queryBuilder('iteration', EQUAL, iterationId);
// join type and iteration query
const first_join = this.filterService.queryJoiner({}, this.filterService.and_notation, type_query);
const second_join = this.filterService.queryJoiner(first_join, this.filterService.and_notation, iteration_query);
const first_join = this.filterService.queryJoiner({}, AND, type_query);
const second_join = this.filterService.queryJoiner(first_join, AND, iteration_query);
return this.filterService.jsonToQuery(second_join);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AuthenticationService } from 'ngx-login-client';

import { IterationQuery, IterationUI } from '../../models/iteration.model';
import { IterationService } from '../../services/iteration.service';
import { AND, EQUAL } from '../../services/query-keys';
import { WorkItemService } from '../../services/work-item.service';
import { FabPlannerIterationModalComponent } from '../iterations-modal/iterations-modal.component';
import { FilterService } from './../../services/filter.service';
Expand Down Expand Up @@ -110,25 +111,25 @@ export class IterationComponent implements OnInit, OnDestroy, OnChanges {

constructURL(iterationId: string) {
//Query for work item type group
const type_query = this.filterService.queryBuilder('typegroup.name', this.filterService.equal_notation, this.witGroup.name);
const type_query = this.filterService.queryBuilder('typegroup.name', EQUAL, this.witGroup.name);
//Query for iteration
const iteration_query = this.filterService.queryBuilder('iteration', this.filterService.equal_notation, iterationId);
const iteration_query = this.filterService.queryBuilder('iteration', EQUAL, iterationId);
//Join type and space query
const first_join = this.filterService.queryJoiner({}, this.filterService.and_notation, type_query);
const second_join = this.filterService.queryJoiner(first_join, this.filterService.and_notation, iteration_query);
const first_join = this.filterService.queryJoiner({}, AND, type_query);
const second_join = this.filterService.queryJoiner(first_join, AND, iteration_query);
//this.setGroupType(witGroup);
//second_join gives json object
return this.filterService.jsonToQuery(second_join);
}

constructURLforBoard(iterationId: string) {
//Query for work item type group
const type_query = this.filterService.queryBuilder('boardContextId', this.filterService.equal_notation, this.witGroup.id);
const type_query = this.filterService.queryBuilder('boardContextId', EQUAL, this.witGroup.id);
//Query for iteration
const iteration_query = this.filterService.queryBuilder('iteration', this.filterService.equal_notation, iterationId);
const iteration_query = this.filterService.queryBuilder('iteration', EQUAL, iterationId);
// join type and iteration query
const first_join = this.filterService.queryJoiner({}, this.filterService.and_notation, type_query);
const second_join = this.filterService.queryJoiner(first_join, this.filterService.and_notation, iteration_query);
const first_join = this.filterService.queryJoiner({}, AND, type_query);
const second_join = this.filterService.queryJoiner(first_join, AND, iteration_query);
return this.filterService.jsonToQuery(second_join);
}

Expand Down
6 changes: 4 additions & 2 deletions src/app/components_ngrx/labels/labels.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import {
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { cloneDeep } from 'lodash';
import { AND, EQUAL } from '../../services/query-keys';
import { LabelUI } from './../../models/label.model';
import { FilterService } from './../../services/filter.service';

@Component({
selector: 'f8-label',
templateUrl: './labels.component.html',
Expand Down Expand Up @@ -58,7 +60,7 @@ export class LabelsComponent {
let showCompleted: boolean = this.queryParams.hasOwnProperty('showCompleted');
const newQuery = this.filterService.queryBuilder(
'label',
this.filterService.equal_notation,
EQUAL,
labelId
);
let existingQuery = {};
Expand All @@ -68,7 +70,7 @@ export class LabelsComponent {
const finalQuery = this.filterService.jsonToQuery(
this.filterService.queryJoiner(
existingQuery,
this.filterService.and_notation,
AND,
newQuery
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { filter, map, switchMap, take, takeUntil, tap } from 'rxjs/operators';
import { BoardQuery, BoardUIQuery } from '../../models/board.model';
import { WorkItemQuery, WorkItemUI } from '../../models/work-item';
import { FilterService } from '../../services/filter.service';
import { AND, EQUAL } from '../../services/query-keys';
import { AppState } from '../../states/app.state';
import * as BoardUIActions from './../../actions/board-ui.actions';
import * as ColumnWorkItemAction from './../../actions/column-workitem.action';
Expand Down Expand Up @@ -101,12 +102,12 @@ export class PlannerBoardComponent implements AfterViewChecked, OnInit, OnDestro
constructUrl(witGroup: GroupTypeUI) {
//Query for work item type group
const type_query = this.filterService.queryBuilder(
'boardContextId', this.filterService.equal_notation, witGroup.id
'boardContextId', EQUAL, witGroup.id
);
//Query for space
//Join type and space query
const first_join = this.filterService.queryJoiner(
{}, this.filterService.and_notation, type_query
{}, AND, type_query
);
//second_join gives json object
return this.filterService.jsonToQuery(first_join);
Expand Down
17 changes: 9 additions & 8 deletions src/app/components_ngrx/planner-list/planner-list.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { EmptyStateConfig } from 'patternfly-ng/empty-state';
import { combineLatest, Observable } from 'rxjs';
import { filter, switchMap, take, tap } from 'rxjs/operators';
import { WorkItemTypeQuery, WorkItemTypeUI } from '../../models/work-item-type';
import { AND, EQUAL, NOT_EQUAL } from '../../services/query-keys';
import { IterationQuery, IterationUI } from './../../models/iteration.model';
import { CookieService } from './../../services/cookie.service';
import { FilterService } from './../../services/filter.service';
Expand Down Expand Up @@ -165,15 +166,15 @@ export class PlannerListComponent implements OnInit, OnDestroy, AfterViewChecked
['closed', 'Done', 'Removed', 'Closed'].forEach(state => {
stateQuery = this.filterService.queryJoiner(
stateQuery,
this.filterService.and_notation,
AND,
this.filterService.queryBuilder(
'state', this.filterService.not_equal_notation, state
'state', NOT_EQUAL, state
)
);
});
exp = this.filterService.queryJoiner(
exp,
this.filterService.and_notation,
AND,
stateQuery
);
} else {
Expand Down Expand Up @@ -290,10 +291,10 @@ export class PlannerListComponent implements OnInit, OnDestroy, AfterViewChecked
.subscribe(groupType => {
const defaultGroupName = groupType.name;
//Query for work item type group
const type_query = this.filterService.queryBuilder('typegroup.name', this.filterService.equal_notation, defaultGroupName);
const type_query = this.filterService.queryBuilder('typegroup.name', EQUAL, defaultGroupName);
//Join type and space query
const first_join = this.filterService.queryJoiner({}, this.filterService.and_notation, type_query);
//const view_query = this.filterService.queryBuilder('tree-view', this.filterService.equal_notation, 'true');
const first_join = this.filterService.queryJoiner({}, AND, type_query);
//const view_query = this.filterService.queryBuilder('tree-view', EQUAL, 'true');
//const third_join = this.filterService.queryJoiner(second_join);
//second_join gives json object
let query = this.filterService.jsonToQuery(first_join);
Expand Down Expand Up @@ -436,7 +437,7 @@ export class PlannerListComponent implements OnInit, OnDestroy, AfterViewChecked
let queryParams = cloneDeep(this.route.snapshot.queryParams);
const newQuery = this.filterService.queryBuilder(
'label',
this.filterService.equal_notation,
EQUAL,
labelId
);
let existingQuery = {};
Expand All @@ -446,7 +447,7 @@ export class PlannerListComponent implements OnInit, OnDestroy, AfterViewChecked
const finalQuery = this.filterService.jsonToQuery(
this.filterService.queryJoiner(
existingQuery,
this.filterService.and_notation,
AND,
newQuery
)
);
Expand Down
43 changes: 31 additions & 12 deletions src/app/components_ngrx/planner-query/planner-query.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,37 @@ <h4>Please wait, we are loading your data.</h4>
</work-item-preview-panel>

<div #querySearch class="f8-query__input-wrapper">
<span
*ngIf="searchQuery !== '' && !query.disabled"
class="pficon-close close f8-query__clear-button"
tooltip="Press ctrl+backspace to clear"
placement="left"
(click)="searchQuery='';"
></span>
<input #query class="f8-query__input"
[disabled]="disableInput"
(keydown)="fetchWorkItemForQuery($event, query.value)"
[(ngModel)]="searchQuery"
placeholder="Enter your Query...">
<div class="dropdown"
[isOpen]="isSuggestionDropdownOpen"
[autoClose]="false"
dropdown>
<span
*ngIf="searchQuery !== '' && !queryInput.disabled"
class="close f8-query__clear-button"
[class.pficon-spinner2]="valueLoading"
[class.pficon-close]="!valueLoading"
tooltip="Press ctrl+backspace to clear"
placement="left"
(click)="clearInputField()"
></span>
<input #queryInput class="f8-query__input"
[disabled]="disableInput"
(keyup)="fetchWorkItemForQuery($event, queryInput.value, queryInput.selectionStart)"
(keydown)="onInputKeyPress($event)"
[(ngModel)]="searchQuery"
(click)="onClickSearchField($event)"
(blur)="onBlurSearchField()"
placeholder="Enter your Query...">
<ng-container *ngIf="(querySuggestion | async) as suggestions">
<ul class="suggestion-box dropdown-menu" *dropdownMenu>
<list-item
*ngFor="let suggestion of suggestions"
[item]="suggestion"
(click)="onSelectSuggestion(suggestion, queryInput.value, queryInput.selectionStart)"
>{{suggestion}}</list-item>
</ul>
</ng-container>
</div>
<span class="f8-query__input-hint">Press Enter to Search....</span>
<div
*ngIf="!(addDisabled | async)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@

&__clear-button {
position: absolute;
right: 30px;
top: 25px;
right: 15px;
top: 10px;
}

&__create-workitem {
Expand Down
Loading

0 comments on commit 01316ba

Please sign in to comment.