Improvement/aae 30909 enhance user experience with tab navigation within the form (#10844)

* AAE-30909 tab-header fixed at the top

* AAE-30909 fixing widh and scrolling issues in workspace and studio-hxp
This commit is contained in:
Soumyajit Chakraborty 2025-05-08 19:23:30 +05:30 committed by GitHub
parent adeb82c137
commit acf9e3e11c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 143 additions and 75 deletions

View File

@ -3,8 +3,10 @@
<div *ngIf="formDefinition.hasTabs()"> <div *ngIf="formDefinition.hasTabs()">
<div *ngIf="hasTabs()" class="alfresco-tabs-widget"> <div *ngIf="hasTabs()" class="alfresco-tabs-widget">
<mat-tab-group> <mat-tab-group>
<mat-tab *ngFor="let tab of visibleTabs()" [label]="tab.title | translate "> <mat-tab *ngFor="let tab of visibleTabs()" [label]="tab.title | translate ">
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" /> <div class="adf-form-tab-content">
<ng-template *ngTemplateOutlet="render; context: { fieldToRender: tab.fields }" />
</div>
</mat-tab> </mat-tab>
</mat-tab-group> </mat-tab-group>
</div> </div>

View File

@ -13,6 +13,40 @@
height: 100%; height: 100%;
} }
.alfresco-tabs-widget {
width: 100%;
position: absolute;
.adf-form-tab-group {
width: 100%;
z-index: 9999;
}
#{ms.$mat-tab-body} {
margin-bottom: 8em;
}
#{ms.$mat-tab-header} {
z-index: 10;
margin: 0;
background-color: white;
position: sticky;
/* stylelint-disable-next-line value-no-vendor-prefix */
position: -webkit-sticky; /* macOS/iOS Safari */
/* stylelint-disable-next-line declaration-no-important */
margin-left: 0 !important;
top: 0;
}
#{ms.$mat-tab-body-wrapper} {
padding-top: 16px;
}
}
.mat-mdc-card-content:first-child {
padding-top: 0;
}
.adf-container-widget { .adf-container-widget {
.adf-grid-list { .adf-grid-list {
display: grid; display: grid;
@ -116,12 +150,18 @@
overflow: hidden; overflow: hidden;
} }
& #{ms.$mat-tab-header} {
position: fixed;
z-index: 1000;
}
& #{ms.$mat-card-header-text} { & #{ms.$mat-card-header-text} {
margin: 0; margin: 0;
} }
& #{ms.$mat-tab-body-content} { & #{ms.$mat-tab-body-content} {
overflow: hidden; overflow: hidden;
padding-top: 0;
} }
& #{mat-tab-label-text} { & #{mat-tab-label-text} {

View File

@ -6,8 +6,11 @@ $mat-tab-label-active: '.mdc-tab--active';
$mat-tab-label-container: '.mat-mdc-tab-label-container'; $mat-tab-label-container: '.mat-mdc-tab-label-container';
$mat-tab-label-text: '.mdc-tab__text-label'; $mat-tab-label-text: '.mdc-tab__text-label';
$mat-tab-body: '.mat-mdc-tab-body'; $mat-tab-body: '.mat-mdc-tab-body';
$mat-tab-header: '.mat-mdc-tab-header';
$mat-tab-body-content: '.mat-mdc-tab-body-content'; $mat-tab-body-content: '.mat-mdc-tab-body-content';
$mat-tab-ink-bar: '.mdc-tab-indicator'; $mat-tab-ink-bar: '.mdc-tab-indicator';
$mat-tab-body-wrapper: '.mat-mdc-tab-body-wrapper';
$mat-tab-body-content: '.mat-mdc-card-content';
$mat-chip: '.mat-mdc-chip'; $mat-chip: '.mat-mdc-chip';
$mat-chip-list: '.mat-mdc-chip-list'; $mat-chip-list: '.mat-mdc-chip-list';
$mat-checkbox: '.mat-mdc-checkbox'; $mat-checkbox: '.mat-mdc-checkbox';

View File

