Skip to content

Commit

Permalink
Sync repo from v92 to v92 20241211091629 (#213)
Browse files Browse the repository at this point in the history
* Automated sync from source branch v92

* readme updated

* modules reset

---------

Co-authored-by: imx-sync-bot <imx-sync-bot@oneidentity>
  • Loading branch information
Martina-Graeber-One-Identity and imx-sync-bot authored Dec 18, 2024
1 parent 5b027f0 commit ed65231
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
83347a0472cb668acbdacd5c219a2d3c843d08a9
deb3af53cfba7230233e3e3d444679956488799e
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

## Change log

### December 11, 2024
- 430843: Fixes an inconsistency in the Attestation History when an approver is defined in multiple sublevels.
- 467451: Fixes some issues with the „Show attestation cases to be approved by chief approval team“ toggle on the Pending Attestation page.
- 472174: Fixes an issue with the data export in data tables, when using additional columns in the configuration.
- 470782: Fixes the information, provided for attestors and receivers.

### November 19, 2024
- 468962: Method confirmGeneral returns a valid value on OkResult.
- 465213: Fixes an infinite loop if the an invalid value is set on a basic CDR.
Expand Down
Binary file not shown.
Binary file added imxweb/imx-modules/elemental-ui-core-18.0.14.tgz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,39 @@
*
*/

import { Injectable, Type } from '@angular/core';
import { OverlayRef } from '@angular/cdk/overlay';
import { Injectable, Type } from '@angular/core';
import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core';
import { TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs';

import { PortalAttestationApprove } from 'imx-api-att';
import { CompareOperator, EntityData, FilterType, ValType } from 'imx-qbm-dbts';
import { SnackBarService, EntityService, ColumnDependentReference, BaseCdr, ExtService, BaseReadonlyCdr, CdrFactoryService } from 'qbm';
import { CompareOperator, EntityData, FilterType, TypedEntity, ValType } from 'imx-qbm-dbts';
import {
AuthenticationService,
BaseCdr,
BaseReadonlyCdr,
CdrFactoryService,
ColumnDependentReference,
EntityService,
ExtService,
SnackBarService,
} from 'qbm';
import { JustificationService, JustificationType, PersonService, UserModelService } from 'qer';
import { ApiService } from '../api.service';
import { AttestationCase } from '../decision/attestation-case';
import { AttestationCasesService } from '../decision/attestation-cases.service';
import { AttestationInquiry } from '../decision/attestation-inquiries/attestation-inquiry.model';
import { AttestationActionComponent } from './attestation-action.component';
import { AttestationCase } from '../decision/attestation-case';
import { AttestationWorkflowService } from './attestation-workflow.service';
import { AttestationCaseAction } from './attestation-case-action.interface';
import { ApiService } from '../api.service';
import { AttestationInquiry } from '../decision/attestation-inquiries/attestation-inquiry.model';
import { AttestationWorkflowService } from './attestation-workflow.service';

@Injectable({
providedIn: 'root',
})
export class AttestationActionService {
public readonly applied = new Subject();
private uidUser: string;

constructor(
private readonly apiService: ApiService,
Expand All @@ -58,10 +68,13 @@ export class AttestationActionService {
private readonly snackBar: SnackBarService,
private readonly entityService: EntityService,
private readonly person: PersonService,
private readonly workflow: AttestationWorkflowService,
private readonly workflow: AttestationWorkflowService,
private readonly userService: UserModelService,
private readonly extService: ExtService
) {}
private readonly extService: ExtService,
authentication: AuthenticationService
) {
authentication.onSessionResponse.subscribe((state) => (this.uidUser = state.UserUid ?? ''));
}

public async directDecision(attestationCases: AttestationCase[], userUid: string): Promise<void> {
const actionParameters = {
Expand Down Expand Up @@ -384,7 +397,7 @@ export class AttestationActionService {
ColumnName: 'ReasonHead',
Type: ValType.Text,
IsMultiLine: true,
MinLen:metadata.mandatory ? 1 : 0
MinLen: metadata.mandatory ? 1 : 0,
}),
metadata.display || '#LDS#Reason for your decision'
);
Expand Down Expand Up @@ -452,7 +465,7 @@ export class AttestationActionService {

try {
justification = await this.justification.createCdr(
approve ? JustificationType.approveAttestation : JustificationType.denyAttestation,
approve ? JustificationType.approveAttestation : JustificationType.denyAttestation
);
} finally {
setTimeout(() => this.busyService.hide(busyIndicator));
Expand All @@ -479,6 +492,7 @@ export class AttestationActionService {
Reason: actionParameters.reason.column.GetValue(),
UidJustification: actionParameters.justification?.column?.GetValue(),
Decision: approve,
SubLevel: this.getSubLevel(attestationCase, attestationCase.data),
});
},
});
Expand Down Expand Up @@ -544,4 +558,26 @@ export class AttestationActionService {
display || '#LDS#Identity'
);
}

