👽 Angular 14 rebase 👽 (#7769)

* fix after rebase

* new release strategy for ng next

Signed-off-by: eromano <eugenioromano16@gmail.com>

* peer dep

Signed-off-by: eromano <eugenioromano16@gmail.com>

* Angular 14

fix unit test and storybook

Signed-off-by: eromano <eugenioromano16@gmail.com>

fix after rebase

Signed-off-by: eromano <eugenioromano16@gmail.com>

update pkg.json

Signed-off-by: eromano <eugenioromano16@gmail.com>

missing dep

Signed-off-by: eromano <eugenioromano16@gmail.com>

Fix mistake and missing code

Dream....build only affected libs

Add utility run commands

* Use nx command to run affected tests

* Fix nx test core

fix content tests

Run unit with watch false

core test fixes

reduce test warnings

Fix process cloud unit

Fix adf unit test

Fix lint process cloud

Disable lint next line

Use right core path

Fix insights unit

fix linting insights

Fix process-services unit

fix the extensions test report

fix test warnings

Fix content unit

Fix bunch of content unit

* Produce an adf alpha of 14

* hopefully fixing the content

* Push back the npm publish

* Remove flaky unit

* Fix linting

* Make the branch as root

* Get rid of angualar13

* Remove the travis depth

* Fixing version for npm

* Enabling cache for unit and build

* Fix scss for core and paths

Copy i18 and asset by using ng-packager

Export the theming alias and fix path

Use ng-package to copy assets process-services-cloud

Use ng-package to copy assets process-services

Use ng-package to copy assets content-services

Use ng-package to copy assets insights

* feat: fix api secondary entry point

* fix storybook rebase

* Move dist under dist/libs from lib/dist

* Fix the webstyle

* Use only necessary nrwl deps and improve lint

* Fix unit for libs

* Convert lint.sh to targets - improve performance

* Use latest of angular

* Align alfresco-js-api

Signed-off-by: eromano <eugenioromano16@gmail.com>
Co-authored-by: eromano <eugenioromano16@gmail.com>
Co-authored-by: Mikolaj Serwicki <mikolaj.serwicki@hyland.com>
Co-authored-by: Tomasz <tomasz.gnyp@hyland.com>
This commit is contained in:
Maurizio Vitale
2022-08-25 10:50:30 +01:00
committed by GitHub
parent 53bc5aab2c
commit 1fa81962a0
1351 changed files with 26853 additions and 11958 deletions

View File

@@ -0,0 +1,11 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

View File

@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';
import { ExtensionRef } from '@alfresco/adf-extensions';
@Component({
selector: 'adf-about-extension-list',
templateUrl: './about-extension-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AboutExtensionListComponent {
columns = [
{
columnDef: 'name',
header: 'ABOUT.PLUGINS.NAME',
cell: (row: ExtensionRef) => `${row.$name}`
},
{
columnDef: 'version',
header: 'ABOUT.PLUGINS.VERSION',
cell: (row: ExtensionRef) => `${row.$version}`
}
];
displayedColumns = this.columns.map((x) => x.columnDef);
@Input()
data: Array<ExtensionRef> = [];
}

View File

@@ -0,0 +1,14 @@
<div class="adf-github-link-container">
<header data-automation-id="adf-github-source-code-title">{{ 'ABOUT.SOURCE_CODE.TITLE' | translate }}</header>
<mat-card class="mat-elevation-z0">
<h3 data-automation-id="adf-github-app-title">{{application}}</h3>
<p *ngIf="version" data-automation-id="adf-github-version">{{ 'ABOUT.VERSION' | translate }}: {{ version }}</p>
<div *ngIf="url">
<small>{{ 'ABOUT.SOURCE_CODE.DESCRIPTION' | translate }}</small>
<div data-automation-id="adf-github-url">
<a [href]="url" target="_blank">{{url}}</a>
</div>
</div>
</mat-card>
</div>

View File

@@ -0,0 +1,3 @@
.adf-github-link-container {
padding: 10px;
}

View File

@@ -0,0 +1,77 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CoreTestingModule } from '../../testing/core.testing.module';
import { setupTestBed } from '../../testing/setup-test-bed';
import { AboutGithubLinkComponent } from './about-github-link.component';
import { aboutGithubDetails } from '../about.mock';
import { TranslateModule } from '@ngx-translate/core';
describe('AboutGithubLinkComponent', () => {
let fixture: ComponentFixture<AboutGithubLinkComponent>;
let component: AboutGithubLinkComponent;
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule
]
});
beforeEach(() => {
fixture = TestBed.createComponent(AboutGithubLinkComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
it('Should fetch appName for app.config and display as title', async () => {
component.application = 'mock-application-name';
fixture.detectChanges();
await fixture.whenStable();
const titleElement = fixture.nativeElement.querySelector('[data-automation-id="adf-github-app-title"]');
expect(titleElement === null).toBeFalsy();
expect(titleElement.innerText).toEqual('mock-application-name');
});
it('should display version', async () => {
component.version = aboutGithubDetails.version;
fixture.detectChanges();
await fixture.whenStable();
const version = fixture.nativeElement.querySelector('[data-automation-id="adf-github-version"]');
expect(version.innerText).toEqual('ABOUT.VERSION: 0.0.7');
});
it('should display adf github link as default if url is not specified', async () => {
fixture.detectChanges();
await fixture.whenStable();
const githubUrl = fixture.nativeElement.querySelector('[data-automation-id="adf-github-url"]');
expect(githubUrl.innerText).toEqual(aboutGithubDetails.defualrUrl);
});
it('should display the github link', async () => {
component.url = aboutGithubDetails.url;
fixture.detectChanges();
await fixture.whenStable();
const githubUrl = fixture.nativeElement.querySelector('[data-automation-id="adf-github-url"]');
expect(githubUrl.innerText).toEqual(aboutGithubDetails.url);
});
});

View File

@@ -0,0 +1,39 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, Input, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'adf-about-github-link',
templateUrl: './about-github-link.component.html',
encapsulation: ViewEncapsulation.None
})
export class AboutGithubLinkComponent {
/** Commit corresponding to the version of ADF to be used. */
@Input()
url = 'https://github.com/Alfresco/alfresco-ng2-components/commits/';
/** Current version of the app running */
@Input()
version: string = '';
/** Title of app running */
@Input()
application: string = '';
constructor() {}
}

View File

@@ -0,0 +1,11 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

View File

@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';
import { LicenseData } from '../interfaces';
@Component({
selector: 'adf-about-license-list',
templateUrl: './about-license-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AboutLicenseListComponent {
columns = [
{
columnDef: 'property',
header: 'ABOUT.LICENSE.PROPERTY',
cell: (row: LicenseData) => `${row.property}`
},
{
columnDef: 'value',
header: 'ABOUT.LICENSE.VALUE',
cell: (row: LicenseData) => `${row.value}`
}
];
displayedColumns = this.columns.map((x) => x.columnDef);
@Input()
data: LicenseData[] = [];
}

View File

@@ -0,0 +1,11 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

View File

@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';
import { ModuleInfo } from '@alfresco/js-api';
@Component({
selector: 'adf-about-module-list',
templateUrl: './module-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ModuleListComponent {
columns = [
{
columnDef: 'title',
header: 'ABOUT.MODULES.NAME',
cell: (row: ModuleInfo) => `${row.title}`
},
{
columnDef: 'version',
header: 'ABOUT.MODULES.VERSION',
cell: (row: ModuleInfo) => `${row.version}`
}
];
displayedColumns = this.columns.map((x) => x.columnDef);
@Input()
data: Array<ModuleInfo> = [];
}

View File

@@ -0,0 +1,11 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

View File

@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';
import { PackageInfo } from '../interfaces';
@Component({
selector: 'adf-about-package-list',
templateUrl: './package-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PackageListComponent {
columns = [
{
columnDef: 'title',
header: 'ABOUT.PACKAGES.NAME',
cell: (row: PackageInfo) => `${row.name}`
},
{
columnDef: 'version',
header: 'ABOUT.PACKAGES.VERSION',
cell: (row: PackageInfo) => `${row.version}`
}
];
displayedColumns = this.columns.map((x) => x.columnDef);
@Input()
data: Array<PackageInfo> = [];
}

View File

@@ -0,0 +1,67 @@
<header data-automation-id="adf-about-product-version-title">{{ 'ABOUT.VERSIONS.TITLE' | translate }}</header>
<mat-card class="mat-elevation-z0">
<ng-container *ngIf="process" data-automation-id="adf-about-bpm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.PROCESS_SERVICE' | translate }}</div>
<p data-automation-id="adf-about-bpm-version">
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ process.majorVersion }}.{{
process.minorVersion }}.{{ process.revisionVersion }}
</p>
</article>
</ng-container>
<br>
<ng-container *ngIf="repository" data-automation-id="adf-about-ecm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.CONTENT_SERVICE' | translate }}</div>
<p data-automation-id="adf-about-ecm-edition">
{{ 'ABOUT.VERSIONS.LABELS.EDITION' | translate }}: {{ repository.edition }}
</p>
<p data-automation-id="adf-about-ecm-version">
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ repository.version.display }}
</p>
</article>
</ng-container>
<br>
<ng-container *ngIf="modeling$ | async as modeling" data-automation-id="adf-about-ecm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.MODELING_SERVICE' | translate }}</div>
<p>
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ modeling.version }}
</p>
</article>
</ng-container>
<br>
<ng-container *ngIf="deployment$| async as deployment" data-automation-id="adf-about-ecm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.DEPLOYMENT_SERVICE' | translate }}</div>
<p>
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ deployment.version }}
</p>
</article>
</ng-container>
<br>
<ng-container *ngIf="rb$ | async as rb" data-automation-id="adf-about-ecm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.RB' | translate }}</div>
<p>
{{ 'ABOUT.VERSIONS.LABELS.EDITION' | translate }}: {{ rb.artifact }}
</p>
<p>
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ rb.version }}
</p>
</article>
</ng-container>
<br>
<ng-container *ngIf="query$ | async as query" data-automation-id="adf-about-ecm-service">
<article>
<div>{{ 'ABOUT.VERSIONS.QUERY_SERVICE' | translate }}</div>
<p>
{{ 'ABOUT.VERSIONS.LABELS.VERSION' | translate }}: {{ query.version }}
</p>
</article>
</ng-container>
</mat-card>

