AAE-26215 standalone form (cloud) (#10535)

This commit is contained in:
Denys Vuika 2025-01-08 07:53:56 -05:00 committed by GitHub
parent 27faf1d2ba
commit b7881db56b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
67 changed files with 453 additions and 642 deletions

View File

@ -34,10 +34,6 @@ describe('AvatarComponent', () => {
const getAvatarImageElement = (): HTMLImageElement => fixture.nativeElement.querySelector('.adf-avatar__image'); const getAvatarImageElement = (): HTMLImageElement => fixture.nativeElement.querySelector('.adf-avatar__image');
it('should create', () => {
expect(component).toBeTruthy();
});
it('should display initials when src is not provided', () => { it('should display initials when src is not provided', () => {
component.src = ''; component.src = '';
fixture.detectChanges(); fixture.detectChanges();

View File

@ -24,6 +24,8 @@ import { FormFieldModel, FormFieldValidator, FormModel, FormOutcomeEvent, FormOu
}) })
// eslint-disable-next-line @angular-eslint/directive-class-suffix // eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class FormBaseComponent { export abstract class FormBaseComponent {
protected _form: FormModel;
static SAVE_OUTCOME_ID: string = '$save'; static SAVE_OUTCOME_ID: string = '$save';
static COMPLETE_OUTCOME_ID: string = '$complete'; static COMPLETE_OUTCOME_ID: string = '$complete';
static START_PROCESS_OUTCOME_ID: string = '$startProcess'; static START_PROCESS_OUTCOME_ID: string = '$startProcess';
@ -96,7 +98,27 @@ export abstract class FormBaseComponent {
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
form: FormModel; /**
* Custom style that is backed by the form.theme.
*/
formStyle: string = '';
get form(): FormModel {
return this._form;
}
/** Underlying form model instance. */
@Input()
set form(form: FormModel) {
this._form = form;
if (form) {
const theme = form.theme?.form;
this.formStyle = theme ? this.flattenStyles(theme) : '';
} else {
this.formStyle = '';
}
}
getParsedFormDefinition(): FormBaseComponent { getParsedFormDefinition(): FormBaseComponent {
return this; return this;
@ -226,4 +248,10 @@ export abstract class FormBaseComponent {
protected abstract storeFormAsMetadata(): void; protected abstract storeFormAsMetadata(): void;
protected abstract onExecuteOutcome(outcome: FormOutcomeModel): boolean; protected abstract onExecuteOutcome(outcome: FormOutcomeModel): boolean;
private flattenStyles(styles: { [key: string]: string }): string {
return Object.entries(styles)
.map(([key, value]) => `${key}: ${value}`)
.join(';');
}
} }

View File

@ -47,3 +47,4 @@ export * from './form-field-variable-options';
export * from './widget-schema.model'; export * from './widget-schema.model';
export * from './theme.model'; export * from './theme.model';
export * from './predefined-theme'; export * from './predefined-theme';
export * from './displayable-cm-properties.model';

View File

@ -57,7 +57,7 @@ export * from './text/text-mask.component';
export * from './display-text'; export * from './display-text';
export * from './header'; export * from './header';
export const WIDGET_DIRECTIVES: any[] = [ export const WIDGET_DIRECTIVES = [
UnknownWidgetComponent, UnknownWidgetComponent,
TextWidgetComponent, TextWidgetComponent,
NumberWidgetComponent, NumberWidgetComponent,
@ -72,6 +72,6 @@ export const WIDGET_DIRECTIVES: any[] = [
DateTimeWidgetComponent, DateTimeWidgetComponent,
JsonWidgetComponent, JsonWidgetComponent,
BaseViewerWidgetComponent BaseViewerWidgetComponent
]; ] as const;
export const MASK_DIRECTIVE: any[] = [InputMaskDirective]; export const MASK_DIRECTIVE = [InputMaskDirective] as const;

View File

@ -1,47 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { FormStylePipe } from './form-style.pipe';
import { ThemeModel } from '../components/widgets/core/theme.model';
describe('FormStylePipe', () => {
let pipe: FormStylePipe;
beforeEach(() => {
pipe = new FormStylePipe();
});
it('should transform form theme into styles', () => {
const formTheme: ThemeModel = {
form: {
'--adf-form-label-font-size': '16px',
'--adf-form-label-color': 'black',
'--adf-form-label-font-weight': 'bold'
}
};
const result = pipe.transform(formTheme);
expect(result).toEqual('--adf-form-label-font-size: 16px;--adf-form-label-color: black;--adf-form-label-font-weight: bold');
});
it('should return an empty string if form theme is undefined', () => {
const result = pipe.transform(undefined);
expect(result).toEqual('');
});
});

View File

@ -1,36 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Pipe, PipeTransform } from '@angular/core';
import { ThemeModel } from '../components/widgets/core/theme.model';
@Pipe({
name: 'adfFormStyle',
standalone: true
})
export class FormStylePipe implements PipeTransform {
transform(formTheme?: ThemeModel): string {
const theme = formTheme?.form;
return theme ? this.flattenStyles(theme) : '';
}
private flattenStyles(styles: { [key: string]: string }): string {
return Object.entries(styles)
.map(([key, value]) => `${key}: ${value}`)
.join(';');
}
}

View File

@ -16,4 +16,3 @@
*/ */
export * from './field-style.pipe'; export * from './field-style.pipe';
export * from './form-style.pipe';

View File

@ -38,10 +38,6 @@ describe('NavbarItemComponent', () => {
button = fixture.nativeElement.querySelector('.adf-navbar-item-btn'); button = fixture.nativeElement.querySelector('.adf-navbar-item-btn');
}); });
it('should create', () => {
expect(component).toBeTruthy();
});
it('should display label', () => { it('should display label', () => {
fixture.detectChanges(); fixture.detectChanges();
expect(button.textContent).toContain('Test Label'); expect(button.textContent).toContain('Test Label');

View File

@ -40,10 +40,6 @@ describe('ProgressComponent', () => {
fixture.detectChanges(); fixture.detectChanges();
}); });
it('should create', () => {
expect(component).toBeTruthy();
});
it('should default to bar variant and indeterminate mode', () => { it('should default to bar variant and indeterminate mode', () => {
expect(component.variant).toBe('bar'); expect(component.variant).toBe('bar');
expect(component.mode).toBe('indeterminate'); expect(component.mode).toBe('indeterminate');

View File

@ -36,18 +36,21 @@ export class CloudFormRenderingService extends FormRenderingService {
constructor() { constructor() {
super(); super();
this.register({ this.register(
[FormFieldTypes.UPLOAD]: () => AttachFileCloudWidgetComponent, {
[FormFieldTypes.DROPDOWN]: () => DropdownCloudWidgetComponent, [FormFieldTypes.UPLOAD]: () => AttachFileCloudWidgetComponent,
[FormFieldTypes.DATE]: () => DateCloudWidgetComponent, [FormFieldTypes.DROPDOWN]: () => DropdownCloudWidgetComponent,
[FormFieldTypes.PEOPLE]: () => PeopleCloudWidgetComponent, [FormFieldTypes.DATE]: () => DateCloudWidgetComponent,
[FormFieldTypes.FUNCTIONAL_GROUP]: () => GroupCloudWidgetComponent, [FormFieldTypes.PEOPLE]: () => PeopleCloudWidgetComponent,
[FormFieldTypes.PROPERTIES_VIEWER]: () => PropertiesViewerWidgetComponent, [FormFieldTypes.FUNCTIONAL_GROUP]: () => GroupCloudWidgetComponent,
[FormFieldTypes.RADIO_BUTTONS]: () => RadioButtonsCloudWidgetComponent, [FormFieldTypes.PROPERTIES_VIEWER]: () => PropertiesViewerWidgetComponent,
[FormFieldTypes.ALFRESCO_FILE_VIEWER]: () => FileViewerWidgetComponent, [FormFieldTypes.RADIO_BUTTONS]: () => RadioButtonsCloudWidgetComponent,
[FormFieldTypes.DISPLAY_RICH_TEXT]: () => DisplayRichTextWidgetComponent, [FormFieldTypes.ALFRESCO_FILE_VIEWER]: () => FileViewerWidgetComponent,
[FormFieldTypes.DATA_TABLE]: () => DataTableWidgetComponent, [FormFieldTypes.DISPLAY_RICH_TEXT]: () => DisplayRichTextWidgetComponent,
[FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY]: () => DisplayExternalPropertyWidgetComponent [FormFieldTypes.DATA_TABLE]: () => DataTableWidgetComponent,
}, true); [FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY]: () => DisplayExternalPropertyWidgetComponent
},
true
);
} }
} }

View File

@ -21,10 +21,14 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { FormCloudComponent } from './form-cloud.component'; import { FormCloudComponent } from './form-cloud.component';
import { FormCustomOutcomesComponent } from './form-cloud-custom-outcomes.component';
import { MatButtonModule } from '@angular/material/button';
@Component({ @Component({
selector: 'adf-cloud-form-with-custom-outcomes', selector: 'adf-cloud-form-with-custom-outcomes',
template: ` <adf-cloud-form #adfCloudForm> standalone: true,
imports: [FormCustomOutcomesComponent, FormCloudComponent, MatButtonModule],
template: `<adf-cloud-form #adfCloudForm>
<adf-cloud-form-custom-outcomes> <adf-cloud-form-custom-outcomes>
<button mat-button id="adf-custom-outcome-1" (click)="onCustomButtonOneClick()">CUSTOM-BUTTON-1</button> <button mat-button id="adf-custom-outcome-1" (click)="onCustomButtonOneClick()">CUSTOM-BUTTON-1</button>
<button mat-button id="adf-custom-outcome-2" (click)="onCustomButtonTwoClick()">CUSTOM-BUTTON-2</button> <button mat-button id="adf-custom-outcome-2" (click)="onCustomButtonTwoClick()">CUSTOM-BUTTON-2</button>
@ -36,7 +40,6 @@ class FormCloudWithCustomOutComesComponent {
adfCloudForm: FormCloudComponent; adfCloudForm: FormCloudComponent;
onCustomButtonOneClick() {} onCustomButtonOneClick() {}
onCustomButtonTwoClick() {} onCustomButtonTwoClick() {}
} }
@ -47,8 +50,7 @@ describe('FormCloudWithCustomOutComesComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, FormCloudWithCustomOutComesComponent]
declarations: [FormCloudWithCustomOutComesComponent]
}); });
fixture = TestBed.createComponent(FormCloudWithCustomOutComesComponent); fixture = TestBed.createComponent(FormCloudWithCustomOutComesComponent);
customComponent = fixture.componentInstance; customComponent = fixture.componentInstance;
@ -58,8 +60,7 @@ describe('FormCloudWithCustomOutComesComponent', () => {
outcomes: [{ id: 'outcome-1', name: 'outcome 1' }] outcomes: [{ id: 'outcome-1', name: 'outcome 1' }]
}; };
const form = new FormModel(formRepresentation); customComponent.adfCloudForm.form = new FormModel(formRepresentation);
customComponent.adfCloudForm.form = form;
fixture.detectChanges(); fixture.detectChanges();
}); });

View File

@ -19,6 +19,7 @@ import { Component } from '@angular/core';
@Component({ @Component({
selector: 'adf-cloud-form-custom-outcomes', selector: 'adf-cloud-form-custom-outcomes',
standalone: true,
template: '<ng-content></ng-content>' template: '<ng-content></ng-content>'
}) })
export class FormCustomOutcomesComponent {} export class FormCustomOutcomesComponent {}

View File

@ -6,7 +6,7 @@
<div <div
*ngIf="hasForm()" *ngIf="hasForm()"
class="adf-cloud-form-container adf-cloud-form-{{displayConfiguration?.options?.fullscreen ? 'fullscreen' : 'inline'}}-container" class="adf-cloud-form-container adf-cloud-form-{{displayConfiguration?.options?.fullscreen ? 'fullscreen' : 'inline'}}-container"
[style]="form.theme | adfFormStyle"> [style]="formStyle">
<div class="adf-cloud-form-content" <div class="adf-cloud-form-content"
[cdkTrapFocus]="displayConfiguration?.options?.trapFocus" [cdkTrapFocus]="displayConfiguration?.options?.trapFocus"
cdkTrapFocusAutoCapture> cdkTrapFocusAutoCapture>
@ -22,78 +22,75 @@
</div> </div>
<adf-toolbar-divider *ngIf="displayConfiguration?.options?.displayCloseButton" /> <adf-toolbar-divider *ngIf="displayConfiguration?.options?.displayCloseButton" />
<button <button
*ngIf="displayConfiguration?.options?.displayCloseButton" *ngIf="displayConfiguration?.options?.displayCloseButton"
class="adf-cloud-form-close-button" class="adf-cloud-form-close-button"
data-automation-id="adf-toolbar-right-back" data-automation-id="adf-toolbar-right-back"
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate" [attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
[attr.data-automation-id]="'adf-cloud-form-close-button'" [attr.data-automation-id]="'adf-cloud-form-close-button'"
[title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate" [title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
mat-icon-button mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}" title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
(click)="switchToDisplayMode()"> (click)="switchToDisplayMode()">
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
</adf-toolbar> </adf-toolbar>
<mat-card <mat-card
appearance="outlined" appearance="outlined"
class="adf-cloud-form-content-card" class="adf-cloud-form-content-card"
[class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'" [class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'"
> >
<div class="adf-cloud-form-content-card-container"> <div class="adf-cloud-form-content-card-container">
<mat-card-header *ngIf="showTitle || showRefreshButton || showValidationIcon"> <mat-card-header *ngIf="showTitle || showRefreshButton || showValidationIcon">
<mat-card-title> <mat-card-title>
<h4> <h4>
<div *ngIf="showValidationIcon" class="adf-form-validation-button"> <div *ngIf="showValidationIcon" class="adf-form-validation-button">
<i id="adf-valid-form-icon" class="material-icons" <i id="adf-valid-form-icon" class="material-icons"
*ngIf="form.isValid; else no_valid_form">check_circle</i> *ngIf="form.isValid; else no_valid_form">check_circle</i>
<ng-template #no_valid_form> <ng-template #no_valid_form>
<i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i> <i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i>
</ng-template> </ng-template>
</div> </div>
<div *ngIf="!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')" class="adf-cloud-form-fullscreen-button"> <div *ngIf="!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')" class="adf-cloud-form-fullscreen-button">
<button mat-icon-button (click)="switchToDisplayMode('fullScreen')" [attr.data-automation-id]="'adf-cloud-form-fullscreen-button'"> <button mat-icon-button (click)="switchToDisplayMode('fullScreen')" [attr.data-automation-id]="'adf-cloud-form-fullscreen-button'">
<mat-icon>fullscreen</mat-icon> <mat-icon>fullscreen</mat-icon>
</button> </button>
</div> </div>
<div *ngIf="showRefreshButton" class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate"> <div *ngIf="showRefreshButton" class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate"> <button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<mat-icon>refresh</mat-icon> <mat-icon>refresh</mat-icon>
</button> </button>
</div> </div>
<span *ngIf="isTitleEnabled()" class="adf-cloud-form-title" [title]="form.taskName" <span *ngIf="isTitleEnabled()" class="adf-cloud-form-title" [title]="form.taskName"
>{{form.taskName}} >{{form.taskName}}
<ng-container *ngIf="!form.taskName"> <ng-container *ngIf="!form.taskName">
{{'FORM.FORM_RENDERER.NAMELESS_TASK' | translate}} {{'FORM.FORM_RENDERER.NAMELESS_TASK' | translate}}
</ng-container> </ng-container>
</span> </span>
</h4> </h4>
</mat-card-title> </mat-card-title>
</mat-card-header> </mat-card-header>
<mat-card-content class="adf-form-container-card-content"> <mat-card-content class="adf-form-container-card-content">
<adf-form-renderer <adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" />
[formDefinition]="form" </mat-card-content>
[readOnly]="readOnly" <mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end">
/> <ng-content select="adf-cloud-form-custom-outcomes"></ng-content>
</mat-card-content> <ng-container *ngFor="let outcome of form.outcomes">
<mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end"> <button
<ng-content select="adf-cloud-form-custom-outcomes"></ng-content> *ngIf="outcome.isVisible"
<ng-container *ngFor="let outcome of form.outcomes"> [id]="'adf-form-'+ outcome.name | formatSpace"
<button [color]="getColorForOutcome(outcome.name)"
*ngIf="outcome.isVisible" mat-button
[id]="'adf-form-'+ outcome.name | formatSpace" [disabled]="!isOutcomeButtonEnabled(outcome)"
[color]="getColorForOutcome(outcome.name)" [class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
mat-button (click)="onOutcomeClicked(outcome)"
[disabled]="!isOutcomeButtonEnabled(outcome)" >
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)" {{outcome.name | translate | uppercase }}
(click)="onOutcomeClicked(outcome)" </button>
> </ng-container>
{{outcome.name | translate | uppercase }} </mat-card-actions>
</button>
</ng-container>
</mat-card-actions>
</div> </div>
</mat-card> </mat-card>
</div> </div>
</div> </div>

View File

@ -32,7 +32,8 @@ import {
WidgetVisibilityService, WidgetVisibilityService,
provideTranslations, provideTranslations,
AuthModule, AuthModule,
FormFieldEvent FormFieldEvent,
NoopTranslateModule
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { ESCAPE } from '@angular/cdk/keycodes'; import { ESCAPE } from '@angular/cdk/keycodes';
@ -46,7 +47,6 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule, TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { Observable, of, throwError } from 'rxjs'; import { Observable, of, throwError } from 'rxjs';
import { FormCloudModule } from '../form-cloud.module';
import { import {
cloudFormMock, cloudFormMock,
conditionalUploadWidgetsMock, conditionalUploadWidgetsMock,
@ -98,7 +98,7 @@ describe('FormCloudComponent', () => {
const resolver = formRenderingService.getComponentTypeResolver(type); const resolver = formRenderingService.getComponentTypeResolver(type);
const widgetType = resolver(null); const widgetType = resolver(null);
const factoryResolver: ComponentFactoryResolver = TestBed.inject(ComponentFactoryResolver); const factoryResolver = TestBed.inject(ComponentFactoryResolver);
const factory = factoryResolver.resolveComponentFactory(widgetType); const factory = factoryResolver.resolveComponentFactory(widgetType);
const componentRef = factory.create(injector); const componentRef = factory.create(injector);
@ -107,7 +107,7 @@ describe('FormCloudComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, FormCloudComponent],
providers: [ providers: [
{ {
provide: VersionCompatibilityService, provide: VersionCompatibilityService,
@ -1539,7 +1539,7 @@ describe('retrieve metadata on submit', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [AuthModule.forRoot({ useHash: true }), NoopAnimationsModule, TranslateModule.forRoot(), CoreModule.forRoot(), FormCloudModule], imports: [AuthModule.forRoot({ useHash: true }), NoopAnimationsModule, NoopTranslateModule, CoreModule.forRoot(), FormCloudComponent],
providers: [ providers: [
provideTranslations('app', 'resources'), provideTranslations('app', 'resources'),
{ {

View File

@ -34,6 +34,7 @@ import {
ConfirmDialogComponent, ConfirmDialogComponent,
ContentLinkModel, ContentLinkModel,
FORM_FIELD_VALIDATORS, FORM_FIELD_VALIDATORS,
FormatSpacePipe,
FormBaseComponent, FormBaseComponent,
FormEvent, FormEvent,
FormFieldModel, FormFieldModel,
@ -41,8 +42,11 @@ import {
FormModel, FormModel,
FormOutcomeEvent, FormOutcomeEvent,
FormOutcomeModel, FormOutcomeModel,
FormRendererComponent,
FormService, FormService,
FormValues, FormValues,
ToolbarComponent,
ToolbarDividerComponent,
UploadWidgetContentLinkModel, UploadWidgetContentLinkModel,
WidgetVisibilityService WidgetVisibilityService
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
@ -55,9 +59,29 @@ import { FormCloudDisplayMode, FormCloudDisplayModeConfiguration } from '../../s
import { FormCloudSpinnerService } from '../services/spinner/form-cloud-spinner.service'; import { FormCloudSpinnerService } from '../services/spinner/form-cloud-spinner.service';
import { DisplayModeService } from '../services/display-mode.service'; import { DisplayModeService } from '../services/display-mode.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { A11yModule } from '@angular/cdk/a11y';
@Component({ @Component({
selector: 'adf-cloud-form', selector: 'adf-cloud-form',
standalone: true,
imports: [
CommonModule,
TranslateModule,
FormatSpacePipe,
MatButtonModule,
MatCardModule,
FormRendererComponent,
MatIconModule,
ToolbarDividerComponent,
ToolbarComponent,
A11yModule
],
providers: [FormCloudSpinnerService],
templateUrl: './form-cloud.component.html', templateUrl: './form-cloud.component.html',
styleUrls: ['./form-cloud.component.scss'] styleUrls: ['./form-cloud.component.scss']
}) })
@ -78,10 +102,6 @@ export class FormCloudComponent extends FormBaseComponent implements OnChanges,
@Input() @Input()
processInstanceId: string; processInstanceId: string;
/** Underlying form model instance. */
@Input()
form: FormModel;
/** Task id to fetch corresponding form and values. */ /** Task id to fetch corresponding form and values. */
@Input() @Input()
taskId: string; taskId: string;

View File

@ -1,7 +1,7 @@
<mat-form-field class="adf-form-definition-selector"> <mat-form-field class="adf-form-definition-selector">
<mat-label>{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.FORM'|translate}}</mat-label> <mat-label>{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.FORM' | translate}}</mat-label>
<mat-select class="adf-form-selector-dropdown" (selectionChange)="onSelect($event)"> <mat-select class="adf-form-selector-dropdown" (selectionChange)="onSelect($event)">
<mat-option [value]="''">{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.NONE'|translate}}</mat-option> <mat-option [value]="''">{{'ADF_CLOUD_TASK_LIST.START_TASK.FORM.LABEL.NONE' | translate}}</mat-option>
<mat-option *ngFor="let form of forms$ | async" [value]="form.id">{{ form.name }}</mat-option> <mat-option *ngFor="let form of forms$ | async" [value]="form.id">{{ form.name }}</mat-option>
</mat-select> </mat-select>
</mat-form-field> </mat-form-field>

View File

@ -17,7 +17,6 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../testing/process-service-cloud.testing.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { FormDefinitionSelectorCloudComponent } from './form-definition-selector-cloud.component'; import { FormDefinitionSelectorCloudComponent } from './form-definition-selector-cloud.component';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service'; import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service';
@ -33,8 +32,7 @@ describe('FormDefinitionCloudComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, FormDefinitionSelectorCloudComponent]
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
fixture = TestBed.createComponent(FormDefinitionSelectorCloudComponent); fixture = TestBed.createComponent(FormDefinitionSelectorCloudComponent);
service = TestBed.inject(FormDefinitionSelectorCloudService); service = TestBed.inject(FormDefinitionSelectorCloudService);

View File

@ -16,7 +16,6 @@
*/ */
import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular';
import { FormCloudModule } from '../form-cloud.module';
import { FormDefinitionSelectorCloudComponent } from './form-definition-selector-cloud.component'; import { FormDefinitionSelectorCloudComponent } from './form-definition-selector-cloud.component';
import { ProcessServicesCloudStoryModule } from '../../testing/process-services-cloud-story.module'; import { ProcessServicesCloudStoryModule } from '../../testing/process-services-cloud-story.module';
import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service'; import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service';
@ -28,7 +27,7 @@ export default {
title: 'Process Services Cloud/Form Cloud/Form Definition Selector Cloud', title: 'Process Services Cloud/Form Cloud/Form Definition Selector Cloud',
decorators: [ decorators: [
moduleMetadata({ moduleMetadata({
imports: [FormCloudModule], imports: [FormDefinitionSelectorCloudComponent],
providers: [{ provide: FormDefinitionSelectorCloudService, useClass: FormDefinitionSelectorCloudServiceMock }] providers: [{ provide: FormDefinitionSelectorCloudService, useClass: FormDefinitionSelectorCloudServiceMock }]
}), }),
applicationConfig({ applicationConfig({

View File

@ -18,17 +18,19 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Observable } from 'rxjs'; import { Observable } from 'rxjs';
import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service'; import { FormDefinitionSelectorCloudService } from '../services/form-definition-selector-cloud.service';
import { MatSelectChange } from '@angular/material/select'; import { MatSelectChange, MatSelectModule } from '@angular/material/select';
import { FormRepresentation } from '../../services/form-fields.interfaces'; import { FormRepresentation } from '../../services/form-fields.interfaces';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
@Component({ @Component({
selector: 'adf-cloud-form-definition-selector', selector: 'adf-cloud-form-definition-selector',
standalone: true,
imports: [CommonModule, TranslateModule, MatSelectModule],
templateUrl: './form-definition-selector-cloud.component.html', templateUrl: './form-definition-selector-cloud.component.html',
styleUrls: ['./form-definition-selector-cloud.component.scss'] styleUrls: ['./form-definition-selector-cloud.component.scss']
}) })
export class FormDefinitionSelectorCloudComponent implements OnInit { export class FormDefinitionSelectorCloudComponent implements OnInit {
/** Name of the application. If specified, this shows the users who have access to the app. */ /** Name of the application. If specified, this shows the users who have access to the app. */
@Input() @Input()
appName: string = ''; appName: string = '';
@ -39,8 +41,7 @@ export class FormDefinitionSelectorCloudComponent implements OnInit {
forms$: Observable<FormRepresentation[]>; forms$: Observable<FormRepresentation[]>;
constructor(private formDefinitionCloudService: FormDefinitionSelectorCloudService) { constructor(private formDefinitionCloudService: FormDefinitionSelectorCloudService) {}
}
ngOnInit(): void { ngOnInit(): void {
this.forms$ = this.formDefinitionCloudService.getStandAloneTaskForms(this.appName); this.forms$ = this.formDefinitionCloudService.getStandAloneTaskForms(this.appName);
@ -49,5 +50,4 @@ export class FormDefinitionSelectorCloudComponent implements OnInit {
onSelect(event: MatSelectChange) { onSelect(event: MatSelectChange) {
this.selectForm.emit(event.value); this.selectForm.emit(event.value);
} }
} }

View File

@ -16,8 +16,12 @@
*/ */
import { Component, Input } from '@angular/core'; import { Component, Input } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
@Component({ @Component({
standalone: true,
imports: [TranslateModule, MatProgressSpinnerModule],
templateUrl: './form-spinner.component.html', templateUrl: './form-spinner.component.html',
styleUrls: ['./form-spinner.component.scss'] styleUrls: ['./form-spinner.component.scss']
}) })

View File

@ -16,7 +16,6 @@
*/ */
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service'; import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service'; import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { AttachFileCloudWidgetComponent } from './attach-file-cloud-widget.component'; import { AttachFileCloudWidgetComponent } from './attach-file-cloud-widget.component';
@ -61,16 +60,10 @@ import {
processVariables processVariables
} from '../../../mocks/attach-file-cloud-widget.mock'; } from '../../../mocks/attach-file-cloud-widget.mock';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { CUSTOM_ELEMENTS_SCHEMA, Injector, runInInjectionContext } from '@angular/core'; import { Injector, runInInjectionContext } from '@angular/core';
import { import { ContentNodeSelectorPanelService, NewVersionUploaderDataAction, NewVersionUploaderService } from '@alfresco/adf-content-services';
ContentModule,
ContentNodeSelectorPanelService,
NewVersionUploaderDataAction,
NewVersionUploaderService
} from '@alfresco/adf-content-services';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { of, throwError } from 'rxjs'; import { of, throwError } from 'rxjs';
import { FormCloudModule } from '../../../form-cloud.module';
const mockNodeToBeVersioned: any = { const mockNodeToBeVersioned: any = {
isFile: true, isFile: true,
@ -150,8 +143,7 @@ describe('AttachFileCloudWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, FormCloudModule, ContentModule.forRoot()], imports: [ProcessServiceCloudTestingModule, AttachFileCloudWidgetComponent]
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
notificationService = TestBed.inject(NotificationService); notificationService = TestBed.inject(NotificationService);
downloadService = TestBed.inject(DownloadService); downloadService = TestBed.inject(DownloadService);

View File

@ -17,21 +17,19 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, inject, OnDestroy, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { import {
FormService, FormService,
ThumbnailService,
NotificationService,
FormValues, FormValues,
ContentLinkModel, ContentLinkModel,
AppConfigService, AppConfigService,
UploadWidgetContentLinkModel, UploadWidgetContentLinkModel,
DestinationFolderPath DestinationFolderPath,
ErrorWidgetComponent
} from '@alfresco/adf-core'; } from '@alfresco/adf-core';
import { Node, NodesApi, RelatedContentRepresentation } from '@alfresco/js-api'; import { Node, NodesApi, RelatedContentRepresentation } from '@alfresco/js-api';
import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service'; import { ContentCloudNodeSelectorService } from '../../../services/content-cloud-node-selector.service';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service'; import { UploadCloudWidgetComponent } from '../upload/upload-cloud.widget';
import { UploadCloudWidgetComponent } from './upload-cloud.widget';
import { DestinationFolderPathModel, DestinationFolderPathType } from '../../../models/form-cloud-representation.model'; import { DestinationFolderPathModel, DestinationFolderPathType } from '../../../models/form-cloud-representation.model';
import { import {
AlfrescoApiService, AlfrescoApiService,
@ -41,15 +39,22 @@ import {
NewVersionUploaderService, NewVersionUploaderService,
VersionManagerUploadData VersionManagerUploadData
} from '@alfresco/adf-content-services'; } from '@alfresco/adf-content-services';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { FilePropertiesTableCloudComponent } from './file-properties-table/file-properties-table-cloud.component';
import { MatButtonModule } from '@angular/material/button';
export const RETRIEVE_METADATA_OPTION = 'retrieveMetadata'; const RETRIEVE_METADATA_OPTION = 'retrieveMetadata';
export const ALIAS_ROOT_FOLDER = '-root-'; const ALIAS_ROOT_FOLDER = '-root-';
export const ALIAS_USER_FOLDER = '-my-'; const ALIAS_USER_FOLDER = '-my-';
export const APP_NAME = '-appname-'; const APP_NAME = '-appname-';
export const VALID_ALIAS = [ALIAS_ROOT_FOLDER, ALIAS_USER_FOLDER, '-shared-']; const VALID_ALIAS = [ALIAS_ROOT_FOLDER, ALIAS_USER_FOLDER, '-shared-'];
@Component({ @Component({
selector: 'adf-cloud-attach-file-cloud-widget', selector: 'adf-cloud-attach-file-cloud-widget',
standalone: true,
imports: [CommonModule, ErrorWidgetComponent, TranslateModule, MatIconModule, FilePropertiesTableCloudComponent, MatButtonModule],
templateUrl: './attach-file-cloud-widget.component.html', templateUrl: './attach-file-cloud-widget.component.html',
styleUrls: ['./attach-file-cloud-widget.component.scss'], styleUrls: ['./attach-file-cloud-widget.component.scss'],
host: { host: {
@ -66,6 +71,12 @@ export const VALID_ALIAS = [ALIAS_ROOT_FOLDER, ALIAS_USER_FOLDER, '-shared-'];
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit, OnDestroy { export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent implements OnInit, OnDestroy {
private contentNodeSelectorService = inject(ContentCloudNodeSelectorService);
private appConfigService = inject(AppConfigService);
private apiService = inject(AlfrescoApiService);
private contentNodeSelectorPanelService = inject(ContentNodeSelectorPanelService);
private newVersionUploaderService = inject(NewVersionUploaderService);
typeId = 'AttachFileCloudWidgetComponent'; typeId = 'AttachFileCloudWidgetComponent';
rootNodeId = ALIAS_USER_FOLDER; rootNodeId = ALIAS_USER_FOLDER;
selectedNode: Node; selectedNode: Node;
@ -81,18 +92,8 @@ export class AttachFileCloudWidgetComponent extends UploadCloudWidgetComponent i
} }
displayedColumns = ['icon', 'fileName', 'action']; displayedColumns = ['icon', 'fileName', 'action'];
constructor( constructor(formService: FormService) {
formService: FormService, super(formService);
thumbnails: ThumbnailService,
processCloudContentService: ProcessCloudContentService,
notificationService: NotificationService,
private contentNodeSelectorService: ContentCloudNodeSelectorService,
private appConfigService: AppConfigService,
private apiService: AlfrescoApiService,
private contentNodeSelectorPanelService: ContentNodeSelectorPanelService,
private newVersionUploaderService: NewVersionUploaderService
) {
super(formService, thumbnails, processCloudContentService, notificationService);
} }
ngOnInit() { ngOnInit() {

View File

@ -29,16 +29,12 @@
</td> </td>
</ng-container> </ng-container>
<ng-container *ngFor="let columnName of field?.params?.displayableCMProperties" <ng-container *ngFor="let prop of field?.params?.displayableCMProperties" [matColumnDef]="prop.name">
[matColumnDef]="columnName.name"> <th mat-header-cell *matHeaderCellDef>{{prop.title ? prop.title : prop.name | titlecase }}</th>
<th mat-header-cell *matHeaderCellDef>{{
columnName.title ? columnName.title : columnName.name | titlecase
}}
</th>
<td mat-cell class="adf-file-properties-table-cell" *matCellDef="let row"> <td mat-cell class="adf-file-properties-table-cell" *matCellDef="let row">
<span matLine id="{{'fileProperty-'+row?.id+'-'+columnName?.name}}" role="button" tabindex="0" <span matLine id="{{'fileProperty-'+row?.id+'-'+prop?.name}}" role="button" tabindex="0"
(keyup.enter)="onRowClicked(row)" (keyup.enter)="onRowClicked(row)"
(click)="onRowClicked(row)">{{ getColumnValue(row, columnName) }}</span> (click)="onRowClicked(row)">{{ getColumnValue(row, prop) }}</span>
</td> </td>
</ng-container> </ng-container>
@ -89,6 +85,5 @@
</ng-container> </ng-container>
<tr mat-header-row class="adf-file-properties-table-header-row" *matHeaderRowDef="displayedColumns"></tr> <tr mat-header-row class="adf-file-properties-table-header-row" *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table> </table>
</div> </div>

View File

@ -17,21 +17,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../../testing/process-service-cloud.testing.module';
import { FilePropertiesTableCloudComponent } from './file-properties-table-cloud.component'; import { FilePropertiesTableCloudComponent } from './file-properties-table-cloud.component';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { MatTableModule } from '@angular/material/table';
import { MatIconModule } from '@angular/material/icon';
describe('FilePropertiesTableCloudComponent', () => { describe('FilePropertiesTableCloudComponent', () => {
let widget: FilePropertiesTableCloudComponent; let widget: FilePropertiesTableCloudComponent;
let fixture: ComponentFixture<FilePropertiesTableCloudComponent>; let fixture: ComponentFixture<FilePropertiesTableCloudComponent>;
beforeEach(async () => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule, MatTableModule, MatIconModule], imports: [ProcessServiceCloudTestingModule, FilePropertiesTableCloudComponent]
declarations: [FilePropertiesTableCloudComponent] });
}).compileComponents();
}); });
beforeEach(() => { beforeEach(() => {

View File

@ -17,19 +17,43 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, inject, Input, Output } from '@angular/core';
import { LocalizedDatePipe, ThumbnailService } from '@alfresco/adf-core'; import { LocalizedDatePipe, ThumbnailService, UploadDirective, DisplayableCMProperties } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { NewVersionUploaderDialogData } from '@alfresco/adf-content-services'; import { NewVersionUploaderDialogData } from '@alfresco/adf-content-services';
import { CommonModule } from '@angular/common';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
import { MatMenuModule } from '@angular/material/menu';
import { MatButtonModule } from '@angular/material/button';
import { MatTableModule } from '@angular/material/table';
import { MatLineModule } from '@angular/material/core';
import { MatListModule } from '@angular/material/list';
export const RETRIEVE_METADATA_OPTION = 'retrieveMetadata'; const RETRIEVE_METADATA_OPTION = 'retrieveMetadata';
@Component({ @Component({
selector: 'adf-cloud-file-properties-table', selector: 'adf-cloud-file-properties-table',
standalone: true,
imports: [
CommonModule,
MatIconModule,
TranslateModule,
MatMenuModule,
UploadDirective,
MatButtonModule,
MatTableModule,
MatLineModule,
MatListModule
],
providers: [LocalizedDatePipe],
templateUrl: './file-properties-table-cloud.component.html', templateUrl: './file-properties-table-cloud.component.html',
styleUrls: ['./file-properties-table-cloud.component.scss'] styleUrls: ['./file-properties-table-cloud.component.scss']
}) })
export class FilePropertiesTableCloudComponent { export class FilePropertiesTableCloudComponent {
private localizedDatePipe = inject(LocalizedDatePipe);
private thumbnailService = inject(ThumbnailService);
@Input() @Input()
uploadedFiles; uploadedFiles;
@ -61,12 +85,10 @@ export class FilePropertiesTableCloudComponent {
uploadNewFileVersion = new EventEmitter<NewVersionUploaderDialogData>(); uploadNewFileVersion = new EventEmitter<NewVersionUploaderDialogData>();
@Output() @Output()
contentModelFileHandler: EventEmitter<any> = new EventEmitter<Node>(); contentModelFileHandler = new EventEmitter<Node>();
@Output() @Output()
removeAttachFile: EventEmitter<any> = new EventEmitter<any>(); removeAttachFile = new EventEmitter<Node>();
constructor(private localizedDatePipe: LocalizedDatePipe, private thumbnailService: ThumbnailService) {}
onRowClicked(file?: Node) { onRowClicked(file?: Node) {
this.rowClick.emit(file); this.rowClick.emit(file);
@ -90,11 +112,11 @@ export class FilePropertiesTableCloudComponent {
this.uploadNewFileVersion.emit(newVersionUploaderDialogData); this.uploadNewFileVersion.emit(newVersionUploaderDialogData);
} }
contentModelFormFileHandler(file?: any) { contentModelFormFileHandler(file?: Node) {
this.contentModelFileHandler.emit(file); this.contentModelFileHandler.emit(file);
} }
onRemoveAttachFile(file: any) { onRemoveAttachFile(file: Node) {
this.removeAttachFile.emit(file); this.removeAttachFile.emit(file);
} }
@ -102,17 +124,15 @@ export class FilePropertiesTableCloudComponent {
return this.thumbnailService.getMimeTypeIcon(mimeType); return this.thumbnailService.getMimeTypeIcon(mimeType);
} }
getColumnValue(file, displayableCMProperty): string { getColumnValue(file, prop: DisplayableCMProperties): string {
if (!file.properties[displayableCMProperty.prefixedName]) { if (!file.properties[prop.prefixedName]) {
const fieldProperty = this.field.params.displayableCMProperties?.find((property) => property.name === displayableCMProperty.name); const fieldProperty = this.field.params.displayableCMProperties?.find((property) => property.name === prop.name);
return fieldProperty.defaultValue ? this.checkDateTypeAndTransform(displayableCMProperty.dataType, fieldProperty.defaultValue) : '--'; return fieldProperty.defaultValue ? this.checkDateTypeAndTransform(prop.dataType, fieldProperty.defaultValue) : '--';
} }
return file.properties[displayableCMProperty.prefixedName] return file.properties[prop.prefixedName] ? this.checkDateTypeAndTransform(prop.dataType, file.properties[prop.prefixedName]) : '--';
? this.checkDateTypeAndTransform(displayableCMProperty.dataType, file.properties[displayableCMProperty.prefixedName])
: '--';
} }
checkDateTypeAndTransform(dataType, value): string { private checkDateTypeAndTransform(dataType: string, value: any): string {
if (dataType === 'd:date') { if (dataType === 'd:date') {
return this.localizedDatePipe.transform(value); return this.localizedDatePipe.transform(value);
} else if (dataType === 'd:datetime') { } else if (dataType === 'd:datetime') {

View File

@ -81,7 +81,7 @@ describe('DisplayRichTextWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CoreTestingModule] imports: [CoreTestingModule, DisplayRichTextWidgetComponent]
}); });
fixture = TestBed.createComponent(DisplayRichTextWidgetComponent); fixture = TestBed.createComponent(DisplayRichTextWidgetComponent);
widget = fixture.componentInstance; widget = fixture.componentInstance;
@ -89,11 +89,6 @@ describe('DisplayRichTextWidgetComponent', () => {
widget.field = fakeFormField; widget.field = fakeFormField;
}); });
it('should create', () => {
fixture.detectChanges();
expect(widget).toBeTruthy();
});
it('should parse editorjs data to html', async () => { it('should parse editorjs data to html', async () => {
const expectedHtml = const expectedHtml =
'<h1>Editor.js</h1><p class="ce-tune-alignment--left">Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>'; '<h1>Editor.js</h1><p class="ce-tune-alignment--left">Display some <font color="#ff1300">formatted</font> <mark class="cdx-marker">text</mark></p>';

View File

@ -24,6 +24,7 @@ import { DomSanitizer } from '@angular/platform-browser';
@Component({ @Component({
selector: 'display-rich-text', selector: 'display-rich-text',
standalone: true,
templateUrl: './display-rich-text.widget.html', templateUrl: './display-rich-text.widget.html',
styleUrls: ['./display-rich-text.widget.scss'], styleUrls: ['./display-rich-text.widget.scss'],
host: { host: {

View File

@ -15,11 +15,9 @@
* limitations under the License. * limitations under the License.
*/ */
import { TranslateModule } from '@ngx-translate/core';
import { FileViewerWidgetComponent } from './file-viewer.widget'; import { FileViewerWidgetComponent } from './file-viewer.widget';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { FormModel, FormService, FormFieldModel } from '@alfresco/adf-core'; import { FormFieldModel, FormModel, FormService, NoopAuthModule, NoopTranslateModule } from '@alfresco/adf-core';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
describe('FileViewerWidgetComponent', () => { describe('FileViewerWidgetComponent', () => {
const fakeForm = new FormModel(); const fakeForm = new FormModel();
@ -44,10 +42,8 @@ describe('FileViewerWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [TranslateModule.forRoot()], imports: [NoopTranslateModule, NoopAuthModule, FileViewerWidgetComponent],
declarations: [FileViewerWidgetComponent], providers: [{ provide: FormService, useValue: formServiceStub }]
providers: [{ provide: FormService, useValue: formServiceStub }],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
formServiceStub = TestBed.inject(FormService); formServiceStub = TestBed.inject(FormService);
@ -55,27 +51,21 @@ describe('FileViewerWidgetComponent', () => {
widget = fixture.componentInstance; widget = fixture.componentInstance;
}); });
it('should set the file id corretly when the field value is an array', (done) => { it('should set the file id corretly when the field value is an array', async () => {
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: [fakePngAnswer] }); widget.field = new FormFieldModel(fakeForm, { id: 'fakeField', value: [fakePngAnswer] });
widget.field = fakeField;
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
fixture.whenStable().then(() => { expect(widget.field.value).toBe('1933');
expect(widget.field.value).toBe('1933');
done();
});
}); });
it('should set the file id corretly when the field value is a string', (done) => { it('should set the file id corretly when the field value is a string', async () => {
const fakeField = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' }); widget.field = new FormFieldModel(fakeForm, { id: 'fakeField', value: 'fakeValue' });
widget.field = fakeField;
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
fixture.whenStable().then(() => { expect(widget.field.value).toBe('fakeValue');
expect(widget.field.value).toBe('fakeValue');
done();
});
}); });
}); });

View File

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

View File

@ -18,8 +18,9 @@
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id" label>{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label> <label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id" label>{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label>
</adf-cloud-group> </adf-cloud-group>
<error-widget [error]="field.validationSummary" /> <error-widget [error]="field.validationSummary" />
<error-widget class="adf-dropdown-required-message" *ngIf="isInvalidFieldRequired() && isTouched()" <error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" /> class="adf-dropdown-required-message" *ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div> </div>
</div> </div>

View File

@ -19,7 +19,6 @@ import { FormFieldModel, FormFieldTypes, FormModel, IdentityGroupModel } from '@
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GroupCloudWidgetComponent } from './group-cloud.widget'; import { GroupCloudWidgetComponent } from './group-cloud.widget';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatChipHarness } from '@angular/material/chips/testing'; import { MatChipHarness } from '@angular/material/chips/testing';
@ -32,9 +31,7 @@ describe('GroupCloudWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, GroupCloudWidgetComponent]
declarations: [GroupCloudWidgetComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
fixture = TestBed.createComponent(GroupCloudWidgetComponent); fixture = TestBed.createComponent(GroupCloudWidgetComponent);
widget = fixture.componentInstance; widget = fixture.componentInstance;

View File

@ -16,17 +16,22 @@
*/ */
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormService, WidgetComponent } from '@alfresco/adf-core'; import { ErrorWidgetComponent, FormService, WidgetComponent } from '@alfresco/adf-core';
import { UntypedFormControl } from '@angular/forms'; import { UntypedFormControl } from '@angular/forms';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { ComponentSelectionMode } from '../../../../types'; import { ComponentSelectionMode } from '../../../../types';
import { IdentityGroupModel } from '../../../../group/models/identity-group.model'; import { IdentityGroupModel } from '../../../../group/models/identity-group.model';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { GroupCloudModule } from '../../../../group/group-cloud.module';
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
@Component({ @Component({
selector: 'group-cloud-widget', selector: 'group-cloud-widget',
standalone: true,
imports: [CommonModule, TranslateModule, ErrorWidgetComponent, GroupCloudModule],
templateUrl: './group-cloud.widget.html', templateUrl: './group-cloud.widget.html',
host: { host: {
'(click)': 'event($event)', '(click)': 'event($event)',
@ -42,7 +47,6 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class GroupCloudWidgetComponent extends WidgetComponent implements OnInit { export class GroupCloudWidgetComponent extends WidgetComponent implements OnInit {
typeId = 'GroupCloudWidgetComponent'; typeId = 'GroupCloudWidgetComponent';
roles: string[]; roles: string[];
mode: ComponentSelectionMode; mode: ComponentSelectionMode;
@ -65,9 +69,7 @@ export class GroupCloudWidgetComponent extends WidgetComponent implements OnInit
this.preSelectGroup = this.field.value ? this.field.value : []; this.preSelectGroup = this.field.value ? this.field.value : [];
this.validate = this.field.readOnly ? false : true; this.validate = this.field.readOnly ? false : true;
} }
// eslint-disable-next-line @typescript-eslint/no-unused-expressions this.search = new UntypedFormControl({ value: '', disabled: this.field.readOnly }, []);
this.search = new UntypedFormControl({value: '', disabled: this.field.readOnly}, []),
this.search.statusChanges this.search.statusChanges
.pipe( .pipe(
filter((value: string) => value === 'INVALID'), filter((value: string) => value === 'INVALID'),

View File

@ -1,5 +1,7 @@
<div class="adf-dropdown-widget {{field.className}}" <div class="adf-dropdown-widget {{field.className}}"
[class.adf-invalid]="!field.isValid && isTouched()" [class.adf-readonly]="field.readOnly" [class.adf-left-label-input-container]="field.leftLabels"> [class.adf-invalid]="!field.isValid && isTouched()"
[class.adf-readonly]="field.readOnly"
[class.adf-left-label-input-container]="field.leftLabels">
<div *ngIf="field.leftLabels"> <div *ngIf="field.leftLabels">
<label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label> <label class="adf-label adf-left-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label>
</div> </div>
@ -18,11 +20,16 @@
(blur)="markAsTouched()" (blur)="markAsTouched()"
[attr.title]="field.tooltip" [attr.title]="field.tooltip"
> >
<label class="adf-label" *ngIf="!field.leftLabels" [attr.for]="field.id" label>{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label> <label class="adf-label"
*ngIf="!field.leftLabels"
[attr.for]="field.id" label
>{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label>
</adf-cloud-people> </adf-cloud-people>
<error-widget [error]="field.validationSummary" /> <error-widget [error]="field.validationSummary" />
<error-widget class="adf-dropdown-required-message" *ngIf="isInvalidFieldRequired() && isTouched()" <error-widget
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" /> class="adf-dropdown-required-message"
*ngIf="isInvalidFieldRequired() && isTouched()"
required="{{ 'FORM.FIELD.REQUIRED' | translate }}" />
</div> </div>
</div> </div>

View File

@ -18,7 +18,6 @@
import { FormFieldModel, FormFieldTypes, FormModel, IdentityUserModel } from '@alfresco/adf-core'; import { FormFieldModel, FormFieldTypes, FormModel, IdentityUserModel } from '@alfresco/adf-core';
import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PeopleCloudWidgetComponent } from './people-cloud.widget'; import { PeopleCloudWidgetComponent } from './people-cloud.widget';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { IdentityUserService } from '../../../../people/services/identity-user.service';
import { mockShepherdsPie, mockYorkshirePudding } from '../../../../people/mock/people-cloud.mock'; import { mockShepherdsPie, mockYorkshirePudding } from '../../../../people/mock/people-cloud.mock';
@ -35,9 +34,7 @@ describe('PeopleCloudWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, PeopleCloudWidgetComponent]
declarations: [PeopleCloudWidgetComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}); });
identityUserService = TestBed.inject(IdentityUserService); identityUserService = TestBed.inject(IdentityUserService);
fixture = TestBed.createComponent(PeopleCloudWidgetComponent); fixture = TestBed.createComponent(PeopleCloudWidgetComponent);

View File

@ -16,18 +16,23 @@
*/ */
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { FormService, WidgetComponent } from '@alfresco/adf-core'; import { ErrorWidgetComponent, FormService, WidgetComponent } from '@alfresco/adf-core';
import { UntypedFormControl } from '@angular/forms'; import { UntypedFormControl } from '@angular/forms';
import { filter } from 'rxjs/operators'; import { filter } from 'rxjs/operators';
import { ComponentSelectionMode } from '../../../../types'; import { ComponentSelectionMode } from '../../../../types';
import { IdentityUserModel } from '../../../../people/models/identity-user.model'; import { IdentityUserModel } from '../../../../people/models/identity-user.model';
import { IdentityUserService } from '../../../../people/services/identity-user.service'; import { IdentityUserService } from '../../../../people/services/identity-user.service';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { PeopleCloudModule } from '../../../../people/people-cloud.module';
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
@Component({ @Component({
selector: 'people-cloud-widget', selector: 'people-cloud-widget',
standalone: true,
imports: [CommonModule, TranslateModule, ErrorWidgetComponent, PeopleCloudModule],
templateUrl: './people-cloud.widget.html', templateUrl: './people-cloud.widget.html',
host: { host: {
'(click)': 'event($event)', '(click)': 'event($event)',
@ -43,6 +48,7 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class PeopleCloudWidgetComponent extends WidgetComponent implements OnInit { export class PeopleCloudWidgetComponent extends WidgetComponent implements OnInit {
private identityUserService = inject(IdentityUserService);
typeId = 'PeopleCloudWidgetComponent'; typeId = 'PeopleCloudWidgetComponent';
appName: string; appName: string;
@ -56,7 +62,7 @@ export class PeopleCloudWidgetComponent extends WidgetComponent implements OnIni
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor(formService: FormService, private identityUserService: IdentityUserService) { constructor(formService: FormService) {
super(formService); super(formService);
} }
@ -70,7 +76,7 @@ export class PeopleCloudWidgetComponent extends WidgetComponent implements OnIni
this.validate = this.field.readOnly ? false : true; this.validate = this.field.readOnly ? false : true;
} }
this.search = new UntypedFormControl({value: '', disabled: this.field.readOnly}, []); this.search = new UntypedFormControl({ value: '', disabled: this.field.readOnly }, []);
this.search.statusChanges this.search.statusChanges
.pipe( .pipe(
@ -94,7 +100,7 @@ export class PeopleCloudWidgetComponent extends WidgetComponent implements OnIni
if (this.field.selectLoggedUser && !this.field.value) { if (this.field.selectLoggedUser && !this.field.value) {
const userInfo = this.identityUserService.getCurrentUserInfo(); const userInfo = this.identityUserService.getCurrentUserInfo();
this.preSelectUsers = [ userInfo ]; this.preSelectUsers = [userInfo];
this.onChangedUser(this.preSelectUsers); this.onChangedUser(this.preSelectUsers);
} }
} }

View File

@ -16,13 +16,17 @@
*/ */
import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewEncapsulation } from '@angular/core';
import { PresetConfig, NodesApiService } from '@alfresco/adf-content-services'; import { PresetConfig, NodesApiService, ContentMetadataComponent } from '@alfresco/adf-content-services';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { CommonModule } from '@angular/common';
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
@Component({ @Component({
selector: 'adf-properties-viewer-wrapper', selector: 'adf-properties-viewer-wrapper',
standalone: true,
imports: [CommonModule, MatProgressSpinnerModule, ContentMetadataComponent],
templateUrl: './properties-viewer-wrapper.component.html', templateUrl: './properties-viewer-wrapper.component.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })

View File

@ -29,7 +29,7 @@ describe('PropertiesViewerWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, PropertiesViewerWrapperComponent],
providers: [NodesApiService, { provide: BasicPropertiesService, useValue: { getProperties: () => [] } }] providers: [NodesApiService, { provide: BasicPropertiesService, useValue: { getProperties: () => [] } }]
}); });
fixture = TestBed.createComponent(PropertiesViewerWrapperComponent); fixture = TestBed.createComponent(PropertiesViewerWrapperComponent);

View File

@ -20,7 +20,6 @@ import { FormFieldModel, FormModel } from '@alfresco/adf-core';
import { PropertiesViewerWidgetComponent } from './properties-viewer.widget'; import { PropertiesViewerWidgetComponent } from './properties-viewer.widget';
import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from '../../../../testing/process-service-cloud.testing.module';
import { fakeNodeWithProperties } from '../../../mocks/attach-file-cloud-widget.mock'; import { fakeNodeWithProperties } from '../../../mocks/attach-file-cloud-widget.mock';
import { PropertiesViewerWrapperComponent } from './properties-viewer-wrapper/properties-viewer-wrapper.component';
import { NodesApiService, BasicPropertiesService } from '@alfresco/adf-content-services'; import { NodesApiService, BasicPropertiesService } from '@alfresco/adf-content-services';
import { of } from 'rxjs'; import { of } from 'rxjs';
@ -47,8 +46,7 @@ describe('PropertiesViewerWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, PropertiesViewerWidgetComponent],
declarations: [PropertiesViewerWrapperComponent],
providers: [NodesApiService, { provide: BasicPropertiesService, useValue: { getProperties: () => [] } }] providers: [NodesApiService, { provide: BasicPropertiesService, useValue: { getProperties: () => [] } }]
}); });
fixture = TestBed.createComponent(PropertiesViewerWidgetComponent); fixture = TestBed.createComponent(PropertiesViewerWidgetComponent);

View File

@ -16,13 +16,18 @@
*/ */
import { Component, EventEmitter, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Output, ViewEncapsulation } from '@angular/core';
import { BaseViewerWidgetComponent, FormService } from '@alfresco/adf-core'; import { BaseViewerWidgetComponent, ErrorWidgetComponent, FormService } from '@alfresco/adf-core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { PropertiesViewerWrapperComponent } from './properties-viewer-wrapper/properties-viewer-wrapper.component';
import { TranslateModule } from '@ngx-translate/core';
import { CommonModule } from '@angular/common';
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
@Component({ @Component({
selector: 'adf-properties-viewer-widget', selector: 'adf-properties-viewer-widget',
standalone: true,
imports: [CommonModule, ErrorWidgetComponent, PropertiesViewerWrapperComponent, TranslateModule],
templateUrl: './properties-viewer.widget.html', templateUrl: './properties-viewer.widget.html',
styleUrls: ['./properties-viewer.widget.scss'], styleUrls: ['./properties-viewer.widget.scss'],
host: { host: {
@ -39,7 +44,6 @@ import { Node } from '@alfresco/js-api';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class PropertiesViewerWidgetComponent extends BaseViewerWidgetComponent { export class PropertiesViewerWidgetComponent extends BaseViewerWidgetComponent {
@Output() @Output()
nodeContentLoaded: EventEmitter<Node> = new EventEmitter(); nodeContentLoaded: EventEmitter<Node> = new EventEmitter();

View File

@ -1,19 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export * from './radio-buttons-cloud.schema';
export * from './radio-buttons-cloud.widget';

View File

@ -1,8 +1,14 @@
<div class="adf-radio-buttons-widget-cloud {{field.className}}" <div class="adf-radio-buttons-widget-cloud {{field.className}}"
[class.adf-readonly]="field.readOnly" [id]="field.id"> [class.adf-readonly]="field.readOnly" [id]="field.id">
<div [ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-button-container': 'adf-radio-button-container-horizontal'"> <div [ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-button-container': 'adf-radio-button-container-horizontal'">
<label class="adf-label" [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span></label> <label class="adf-label"
<mat-radio-group [ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-group': 'adf-radio-group-horizontal'" class="adf-radio-group" [(ngModel)]="field.value" [disabled]="field.readOnly"> [attr.for]="field.id">{{field.name | translate }}<span class="adf-asterisk" *ngIf="isRequired()">*</span>
</label>
<mat-radio-group
[ngClass]="(field.alignmentType === 'vertical') ? 'adf-radio-group': 'adf-radio-group-horizontal'"
class="adf-radio-group"
[(ngModel)]="field.value"
[disabled]="field.readOnly">
<mat-radio-button <mat-radio-button
[title]="field.tooltip" [title]="field.tooltip"
[id]="field.id + '-' + opt.id" [id]="field.id + '-' + opt.id"

View File

@ -46,7 +46,7 @@ describe('RadioButtonsCloudWidgetComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule] imports: [ProcessServiceCloudTestingModule, RadioButtonsCloudWidgetComponent]
}); });
formCloudService = TestBed.inject(FormCloudService); formCloudService = TestBed.inject(FormCloudService);
formUtilsService = TestBed.inject(FormUtilsService); formUtilsService = TestBed.inject(FormUtilsService);

View File

@ -18,14 +18,19 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, DestroyRef, inject, OnInit, ViewEncapsulation } from '@angular/core';
import { ErrorMessageModel, FormFieldOption, FormService, WidgetComponent } from '@alfresco/adf-core'; import { ErrorMessageModel, ErrorWidgetComponent, FormFieldOption, FormService, WidgetComponent } from '@alfresco/adf-core';
import { FormCloudService } from '../../../services/form-cloud.service'; import { FormCloudService } from '../../../services/form-cloud.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateModule, TranslateService } from '@ngx-translate/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormUtilsService } from '../../../services/form-utils.service'; import { FormUtilsService } from '../../../services/form-utils.service';
import { MatRadioModule } from '@angular/material/radio';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({ @Component({
selector: 'radio-buttons-cloud-widget', selector: 'radio-buttons-cloud-widget',
standalone: true,
imports: [CommonModule, ErrorWidgetComponent, MatRadioModule, TranslateModule, FormsModule],
templateUrl: './radio-buttons-cloud.widget.html', templateUrl: './radio-buttons-cloud.widget.html',
styleUrls: ['./radio-buttons-cloud.widget.scss'], styleUrls: ['./radio-buttons-cloud.widget.scss'],
host: { host: {
@ -42,17 +47,16 @@ import { FormUtilsService } from '../../../services/form-utils.service';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements OnInit { export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements OnInit {
private formCloudService = inject(FormCloudService);
private translateService = inject(TranslateService);
private formUtilsService = inject(FormUtilsService);
typeId = 'RadioButtonsCloudWidgetComponent'; typeId = 'RadioButtonsCloudWidgetComponent';
restApiError: ErrorMessageModel; restApiError: ErrorMessageModel;
private readonly destroyRef = inject(DestroyRef); private readonly destroyRef = inject(DestroyRef);
constructor( constructor(formService: FormService) {
public formService: FormService,
private readonly formCloudService: FormCloudService,
private readonly translateService: TranslateService,
private readonly formUtilsService: FormUtilsService
) {
super(formService); super(formService);
} }
@ -68,16 +72,16 @@ export class RadioButtonsCloudWidgetComponent extends WidgetComponent implements
this.formCloudService this.formCloudService
.getRestWidgetData(this.field.form.id, this.field.id, body) .getRestWidgetData(this.field.form.id, this.field.id, body)
.pipe(takeUntilDestroyed(this.destroyRef)) .pipe(takeUntilDestroyed(this.destroyRef))
.subscribe( .subscribe({
(result: FormFieldOption[]) => { next: (result) => {
this.field.options = result; this.field.options = result;
this.field.updateForm(); this.field.updateForm();
}, },
(err) => { error: (err) => {
this.resetRestApiOptions(); this.resetRestApiOptions();
this.handleError(err); this.handleError(err);
} }
); });
} }
onOptionClick(optionSelected: any) { onOptionClick(optionSelected: any) {

View File

@ -9,8 +9,8 @@
<img matListItemLine class="adf-upload-widget__icon" [id]="'file-'+file.id+'-icon'" <img matListItemLine class="adf-upload-widget__icon" [id]="'file-'+file.id+'-icon'"
[src]="getIcon(file.content.mimeType)" [alt]="mimeTypeIcon" (click)="fileClicked(file)" [src]="getIcon(file.content.mimeType)" [alt]="mimeTypeIcon" (click)="fileClicked(file)"
(keyup.enter)="fileClicked(file)" role="button" tabindex="0" /> (keyup.enter)="fileClicked(file)" role="button" tabindex="0" />
<span class="adf-upload-widget__button" matLine id="{{'file-'+file.id}}" (click)="fileClicked(file)" (keyup.enter)="fileClicked(file)" <span class="adf-upload-widget__button adf-file" matLine id="{{'file-'+file.id}}" (click)="fileClicked(file)" (keyup.enter)="fileClicked(file)"
role="button" tabindex="0" class="adf-file">{{file.name}}</span> role="button" tabindex="0">{{file.name}}</span>
<button *ngIf="!field.readOnly" mat-icon-button [id]="'file-'+file.id+'-remove'" <button *ngIf="!field.readOnly" mat-icon-button [id]="'file-'+file.id+'-remove'"
(click)="removeFile(file);" (keyup.enter)="removeFile(file);"> (click)="removeFile(file);" (keyup.enter)="removeFile(file);">
<mat-icon class="mat-24">highlight_off</mat-icon> <mat-icon class="mat-24">highlight_off</mat-icon>

View File

@ -17,17 +17,25 @@
/* eslint-disable @angular-eslint/component-selector */ /* eslint-disable @angular-eslint/component-selector */
import { Component, ElementRef, EventEmitter, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, EventEmitter, inject, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { Observable, from } from 'rxjs'; import { Observable, from } from 'rxjs';
import { mergeMap } from 'rxjs/operators'; import { mergeMap } from 'rxjs/operators';
import { WidgetComponent, FormService, ThumbnailService, NotificationService } from '@alfresco/adf-core'; import { WidgetComponent, FormService, ThumbnailService, NotificationService, ErrorWidgetComponent } from '@alfresco/adf-core';
import { ProcessCloudContentService } from '../../../services/process-cloud-content.service'; import { ProcessCloudContentService } from '../../../services/process-cloud-content.service';
import { FileSourceTypes, DestinationFolderPathType } from '../../../models/form-cloud-representation.model'; import { FileSourceTypes, DestinationFolderPathType } from '../../../models/form-cloud-representation.model';
import { VersionManagerUploadData } from '@alfresco/adf-content-services'; import { VersionManagerUploadData } from '@alfresco/adf-content-services';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
import { MatListModule } from '@angular/material/list';
import { MatLineModule } from '@angular/material/core';
@Component({ @Component({
selector: 'upload-cloud-widget', selector: 'upload-cloud-widget',
standalone: true,
imports: [CommonModule, TranslateModule, ErrorWidgetComponent, MatIconModule, MatButtonModule, MatListModule, MatLineModule],
templateUrl: './upload-cloud.widget.html', templateUrl: './upload-cloud.widget.html',
styleUrls: ['./upload-cloud.widget.scss'], styleUrls: ['./upload-cloud.widget.scss'],
host: { host: {
@ -44,6 +52,10 @@ import { VersionManagerUploadData } from '@alfresco/adf-content-services';
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class UploadCloudWidgetComponent extends WidgetComponent implements OnInit { export class UploadCloudWidgetComponent extends WidgetComponent implements OnInit {
protected thumbnailService = inject(ThumbnailService);
protected processCloudContentService = inject(ProcessCloudContentService);
protected notificationService = inject(NotificationService);
hasFile: boolean; hasFile: boolean;
displayText: string; displayText: string;
multipleOption: string = ''; multipleOption: string = '';
@ -55,12 +67,7 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
@ViewChild('uploadFiles') @ViewChild('uploadFiles')
fileInput: ElementRef; fileInput: ElementRef;
constructor( constructor(formService: FormService) {
formService: FormService,
private thumbnailService: ThumbnailService,
protected processCloudContentService: ProcessCloudContentService,
protected notificationService: NotificationService
) {
super(formService); super(formService);
} }
@ -101,16 +108,16 @@ export class UploadCloudWidgetComponent extends WidgetComponent implements OnIni
if (files && files.length > 0) { if (files && files.length > 0) {
from(files) from(files)
.pipe(mergeMap((file) => this.uploadRawContent(file))) .pipe(mergeMap((file) => this.uploadRawContent(file)))
.subscribe( .subscribe({
(res) => { next: (res) => {
filesSaved.push(res); filesSaved.push(res);
}, },
(error) => this.widgetError.emit(`Error uploading file. See console output for more details. ${error}`), error: (error) => this.widgetError.emit(`Error uploading file. See console output for more details. ${error}`),
() => { complete: () => {
this.fixIncompatibilityFromPreviousAndNewForm(filesSaved); this.fixIncompatibilityFromPreviousAndNewForm(filesSaved);
this.hasFile = true; this.hasFile = true;
} }
); });
} }
} }

View File

@ -16,86 +16,43 @@
*/ */
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CoreModule, FormatSpacePipe, TOOLBAR_DIRECTIVES, FormStylePipe } from '@alfresco/adf-core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';
import { FormCloudComponent } from './components/form-cloud.component'; import { FormCloudComponent } from './components/form-cloud.component';
import { FormDefinitionSelectorCloudComponent } from './components/form-definition-selector-cloud.component'; import { FormDefinitionSelectorCloudComponent } from './components/form-definition-selector-cloud.component';
import { FormCustomOutcomesComponent } from './components/form-cloud-custom-outcomes.component'; import { FormCustomOutcomesComponent } from './components/form-cloud-custom-outcomes.component';
import {
AlfrescoViewerComponent,
CONTENT_METADATA_DIRECTIVES,
CONTENT_UPLOAD_DIRECTIVES,
ContentNodeSelectorModule
} from '@alfresco/adf-content-services';
import { GroupCloudWidgetComponent } from './components/widgets/group/group-cloud.widget'; import { GroupCloudWidgetComponent } from './components/widgets/group/group-cloud.widget';
import { PeopleCloudWidgetComponent } from './components/widgets/people/people-cloud.widget'; import { PeopleCloudWidgetComponent } from './components/widgets/people/people-cloud.widget';
import { AttachFileCloudWidgetComponent } from './components/widgets/attach-file/attach-file-cloud-widget.component'; import { AttachFileCloudWidgetComponent } from './components/widgets/attach-file/attach-file-cloud-widget.component';
import { UploadCloudWidgetComponent } from './components/widgets/attach-file/upload-cloud.widget'; import { UploadCloudWidgetComponent } from './components/widgets/upload/upload-cloud.widget';
import { PeopleCloudModule } from '../people/people-cloud.module';
import { GroupCloudModule } from '../group/group-cloud.module';
import { PropertiesViewerWidgetComponent } from './components/widgets/properties-viewer/properties-viewer.widget'; import { PropertiesViewerWidgetComponent } from './components/widgets/properties-viewer/properties-viewer.widget';
import { PropertiesViewerWrapperComponent } from './components/widgets/properties-viewer/properties-viewer-wrapper/properties-viewer-wrapper.component'; import { PropertiesViewerWrapperComponent } from './components/widgets/properties-viewer/properties-viewer-wrapper/properties-viewer-wrapper.component';
import { RadioButtonsCloudWidgetComponent } from './components/widgets/radio-buttons/radio-buttons-cloud.widget'; import { RadioButtonsCloudWidgetComponent } from './components/widgets/radio-buttons/radio-buttons-cloud.widget';
import { FilePropertiesTableCloudComponent } from './components/widgets/attach-file/file-properties-table-cloud.component'; import { FilePropertiesTableCloudComponent } from './components/widgets/attach-file/file-properties-table/file-properties-table-cloud.component';
import { FileViewerWidgetComponent } from './components/widgets/file-viewer/file-viewer.widget'; import { FileViewerWidgetComponent } from './components/widgets/file-viewer/file-viewer.widget';
import { DisplayRichTextWidgetComponent } from './components/widgets/display-rich-text/display-rich-text.widget'; import { DisplayRichTextWidgetComponent } from './components/widgets/display-rich-text/display-rich-text.widget';
import { RichTextEditorComponent } from '../rich-text-editor'; import { RichTextEditorComponent } from '../rich-text-editor';
import { A11yModule } from '@angular/cdk/a11y';
import { OverlayModule } from '@angular/cdk/overlay';
import { FormSpinnerComponent } from './components/spinner/form-spinner.component'; import { FormSpinnerComponent } from './components/spinner/form-spinner.component';
import { FormCloudSpinnerService } from './services/spinner/form-cloud-spinner.service';
export const FORM_CLOUD_DIRECTIVES = [
RichTextEditorComponent,
FormSpinnerComponent,
PropertiesViewerWrapperComponent,
PropertiesViewerWidgetComponent,
DisplayRichTextWidgetComponent,
FileViewerWidgetComponent,
FilePropertiesTableCloudComponent,
FormCustomOutcomesComponent,
FormDefinitionSelectorCloudComponent,
RadioButtonsCloudWidgetComponent,
AttachFileCloudWidgetComponent,
UploadCloudWidgetComponent,
PeopleCloudWidgetComponent,
GroupCloudWidgetComponent,
FormCloudComponent
] as const;
/** @deprecated use ...FORM_CLOUD_DIRECTIVES instead */
@NgModule({ @NgModule({
imports: [ imports: [...FORM_CLOUD_DIRECTIVES],
CommonModule, exports: [...FORM_CLOUD_DIRECTIVES]
OverlayModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
CoreModule,
ContentNodeSelectorModule,
PeopleCloudModule,
GroupCloudModule,
RichTextEditorComponent,
...TOOLBAR_DIRECTIVES,
A11yModule,
FormatSpacePipe,
AlfrescoViewerComponent,
...CONTENT_UPLOAD_DIRECTIVES,
...CONTENT_METADATA_DIRECTIVES,
FormStylePipe
],
declarations: [
FormCloudComponent,
UploadCloudWidgetComponent,
FormDefinitionSelectorCloudComponent,
FormCustomOutcomesComponent,
RadioButtonsCloudWidgetComponent,
AttachFileCloudWidgetComponent,
PeopleCloudWidgetComponent,
GroupCloudWidgetComponent,
PropertiesViewerWrapperComponent,
PropertiesViewerWidgetComponent,
FilePropertiesTableCloudComponent,
FileViewerWidgetComponent,
DisplayRichTextWidgetComponent,
FormSpinnerComponent
],
exports: [
FormCloudComponent,
UploadCloudWidgetComponent,
FormDefinitionSelectorCloudComponent,
FormCustomOutcomesComponent,
RadioButtonsCloudWidgetComponent,
AttachFileCloudWidgetComponent,
PeopleCloudWidgetComponent,
GroupCloudWidgetComponent,
PropertiesViewerWidgetComponent,
FileViewerWidgetComponent,
DisplayRichTextWidgetComponent
],
providers: [FormCloudSpinnerService]
}) })
export class FormCloudModule {} export class FormCloudModule {}

View File

@ -1318,99 +1318,3 @@ export const fakeMetadataForm = {
variables: [] variables: []
} }
}; };
export const fakeViewerForm = {
id: 'form-de8895be-d0d7-4434-beef-559b15305d72',
name: 'StartEventForm',
description: '',
version: 0,
formDefinition: {
tabs: [],
fields: [
{
type: 'container',
id: '5a6b24c1-db2b-45e9-9aff-142395433d23',
name: 'Label',
tab: null,
fields: {
1: [
{
id: 'content_form_nodes',
name: 'Nodes',
type: 'upload',
readOnly: false,
required: true,
colspan: 1,
visibilityCondition: null,
params: {
existingColspan: 1,
maxColspan: 2,
fileSource: {
serviceId: 'alfresco-content',
name: 'Alfresco Content',
metadataAllowed: true
},
multiple: true,
menuOptions: {
show: true,
download: true,
retrieveMetadata: true,
remove: true
},
link: false
}
}
],
2: [
{
id: 'upload_widget',
name: 'Nodes',
type: 'upload',
readOnly: false,
required: true,
colspan: 1,
visibilityCondition: null,
params: {
existingColspan: 1,
maxColspan: 2,
fileSource: {
serviceId: 'alfresco-content',
name: 'Alfresco Content',
metadataAllowed: true
},
multiple: true,
menuOptions: {
show: true,
download: true,
retrieveMetadata: true,
remove: true
},
link: false
}
}
],
3: [
{
id: 'cmfb85b2a7295ba41209750bca176ccaf9a',
name: 'File viewer',
type: 'file-viewer',
readOnly: false,
required: false,
colspan: 1,
visibilityCondition: null,
params: {
existingColspan: 1,
maxColspan: 2,
uploadWidget: 'content_form_nodes'
}
}
]
},
numberOfColumns: 2
}
],
outcomes: [],
metadata: {},
variables: []
}
};

View File

@ -17,23 +17,27 @@
export * from './models/task-variable-cloud.model'; export * from './models/task-variable-cloud.model';
export * from './components/spinner/form-spinner.component';
export * from './components/form-cloud-custom-outcomes.component'; export * from './components/form-cloud-custom-outcomes.component';
export * from './components/form-cloud.component'; export * from './components/form-cloud.component';
export * from './components/form-definition-selector-cloud.component'; export * from './components/form-definition-selector-cloud.component';
export * from './components/cloud-form-rendering.service'; export * from './components/cloud-form-rendering.service';
export * from './components/widgets/attach-file/attach-file-cloud-widget.component'; export * from './components/widgets/attach-file/attach-file-cloud-widget.component';
export * from './components/widgets/attach-file/upload-cloud.widget'; export * from './components/widgets/attach-file/file-properties-table/file-properties-table-cloud.component';
export * from './components/widgets/upload/upload-cloud.widget';
export * from './components/widgets/date/date-cloud.widget'; export * from './components/widgets/date/date-cloud.widget';
export * from './components/widgets/dropdown/dropdown-cloud.widget'; export * from './components/widgets/dropdown/dropdown-cloud.widget';
export * from './components/widgets/group/group-cloud.widget'; export * from './components/widgets/group/group-cloud.widget';
export * from './components/widgets/people/people-cloud.widget'; export * from './components/widgets/people/people-cloud.widget';
export * from './components/widgets/properties-viewer/properties-viewer.widget'; export * from './components/widgets/properties-viewer/properties-viewer.widget';
export * from './components/widgets/properties-viewer/properties-viewer-wrapper/properties-viewer-wrapper.component';
export * from './components/widgets/file-viewer/file-viewer.widget'; export * from './components/widgets/file-viewer/file-viewer.widget';
export * from './components/widgets/display-rich-text/display-rich-text.widget'; export * from './components/widgets/display-rich-text/display-rich-text.widget';
// widgets with schema // widgets with schema
export * from './components/widgets/radio-buttons'; export * from './components/widgets/radio-buttons/radio-buttons-cloud.widget';
export * from './components/widgets/radio-buttons/radio-buttons-cloud.schema';
export * from './services/content-cloud-node-selector.service'; export * from './services/content-cloud-node-selector.service';
export * from './services/form-cloud.service'; export * from './services/form-cloud.service';

View File

@ -34,7 +34,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
template: `<div>adf-cloud-overlay-test</div>` template: `<div>adf-cloud-overlay-test</div>`
}) })
class SpinnerTestComponent { class SpinnerTestComponent {
destroyRef = inject(DestroyRef) destroyRef = inject(DestroyRef);
} }
describe('FormCloudSpinnerService', () => { describe('FormCloudSpinnerService', () => {
@ -47,10 +47,10 @@ describe('FormCloudSpinnerService', () => {
const showSpinnerEvent = new FormSpinnerEvent('toggle-spinner', { showSpinner: true, message: 'LOAD_SPINNER_MESSAGE' }); const showSpinnerEvent = new FormSpinnerEvent('toggle-spinner', { showSpinner: true, message: 'LOAD_SPINNER_MESSAGE' });
const hideSpinnerEvent = new FormSpinnerEvent('toggle-spinner', { showSpinner: false }); const hideSpinnerEvent = new FormSpinnerEvent('toggle-spinner', { showSpinner: false });
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [FormSpinnerComponent, SpinnerTestComponent], imports: [OverlayModule, PortalModule, MatProgressSpinnerModule, TranslateModule.forRoot(), FormSpinnerComponent],
declarations: [SpinnerTestComponent],
providers: [ providers: [
FormCloudSpinnerService, FormCloudSpinnerService,
{ {
@ -59,15 +59,14 @@ describe('FormCloudSpinnerService', () => {
toggleFormSpinner: new Subject() toggleFormSpinner: new Subject()
} }
} }
], ]
imports: [OverlayModule, PortalModule, MatProgressSpinnerModule, TranslateModule.forRoot()]
}); });
fixture = TestBed.createComponent(SpinnerTestComponent); fixture = TestBed.createComponent(SpinnerTestComponent);
rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture); rootLoader = TestbedHarnessEnvironment.documentRootLoader(fixture);
spinnerService = TestBed.inject(FormCloudSpinnerService); spinnerService = TestBed.inject(FormCloudSpinnerService);
formService = TestBed.inject(FormService); formService = TestBed.inject(FormService);
destroyRef = fixture.componentInstance.destroyRef destroyRef = fixture.componentInstance.destroyRef;
}); });
it('should toggle spinner', async () => { it('should toggle spinner', async () => {

View File

@ -21,7 +21,7 @@ import { APP_LIST_CLOUD_DIRECTIVES } from './app/app-list-cloud.module';
import { TaskCloudModule } from './task/task-cloud.module'; import { TaskCloudModule } from './task/task-cloud.module';
import { ProcessCloudModule } from './process/process-cloud.module'; import { ProcessCloudModule } from './process/process-cloud.module';
import { GroupCloudModule } from './group/group-cloud.module'; import { GroupCloudModule } from './group/group-cloud.module';
import { FormCloudModule } from './form/form-cloud.module'; import { FORM_CLOUD_DIRECTIVES } from './form/form-cloud.module';
import { TaskFormModule } from './task/task-form/task-form.module'; import { TaskFormModule } from './task/task-form/task-form.module';
import { import {
LocalPreferenceCloudService, LocalPreferenceCloudService,
@ -44,7 +44,7 @@ import { RichTextEditorComponent } from './rich-text-editor';
TaskCloudModule, TaskCloudModule,
GroupCloudModule, GroupCloudModule,
PeopleCloudModule, PeopleCloudModule,
FormCloudModule, ...FORM_CLOUD_DIRECTIVES,
TaskFormModule, TaskFormModule,
ApolloModule, ApolloModule,
RichTextEditorComponent RichTextEditorComponent
@ -55,7 +55,7 @@ import { RichTextEditorComponent } from './rich-text-editor';
ProcessCloudModule, ProcessCloudModule,
TaskCloudModule, TaskCloudModule,
GroupCloudModule, GroupCloudModule,
FormCloudModule, ...FORM_CLOUD_DIRECTIVES,
TaskFormModule, TaskFormModule,
PeopleCloudModule, PeopleCloudModule,
RichTextEditorComponent RichTextEditorComponent

View File

@ -18,13 +18,12 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { ProcessFiltersCloudModule } from './process-filters/process-filters-cloud.module'; import { ProcessFiltersCloudModule } from './process-filters/process-filters-cloud.module';
import { ProcessListCloudModule } from './process-list/process-list-cloud.module'; import { ProcessListCloudModule } from './process-list/process-list-cloud.module';
import { CoreModule, LocalizedDatePipe } from '@alfresco/adf-core'; import { CoreModule } from '@alfresco/adf-core';
import { StartProcessCloudComponent } from './start-process/components/start-process-cloud.component'; import { StartProcessCloudComponent } from './start-process/components/start-process-cloud.component';
import { ProcessHeaderCloudComponent } from './process-header/components/process-header-cloud.component'; import { ProcessHeaderCloudComponent } from './process-header/components/process-header-cloud.component';
@NgModule({ @NgModule({
imports: [CoreModule, ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent], imports: [CoreModule, ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent],
exports: [ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent], exports: [ProcessFiltersCloudModule, ProcessListCloudModule, StartProcessCloudComponent, ProcessHeaderCloudComponent]
providers: [LocalizedDatePipe]
}) })
export class ProcessCloudModule {} export class ProcessCloudModule {}

View File

@ -24,17 +24,14 @@ import { LocalPreferenceCloudService } from '../../services/local-preference-clo
import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../services/cloud-token.service'; import { PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN } from '../../services/cloud-token.service';
@NgModule({ @NgModule({
imports: [ imports: [CommonModule, MaterialModule, CoreModule],
CommonModule, providers: [
MaterialModule, {
CoreModule provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN,
useClass: LocalPreferenceCloudService
}
], ],
providers: [{
provide: PROCESS_LISTS_PREFERENCES_SERVICE_TOKEN,
useClass: LocalPreferenceCloudService
}],
declarations: [ProcessListCloudComponent], declarations: [ProcessListCloudComponent],
exports: [ProcessListCloudComponent] exports: [ProcessListCloudComponent]
}) })
export class ProcessListCloudModule { } export class ProcessListCloudModule {}

View File

@ -22,14 +22,6 @@ import { of, throwError } from 'rxjs';
import { StartProcessCloudService } from '../services/start-process-cloud.service'; import { StartProcessCloudService } from '../services/start-process-cloud.service';
import { FormCloudService } from '../../../form/services/form-cloud.service'; import { FormCloudService } from '../../../form/services/form-cloud.service';
import { StartProcessCloudComponent } from './start-process-cloud.component'; import { StartProcessCloudComponent } from './start-process-cloud.component';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatRippleModule, MatCommonModule, MatOptionModule } from '@angular/material/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { import {
fakeProcessDefinitions, fakeProcessDefinitions,
fakeStartForm, fakeStartForm,
@ -88,20 +80,7 @@ describe('StartProcessCloudComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ imports: [ProcessServiceCloudTestingModule, StartProcessCloudComponent]
ProcessServiceCloudTestingModule,
FormsModule,
MatCommonModule,
ReactiveFormsModule,
MatCardModule,
MatIconModule,
MatAutocompleteModule,
MatOptionModule,
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatRippleModule
]
}); });
processService = TestBed.inject(StartProcessCloudService); processService = TestBed.inject(StartProcessCloudService);
formCloudService = TestBed.inject(FormCloudService); formCloudService = TestBed.inject(FormCloudService);

View File

@ -56,10 +56,11 @@ import { TranslateModule } from '@ngx-translate/core';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatCardModule } from '@angular/material/card'; import { MatCardModule } from '@angular/material/card';
import { MatButtonModule } from '@angular/material/button'; import { MatButtonModule } from '@angular/material/button';
import { FormCloudModule } from '../../../form/form-cloud.module';
import { MatIconModule } from '@angular/material/icon'; import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input'; import { MatInputModule } from '@angular/material/input';
import { MatOptionModule } from '@angular/material/core'; import { MatOptionModule } from '@angular/material/core';
import { FormCloudComponent } from '../../../form/components/form-cloud.component';
import { FormCustomOutcomesComponent } from '../../../form/components/form-cloud-custom-outcomes.component';
const MAX_NAME_LENGTH: number = 255; const MAX_NAME_LENGTH: number = 255;
const PROCESS_DEFINITION_DEBOUNCE: number = 300; const PROCESS_DEFINITION_DEBOUNCE: number = 300;
@ -75,14 +76,16 @@ const PROCESS_DEFINITION_IDENTIFIER_REG_EXP = new RegExp('%{processdefinition}',
MatProgressSpinnerModule, MatProgressSpinnerModule,
MatCardModule, MatCardModule,
MatButtonModule, MatButtonModule,
FormCloudModule,
InplaceFormInputComponent, InplaceFormInputComponent,
MatIconModule, MatIconModule,
MatInputModule, MatInputModule,
MatOptionModule, MatOptionModule,
MatAutocompleteModule, MatAutocompleteModule,
ReactiveFormsModule ReactiveFormsModule,
FormCloudComponent,
FormCustomOutcomesComponent
], ],
providers: [LocalizedDatePipe],
templateUrl: './start-process-cloud.component.html', templateUrl: './start-process-cloud.component.html',
styleUrls: ['./start-process-cloud.component.scss'], styleUrls: ['./start-process-cloud.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@ -16,9 +16,6 @@
*/ */
export * from './components/start-process-cloud.component'; export * from './components/start-process-cloud.component';
export * from './models/process-instance-cloud.model'; export * from './models/process-instance-cloud.model';
export * from './models/process-payload-cloud.model'; export * from './models/process-payload-cloud.model';
export * from './services/start-process-cloud.service'; export * from './services/start-process-cloud.service';
export * from './start-process-cloud.module';

View File

@ -1,26 +0,0 @@
/*!
* @license
* Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { NgModule } from '@angular/core';
import { StartProcessCloudComponent } from './components/start-process-cloud.component';
/** @deprecated use StartProcessCloudComponent instead */
@NgModule({
imports: [StartProcessCloudComponent],
exports: [StartProcessCloudComponent]
})
export class StartProcessCloudModule {}

View File

@ -70,8 +70,13 @@ describe('TaskFormCloudComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ProcessServiceCloudTestingModule], imports: [
declarations: [FormCloudComponent, UserTaskCloudButtonsComponent, FormCustomOutcomesComponent] ProcessServiceCloudTestingModule,
FormCloudComponent,
FormCustomOutcomesComponent,
UserTaskCloudButtonsComponent,
TaskFormCloudComponent
]
}); });
taskDetails.status = TASK_ASSIGNED_STATE; taskDetails.status = TASK_ASSIGNED_STATE;
taskDetails.permissions = [TASK_VIEW_PERMISSION]; taskDetails.permissions = [TASK_VIEW_PERMISSION];

View File

@ -18,7 +18,6 @@
import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular';
import { FormCloudService } from '../../../../form/public-api'; import { FormCloudService } from '../../../../form/public-api';
import { TaskCloudService } from '../../../services/task-cloud.service'; import { TaskCloudService } from '../../../services/task-cloud.service';
import { TaskFormModule } from '../../task-form.module';
import { TaskFormCloudComponent } from './task-form-cloud.component'; import { TaskFormCloudComponent } from './task-form-cloud.component';
import { TaskCloudServiceMock } from '../../../mock/task-cloud.service.mock'; import { TaskCloudServiceMock } from '../../../mock/task-cloud.service.mock';
import { FormCloudServiceMock } from '../../../../form/mocks/form-cloud.service.mock'; import { FormCloudServiceMock } from '../../../../form/mocks/form-cloud.service.mock';
@ -30,7 +29,7 @@ export default {
title: 'Process Services Cloud/Task Cloud/Task Form/Task Form Cloud', title: 'Process Services Cloud/Task Cloud/Task Form/Task Form Cloud',
decorators: [ decorators: [
moduleMetadata({ moduleMetadata({
imports: [TaskFormModule], imports: [TaskFormCloudComponent],
providers: [ providers: [
{ provide: TaskCloudService, useClass: TaskCloudServiceMock }, { provide: TaskCloudService, useClass: TaskCloudServiceMock },
{ provide: FormCloudService, useClass: FormCloudServiceMock } { provide: FormCloudService, useClass: FormCloudServiceMock }

View File

@ -24,9 +24,14 @@ import { DropdownCloudWidgetComponent } from '../../../../form/components/widget
import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces'; import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces';
import { TaskCloudService } from '../../../services/task-cloud.service'; import { TaskCloudService } from '../../../services/task-cloud.service';
import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model'; import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model';
import { CommonModule } from '@angular/common';
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
import { FormCustomOutcomesComponent } from '../../../../form/components/form-cloud-custom-outcomes.component';
@Component({ @Component({
selector: 'adf-cloud-task-form', selector: 'adf-cloud-task-form',
standalone: true,
imports: [CommonModule, UserTaskCloudButtonsComponent, FormCustomOutcomesComponent, FormCloudComponent],
templateUrl: './task-form-cloud.component.html', templateUrl: './task-form-cloud.component.html',
styleUrls: ['./task-form-cloud.component.scss'], styleUrls: ['./task-form-cloud.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@ -20,7 +20,6 @@ import { UserTaskCloudButtonsComponent } from './user-task-cloud-buttons.compone
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { MatButtonHarness } from '@angular/material/button/testing'; import { MatButtonHarness } from '@angular/material/button/testing';
import { NoopTranslateModule } from '@alfresco/adf-core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { ProcessServiceCloudTestingModule } from 'lib/process-services-cloud/src/lib/testing/process-service-cloud.testing.module'; import { ProcessServiceCloudTestingModule } from 'lib/process-services-cloud/src/lib/testing/process-service-cloud.testing.module';
@ -36,8 +35,7 @@ describe('UserTaskCloudButtonsComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopTranslateModule, ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, UserTaskCloudButtonsComponent]
declarations: [UserTaskCloudButtonsComponent]
}); });
fixture = TestBed.createComponent(UserTaskCloudButtonsComponent); fixture = TestBed.createComponent(UserTaskCloudButtonsComponent);
debugElement = fixture.debugElement; debugElement = fixture.debugElement;

View File

@ -16,9 +16,16 @@
*/ */
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { UnClaimTaskCloudDirective } from '../../../directives/unclaim-task-cloud.directive';
import { ClaimTaskCloudDirective } from '../../../directives/claim-task-cloud.directive';
@Component({ @Component({
selector: 'adf-cloud-user-task-cloud-buttons', selector: 'adf-cloud-user-task-cloud-buttons',
standalone: true,
imports: [CommonModule, TranslateModule, UnClaimTaskCloudDirective, ClaimTaskCloudDirective, MatButtonModule],
styles: ['button { margin-right: 8px; }'], styles: ['button { margin-right: 8px; }'],
templateUrl: './user-task-cloud-buttons.component.html' templateUrl: './user-task-cloud-buttons.component.html'
}) })

View File

@ -15,7 +15,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { NoopTranslateModule } from '@alfresco/adf-core';
import { import {
TASK_ASSIGNED_STATE, TASK_ASSIGNED_STATE,
TASK_CLAIM_PERMISSION, TASK_CLAIM_PERMISSION,
@ -64,8 +63,7 @@ describe('UserTaskCloudComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [NoopTranslateModule, ProcessServiceCloudTestingModule], imports: [ProcessServiceCloudTestingModule, UserTaskCloudComponent, TaskFormCloudComponent]
declarations: [UserTaskCloudComponent, TaskFormCloudComponent]
}); });
fixture = TestBed.createComponent(UserTaskCloudComponent); fixture = TestBed.createComponent(UserTaskCloudComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@ -15,13 +15,21 @@
* limitations under the License. * limitations under the License.
*/ */
import { ContentLinkModel, FormFieldValidator, FormModel, FormOutcomeEvent } from '@alfresco/adf-core'; import { ContentLinkModel, EmptyContentComponent, FormFieldValidator, FormModel, FormOutcomeEvent } from '@alfresco/adf-core';
import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; import { Component, DestroyRef, EventEmitter, inject, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces'; import { FormCloudDisplayModeConfiguration } from '../../../../services/form-fields.interfaces';
import { TaskCloudService } from '../../../services/task-cloud.service'; import { TaskCloudService } from '../../../services/task-cloud.service';
import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model'; import { TaskDetailsCloudModel } from '../../../start-task/models/task-details-cloud.model';
import { TaskFormCloudComponent } from '../task-form-cloud/task-form-cloud.component'; import { TaskFormCloudComponent } from '../task-form-cloud/task-form-cloud.component';
import { CommonModule } from '@angular/common';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { UserTaskCloudButtonsComponent } from '../user-task-cloud-buttons/user-task-cloud-buttons.component';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { TaskScreenCloudComponent } from '../../../../screen/components/screen-cloud/screen-cloud.component';
import { CompleteTaskDirective } from '../../../directives/complete-task.directive';
const TaskTypes = { const TaskTypes = {
Form: 'form', Form: 'form',
@ -33,6 +41,19 @@ type TaskTypesType = (typeof TaskTypes)[keyof typeof TaskTypes];
@Component({ @Component({
selector: 'adf-cloud-user-task', selector: 'adf-cloud-user-task',
standalone: true,
imports: [
CommonModule,
MatProgressSpinnerModule,
UserTaskCloudButtonsComponent,
TranslateModule,
MatButtonModule,
MatCardModule,
EmptyContentComponent,
TaskScreenCloudComponent,
TaskFormCloudComponent,
CompleteTaskDirective
],
templateUrl: './user-task-cloud.component.html', templateUrl: './user-task-cloud.component.html',
styleUrls: ['./user-task-cloud.component.scss'] styleUrls: ['./user-task-cloud.component.scss']
}) })

View File

@ -16,19 +16,23 @@
*/ */
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common'; import { FORM_CLOUD_DIRECTIVES } from '../../form/form-cloud.module';
import { MaterialModule } from '../../material.module';
import { FormCloudModule } from '../../form/form-cloud.module';
import { TASK_DIRECTIVES } from '../directives/task-directive.module'; import { TASK_DIRECTIVES } from '../directives/task-directive.module';
import { TaskFormCloudComponent } from './components/task-form-cloud/task-form-cloud.component'; import { TaskFormCloudComponent } from './components/task-form-cloud/task-form-cloud.component';
import { CoreModule } from '@alfresco/adf-core';
import { TaskScreenCloudComponent } from '../../screen/components/screen-cloud/screen-cloud.component'; import { TaskScreenCloudComponent } from '../../screen/components/screen-cloud/screen-cloud.component';
import { UserTaskCloudComponent } from './components/user-task-cloud/user-task-cloud.component'; import { UserTaskCloudComponent } from './components/user-task-cloud/user-task-cloud.component';
import { UserTaskCloudButtonsComponent } from './components/user-task-cloud-buttons/user-task-cloud-buttons.component'; import { UserTaskCloudButtonsComponent } from './components/user-task-cloud-buttons/user-task-cloud-buttons.component';
/** @deprecated use standalone component imports instead */
@NgModule({ @NgModule({
imports: [CoreModule, CommonModule, MaterialModule, FormCloudModule, ...TASK_DIRECTIVES, TaskScreenCloudComponent], imports: [
declarations: [TaskFormCloudComponent, UserTaskCloudComponent, UserTaskCloudButtonsComponent], ...FORM_CLOUD_DIRECTIVES,
...TASK_DIRECTIVES,
TaskScreenCloudComponent,
UserTaskCloudButtonsComponent,
TaskFormCloudComponent,
UserTaskCloudComponent
],
exports: [TaskFormCloudComponent, UserTaskCloudComponent] exports: [TaskFormCloudComponent, UserTaskCloudComponent]
}) })
export class TaskFormModule {} export class TaskFormModule {}

View File

@ -79,10 +79,6 @@ export class FormComponent extends FormBaseComponent implements OnInit, OnChange
protected nodeService = inject(NodesApiService); protected nodeService = inject(NodesApiService);
private cdRef = inject(ChangeDetectorRef); private cdRef = inject(ChangeDetectorRef);
/** Underlying form model instance. */
@Input()
form: FormModel;
/** Task id to fetch corresponding form and values. */ /** Task id to fetch corresponding form and values. */
@Input() @Input()
taskId: string; taskId: string;