private getSubLevel(entity: TypedEntity, extended: any): number {
//get all workflowsteps for the current decision level
const steps = extended.WorkflowSteps?.Entities?.filter(
(elem) =>
elem?.Columns?.UID_QERWorkingMethod.Value === entity.GetEntity().GetColumn('UID_QERWorkingMethod').GetValue() &&
elem.Columns.LevelNumber.Value === entity.GetEntity().GetColumn('DecisionLevel').GetValue()
);
// get the Workflow data that
// - belong to one of the current workflow steps
// - can be decided by the user
// - are not decided yet
const data = steps.flatMap((step) =>
extended.WorkflowData.Entities.filter(
(elem) =>
elem?.Columns?.UID_QERWorkingStep.Value === step?.Columns?.UID_QERWorkingStep.Value &&
elem?.Columns?.UID_PersonHead.Value === this.uidUser &&
elem?.Columns?.Decision?.Value === ''
)
);
return data[0]?.Columns?.SubLevelNumber?.Value ?? 0; //return the sublevel number
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,5 @@ import { EntityData } from 'imx-qbm-dbts';
export interface Approvers {
current: EntityData[];
future: EntityData[];
canSeeSteps: boolean;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<li data-imx-identifier="decision-step-is-calculating" class="imx-event imx-pending"
*ngIf="approvers.current.length === 0">
*ngIf="approvers.current.length === 0 && approvers.canSeeSteps">
<mat-card>
{{'#LDS#The next approval step is currently being calculated.' | translate}}
{{
'#LDS#The next approval step is currently being calculated.' | translate
}}
</mat-card>
</li>
<li data-imx-identifier="decision-step-current-approvers" class="imx-event imx-pending"
Expand Down
21 changes: 12 additions & 9 deletions imxweb/projects/att/src/lib/decision/attestation-cases.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,17 @@ export class AttestationCasesService {
}

public async get(
attDecisionParameters: AttestationDecisionLoadParameters,
isUserEscalationApprover = false
): Promise<TypedEntityCollectionData<AttestationCase> | undefined> {
const collection = await this.attClient.typedClient.PortalAttestationApprove.Get(attDecisionParameters, {
signal: this.abortController.signal,
});
if (!collection) {
return undefined;
}
attDecisionParameters?: AttestationDecisionLoadParameters,
isUserEscalationApprover = false,
signal?: AbortSignal,
): Promise<TypedEntityCollectionData<AttestationCase>> {
const navigationState = {
...attDecisionParameters,
Escalation:
((attDecisionParameters?.uid_attestationcase ?? '') !== '' && isUserEscalationApprover) || attDecisionParameters?.Escalation,
};

const collection = await this.attClient.typedClient.PortalAttestationApprove.Get(navigationState, { signal });
return {
tableName: collection?.tableName,
totalCount: collection?.totalCount,
Expand Down Expand Up @@ -166,6 +168,7 @@ export class AttestationCasesService {
return {
current: approverContainer.approverNow,
future: approverContainer.approverFuture,
canSeeSteps: approverContainer.canSeeSteps,
};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ export class AttestationDecisionComponent implements OnInit, OnDestroy {
attestationCaseWithPolicy = (
await this.attestationCases.get(
{
Escalation: this.viewEscalation,
Escalation: this.isUserEscalationApprover,
uidpolicy: attestationCase.UID_AttestationPolicy.value,
filter: [
{
Expand Down
65 changes: 38 additions & 27 deletions imxweb/projects/qbm/src/lib/data-export/export-columns.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,20 @@ import _ from 'lodash';
import { DataSourceToolbarSettings } from '../data-source-toolbar/data-source-toolbar-settings';

export interface DSTExportState {
dataModel?: DataModel,
selectedExport?: FormControl,
exportOptions?: EuiSelectOption[],
isAllData?: boolean,
columns?: FormControl[],
columnOptions?: EuiSelectOption[]
dataModel?: DataModel;
selectedExport?: FormControl;
exportOptions?: EuiSelectOption[];
isAllData?: boolean;
columns?: FormControl[];
columnOptions?: EuiSelectOption[];
}
export interface FilteredColumnOption{
value: string; options: EuiSelectOption[];
export interface FilteredColumnOption {
value: string;
options: EuiSelectOption[];
}

@Injectable({
providedIn: 'root'
providedIn: 'root',
})
export class ExportColumnsService {
public columnOptions: EuiSelectOption[];
Expand All @@ -63,14 +64,15 @@ export class ExportColumnsService {
{
display: 'PDF',
value: 'application/pdf',
}
},
];
public exportOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => option.display.toLowerCase().includes(searchInputValue.toLowerCase());
public exportOptionsFilter = (option: EuiSelectOption, searchInputValue: string) =>
option.display.toLowerCase().includes(searchInputValue.toLowerCase());

public columnOptionsFilter = (option: EuiSelectOption, searchInputValue: string) => {
const sanitizedInput = searchInputValue.toLowerCase();
return option.display.toLowerCase().includes(sanitizedInput) || option?.displayDetail?.toLowerCase().includes(sanitizedInput);
}
};

// This function will check if the incoming data model is different from what exists.
public setupExport(settings?: DataSourceToolbarSettings): void {
Expand All @@ -84,32 +86,41 @@ export class ExportColumnsService {
}

public checkDataModel(dataModel: DataModel): boolean {
const stashedProperties = this.stashedState.dataModel.Properties.map(column => column.Property.ColumnName);
const properties = dataModel.Properties.map(column => column.Property.ColumnName);
const stashedProperties = this.stashedState.dataModel.Properties.map((column) => column.Property.ColumnName);
const properties = dataModel.Properties.map((column) => column.Property.ColumnName);
return _.isEqual(stashedProperties, properties);
}

// Saves the column options internally
public createInitialState(settings: DataSourceToolbarSettings): void {
// Column Options sorted alphebetically, not filtering by IsAdditional - this leads to empty exports
const columnOptions = settings.dataModel.Properties.map(prop => {

const columnOptions = settings.dataModel.Properties.map((prop) => {
return this.makeOption(prop);
});
columnOptions.sort((a, b) => a.display >= b.display ? 1: -1);
columnOptions.sort((a, b) => (a.display >= b.display ? 1 : -1));


const selectedExport = new FormControl('text/csv');

// Check for initial columns, or try to use displayed columns
const columns: FormControl[] = [];
if (settings.exportMethod?.initialColumns) {
settings.exportMethod.initialColumns.forEach(column => {
const option = columnOptions.find(prop => prop.value === column);
// get additional columns from the configuration
const conf = settings.viewConfig?.viewConfigs?.find((elem) => elem.UseAsDefault);
const additional = conf?.AdditionalTableColumns ?? [];
// Create an unique, combined list
const columnsToDisplay = new Set(settings.exportMethod.initialColumns.concat(additional));

columnsToDisplay.forEach((column) => {
const option = columnOptions.find((prop) => prop.value === column);
if (option) {
columns.push(this.createColumn(option));
}
})
});
} else if (settings?.displayedColumns) {
settings.displayedColumns.forEach(column => {
const option = columnOptions.find(prop => prop.value === column.ColumnName);
settings.displayedColumns.forEach((column) => {
const option = columnOptions.find((prop) => prop.value === column.ColumnName);
if (option) {
columns.push(this.createColumn(option));
}
Expand All @@ -127,8 +138,8 @@ export class ExportColumnsService {
columns,
isAllData: this.isAllData,
selectedExport,
exportOptions: this.exportOptions
}
exportOptions: this.exportOptions,
};
}

// Setup an option for column export
Expand All @@ -137,8 +148,8 @@ export class ExportColumnsService {
return {
display,
value: property.Property.ColumnName,
displayDetail: property.Property?.Description
}
displayDetail: property.Property?.Description,
};
}

// Create a new column for export
Expand All @@ -149,10 +160,10 @@ export class ExportColumnsService {
// Stash the state of the sidesheet for later use
public stashState(): void {
// Filter out all invalid columns, leave one if all are invalid
if (this.stashedState.columns.every(column => column.invalid)) {
if (this.stashedState.columns.every((column) => column.invalid)) {
this.stashedState.columns = [this.createColumn()];
} else {
this.stashedState.columns = this.stashedState.columns.filter(column => column.valid);
this.stashedState.columns = this.stashedState.columns.filter((column) => column.valid);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export class ApproverContainer {
*/
public approverNow: EntityData[] = [];

public canSeeSteps: boolean;

/**
* List of next approvers
*/
Expand Down Expand Up @@ -120,6 +122,8 @@ export class ApproverContainer {
const orderedWorkingSteps = this.buildOrderedWorkingSteps();
this.logger?.trace(this, 'working steps with order', orderedWorkingSteps);

this.canSeeSteps = this.request.pwoData?.WorkflowSteps?.Entities.length > 0;

if (canSeeCurrent) {
const currentSteps = orderedWorkingSteps.filter((step) => step.order === 1);
this.logger?.trace(this, 'current steps', currentSteps);
Expand Down

0 comments on commit ed65231

Please sign in to comment.