View File

@@ -0,0 +1,67 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, Input, ViewEncapsulation } from '@angular/core';
import { RepositoryInfo } from '@alfresco/js-api';
import { Observable } from 'rxjs';
import { BpmProductVersionModel } from '../../models/product-version.model';
import { AaeInfoService, ActivitiDependencyInfo } from '../services/aae-info.service';
import { AppConfigService } from '../../app-config/app-config.service';
@Component({
selector: 'adf-about-platform-version',
templateUrl: './about-platform-version.component.html',
encapsulation: ViewEncapsulation.None
})
export class AboutPlatformVersionComponent {
/** repository info. */
@Input()
repository: RepositoryInfo = null;
/** process info. */
@Input()
process: BpmProductVersionModel = null;
modeling$: Observable<ActivitiDependencyInfo>;
deployment$: Observable<ActivitiDependencyInfo>;
rb$: Observable<ActivitiDependencyInfo>;
query$: Observable<ActivitiDependencyInfo>;
constructor(private aaeInfoService: AaeInfoService, private appConfigService: AppConfigService) {
this.modelingInfo();
this.deploymentInfo();
this.rbInfo();
}
modelingInfo() {
this.modeling$ = this.aaeInfoService.getServiceVersion('modeling-service');
}
deploymentInfo() {
this.deployment$ = this.aaeInfoService.getServiceVersion('deployment-service');
}
rbInfo() {
this.rb$ = this.aaeInfoService.getServiceVersion(`${this.appConfigService.get('oauth2.clientId')}/rb`);
}
queryInfo() {
this.query$ = this.aaeInfoService.getServiceVersion(`${this.appConfigService.get('oauth2.clientId')}/query`);
}
}

View File

@@ -0,0 +1,11 @@
<div class="adf-github-link-container">
<header data-automation-id="adf-about-setting-title">{{ 'ABOUT.SERVER_SETTINGS.TITLE' | translate }}</header>
<mat-card class="mat-elevation-z0">
<p data-automation-id="adf-process-service-host">
{{ 'ABOUT.SERVER_SETTINGS.PROCESS_SERVICE_HOST' | translate: {value: bpmHost} }}
</p>
<p data-automation-id="adf-content-service-host">
{{ 'ABOUT.SERVER_SETTINGS.CONTENT_SERVICE_HOST' | translate: {value: ecmHost} }}
</p>
</mat-card>
</div>

View File

@@ -0,0 +1,3 @@
.adf-github-link-container {
padding: 10px;
}

View File

@@ -0,0 +1,58 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CoreTestingModule } from '../../testing/core.testing.module';
import { setupTestBed } from '../../testing/setup-test-bed';
import { AboutServerSettingsComponent } from './about-server-settings.component';
import { AppConfigService } from '../../app-config/app-config.service';
import { aboutGithubDetails } from '../about.mock';
import { TranslateModule } from '@ngx-translate/core';
describe('AboutServerSettingsComponent', () => {
let fixture: ComponentFixture<AboutServerSettingsComponent>;
let component: AboutServerSettingsComponent;
let appConfigService: AppConfigService;
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule
]
});
beforeEach(() => {
fixture = TestBed.createComponent(AboutServerSettingsComponent);
component = fixture.componentInstance;
appConfigService = TestBed.inject(AppConfigService);
appConfigService.config = Object.assign(appConfigService.config, {
ecmHost: aboutGithubDetails.ecmHost,
bpmHost: aboutGithubDetails.bpmHost
});
fixture.detectChanges();
});
afterEach(() => {
fixture.destroy();
});
it('should fetch process and content hosts from the app.config.json file', async () => {
await fixture.whenStable();
expect(component.bpmHost).toEqual(aboutGithubDetails.bpmHost);
expect(component.ecmHost).toEqual(aboutGithubDetails.ecmHost);
});
});

View File

@@ -0,0 +1,36 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
@Component({
selector: 'adf-about-server-settings',
templateUrl: './about-server-settings.component.html',
encapsulation: ViewEncapsulation.None
})
export class AboutServerSettingsComponent implements OnInit {
ecmHost = '';
bpmHost = '';
constructor(private appConfig: AppConfigService) {}
ngOnInit() {
this.ecmHost = this.appConfig.get<string>(AppConfigValues.ECMHOST);
this.bpmHost = this.appConfig.get<string>(AppConfigValues.BPMHOST);
}
}

View File

