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

fix(query-builder): exit edit mode on chip/add button click #15207

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
7d8a92e
fix(query-builder): exit edit mode on item click
teodosiah Jan 7, 2025
e959dc8
fix(query-builder): exit edit mode on add btn click
teodosiah Jan 7, 2025
f3a9428
fix(query-builder): remove unnecessary focus and detectChanges
teodosiah Jan 8, 2025
e65e526
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 8, 2025
1812556
fix(query-builder): exit edit on drag & delete, fix drop-down pos
teodosiah Jan 8, 2025
de47ddb
fix(query-builder): address review comments
teodosiah Jan 9, 2025
89a7ace
fix(query-builder): exit edit on group, entity and field click
teodosiah Jan 9, 2025
3bef539
fix(query-builder): reuse exitEditAddMode method
teodosiah Jan 9, 2025
cda31f9
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 10, 2025
109fdc0
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 14, 2025
afe81ac
Merge branch 'thristodorova/query-builder-exit-edit-mode' of https://…
teodosiah Jan 14, 2025
fba33a4
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 17, 2025
7d82baf
fix(query-builder): prevent exit edit of inner query
teodosiah Jan 20, 2025
5be348e
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 20, 2025
ef0f172
fix(query-builder): prevent exit edit on drag icon focus
teodosiah Jan 20, 2025
4a36681
Merge branch 'ipetrov/query-builder-drag-and-drop-nogap' of https://g…
teodosiah Jan 21, 2025
a388c91
test(query-builder): add exit edit mode on same level tests
teodosiah Jan 21, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
<igx-select #entitySelect
type="box"
(selectionChanging)="onEntitySelectChanging($event)"
(opening)="exitEditAddMode(true)"
[overlaySettings]="entitySelectOverlaySettings"
[ngModel]="selectedEntity"
[style.display]="isInEditMode() ? 'block' : 'none'"
Expand Down Expand Up @@ -40,6 +41,7 @@
searchPlaceholder="{{ this.resourceStrings.igx_query_builder_search }}"
[style.display]="isInEditMode() ? 'block' : 'none'"
(selectionChanging)="onReturnFieldSelectChanging($event)"
(opening)="exitEditAddMode()"
>
<ng-template igxComboHeader>
<div
Expand Down Expand Up @@ -71,6 +73,7 @@
[ngModel]="selectedReturnFields[0]"
[placeholder]="this.resourceStrings.igx_query_builder_select_return_field_single"
[style.display]="isInEditMode() ? 'block' : 'none'"
(opening)="exitEditAddMode()"
>
<igx-select-item *ngFor="let field of fields" [value]="field.field">
{{ field.field }}
Expand Down Expand Up @@ -135,7 +138,7 @@
[draggable]="canBeDragged() ? 'true' : 'false'"
[hideBaseOnDrag] = "false"
[animateOnRelease] = "false"
(moveStart)="canBeDragged() ? onMoveStart(dragRef, expressionItem, false): null"
(moveStart)="canBeDragged() ? onMoveStart(dragRef, expressionItem, false, true): null"
(moveEnd)="onMoveEnd()"
(dragEnter)="onChipEnter(dragRef, expressionItem, false)"
(dragOver)="onChipOver(dragRef, false)"
Expand Down Expand Up @@ -233,7 +236,7 @@
<div igxDragIgnore class="igx-filter-tree__expression-actions">
<button #addExpressionButton igxDragIgnore igxIconButton="flat" [igxDropDownItemNavigation]="addOptionsDropDown"
aria-labelledby="add-expression" (keydown)="invokeClick($event)"
(click)="openExpressionAdd(expressionItem, addExpressionButton)"
(click)="clickExpressionAdd(expressionItem, addExpressionButton)"
(blur)="addExpressionBlur()">
<igx-icon id="add-expression">add</igx-icon>
</button>
Expand All @@ -259,6 +262,7 @@
(dropped)="onDivDropped(expressionItem)"
*ngIf="expressionItem.inEditMode"
class="igx-filter-tree__inputs"
[style.scroll-margin-top]="'30px'"
>
<igx-select
#fieldSelect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,9 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
this._selectedReturnFields = [];
}

