Skip to content

Commit

Permalink
rebase with next
Browse files Browse the repository at this point in the history
  • Loading branch information
dvoegelin committed Aug 23, 2024
2 parents e4d17c6 + 622247b commit cb106df
Show file tree
Hide file tree
Showing 12 changed files with 30,665 additions and 27,591 deletions.
58,057 changes: 30,491 additions & 27,566 deletions projects/demo/assets/documentation.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export class NovoDateFormatDirective extends IMaskDirective<any> {

normalize(value: string) {
const pattern = this.labels.dateFormat.toUpperCase();
if (!value) {
return "";
}
return DateUtil.format(DateUtil.parse(value), pattern);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Directive, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { UntypedFormGroup } from '@angular/forms';
import { AfterViewInit, Directive, Input, OnDestroy, OnInit, QueryList, ViewChild, ViewChildren } from '@angular/core';
import { FormControlDirective, FormControlName, UntypedFormGroup } from '@angular/forms';
import { NovoLabelService } from 'novo-elements/services';
import { NovoConditionFieldDef } from '../query-builder.directives';
import { NovoConditionFieldDef, NovoConditionOperatorsDef } from '../query-builder.directives';
import { Operator } from '../query-builder.types';

@Directive()
export abstract class AbstractConditionFieldDef implements OnDestroy, OnInit {
export abstract class AbstractConditionFieldDef implements OnDestroy, OnInit, AfterViewInit {
/** Column name that should be used to reference this column. */
@Input()
get name(): string {
Expand All @@ -20,24 +20,63 @@ export abstract class AbstractConditionFieldDef implements OnDestroy, OnInit {
_name: string;

defaultOperator: Operator | string;
protected _previousOperatorValue: Operator;

protected operatorEditGroups: Set<Operator>[] = [];

@ViewChild(NovoConditionFieldDef, { static: true }) fieldDef: NovoConditionFieldDef;
@ViewChildren(FormControlName) formControlsByName: QueryList<FormControlName>;

constructor(public labels: NovoLabelService) {}

ngOnInit() {
this._syncFieldDefName();
this._syncFieldDefOperatorValue();
this._previousOperatorValue = this.defaultOperator as Operator;
// Need to add self to FilterBuilder because "ContentChildren won't find it"
this.fieldDef?.register();
}

ngAfterViewInit() {
setTimeout(() => {
this.frameAfterViewInit();
});
}

frameAfterViewInit() {
const operatorField = this.formControlsByName.find(formControlDirective => formControlDirective.name === 'operator')?.control;
if (operatorField) {
this._previousOperatorValue = operatorField.value;
}
}

ngOnDestroy() {
this.fieldDef?.unregister();
}

/**
* Define an edit group of operators. Once defined, if the user switches from one of these operators to another,
* then the condition value will not be cleared. This makes sense if both operators use the same UI controls for editing.
* @param operators The set of Operator values intended to share UI controls.
*/
protected defineOperatorEditGroup(...operators: Operator[]): void {
this.operatorEditGroups.push(new Set(operators));
}

onOperatorSelect(formGroup: UntypedFormGroup): void {
formGroup.get('value').setValue(null);
let clearVal = true;
if (this._previousOperatorValue && this.operatorEditGroups?.length) {
const previousOperatorGroupIndex = this.operatorEditGroups.findIndex(grp => grp.has(this._previousOperatorValue));
const newOperatorValue = formGroup.get('operator').getRawValue();
const newOperatorGroupIndex = this.operatorEditGroups.findIndex(grp => grp.has(newOperatorValue));
if (previousOperatorGroupIndex !== -1 && newOperatorGroupIndex !== -1 && previousOperatorGroupIndex === newOperatorGroupIndex) {
clearVal = false;
}
}
this._previousOperatorValue = formGroup.get('operator').value;
if (clearVal) {
formGroup.get('value').setValue(null);
}
}

/** Synchronizes the column definition name with the text column name. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Component,
computed,
ElementRef,
inject,
input,
InputSignal,
OnDestroy,
Expand All @@ -15,14 +16,15 @@ import {
ViewEncapsulation,
WritableSignal
} from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import { NovoPickerToggleElement } from 'novo-elements/elements/field';
import { PlacesListComponent } from 'novo-elements/elements/places';
import { NovoLabelService } from 'novo-elements/services';
import { Helpers, Key } from 'novo-elements/utils';
import { Subscription } from 'rxjs';
import { AddressCriteriaConfig, AddressData, AddressRadius, AddressRadiusUnitsName, Operator, RadiusUnits } from '../query-builder.types';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { NovoSelectElement } from 'novo-elements/elements/select';

/**
* Handle selection of field values when a list of options is provided.
Expand Down Expand Up @@ -82,6 +84,7 @@ export class NovoDefaultAddressConditionDef extends AbstractConditionFieldDef im
@ViewChildren(NovoPickerToggleElement) overlayChildren: QueryList<NovoPickerToggleElement>;
@ViewChildren('addressInput') inputChildren: QueryList<ElementRef>;
@ViewChild('placesPicker') placesPicker: PlacesListComponent;
@ViewChildren(NovoSelectElement) addressSideTest: any;

// Static defaults
radiusValues: number[] = [5, 10, 20, 30, 40, 50, 100];
Expand Down Expand Up @@ -115,19 +118,21 @@ export class NovoDefaultAddressConditionDef extends AbstractConditionFieldDef im

private _addressChangesSubscription: Subscription = Subscription.EMPTY;

constructor(public element: ElementRef, public labels: NovoLabelService) {
super(labels);
public element = inject(ElementRef);

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.includeAny, Operator.excludeAny, Operator.radius);
}

ngAfterViewInit() {
setTimeout(() => {
// Initialize the radius value from existing data
this.assignRadiusFromValue();
frameAfterViewInit(): void {
super.frameAfterViewInit();
// Initialize the radius value from existing data
this.assignRadiusFromValue();

// Update the radius on address value changes
this._addressChangesSubscription = this.inputChildren.changes.subscribe(() => {
this.assignRadiusFromValue();
})
// Update the radius on address value changes
this._addressChangesSubscription = this.inputChildren.changes.subscribe(() => {
this.assignRadiusFromValue();
});
}

Expand Down Expand Up @@ -203,6 +208,17 @@ export class NovoDefaultAddressConditionDef extends AbstractConditionFieldDef im
this.closePlacesList(viewIndex);
}

// Override abstract behavior - allow moving location from includeAny to radius, but when moving the opposite direction,
// trim out radius information from the value
onOperatorSelect(formGroup: UntypedFormGroup): void {
const previousOperator = this._previousOperatorValue;
super.onOperatorSelect(formGroup);
if ([previousOperator, formGroup.get('operator').getRawValue()].indexOf(Operator.radius) !== -1 &&
formGroup.get('value').getRawValue() != null) {
formGroup.get('value').setValue(this.updateRadiusInValues(formGroup, this.getValue(formGroup)));
}
}

onRadiusSelect(formGroup: AbstractControl, radius: number): void {
this.radius.set(radius);
// We must dirty the form explicitly to show up as a user modification when it was done programmatically
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { Operator } from '../query-builder.types';
import { NovoLabelService } from 'novo-elements/services';

/**
* When constructing a query using a field that is a boolean with only true/false as possible values.
Expand Down Expand Up @@ -29,4 +30,9 @@ import { Operator } from '../query-builder.types';
})
export class NovoDefaultBooleanConditionDef extends AbstractConditionFieldDef {
defaultOperator = Operator.include;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.include, Operator.exclude, Operator.isNull);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, QueryList, ViewChildren, ViewEncaps
import { NovoPickerToggleElement } from 'novo-elements/elements/field';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { Operator } from '../query-builder.types';
import { NovoLabelService } from 'novo-elements/services';

/**
* Most complicated of the default conditions defs, a date needs to provide a different
Expand Down Expand Up @@ -59,6 +60,11 @@ export class NovoDefaultDateConditionDef extends AbstractConditionFieldDef {

defaultOperator = Operator.within;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.before, Operator.after);
}

closePanel(event, viewIndex): void {
const overlay = this.overlayChildren.find(item => item.overlayId === viewIndex);
overlay.closePanel(event);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, QueryList, ViewChildren, ViewEncaps
import { NovoPickerToggleElement } from 'novo-elements/elements/field';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { Operator } from '../query-builder.types';
import { NovoLabelService } from 'novo-elements/services';

/**
* Most complicated of the default conditions defs, a date needs to provide a different
Expand Down Expand Up @@ -58,6 +59,11 @@ export class NovoDefaultDateTimeConditionDef extends AbstractConditionFieldDef {

defaultOperator = Operator.within;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.before, Operator.after);
}

closePanel(event, viewIndex): void {
const overlay = this.overlayChildren.find(item => item.overlayId === viewIndex);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { Operator } from '../query-builder.types';
import { NovoLabelService } from 'novo-elements/services';

/**
* When constructing a query using a field that is an Int, Double, Number ...etc.
Expand Down Expand Up @@ -36,4 +37,9 @@ import { Operator } from '../query-builder.types';
})
export class NovoDefaultNumberConditionDef extends AbstractConditionFieldDef {
defaultOperator = Operator.equalTo;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.greaterThan, Operator.lessThan, Operator.equalTo);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChangeDetectionStrategy, Component, ViewChild, ViewEncapsulation } from '@angular/core';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { NovoLabelService } from 'novo-elements/services';
import { Operator } from '../query-builder.types';
import { NovoSelectElement } from 'novo-elements/elements/select';
import { AbstractConditionFieldDef } from './abstract-condition.definition';

/**
* Handle selection of field values when a list of options is provided.
Expand Down Expand Up @@ -41,4 +41,9 @@ import { NovoSelectElement } from 'novo-elements/elements/select';
})
export class NovoDefaultPickerConditionDef extends AbstractConditionFieldDef {
defaultOperator = Operator.includeAny;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.includeAny, Operator.includeAll, Operator.excludeAny);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { FormControl, FormGroup } from '@angular/forms';
import { NovoDefaultStringConditionDef } from './string-condition.definition';

describe('StringConditionDefinition', () => {
let formGroup: FormGroup;

beforeEach(() => {
formGroup = new FormGroup({
value: new FormControl(null),
operator: new FormControl('includeAny'),
});
})

it('should combine arrays in the form control', () => {
const mockEvent = {
input: {
value: 'string1'
},
value: 'string1'
};
NovoDefaultStringConditionDef.prototype.add(mockEvent, formGroup);
expect(formGroup.controls.value.value).toEqual(['string1']);
const arrayOne = formGroup.controls.value.value;
mockEvent.value = 'string2';
NovoDefaultStringConditionDef.prototype.add(mockEvent, formGroup);
expect(formGroup.controls.value.value).toEqual(['string1', 'string2']);
// verify this is a different array object for change detection
expect(formGroup.controls.value.value).not.toBe(arrayOne);
});

it('should remove values accordingly', () => {
const arrayOne = ['string1', 'string3', 'string5'];
formGroup.controls.value.setValue(arrayOne);
NovoDefaultStringConditionDef.prototype.remove('string3', formGroup);
expect(formGroup.controls.value.value).toEqual(['string1', 'string5']);
expect(formGroup.controls.value.value).not.toBe(arrayOne);
});

describe('AbstractConditionFieldDef', () => {
it('should only reset value if the operator edit group has changed', () => {
const mockObj = {
_previousOperatorValue: 'includeAny',
operatorEditGroups: [new Set(['includeAny', 'includeAll'])],
};
formGroup.controls.value.setValue('test');
formGroup.controls.operator.setValue('includeAll');
NovoDefaultStringConditionDef.prototype.onOperatorSelect.call(mockObj, formGroup);
expect(formGroup.controls.value.value).toBe('test');

formGroup.controls.operator.setValue('notEditGroup');
NovoDefaultStringConditionDef.prototype.onOperatorSelect.call(mockObj, formGroup);
expect(formGroup.controls.value.value).toBe(null);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
import { AbstractControl } from '@angular/forms';
import { AbstractConditionFieldDef } from './abstract-condition.definition';
import { NovoLabelService } from 'novo-elements/services';
import { Operator } from '../query-builder.types';
import { AbstractConditionFieldDef } from './abstract-condition.definition';

/**
* Constructing filters against String fields can be complex. Each "chip" added to the
Expand Down Expand Up @@ -59,6 +60,11 @@ import { Operator } from '../query-builder.types';
export class NovoDefaultStringConditionDef extends AbstractConditionFieldDef {
defaultOperator = Operator.includeAny;

constructor(labelService: NovoLabelService) {
super(labelService);
this.defineOperatorEditGroup(Operator.includeAny, Operator.includeAll, Operator.excludeAny);
}

getValue(formGroup: AbstractControl): any[] {
return formGroup.value?.value || [];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { HttpClient } from '@angular/common/http';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, inject, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { AbstractControl, UntypedFormBuilder, UntypedFormControl } from '@angular/forms';
import {
AbstractConditionFieldDef,
Expand Down Expand Up @@ -49,9 +49,7 @@ export class CustomPickerConditionDef extends AbstractConditionFieldDef implemen
/** Subject that emits when the component has been destroyed. */
protected _onDestroy = new Subject<void>();

constructor(public http: HttpClient, labels: NovoLabelService) {
super(labels);
}
http = inject(HttpClient);

ngOnInit() {
super.ngOnInit();
Expand Down Expand Up @@ -92,7 +90,10 @@ export class JustCriteriaExample implements OnInit {
andOr = [Conjunction.AND, Conjunction.OR];
andOrNot = [Conjunction.AND, Conjunction.OR, Conjunction.NOT];

addressConfig: AddressCriteriaConfig = {};
addressConfig: AddressCriteriaConfig = {
radiusEnabled: true,
radiusUnits: 'miles'
};
addressRadiusEnabled: boolean = false;
addressRadiusEnabledOptions: { label: string, value: boolean }[] = [
{ label: 'Yes', value: true },
Expand Down

0 comments on commit cb106df

Please sign in to comment.