@@ -0,0 +1,11 @@
<mat-table [dataSource]="data">
<ng-container *ngFor="let column of columns" [matColumnDef]="column.columnDef">
<mat-header-cell *matHeaderCellDef>
{{ column.header | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let row">{{ column.cell(row) }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
</mat-table>

View File

@@ -0,0 +1,45 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ViewEncapsulation, ChangeDetectionStrategy, Input } from '@angular/core';
import { StatusData } from '../interfaces';
@Component({
selector: 'adf-about-status-list',
templateUrl: './about-status-list.component.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class AboutStatusListComponent {
columns = [
{
columnDef: 'property',
header: 'ABOUT.STATUS.PROPERTY',
cell: (row: StatusData) => `${row.property}`
},
{
columnDef: 'value',
header: 'ABOUT.STATUS.VALUE',
cell: (row: StatusData) => `${row.value}`
}
];
displayedColumns = this.columns.map((x) => x.columnDef);
@Input()
data: StatusData[] = [];
}

View File

@@ -0,0 +1,41 @@
<div class="adf-about-container">
<adf-about-github-link *ngIf="dev" [application]="pkg.application" [url]="url" ></adf-about-github-link>
<adf-about-server-settings *ngIf="dev" ></adf-about-server-settings>
<adf-about-platform-version [repository]="repository"
[process]="bpmVersion">
</adf-about-platform-version>
<ng-container *ngIf="repository">
<article *ngIf="licenseEntries">
<header>{{ 'ABOUT.LICENSE.TITLE' | translate }}</header>
<adf-about-license-list [data]="licenseEntries"></adf-about-license-list>
</article>
<article *ngIf="statusEntries">
<header>{{ 'ABOUT.STATUS.TITLE' | translate }}</header>
<adf-about-status-list [data]="statusEntries"></adf-about-status-list>
</article>
<article *ngIf="repository?.modules">
<header>{{ 'ABOUT.MODULES.TITLE' | translate }}</header>
<adf-about-module-list [data]="repository.modules"></adf-about-module-list>
</article>
</ng-container>
<article *ngIf="dependencyEntries && dev" >
<header>{{ 'ABOUT.PACKAGES.TITLE' | translate }}</header>
<adf-about-package-list [data]="dependencyEntries"></adf-about-package-list>
</article>
<ng-container *ngIf="extensions$ | async as extensions">
<article *ngIf="extensions.length > 0">
<header>{{ 'ABOUT.PLUGINS.TITLE' | translate }}</header>
<adf-about-extension-list [data]="extensions"></adf-about-extension-list>
</article>
</ng-container>
</div>

View File

@@ -0,0 +1,9 @@
adf-about {
.adf-about-container {
margin: 10px 0 5px 2px;
}
header {
margin: 5px;
}
}

View File

@@ -0,0 +1,67 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Meta, moduleMetadata, Story } from '@storybook/angular';
import { AboutComponent } from './about.component';
import { AboutModule } from './about.module';
import { AuthenticationService, DiscoveryApiService } from '../services';
import { AppConfigServiceMock, AuthenticationMock } from '../mock';
import { DiscoveryApiServiceMock } from '../mock/discovery-api.service.mock';
import { AppExtensionService, AppExtensionServiceMock } from '@alfresco/adf-extensions';
import { AppConfigService } from '../app-config/app-config.service';
import { CoreStoryModule } from '../testing/core.story.module';
export default {
component: AboutComponent,
title: 'Core/Components/About',
decorators: [
moduleMetadata({
imports: [CoreStoryModule, AboutModule],
providers: [
{ provide: AuthenticationService, useClass: AuthenticationMock },
{ provide: DiscoveryApiService, useClass: DiscoveryApiServiceMock },
{ provide: AppExtensionService, useClass: AppExtensionServiceMock },
{ provide: AppConfigService, useClass: AppConfigServiceMock }
]
})
]
} as Meta;
const template: Story<AboutComponent> = (args: AboutComponent) => ({
props: args
});
export const devAbout = template.bind({});
devAbout.args = {
dev: true,
pkg: {
name: 'My Storybook App', commit: 'my-commit-value', version: '1.0.0', dependencies: {
'@alfresco/adf-content-services': '4.7.0',
'@alfresco/adf-core': '4.7.0',
'@alfresco/adf-extensions': '4.7.0',
'@alfresco/adf-process-services': '4.7.0',
'@alfresco/adf-process-services-cloud': '4.7.0',
'@alfresco/js-api': '4.7.0-3976'
}
}
};
export const prodAbout = template.bind({});
prodAbout.args = {
dev: false
};

View File

@@ -0,0 +1,118 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { AppExtensionService, ExtensionRef } from '@alfresco/adf-extensions';
import { Observable } from 'rxjs';
import { AppConfigService } from '../app-config/app-config.service';
import { RepositoryInfo } from '@alfresco/js-api';
import { BpmProductVersionModel } from '../models/product-version.model';
import { AuthenticationService } from '../services/authentication.service';
import { DiscoveryApiService } from '../services/discovery-api.service';
import { LicenseData, PackageInfo, StatusData } from './interfaces';
@Component({
selector: 'adf-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class AboutComponent implements OnInit {
repository: RepositoryInfo = null;
bpmVersion: BpmProductVersionModel = null;
statusEntries: StatusData[];
licenseEntries: LicenseData[];
dependencyEntries: PackageInfo[] = [];
url: string;
version: string;
dependencies: string;
application: string;
/** If active show more information about the app and the platform useful in debug. */
@Input() dev: boolean = false;
/** pkg json. */
@Input() pkg: any;
/** Regular expression for filtering dependencies packages. */
@Input() regexp = '^(@alfresco)';
extensions$: Observable<ExtensionRef[]>;
constructor(private authService: AuthenticationService,
private discovery: DiscoveryApiService,
private appExtensions: AppExtensionService,
private appConfigService: AppConfigService) {
this.extensions$ = this.appExtensions.references$;
this.application = this.appConfigService.get<string>(
'application.name'
);
}
ngOnInit() {
this.url = `https://github.com/Alfresco/${this.pkg?.name}/commits/${this.pkg?.commit}`;
this.version = this.pkg?.version;
this.dependencies = this.pkg?.dependencies;
if (this.dependencies) {
const alfrescoPackages = Object.keys(this.dependencies).filter((val) => new RegExp(this.regexp).test(val));
alfrescoPackages.forEach((val) => {
this.dependencyEntries.push({
name: val,
version: (this.dependencies[val])
});
});
}
if (this.authService.isEcmLoggedIn()) {
this.setECMInfo();
}
if (this.authService.isBpmLoggedIn()) {
this.setBPMInfo();
}
}
setECMInfo() {
this.discovery.getEcmProductInfo().subscribe((repository) => {
this.repository = repository;
this.statusEntries = Object.keys(repository.status).map((key) => ({
property: key,
value: repository.status[key]
}));
if (repository.license) {
this.licenseEntries = Object.keys(repository.license).map((key) => ({
property: key,
value: repository.license[key]
}));
}
});
}
setBPMInfo() {
this.discovery.getBpmProductInfo().subscribe((bpmVersion) => {
this.bpmVersion = bpmVersion;
});
}
}

View File

@@ -0,0 +1,120 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 const mockDependencies = {
'@alfresco/mock-core': '3.7.0',
'@alfresco/mock-services': '2.0.0',
'@angular/mock-core': '8.0.0',
'@angular/mock-services': '8.0.0'
};
export const mockPlugins = [
{
$name: 'plugin1',
$version: '1.0.0',
$vendor: 'mockVender-1',
$license: 'MockLicense-2.0',
$runtime: '2.7.0',
$description: 'example plugin'
},
{
$name: 'plugin2',
$version: '1.0.0',
$vendor: 'mockVender-2',
$license: 'MockLicense-3.0',
$runtime: '2.7.0',
$description: 'example plugin 2'
}
];
export const aboutGithubDetails = {
url: 'https://github.com/componany/repository/commits/',
defualrUrl: 'https://github.com/Alfresco/alfresco-ng2-components/commits/',
version: '0.0.7',
ecmHost: 'https://mock.ecmhost.com',
bpmHost: 'https://mock.bpmhost.com',
appName: 'mock-application-name'
};
export const aboutAPSMockDetails = {
revisionVersion: '0',
edition: 'APS',
type: 'bpmSuite',
majorVersion: '1',
minorVersion: '10'
};
export const mockModules: any = {
edition: 'Enterprise',
version: {
major: '6',
minor: '2',
patch: '0',
hotfix: '0',
schema: 13001,
label: 'ra498a911-b5',
display: '6.2.0.0'
},
license: {
issuedAt: '2018-12-20T12:07:31.276+0000',
expiresAt: '2019-05-31T23:00:00.000+0000',
remainingDays: 100,
holder: 'CompanyQA',
mode: 'ENTERPRISE',
entitlements: {
isClusterEnabled: true,
isCryptodocEnabled: true
}
},
status: {
isReadOnly: false,
isAuditEnabled: true,
isQuickShareEnabled: true,
isThumbnailGenerationEnabled: true
},
modules: [
{
id: 'mock-id',
title: 'ABC Repo',
description: 'ABC Repository Extension',
version: '3.2.0',
installState: 'UNKNOWN',
versionMin: '6.1',
versionMax: '999'
},
{
id: 'aos-module-id',
title: 'AOFS Module',
description: 'Allows applications that can talk to a SharePoint server to talk to your Alfresco installation',
version: '1.3.0',
installDate: '2019-02-07T12:26:13.271+0000',
installState: 'INSTALLED',
versionMin: '6.0',
versionMax: '999'
},
{
id: 'mock-saml-repo',
title: 'SAML Repository Module',
description: 'The Repository piece of the Alfresco SAML Module',
version: '1.1.1',
installDate: '2019-02-07T12:26:12.565+0000',
installState: 'INSTALLED',
versionMin: '6.0',
versionMax: '6.99'
}
]
};

View File

@@ -0,0 +1,62 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { MaterialModule } from '../material.module';
import { AboutGithubLinkComponent } from './about-github-link/about-github-link.component';
import { AboutServerSettingsComponent } from './about-server-settings/about-server-settings.component';
import { AboutExtensionListComponent } from './about-extension-list/about-extension-list.component';
import { AboutLicenseListComponent } from './about-license-list/about-license-list.component';
import { PackageListComponent } from './about-package/package-list.component';
import { AboutStatusListComponent } from './about-status-list/about-status-list.component';
import { ModuleListComponent } from './about-module-list/module-list.component';
import { AboutPlatformVersionComponent } from './about-platform-version/about-platform-version.component';
import { AboutComponent } from './about.component';
@NgModule({
imports: [
CommonModule,
MaterialModule,
TranslateModule
],
declarations: [
AboutComponent,
AboutPlatformVersionComponent,
AboutGithubLinkComponent,
AboutServerSettingsComponent,
AboutExtensionListComponent,
AboutLicenseListComponent,
PackageListComponent,
AboutStatusListComponent,
ModuleListComponent
],
exports: [
AboutComponent,
AboutPlatformVersionComponent,
AboutGithubLinkComponent,
AboutServerSettingsComponent,
AboutExtensionListComponent,
AboutLicenseListComponent,
PackageListComponent,
AboutStatusListComponent,
ModuleListComponent
]
})
export class AboutModule {}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './public-api';

View File

@@ -0,0 +1,31 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 interface PackageInfo {
name: string;
version: string;
}
export interface StatusData {
property: string;
value: string;
}
export interface LicenseData {
property: string;
value: string;
}

View File

@@ -0,0 +1,28 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './about-extension-list/about-extension-list.component';
export * from './about-github-link/about-github-link.component';
export * from './about-license-list/about-license-list.component';
export * from './about-module-list/module-list.component';
export * from './about-package/package-list.component';
export * from './about-platform-version/about-platform-version.component';
export * from './about-server-settings/about-server-settings.component';
export * from './about-status-list/about-status-list.component';
export * from './about.component';
export * from './about.module';

View File

@@ -0,0 +1,55 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { AppConfigService } from '../../app-config/app-config.service';
export interface ActivitiDependencyInfo {
artifact: string;
version: string;
activiti: string;
}
@Injectable({
providedIn: 'root'
})
export class AaeInfoService {
contextRoot = '';
constructor(protected httpClient: HttpClient, protected appConfigService: AppConfigService) {
this.contextRoot = appConfigService.get('bpmHost', '');
}
getServiceVersion(serviceName: string): Observable<ActivitiDependencyInfo> {
return this.httpClient.get<any>(`${this.contextRoot}/${serviceName}/actuator/info`).pipe(
map((response: any) => {
let activitiVersion = 'N/A';
if (response.build.activiti) {
activitiVersion = response.build.activiti.version;
}
return {
artifact: response.build.artifact,
version: response.build.version,
activiti: activitiVersion
};
})
);
}
}

View File

@@ -0,0 +1,29 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { ApiClientFactory, Constructor } from '@alfresco/adf-core/api';
import { Injectable } from '@angular/core';
import { AlfrescoApiService } from '../services/alfresco-api.service';
@Injectable()
export class LegacyClientFactory implements ApiClientFactory {
constructor(private alfrescoApiService: AlfrescoApiService) { }
create<T>(apiClass: Constructor<T>): T {
return new apiClass(this.alfrescoApiService.getInstance());
}
}

View File

@@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { API_CLIENT_FACTORY_TOKEN } from '@alfresco/adf-core/api';
import { LegacyClientFactory } from './legacy-api-client.factory';
@NgModule({
providers: [
{ provide: API_CLIENT_FACTORY_TOKEN, useClass: LegacyClientFactory }
]
})
export class LegacyApiClientModule { }

View File

@@ -0,0 +1,34 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AppConfigPipe } from './app-config.pipe';
@NgModule({
imports: [
HttpClientModule
],
declarations: [
AppConfigPipe
],
exports: [
AppConfigPipe
]
})
export class AppConfigModule {
}

View File

@@ -0,0 +1,30 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { AppConfigService } from './app-config.service';
@Pipe({
name: 'adfAppConfig'
})
export class AppConfigPipe implements PipeTransform {
constructor(private config: AppConfigService) {}
transform(value: string, fallback?: any): any {
return this.config.get(value, fallback);
}
}

View File

@@ -0,0 +1,187 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { HttpClient, HttpClientModule } from '@angular/common/http';
import { fakeAsync, TestBed } from '@angular/core/testing';
import { AppConfigService } from './app-config.service';
import { AppConfigModule } from './app-config.module';
import { ExtensionConfig, ExtensionService } from '@alfresco/adf-extensions';
import { of } from 'rxjs';
import { Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
class TestExtensionService extends ExtensionService {
onSetup(config: ExtensionConfig) {
this.onSetup$.next(config);
}
}
describe('AppConfigService', () => {
let appConfigService: AppConfigService;
let extensionService: ExtensionService;
let httpClient: HttpClient;
const mockResponse = {
ecmHost: 'http://localhost:4000/ecm',
bpmHost: 'http://localhost:4000/ecm',
application: {
name: 'Custom Name'
},
files: {
excluded: ['excluded']
},
logLevel: 'silent',
alfrescoRepositoryName: 'alfresco-1'
};
beforeEach(() => {
TestBed.configureTestingModule({
imports: [
HttpClientModule,
AppConfigModule
],
providers: [
{ provide: ExtensionService, useClass: TestExtensionService }
]
});
});
beforeEach(() => {
httpClient = TestBed.inject(HttpClient);
spyOn(httpClient, 'get').and.returnValue(of(mockResponse));
extensionService = TestBed.inject(ExtensionService);
appConfigService = TestBed.inject(AppConfigService);
appConfigService.load();
});
it('should merge the configs from extensions', () => {
appConfigService.config = {
application: {
name: 'application name'
}
};
(extensionService as TestExtensionService).onSetup({
appConfig: {
application: {
name: 'custom name'
}
}
} as any);
expect(appConfigService.get('application.name')).toEqual('custom name');
});
it('should merge the configs upon new data loaded', async () => {
appConfigService.config = {
application: {
name: 'application name'
}
};
(extensionService as TestExtensionService).onSetup({
appConfig: {
application: {
name: 'custom name'
}
}
} as any);
expect(appConfigService.get('application.name')).toEqual('custom name');
await appConfigService.load();
expect(appConfigService.get('application.name')).toEqual('custom name');
});
it('should stream only the selected attribute changes when using select', fakeAsync(() => {
appConfigService.config.testProp = true;
appConfigService.select('testProp').subscribe((property) => {
expect(property).toBeTruthy();
});
}));
it('should stream the page size value when is set', fakeAsync(() => {
appConfigService.config.testProp = true;
appConfigService.onLoad.subscribe((config) => {
expect(config.testProp).toBeTruthy();
});
}));
it('should skip the optional port number', () => {
appConfigService.config.testUrl = 'http://{hostname}{:port}';
spyOn(appConfigService, 'getLocationHostname').and.returnValue('localhost');
spyOn(appConfigService, 'getLocationPort').and.returnValue('');
expect(appConfigService.get('testUrl')).toBe('http://localhost');
});
it('should set the optional port number', () => {
appConfigService.config.testUrl = 'http://{hostname}{:port}';
spyOn(appConfigService, 'getLocationHostname').and.returnValue('localhost');
spyOn(appConfigService, 'getLocationPort').and.returnValue(':9090');
expect(appConfigService.get('testUrl')).toBe('http://localhost:9090');
});
it('should set the mandatory port number', () => {
appConfigService.config.testUrl = 'http://{hostname}:{port}';
spyOn(appConfigService, 'getLocationHostname').and.returnValue('localhost');
spyOn(appConfigService, 'getLocationPort').and.returnValue('9090');
expect(appConfigService.get('testUrl')).toBe('http://localhost:9090');
});
it('should use protocol value', () => {
spyOn(appConfigService, 'getLocationPort').and.returnValue('9090');
const protocolSpy = spyOn(appConfigService, 'getLocationProtocol');
appConfigService.config.testUrl = '{protocol}//{hostname}:{port}';
protocolSpy.and.returnValue('https:');
expect(appConfigService.get('testUrl')).toBe('https://localhost:9090');
protocolSpy.and.returnValue('ftp:');
expect(appConfigService.get('testUrl')).toBe('ftp://localhost:9090');
});
it('should load external settings', () => {
appConfigService.load().then((config) => {
expect(config).toEqual(mockResponse);
});
});
it('should retrieve settings', () => {
appConfigService.load().then(() => {
expect(appConfigService.get('ecmHost')).toBe(mockResponse.ecmHost);
expect(appConfigService.get('bpmHost')).toBe(mockResponse.bpmHost);
expect(appConfigService.get('application.name')).toBe(mockResponse.application.name);
});
});
it('should take excluded file list', () => {
appConfigService.load().then(() => {
expect(appConfigService.get('files.excluded')[0]).toBe('excluded');
});
});
});

View File

@@ -0,0 +1,242 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { ObjectUtils } from '../utils/object-utils';
import { Observable, Subject } from 'rxjs';
import { map, distinctUntilChanged, take } from 'rxjs/operators';
import { ExtensionConfig, ExtensionService, mergeObjects } from '@alfresco/adf-extensions';
import { OpenidConfiguration } from '../services/openid-configuration.interface';
/* spellchecker: disable */
// eslint-disable-next-line no-shadow
export enum AppConfigValues {
APP_CONFIG_LANGUAGES_KEY = 'languages',
PROVIDERS = 'providers',
OAUTHCONFIG = 'oauth2',
ECMHOST = 'ecmHost',
BASESHAREURL = 'baseShareUrl',
BPMHOST = 'bpmHost',
IDENTITY_HOST = 'identityHost',
AUTHTYPE = 'authType',
CONTEXTROOTECM = 'contextRootEcm',
CONTEXTROOTBPM = 'contextRootBpm',
ALFRESCO_REPOSITORY_NAME = 'alfrescoRepositoryName',
LOG_LEVEL = 'logLevel',
LOGIN_ROUTE = 'loginRoute',
DISABLECSRF = 'disableCSRF',
AUTH_WITH_CREDENTIALS = 'auth.withCredentials',
APPLICATION = 'application',
STORAGE_PREFIX = 'application.storagePrefix',
NOTIFY_DURATION = 'notificationDefaultDuration'
}
// eslint-disable-next-line no-shadow
export enum Status {
INIT = 'init',
LOADING = 'loading',
LOADED = 'loaded'
}
/* spellchecker: enable */
@Injectable({
providedIn: 'root'
})
export class AppConfigService {
config: any = {
application: {
name: 'Alfresco ADF Application'
},
ecmHost: 'http://{hostname}{:port}/ecm',
bpmHost: 'http://{hostname}{:port}/bpm',
logLevel: 'silent'
};
status: Status = Status.INIT;
protected onLoadSubject: Subject<any>;
onLoad: Observable<any>;
constructor(protected http: HttpClient, protected extensionService: ExtensionService) {
this.onLoadSubject = new Subject();
this.onLoad = this.onLoadSubject.asObservable();
extensionService.setup$.subscribe((config) => {
this.onExtensionsLoaded(config);
});
}
/**
* Requests notification of a property value when it is loaded.
*
* @param property The desired property value
* @returns Property value, when loaded
*/
select(property: string): Observable<any> {
return this.onLoadSubject
.pipe(
map((config) => config[property]),
distinctUntilChanged()
);
}
/**
* Gets the value of a named property.
*
* @param key Name of the property
* @param defaultValue Value to return if the key is not found
* @returns Value of the property
*/
get<T>(key: string, defaultValue?: T): T {
let result: any = ObjectUtils.getValue(this.config, key);
if (typeof result === 'string') {
const keywords = new Map<string, string>();
keywords.set('hostname', this.getLocationHostname());
keywords.set(':port', this.getLocationPort(':'));
keywords.set('port', this.getLocationPort());
keywords.set('protocol', this.getLocationProtocol());
result = this.formatString(result, keywords);
}
if (typeof result === 'object') {
result = JSON.parse(JSON.stringify(result).replace('{hostname}', this.getLocationHostname()));
result = JSON.parse(JSON.stringify(result).replace('{:port}', this.getLocationPort(':')));
result = JSON.parse(JSON.stringify(result).replace('{protocol}', this.getLocationProtocol()));
}
if (result === undefined) {
return defaultValue;
}
return result;
}
/**
* Gets the location.protocol value.
*
* @returns The location.protocol string
*/
getLocationProtocol(): string {
return location.protocol;
}
/**
* Gets the location.hostname property.
*
* @returns Value of the property
*/
getLocationHostname(): string {
return location.hostname;
}
/**
* Gets the location.port property.
*
* @param prefix Text added before port value
* @returns Port with prefix
*/
getLocationPort(prefix: string = ''): string {
return location.port ? prefix + location.port : '';
}
protected onLoaded() {
this.onLoadSubject.next(this.config);
}
protected onDataLoaded(data: any) {
this.config = Object.assign({}, this.config, data || {});
this.onLoadSubject.next(this.config);
this.extensionService.setup$
.pipe(take(1))
.subscribe((config) => this.onExtensionsLoaded(config));
}
protected onExtensionsLoaded(config: ExtensionConfig) {
if (config) {
const customConfig = config.appConfig;
if (customConfig) {
this.config = mergeObjects(this.config, customConfig);
}
}
}
/**
* Loads the config file.
*
* @returns Notification when loading is complete
*/
load(): Promise<any> {
return new Promise(async (resolve) => {
const configUrl = `app.config.json?v=${Date.now()}`;
if (this.status === Status.INIT) {
this.status = Status.LOADING;
this.http.get(configUrl).subscribe(
(data: any) => {
this.status = Status.LOADED;
this.onDataLoaded(data);
resolve(this.config);
},
() => {
resolve(this.config);
}
);
} else if (this.status === Status.LOADED) {
resolve(this.config);
} else if (this.status === Status.LOADING) {
this.onLoad.subscribe(() => {
resolve(this.config);
});
}
});
}
/**
* Call the discovery API to fetch configuration
*
* @returns Discovery configuration
*/
loadWellKnown(hostIdp: string): Promise<OpenidConfiguration> {
return new Promise(async (resolve, reject) => {
this.http
.get<OpenidConfiguration>(`${hostIdp}/.well-known/openid-configuration`)
.subscribe({
next: (res: OpenidConfiguration) => {
resolve(res);
},
error: (err: any) => {
reject(err);
}
});
});
}
private formatString(str: string, keywords: Map<string, string>): string {
let result = str;
keywords.forEach((value, key) => {
const expr = new RegExp('{' + key + '}', 'gm');
result = result.replace(expr, value);
});
return result;
}
}

View File

@@ -0,0 +1,40 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { StorageService } from '../services/storage.service';
import { AppConfigService, AppConfigValues } from './app-config.service';
import { ExtensionService } from '@alfresco/adf-extensions';
@Injectable()
export class DebugAppConfigService extends AppConfigService {
constructor(private storage: StorageService, http: HttpClient, extensionService: ExtensionService) {
super(http, extensionService);
}
/** @override */
get<T>(key: string, defaultValue?: T): T {
if (key === AppConfigValues.OAUTHCONFIG) {
return (JSON.parse(this.storage.getItem(key)) || super.get<T>(key, defaultValue));
} else if (key === AppConfigValues.APPLICATION) {
return undefined;
} else {
return (this.storage.getItem(key) as any || super.get<T>(key, defaultValue));
}
}
}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './public-api';

View File

@@ -0,0 +1,22 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './app-config.service';
export * from './debug-app-config.service';
export * from './app-config.pipe';
export * from './app-config.module';

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="2560" height="2560" x="0" y="0" enable-background="new 0 0 2560 2560" version="1.1" viewBox="0 0 2560 2560" xml:space="preserve"><g id="B"><rect width="2560" height="2560" y="0" fill="#FAFAFA"/><g><defs><rect id="SVGID_1_" width="2560" height="2560"/></defs><clipPath id="SVGID_2_"><use overflow="visible" xlink:href="#SVGID_1_"/></clipPath><g clip-path="url(#SVGID_2_)"><circle cx="16" cy="6272" r="5120" fill="#8BC34A" opacity=".8"/><circle cx="4096" cy="2048" r="2560" fill="#03A9F4" opacity=".6"/><circle cx="0" cy="-256" r="1920" fill="#FF9800" opacity=".8"/><circle cx="-384" cy="1280" r="1280" fill="#FFD600" opacity=".3"/></g></g></g><g id="Layer_2" display="none"><rect width="2560" height="1280" y="640" fill="none" stroke="#FFF" stroke-miterlimit="10" display="inline"/></g></svg>

After

Width:  |  Height:  |  Size: 881 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="currentColor"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M11 18c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm-2-8c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0-6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm6 4c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 456 B

View File

@@ -0,0 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="dynamic_feed-24px" opacity="1">
<g id="Group_6558" data-name="Group 6558">
<rect id="Rectangle_706" data-name="Rectangle 706" width="24" height="24" fill="none"/>
</g>
<g id="Group_6560" data-name="Group 6560">
<g id="Group_6559" data-name="Group 6559">
<path id="Path_5992" data-name="Path 5992" d="M8,8H6v7a2.006,2.006,0,0,0,2,2h9V15H8Z"/>
<path id="Path_5993" data-name="Path 5993" d="M20,3H12a2.006,2.006,0,0,0-2,2v6a2.006,2.006,0,0,0,2,2h8a2.006,2.006,0,0,0,2-2V5A2.006,2.006,0,0,0,20,3Zm0,8H12V7h8Z"/>
<path id="Path_5994" data-name="Path 5994" d="M4,12H2v7a2.006,2.006,0,0,0,2,2h9V19H4Z"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 772 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,6 @@
<svg id="Component_268_6" data-name="Component 268 6" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
<rect id="Rectangle_4868" data-name="Rectangle 4868" width="18" height="18" fill="none"/>
<g id="_1.-Icons_1.-system_ic-filter" data-name="1.-Icons/1.-system/ic-filter" transform="translate(-1 -1)" opacity="0.87">
<path id="Combined-Shape" d="M10.722,13.893a.793.793,0,0,1,.788.7l.005.092v.568h1.48a.793.793,0,0,1,.092,1.58l-.092.005h-1.48v.431a.793.793,0,0,1-1.58.092l-.005-.092V14.686A.793.793,0,0,1,10.722,13.893Zm-2.379,1.36a.793.793,0,0,1,.092,1.58l-.092.005H7.55a.793.793,0,0,1-.092-1.58l.092-.005Zm.793-7.478a.793.793,0,0,1,.788.7l.005.092v.568h5.444a.793.793,0,0,1,.092,1.58l-.092.005H9.929v.431a.793.793,0,0,1-1.58.092l-.005-.092V8.568A.793.793,0,0,1,9.136,7.775ZM5.964,9.136a.793.793,0,0,1,.092,1.58l-.092.005H4.379a.793.793,0,0,1-.092-1.58l.092-.005ZM13.1,2a.793.793,0,0,1,.788.7l.005.092V3.36h3.066a.793.793,0,0,1,.092,1.58l-.092.005H13.893v.431a.793.793,0,0,1-1.58.092l-.005-.092V2.793A.793.793,0,0,1,13.1,2ZM9.929,3.36a.793.793,0,0,1,.092,1.58l-.092.005H2.793A.793.793,0,0,1,2.7,3.366l.092-.005Z" fill-rule="evenodd"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><rect id="backgroundrect" width="100%" height="100%" x="0" y="0" fill="none" stroke="none"/><g class="currentLayer"><title>Layer 1</title><path id="svg_1" fill="#000" fill-opacity=".28" fill-rule="evenodd" d="M9.986754953861237,3.973509907722475 H3.986754953861237 C2.8867549538612365,3.973509907722475 1.986754953861237,4.8735099077224735 1.986754953861237,5.973509907722473 v12 c0,1.1 0.9,2 2,2 h16 c1.1,0 2,-0.9 2,-2 V7.973509907722473 c0,-1.1 -0.9,-2 -2,-2 h-8 L9.986754953861237,3.973509907722475 z"/></g></svg>

After

Width:  |  Height:  |  Size: 579 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" version="1.1" viewBox="0 0 24 24"><title>folder-with-rule copy</title><desc>Created with Sketch.</desc><g id="folder-with-rule-copy" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="systemicon/folder-with-rules-active"><g id="folder-with-rules"><g id="Group"><polygon id="Fill-1" points="0 24 24 24 24 0 0 0"/><path id="Fill-2" fill="#D9E021" d="M10,4 L4,4 C2.895,4 2.01,4.895 2.01,6 L2,18 C2,19.105 2.895,20 4,20 L20,20 C21.105,20 22,19.105 22,18 L22,8 C22,6.895 21.105,6 20,6 L12,6 L10,4 Z"/><polygon id="Fill-1-Copy" fill="#FFF" points="14.862 9 16.436 10.574 13.495 13.515 10.55 10.574 12.125 9 8 9 8 13.125 9.575 11.551 12.811 14.789 12.811 18 14.186 18 14.186 14.776 17.412 11.551 18.986 13.125 18.986 9"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 861 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" version="1.1" viewBox="0 0 24 24"><title>folder-shortcut-link copy</title><desc>Created with Sketch.</desc><g id="folder-shortcut-link-copy" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="systemicon/folder-shortcut-link-active"><g id="folder-shortcut-link"><g id="Group-9"><polygon id="Fill-1" points="0 24 24 24 24 0 0 0"/><path id="Path-2-Copy" fill="#D9E021" d="M2.70933755,4.54327602 L2,5.924926 L2,18.8121399 L2.69466158,19.5150573 C2.88252616,19.7051546 3.13866895,19.8121399 3.40593302,19.8121399 L20.6045166,19.8121399 L21.3116234,19.1050331 C21.4991598,18.9174967 21.6045166,18.6631428 21.6045166,18.3979263 L21.6045166,7.00924449 L20.9015261,6.24697884 C20.7122055,6.04169503 20.4456711,5.924926 20.1664154,5.924926 L11.1733882,5.924926 C10.8510886,5.924926 10.548546,5.76958526 10.3607292,5.50766556 L9.57882415,4.41726045 C9.39100739,4.15534074 9.08846483,4 8.76616517,4 L3.59894601,4 C3.2240117,4 2.88057904,4.20973129 2.70933755,4.54327602 Z"/><path id="Fill-2" fill="#FFF" d="M15.75,10 L13.15,10 L13.15,11.235 L15.75,11.235 C16.8615,11.235 17.765,12.1385 17.765,13.25 C17.765,14.3615 16.8615,15.265 15.75,15.265 L13.15,15.265 L13.15,16.5 L15.75,16.5 C17.544,16.5 19,15.044 19,13.25 C19,11.456 17.544,10 15.75,10 L15.75,10 Z M9.9,13.9 L15.1,13.9 L15.1,12.6 L9.9,12.6 L9.9,13.9 Z M7.235,13.25 C7.235,12.1385 8.1385,11.235 9.25,11.235 L11.85,11.235 L11.85,10 L9.25,10 C7.456,10 6,11.456 6,13.25 C6,15.044 7.456,16.5 9.25,16.5 L11.85,16.5 L11.85,15.265 L9.25,15.265 C8.1385,15.265 7.235,14.3615 7.235,13.25 L7.235,13.25 Z"/></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="20" height="16" version="1.1" viewBox="0 0 20 16"><title>System Icon Links</title><desc>Created with Sketch.</desc><g id="Style" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="icons" transform="translate(-289.000000, -4488.000000)"><g id="File" transform="translate(140.000000, 4130.000000)"><g id="Icon-Links-Folder" transform="translate(120.000000, 328.000000)"><g id="System-Icon-Links" transform="translate(28.000000, 30.000000)"><path id="Path-2-Copy" fill="#000" d="M1.70933755,0.543276016 L1,1.924926 L1,14.8121399 L1.69466158,15.5150573 L1.69466158,15.5150573 C1.88252616,15.7051546 2.13866895,15.8121399 2.40593302,15.8121399 L19.6045166,15.8121399 L20.3116234,15.1050331 L20.3116234,15.1050331 C20.4991598,14.9174967 20.6045166,14.6631428 20.6045166,14.3979263 L20.6045166,3.00924449 L19.9015261,2.24697884 L19.9015261,2.24697884 C19.7122055,2.04169503 19.4456711,1.924926 19.1664154,1.924926 L10.1733882,1.924926 L10.1733882,1.924926 C9.85108856,1.924926 9.548546,1.76958526 9.36072924,1.50766556 L8.57882415,0.417260445 L8.57882415,0.417260445 C8.39100739,0.155340737 8.08846483,-6.31724684e-16 7.76616517,0 L2.59894601,0 L2.59894601,-1.11022302e-16 C2.2240117,-4.21479881e-17 1.88057904,0.209731289 1.70933755,0.543276016 Z" opacity=".54"/><path id="Fill-2" fill="#FFF" d="M10,6 L7.6,6 L7.6,7.14 L10,7.14 C11.026,7.14 11.86,7.974 11.86,9 C11.86,10.026 11.026,10.86 10,10.86 L7.6,10.86 L7.6,12 L10,12 C11.656,12 13,10.656 13,9 C13,7.344 11.656,6 10,6 L10,6 Z M4.6,9.6 L9.4,9.6 L9.4,8.4 L4.6,8.4 L4.6,9.6 Z M2.14,9 C2.14,7.974 2.974,7.14 4,7.14 L6.4,7.14 L6.4,6 L4,6 C2.344,6 1,7.344 1,9 C1,10.656 2.344,12 4,12 L6.4,12 L6.4,10.86 L4,10.86 C2.974,10.86 2.14,10.026 2.14,9 L2.14,9 Z" transform="translate(7.000000, 9.000000) rotate(-45.000000) translate(-7.000000, -9.000000)"/></g></g></g></g></g></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#000" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>

After

Width:  |  Height:  |  Size: 267 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" version="1.1" viewBox="0 0 24 24"><title>filetype/folder</title><desc>Created with Sketch.</desc><g id="Symbols" fill="none" fill-rule="evenodd" stroke="none" stroke-width="1"><g id="filetype/folder"><polygon id="Fill-1" points="0 24 24 24 24 0 0 0"/><path id="Fill-2" fill="#D9E021" d="M10,4 L4,4 C2.895,4 2.01,4.895 2.01,6 L2,18 C2,19.105 2.895,20 4,20 L20,20 C21.105,20 22,19.105 22,18 L22,8 C22,6.895 21.105,6 20,6 L12,6 L10,4 Z"/><g id="cog" fill="#FFF" fill-rule="nonzero" transform="translate(10.000000, 8.000000)"><path id="Shape" d="M8.97602103,5.70765953 L9.87354689,6.20360587 C9.97604967,6.2602388 10.0236259,6.37735544 9.98851764,6.48556081 C9.7553749,7.20414773 9.3573263,7.85333966 8.83672508,8.39253187 C8.75648164,8.47568691 8.62677806,8.49455592 8.52435171,8.4379753 L7.6274998,7.9421096 C7.25015532,8.25161622 6.81633302,8.49173291 6.34786835,8.65037397 L6.34786835,9.64194408 C6.34787008,9.75522045 6.26583319,9.85335946 6.15038149,9.87819349 C5.41418114,10.0364592 4.62349658,10.0446447 3.85014503,9.87833462 C3.73452139,9.85347581 3.65211059,9.7554317 3.65211059,9.6419844 L3.65211059,8.65037397 C3.18364144,8.49174219 2.74981745,8.25162456 2.37247914,7.9421096 L1.47562723,8.4379753 C1.37320088,8.49455592 1.24349729,8.47568691 1.16325386,8.39253187 C0.642673695,7.85333966 0.244604043,7.20414773 0.011461297,6.48556081 C-0.02364701,6.3773756 0.023929274,6.26025896 0.126432051,6.20360587 L1.02397897,5.70765953 C0.933828729,5.23983992 0.933828729,4.76018024 1.02397897,4.29236063 L0.126453112,3.79641429 C0.0239503348,3.73978137 -0.0236259492,3.62266472 0.0114823578,3.51445935 C0.244625104,2.79587243 0.642673695,2.1466805 1.16327492,1.60748829 C1.24351836,1.52433325 1.37322194,1.50546424 1.47564829,1.56204486 L2.3725002,2.05791056 C2.74984468,1.74840395 3.18366698,1.50828725 3.65213165,1.34964619 L3.65213165,0.358055922 C3.65212992,0.244779553 3.73416681,0.146640538 3.84961851,0.12180651 C4.58581886,-0.0364592244 5.37650342,-0.0446446879 6.14985497,0.121665382 C6.26547861,0.146524191 6.34788941,0.244568301 6.34788941,0.358015599 L6.34788941,1.34962603 C6.81635856,1.50825781 7.25018255,1.74837544 7.62752086,2.0578904 L8.52437277,1.5620247 C8.62679912,1.50544408 8.75650271,1.52431309 8.83674614,1.60746813 C9.3573263,2.14666034 9.75539596,2.79585227 9.9885387,3.51443919 C10.023647,3.6226244 9.97607073,3.73974104 9.87356795,3.79639413 L8.97602103,4.29234047 C9.06617149,4.76016684 9.06617149,5.23983316 8.97602103,5.70765953 Z M6.68486176,5 C6.68486176,4.11064738 5.92903278,3.38710079 5,3.38710079 C4.07096722,3.38710079 3.31513824,4.11064738 3.31513824,5 C3.31513824,5.88935262 4.07096722,6.61289921 5,6.61289921 C5.92903278,6.61289921 6.68486176,5.88935262 6.68486176,5 Z"/></g></g></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.3.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 24 24" style="enable-background:new 0 0 24 24;" xml:space="preserve">
<style type="text/css">
.st0{opacity:1;}
.st1{fill:none;}
.st2{fill-rule:evenodd;clip-rule:evenodd;}
</style>
<g id="Asset-Artboard-Page" class="st0">
<g id="ic-archive-sync-1.-Icons_1.-system_ic-process">
<path id="Bounding-box" class="st1" d="M0,0h24v24H0V0z"/>
<path id="Combined-Shape" class="st2" d="M5.5,15.4c1.4,0,2.5,1.1,2.5,2.5s-1.1,2.5-2.5,2.5S3,19.3,3,17.9S4.1,15.4,5.5,15.4z
M18.5,15.4l2.5,5h-5L18.5,15.4z M6,13.1v1H5v-1H6z M19,13.6v1h-1v-1H19z M6,11.1v1H5v-1H6z M19,11.6v1h-1v-1H19z M6,9.1v1H5v-1H6
z M19,9.6v1h-1v-1H19z M8,3v5H3V3H8z M10.3,5v1h-1V5H10.3z M12.3,5v1h-1V5H12.3z M14.3,5v1h-1V5H14.3z M18.5,8.7l-3.2-3.2l3.2-3.2
l3.2,3.2L18.5,8.7z"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

View File

@@ -0,0 +1,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="Group_8310" data-name="Group 8310" transform="translate(8394 -1374)" opacity="1">
<path id="Subtraction_5" data-name="Subtraction 5" d="M6.01,8V5H3V3H6.01V0L10,4,6.012,8Z" transform="translate(-8382 1383)"/>
<path id="Path_17965" data-name="Path 17965" d="M0,0H24V24H0Z" transform="translate(-8394 1374)" fill="none"/>
<path id="Subtraction_4" data-name="Subtraction 4" d="M16,18H2a2,2,0,0,1-2-2V2A2,2,0,0,1,2,0H14l4,4V5H16V4.83L13.17,2H2V16H18A2,2,0,0,1,16,18ZM9,15a3,3,0,1,1,3-3A3,3,0,0,1,9,15Zm3-8H3V3h9V7Z" transform="translate(-8392 1377)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 666 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="save-24px_1_" data-name="save-24px (1)" opacity="1">
<path id="Path_17965" data-name="Path 17965" d="M0,0H24V24H0Z" fill="none"/>
<path id="Path_17966" data-name="Path 17966" d="M17,3H5A2,2,0,0,0,3,5V19a2,2,0,0,0,2,2H19a2.006,2.006,0,0,0,2-2V7Zm2,16H5V5H16.17L19,7.83Zm-7-7a3,3,0,1,0,3,3A3,3,0,0,0,12,12ZM6,6h9v4H6Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 434 B

View File

@@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<g id="icon-adw-task-24px" opacity="1">
<path id="Path_6787" data-name="Path 6787" d="M0,0H24V24H0Z" fill="none"/>
<path id="Path_6788" data-name="Path 6788" d="M19,4H5A2,2,0,0,0,3,6V18a2,2,0,0,0,2,2H19a2.006,2.006,0,0,0,2-2V6A2,2,0,0,0,19,4Zm0,14H5V8H19Z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 367 B

View File

@@ -0,0 +1,6 @@
<head>
<title>Alfresco silent static page</title>
</head>
<body>
Silent refresh static page
</body>

View File

@@ -0,0 +1,24 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component } from '@angular/core';
@Component({
selector: 'adf-blank-page',
template: ``
})
export class BlankPageComponent {}

View File

@@ -0,0 +1,31 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { BlankPageComponent } from './blank-page.component';
@NgModule({
declarations: [
BlankPageComponent
],
exports: [
BlankPageComponent
]
})
export class BlankPageModule {
}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './public-api';

View File

@@ -0,0 +1,19 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './blank-page.component';
export * from './blank-page.module';

View File

@@ -0,0 +1,20 @@
<div id="adf-buttons-menu" class="adf-buttons-menu" *ngIf="!isMenuEmpty">
<div *ngIf="isMobile()">
<button mat-icon-button [matMenuTriggerFor]="editReportMenu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #editReportMenu="matMenu" class="adf-buttons-menu-mobile">
<ng-content *ngTemplateOutlet="desktop">
</ng-content>
</mat-menu>
</div>
<div *ngIf="!isMobile()" class="adf-buttons-menu-desktop">
<ng-content *ngTemplateOutlet="desktop">
</ng-content>
</div>
</div>
<ng-template #desktop>
<ng-content></ng-content>
</ng-template>

View File

@@ -0,0 +1,29 @@
.adf-buttons-menu {
margin-right: 10px;
& div {
display: flex;
}
&-mobile {
margin-right: 10px;
}
&-desktop {
display: flex;
button {
color: black;
padding: 0;
}
button > span {
display: none;
}
button > mat-icon.mat-icon.material-icons {
color: black;
margin: 0 10px;
}
}
}

View File

@@ -0,0 +1,146 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { TestBed, ComponentFixture } from '@angular/core/testing';
import { MaterialModule } from '../material.module';
import { CoreTestingModule } from '../testing/core.testing.module';
import { setupTestBed } from '../testing/setup-test-bed';
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
@Component({
selector: 'adf-custom-container',
template: `
<adf-buttons-action-menu>
<button mat-menu-item (click)="assignValue()">
<mat-icon>settings</mat-icon><span> Button </span>
</button>
</adf-buttons-action-menu>
`
})
export class CustomContainerComponent {
value: number;
assignValue() {
this.value = 1;
}
}
@Component({
selector: 'adf-custom-empty-container',
template: `
<adf-buttons-action-menu>
</adf-buttons-action-menu>
`
})
export class CustomEmptyContainerComponent {
}
describe('ButtonsMenuComponent', () => {
describe('When Buttons are injected', () => {
let fixture: ComponentFixture<CustomContainerComponent>;
let component: CustomContainerComponent;
let element: HTMLElement;
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule,
MaterialModule
],
declarations: [
CustomContainerComponent
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
});
beforeEach(() => {
fixture = TestBed.createComponent(CustomContainerComponent);
element = fixture.debugElement.nativeElement;
component = fixture.componentInstance;
});
afterEach(() => {
fixture.destroy();
});
it('should render buttons menu when at least one button is declared', async () => {
fixture.detectChanges();
await fixture.whenStable();
const buttonsMenuElement = element.querySelector('#adf-buttons-menu');
expect(buttonsMenuElement).toBeDefined();
});
it('should trigger event when a specific button is clicked', async () => {
expect(component.value).toBeUndefined();
fixture.detectChanges();
await fixture.whenStable();
const button = element.querySelector('button');
button.click();
fixture.detectChanges();
await fixture.whenStable();
expect(component.value).toBe(1);
});
});
describe('When no buttons are injected', () => {
let fixture: ComponentFixture<CustomEmptyContainerComponent>;
let element: HTMLElement;
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule,
MaterialModule
],
declarations: [
CustomEmptyContainerComponent
],
schemas: [
CUSTOM_ELEMENTS_SCHEMA
]
});
beforeEach(() => {
fixture = TestBed.createComponent(CustomEmptyContainerComponent);
element = fixture.nativeElement;
});
afterEach(() => {
fixture.destroy();
TestBed.resetTestingModule();
});
it('should hide buttons menu if buttons input is empty', async () => {
fixture.detectChanges();
await fixture.whenStable();
const buttonsMenuElement = element.querySelector('#adf-buttons-menu');
expect(buttonsMenuElement).toBeNull();
});
});
});

