[AAE-10777] Move in common service the real common services (#8203)

* Move in common service the real common services
remove Pagination js-api dependencies
move search-input component in content

* fix unit

* fix lint

* fix

* fix
This commit is contained in:
Eugenio Romano
2023-01-31 00:42:29 +01:00
committed by GitHub
parent 89b79c9e45
commit 4f25426c25
105 changed files with 156 additions and 381 deletions

View File

@@ -15,16 +15,16 @@
* limitations under the License.
*/
import { Pagination } from '@alfresco/js-api';
import { Observable } from 'rxjs';
import { IdentityGroupModel } from '../models/identity-group.model';
import { IdentityRoleModel } from '../models/identity-role.model';
import { IdentityUserModel } from '../models/identity-user.model';
import { PaginationModel } from '../../models/pagination.model';
export interface IdentityUserQueryResponse {
entries: IdentityUserModel[];
pagination: Pagination;
pagination: PaginationModel;
}
export interface IdentityUserPasswordModel {

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { Pagination } from '@alfresco/js-api';
import { PaginationModel } from '../../models/pagination.model';
export interface IdentityGroupModel {
id?: string;
@@ -35,7 +35,7 @@ export interface IdentityGroupSearchParam {
export interface IdentityGroupQueryResponse {
entries: IdentityGroupModel[];
pagination: Pagination;
pagination: PaginationModel;
}
export interface IdentityGroupQueryCloudRequestModel {

View File

@@ -19,14 +19,14 @@ import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { throwError as observableThrowError, Observable, of } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import { Pagination } from '@alfresco/js-api';
import { PaginationModel } from '../../models/pagination.model';
import { IdentityRoleModel } from '../models/identity-role.model';
import { AppConfigService } from '../../app-config/app-config.service';
import { LogService } from '../../common/services/log.service';
export interface IdentityRoleResponseModel {
entries: IdentityRoleModel[];
pagination: Pagination;
pagination: PaginationModel;
}
@Injectable({

View File

@@ -30,7 +30,7 @@ import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
import { BaseCardView } from '../base-card-view';
import { ClipboardService } from '../../../clipboard/clipboard.service';
import { TranslationService } from '../../../services/translation.service';
import { TranslationService } from '../../../translation/translation.service';
@Component({
providers: [

View File

@@ -21,7 +21,7 @@ import { CardViewUpdateService } from '../../services/card-view-update.service';
import { BaseCardView } from '../base-card-view';
import { MatChipInputEvent } from '@angular/material/chips';
import { ClipboardService } from '../../../clipboard/clipboard.service';
import { TranslationService } from '../../../services/translation.service';
import { TranslationService } from '../../../translation/translation.service';
import { CardViewItemValidator } from '../../interfaces/card-view-item-validator.interface';
import { UntypedFormControl } from '@angular/forms';
import { debounceTime, takeUntil, filter } from 'rxjs/operators';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { Observable } from 'rxjs';
import { CardViewArrayItemProperties } from '../interfaces/card-view-arrayitem-properties.interface';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewBoolItemProperties } from '../interfaces/card-view.interfaces';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewDateItemProperties } from '../interfaces/card-view.interfaces';
import { LocalizedDatePipe } from '../../pipes/localized-date.pipe';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewDateItemModel } from './card-view-dateitem.model';
import { CardViewDateItemProperties } from '../interfaces/card-view.interfaces';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewTextItemModel } from './card-view-textitem.model';
import { CardViewTextItemProperties } from '../interfaces/card-view.interfaces';
import { CardViewItemFloatValidator } from '../validators/card-view.validators';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewTextItemModel } from './card-view-textitem.model';
import { CardViewTextItemProperties } from '../interfaces/card-view.interfaces';
import { CardViewItemIntValidator } from '../validators/card-view.validators';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewKeyValuePairsItemProperties } from '../interfaces/card-view.interfaces';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewSelectItemProperties, CardViewSelectItemOption } from '../interfaces/card-view.interfaces';
import { Observable, of } from 'rxjs';

View File

@@ -16,7 +16,7 @@
*/
import { CardViewItem } from '../interfaces/card-view-item.interface';
import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentModel } from '../../common/services/dynamic-component-mapper.service';
import { CardViewBaseItemModel } from './card-view-baseitem.model';
import { CardViewTextItemPipeProperty, CardViewTextItemProperties } from '../interfaces/card-view.interfaces';

View File

@@ -27,6 +27,7 @@ export {
SelectFilterInputComponent
} from './components/card-view.components';
export * from './interfaces/card-view.interfaces';
export * from './interfaces/card-view.interfaces';
export * from './validators/card-view.validators';
export * from './models/card-view.models';

View File

@@ -22,7 +22,7 @@ import { CardViewTextItemComponent } from '../components/card-view-textitem/card
import { CardViewSelectItemComponent } from '../components/card-view-selectitem/card-view-selectitem.component';
import { CardViewBoolItemComponent } from '../components/card-view-boolitem/card-view-boolitem.component';
import { CardViewKeyValuePairsItemComponent } from '../components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component';
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../common/services/dynamic-component-mapper.service';
import { CardViewArrayItemComponent } from '../components/card-view-arrayitem/card-view-arrayitem.component';
@Injectable({

View File

@@ -20,6 +20,11 @@ export * from './services/log.service';
export * from './services/storage.service';
export * from './services/user-preferences.service';
export * from './services/language-item.interface';
export * from './services/dynamic-component-mapper.service';
export * from './services/highlight-transform.service';
export * from './services/page-title.service';
export * from './services/thumbnail.service';
export * from './services/sort-by-category.service';
export * from './models/log-levels.model';

View File

@@ -16,11 +16,11 @@
*/
import { TestBed } from '@angular/core/testing';
import { CoreTestingModule } from '../testing/core.testing.module';
import { setupTestBed } from '../testing/setup-test-bed';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { setupTestBed } from '../../testing/setup-test-bed';
import { UserPreferencesService } from './user-preferences.service';
import { TranslateModule } from '@ngx-translate/core';
import { CoreModule } from '../core.module';
import { CoreModule } from '../../core.module';
describe('DirectionalityConfigService', () => {
let userPreferencesService: UserPreferencesService;

View File

@@ -17,7 +17,7 @@
import { Injectable, Inject, Renderer2, RendererFactory2 } from '@angular/core';
import { Directionality, Direction } from '@angular/cdk/bidi';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { UserPreferencesService } from './user-preferences.service';
import { DOCUMENT } from '@angular/common';
@Injectable({

View File

@@ -16,7 +16,8 @@
*/
import { Type } from '@angular/core';
import { getType } from './get-type';
const getType = (type: any): any => () => type;
export interface DynamicComponentModel { type: string }
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<any>;

View File

@@ -17,8 +17,8 @@
import { Injectable } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { AppConfigService } from '../app-config/app-config.service';
import { TranslationService } from './translation.service';
import { AppConfigService } from '../../app-config/app-config.service';
import { TranslationService } from '../../translation/translation.service';
@Injectable({
providedIn: 'root'

View File

@@ -17,8 +17,8 @@
import { TestBed } from '@angular/core/testing';
import { ThumbnailService } from './thumbnail.service';
import { setupTestBed } from '../testing/setup-test-bed';
import { CoreTestingModule } from '../testing/core.testing.module';
import { setupTestBed } from '../../testing/setup-test-bed';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TranslateModule } from '@ngx-translate/core';
describe('ThumbnailService', () => {

View File

@@ -19,7 +19,7 @@
import { Injectable } from '@angular/core';
import { MatIconRegistry } from '@angular/material/icon';
import { DomSanitizer } from '@angular/platform-browser';
import { AlfrescoApiService } from './alfresco-api.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { ContentApi, NodeEntry } from '@alfresco/js-api';
const DEFAULT_ICON = './assets/images/ft_ic_miscellaneous.svg';

View File

@@ -47,15 +47,14 @@ import { DownloadZipDialogModule } from './dialogs/download-zip/download-zip.dia
import { PipeModule } from './pipes/pipe.module';
import { AlfrescoApiService } from './services/alfresco-api.service';
import { TranslationService } from './services/translation.service';
import { TranslationService } from './translation/translation.service';
import { startupServiceFactory } from './services/startup-service-factory';
import { SortingPickerModule } from './sorting-picker/sorting-picker.module';
import { IconModule } from './icon/icon.module';
import { TranslateLoaderService } from './services/translate-loader.service';
import { TranslateLoaderService } from './translation/translate-loader.service';
import { ExtensionsModule } from '@alfresco/adf-extensions';
import { directionalityConfigFactory } from './services/directionality-config-factory';
import { DirectionalityConfigService } from './services/directionality-config.service';
import { SearchTextModule } from './search-text/search-text-input.module';
import { directionalityConfigFactory } from './common/services/directionality-config-factory';
import { DirectionalityConfigService } from './common/services/directionality-config.service';
import { AlfrescoJsClientsModule } from '@alfresco/adf-core/api';
import { AuthenticationInterceptor, Authentication } from '@alfresco/adf-core/auth';
import { LegacyApiClientModule } from './api-factories/legacy-api-client.module';
@@ -95,7 +94,6 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
IconModule,
SortingPickerModule,
NotificationHistoryModule,
SearchTextModule,
BlankPageModule,
LegacyApiClientModule,
AlfrescoJsClientsModule,
@@ -136,7 +134,6 @@ import { MAT_SNACK_BAR_DEFAULT_OPTIONS } from '@angular/material/snack-bar';
SortingPickerModule,
IconModule,
NotificationHistoryModule,
SearchTextModule,
BlankPageModule,
RichTextEditorModule
]

View File

@@ -18,7 +18,7 @@
import { Component, ViewChildren } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { HighlightTransformService } from '../services/highlight-transform.service';
import { HighlightTransformService } from '../common/services/highlight-transform.service';
import { HighlightDirective } from './highlight.directive';
import { setupTestBed } from '../testing/setup-test-bed';
import { CoreTestingModule } from '../testing/core.testing.module';

View File

@@ -18,7 +18,7 @@
/* eslint-disable @angular-eslint/no-input-rename */
import { Directive, ElementRef, Input, Renderer2, AfterViewChecked } from '@angular/core';
import { HighlightTransformService, HighlightTransformResult } from '../services/highlight-transform.service';
import { HighlightTransformService, HighlightTransformResult } from '../common/services/highlight-transform.service';
@Directive({
selector: '[adf-highlight]'

View File

@@ -1,27 +0,0 @@
/*!
* @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 { NodeEntry } from '@alfresco/js-api';
export interface FolderCreatedEvent {
name: string;
relativePath?: string;
parentId?: string;
node?: NodeEntry;
}

View File

@@ -17,5 +17,4 @@
export * from './base.event';
export * from './base-ui.event';
export * from './folder-created.event';
export * from './file.event';

View File

@@ -23,7 +23,7 @@ import { CheckboxWidgetComponent } from './checkbox.widget';
import { setupTestBed } from '../../../../testing/setup-test-bed';
import { FormBaseModule } from '../../../form-base.module';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateLoaderService } from '../../../../services/translate-loader.service';
import { TranslateLoaderService } from '../../../../translation/translate-loader.service';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { CoreTestingModule } from '../../../../testing';
import { MatTooltipModule } from '@angular/material/tooltip';

View File

@@ -24,9 +24,7 @@ import { FormFieldModel } from './form-field.model';
import { FormOutcomeModel } from './form-outcome.model';
import { FormModel } from './form.model';
import { TabModel } from './tab.model';
import { fakeMetadataForm, fakeViewerForm } from '../../mock/form.mock';
import { Node } from '@alfresco/js-api';
import { UploadWidgetContentLinkModel } from './upload-widget-content-link.model';
import { fakeMetadataForm } from '../../mock/form.mock';
import { CoreTestingModule, setupTestBed } from '../../../../testing';
describe('FormModel', () => {
@@ -609,37 +607,4 @@ describe('FormModel', () => {
});
});
describe('setNodeIdValueForViewersLinkedToUploadWidget', () => {
const fakeNodeWithProperties: Node = {
id: 'fake-properties',
name: 'fake-properties-name',
content: {
mimeType: 'application/pdf'
},
properties: {
'pfx:property_one': 'testValue',
'pfx:property_two': true
}
} as Node;
let form: FormModel;
it('should set the node id to the viewers linked to the upload widget in the event', () => {
form = new FormModel(fakeMetadataForm);
const uploadWidgetContentLinkModel = new UploadWidgetContentLinkModel(fakeNodeWithProperties, 'content_form_nodes');
form.setNodeIdValueForViewersLinkedToUploadWidget(uploadWidgetContentLinkModel);
expect(form.values['cmfb85b2a7295ba41209750bca176ccaf9a']).toBe(fakeNodeWithProperties.id);
});
it('should not set the node id to the viewers when they are not linked', () => {
form = new FormModel(fakeViewerForm);
const uploadWidgetContentLinkModel = new UploadWidgetContentLinkModel(fakeNodeWithProperties, 'upload_widget');
form.setNodeIdValueForViewersLinkedToUploadWidget(uploadWidgetContentLinkModel);
expect(form.values['cmfb85b2a7295ba41209750bca176ccaf9a']).toBeNull();
});
});
});

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service';
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../common/services/dynamic-component-mapper.service';
import { Injectable, Type } from '@angular/core';
import * as widgets from '../components/widgets';

View File

@@ -21,7 +21,7 @@ import { LanguageMenuComponent } from './language-menu.component';
import { CoreTestingModule } from '../testing/core.testing.module';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { TranslateModule } from '@ngx-translate/core';
import { LanguageService } from '../services/language.service';
import { LanguageService } from './service/language.service';
describe('LanguageMenuComponent', () => {

View File

@@ -21,7 +21,7 @@ import { CoreStoryModule } from '../testing/core.story.module';
import { LanguageMenuModule } from './language-menu.module';
import { LanguageMenuComponent } from './language-menu.component';
import { LanguageService } from '../services/language.service';
import { LanguageService } from './service/language.service';
import { LanguageServiceMock } from '../mock/language.service.mock';
export default {

View File

@@ -16,7 +16,7 @@
*/
import { Component, EventEmitter, Output } from '@angular/core';
import { LanguageService } from '../services/language.service';
import { LanguageService } from './service/language.service';
import { Observable } from 'rxjs';
import { LanguageItem } from '../common/services/language-item.interface';

View File

@@ -21,7 +21,7 @@ import { CoreStoryModule } from '../testing/core.story.module';
import { LanguageMenuModule } from './language-menu.module';
import { LanguagePickerComponent } from './language-picker.component';
import { LanguageService } from '../services/language.service';
import { LanguageService } from './service/language.service';
import { LanguageServiceMock } from '../mock/language.service.mock';
export default {

View File

@@ -15,6 +15,8 @@
* limitations under the License.
*/
export * from './service/language.service';
export * from './language-menu.component';
export * from './language-menu.module';
export * from './language-picker.component';

View File

@@ -16,7 +16,7 @@
*/
import { Observable } from 'rxjs';
import { LanguageItem } from '../common/services/language-item.interface';
import { LanguageItem } from '../../common/services/language-item.interface';
export interface LanguageServiceInterface {

View File

@@ -18,9 +18,9 @@
import { LanguageServiceInterface } from './language.service.interface';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { AppConfigService, AppConfigValues } from '../app-config/app-config.service';
import { LanguageItem } from '../common/services/language-item.interface';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { AppConfigService, AppConfigValues } from '../../app-config/app-config.service';
import { LanguageItem } from '../../common/services/language-item.interface';
import { UserPreferencesService } from '../../common/services/user-preferences.service';
@Injectable({providedIn: 'root'})
export class LanguageService implements LanguageServiceInterface {

View File

@@ -23,7 +23,7 @@ import { AbstractControl, UntypedFormBuilder, UntypedFormGroup, Validators } fro
import { Router, ActivatedRoute, Params } from '@angular/router';
import { AuthenticationService } from '../../auth/services/authentication.service';
import { OauthConfigModel } from '../../auth/models/oauth-config.model';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
import { UserPreferencesService } from '../../common/services/user-preferences.service';
import { AlfrescoApiService } from '../../services/alfresco-api.service';

View File

@@ -15,7 +15,7 @@
* limitations under the License.
*/
import { LanguageServiceInterface } from '../services/language.service.interface';
import { LanguageServiceInterface } from '../language-menu/service/language.service.interface';
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { LanguageItem } from '../common/services/language-item.interface';

View File

@@ -17,7 +17,7 @@
import { EventEmitter, Injectable } from '@angular/core';
import { Observable, of } from 'rxjs';
import { TranslationService } from '../services/translation.service';
import { TranslationService } from '../translation/translation.service';
export interface LangChangeEvent {
lang: string;

View File

@@ -27,7 +27,6 @@ export * from './request-pagination.model';
export * from './decimal-number.model';
export * from './bpm-user.model';
export * from './ecm-user.model';
export * from './search-text-input.model';
export * from './node-metadata.model';
export * from './application-access.model';
export * from './user-access.model';

View File

@@ -1,37 +0,0 @@
/*!
* @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.
*/
// eslint-disable-next-line no-shadow
export enum SearchTextStateEnum {
expanded = 'expanded',
collapsed = 'collapsed'
}
export interface SearchAnimationState {
value: string;
params?: any;
}
export interface SearchAnimationControl {
active: SearchAnimationState;
inactive: SearchAnimationState;
}
export interface SearchAnimationDirection {
ltr: SearchAnimationControl;
rtl: SearchAnimationControl;
}

View File

@@ -22,7 +22,7 @@ import { MatMenuTrigger, MenuPositionX, MenuPositionY } from '@angular/material/
import { takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { StorageService } from '../../common/services/storage.service';
import { Pagination } from '@alfresco/js-api';
import { PaginationModel } from '../../models/pagination.model';
@Component({
selector: 'adf-notification-history',
@@ -53,7 +53,7 @@ export class NotificationHistoryComponent implements OnDestroy, OnInit, AfterVie
onDestroy$ = new Subject<boolean>();
notifications: NotificationModel[] = [];
paginatedNotifications = [];
pagination: Pagination;
pagination: PaginationModel;
constructor(
private notificationService: NotificationService,

View File

@@ -22,7 +22,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatSnackBar, MatSnackBarConfig, MatSnackBarModule } from '@angular/material/snack-bar';
import { NotificationService } from './notification.service';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
import { setupTestBed } from '../../testing/setup-test-bed';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { TranslateModule } from '@ngx-translate/core';

View File

@@ -17,7 +17,7 @@
import { Injectable } from '@angular/core';
import { MatSnackBar, MatSnackBarRef, MatSnackBarConfig } from '@angular/material/snack-bar';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
import { Subject } from 'rxjs';
import { NotificationModel } from '../models/notification.model';
import { info, warning, error } from '../helpers/notification.factory';

View File

@@ -16,7 +16,7 @@
*/
import { Pipe, PipeTransform } from '@angular/core';
import { TranslationService } from '../services/translation.service';
import { TranslationService } from '../translation/translation.service';
@Pipe({
name: 'adfFileSize',

View File

@@ -16,7 +16,7 @@
*/
import { Pipe, PipeTransform } from '@angular/core';
import { TranslationService } from '../services/translation.service';
import { TranslationService } from '../translation/translation.service';
@Pipe({
name: 'adfLocalizedRole'

View File

@@ -16,7 +16,7 @@
*/
import { Pipe, PipeTransform } from '@angular/core';
import { ThumbnailService } from '../services/thumbnail.service';
import { ThumbnailService } from '../common/services/thumbnail.service';
@Pipe({
name: 'adfMimeTypeIcon'

View File

@@ -16,7 +16,7 @@
*/
import { Pipe, PipeTransform } from '@angular/core';
import { HighlightTransformService, HighlightTransformResult } from '../services/highlight-transform.service';
import { HighlightTransformService, HighlightTransformResult } from '../common/services/highlight-transform.service';
@Pipe({
name: 'highlight'

View File

@@ -1,33 +0,0 @@
/*!
* @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 { trigger, transition, animate, style, state, AnimationTriggerMetadata } from '@angular/animations';
export const searchAnimation: AnimationTriggerMetadata = trigger('transitionMessages', [
state('active', style({
'margin-left': '{{ margin-left }}px',
'margin-right': '{{ margin-right }}px',
transform: '{{ transform }}'
}), { params: { 'margin-left': 0, 'margin-right': 0, transform: 'translateX(0%)' } }),
state('inactive', style({
'margin-left': '{{ margin-left }}px',
'margin-right': '{{ margin-right }}px',
transform: '{{ transform }}'
}), { params: { 'margin-left': 0, 'margin-right': 0, transform: 'translateX(0%)' } }),
state('no-animation', style({ transform: 'translateX(0%)', width: '100%' })),
transition('active <=> inactive', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'))
]);

View File

@@ -1,48 +0,0 @@
/*!
* @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 { QueryBody, NodePaging } from '@alfresco/js-api';
import { Subject } from 'rxjs';
import { ElementRef } from '@angular/core';
export interface SearchConfigurationInterface {
/**
* Generates a QueryBody object with custom search parameters.
*
* @param searchTerm Term text to search for
* @param maxResults Maximum number of search results to show in a page
* @param skipCount The offset of the start of the page within the results list
* @returns Query body defined by the parameters
*/
generateQueryBody(searchTerm: string, maxResults: number, skipCount: number): QueryBody;
}
export interface SearchComponentInterface {
panel: ElementRef;
showPanel: boolean;
results: NodePaging;
isOpen: boolean;
keyPressedStream: Subject<string>;
displayWith: ((value: any) => string) | null;
resetResults(): void;
hidePanel(): void;
setVisibility(): void;
}

View File

@@ -1,23 +0,0 @@
/*!
* @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 './animations';
export * from './search-text-input.component';
export * from './search-trigger.directive';
export * from './search-text-input.module';
export * from './interfaces/search-configuration.interface';

View File

@@ -1,38 +0,0 @@
<div class="adf-search-container" [attr.state]="subscriptAnimationState.value">
<div [@transitionMessages]="subscriptAnimationState"
(@transitionMessages.done)="applySearchFocus($event)">
<button mat-icon-button
*ngIf="expandable"
id="adf-search-button"
class="adf-search-button"
[title]="'SEARCH.BUTTON.TOOLTIP' | translate"
(click)="toggleSearchBar()"
(keyup.enter)="toggleSearchBar()">
<mat-icon [attr.aria-label]="'SEARCH.BUTTON.ARIA-LABEL' | translate">search</mat-icon>
</button>
<mat-form-field class="adf-input-form-field-divider" [hintLabel]="hintLabel">
<input matInput
#searchInput
[attr.aria-label]="'SEARCH.INPUT.ARIA-LABEL' | translate"
[attr.type]="inputType"
[autocomplete]="getAutoComplete()"
id="adf-control-input"
[(ngModel)]="searchTerm"
[placeholder]="placeholder"
(focus)="activateToolbar()"
(blur)="onBlur($event)"
(keyup.escape)="toggleSearchBar()"
(keyup.arrowdown)="selectFirstResult($event)"
(ngModelChange)="inputChange($event)"
[searchAutocomplete]="searchAutocomplete ? searchAutocomplete : null"
(keyup.enter)="searchSubmit($event)">
<button mat-icon-button matSuffix
data-automation-id="adf-clear-search-button"
class="adf-clear-search-button"
*ngIf="canShowClearSearch()"
(mousedown)="resetSearch()">
<mat-icon>clear</mat-icon>
</button>
</mat-form-field>
</div>
</div>

View File

@@ -1,37 +0,0 @@
.adf-search-container {
overflow: hidden !important;
}
.adf-search-button {
left: -13px;
}
[dir='rtl'] .adf-search-button {
right: -13px;
}
[dir='ltr'] .adf-search-button {
left: -13px;
}
.adf {
&-search-fixed-text {
line-height: normal;
}
&-input-form-field-divider {
.mat-form-field-underline {
background-color: var(--adf-search-input-bg-color);
.mat-form-field-ripple {
background-color: var(--adf-search-input-bg-color);
}
}
font-size: var(--theme-subheading-2-font-size);
}
}
.adf-highlight {
color: var(--adf-search-input-highlight-color);
}

View File

@@ -1,386 +0,0 @@
/*!
* @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, discardPeriodicTasks, fakeAsync, tick } from '@angular/core/testing';
import { CoreTestingModule } from '../testing/core.testing.module';
import { SearchTextInputComponent } from './search-text-input.component';
import { DebugElement } from '@angular/core';
import { By } from '@angular/platform-browser';
import { Subject } from 'rxjs';
import { TranslateModule } from '@ngx-translate/core';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { setupTestBed } from '../testing/setup-test-bed';
describe('SearchTextInputComponent', () => {
let fixture: ComponentFixture<SearchTextInputComponent>;
let component: SearchTextInputComponent;
let debugElement: DebugElement;
let element: HTMLElement;
let userPreferencesService: UserPreferencesService;
setupTestBed({
imports: [
TranslateModule.forRoot(),
CoreTestingModule
]
});
beforeEach(() => {
fixture = TestBed.createComponent(SearchTextInputComponent);
component = fixture.componentInstance;
debugElement = fixture.debugElement;
element = fixture.nativeElement;
userPreferencesService = TestBed.inject(UserPreferencesService);
component.focusListener = new Subject<any>();
});
afterEach(() => {
fixture.destroy();
});
describe('component rendering', () => {
it('should display a search input field when specified', async () => {
fixture.detectChanges();
await fixture.whenStable();
component.inputType = 'search';
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelectorAll('input[type="search"]').length).toBe(1);
});
});
describe('expandable option false', () => {
beforeEach(() => {
component.expandable = false;
});
it('search button should be hide', () => {
fixture.detectChanges();
const searchButton: any = element.querySelector('#adf-search-button');
expect(searchButton).toBe(null);
});
it('should not have animation', () => {
userPreferencesService.setWithoutStore('textOrientation', 'rtl');
fixture.detectChanges();
expect(component.subscriptAnimationState.value).toBe('no-animation');
});
});
describe('search button', () => {
it('should NOT display a autocomplete list control when configured not to', fakeAsync(() => {
fixture.detectChanges();
tick(100);
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
searchButton.triggerEventHandler('click', null);
fixture.detectChanges();
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('inactive');
discardPeriodicTasks();
}));
it('click on the search button should open the input box when is close', fakeAsync(() => {
fixture.detectChanges();
tick(100);
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
searchButton.triggerEventHandler('click', null);
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
discardPeriodicTasks();
}));
it('Search button should not change the input state too often', fakeAsync(() => {
fixture.detectChanges();
tick(100);
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
searchButton.triggerEventHandler('click', null);
fixture.detectChanges();
tick(100);
searchButton.triggerEventHandler('click', null);
fixture.detectChanges();
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('inactive');
discardPeriodicTasks();
}));
it('Search bar should close when user press ESC button', fakeAsync(() => {
fixture.detectChanges();
tick(100);
const inputDebugElement = debugElement.query(By.css('#adf-control-input'));
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('active');
inputDebugElement.triggerEventHandler('keyup.escape', {});
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.value).toBe('inactive');
discardPeriodicTasks();
}));
});
describe('toggle animation', () => {
beforeEach(() => {
fixture.detectChanges();
});
it('should have margin-left set when active and direction is ltr', fakeAsync(() => {
userPreferencesService.setWithoutStore('textOrientation', 'ltr');
fixture.detectChanges();
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
searchButton.triggerEventHandler('click', null);
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.params).toEqual({ 'margin-left': 13 });
discardPeriodicTasks();
}));
it('should have positive transform translateX set when inactive and direction is ltr', fakeAsync(() => {
userPreferencesService.setWithoutStore('textOrientation', 'ltr');
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
searchButton.triggerEventHandler('click', null);
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.params).toEqual({ transform: 'translateX(82%)' });
discardPeriodicTasks();
}));
it('should have margin-right set when active and direction is rtl', fakeAsync(() => {
userPreferencesService.setWithoutStore('textOrientation', 'rtl');
fixture.detectChanges();
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
searchButton.triggerEventHandler('click', null);
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.params).toEqual({ 'margin-right': 13 });
discardPeriodicTasks();
}));
it('should have negative transform translateX set when inactive and direction is rtl', fakeAsync(() => {
userPreferencesService.setWithoutStore('textOrientation', 'rtl');
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
const searchButton: DebugElement = debugElement.query(By.css('#adf-search-button'));
searchButton.triggerEventHandler('click', null);
tick(100);
fixture.detectChanges();
tick(100);
expect(component.subscriptAnimationState.params).toEqual({ transform: 'translateX(-82%)' });
discardPeriodicTasks();
}));
it('should set browser autocomplete to on when configured', async () => {
component.autocomplete = true;
fixture.detectChanges();
await fixture.whenStable();
expect(element.querySelector('#adf-control-input').getAttribute('autocomplete')).toBe('on');
});
});
describe('Search visibility', () => {
beforeEach(() => {
userPreferencesService.setWithoutStore('textOrientation', 'ltr');
fixture.detectChanges();
});
it('should emit an event when the search becomes active', fakeAsync(() => {
const searchVisibilityChangeSpy = spyOn(component.searchVisibility, 'emit');
component.toggleSearchBar();
tick(200);
expect(searchVisibilityChangeSpy).toHaveBeenCalledWith(true);
}));
it('should emit an event when the search becomes inactive', fakeAsync(() => {
component.toggleSearchBar();
tick(200);
expect(component.subscriptAnimationState.value).toEqual('active');
const searchVisibilityChangeSpy = spyOn(component.searchVisibility, 'emit');
component.toggleSearchBar();
tick(200);
expect(component.subscriptAnimationState.value).toEqual('inactive');
expect(searchVisibilityChangeSpy).toHaveBeenCalledWith(false);
}));
it('should reset emit when the search becomes inactive', fakeAsync(() => {
const resetSpy = spyOn(component.reset, 'emit');
component.toggleSearchBar();
tick(200);
expect(component.subscriptAnimationState.value).toEqual('active');
component.searchTerm = 'fake-search-term';
component.toggleSearchBar();
tick(200);
expect(resetSpy).toHaveBeenCalled();
expect(component.searchTerm).toEqual('');
}));
describe('Clear button', () => {
beforeEach(fakeAsync(() => {
fixture.detectChanges();
component.subscriptAnimationState.value = 'active';
fixture.detectChanges();
tick(200);
}));
it('should clear button be visible when showClearButton is set to true', async () => {
component.showClearButton = true;
fixture.detectChanges();
await fixture.whenStable();
const clearButton = fixture.debugElement.query(By.css('[data-automation-id="adf-clear-search-button"]'));
expect(clearButton).not.toBeNull();
});
it('should clear button not be visible when showClearButton is set to false', () => {
component.showClearButton = false;
fixture.detectChanges();
const clearButton = fixture.debugElement.query(By.css('[data-automation-id="adf-clear-search-button"]'));
expect(clearButton).toBeNull();
});
it('should reset the search when clicking the clear button', async () => {
const resetEmitSpy = spyOn(component.reset, 'emit');
const searchVisibilityChangeSpy = spyOn(component.searchVisibility, 'emit');
component.searchTerm = 'fake-search-term';
component.showClearButton = true;
fixture.detectChanges();
await fixture.whenStable();
const clearButton = fixture.debugElement.query(By.css('[data-automation-id="adf-clear-search-button"]'));
clearButton.nativeElement.dispatchEvent(new MouseEvent('mousedown'));
fixture.detectChanges();
await fixture.whenStable();
expect(resetEmitSpy).toHaveBeenCalled();
expect(searchVisibilityChangeSpy).toHaveBeenCalledWith(false);
expect(component.subscriptAnimationState.value).toEqual('inactive');
expect(component.searchTerm).toEqual('');
});
});
describe('Collapse on blur', () => {
beforeEach(fakeAsync(() => {
fixture.detectChanges();
component.toggleSearchBar();
tick(200);
}));
it('should collapse search on blur when the collapseOnBlur is set to true', fakeAsync (() => {
const searchVisibilityChangeSpy = spyOn(component.searchVisibility, 'emit');
const resetEmitSpy = spyOn(component.reset, 'emit');
component.collapseOnBlur = true;
component.searchTerm = 'fake-search-term';
component.onBlur({ relatedTarget: null });
tick(200);
expect(searchVisibilityChangeSpy).toHaveBeenCalledWith(false);
expect(component.subscriptAnimationState.value).toEqual('inactive');
expect(component.searchTerm).toEqual('');
expect(resetEmitSpy).toHaveBeenCalled();
}));
it('should not collapse search on blur when the collapseOnBlur is set to false', () => {
const searchVisibilityChangeSpy = spyOn(component.searchVisibility, 'emit');
component.searchTerm = 'fake-search-term';
component.collapseOnBlur = false;
component.onBlur({ relatedTarget: null });
expect(searchVisibilityChangeSpy).not.toHaveBeenCalled();
expect(component.subscriptAnimationState.value).toEqual('active');
expect(component.searchTerm).toEqual('fake-search-term');
});
});
});
});

View File

@@ -1,196 +0,0 @@
/*!
* @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 { CoreStoryModule } from '../testing/core.story.module';
import { SearchTextInputComponent } from './search-text-input.component';
import { SearchTextModule } from './search-text-input.module';
export default {
component: SearchTextInputComponent,
title: 'Core/Search Text Input/Search Text Input',
decorators: [
moduleMetadata({
imports: [CoreStoryModule, SearchTextModule]
})
],
argTypes: {
autocomplete: {
control: 'boolean',
description: 'Toggles auto-completion of the search input field.',
defaultValue: false,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
},
expandable: {
control: 'boolean',
description: 'Toggles whether to use an expanding search control. If false, a regular input is used.',
defaultValue: true,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'true' }
}
},
inputType: {
control: 'radio',
options: ['date', 'month', 'number', 'search', 'text', 'time'],
description: 'Type of the input field to render, e.g. "search" or "text" (default).',
defaultValue: 'text',
table: {
category: 'HTML input attributes',
type: { summary: 'string' },
defaultValue: { summary: 'text' }
}
},
liveSearchEnabled: {
control: 'boolean',
description: 'Toggles "find-as-you-type" suggestions for possible matches.',
defaultValue: true,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'true' }
}
},
searchAutocomplete: {
control: 'boolean',
description: 'Trigger autocomplete results on input change.',
defaultValue: false,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
},
searchTerm: {
control: 'text',
description: 'Search term preselected.',
defaultValue: '',
table: {
category: 'HTML input attributes',
type: { summary: 'string' },
defaultValue: { summary: '' }
}
},
debounceTime: {
control: 'number',
description: 'Debounce time in milliseconds.',
defaultValue: 0,
table: {
type: { summary: 'number' },
defaultValue: { summary: '0' }
}
},
focusListener: {
control: 'object',
description: 'Listener for results-list events (focus, blur and focusout).',
table: {
type: { summary: 'Observable<FocusEvent>' }
}
},
collapseOnSubmit: {
control: 'boolean',
description: 'Collapse search bar on submit.',
defaultValue: true,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'true' }
}
},
defaultState: {
control: 'inline-radio',
options: ['collapsed', 'expanded'],
description: 'Default state.',
defaultValue: 'collapsed',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'collapsed' }
}
},
collapseOnBlur: {
control: 'boolean',
description: 'Collapse search bar on blur.',
defaultValue: true,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'true' }
}
},
showClearButton: {
control: 'boolean',
description: 'Toggles whether to show a clear button that closes the search.',
defaultValue: false,
table: {
type: { summary: 'boolean' },
defaultValue: { summary: 'false' }
}
},
placeholder: {
control: 'text',
description: 'Placeholder text to show in the input field.',
defaultValue: '',
table: {
category: 'HTML input attributes',
type: { summary: 'string' },
defaultValue: { summary: '' }
}
},
hintLabel: {
control: 'text',
description: 'Hint label.',
defaultValue: '',
table: {
category: 'HTML input attributes',
type: { summary: 'string' },
defaultValue: { summary: '' }
}
},
searchChange: {
action: 'searchChange',
description: 'Emitted when the search term is changed. The search term is provided in the "value" property of the returned object. If the term is less than three characters in length then it is truncated to an empty string.',
table: { category: 'Actions' }
},
submit: {
action: 'submit',
description: 'Emitted when the search is submitted by pressing the ENTER key.',
table: { category: 'Actions' }
},
selectResult: {
action: 'selectResult',
description: 'Emitted when the result list is selected.',
table: { category: 'Actions' }
},
reset: {
action: 'reset',
description: 'Emitted when the result list is reset.',
table: { category: 'Actions' }
},
searchVisibility: {
action: 'searchVisibility',
description: 'Emitted when the search visibility changes. True when the search is active, false when it is inactive.',
table: { category: 'Actions' }
}
}
} as Meta;
const template: Story<SearchTextInputComponent> = (args: SearchTextInputComponent) => ({
props: args
});
export const searchTextInput = template.bind({});
searchTextInput.parameters = { layout: 'centered' };

View File

@@ -1,323 +0,0 @@
/*!
* @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 { ViewEncapsulation, Component, Input, OnDestroy, ViewChild, ElementRef, Output, EventEmitter, OnInit } from '@angular/core';
import { Subject, Observable, Subscription } from 'rxjs';
import { debounceTime, takeUntil, filter } from 'rxjs/operators';
import { Direction } from '@angular/cdk/bidi';
import { searchAnimation } from './animations';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { SearchTextStateEnum, SearchAnimationState, SearchAnimationDirection } from '../models/search-text-input.model';
@Component({
selector: 'adf-search-text-input',
templateUrl: './search-text-input.component.html',
styleUrls: ['./search-text-input.component.scss'],
animations: [searchAnimation],
encapsulation: ViewEncapsulation.None,
host: {
class: 'adf-search-text-input'
}
})
export class SearchTextInputComponent implements OnInit, OnDestroy {
/** Toggles auto-completion of the search input field. */
@Input()
autocomplete: boolean = false;
/** Toggles whether to use an expanding search control. If false
* then a regular input is used.
*/
@Input()
expandable: boolean = true;
/** Type of the input field to render, e.g. "search" or "text" (default). */
@Input()
inputType: string = 'text';
/** Toggles "find-as-you-type" suggestions for possible matches. */
@Input()
liveSearchEnabled: boolean = true;
/** Trigger autocomplete results on input change. */
@Input()
searchAutocomplete: any = false;
/** Search term preselected */
@Input()
searchTerm: string = '';
/** Debounce time in milliseconds. */
@Input()
debounceTime: number = 0;
/** Listener for results-list events (focus, blur and focusout). */
@Input()
focusListener: Observable<FocusEvent>;
/** Collapse search bar on submit. */
@Input()
collapseOnSubmit: boolean = true;
/** Default state expanded or Collapsed. */
@Input()
defaultState: SearchTextStateEnum = SearchTextStateEnum.collapsed;
/** Toggles whether to collapse the search on blur. */
@Input()
collapseOnBlur: boolean = true;
/** Toggles whether to show a clear button that closes the search */
@Input()
showClearButton: boolean = false;
/** Placeholder text to show in the input field */
@Input()
placeholder: string = '';
/** Hint label */
@Input()
hintLabel = '';
/** Emitted when the search term is changed. The search term is provided
* in the 'value' property of the returned object. If the term is less
* than three characters in length then it is truncated to an empty
* string.
*/
@Output()
searchChange: EventEmitter<string> = new EventEmitter();
/** Emitted when the search is submitted by pressing the ENTER key.
* The search term is provided as the value of the event.
*/
@Output()
submit: EventEmitter<any> = new EventEmitter();
/** Emitted when the result list is selected */
@Output()
selectResult: EventEmitter<any> = new EventEmitter();
/** Emitted when the result list is reset */
@Output()
reset: EventEmitter<boolean> = new EventEmitter();
/** Emitted when the search visibility changes. True when the search is active, false when it is inactive */
@Output()
searchVisibility: EventEmitter<boolean> = new EventEmitter<boolean>();
@ViewChild('searchInput', { static: true })
searchInput: ElementRef;
subscriptAnimationState: any;
animationStates: SearchAnimationDirection = {
ltr : {
active: { value: 'active', params: { 'margin-left': 13 } },
inactive: { value: 'inactive', params: { transform: 'translateX(82%)' } }
},
rtl: {
active: { value: 'active', params: { 'margin-right': 13 } },
inactive: { value: 'inactive', params: { transform: 'translateX(-82%)' } }
}
};
private dir = 'ltr';
private onDestroy$ = new Subject<boolean>();
private toggleSearch = new Subject<any>();
private focusSubscription: Subscription;
private valueChange = new Subject<string>();
constructor(
private userPreferencesService: UserPreferencesService
) {
this.toggleSearch
.pipe(
debounceTime(200),
takeUntil(this.onDestroy$)
)
.subscribe(() => {
if (this.expandable) {
this.subscriptAnimationState = this.toggleAnimation();
if (this.subscriptAnimationState.value === 'inactive') {
this.searchTerm = '';
this.reset.emit(true);
if (document.activeElement.id === this.searchInput.nativeElement.id) {
this.searchInput.nativeElement.blur();
}
}
this.emitVisibilitySearch();
}
});
}
ngOnInit() {
this.userPreferencesService
.select('textOrientation')
.pipe(takeUntil(this.onDestroy$))
.subscribe((direction: Direction) => {
this.dir = direction;
this.subscriptAnimationState = this.getDefaultState(this.dir);
});
this.subscriptAnimationState = this.getDefaultState(this.dir);
this.setValueChangeHandler();
this.setupFocusEventHandlers();
}
applySearchFocus(animationDoneEvent) {
if (animationDoneEvent.toState === 'active' && this.isDefaultStateCollapsed()) {
this.searchInput.nativeElement.focus();
}
}
getAutoComplete(): string {
return this.autocomplete ? 'on' : 'off';
}
private toggleAnimation() {
if (this.dir === 'ltr') {
return this.subscriptAnimationState.value === 'inactive' ?
{ value: 'active', params: { 'margin-left': 13 } } :
{ value: 'inactive', params: { transform: 'translateX(82%)' } };
} else {
return this.subscriptAnimationState.value === 'inactive' ?
{ value: 'active', params: { 'margin-right': 13 } } :
{ value: 'inactive', params: { transform: 'translateX(-82%)' } };
}
}
private getDefaultState(dir: string): SearchAnimationState {
if (this.dir) {
return this.getAnimationState(dir);
}
return this.animationStates.ltr.inactive;
}
private getAnimationState(dir: string): SearchAnimationState {
if (this.expandable && this.isDefaultStateExpanded()) {
return this.animationStates[dir].active;
} else if ( this.expandable ) {
return this.animationStates[dir].inactive;
} else {
return { value: 'no-animation' };
}
}
private setupFocusEventHandlers() {
if ( this.focusListener ) {
const focusEvents: Observable<FocusEvent> = this.focusListener
.pipe(
debounceTime(50),
filter(($event: any) => this.isSearchBarActive() && ($event.type === 'blur' || $event.type === 'focusout' || $event.type === 'focus')),
takeUntil(this.onDestroy$)
);
this.focusSubscription = focusEvents.subscribe( (event: FocusEvent) => {
if ( event.type === 'focus') {
this.searchInput.nativeElement.focus();
} else {
this.toggleSearchBar();
}
});
}
}
private setValueChangeHandler() {
this.valueChange.pipe(
debounceTime(this.debounceTime),
takeUntil(this.onDestroy$)
).subscribe( (value: string) => {
this.searchChange.emit(value);
});
}
selectFirstResult($event) {
this.selectResult.emit($event);
}
onBlur($event) {
if (this.collapseOnBlur && !$event.relatedTarget) {
this.resetSearch();
}
}
inputChange($event: any) {
this.valueChange.next($event);
}
toggleSearchBar() {
if (this.toggleSearch) {
this.toggleSearch.next();
}
}
searchSubmit(event: any) {
this.submit.emit(event);
if (this.collapseOnSubmit) {
this.toggleSearchBar();
}
}
activateToolbar(): boolean {
if (!this.isSearchBarActive()) {
this.toggleSearchBar();
}
return false;
}
isSearchBarActive(): boolean {
return this.subscriptAnimationState.value === 'active';
}
ngOnDestroy() {
if (this.toggleSearch) {
this.toggleSearch.complete();
this.toggleSearch = null;
}
if (this.focusSubscription) {
this.focusSubscription.unsubscribe();
this.focusSubscription = null;
this.focusListener = null;
}
this.onDestroy$.next(true);
this.onDestroy$.complete();
}
canShowClearSearch(): boolean {
return this.showClearButton && this.isSearchBarActive();
}
resetSearch() {
if (this.isSearchBarActive()) {
this.toggleSearchBar();
}
}
private isDefaultStateCollapsed(): boolean {
return this.defaultState === SearchTextStateEnum.collapsed;
}
private isDefaultStateExpanded(): boolean {
return this.defaultState === SearchTextStateEnum.expanded;
}
private emitVisibilitySearch() {
this.searchVisibility.emit(this.isSearchBarActive());
}
}

View File

@@ -1,42 +0,0 @@
/*!
* @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 { CommonModule } from '@angular/common';
import { MaterialModule } from '../material.module';
import { FormsModule } from '@angular/forms';
import { SearchTextInputComponent } from './search-text-input.component';
import { TranslateModule } from '@ngx-translate/core';
import { SearchTriggerDirective } from './search-trigger.directive';
@NgModule({
declarations: [
SearchTextInputComponent,
SearchTriggerDirective
],
imports: [
CommonModule,
TranslateModule,
MaterialModule,
FormsModule
],
exports: [
SearchTextInputComponent,
SearchTriggerDirective
]
})
export class SearchTextModule {}

View File

@@ -1,222 +0,0 @@
/*!
* @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.
*/
/* eslint-disable @angular-eslint/no-input-rename, @typescript-eslint/no-use-before-define, @angular-eslint/no-input-rename */
import { ENTER, ESCAPE } from '@angular/cdk/keycodes';
import {
ChangeDetectorRef,
Directive,
ElementRef,
forwardRef,
Inject,
Input,
NgZone,
OnDestroy,
Optional
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { DOCUMENT } from '@angular/common';
import { Observable, Subject, Subscription, merge, of, fromEvent } from 'rxjs';
import { filter, switchMap, takeUntil } from 'rxjs/operators';
import { SearchComponentInterface } from './interfaces/search-configuration.interface';
export const SEARCH_AUTOCOMPLETE_VALUE_ACCESSOR: any = {
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => SearchTriggerDirective),
multi: true
};
/**
* Directive selectors without adf- prefix will be deprecated on 3.0.0
*/
@Directive({
// eslint-disable-next-line @angular-eslint/directive-selector
selector: `input[searchAutocomplete], textarea[searchAutocomplete]`,
host: {
role: 'combobox',
'[attr.autocomplete]': 'autocomplete',
'aria-autocomplete': 'list',
'[attr.aria-expanded]': 'panelOpen.toString()',
'(blur)': 'onTouched()',
'(input)': 'handleInput($event)',
'(keydown)': 'handleKeydown($event)'
},
providers: [SEARCH_AUTOCOMPLETE_VALUE_ACCESSOR]
})
export class SearchTriggerDirective implements ControlValueAccessor, OnDestroy {
private onDestroy$: Subject<boolean> = new Subject<boolean>();
@Input('searchAutocomplete')
searchPanel: SearchComponentInterface;
@Input()
autocomplete: string = 'off';
private _panelOpen: boolean = false;
private closingActionsSubscription: Subscription;
private escapeEventStream = new Subject<void>();
onChange: (value: any) => void = () => { };
onTouched = () => { };
constructor(private element: ElementRef,
private ngZone: NgZone,
private changeDetectorRef: ChangeDetectorRef,
@Optional() @Inject(DOCUMENT) private document: any) { }
ngOnDestroy() {
this.onDestroy$.next(true);
this.onDestroy$.complete();
if (this.escapeEventStream) {
this.escapeEventStream = null;
}
if ( this.closingActionsSubscription ) {
this.closingActionsSubscription.unsubscribe();
}
}
get panelOpen(): boolean {
return this._panelOpen && this.searchPanel.showPanel;
}
openPanel(): void {
this.searchPanel.isOpen = this._panelOpen = true;
this.closingActionsSubscription = this.subscribeToClosingActions();
}
closePanel(): void {
if (this._panelOpen) {
this.closingActionsSubscription.unsubscribe();
this._panelOpen = false;
this.searchPanel.resetResults();
this.searchPanel.hidePanel();
this.changeDetectorRef.detectChanges();
}
}
get panelClosingActions(): Observable<any> {
return merge(
this.escapeEventStream,
this.outsideClickStream
);
}
private get outsideClickStream(): Observable<any> {
if (!this.document) {
return of(null);
}
return merge(
fromEvent(this.document, 'click'),
fromEvent(this.document, 'touchend')
).pipe(
filter((event: MouseEvent | TouchEvent) => {
const clickTarget = event.target as HTMLElement;
return this._panelOpen && clickTarget !== this.element.nativeElement;
}),
takeUntil(this.onDestroy$)
);
}
writeValue(value: any): void {
Promise.resolve(null).then(() => this.setTriggerValue(value));
}
registerOnChange(fn: (value: any) => any): void {
this.onChange = fn;
}
registerOnTouched(fn: () => any) {
this.onTouched = fn;
}
handleKeydown(event: KeyboardEvent): void {
const keyCode = event.keyCode;
if (keyCode === ESCAPE && this.panelOpen) {
this.escapeEventStream.next();
event.stopPropagation();
} else if (keyCode === ENTER) {
this.escapeEventStream.next();
event.preventDefault();
}
}
handleInput(event: KeyboardEvent): void {
if (document.activeElement === event.target ) {
const inputValue: string = (event.target as HTMLInputElement).value;
this.onChange(inputValue);
if (inputValue && this.searchPanel) {
this.searchPanel.keyPressedStream.next(inputValue);
this.openPanel();
} else if (this.searchPanel) {
this.searchPanel.resetResults();
this.closePanel();
}
}
}
private isPanelOptionClicked(event: MouseEvent) {
let isPanelOption: boolean = false;
if ( event && this.searchPanel ) {
const clickTarget = event.target as HTMLElement;
isPanelOption = !this.isNoResultOption() &&
!!this.searchPanel.panel &&
!!this.searchPanel.panel.nativeElement.contains(clickTarget);
}
return isPanelOption;
}
private isNoResultOption(): boolean {
return this.searchPanel && this.searchPanel.results.list ? this.searchPanel.results.list.entries.length === 0 : true;
}
private subscribeToClosingActions(): Subscription {
const firstStable = this.ngZone.onStable.asObservable();
const optionChanges = this.searchPanel.keyPressedStream.asObservable();
return merge(firstStable, optionChanges)
.pipe(
switchMap(() => {
this.searchPanel.setVisibility();
return this.panelClosingActions;
}),
takeUntil(this.onDestroy$)
)
.subscribe((event) => this.setValueAndClose(event));
}
private setTriggerValue(value: any): void {
const toDisplay = this.searchPanel && this.searchPanel.displayWith ?
this.searchPanel.displayWith(value) : value;
const inputValue = toDisplay != null ? toDisplay : '';
this.element.nativeElement.value = inputValue;
}
private setValueAndClose(event: any | null): void {
if (this.isPanelOptionClicked(event) && !event.defaultPrevented) {
this.setTriggerValue(event.target.textContent.trim());
this.onChange(event.target.textContent.trim());
this.element.nativeElement.focus();
}
this.closePanel();
}
}

View File

@@ -19,7 +19,6 @@ import { Injectable } from '@angular/core';
import { DomSanitizer } from '@angular/platform-browser';
import { ContentApi, MinimalNode, Node, NodeEntry, NodesApi } from '@alfresco/js-api';
import { Observable, Subject, from, throwError } from 'rxjs';
import { FolderCreatedEvent } from '../events/folder-created.event';
import { AlfrescoApiService } from './alfresco-api.service';
import { AuthenticationService } from '../auth/services/authentication.service';
import { LogService } from '../common/services/log.service';
@@ -27,7 +26,14 @@ import { catchError } from 'rxjs/operators';
import { PermissionsEnum } from '../models/permissions.enum';
import { AllowableOperationsEnum } from '../models/allowable-operations.enum';
import { DownloadService } from './download.service';
import { ThumbnailService } from './thumbnail.service';
import { ThumbnailService } from '../common/services/thumbnail.service';
export interface FolderCreatedEvent {
name: string;
relativePath?: string;
parentId?: string;
node?: NodeEntry;
}
@Injectable({
providedIn: 'root'

View File

@@ -1,85 +0,0 @@
/*!
* @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 {
AlfrescoApiCompatibility,
ContentApi,
Node, NodesApi
} from '@alfresco/js-api';
import { ReplaySubject, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class ExternalAlfrescoApiService {
/**
* Publish/subscribe to events related to node updates.
*/
nodeUpdated = new Subject<Node>();
alfrescoApiInitialized: ReplaySubject<boolean> = new ReplaySubject(1);
protected alfrescoApi: AlfrescoApiCompatibility;
_nodesApi: NodesApi;
getInstance(): AlfrescoApiCompatibility {
return this.alfrescoApi;
}
get contentApi(): ContentApi {
return this.getInstance().content;
}
get nodesApi(): NodesApi {
this._nodesApi = this._nodesApi ?? new NodesApi(this.getInstance());
return this._nodesApi;
}
init(ecmHost: string, contextRoot: string) {
const domainPrefix = this.createPrefixFromHost(ecmHost);
const config = {
provider: 'ECM',
hostEcm: ecmHost,
authType: 'BASIC',
contextRoot,
domainPrefix
};
this.initAlfrescoApi(config);
this.alfrescoApiInitialized.next(true);
}
protected initAlfrescoApi(config) {
if (this.alfrescoApi) {
this.alfrescoApi.configureJsApi(config);
} else {
this.alfrescoApi = new AlfrescoApiCompatibility(config);
}
}
private createPrefixFromHost(url: string): string {
const match = url.match(/:\/\/(www[0-9]?\.)?(.[^/:]+)/i);
let result = null;
if (match != null && match.length > 2 && typeof match[2] === 'string' && match[2].length > 0) {
result = match[2];
}
return result;
}
}

View File

@@ -17,27 +17,16 @@
export * from './alfresco-api.service';
export * from './content.service';
export * from './page-title.service';
export * from './renditions.service';
export * from './translation.service';
export * from './translate-loader.service';
export * from './thumbnail.service';
export * from './upload.service';
export * from './dynamic-component-mapper.service';
export * from './highlight-transform.service';
export * from './deleted-nodes-api.service';
export * from './nodes-api.service';
export * from './people-content.service';
export * from './people-process.service';
export * from './discovery-api.service';
export * from './external-alfresco-api.service';
export * from './download-zip.service';
export * from './automation.service';
export * from './automation.service';
export * from './download.service';
export * from './bpm-user.service';
export * from './ecm-user.service';
export * from './language.service';
export * from './sort-by-category.service';
export * from './user-access.service';
export * from './user-info-resolver.service';

View File

@@ -18,7 +18,7 @@
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { CoreTestingModule } from '../../testing/core.testing.module';
import { ErrorContentComponent } from './error-content.component';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
import { setupTestBed } from '../../testing/setup-test-bed';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';

View File

@@ -23,7 +23,7 @@ import {
OnInit
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
@Component({
selector: 'adf-error-content',
templateUrl: './error-content.component.html',

View File

@@ -17,7 +17,7 @@
import { Injectable } from '@angular/core';
import { AppConfigService } from '../app-config/app-config.service';
import { AlfrescoApiService } from './alfresco-api.service';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { StorageService } from '../common/services/storage.service';
import { UserPreferencesService } from '../common/services/user-preferences.service';
import { DemoForm } from '../mock/form/demo-form.mock';

View File

@@ -19,7 +19,7 @@ import { NgModule } from '@angular/core';
import { CoreModule } from '../core.module';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateModule } from '@ngx-translate/core';
import { TRANSLATION_PROVIDER } from '../services/translation.service';
import { TRANSLATION_PROVIDER } from '../translation/translation.service';
@NgModule({
imports: [

View File

@@ -24,14 +24,14 @@ import { AlfrescoApiService } from '../services/alfresco-api.service';
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
import { AppConfigService } from '../app-config/app-config.service';
import { AppConfigServiceMock } from '../common/mock/app-config.service.mock';
import { TranslationService } from '../services/translation.service';
import { TranslationService } from '../translation/translation.service';
import { TranslationMock } from '../mock/translation.service.mock';
import { DatePipe } from '@angular/common';
import { CookieService } from '../common/services/cookie.service';
import { CookieServiceMock } from '../mock/cookie.service.mock';
import { HttpClientModule } from '@angular/common/http';
import { directionalityConfigFactory } from '../services/directionality-config-factory';
import { DirectionalityConfigService } from '../services/directionality-config.service';
import { directionalityConfigFactory } from '../common/services/directionality-config-factory';
import { DirectionalityConfigService } from '../common/services/directionality-config.service';
@NgModule({
imports: [

View File

@@ -17,3 +17,4 @@
export * from './setup-test-bed';
export * from './core.testing.module';
export * from './automation.service';

View File

@@ -15,4 +15,5 @@
* limitations under the License.
*/
export const getType = (type: any): any => () => type;
export * from './translation.service';
export * from './translate-loader.service';

View File

@@ -24,7 +24,7 @@ import { TranslateLoaderService } from './translate-loader.service';
import { TRANSLATION_PROVIDER, TranslationService } from './translation.service';
import { AppConfigService } from '../app-config/app-config.service';
import { AppConfigServiceMock } from '../common/mock/app-config.service.mock';
import { AlfrescoApiService } from './alfresco-api.service';
import { AlfrescoApiService } from '../services/alfresco-api.service';
import { AlfrescoApiServiceMock } from '../mock/alfresco-api.service.mock';
declare let jasmine: any;

View File

@@ -21,7 +21,7 @@ import { AlfrescoApiService } from '../../services/alfresco-api.service';
import { LogService } from '../../common/services/log.service';
import { Subject } from 'rxjs';
import { Track } from '../models/viewer.model';
import { TranslationService } from '../../services/translation.service';
import { TranslationService } from '../../translation/translation.service';
@Injectable({
providedIn: 'root'

View File

@@ -41,10 +41,10 @@ export * from './lib/clipboard/index';
export * from './lib/dialogs/index';
export * from './lib/icon/index';
export * from './lib/notifications/index';
export * from './lib/search-text/index';
export * from './lib/blank-page/index';
export * from './lib/rich-text-editor/index';
export * from './lib/snackbar-content/index';
export * from './lib/translation/index';
export * from './lib/common/utils/index';
export * from './lib/interface/index';