Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18babc1f5668dd9c130706cee0841b58762c06cc
f70881aebe952327a2f72c75ff8e9558794abdfd
3 changes: 3 additions & 0 deletions .sync-history
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
f70881aeb 2026-06-17 Merged PR 93671: #721953 - QER: Fix IsInActive field not visible for non-admin users in identity sidesheet
e7f62f45c 2026-06-17 Merged PR 93417: #709042 - Web Portal: Fix ValidFrom error message when approving requests with MaxValidDays
679fe1db7 2026-06-11 Merged PR 93262: #706275 Enable bulk edit for role-membership cart items
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
### June 18, 2026
- 710272: Fixing an issue with Rule violations filter column mismatch.
- 706275: Fixing enable bulk edit for role-membership cart items.
- 709042: Fixing an issue with new request approval workflow valid dates.
- 721953: Fixing IsInActive field not visible for non-admin users in identity sidesheet.

### May 26, 2026
- 708344: Fixing an issue with ordering a product where the service item has a mandatory image form field.
- 706275: Fixes an issue with bulk editing does not work in shopping cart for some items.
Expand Down
Binary file modified imxweb/imx-modules/imx-api-aad.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-aob.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-apc.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-att.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-cpl.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-dpr.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-hds.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-olg.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-pol.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-qbm.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-qer.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-rmb.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-rms.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-rps.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-sac.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-tsb.tgz
Binary file not shown.
Binary file modified imxweb/imx-modules/imx-api-uci.tgz
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export class RulesViolationsService {
const call = await this.cplClient.typedClient.PortalRules.Get({
filter: [
{ ColumnName: 'UID_NonCompliance', CompareOp: CompareOperator.Equal, Type: FilterType.Compare, Value1: uidNonCompliance },
{ ColumnName: 'isWorkingcopy', CompareOp: CompareOperator.Equal, Type: FilterType.Compare, Value1: false },
{ ColumnName: 'IsWorkingCopy', CompareOp: CompareOperator.Equal, Type: FilterType.Compare, Value1: false },
],
});
return call.Data[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,14 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy {

// Handle the IsInActive column outside the context of a CDR editor so the UI can invert the meaning to make more sense to the user
// This should be inversed on the api data response at some point, but until then we handle it in the UI
this.isActiveFormControl.setValue(!this.data.selectedIdentity.IsInActive.value);
if (!this.data.canEdit || !this.data.selectedIdentity.IsInActive.GetMetadata().CanEdit()) {
this.isActiveFormControl.disable();
// For non-admins, IsInActive is rendered as a CDR field instead, so we skip the toggle form control registration.
if (this.data.isAdmin) {
this.isActiveFormControl.setValue(!this.data.selectedIdentity.IsInActive.value);
if (!this.data.canEdit || !this.data.selectedIdentity.IsInActive.GetMetadata().CanEdit()) {
this.isActiveFormControl.disable();
}
this.detailsFormGroup.addControl(this.data.selectedIdentity.IsInActive.Column.ColumnName, this.isActiveFormControl);
}
this.detailsFormGroup.addControl(this.data.selectedIdentity.IsInActive.Column.ColumnName, this.isActiveFormControl);

this.isSecurityIncidentFormControl.setValue(this.data.selectedIdentity.IsSecurityIncident.value);
if (!this.data.canEdit || !this.data.selectedIdentity.IsSecurityIncident.GetMetadata().CanEdit()) {
Expand All @@ -355,7 +358,7 @@ export class IdentitySidesheetComponent implements OnInit, OnDestroy {
const organizationalColumns = this.data.projectConfig.PersonConfig?.VI_Employee_MasterData_OrganizationalAttributes || [];
this.cdrListOrganizational = this.cdrFactoryService.buildCdrFromColumnList(
this.data.selectedIdentity.GetEntity(),
organizationalColumns.filter((column) => column !== 'IsInActive'),
organizationalColumns.filter((column) => !this.data.isAdmin || column !== 'IsInActive'),
!this.data.canEdit,
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,14 @@
*
*/

import { UntypedFormGroup } from '@angular/forms';
import { Approval } from '../approval';
import { WorkflowActionEdit } from './workflow-action-edit.interface';

export interface WorkflowActionEditWrapper {
title: string;
message: string;
data: WorkflowActionEdit;
apply: (request: Approval) => Promise<any>;
apply: (request: Approval, formGroup: UntypedFormGroup) => Promise<any>;
discardChangesOnAbort?: boolean;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
data-imx-identifier="workflow-action-button-save"
mat-flat-button
color="primary"
(click)="sideSheetRef.close(true)"
(click)="onClose()"
*ngIf="formGroup"
[disabled]="formGroup.invalid"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,4 +79,8 @@ export class WorkflowActionComponent {
);
}
}

onClose(): void {
this.sideSheetRef.close(this.formGroup);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { EuiLoadingService, EuiSidesheetService } from '@elemental-ui/core';
import { TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs';

import { AbstractControl } from '@angular/forms';
import { AbstractControl, UntypedFormGroup } from '@angular/forms';
import {
CollectionLoadParameters,
CompareOperator,
Expand Down Expand Up @@ -87,7 +87,7 @@ export class WorkflowActionService {
private readonly extService: ExtService,
private readonly userService: UserModelService,
private readonly queueService: ProcessingQueueService,
) { }
) {}

public async directDecisions(requests: (Approval | TypedEntity)[], userUid: string): Promise<void> {
const actionParameters = {
Expand Down Expand Up @@ -374,11 +374,10 @@ export class WorkflowActionService {
message:
'#LDS#The validity period you specified is not valid. The validity end date lies before the validity start date, or vice versa. Change the validity period.',
},

},
apply: async (request: Approval) => {
if (request.canSetValidFrom() && actionParameters.validFrom) {
const from = actionParameters.validFrom.column.GetValue();
apply: async (request: Approval, formGroup: UntypedFormGroup) => {
if (request.canSetValidFrom() && formGroup.controls.ValidFrom) {
const from = formGroup.controls.ValidFrom!.value;
if (from) {
request.ValidFrom.value = addTimeNowToDate(from);
} else {
Expand All @@ -387,16 +386,15 @@ export class WorkflowActionService {
}
}

if (request.canSetValidUntil(itShopConfig) && actionParameters.validUntil) {
const until = actionParameters.validUntil.column.GetValue();
if (request.canSetValidUntil(itShopConfig) && formGroup.controls.ValidUntil) {
const until = formGroup.controls.ValidUntil!.value;
if (until) {
request.ValidUntil.value = addTimeNowToDate(until);
} else {
// The value was removed, so set it to null in order to not send an invalid date to the backend
await request.ValidUntil.Column.PutValue(null);
}
}

await request.commit();
await this.approvalsService.makeDecision(request, {
Reason: actionParameters.reason?.column.GetValue(),
Expand Down Expand Up @@ -439,13 +437,13 @@ export class WorkflowActionService {
isInEscalationView: isEscalation,
customValidation: itShopConfig?.VI_ITShop_ApproverReasonMandatoryOnDeny
? {
validate: () => {
const reasonValue = actionParameters.reason?.column.GetValue();
const justificationValue = actionParameters.justification?.column?.GetValue();
return (reasonValue != null && reasonValue.length > 0) || (justificationValue != null && justificationValue.length > 0);
},
message: '#LDS#Please enter or select a reason for your decision.',
}
validate: () => {
const reasonValue = actionParameters.reason?.column.GetValue();
const justificationValue = actionParameters.justification?.column?.GetValue();
return (reasonValue != null && reasonValue.length > 0) || (justificationValue != null && justificationValue.length > 0);
},
message: '#LDS#Please enter or select a reason for your decision.',
}
: undefined,
},
apply: async (request: Approval) => {
Expand Down Expand Up @@ -599,7 +597,7 @@ export class WorkflowActionService {
request.GetEntity().GetDisplay(),
'',
async () => {
await config.apply(request as Approval);
await config.apply(request as Approval, result);
},
request.GetEntity().GetKeys().join(','),
),
Expand All @@ -614,7 +612,7 @@ export class WorkflowActionService {
let success: boolean;
try {
for (const request of config.data.requests) {
await config.apply(request as Approval);
await config.apply(request as Approval, result);
}
success = true;
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,18 +155,18 @@ export class CartItemsComponent implements OnInit, OnChanges {
updated: observable,
cloneItem: this.itemCanBeCloned(cartItem)
? async () => {
reloadItems = true;
this.logger.trace(this, 'shopping cart must be reloaded');
this.cartItemClone.cloneItemForPersons({
personOrderedFkRelations: cartItem.UID_PersonOrdered.GetMetadata().GetFkRelations(),
accProduct: {
DataValue: cartItem.UID_AccProduct.value,
DisplayValue: cartItem.UID_AccProduct.Column.GetDisplayValue(),
},
uidITShopOrg: cartItem.UID_ITShopOrg.value,
display: cartItem.GetEntity().GetDisplay(),
});
}
reloadItems = true;
this.logger.trace(this, 'shopping cart must be reloaded');
this.cartItemClone.cloneItemForPersons({
personOrderedFkRelations: cartItem.UID_PersonOrdered.GetMetadata().GetFkRelations(),
accProduct: {
DataValue: cartItem.UID_AccProduct.value,
DisplayValue: cartItem.UID_AccProduct.Column.GetDisplayValue(),
},
uidITShopOrg: cartItem.UID_ITShopOrg.value,
display: cartItem.GetEntity().GetDisplay(),
});
}
: undefined,
};

Expand Down Expand Up @@ -275,16 +275,12 @@ export class CartItemsComponent implements OnInit, OnChanges {
});
}

public HasSelectedItems(): boolean {
return this.selectedItems != null && this.selectedItems.length > 0;
}

public itemSelectable(event: any): void {
const cartItem: PortalCartitem = event.item;
event.selectableRows.push(
cartItem.UID_ShoppingCartItemParent.value == null ||
cartItem.UID_ShoppingCartItemParent.value.length === 0 ||
cartItem.IsOptionalChild.value,
cartItem.UID_ShoppingCartItemParent.value.length === 0 ||
cartItem.IsOptionalChild.value,
);
}

Expand All @@ -300,15 +296,6 @@ export class CartItemsComponent implements OnInit, OnChanges {
return this.itemsCanBeMoved(true);
}

/**
* If only one item is selected, it can be edited. If multiple items are selected, they can be edited if they don't have parameters that prevent copying.
* @returns boolean indicating if the selected items can be edited
*/
public itemsCanBeEdited(): boolean {
return this.selectedItems.length === 1
|| (this.HasSelectedItems() && this.selectedItems.every((item) => !item.IsNoCopyParametersPerson.value));
}

public async showValidationOverview(cartItem: PortalCartitem): Promise<void> {
if (cartItem.CheckResult.value === CartItemCheckStatus.notChecked) {
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ <h2 *ngIf="!isEmpty" class="mat-headline-5">
</button>
<button
data-imx-identifier="imx-table-actions-edit-menu"
[disabled]="!cartItems?.itemsCanBeEdited()"
[disabled]="!cartItems?.haveSelectedItems()"
title="{{ '#LDS#Opens common request properties for the selected products for editing' | translate }}"
mat-menu-item
(click)="cartItems?.editSelectedItems()"
Expand Down