View File

@@ -0,0 +1,41 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Component, ContentChildren, QueryList, AfterContentInit, ViewEncapsulation } from '@angular/core';
import { MatMenuItem } from '@angular/material/menu';
@Component({
selector: 'adf-buttons-action-menu',
templateUrl: './buttons-menu.component.html',
styleUrls: ['./buttons-menu.component.scss'],
encapsulation: ViewEncapsulation.None
})
export class ButtonsMenuComponent implements AfterContentInit {
@ContentChildren(MatMenuItem) buttons: QueryList<MatMenuItem>;
isMenuEmpty: boolean;
ngAfterContentInit() {
this.isMenuEmpty = this.buttons.length <= 0;
}
isMobile(): boolean {
return !!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
}
}

View File

@@ -0,0 +1,39 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { TranslateModule } from '@ngx-translate/core';
import { MaterialModule } from '../material.module';
import { ButtonsMenuComponent } from './buttons-menu.component';
import { FlexLayoutModule } from '@angular/flex-layout';
@NgModule({
imports: [
CommonModule,
MaterialModule,
TranslateModule,
FlexLayoutModule
],
declarations: [
ButtonsMenuComponent
],
exports: [
ButtonsMenuComponent
]
})
export class ButtonsMenuModule {}

View File

@@ -0,0 +1,18 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './public-api';

