Skip to content

Commit

Permalink
Remove Select from AQL builder in Criteria mode
Browse files Browse the repository at this point in the history
askask committed Aug 26, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 08f34f1 commit 2e22030
Showing 19 changed files with 217 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
<h2 class="mat-headline-3">From</h2>
<h2 *ngIf="dialogMode !== AqlBuilderDialogMode.Criteria" class="mat-headline-3">From</h2>

<div class="num-select-box contains" fxLayout="column" fxLayoutGap="20px">
<div *ngIf="dialogMode === AqlBuilderDialogMode.Criteria">
<h2 class="mat-headline-3 pointer" (click)="setDestination()">From</h2>
<div
class="num-select-flag pointer"
[ngClass]="{
'num-select-flag--active': aqbModel.selectDestination === AqbSelectDestination.From
}"
role="button"
tabindex="0"
aria-labelledby="section-heading"
(keydown.enter)="setDestination()"
(keydown.space)="setDestination()"
(click)="setDestination()"
data-test="aqb__select__set-destination-button"
>
<fa-icon icon="check"></fa-icon>
</div>
</div>

<div
class="num-select-box"
fxLayout="column"
fxLayoutGap="20px"
[ngClass]="{
'num-select-box--active': aqbModel.selectDestination === AqbSelectDestination.From,
contains: dialogMode !== AqlBuilderDialogMode.Criteria
}"
>
<num-aql-builder-contains-group
*ngFor="let composition of compositions; let i = index"
role="list"
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@ import { AqbContainsCompositionUiModel } from '../../../../shared/models/aqb/aqb
import { AqbUiModel } from '../../../../shared/models/aqb/aqb-ui.model'

import { AqlBuilderContainsComponent } from './aql-builder-contains.component'
import { FontAwesomeTestingModule } from '@fortawesome/angular-fontawesome/testing'

describe('AqlBuilderContainsComponent', () => {
let component: AqlBuilderContainsComponent
@@ -35,6 +36,7 @@ describe('AqlBuilderContainsComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [AqlBuilderContainsComponent, ContainsGroupStubComponent],
imports: [FontAwesomeTestingModule],
}).compileComponents()
})

Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Component, Input } from '@angular/core'
import { AqbContainsCompositionUiModel } from '../../../../shared/models/aqb/aqb-contains-composition-ui.model'
import { AqbUiModel } from '../../../../shared/models/aqb/aqb-ui.model'
import { AqbSelectDestination } from '../../../../shared/models/aqb/aqb-select-destination.enum'
import { AqlBuilderDialogMode } from '../../../../shared/models/archetype-query-builder/aql-builder-dialog-mode.enum'