this.init();
if (!this._preventInit) {
this.init();
}
}

/**
Expand Down Expand Up @@ -510,6 +512,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
private _currentGroupButtonsContainer: ElementRef;
private _addModeExpression: ExpressionOperandItem;
private _editedExpression: ExpressionOperandItem;
private _preventInit = false;
private _prevFocusedContainer: ElementRef;
private _expandedExpressions: IFilteringExpression[] = [];
private _fields: FieldType[];
Expand Down Expand Up @@ -747,7 +750,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
/**
* @hidden @internal
*/
public addCondition(parent: ExpressionGroupItem, afterExpression?: ExpressionItem) {
public addCondition(parent: ExpressionGroupItem, afterExpression?: ExpressionOperandItem) {
this.cancelOperandAdd();

const operandItem = new ExpressionOperandItem({
Expand Down Expand Up @@ -926,6 +929,22 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
}
}

/**
* @hidden @internal
*/
public exitEditAddMode(shouldPreventInit = false) {
if (!this._editedExpression) {
return;
}

this.exitOperandEdit();
this.cancelOperandAdd();

if (shouldPreventInit) {
this._preventInit = true;
}
}

/**
* @hidden @internal
*
Expand Down Expand Up @@ -975,6 +994,7 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
* @hidden @internal
*/
public onChipRemove(expressionItem: ExpressionItem) {
this.exitEditAddMode();
this.deleteItem(expressionItem);
}

Expand Down Expand Up @@ -1014,8 +1034,11 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
}

//When we pick up a chip
public onMoveStart(sourceDragElement: HTMLElement, sourceExpressionItem: ExpressionItem, isKeyboardDrag: boolean): void {
public onMoveStart(sourceDragElement: HTMLElement, sourceExpressionItem: ExpressionItem, isKeyboardDrag: boolean, shouldExitEdit = false): void {
//console.log('Picked up:', event, sourceDragElement);
if(shouldExitEdit) {
this.exitEditAddMode();
}
this.resetDragAndDrop(true);
this.isKeyboardDrag = isKeyboardDrag;
this.sourceExpressionItem = sourceExpressionItem;
Expand Down Expand Up @@ -1523,9 +1546,71 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
* @hidden @internal
*/
public enterExpressionEdit(expressionItem: ExpressionOperandItem) {
this.exitOperandEdit();
this.cancelOperandAdd();
if (this.shouldPreventExitEdit(expressionItem)) {
this.focusLastEditedExpressionInput();
return;
}
this.exitEditAddMode(true);
this.cdr.detectChanges();
this.enterEditMode(expressionItem);
}


/**
* @hidden @internal
*/
public clickExpressionAdd(expressionItem: ExpressionOperandItem, targetButton: HTMLElement) {
if (this.shouldPreventExitEdit(expressionItem)) {
this.focusLastEditedExpressionInput();
return;
}
this.exitEditAddMode(true);
this.cdr.detectChanges();
this.openExpressionAddDialog(targetButton);
}

/**
* @hidden @internal
*/
public openExpressionAddDialog(targetButton: HTMLElement) {
this.addExpressionDropDownOverlaySettings.target = targetButton;
this.addExpressionDropDownOverlaySettings.positionStrategy = new ConnectedPositioningStrategy({
horizontalDirection: HorizontalAlignment.Right,
horizontalStartPoint: HorizontalAlignment.Right,
verticalStartPoint: VerticalAlignment.Bottom
});

this.addExpressionItemDropDown.open(this.addExpressionDropDownOverlaySettings);
}

/**
* @hidden @internal
*/
public enterExpressionAdd(event: ISelectionEventArgs, expressionItem: ExpressionOperandItem) {
if (this._addModeExpression) {
this._addModeExpression.inAddMode = false;
}

if (this.parentExpression) {
this.inEditModeChange.emit(this.parentExpression);
}

const parent = expressionItem.parent ?? this.rootGroup;
requestAnimationFrame(() => {
if (event.newSelection.value === 'addCondition') {
this.addCondition(parent, expressionItem);
} else if (event.newSelection.value === 'addGroup') {
this.addReverseGroup(parent, expressionItem);
}
expressionItem.inAddMode = true;
this._addModeExpression = expressionItem;
})
}

/**
* @hidden @internal
*/
public enterEditMode(expressionItem: ExpressionOperandItem) {
if (this._editedExpression) {
this._editedExpression.inEditMode = false;
}
Expand Down Expand Up @@ -1580,46 +1665,6 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
}
}


/**
* @hidden @internal
*/
public openExpressionAdd(expressionItem: ExpressionOperandItem, targetButton: HTMLElement) {
this.exitOperandEdit();

this.addExpressionDropDownOverlaySettings.target = targetButton;
this.addExpressionDropDownOverlaySettings.positionStrategy = new ConnectedPositioningStrategy({
horizontalDirection: HorizontalAlignment.Right,
horizontalStartPoint: HorizontalAlignment.Right,
verticalStartPoint: VerticalAlignment.Bottom
});
this.addExpressionItemDropDown.open(this.addExpressionDropDownOverlaySettings);
}

/**
* @hidden @internal
*/
public enterExpressionAdd(event: ISelectionEventArgs, expressionItem: ExpressionOperandItem) {
if (this._addModeExpression) {
this._addModeExpression.inAddMode = false;
}

if (this.parentExpression) {
this.inEditModeChange.emit(this.parentExpression);
}

const parent = expressionItem.parent ?? this.rootGroup;
requestAnimationFrame(() => {
if (event.newSelection.value === 'addCondition') {
this.addCondition(parent, expressionItem);
} else if (event.newSelection.value === 'addGroup') {
this.addReverseGroup(parent, expressionItem);
}
expressionItem.inAddMode = true;
this._addModeExpression = expressionItem;
})
}

/**
* @hidden @internal
*/
Expand All @@ -1631,6 +1676,8 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
* @hidden @internal
*/
public onGroupClick(button: HTMLButtonElement, groupItem: ExpressionGroupItem) {
this.exitEditAddMode();

this.switchGroupDropDownOverlaySettings = IgxOverlayService.createRelativeOverlaySettings(
button as HTMLElement,
RelativePosition.Default);
Expand Down Expand Up @@ -1856,6 +1903,21 @@ export class IgxQueryBuilderTreeComponent implements AfterViewInit, OnDestroy {
return ctx;
}

private shouldPreventExitEdit(expressionItem: ExpressionOperandItem): boolean {
const innerQuery = this.innerQueries.filter(q => q.isInEditMode())[0]
return this._editedExpression &&
innerQuery && innerQuery.hasEditedExpression &&
this._editedExpression.expression.searchTree != expressionItem.expression.searchTree;
}

private focusLastEditedExpressionInput() {
const innerQuery = this.innerQueries.filter(q => q.isInEditMode())[0];
const expressionToScroll = innerQuery._editingInputsContainer?.nativeElement as Element;
const itemToFocus = Array.from(expressionToScroll.children).filter(input => input.querySelector('input') && !input.querySelector('input').disabled).pop().querySelector('input') as HTMLElement;
expressionToScroll.scrollIntoView();
itemToFocus.focus();
}

private setFormat(field: FieldType) {
if (!field.pipeArgs) {
field.pipeArgs = { digitsInfo: DEFAULT_PIPE_DIGITS_INFO };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1060,6 +1060,88 @@ describe('IgxQueryBuilder', () => {
QueryBuilderFunctions.verifyExpressionChipContent(fix, [0], 'ProductName', 'Starts With', 'a', 1);
}));

it('Should switch edit mode on click on chip on the same level.', fakeAsync(()=>{
queryBuilder.expressionTree = QueryBuilderFunctions.generateExpressionTree();
fix.detectChanges();
tick(100);
fix.detectChanges();

QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [0]);
tick(50);
fix.detectChanges();

// Click the existing chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [0], 1);
tick(50);
fix.detectChanges();
// Verify inputs values
QueryBuilderFunctions.verifyEditModeExpressionInputValues(fix, 'ProductName', 'Contains', 'a', 1);

// Click the existing chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [0], 1);
tick(50);
fix.detectChanges();
// Verify inputs values
QueryBuilderFunctions.verifyEditModeExpressionInputValues(fix, 'Released', 'True', '', 1 );
QueryBuilderFunctions.verifyExpressionChipContent(fix, [0], 'ProductName', 'Contains', 'a', 1);
}));

it('Should exit edit mode on add, change group buttons, entity and fields select click.', fakeAsync(() => {
queryBuilder.expressionTree = QueryBuilderFunctions.generateExpressionTree();
fix.detectChanges();
tick(100);
fix.detectChanges();

// Click chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [1]);
tick(50);
fix.detectChanges();

// Hover exprssion and click add button
UIInteractions.hoverElement(QueryBuilderFunctions.getQueryBuilderTreeItem(fix, [0]) as HTMLElement);
tick(50);
fix.detectChanges();
(QueryBuilderFunctions.getQueryBuilderTreeExpressionIcon(fix, [0], 'add') as HTMLElement).click();
tick(50);
fix.detectChanges();

expect(queryBuilder.queryTree.hasEditedExpression).toBeFalse();

// Click chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [1]);
tick(50);
fix.detectChanges();

// Click change group button
QueryBuilderFunctions.clickQueryBuilderGroupContextMenu(fix, 0);
tick(100);
fix.detectChanges();

expect(queryBuilder.queryTree.hasEditedExpression).toBeFalse();

// Click chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [1]);
tick(50);
fix.detectChanges();

// Click fields select
QueryBuilderFunctions.clickQueryBuilderFieldsCombo(fix);
fix.detectChanges();

expect(queryBuilder.queryTree.hasEditedExpression).toBeFalse();

// Click chip to enter edit mode.
QueryBuilderFunctions.clickQueryBuilderTreeExpressionChip(fix, [1]);
tick(50);
fix.detectChanges();

// Click entity select
QueryBuilderFunctions.clickQueryBuilderEntitySelect(fix);
fix.detectChanges();

expect(queryBuilder.queryTree.hasEditedExpression).toBeFalse();
}));

it('Should display an alert dialog when the entity is changed and showEntityChangeDialog is true.', fakeAsync(() => {
const queryBuilderElement: HTMLElement = fix.debugElement.queryAll(By.css(`.${QueryBuilderConstants.QUERY_BUILDER_CLASS}`))[0].nativeElement;
const queryTreeElement = queryBuilderElement.querySelector(`.${QueryBuilderConstants.QUERY_BUILDER_TREE}`);
Expand Down Expand Up @@ -1594,8 +1676,8 @@ describe('IgxQueryBuilder', () => {
fix.detectChanges();

// Verify both parent and child commit buttons are enabled
let parentCommitBtn = QueryBuilderFunctions.getQueryBuilderExpressionCommitButton(fix);
let childCommitBtn = QueryBuilderFunctions.getQueryBuilderExpressionCommitButton(fix, 1);
const parentCommitBtn = QueryBuilderFunctions.getQueryBuilderExpressionCommitButton(fix);
const childCommitBtn = QueryBuilderFunctions.getQueryBuilderExpressionCommitButton(fix, 1);

ControlsFunction.verifyButtonIsDisabled(parentCommitBtn as HTMLElement);
ControlsFunction.verifyButtonIsDisabled(childCommitBtn as HTMLElement, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class IgxQueryBuilderComponent implements OnDestroy {
this._fields = fields;
this.entities = [
{
name: null,
name: null,
fields: fields
}
];
Expand Down