mirror of
https://github.com/Alfresco/alfresco-content-app.git
synced 2026-09-09 18:02:54 +00:00
[ACS-9980] Add the option to provide custom user profile sections (#4859)
* [ACS-9980] Add the option to provide custom user profile sections * [ACS-9980] Cr fixes * [ACS-9980] Formatting fix
This commit is contained in:
@@ -463,7 +463,12 @@
|
||||
"COLLAPSE_NAVIGATION": "Collapse navigation menu",
|
||||
"OPTIONS_SETTINGS": "Options and settings",
|
||||
"MY_PROFILE": "My profile",
|
||||
"EXPAND_NAVIGATION": "Expand navigation menu"
|
||||
"EXPAND_NAVIGATION": "Expand navigation menu",
|
||||
"EXPAND_SECTION": "Expand section",
|
||||
"COLLAPSE_SECTION": "Collapse section",
|
||||
"EDIT": "Edit",
|
||||
"CANCEL": "Cancel",
|
||||
"SAVE": "Save"
|
||||
},
|
||||
"FOLDER_INFO": {
|
||||
"ICON": "Folder Icon",
|
||||
|
||||
@@ -166,7 +166,8 @@ import { SaveSearchSidenavComponent } from './components/search/search-save/side
|
||||
'app.canShowLogout': rules.canShowLogout,
|
||||
'app.isContentServiceEnabled': rules.isContentServiceEnabled,
|
||||
'app.areTagsEnabled': rules.areTagsEnabled,
|
||||
'app.areCategoriesEnabled': rules.areCategoriesEnabled
|
||||
'app.areCategoriesEnabled': rules.areCategoriesEnabled,
|
||||
'app.isSSOEnabled': rules.isSSOEnabled
|
||||
}
|
||||
})
|
||||
]
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
<div class="app-profile-container">
|
||||
<div class="app-profile-row">
|
||||
<div class="app-profile-title">
|
||||
<button *ngIf="(appNavNarMode$ | async) === 'collapsed'" mat-icon-button (click)="toggleClick()"
|
||||
title="{{'APP.TOOLTIPS.EXPAND_NAVIGATION' | translate}}">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
@if ((appNavNarMode$ | async) === 'collapsed') {
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="toggleNavigationMenu()"
|
||||
[attr.title]="'APP.TOOLTIPS.EXPAND_NAVIGATION' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.EXPAND_NAVIGATION' | translate">
|
||||
<mat-icon>menu</mat-icon>
|
||||
</button>
|
||||
}
|
||||
<button
|
||||
class="app-profile-icon"
|
||||
mat-icon-button
|
||||
@@ -16,26 +21,49 @@
|
||||
<h3 class="app-profile">{{'APP.EDIT_PROFILE.MY_PROFILE' | translate}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="app-profile-general-row" [formGroup]="profileForm">
|
||||
<div class="app-profile-general-row" [formGroup]="profileForm" id="general-dropdown">
|
||||
<div class="app-profile-general">
|
||||
<div class="app-profile-general-section">
|
||||
<mat-icon class="app-profile-general-icon" (click)="toggleGeneralDropdown()" id="toggle-general-dropdown">
|
||||
{{ generalSectionDropdown ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="toggleGeneralDropdown()"
|
||||
[attr.title]="`APP.TOOLTIPS.${generalSectionDropdown ? 'COLLAPSE' : 'EXPAND'}_SECTION` | translate"
|
||||
[attr.aria-label]="`APP.TOOLTIPS.${generalSectionDropdown ? 'COLLAPSE' : 'EXPAND'}_SECTION` | translate">
|
||||
<mat-icon>{{ generalSectionDropdown ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
</button>
|
||||
<h4 class="app-general-title">{{'APP.EDIT_PROFILE.GENERAL' | translate}}</h4>
|
||||
</div>
|
||||
<div class="app-general-edit-btn" *ngIf="generalSectionButtonsToggle">
|
||||
<button mat-raised-button (click)="toggleGeneralButtons()" id="general-edit-button"
|
||||
class="app-general-edit">{{'APP.EDIT_PROFILE.EDIT' | translate}}</button>
|
||||
</div>
|
||||
<div class="app-general-edit-btn" *ngIf="!generalSectionButtonsToggle">
|
||||
<button mat-raised-button class="app-general-cancel-btn" id="general-cancel-button"
|
||||
(click)="toggleGeneralButtons()">{{'APP.EDIT_PROFILE.CANCEL' | translate}}</button>
|
||||
<button mat-raised-button class="app-general-save-btn" id="general-save-button" [disabled]="profileForm.invalid"
|
||||
(click)="onSaveGeneralData(profileForm)">{{'APP.EDIT_PROFILE.SAVE' | translate}}</button>
|
||||
</div>
|
||||
@if (generalSectionButtonsToggle) {
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="toggleGeneralButtons()"
|
||||
class="app-general-edit"
|
||||
[attr.title]="'APP.TOOLTIPS.EDIT' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.EDIT' | translate">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
} @else {
|
||||
<button
|
||||
mat-icon-button
|
||||
class="app-general-cancel-btn"
|
||||
[attr.title]="'APP.TOOLTIPS.CANCEL' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.CANCEL' | translate"
|
||||
(click)="toggleGeneralButtons()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
[attr.title]="'APP.TOOLTIPS.SAVE' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.SAVE' | translate"
|
||||
[disabled]="profileForm.invalid"
|
||||
(click)="onSaveGeneralData(profileForm)">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-divider" *ngIf="generalSectionDropdown" />
|
||||
<div *ngIf="generalSectionDropdown">
|
||||
@if (generalSectionDropdown) {
|
||||
<mat-divider class="app-divider" />
|
||||
<div class="app-general-dropdown">
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.FIRST_NAME' | translate}}</h4>
|
||||
@@ -49,106 +77,176 @@
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.JOB_TITLE' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="generalSectionButtonsToggle">{{personDetails?.jobTitle}}</p>
|
||||
<input type="text" value="" formControlName="jobTitle" *ngIf="!generalSectionButtonsToggle"
|
||||
class="app-profile-general-dropdown-input-details app-selected">
|
||||
@if (generalSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.jobTitle}}</p>
|
||||
} @else {
|
||||
<input type="text" value="" formControlName="jobTitle" class="app-profile-general-dropdown-input-details app-selected">
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.LOCATION' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="generalSectionButtonsToggle">{{personDetails?.location}}</p>
|
||||
<input type="text" value="" formControlName="location" *ngIf="!generalSectionButtonsToggle"
|
||||
class="app-profile-general-dropdown-input-details app-selected">
|
||||
@if (generalSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.location}}</p>
|
||||
} @else {
|
||||
<input type="text" value="" formControlName="location" class="app-profile-general-dropdown-input-details app-selected">
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.TELEPHONE' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="generalSectionButtonsToggle">{{personDetails?.telephone}}</p>
|
||||
<input type="tel" name="Telephone" value="" formControlName="telephone" *ngIf="!generalSectionButtonsToggle"
|
||||
class="app-profile-general-dropdown-input-details app-selected" aria-describedby="app-view-profile-phone-error-message">
|
||||
<mat-error class="app-error-message" *ngIf="profileForm.get('telephone').invalid" role="alert" id="app-view-profile-phone-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
@if (generalSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.telephone}}</p>
|
||||
} @else {
|
||||
<input
|
||||
type="tel"
|
||||
name="Telephone"
|
||||
value=""
|
||||
formControlName="telephone"
|
||||
class="app-profile-general-dropdown-input-details app-selected"
|
||||
aria-describedby="app-view-profile-phone-error-message">
|
||||
}
|
||||
@if (profileForm.controls['telephone'].errors) {
|
||||
<mat-error class="app-error-message" role="alert" id="app-view-profile-phone-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.MOBILE' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="generalSectionButtonsToggle">{{personDetails?.mobile}}</p>
|
||||
<input type="tel" value="" formControlName="mobile" *ngIf="!generalSectionButtonsToggle"
|
||||
class="app-profile-general-dropdown-input-details app-selected" aria-describedby="app-view-profile-mobile-error-message">
|
||||
<mat-error class="app-error-message" *ngIf="profileForm.get('mobile').invalid" role="alert" id="app-view-profile-mobile-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
@if (generalSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.mobile}}</p>
|
||||
} @else {
|
||||
<input
|
||||
type="tel"
|
||||
value=""
|
||||
formControlName="mobile"
|
||||
class="app-profile-general-dropdown-input-details app-selected"
|
||||
aria-describedby="app-view-profile-mobile-error-message">
|
||||
}
|
||||
@if (profileForm.controls['mobile'].errors) {
|
||||
<mat-error class="app-error-message" role="alert" id="app-view-profile-mobile-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="app-profile-contact-row" [formGroup]="profileForm">
|
||||
<div class="app-profile-contact-row" [formGroup]="profileForm" id="contact-dropdown">
|
||||
<div class="app-profile-general profile-general-bottom-radius">
|
||||
<div class="app-profile-general-section">
|
||||
<mat-icon class="app-profile-general-icon" (click)="toggleContactDropdown()" id="toggle-contact-dropdown">
|
||||
{{ contactSectionDropdown ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="toggleContactDropdown()"
|
||||
[attr.title]="`APP.TOOLTIPS.${contactSectionDropdown ? 'COLLAPSE' : 'EXPAND'}_SECTION` | translate"
|
||||
[attr.aria-label]="`APP.TOOLTIPS.${contactSectionDropdown ? 'COLLAPSE' : 'EXPAND'}_SECTION` | translate">
|
||||
<mat-icon>{{ contactSectionDropdown ? 'expand_more' : 'chevron_right'}}</mat-icon>
|
||||
</button>
|
||||
<h4 class="app-general-title">{{'APP.EDIT_PROFILE.COMPANY_DETAILS' | translate}}</h4>
|
||||
</div>
|
||||
|
||||
<div class="app-general-edit-btn" *ngIf="contactSectionButtonsToggle">
|
||||
<button mat-raised-button class="app-general-edit" id="contact-edit-button"
|
||||
(click)="toggleContactButtons()">{{'APP.EDIT_PROFILE.EDIT' | translate}}</button>
|
||||
</div>
|
||||
<div class="app-general-edit-btn" *ngIf="!contactSectionButtonsToggle">
|
||||
<button mat-raised-button class="app-general-cancel-btn" id="contact-cancel-button"
|
||||
(click)="toggleContactButtons()">{{'APP.EDIT_PROFILE.CANCEL' | translate}}</button>
|
||||
<button mat-raised-button class="app-general-save-btn" id="contact-save-button" [disabled]="profileForm.invalid"
|
||||
(click)="onSaveCompanyData(profileForm)">{{'APP.EDIT_PROFILE.SAVE' | translate}}</button>
|
||||
</div>
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<button
|
||||
mat-icon-button
|
||||
(click)="toggleContactButtons()"
|
||||
class="app-general-edit"
|
||||
[attr.title]="'APP.TOOLTIPS.EDIT' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.EDIT' | translate">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
} @else {
|
||||
<button
|
||||
mat-icon-button
|
||||
class="app-general-cancel-btn"
|
||||
[attr.title]="'APP.TOOLTIPS.CANCEL' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.CANCEL' | translate"
|
||||
(click)="toggleContactButtons()">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<button
|
||||
mat-icon-button
|
||||
color="primary"
|
||||
[attr.title]="'APP.TOOLTIPS.SAVE' | translate"
|
||||
[attr.aria-label]="'APP.TOOLTIPS.SAVE' | translate"
|
||||
[disabled]="profileForm.invalid"
|
||||
(click)="onSaveCompanyData(profileForm)">
|
||||
<mat-icon>check</mat-icon>
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-divider" *ngIf="contactSectionDropdown" />
|
||||
<div *ngIf="contactSectionDropdown">
|
||||
@if (contactSectionDropdown) {
|
||||
<mat-divider class="app-divider" />
|
||||
<div class="app-general-dropdown">
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.NAME' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="contactSectionButtonsToggle">{{personDetails?.company?.organization}}</p>
|
||||
<input type="text" value="" *ngIf="!contactSectionButtonsToggle" formControlName="companyName"
|
||||
class="app-profile-general-dropdown-input-details app-selected">
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.company?.organization}}</p>
|
||||
} @else {
|
||||
<input type="text" value="" formControlName="companyName" class="app-profile-general-dropdown-input-details app-selected">
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.ADDRESS' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="contactSectionButtonsToggle">{{personDetails?.company?.address1}}</p>
|
||||
<input type="text" value="" *ngIf="!contactSectionButtonsToggle" formControlName="companyAddress"
|
||||
class="app-profile-general-dropdown-input-details app-selected">
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.company?.address1}}</p>
|
||||
} @else {
|
||||
<input type="text" value="" formControlName="companyAddress" class="app-profile-general-dropdown-input-details app-selected">
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.POSTCODE' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="contactSectionButtonsToggle">{{personDetails?.company?.postcode}}</p>
|
||||
<input type="text" value="" *ngIf="!contactSectionButtonsToggle" formControlName="companyPostCode"
|
||||
class="app-profile-general-dropdown-input-details app-selected">
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.company?.postcode}}</p>
|
||||
} @else {
|
||||
<input type="text" value="" formControlName="companyPostCode" class="app-profile-general-dropdown-input-details app-selected">
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.TELEPHONE' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="contactSectionButtonsToggle">{{personDetails?.company?.telephone}}</p>
|
||||
<input type="tel" value="" *ngIf="!contactSectionButtonsToggle" formControlName="companyTelephone"
|
||||
class="app-profile-general-dropdown-input-details app-selected" aria-describedby="app-view-profile-company-phone-error-message">
|
||||
<mat-error class="app-error-message" *ngIf="profileForm.get('companyTelephone').invalid" role="alert"
|
||||
id="app-view-profile-company-phone-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.company?.telephone}}</p>
|
||||
} @else {
|
||||
<input
|
||||
type="tel"
|
||||
value=""
|
||||
formControlName="companyTelephone"
|
||||
class="app-profile-general-dropdown-input-details app-selected"
|
||||
aria-describedby="app-view-profile-company-phone-error-message">
|
||||
}
|
||||
@if (profileForm.controls['companyTelephone'].errors) {
|
||||
<mat-error class="app-error-message" role="alert" id="app-view-profile-company-phone-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
}
|
||||
</div>
|
||||
<mat-divider class="app-general-dropdown-divider" />
|
||||
<div class="app-general-dropdown-details">
|
||||
<h4 class="app-profile-general-dropdown-heading">{{'APP.EDIT_PROFILE.EMAIL' | translate}}</h4>
|
||||
<p class="app-profile-general-dropdown-details" *ngIf="contactSectionButtonsToggle">{{personDetails?.company?.email}}</p>
|
||||
<input type="text" value="" *ngIf="!contactSectionButtonsToggle" formControlName="companyEmail"
|
||||
class="app-profile-general-dropdown-input-details app-selected" aria-describedby="app-view-profile-company-email-error-message">
|
||||
<mat-error class="app-error-message" *ngIf="profileForm.get('companyEmail').invalid" role="alert"
|
||||
id="app-view-profile-company-email-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
@if (contactSectionButtonsToggle) {
|
||||
<p class="app-profile-general-dropdown-details">{{personDetails?.company?.email}}</p>
|
||||
} @else {
|
||||
<input
|
||||
type="text"
|
||||
value=""
|
||||
formControlName="companyEmail"
|
||||
class="app-profile-general-dropdown-input-details app-selected"
|
||||
aria-describedby="app-view-profile-company-email-error-message">
|
||||
}
|
||||
@if (profileForm.controls['companyEmail'].errors) {
|
||||
<mat-error class="app-error-message" role="alert" id="app-view-profile-company-email-error-message">
|
||||
{{ 'APP.EDIT_PROFILE.INVALID_INPUT' | translate }}
|
||||
</mat-error>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@for (section of sections; track $index) {
|
||||
<adf-dynamic-component [id]="section.component"/>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -43,6 +43,7 @@ app-view-profile {
|
||||
}
|
||||
|
||||
.app-profile-general-icon {
|
||||
padding: 0 0.5rem 0 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -52,7 +53,16 @@ app-view-profile {
|
||||
|
||||
.app-profile-general {
|
||||
display: flex;
|
||||
padding-left: 1rem;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
|
||||
.app-general-edit {
|
||||
color: var(--adf-theme-foreground-text-color-054);
|
||||
}
|
||||
|
||||
.app-general-cancel-btn {
|
||||
color: var(--adf-metadata-action-button-clear-color);
|
||||
}
|
||||
}
|
||||
|
||||
.app-profile-general-bottom-radius {
|
||||
@@ -62,48 +72,12 @@ app-view-profile {
|
||||
|
||||
.app-profile-general-section {
|
||||
display: flex;
|
||||
width: 60%;
|
||||
padding-top: 1rem;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.app-general-title {
|
||||
margin-left: 0.6rem;
|
||||
margin-top: 4px;
|
||||
letter-spacing: 0.5px;
|
||||
}
|
||||
|
||||
.app-general-edit-btn {
|
||||
width: 60%;
|
||||
text-align: end;
|
||||
|
||||
.app-general-edit {
|
||||
background: var(--theme-grey-text-background-color);
|
||||
height: 30px;
|
||||
margin: 1rem;
|
||||
}
|
||||
|
||||
.app-general-cancel-btn {
|
||||
height: 30px;
|
||||
margin: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
background-color: var(--theme-grey-text-background-color);
|
||||
padding-top: 0.25px;
|
||||
}
|
||||
|
||||
.app-general-save-btn {
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
margin: 1rem;
|
||||
margin-left: 0.5rem;
|
||||
color: var(--theme-white-background);
|
||||
background-color: var(--theme-blue-button-color);
|
||||
font-weight: 600;
|
||||
}
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.app-divider {
|
||||
border-top-width: 2px;
|
||||
border-top-width: 1px;
|
||||
border-top-color: var(--theme-grey-background-color);
|
||||
padding-left: -1px;
|
||||
padding-right: 1px;
|
||||
@@ -116,10 +90,6 @@ app-view-profile {
|
||||
box-shadow: 0 0 2px var(--theme-blue-button-color);
|
||||
}
|
||||
|
||||
.app-general-edit:hover {
|
||||
background: var(--theme-grey-hover-background-color);
|
||||
}
|
||||
|
||||
.app-general-dropdown-divider {
|
||||
border-top-color: var(--theme-grey-divider-color);
|
||||
}
|
||||
@@ -183,7 +153,7 @@ app-view-profile {
|
||||
}
|
||||
|
||||
.app-profile-contact-row {
|
||||
margin: 2rem 0 5rem 2rem;
|
||||
margin: 2rem 0 0 2rem;
|
||||
width: 70%;
|
||||
border: 1px solid var(--theme-grey-background-color);
|
||||
border-radius: 1rem;
|
||||
|
||||
+20
-16
@@ -25,13 +25,13 @@
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { ViewProfileComponent } from './view-profile.component';
|
||||
import { AppTestingModule } from '../../testing/app-testing.module';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, Subject } from 'rxjs';
|
||||
import { AppService } from '@alfresco/aca-shared';
|
||||
import { BehaviorSubject, of, Subject } from 'rxjs';
|
||||
import { AppExtensionService, AppService } from '@alfresco/aca-shared';
|
||||
import { UnitTestingUtils } from '@alfresco/adf-core';
|
||||
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
|
||||
import { HarnessLoader } from '@angular/cdk/testing';
|
||||
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
|
||||
|
||||
describe('ViewProfileComponent', () => {
|
||||
let fixture: ComponentFixture<ViewProfileComponent>;
|
||||
@@ -39,6 +39,7 @@ describe('ViewProfileComponent', () => {
|
||||
let router: Router;
|
||||
let unitTestingUtils: UnitTestingUtils;
|
||||
let loader: HarnessLoader;
|
||||
let appExtensionService: AppExtensionService;
|
||||
|
||||
const appServiceMock = {
|
||||
toggleAppNavBar$: new Subject(),
|
||||
@@ -61,6 +62,7 @@ describe('ViewProfileComponent', () => {
|
||||
router = TestBed.inject(Router);
|
||||
loader = TestbedHarnessEnvironment.loader(fixture);
|
||||
unitTestingUtils = new UnitTestingUtils(fixture.debugElement, loader);
|
||||
appExtensionService = TestBed.inject(AppExtensionService);
|
||||
router.initialNavigation();
|
||||
});
|
||||
|
||||
@@ -71,7 +73,7 @@ describe('ViewProfileComponent', () => {
|
||||
|
||||
it('should toggle the appService toggleAppNavBar$ Subject', () => {
|
||||
spyOn(appServiceMock.toggleAppNavBar$, 'next');
|
||||
component.toggleClick();
|
||||
component.toggleNavigationMenu();
|
||||
expect(appServiceMock.toggleAppNavBar$.next).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -156,8 +158,7 @@ describe('ViewProfileComponent', () => {
|
||||
component.generalSectionDropdown = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const generalToggleIcon = fixture.debugElement.query(By.css('#toggle-general-dropdown'));
|
||||
generalToggleIcon.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#general-dropdown button');
|
||||
|
||||
expect(component.toggleGeneralDropdown).toHaveBeenCalled();
|
||||
expect(component.generalSectionButtonsToggle).toBe(true);
|
||||
@@ -168,8 +169,7 @@ describe('ViewProfileComponent', () => {
|
||||
component.contactSectionDropdown = false;
|
||||
fixture.detectChanges();
|
||||
|
||||
const contactToggleIcon = fixture.debugElement.query(By.css('#toggle-contact-dropdown'));
|
||||
contactToggleIcon.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#contact-dropdown button');
|
||||
|
||||
expect(component.toggleContactDropdown).toHaveBeenCalled();
|
||||
expect(component.contactSectionButtonsToggle).toBe(true);
|
||||
@@ -179,12 +179,10 @@ describe('ViewProfileComponent', () => {
|
||||
spyOn(component, 'toggleGeneralButtons').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const generalEditButton = fixture.debugElement.query(By.css('#general-edit-button'));
|
||||
generalEditButton.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#general-dropdown .app-general-edit');
|
||||
fixture.detectChanges();
|
||||
|
||||
const generalCancelButton = fixture.debugElement.query(By.css('#general-cancel-button'));
|
||||
generalCancelButton.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#general-dropdown .app-general-cancel-btn');
|
||||
|
||||
expect(component.toggleGeneralButtons).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
@@ -193,12 +191,10 @@ describe('ViewProfileComponent', () => {
|
||||
spyOn(component, 'toggleContactButtons').and.callThrough();
|
||||
fixture.detectChanges();
|
||||
|
||||
const contactEditButton = fixture.debugElement.query(By.css('#contact-edit-button'));
|
||||
contactEditButton.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#contact-dropdown .app-general-edit');
|
||||
fixture.detectChanges();
|
||||
|
||||
const contactCancelButton = fixture.debugElement.query(By.css('#contact-cancel-button'));
|
||||
contactCancelButton.triggerEventHandler('click', null);
|
||||
unitTestingUtils.clickByCSS('#contact-dropdown .app-general-cancel-btn');
|
||||
|
||||
expect(component.toggleContactButtons).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
@@ -209,4 +205,12 @@ describe('ViewProfileComponent', () => {
|
||||
|
||||
expect(router.navigate).toHaveBeenCalledWith(['/personal-files'], { replaceUrl: true });
|
||||
});
|
||||
|
||||
it('should render additional user profile sections if provided', () => {
|
||||
spyOn(appExtensionService, 'getUserProfileSections').and.returnValue(of([{ id: 'test-section' }]));
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(component.sections.length).toBe(1);
|
||||
expect(unitTestingUtils.getByDirective(DynamicExtensionComponent)).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,8 +27,8 @@ import { PeopleApi, Person } from '@alfresco/js-api';
|
||||
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
|
||||
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { AppService } from '@alfresco/aca-shared';
|
||||
import { Observable, take, throwError } from 'rxjs';
|
||||
import { AppExtensionService, AppService, UserProfileSection } from '@alfresco/aca-shared';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
@@ -36,9 +36,19 @@ import { TranslatePipe } from '@ngx-translate/core';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
||||
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
|
||||
|
||||
@Component({
|
||||
imports: [CommonModule, TranslatePipe, ReactiveFormsModule, MatButtonModule, MatIconModule, MatDividerModule, MatFormFieldModule],
|
||||
imports: [
|
||||
CommonModule,
|
||||
TranslatePipe,
|
||||
ReactiveFormsModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatDividerModule,
|
||||
MatFormFieldModule,
|
||||
DynamicExtensionComponent
|
||||
],
|
||||
selector: 'app-view-profile',
|
||||
templateUrl: './view-profile.component.html',
|
||||
styleUrls: ['./view-profile.component.scss'],
|
||||
@@ -60,13 +70,15 @@ export class ViewProfileComponent implements OnInit {
|
||||
contactSectionDropdown = false;
|
||||
contactSectionButtonsToggle = true;
|
||||
appNavNarMode$: Observable<'collapsed' | 'expanded'>;
|
||||
sections: UserProfileSection[] = [];
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
apiService: AlfrescoApiService,
|
||||
private appService: AppService
|
||||
private readonly apiService: AlfrescoApiService,
|
||||
private readonly appService: AppService,
|
||||
private readonly extensionService: AppExtensionService
|
||||
) {
|
||||
this.peopleApi = new PeopleApi(apiService.getInstance());
|
||||
this.peopleApi = new PeopleApi(this.apiService.getInstance());
|
||||
this.appNavNarMode$ = appService.appNavNarMode$.pipe(takeUntilDestroyed());
|
||||
}
|
||||
|
||||
@@ -81,9 +93,14 @@ export class ViewProfileComponent implements OnInit {
|
||||
.catch((error) => {
|
||||
throwError(error);
|
||||
});
|
||||
|
||||
this.extensionService
|
||||
.getUserProfileSections()
|
||||
.pipe(take(1))
|
||||
.subscribe((sections) => (this.sections = sections));
|
||||
}
|
||||
|
||||
toggleClick() {
|
||||
toggleNavigationMenu() {
|
||||
this.appService.toggleAppNavBar$.next();
|
||||
}
|
||||
|
||||
@@ -112,10 +129,6 @@ export class ViewProfileComponent implements OnInit {
|
||||
|
||||
toggleGeneralDropdown() {
|
||||
this.generalSectionDropdown = !this.generalSectionDropdown;
|
||||
|
||||
if (!this.generalSectionDropdown) {
|
||||
this.generalSectionButtonsToggle = true;
|
||||
}
|
||||
}
|
||||
|
||||
toggleGeneralButtons() {
|
||||
@@ -143,10 +156,6 @@ export class ViewProfileComponent implements OnInit {
|
||||
|
||||
toggleLoginDropdown() {
|
||||
this.loginSectionDropdown = !this.loginSectionDropdown;
|
||||
|
||||
if (!this.loginSectionDropdown) {
|
||||
this.loginSectionButtonsToggle = true;
|
||||
}
|
||||
}
|
||||
|
||||
toggleLoginButtons() {
|
||||
@@ -161,10 +170,6 @@ export class ViewProfileComponent implements OnInit {
|
||||
|
||||
toggleContactDropdown() {
|
||||
this.contactSectionDropdown = !this.contactSectionDropdown;
|
||||
|
||||
if (!this.contactSectionDropdown) {
|
||||
this.contactSectionButtonsToggle = true;
|
||||
}
|
||||
}
|
||||
|
||||
toggleContactButtons() {
|
||||
|
||||
@@ -1196,6 +1196,18 @@ describe('app.evaluators', () => {
|
||||
expect(app.isSmartFolder(context)).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
describe('isSSOEnabled', () => {
|
||||
it('should return true if sso is enabled', () => {
|
||||
context.appConfig = { get: () => 'OAUTH' } as any;
|
||||
expect(app.isSSOEnabled(context)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if sso is not enabled', () => {
|
||||
context.appConfig = { get: () => 'basic' } as any;
|
||||
expect(app.isSSOEnabled(context)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Versions compatibility', () => {
|
||||
|
||||
@@ -560,3 +560,5 @@ export const canDisplayKnowledgeRetrievalButton = (context: AcaRuleContext): boo
|
||||
navigation.isRecentFiles(context) ||
|
||||
navigation.isFavorites(context) ||
|
||||
((navigation.isSearchResults(context) || navigation.isLibraryContent(context)) && !navigation.isLibraries(context)));
|
||||
|
||||
export const isSSOEnabled = (context: AcaRuleContext): boolean => context.appConfig.get('authType') === 'OAUTH';
|
||||
|
||||
@@ -34,3 +34,7 @@ export interface Badge extends Partial<Pick<ContentActionRef, 'component' | 'act
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
}
|
||||
|
||||
export interface UserProfileSection extends Partial<Pick<ContentActionRef, 'component' | 'rules'>> {
|
||||
id: string;
|
||||
}
|
||||
|
||||
@@ -1682,6 +1682,41 @@ describe('AppExtensionService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should get custom user profile sections from config', (done) => {
|
||||
extensions.setEvaluators({
|
||||
'action.enabled': () => true
|
||||
});
|
||||
|
||||
applyConfig({
|
||||
...defaultConfigMock,
|
||||
features: {
|
||||
userProfileSections: [
|
||||
{
|
||||
id: 'section1-id',
|
||||
component: 'testComponent1',
|
||||
rules: {
|
||||
visible: 'action.enabled'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'section2-id',
|
||||
component: 'testComponent2',
|
||||
rules: {
|
||||
visible: 'action.enabled'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
service.getUserProfileSections().subscribe((sections) => {
|
||||
expect(sections.length).toBe(2);
|
||||
expect(sections[0].id).toEqual('section1-id');
|
||||
expect(sections[1].id).toEqual('section2-id');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should update sidebar actions correctly', () => {
|
||||
spyOn(loader, 'getContentActions').and.callThrough();
|
||||
service.updateSidebarActions();
|
||||
|
||||
@@ -53,7 +53,7 @@ import { AppConfigService, AuthenticationService, LogService } from '@alfresco/a
|
||||
import { BehaviorSubject, Observable, Subject } from 'rxjs';
|
||||
import { NodeEntry, RepositoryInfo } from '@alfresco/js-api';
|
||||
import { ViewerRules } from '../models/viewer.rules';
|
||||
import { Badge } from '../models/types';
|
||||
import { Badge, UserProfileSection } from '../models/types';
|
||||
import { NodePermissionService } from '../services/node-permission.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { SearchCategory } from '@alfresco/adf-content-services';
|
||||
@@ -92,6 +92,7 @@ export class AppExtensionService implements RuleContext {
|
||||
private _filesDocumentListPreset = new BehaviorSubject<Array<DocumentListPresetRef>>([]);
|
||||
private _customMetadataPanels = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||
private _bulkActions = new BehaviorSubject<Array<ContentActionRef>>([]);
|
||||
private readonly _userProfileSections = new BehaviorSubject<Array<UserProfileSection>>([]);
|
||||
|
||||
documentListPresets: {
|
||||
libraries: Array<DocumentListPresetRef>;
|
||||
@@ -169,6 +170,7 @@ export class AppExtensionService implements RuleContext {
|
||||
this._openWithActions.next(this.loader.getContentActions(config, 'features.viewer.openWith'));
|
||||
this._createActions.next(this.loader.getElements<ContentActionRef>(config, 'features.create'));
|
||||
this._badges.next(this.loader.getElements<Badge>(config, 'features.badges'));
|
||||
this._userProfileSections.next(this.loader.getElements<UserProfileSection>(config, 'features.userProfileSections'));
|
||||
this._filesDocumentListPreset.next(this.getDocumentListPreset(config, 'files'));
|
||||
this._customMetadataPanels.next(this.loader.getElements<ContentActionRef>(config, 'features.customMetadataPanels'));
|
||||
this._bulkActions.next(this.loader.getElements<ContentActionRef>(config, 'features.bulk-actions'));
|
||||
@@ -384,6 +386,10 @@ export class AppExtensionService implements RuleContext {
|
||||
return this._badges.pipe(map((badges) => badges.filter((badge) => this.evaluateRule(badge.rules.visible, node))));
|
||||
}
|
||||
|
||||
getUserProfileSections(): Observable<Array<UserProfileSection>> {
|
||||
return this._userProfileSections.pipe(map((sections) => sections.filter((section) => this.evaluateRule(section.rules.visible))));
|
||||
}
|
||||
|
||||
getCustomMetadataPanels(node: NodeEntry): Observable<Array<ContentActionRef>> {
|
||||
return this._customMetadataPanels.pipe(map((panels) => panels.filter((panel) => this.evaluateRule(panel.rules.visible, node))));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user