mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2026-09-09 18:03:21 +00:00
AAE-39155 Implement button widget on ADF (#11324)
* AAE-39155 Initial implementation * AAE-39155 Improve button position
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
<button
|
||||||
|
mat-flat-button
|
||||||
|
class="adf-button-widget__button"
|
||||||
|
[color]="'primary'"
|
||||||
|
[matTooltip]="field?.tooltip"
|
||||||
|
[matTooltipShowDelay]="tooltipShowDelay"
|
||||||
|
[disabled]="field?.readOnly ?? false"
|
||||||
|
(click)="onClick($event)"
|
||||||
|
>
|
||||||
|
{{ field?.name | translate }}
|
||||||
|
</button>
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
.adf-button-widget {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-height: 96px;
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 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 { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { ButtonWidgetComponent } from './button.widget';
|
||||||
|
import { HarnessLoader } from '@angular/cdk/testing';
|
||||||
|
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||||
|
import { MatButtonHarness } from '@angular/material/button/testing';
|
||||||
|
import { MatTooltipHarness } from '@angular/material/tooltip/testing';
|
||||||
|
|
||||||
|
describe('ButtonWidgetComponent', () => {
|
||||||
|
let component: ButtonWidgetComponent;
|
||||||
|
let fixture: ComponentFixture<ButtonWidgetComponent>;
|
||||||
|
let loader: HarnessLoader;
|
||||||
|
|
||||||
|
const buttonSelector = '.adf-button-widget__button';
|
||||||
|
const mockField = { id: 'button1', name: 'Click me!', type: 'button', readOnly: false, className: 'custom-button-class', tooltip: '' };
|
||||||
|
|
||||||
|
const getButton = async () => loader.getHarness(MatButtonHarness.with({ selector: buttonSelector }));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [ButtonWidgetComponent]
|
||||||
|
});
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(ButtonWidgetComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||||
|
|
||||||
|
fixture.componentRef.setInput('field', mockField);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display button with the given name', async () => {
|
||||||
|
const button = await getButton();
|
||||||
|
const buttonText = await button.getText();
|
||||||
|
|
||||||
|
expect(buttonText).toBe('Click me!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT disable button when readOnly is false', async () => {
|
||||||
|
const button = await getButton();
|
||||||
|
|
||||||
|
expect(await button.isDisabled()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should disable button when readOnly is true', async () => {
|
||||||
|
fixture.componentRef.setInput('field', { ...mockField, readOnly: true });
|
||||||
|
const button = await getButton();
|
||||||
|
|
||||||
|
expect(await button.isDisabled()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should attach className to the widget host element', () => {
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
|
const hostElement = fixture.nativeElement;
|
||||||
|
|
||||||
|
expect(hostElement.classList).toContain('custom-button-class');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should NOT show tooltip when tooltip text is not defined', async () => {
|
||||||
|
const buttonTooltip = await loader.getHarness(MatTooltipHarness.with({ selector: buttonSelector }));
|
||||||
|
|
||||||
|
await buttonTooltip.show();
|
||||||
|
|
||||||
|
expect(await buttonTooltip.isOpen()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should show tooltip when tooltip text is defined', async () => {
|
||||||
|
const expectedTooltip = 'This is a tooltip';
|
||||||
|
|
||||||
|
fixture.componentRef.setInput('field', { ...mockField, tooltip: expectedTooltip });
|
||||||
|
|
||||||
|
const buttonTooltip = await loader.getHarness(MatTooltipHarness.with({ selector: buttonSelector }));
|
||||||
|
|
||||||
|
await buttonTooltip.show();
|
||||||
|
|
||||||
|
expect(await buttonTooltip.isOpen()).toBe(true);
|
||||||
|
expect(await buttonTooltip.getTooltipText()).toBe(expectedTooltip);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call event method only once when widget is clicked', async () => {
|
||||||
|
const eventSpy = spyOn(component, 'event');
|
||||||
|
|
||||||
|
const button = await getButton();
|
||||||
|
await button.click();
|
||||||
|
|
||||||
|
expect(eventSpy).toHaveBeenCalledTimes(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/*!
|
||||||
|
* @license
|
||||||
|
* Copyright © 2005-2025 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable @angular-eslint/component-selector */
|
||||||
|
|
||||||
|
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
|
||||||
|
import { WidgetComponent } from '../widget.component';
|
||||||
|
import { FormService } from '../../../services/form.service';
|
||||||
|
import { TranslatePipe } from '@ngx-translate/core';
|
||||||
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'button-widget',
|
||||||
|
templateUrl: './button.widget.html',
|
||||||
|
styleUrl: './button.widget.scss',
|
||||||
|
host: {
|
||||||
|
'[class]': 'hostClasses'
|
||||||
|
},
|
||||||
|
encapsulation: ViewEncapsulation.None,
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
|
imports: [TranslatePipe, MatButtonModule, MatTooltipModule]
|
||||||
|
})
|
||||||
|
export class ButtonWidgetComponent extends WidgetComponent {
|
||||||
|
readonly tooltipShowDelay: number = 500;
|
||||||
|
|
||||||
|
constructor(public formService: FormService) {
|
||||||
|
super(formService);
|
||||||
|
}
|
||||||
|
|
||||||
|
get hostClasses(): string {
|
||||||
|
return `adf-button-widget ${this.field?.className || ''}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick(event: Event): void {
|
||||||
|
this.event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,6 +53,7 @@ export class FormFieldTypes {
|
|||||||
static JSON: string = 'json';
|
static JSON: string = 'json';
|
||||||
static DATA_TABLE: string = 'data-table';
|
static DATA_TABLE: string = 'data-table';
|
||||||
static DISPLAY_EXTERNAL_PROPERTY: string = 'display-external-property';
|
static DISPLAY_EXTERNAL_PROPERTY: string = 'display-external-property';
|
||||||
|
static BUTTON: string = 'button';
|
||||||
|
|
||||||
static READONLY_TYPES: string[] = [FormFieldTypes.HYPERLINK, FormFieldTypes.DISPLAY_VALUE, FormFieldTypes.READONLY_TEXT, FormFieldTypes.GROUP];
|
static READONLY_TYPES: string[] = [FormFieldTypes.HYPERLINK, FormFieldTypes.DISPLAY_VALUE, FormFieldTypes.READONLY_TEXT, FormFieldTypes.GROUP];
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { DateTimeWidgetComponent } from './date-time/date-time.widget';
|
|||||||
import { JsonWidgetComponent } from './json/json.widget';
|
import { JsonWidgetComponent } from './json/json.widget';
|
||||||
import { BaseViewerWidgetComponent } from './base-viewer/base-viewer.widget';
|
import { BaseViewerWidgetComponent } from './base-viewer/base-viewer.widget';
|
||||||
import { DecimalWidgetComponent } from './decimal/decimal.component';
|
import { DecimalWidgetComponent } from './decimal/decimal.component';
|
||||||
|
import { ButtonWidgetComponent } from './button/button.widget';
|
||||||
|
|
||||||
// core
|
// core
|
||||||
export * from './widget.component';
|
export * from './widget.component';
|
||||||
@@ -52,6 +53,7 @@ export * from './date-time/date-time.widget';
|
|||||||
export * from './json/json.widget';
|
export * from './json/json.widget';
|
||||||
export * from './base-viewer/base-viewer.widget';
|
export * from './base-viewer/base-viewer.widget';
|
||||||
export * from './text/text-mask.component';
|
export * from './text/text-mask.component';
|
||||||
|
export * from './button/button.widget';
|
||||||
|
|
||||||
// widgets with schema
|
// widgets with schema
|
||||||
export * from './display-text';
|
export * from './display-text';
|
||||||
@@ -72,7 +74,8 @@ export const WIDGET_DIRECTIVES = [
|
|||||||
ErrorWidgetComponent,
|
ErrorWidgetComponent,
|
||||||
DateTimeWidgetComponent,
|
DateTimeWidgetComponent,
|
||||||
JsonWidgetComponent,
|
JsonWidgetComponent,
|
||||||
BaseViewerWidgetComponent
|
BaseViewerWidgetComponent,
|
||||||
|
ButtonWidgetComponent
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export const MASK_DIRECTIVE = [InputMaskDirective] as const;
|
export const MASK_DIRECTIVE = [InputMaskDirective] as const;
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ export class FormRenderingService extends DynamicComponentMapper {
|
|||||||
[FormFieldTypes.JSON]: DynamicComponentResolver.fromType(widgets.JsonWidgetComponent),
|
[FormFieldTypes.JSON]: DynamicComponentResolver.fromType(widgets.JsonWidgetComponent),
|
||||||
[FormFieldTypes.DISPLAY_VALUE]: DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
|
[FormFieldTypes.DISPLAY_VALUE]: DynamicComponentResolver.fromType(widgets.TextWidgetComponent),
|
||||||
[FormFieldTypes.DATETIME]: DynamicComponentResolver.fromType(widgets.DateTimeWidgetComponent),
|
[FormFieldTypes.DATETIME]: DynamicComponentResolver.fromType(widgets.DateTimeWidgetComponent),
|
||||||
[FormFieldTypes.VIEWER]: DynamicComponentResolver.fromType(widgets.BaseViewerWidgetComponent)
|
[FormFieldTypes.VIEWER]: DynamicComponentResolver.fromType(widgets.BaseViewerWidgetComponent),
|
||||||
|
[FormFieldTypes.BUTTON]: DynamicComponentResolver.fromType(widgets.ButtonWidgetComponent)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -258,7 +258,8 @@ export enum FormFieldType {
|
|||||||
uploadFolder = 'uploadFolder',
|
uploadFolder = 'uploadFolder',
|
||||||
displayValue = 'readonly',
|
displayValue = 'readonly',
|
||||||
displayText = 'readonly-text',
|
displayText = 'readonly-text',
|
||||||
fileViewer = 'file-viewer'
|
fileViewer = 'file-viewer',
|
||||||
|
button = 'button'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FormCloudDisplayModeConfigurationOptions {
|
export interface FormCloudDisplayModeConfigurationOptions {
|
||||||
|
|||||||
Reference in New Issue
Block a user