View File

@@ -0,0 +1,19 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 './buttons-menu.component';
export * from './buttons-menu.module';

View File

@@ -0,0 +1,98 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatChipsModule } from '@angular/material/chips';
import { MatNativeDateModule } from '@angular/material/core';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { MatMenuModule } from '@angular/material/menu';
import { MatSelectModule } from '@angular/material/select';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { MatTableModule } from '@angular/material/table';
import { MatTooltipModule } from '@angular/material/tooltip';
import { MatDatetimepickerModule, MatNativeDatetimeModule } from '@mat-datetimepicker/core';
import { FlexLayoutModule } from '@angular/flex-layout';
import { TranslateModule } from '@ngx-translate/core';
import { CardViewContentProxyDirective } from './directives/card-view-content-proxy.directive';
import { CardViewComponent } from './components/card-view/card-view.component';
import { CardViewBoolItemComponent } from './components/card-view-boolitem/card-view-boolitem.component';
import { CardViewDateItemComponent } from './components/card-view-dateitem/card-view-dateitem.component';
import { CardViewItemDispatcherComponent } from './components/card-view-item-dispatcher/card-view-item-dispatcher.component';
import { CardViewMapItemComponent } from './components/card-view-mapitem/card-view-mapitem.component';
import { CardViewTextItemComponent } from './components/card-view-textitem/card-view-textitem.component';
import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component';
import { CardViewSelectItemComponent } from './components/card-view-selectitem/card-view-selectitem.component';
import { CardViewArrayItemComponent } from './components/card-view-arrayitem/card-view-arrayitem.component';
import { SelectFilterInputComponent } from './components/card-view-selectitem/select-filter-input/select-filter-input.component';
@NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
FlexLayoutModule,
TranslateModule,
MatDatepickerModule,
MatNativeDateModule,
MatCheckboxModule,
MatInputModule,
MatTableModule,
MatIconModule,
MatSelectModule,
MatButtonModule,
MatChipsModule,
MatMenuModule,
MatCardModule,
MatDatetimepickerModule,
MatNativeDatetimeModule,
MatSlideToggleModule,
MatTooltipModule
],
declarations: [
CardViewComponent,
CardViewBoolItemComponent,
CardViewDateItemComponent,
CardViewMapItemComponent,
CardViewTextItemComponent,
CardViewKeyValuePairsItemComponent,
CardViewSelectItemComponent,
CardViewItemDispatcherComponent,
CardViewContentProxyDirective,
CardViewArrayItemComponent,
SelectFilterInputComponent
],
exports: [
CardViewComponent,
CardViewBoolItemComponent,
CardViewDateItemComponent,
CardViewMapItemComponent,
CardViewTextItemComponent,
CardViewSelectItemComponent,
CardViewKeyValuePairsItemComponent,
CardViewArrayItemComponent,
SelectFilterInputComponent
]
})
export class CardViewModule {}