@ -4,94 +4,107 @@
<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]="formStyle"> [style]="formStyle"
<div class="adf-cloud-form-content" >
[cdkTrapFocus]="displayConfiguration?.options?.trapFocus" <div class="adf-cloud-form-content" [cdkTrapFocus]="displayConfiguration?.options?.trapFocus" cdkTrapFocusAutoCapture>
cdkTrapFocusAutoCapture> <adf-toolbar class="adf-cloud-form-toolbar" *ngIf="displayConfiguration?.options?.displayToolbar">
<div class="adf-cloud-form__form-title">
<span class="adf-cloud-form__display-name" [title]="form.taskName">
{{ form.taskName }}
<ng-container *ngIf="!form.taskName">
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</ng-container>
</span>
</div>
<adf-toolbar class="adf-cloud-form-toolbar" *ngIf="displayConfiguration?.options?.displayToolbar"> <adf-toolbar-divider *ngIf="displayConfiguration?.options?.displayCloseButton" />
<div class="adf-cloud-form__form-title"> <button
<span class="adf-cloud-form__display-name" [title]="form.taskName"> *ngIf="displayConfiguration?.options?.displayCloseButton"
{{form.taskName}} class="adf-cloud-form-close-button"
<ng-container *ngIf="!form.taskName"> data-automation-id="adf-toolbar-right-back"
{{'FORM.FORM_RENDERER.NAMELESS_TASK' | translate}} [attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
</ng-container> [attr.data-automation-id]="'adf-cloud-form-close-button'"
</span> [title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
</div> mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
<adf-toolbar-divider *ngIf="displayConfiguration?.options?.displayCloseButton" /> (click)="switchToDisplayMode()"
<button
*ngIf="displayConfiguration?.options?.displayCloseButton"
class="adf-cloud-form-close-button"
data-automation-id="adf-toolbar-right-back"
[attr.aria-label]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
[attr.data-automation-id]="'adf-cloud-form-close-button'"
[title]="'ADF_VIEWER.ACTIONS.CLOSE' | translate"
mat-icon-button
title="{{ 'ADF_VIEWER.ACTIONS.CLOSE' | translate }}"
(click)="switchToDisplayMode()">
<mat-icon>close</mat-icon>
</button>
</adf-toolbar>
<mat-card
appearance="outlined"
class="adf-cloud-form-content-card"
[class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'"
> >
<div class="adf-cloud-form-content-card-container"> <mat-icon>close</mat-icon>
<mat-card-header *ngIf="showTitle || showRefreshButton || showValidationIcon"> </button>
<mat-card-title> </adf-toolbar>
<h4>
<div *ngIf="showValidationIcon" class="adf-form-validation-button"> <mat-card
<i id="adf-valid-form-icon" class="material-icons" appearance="outlined"
*ngIf="form.isValid; else no_valid_form">check_circle</i> class="adf-cloud-form-content-card"
<ng-template #no_valid_form> [class.adf-cloud-form-content-card-fullscreen]="displayMode === 'fullScreen'"
<i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i> >
</ng-template> <div class="adf-cloud-form-content-card-container">
</div> <mat-card-header *ngIf="showTitle || showRefreshButton || showValidationIcon">
<div *ngIf="!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')" class="adf-cloud-form-fullscreen-button"> <mat-card-title>
<button mat-icon-button (click)="switchToDisplayMode('fullScreen')" [attr.data-automation-id]="'adf-cloud-form-fullscreen-button'"> <h4>
<mat-icon>fullscreen</mat-icon> <div *ngIf="showValidationIcon" class="adf-form-validation-button">
</button> <i id="adf-valid-form-icon" class="material-icons" *ngIf="form.isValid; else no_valid_form">check_circle</i>
</div> <ng-template #no_valid_form>
<div *ngIf="showRefreshButton" class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate"> <i id="adf-invalid-form-icon" class="material-icons adf-invalid-color">error</i>
<button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate"> </ng-template>
<mat-icon>refresh</mat-icon> </div>
</button> <div
</div> *ngIf="!displayConfiguration?.options?.fullscreen && findDisplayConfiguration('fullScreen')"
<span *ngIf="isTitleEnabled()" class="adf-cloud-form-title" [title]="form.taskName" class="adf-cloud-form-fullscreen-button"
>{{form.taskName}} >
<ng-container *ngIf="!form.taskName"> <button
{{'FORM.FORM_RENDERER.NAMELESS_TASK' | translate}} mat-icon-button
</ng-container> (click)="switchToDisplayMode('fullScreen')"
</span> [attr.data-automation-id]="'adf-cloud-form-fullscreen-button'"
</h4> >
</mat-card-title> <mat-icon>fullscreen</mat-icon>
</mat-card-header> </button>
<mat-card-content class="adf-form-container-card-content"> </div>
<adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" /> <div *ngIf="showRefreshButton" class="adf-cloud-form-reload-button" [title]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
</mat-card-content> <button mat-icon-button (click)="onRefreshClicked()" [attr.aria-label]="'ADF_VIEWER.ACTIONS.FULLSCREEN' | translate">
<mat-icon>refresh</mat-icon>
</button>
</div>
<span *ngIf="isTitleEnabled()" class="adf-cloud-form-title" [title]="form.taskName"
>{{ form.taskName }}
<ng-container *ngIf="!form.taskName">
{{ 'FORM.FORM_RENDERER.NAMELESS_TASK' | translate }}
</ng-container>
</span>
</h4>
</mat-card-title>
</mat-card-header>
<mat-card-content class="adf-form-container-card-content">
<adf-form-renderer [formDefinition]="form" [readOnly]="readOnly" />
</mat-card-content>
<div class="adf-cloud-form-content-card-actions">
<mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end"> <mat-card-actions *ngIf="form.hasOutcomes()" class="adf-form-mat-card-actions" align="end">
<mat-checkbox id="adf-form-open-next-task" *ngIf="showNextTaskCheckbox" [checked]="isNextTaskCheckboxChecked" (change)="onNextTaskCheckboxCheckedChanged($event)">{{'ADF_CLOUD_TASK_FORM.OPEN_NEXT_TASK.LABEL' | translate}}</mat-checkbox> <mat-checkbox
id="adf-form-open-next-task"
*ngIf="showNextTaskCheckbox"
[checked]="isNextTaskCheckboxChecked"
(change)="onNextTaskCheckboxCheckedChanged($event)"
>{{ 'ADF_CLOUD_TASK_FORM.OPEN_NEXT_TASK.LABEL' | translate }}</mat-checkbox
>
<span class="adf-card-actions-spacer"></span> <span class="adf-card-actions-spacer"></span>
<ng-content select="adf-cloud-form-custom-outcomes" /> <ng-content select="adf-cloud-form-custom-outcomes" />
<ng-container *ngFor="let outcome of form.outcomes"> <ng-container *ngFor="let outcome of form.outcomes">
<button <button
*ngIf="outcome.isVisible" *ngIf="outcome.isVisible"
[id]="'adf-form-'+ outcome.name | formatSpace" [id]="'adf-form-' + outcome.name | formatSpace"
[color]="getColorForOutcome(outcome.name)" [color]="getColorForOutcome(outcome.name)"
mat-button mat-button
[disabled]="!isOutcomeButtonEnabled(outcome)" [disabled]="!isOutcomeButtonEnabled(outcome)"
[class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)" [class.adf-form-hide-button]="!isOutcomeButtonVisible(outcome, form.readOnly)"
(click)="onOutcomeClicked(outcome)" (click)="onOutcomeClicked(outcome)"
> >
{{outcome.name | translate | uppercase }} {{ outcome.name | translate | uppercase }}
</button> </button>
</ng-container> </ng-container>
</mat-card-actions> </mat-card-actions>
</div> </div>
</mat-card> </div>
</div> </mat-card>
</div>
</div> </div>

View File

@ -17,6 +17,7 @@
flex: 1; flex: 1;
flex-direction: column; flex-direction: column;
display: flex; display: flex;
position: relative;
} }
.adf-card-actions-spacer { .adf-card-actions-spacer {
@ -72,13 +73,14 @@
&-content-card { &-content-card {
overflow-y: auto; overflow-y: auto;
position: static;
&-fullscreen { &-fullscreen {
padding: 0; padding: 0;
height: 100%; height: 100%;
width: 100%; width: 100%;
.adf-cloud-form-content-card-container { &-container {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
@ -89,6 +91,14 @@
} }
} }
} }
&-actions {
position: fixed;
bottom: 0;
width: -webkit-fill-available;
z-index: 1;
background-color: white;
}
} }
&-sidebars { &-sidebars {