@Component({
selector: 'num-aql-builder-contains',
@@ -16,6 +18,9 @@ export class AqlBuilderContainsComponent {
@Input()
compositions: AqbContainsCompositionUiModel[] = []

@Input()
dialogMode: AqlBuilderDialogMode = AqlBuilderDialogMode.Criteria

deleteCompositionByReferenceId(compositionReferenceId: number): void {
this.aqbModel.handleDeletionByCompositionReferenceIds([compositionReferenceId])
this.compositions = this.compositions.filter(
@@ -26,4 +31,11 @@ export class AqlBuilderContainsComponent {
deleteArchetypesByReferenceIds(archetypeReferenceIds: number[]): void {
this.aqbModel.handleDeletionByArchetypeReferenceIds(archetypeReferenceIds)
}

setDestination(): void {
this.aqbModel.selectDestination = AqbSelectDestination.From
}

protected readonly AqbSelectDestination = AqbSelectDestination
protected readonly AqlBuilderDialogMode = AqlBuilderDialogMode
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<section fxLayout="row wrap" fxLayoutGap="15px" fxLayoutAlign="start center">
<div class="name-field mat-body-strong" data-test="aqb__select__item__name">
<span>{{ item.name | archetype: true }}</span>
<span *ngIf="item.isComposition"> ({{ item.templateId }})</span>
<span *ngIf="item.modelType"> ({{ item.templateId }})</span>
</div>
</section>

Original file line number Diff line number Diff line change
@@ -30,7 +30,7 @@ describe('AqlBuilderSelectItemComponent', () => {
containmentTreeNode,
compositionReferenceId,
archetypeReferenceId,
false,
'archetype',
templateId
)

Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
<h2 id="section-heading" class="mat-headline-3 pointer" (click)="setDestination()">Select</h2>
<div
class="num-select-flag pointer"
[ngClass]="{
'num-select-flag--active': aqbModel.selectDestination === AqbSelectDestination.Select
}"
role="button"
tabindex="0"
aria-labelledby="section-heading"
(keydown.enter)="setDestination()"
(keydown.space)="setDestination()"
(click)="setDestination()"
data-test="aqb__select__set-destination-button"
>
<fa-icon icon="check"></fa-icon>
<div *ngIf="dialogMode === AqlBuilderDialogMode.Criteria">
<h2 id="section-heading" class="mat-headline-3">Select</h2>
<p>
{{ 'QUERIES.NO_SELECT' | translate }}
</p>
</div>
<div
class="num-select-box"
fxLayout="column"
[ngClass]="{
'num-select-box--active': aqbModel.selectDestination === AqbSelectDestination.Select
}"
>
<num-aql-builder-select-item
class="aqb-item mat-elevation-z2"

<div *ngIf="dialogMode !== AqlBuilderDialogMode.Criteria">
<h2 id="section-heading" class="mat-headline-3 pointer" (click)="setDestination()">Select</h2>
<div
class="num-select-flag pointer"
[ngClass]="{
'aqb-item--last': i === aqbModel.select.length - 1
'num-select-flag--active': aqbModel.selectDestination === AqbSelectDestination.Select
}"
fxLayout="row"
fxLayoutAlign="space-between start"
*ngFor="let item of aqbModel.select; let i = index"
[item]="item"
(deleteItem)="deleteItem(i)"
data-test="aqb__select__item"
></num-aql-builder-select-item>
role="button"
tabindex="0"
aria-labelledby="section-heading"
(keydown.enter)="setDestination()"
(keydown.space)="setDestination()"
(click)="setDestination()"
data-test="aqb__select__set-destination-button"
>
<fa-icon icon="check"></fa-icon>
</div>
<div
class="num-select-box"
fxLayout="column"
[ngClass]="{
'num-select-box--active': aqbModel.selectDestination === AqbSelectDestination.Select
}"
>
<num-aql-builder-select-item
class="aqb-item mat-elevation-z2"
[ngClass]="{
'aqb-item--last': i === aqbModel.select.length - 1
}"
fxLayout="row"
fxLayoutAlign="space-between start"
*ngFor="let item of aqbModel.select; let i = index"
[item]="item"
(deleteItem)="deleteItem(i)"
data-test="aqb__select__item"
></num-aql-builder-select-item>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@ import { Component, Input } from '@angular/core'

import { AqbSelectDestination } from '../../../../shared/models/aqb/aqb-select-destination.enum'
import { AqbUiModel } from '../../../../shared/models/aqb/aqb-ui.model'
import { AqlBuilderDialogMode } from '../../../../shared/models/archetype-query-builder/aql-builder-dialog-mode.enum'

@Component({
selector: 'num-aql-builder-select',
@@ -15,11 +16,16 @@ export class AqlBuilderSelectComponent {
@Input()
aqbModel: AqbUiModel

@Input()
dialogMode: AqlBuilderDialogMode = AqlBuilderDialogMode.Criteria

deleteItem(index: number): void {
this.aqbModel.select.splice(index, 1)
}

setDestination(): void {
this.aqbModel.selectDestination = AqbSelectDestination.Select
}

protected readonly AqlBuilderDialogMode = AqlBuilderDialogMode
}
Original file line number Diff line number Diff line change
@@ -42,7 +42,8 @@
class="mat-tree-node__display-name"
[ngClass]="{
'mat-tree-node__display-name--disabled':
mode === Mode.DataRetrieval && selectDestination === Destination.Select
(mode === Mode.DataRetrieval && selectDestination === Destination.Select) ||
(mode === Mode.Criteria && selectDestination === Destination.From)
}"
>{{ node.displayName }}</span
>
Original file line number Diff line number Diff line change
@@ -149,7 +149,7 @@ describe('AqlEditorCeatorComponent', () => {

describe('When a query is supposed to be created with the builder', () => {
const dialogContentPayload: IAqlBuilderDialogInput = {
mode: AqlBuilderDialogMode.Criteria,
mode: AqlBuilderDialogMode.Search,
model: new AqbUiModel(),
}
const dialogConfig: DialogConfig = {
@@ -158,7 +158,7 @@ describe('AqlEditorCeatorComponent', () => {
}

it('should open the dialog with the config including the content payload', () => {
component.openBuilderDialog(AqlBuilderDialogMode.Criteria)
component.openBuilderDialog(AqlBuilderDialogMode.Search)
expect(mockDialogService.openDialog).toHaveBeenCalledTimes(1)
expect(dialogCallParameter.dialogContentComponent).toEqual(
dialogConfig.dialogContentComponent
Original file line number Diff line number Diff line change
@@ -18,6 +18,9 @@ import {
VALIDATION_ERROR_CONFIG,
VALIDATION_SUCCESS_CONFIG,
} from './constants'
import { AqbSelectDestination } from '../../../../shared/models/aqb/aqb-select-destination.enum'
import { AqbSelectItemUiModel } from '../../../../shared/models/aqb/aqb-select-item-ui.model'
import { IContainmentTreeNode } from '../../models/containment-tree-node.interface'

@Component({
selector: 'num-aql-editor-creator',
@@ -115,6 +118,14 @@ export class AqlEditorCeatorComponent {
}

openBuilderDialog(mode: AqlBuilderDialogMode): void {
if (mode === AqlBuilderDialogMode.Criteria) {
const node = new (class implements IContainmentTreeNode {
displayName = 'EHR'
})()
this.aqbModel.selectDestination = AqbSelectDestination.From
this.aqbModel.select = [new AqbSelectItemUiModel(node, 0, 0, 'ehr', '')]
}

const dialogContentPayload: IAqlBuilderDialogInput = {
mode: mode,
model: this.aqbModel,
Original file line number Diff line number Diff line change
@@ -9,10 +9,14 @@
></num-aql-builder-templates>

<section role="region" fxFlex="auto" fxLayout="column" fxLayoutGap="24px">
<num-aql-builder-select [aqbModel]="aqbModel"></num-aql-builder-select>
<num-aql-builder-select
[aqbModel]="aqbModel"
[dialogMode]="dialogInput.mode"
></num-aql-builder-select>
<num-aql-builder-contains
[aqbModel]="aqbModel"
[compositions]="compositions"
[dialogMode]="dialogInput.mode"
></num-aql-builder-contains>
<num-aql-builder-where
[aqbModel]="aqbModel"
@@ -31,7 +35,11 @@

<num-button
type="primary"
[isDisabled]="!aqbModel.select.length"
[isDisabled]="
dialogInput.mode === AqlBuilderDialogMode.Criteria
? !aqbModel.contains.compositions.size
: !aqbModel.select.length
"
(singleClick)="handleDialogConfirm()"
data-test="aqb__confirm-button"
>{{ 'BUTTON.APPLY_SELECTION' | translate }}</num-button
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ import { AqbUiModel } from '../../../../shared/models/aqb/aqb-ui.model'
import { COMPILE_ERROR_CONFIG } from './constants'

import { DialogAqlBuilderComponent } from './dialog-aql-builder.component'
import { selectClickTestCases } from './tests/select-click-testcases'
import { ISelectClickTest, selectClickTestCases } from './tests/select-click-testcases'

describe('DialogAqlBuilderComponent', () => {
let component: DialogAqlBuilderComponent
@@ -36,11 +36,13 @@ describe('DialogAqlBuilderComponent', () => {
@Component({ selector: 'num-aql-builder-select', template: '' })
class SelectStubComponent {
@Input() aqbModel: any
@Input() dialogMode: any
}
@Component({ selector: 'num-aql-builder-contains', template: '' })
class ContainsStubComponent {
@Input() compositions: any
@Input() aqbModel: any
@Input() dialogMode: any
}
@Component({ selector: 'num-aql-builder-where', template: '' })
class WhereStubComponent {
@@ -86,10 +88,10 @@ describe('DialogAqlBuilderComponent', () => {
jest.clearAllMocks()
})

describe('When the dialog is in aqlEditor mode', () => {
describe('When the dialog is in Search mode', () => {
beforeEach(() => {
component.dialogInput = {
mode: AqlBuilderDialogMode.Criteria,
mode: AqlBuilderDialogMode.Search,
model: new AqbUiModel(),
}

@@ -100,9 +102,20 @@ describe('DialogAqlBuilderComponent', () => {
expect(component).toBeTruthy()
expect(aqlEditorService.getTemplates).toHaveBeenCalled()
})
})

describe('When the dialog is', () => {
beforeEach(() => {
component.dialogInput = {
mode: AqlBuilderDialogMode.Search, //overwritten in test
model: new AqbUiModel(),
}

fixture.detectChanges()
})

test.each(selectClickTestCases)(
'should call or not call the aqb Model to handle the clickEvent',
test.each<ISelectClickTest>(selectClickTestCases)(
'in $mode mode should call or not call the aqb Model to handle the clickEvent (%#)',
(testcase) => {
jest.spyOn(component.aqbModel, 'handleElementSelect')

Original file line number Diff line number Diff line change
@@ -83,7 +83,22 @@ export class DialogAqlBuilderComponent

return false
}
isAllowedSelectionInEditor(clickEvent: IAqbSelectClick): boolean {

isAllowedSelectionInCriteria(clickEvent: IAqbSelectClick): boolean {
if (this.aqbModel.selectDestination === AqbSelectDestination.From) {
if (!clickEvent.item.rmType) {
return true
}
} else {
if (clickEvent.item.rmType) {
return true
}
}

return false
}

isAllowedSelectionInSearch(clickEvent: IAqbSelectClick): boolean {
if (this.aqbModel.selectDestination === AqbSelectDestination.Select) {
return true
} else {
@@ -96,9 +111,14 @@ export class DialogAqlBuilderComponent
}

isAllowedSelection(clickEvent: IAqbSelectClick): boolean {
return this.dialogInput.mode === AqlBuilderDialogMode.DataRetrieval
? this.isAllowedSelectionInRetrieval(clickEvent)
: this.isAllowedSelectionInEditor(clickEvent)
switch (this.dialogInput.mode) {
case AqlBuilderDialogMode.DataRetrieval:
return this.isAllowedSelectionInRetrieval(clickEvent)
case AqlBuilderDialogMode.Criteria:
return this.isAllowedSelectionInCriteria(clickEvent)
case AqlBuilderDialogMode.Search:
return this.isAllowedSelectionInSearch(clickEvent)
}
}

handleItemSelect(clickEvent: IAqbSelectClick): void {
@@ -126,4 +146,6 @@ export class DialogAqlBuilderComponent
handleDialogCancel(): void {
this.closeDialog.emit()
}

protected readonly AqlBuilderDialogMode = AqlBuilderDialogMode
}
Original file line number Diff line number Diff line change
@@ -31,9 +31,10 @@ const selectedItemWithoutRmType: IContainmentTreeNode = {
}

export const selectClickTestCases: ISelectClickTest[] = [
// Select
{
result: true,
mode: AqlBuilderDialogMode.Criteria,
mode: AqlBuilderDialogMode.Search,
selectDestination: AqbSelectDestination.Select,
clickEvent: {
item: selectedItemWithRmType,
@@ -43,7 +44,7 @@ export const selectClickTestCases: ISelectClickTest[] = [
},
{
result: true,
mode: AqlBuilderDialogMode.Criteria,
mode: AqlBuilderDialogMode.Search,
selectDestination: AqbSelectDestination.Select,
clickEvent: {
item: selectedItemWithoutRmType,
@@ -82,6 +83,16 @@ export const selectClickTestCases: ISelectClickTest[] = [
templateId: 'temp1',
},
},
{
result: false,
mode: AqlBuilderDialogMode.Search,
selectDestination: AqbSelectDestination.Where,
clickEvent: {
item: selectedItemWithoutRmType,
compositionId: 'comp1',
templateId: 'temp1',
},
},
{
result: false,
mode: AqlBuilderDialogMode.DataRetrieval,
@@ -102,6 +113,16 @@ export const selectClickTestCases: ISelectClickTest[] = [
templateId: 'temp1',
},
},
{
result: true,
mode: AqlBuilderDialogMode.Search,
selectDestination: AqbSelectDestination.Where,
clickEvent: {
item: selectedItemWithRmType,
compositionId: 'comp1',
templateId: 'temp1',
},
},
{
result: true,
mode: AqlBuilderDialogMode.DataRetrieval,
@@ -112,4 +133,25 @@ export const selectClickTestCases: ISelectClickTest[] = [
templateId: 'temp1',
},
},
// From
{
result: true,
mode: AqlBuilderDialogMode.Criteria,
selectDestination: AqbSelectDestination.From,
clickEvent: {
item: selectedItemWithoutRmType,
compositionId: 'comp1',
templateId: 'temp1',
},
},
{
result: false,
mode: AqlBuilderDialogMode.Criteria,
selectDestination: AqbSelectDestination.From,
clickEvent: {
item: selectedItemWithRmType,
compositionId: 'comp1',
templateId: 'temp1',
},
},
]
1 change: 1 addition & 0 deletions src/app/shared/models/aqb/aqb-select-destination.enum.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum AqbSelectDestination {
Select = 'SELECT',
From = 'FROM',
Where = 'WHERE',
}
11 changes: 7 additions & 4 deletions src/app/shared/models/aqb/aqb-select-item-ui.model.ts
Original file line number Diff line number Diff line change
@@ -13,14 +13,14 @@ export class AqbSelectItemUiModel {
humanReadablePath: string
compositionReferenceId: number
archetypeReferenceId: number
isComposition: boolean
modelType: 'composition' | 'archetype' | 'ehr'
templateId: string

constructor(
item: IContainmentTreeNode,
compositionReferenceId: number,
archetypeReferenceId: number,
isComposition: boolean,
modelType: 'composition' | 'archetype' | 'ehr',
templateId: string
) {
this.name = item.name || item.archetypeId
@@ -30,7 +30,7 @@ export class AqbSelectItemUiModel {
this.humanReadablePath = item.humanReadablePath
this.compositionReferenceId = compositionReferenceId
this.archetypeReferenceId = archetypeReferenceId
this.isComposition = isComposition
this.modelType = modelType
this.templateId = templateId
}

@@ -39,7 +39,10 @@ export class AqbSelectItemUiModel {
_type: AqbNodeType.SelectExpression,
columnExpression: {
_type: AqbNodeType.IdentifiedPath,
root: `${this.isComposition ? 'c' : 'o'}${this.archetypeReferenceId}`,
root:
this.modelType === 'ehr'
? 'e'
: `${this.modelType === 'composition' ? 'c' : 'o'}${this.archetypeReferenceId}`,
...(this.aqlPath && { path: this.aqlPath }),
},
...(this.givenName && { alias: this.givenName }),
4 changes: 2 additions & 2 deletions src/app/shared/models/aqb/aqb-ui.model.ts
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@ export class AqbUiModel {
isComposition,
clickEvent.templateId
)
} else {
} else if (this.selectDestination === AqbSelectDestination.Where) {
const userGeneratedWhereClause = this.where.children[1] as AqbWhereGroupUiModel
this.pushToWhereClause(
userGeneratedWhereClause,
@@ -110,7 +110,7 @@ export class AqbUiModel {
clickEvent.item,
compositionReferenceId,
archetypeReferenceId,
isComposition,
isComposition ? 'composition' : 'archetype',
templateId
)
this.select.push(aqbSelect)
1 change: 1 addition & 0 deletions src/assets/i18n/de.json
Original file line number Diff line number Diff line change
@@ -101,6 +101,7 @@
"COMPILE_ERROR_MESSAGE": "Das Kriterium konnte nicht kompiliert werden. Bitte überprüfen Sie die Konfiguration des Kriteriums und versuchen Sie es erneut.",
"GET_COMPOSITION_ERROR": "Dar Rückgabeparameter kann nicht geladen werden. Bitte schließen Sie das Fenster und versuchen Sie es erneut.",
"COLUMNS": "Spalten",
"NO_SELECT": "Bitte beachten Sie: Für die Erstellung eines Kriteriums wird kein SELECT verwendet.",
"WHERE_RESTRICTED_TO_COHORT": "Bitte beachten Sie: Die WHERE-Klausel ist auf die Kohorte beschränkt.",
"VALIDATION_ERROR": "Die Syntax des Kriteriums ist nicht valide",
"VALIDATION_SUCCESS": "Die Syntax des Kriteriums ist valide",
1 change: 1 addition & 0 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
@@ -101,6 +101,7 @@
"COMPILE_ERROR_MESSAGE": "The criterium could not be complied. Please check the criterium configuration and try again.",
"GET_COMPOSITION_ERROR": "The template cannot be loaded. Please close the window and try again.",
"COLUMNS": "Columns",
"NO_SELECT": "Please note: SELECT is not used to create a criterion.",
"WHERE_RESTRICTED_TO_COHORT": "Please note: the WHERE clause is restricted to the cohort.",
"VALIDATION_ERROR": "The syntax of the criterium is not valid",
"VALIDATION_SUCCESS": "The syntax of the criterium is valid",

0 comments on commit 2e22030

Please sign in to comment.