View File

@@ -0,0 +1,49 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { Input, OnDestroy, Directive } from '@angular/core';
import { CardViewUpdateService } from '../services/card-view-update.service';
import { CardViewItem } from '../interfaces/card-view.interfaces';
import { CardViewBaseItemModel } from '../models/card-view-baseitem.model';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
@Directive()
// eslint-disable-next-line @angular-eslint/directive-class-suffix
export abstract class BaseCardView<T extends CardViewItem> implements OnDestroy {
@Input()
property: T;
protected destroy$ = new Subject<boolean>();
constructor(protected cardViewUpdateService: CardViewUpdateService) {
this.cardViewUpdateService.updateItem$
.pipe(takeUntil(this.destroy$))
.subscribe((itemModel: CardViewBaseItemModel) => {
if (this.property.key === itemModel.key) {
this.property.value = itemModel.value;
}
});
}
ngOnDestroy(): void {
this.destroy$.next(true);
this.destroy$.complete();
}
}

View File

@@ -0,0 +1,56 @@
<div [attr.data-automation-id]="'card-array-label-' + property.key" class="adf-property-label">{{ property.label | translate }}</div>
<div class="adf-property-value adf-card-view-array-item-container">
<ng-container *ngIf="(property.displayValue | async) as items; else elseEmptyValueBlock">
<mat-chip-list *ngIf="items.length > 0; else elseEmptyValueBlock" data-automation-id="card-arrayitem-chip-list-container">
<ng-container *ngIf="displayCount() > 0; else withOutDisplayCount" >
<mat-chip
*ngFor="let item of items.slice(0, displayCount())"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon">{{item.icon}}</mat-icon>
<span>{{item?.value}}</span>
</mat-chip>
<mat-chip
*ngIf="items.length > displayCount()"
data-automation-id="card-arrayitem-more-chip"
[matMenuTriggerFor]="menu">
<span>{{items.length - displayCount()}} {{'CORE.CARDVIEW.MORE' | translate}}</span>
</mat-chip>
</ng-container>
<ng-template #withOutDisplayCount>
<mat-chip
*ngFor="let item of items"
(click)="clicked()"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon">{{item.icon}}</mat-icon>
<span>{{item?.value}}</span>
</mat-chip>
</ng-template>
</mat-chip-list>
<mat-menu #menu="matMenu">
<mat-card class="adf-array-item-more-chip-container">
<mat-card-content>
<mat-chip-list>
<mat-chip (click)="clicked()"
*ngFor="let item of items.slice(displayCount(), items.length)"
[attr.data-automation-id]="'card-arrayitem-chip-' + item.value">
<mat-icon *ngIf="item?.icon" class="adf-array-item-icon">{{item.icon}}</mat-icon>
<span>{{item?.value}}</span>
</mat-chip>
</mat-chip-list>
</mat-card-content>
</mat-card>
</mat-menu>
</ng-container>
<ng-template #elseEmptyValueBlock>
<span class="adf-card-array-item-default" data-automation-id="card-arrayitem-default">{{ property?.default | translate }}</span>
</ng-template>
<button mat-icon-button *ngIf="showClickableIcon()"
(click)="clicked()"
class="adf-array-item-action"
[attr.aria-label]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.title]="'CORE.METADATA.ACTIONS.EDIT' | translate"
[attr.data-automation-id]="'card-array-item-clickable-icon-' + property.key">
<mat-icon class="adf-array-item-icon">{{property.icon}}</mat-icon>
</button>
</div>

