AAE-38063 Default buttons are temporarily visible before the custom buttons in workspace (#11198)

* Bonus Content: Remove warnings from console

* Fixes: Prevents display issues during form loading

Ensures the process definition card and start button are not rendered until the form is fully loaded or an error occurs during the loading process.
This prevents flickering and ensures a smoother user experience.

* BONUS content: calm down sonar cube

* Removes unnecessary error handling

Removes the error handler from the `subscribe` block of the `startProcess` method in `StartProcessCloudComponent`.
The error handling was redundant, as errors are already handled by other mechanisms.
This simplifies the code and avoids potential duplicate error handling.

* Uses `test` method for regex checks

Replaces the `exec` method with the `test` method for regular
expression checks to determine if a pattern exists within a string.

This resolves potential issues where the return value of `exec`
(an array or null) was not being properly evaluated as a boolean
condition, leading to incorrect logic execution.

---------

Co-authored-by: Fabian Kindgen <39992669+fkindgen@users.noreply.github.com>
This commit is contained in:
Michaela
2025-09-17 15:49:28 +02:00
committed by GitHub
parent d230176e7f
commit 1b212e8805
6 changed files with 54 additions and 52 deletions

View File

@@ -15,7 +15,6 @@
* limitations under the License.
*/
import { NgIf } from '@angular/common';
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { TranslatePipe } from '@ngx-translate/core';
import { ViewerComponent } from '../../../../viewer';
@@ -40,7 +39,7 @@ import { WidgetComponent } from '../widget.component';
'(invalid)': 'event($event)',
'(select)': 'event($event)'
},
imports: [NgIf, TranslatePipe, ViewerComponent, ErrorWidgetComponent],
imports: [TranslatePipe, ViewerComponent, ErrorWidgetComponent],
encapsulation: ViewEncapsulation.None
})
export class BaseViewerWidgetComponent extends WidgetComponent implements OnInit {

View File

@@ -18,13 +18,12 @@
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
import { ApplicationInstanceModel, DEFAULT_APP_INSTANCE_ICON, DEFAULT_APP_INSTANCE_THEME } from '../../models/application-instance.model';
import { CommonModule } from '@angular/common';
import { TranslatePipe } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { MatCardModule } from '@angular/material/card';
@Component({
selector: 'adf-cloud-app-details',
imports: [CommonModule, TranslatePipe, MatIconModule, MatCardModule],
imports: [CommonModule, MatIconModule, MatCardModule],
templateUrl: './app-details-cloud.component.html',
styleUrls: ['./app-details-cloud.component.scss'],
encapsulation: ViewEncapsulation.None

View File

@@ -19,13 +19,12 @@ import { Component, ViewEncapsulation } from '@angular/core';
import { FormService, BaseViewerWidgetComponent, ErrorWidgetComponent } from '@alfresco/adf-core';
import { AlfrescoViewerComponent } from '@alfresco/adf-content-services';
import { TranslatePipe } from '@ngx-translate/core';
import { NgIf } from '@angular/common';
/* eslint-disable @angular-eslint/component-selector */
@Component({
selector: 'file-viewer-widget',
imports: [NgIf, ErrorWidgetComponent, AlfrescoViewerComponent, TranslatePipe],
imports: [ErrorWidgetComponent, AlfrescoViewerComponent, TranslatePipe],
templateUrl: './file-viewer.widget.html',
styleUrls: ['./file-viewer.widget.scss'],
host: {

View File

@@ -1,4 +1,4 @@
@if (processDefinitionLoaded) {
@if (processDefinitionLoaded && !isFormCloudLoading) {
<mat-card appearance="outlined" class="adf-start-process">
<mat-card-content>
@if (showTitle) {

View File

@@ -1150,15 +1150,14 @@ describe('StartProcessCloudComponent', () => {
component.ngOnChanges({ appName: firstChange });
component.processDefinitionList = fakeProcessDefinitions;
component.processDefinitionName = fakeProcessDefinitions[0].name;
fixture.detectChanges();
});
it('start process button should be enabled when isProcessStarting is false', async () => {
fixture.detectChanges();
it('start process button should be enabled when isProcessStarting is false', () => {
component.processForm.controls['processInstanceName'].setValue(fakeProcessDefinitions[0].id);
component.appName = 'test app name';
component.isProcessStarting = false;
fixture.detectChanges();
await fixture.whenStable();
const startButton = fixture.debugElement.query(By.css('#button-start'));
expect(startButton).not.toBeNull();
@@ -1166,27 +1165,21 @@ describe('StartProcessCloudComponent', () => {
expect((startButton.nativeElement as HTMLButtonElement).disabled).toBeFalse();
});
it('start process button should be disabled when isFormCloudLoading is true', async () => {
fixture.detectChanges();
it('start process button should be null when isFormCloudLoading is true', () => {
component.processForm.controls['processInstanceName'].setValue(fakeProcessDefinitions[0].id);
component.appName = 'test app name';
component.isFormCloudLoading = true;
fixture.detectChanges();
await fixture.whenStable();
const startButton = fixture.debugElement.query(By.css('#button-start'));
expect(startButton).not.toBeNull();
expect(component.disableStartButton).toBeTrue();
expect((startButton.nativeElement as HTMLButtonElement).disabled).toBeTrue();
expect(startButton).toBeFalsy();
});
it('start process button should be disabled when isLoading is true', async () => {
fixture.detectChanges();
it('start process button should be disabled when isLoading is true', () => {
component.processForm.controls['processInstanceName'].setValue(fakeProcessDefinitions[0].id);
component.appName = 'test app name';
component.isProcessStarting = true;
fixture.detectChanges();
await fixture.whenStable();
const startButton = fixture.debugElement.query(By.css('#button-start'));
expect(startButton).not.toBeNull();

View File

@@ -66,8 +66,8 @@ import { MatDialog } from '@angular/material/dialog';
const MAX_NAME_LENGTH: number = 255;
const PROCESS_DEFINITION_DEBOUNCE: number = 300;
const DATE_TIME_IDENTIFIER_REG_EXP = new RegExp('%{datetime}', 'i');
const PROCESS_DEFINITION_IDENTIFIER_REG_EXP = new RegExp('%{processdefinition}', 'i');
const DATE_TIME_IDENTIFIER_REG_EXP = /%{datetime}/i;
const PROCESS_DEFINITION_IDENTIFIER_REG_EXP = /%{processdefinition}/i;
@Component({
selector: 'adf-cloud-start-process',
@@ -174,7 +174,7 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
isProcessStarting = false;
isFormCloudLoaded = false;
isFormCloudLoading = false;
isFormCloudLoading = true;
processDefinitionLoaded = false;
showStartProcessButton$: Observable<boolean>;
@@ -237,13 +237,18 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
return this.translateService.instant('ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.FORM.ACTION.CANCEL').toUpperCase();
}
constructor(private translateService: TranslationService) {
constructor(private readonly translateService: TranslationService) {
this.startProcessButtonLabel = this.defaultStartProcessButtonLabel;
this.cancelButtonLabel = this.defaultCancelProcessButtonLabel;
}
ngOnInit() {
this.processDefinition.setValue(this.processDefinitionName);
if (this.processDefinitionName) {
this.processDefinition.setValue(this.processDefinitionName);
} else {
this.isFormCloudLoading = false;
}
this.processDefinition.valueChanges
.pipe(debounceTime(PROCESS_DEFINITION_DEBOUNCE))
.pipe(takeUntilDestroyed(this.destroyRef))
@@ -295,8 +300,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
private selectProcessDefinitionByProcessDefinitionName(processDefinitionName: string): void {
this.filteredProcesses = this.getProcessDefinitionListByNameOrKey(processDefinitionName);
if (this.isProcessFormValid && this.filteredProcesses && this.filteredProcesses.length === 1) {
this.isFormCloudLoading = this.isProcessFormValid && this.filteredProcesses && this.filteredProcesses.length === 1;
if (this.isFormCloudLoading) {
this.setProcessDefinitionOnForm(this.filteredProcesses[0].name);
}
}
@@ -314,30 +319,34 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
this.startProcessCloudService
.getStartEventConstants(this.appName, processDefinitionCurrent.id)
.pipe(catchError(() => of([] as TaskVariableCloud[])))
]).subscribe(([staticMappings, constants]) => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
this.processDefinitionCurrent = processDefinitionCurrent;
this.isFormCloudLoading = false;
]).subscribe({
next: ([staticMappings, constants]) => {
this.staticMappings = staticMappings;
this.resolvedValues = this.staticMappings.concat(this.values || []);
this.processDefinitionCurrent = processDefinitionCurrent;
const displayStart = constants?.find((constant) => constant.name === 'startEnabled');
const startLabel = constants?.find((constant) => constant.name === 'startLabel');
const displayStart = constants?.find((constant) => constant.name === 'startEnabled');
const startLabel = constants?.find((constant) => constant.name === 'startLabel');
const displayCancel = constants?.find((constant) => constant.name === 'cancelEnabled');
const cancelLabel = constants?.find((constant) => constant.name === 'cancelLabel');
const displayCancel = constants?.find((constant) => constant.name === 'cancelEnabled');
const cancelLabel = constants?.find((constant) => constant.name === 'cancelLabel');
if (displayStart) {
this.displayStartSubject.next(displayStart?.value);
}
if (startLabel) {
this.startProcessButtonLabel = startLabel?.value?.trim()?.length > 0 ? startLabel.value.trim() : this.defaultStartProcessButtonLabel;
}
if (displayStart) {
this.displayStartSubject.next(displayStart?.value);
}
if (startLabel) {
this.startProcessButtonLabel =
startLabel?.value?.trim()?.length > 0 ? startLabel.value.trim() : this.defaultStartProcessButtonLabel;
}
if (displayCancel) {
this.showCancelButton = displayCancel?.value === 'true' && this.showCancelButton;
}
if (cancelLabel) {
this.cancelButtonLabel = cancelLabel?.value?.trim()?.length > 0 ? cancelLabel.value.trim() : this.defaultCancelProcessButtonLabel;
if (displayCancel) {
this.showCancelButton = displayCancel?.value === 'true' && this.showCancelButton;
}
if (cancelLabel) {
this.cancelButtonLabel = cancelLabel?.value?.trim()?.length > 0 ? cancelLabel.value.trim() : this.defaultCancelProcessButtonLabel;
}
this.isFormCloudLoading = false;
}
});
@@ -379,8 +388,8 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
this.startProcessCloudService
.getProcessDefinitions(this.appName)
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(
(processDefinitionRepresentations: ProcessDefinitionCloud[]) => {
.subscribe({
next: (processDefinitionRepresentations: ProcessDefinitionCloud[]) => {
this.processDefinitionList = processDefinitionRepresentations;
if (processDefinitionRepresentations.length === 1) {
this.selectDefaultProcessDefinition();
@@ -393,14 +402,17 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
this.setProcessDefinitionOnForm(processDefinition.name);
this.processDefinitionSelectionChanged(processDefinition);
}
} else {
this.isFormCloudLoading = false;
}
this.processDefinitionLoaded = true;
},
() => {
error: () => {
this.errorMessageId = 'ADF_CLOUD_PROCESS_LIST.ADF_CLOUD_START_PROCESS.ERROR.LOAD_PROCESS_DEFS';
this.isFormCloudLoading = false;
}
);
});
}
private isValidName(name: string): boolean {
@@ -564,12 +576,12 @@ export class StartProcessCloudComponent implements OnChanges, OnInit {
getDefaultProcessName(processNameFormat: string, processInstance?: ProcessInstanceCloud): string {
let processName = processNameFormat;
if (processName.match(DATE_TIME_IDENTIFIER_REG_EXP)) {
if (DATE_TIME_IDENTIFIER_REG_EXP.test(processName)) {
const presentDateTime = getTime(new Date());
processName = processName.replace(DATE_TIME_IDENTIFIER_REG_EXP, this.localizedDatePipe.transform(presentDateTime, 'medium'));
}
if (processName.match(PROCESS_DEFINITION_IDENTIFIER_REG_EXP)) {
if (PROCESS_DEFINITION_IDENTIFIER_REG_EXP.test(processName)) {
const selectedProcessDefinitionName = processInstance ? processInstance.processDefinitionName : '';
processName = processName.replace(PROCESS_DEFINITION_IDENTIFIER_REG_EXP, selectedProcessDefinitionName);
}