View File

@@ -0,0 +1,48 @@
.adf {
&-array-item-icon {
font-size: var(--theme-subheading-2-font-size);
padding-top: 8px;
}
&-array-item-action {
color: var(--adf-card-view-text-color);
}
&-array-item-action:hover,
&-array-item-action:focus {
color: var(--theme-text-fg-color);
}
&-card-array-item-default {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
display: block;
}
&-array-item-more-chip-container {
&.mat-card {
box-shadow: none;
max-height: 300px;
overflow-y: auto;
}
}
&-property-value {
.mat-chip-list {
padding-top: 6px;
}
}
&-card-view-array-item-container {
flex-direction: row;
box-sizing: border-box;
display: flex;
place-content: center space-between;
align-items: center;
.mat-chip:hover {
cursor: pointer;
}
}
}

View File

@@ -0,0 +1,192 @@
/*!
* @license
* Copyright 2019 Alfresco Software, Ltd.
*
* 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 { of } from 'rxjs';
import { setupTestBed } from '../../../testing/setup-test-bed';
import { CoreTestingModule } from '../../../testing/core.testing.module';
import { CardViewArrayItemComponent } from './card-view-arrayitem.component';
import { CardViewArrayItemModel, CardViewArrayItem } from '../../models/card-view-arrayitem.model';
import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core';
import { CardViewUpdateService } from '../../services/card-view-update.service';
describe('CardViewArrayItemComponent', () => {
let component: CardViewArrayItemComponent;
let fixture: ComponentFixture<CardViewArrayItemComponent>;
let service: CardViewUpdateService;
let serviceSpy: jasmine.Spy;
const mockData = [
{ icon: 'person', value: 'Zlatan' },
{ icon: 'group', value: 'Lionel Messi' },
{ icon: 'person', value: 'Mohamed' },
{ icon: 'person', value: 'Ronaldo' }
] as CardViewArrayItem[];
const mockDefaultProps = {
label: 'Array of items',
value: of(mockData),
key: 'array',
icon: 'edit'
};
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule
]
});
afterEach(() => {
fixture.destroy();
});
beforeEach(() => {
fixture = TestBed.createComponent(CardViewArrayItemComponent);
service = TestBed.inject(CardViewUpdateService);
component = fixture.componentInstance;
component.property = new CardViewArrayItemModel(mockDefaultProps);
});
describe('Click event', () => {
beforeEach(() => {
serviceSpy = spyOn(service, 'clicked');
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
clickable: true
});
fixture.detectChanges();
});
it('should call service on chip click', () => {
const chip: HTMLElement = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Zlatan"]');
chip.dispatchEvent(new Event('click'));
expect(serviceSpy).toHaveBeenCalled();
});
it('should call service on edit icon click', () => {
const editIcon: HTMLElement = fixture.nativeElement.querySelector('[data-automation-id="card-array-item-clickable-icon-array"]');
editIcon.dispatchEvent(new Event('click'));
expect(serviceSpy).toHaveBeenCalled();
});
it('should NOT call service on chip list container click', () => {
const chiplistContainer: HTMLElement = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-list-container"]');
chiplistContainer.dispatchEvent(new Event('click'));
expect(serviceSpy).not.toHaveBeenCalled();
});
});
describe('Rendering', () => {
it('should render the label', () => {
fixture.detectChanges();
const labelValue = fixture.debugElement.query(By.css('.adf-property-label'));
expect(labelValue).not.toBeNull();
expect(labelValue.nativeElement.innerText).toBe('Array of items');
});
it('should render chip list', () => {
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
editable: true
});
fixture.detectChanges();
const chiplistContainer = fixture.debugElement.query(By.css('[data-automation-id="card-arrayitem-chip-list-container"]'));
const chip1 = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Zlatan"] span');
const chip2 = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Lionel Messi"] span');
expect(chiplistContainer).not.toBeNull();
expect(chip1.innerText).toEqual('Zlatan');
expect(chip2.innerText).toEqual('Lionel Messi');
});
it('should render chip with defined icon', () => {
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
editable: true
});
fixture.detectChanges();
const chiplistContainer = fixture.debugElement.query(By.css('[data-automation-id="card-arrayitem-chip-list-container"]'));
const chip1 = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Zlatan"] span');
const chip1Icon = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Zlatan"] mat-icon');
const chip2 = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Lionel Messi"] span');
const chip2Icon = fixture.nativeElement.querySelector('[data-automation-id="card-arrayitem-chip-Lionel Messi"] mat-icon');
expect(chiplistContainer).not.toBeNull();
expect(chip1.innerText).toEqual('Zlatan');
expect(chip1Icon.innerText).toEqual('person');
expect(chip2.innerText).toEqual('Lionel Messi');
expect(chip2Icon.innerText).toEqual('group');
});
it('should render defined icon if clickable set to true', () => {
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
clickable: true
});
fixture.detectChanges();
const editicon = fixture.nativeElement.querySelector('[data-automation-id="card-array-item-clickable-icon-array"]');
expect(editicon).toBeDefined();
expect(editicon.innerText).toBe('edit');
});
it('should not render defined icon if clickable set to false', () => {
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
clickable: false
});
fixture.detectChanges();
const editicon = fixture.nativeElement.querySelector('[data-automation-id="card-array-item-clickable-icon-array"]');
expect(editicon).toBeNull();
});
it('should render all values if noOfItemsToDisplay is not defined', () => {
fixture.detectChanges();
const chiplistContainer = fixture.debugElement.query(By.css('[data-automation-id="card-arrayitem-chip-list-container"]'));
const moreElement = fixture.debugElement.query(By.css('[data-automation-id="card-arrayitem-more-chip"]'));
const chip = fixture.nativeElement.querySelectorAll('mat-chip');
expect(chiplistContainer).not.toBeNull();
expect(moreElement).toBeNull();
expect(chip.length).toBe(4);
});
it('should render only two values along with more item chip if noOfItemsToDisplay is set to 2', () => {
component.property = new CardViewArrayItemModel({
...mockDefaultProps,
noOfItemsToDisplay: 2
});
fixture.detectChanges();
const chiplistContainer = fixture.debugElement.query(By.css('[data-automation-id="card-arrayitem-chip-list-container"]'));
const chip = fixture.debugElement.queryAll(By.css('mat-chip'));
expect(chiplistContainer).not.toBeNull();
expect(chip.length).toBe(3);
expect(chip[2].nativeElement.innerText).toBe('2 CORE.CARDVIEW.MORE');
});
});
});

Some files were not shown because too many files have changed in this diff Show More