ACS-7390: Migrating content components to Standalone (#9997)

* ACS-7393: content metadata as standalone

* ACS-7408: version manager as standalone

* ACS-7408: version manager as standalone

* ACS-7408: version manager as standalone

* ACS-7407: upload as standalone

* ACS-7404: tag as standalone

* ACS-7404: tag as standalone

* ACS-7401: permission manager as standalone

* ACS-7395: content node share as standalone

* ACS-7402: search components [ci:force]

* ACS-7402: search components [ci:force]

* content node selector panel

* content node selector panel

* Revert "content node selector panel"

This reverts commit 3ad828e443.

* Revert "content node selector panel"

This reverts commit 5a2cd5a5b3.
This commit is contained in:
Denys Vuika
2024-07-26 11:04:02 -04:00
committed by GitHub
parent 36eb19de67
commit e4b9cf3dbe
70 changed files with 682 additions and 516 deletions

View File

@@ -61,7 +61,8 @@ describe('ContentMetadataCardComponent', () => {
MatDialogModule, MatDialogModule,
PipeModule, PipeModule,
MatSnackBarModule, MatSnackBarModule,
MatTooltipModule MatTooltipModule,
ContentMetadataCardComponent
], ],
providers: [ providers: [
{ provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock }, { provide: AlfrescoApiService, useClass: AlfrescoApiServiceMock },
@@ -69,7 +70,7 @@ describe('ContentMetadataCardComponent', () => {
{ {
provide: APP_INITIALIZER, provide: APP_INITIALIZER,
useFactory: versionCompatibilityFactory, useFactory: versionCompatibilityFactory,
deps: [ VersionCompatibilityService ], deps: [VersionCompatibilityService],
multi: true multi: true
} }
] ]

View File

@@ -22,9 +22,17 @@ import { ContentMetadataCustomPanel, PresetConfig } from '../../interfaces/conte
import { VersionCompatibilityService } from '../../../version-compatibility/version-compatibility.service'; import { VersionCompatibilityService } from '../../../version-compatibility/version-compatibility.service';
import { ContentService } from '../../../common/services/content.service'; import { ContentService } from '../../../common/services/content.service';
import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum'; import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ContentMetadataComponent } from '../content-metadata/content-metadata.component';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
@Component({ @Component({
selector: 'adf-content-metadata-card', selector: 'adf-content-metadata-card',
standalone: true,
imports: [CommonModule, MatCardModule, ContentMetadataComponent, MatButtonModule, MatIconModule, TranslateModule],
templateUrl: './content-metadata-card.component.html', templateUrl: './content-metadata-card.component.html',
styleUrls: ['./content-metadata-card.component.scss'], styleUrls: ['./content-metadata-card.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,

View File

@@ -195,7 +195,8 @@ describe('ContentMetadataComponent', () => {
MatSnackBarModule, MatSnackBarModule,
MatProgressBarModule, MatProgressBarModule,
MatTooltipModule, MatTooltipModule,
PipeModule PipeModule,
ContentMetadataComponent
], ],
providers: [ providers: [
{ provide: TranslationService, useClass: TranslationMock }, { provide: TranslationService, useClass: TranslationMock },

View File

@@ -15,21 +15,14 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewEncapsulation } from '@angular/core';
Component,
Input,
OnChanges,
OnDestroy,
OnInit,
SimpleChanges,
ViewEncapsulation
} from '@angular/core';
import { Category, CategoryEntry, CategoryLinkBody, CategoryPaging, Node, TagBody, TagEntry, TagPaging } from '@alfresco/js-api'; import { Category, CategoryEntry, CategoryLinkBody, CategoryPaging, Node, TagBody, TagEntry, TagPaging } from '@alfresco/js-api';
import { forkJoin, Observable, of, Subject, zip } from 'rxjs'; import { forkJoin, Observable, of, Subject, zip } from 'rxjs';
import { import {
AppConfigService, AppConfigService,
CardViewBaseItemModel, CardViewBaseItemModel,
CardViewItem, CardViewItem,
CardViewModule,
NotificationService, NotificationService,
TranslationService, TranslationService,
UpdateNotification UpdateNotification
@@ -45,6 +38,17 @@ import { CategoryService } from '../../../category/services/category.service';
import { CategoriesManagementMode } from '../../../category/categories-management/categories-management-mode'; import { CategoriesManagementMode } from '../../../category/categories-management/categories-management-mode';
import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum'; import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum';
import { ContentService } from '../../../common/services/content.service'; import { ContentService } from '../../../common/services/content.service';
import { CommonModule } from '@angular/common';
import { MatExpansionModule } from '@angular/material/expansion';
import { ContentMetadataHeaderComponent } from './content-metadata-header.component';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { MatChipsModule } from '@angular/material/chips';
import { CategoriesManagementComponent } from '../../../category';
import { DynamicExtensionComponent } from '@alfresco/adf-extensions';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { TagsCreatorComponent } from '../../../tag';
const DEFAULT_SEPARATOR = ', '; const DEFAULT_SEPARATOR = ', ';
@@ -56,6 +60,21 @@ enum DefaultPanels {
@Component({ @Component({
selector: 'adf-content-metadata', selector: 'adf-content-metadata',
standalone: true,
imports: [
CommonModule,
MatExpansionModule,
ContentMetadataHeaderComponent,
MatButtonModule,
TranslateModule,
MatIconModule,
CardViewModule,
MatChipsModule,
CategoriesManagementComponent,
DynamicExtensionComponent,
MatProgressBarModule,
TagsCreatorComponent
],
templateUrl: './content-metadata.component.html', templateUrl: './content-metadata.component.html',
styleUrls: ['./content-metadata.component.scss'], styleUrls: ['./content-metadata.component.scss'],
host: { class: 'adf-content-metadata' }, host: { class: 'adf-content-metadata' },
@@ -173,12 +192,10 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
this.updateChanges(updatedNode.changed); this.updateChanges(updatedNode.changed);
}); });
this.cardViewContentUpdateService.updatedAspect$ this.cardViewContentUpdateService.updatedAspect$.pipe(debounceTime(500), takeUntil(this.onDestroy$)).subscribe((node) => {
.pipe(debounceTime(500), takeUntil(this.onDestroy$)) this.node.aspectNames = node?.aspectNames;
.subscribe((node) => { this.loadProperties(node);
this.node.aspectNames = node?.aspectNames; });
this.loadProperties(node);
});
this.loadProperties(this.node); this.loadProperties(this.node);
this.verifyAllowableOperations(); this.verifyAllowableOperations();
@@ -210,7 +227,10 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
} }
isPanelEditing(panelTitle: string): boolean { isPanelEditing(panelTitle: string): boolean {
return this.editing && ((this.currentPanel.panelTitle === panelTitle && this.editedPanelTitle === panelTitle) || this.editedPanelTitle === panelTitle); return (
this.editing &&
((this.currentPanel.panelTitle === panelTitle && this.editedPanelTitle === panelTitle) || this.editedPanelTitle === panelTitle)
);
} }
protected handleUpdateError(error: Error) { protected handleUpdateError(error: Error) {
@@ -250,7 +270,6 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
if (changes.displayDefaultProperties?.currentValue) { if (changes.displayDefaultProperties?.currentValue) {
this.expandPanel(this.DefaultPanels.PROPERTIES); this.expandPanel(this.DefaultPanels.PROPERTIES);
} }
} }
ngOnDestroy() { ngOnDestroy() {
@@ -365,7 +384,8 @@ export class ContentMetadataComponent implements OnChanges, OnInit, OnDestroy {
} }
keyDown(event: KeyboardEvent) { keyDown(event: KeyboardEvent) {
if (event.keyCode === 37 || event.keyCode === 39) { // ArrowLeft && ArrowRight if (event.keyCode === 37 || event.keyCode === 39) {
// ArrowLeft && ArrowRight
event.stopPropagation(); event.stopPropagation();
} }
} }

View File

@@ -15,35 +15,16 @@
* limitations under the License. * limitations under the License.
*/ */
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
import { CoreModule } from '@alfresco/adf-core';
import { ContentMetadataComponent } from './components/content-metadata/content-metadata.component'; import { ContentMetadataComponent } from './components/content-metadata/content-metadata.component';
import { ContentMetadataCardComponent } from './components/content-metadata-card/content-metadata-card.component'; import { ContentMetadataCardComponent } from './components/content-metadata-card/content-metadata-card.component';
import { TagModule } from '../tag/tag.module';
import { CategoriesModule } from '../category/category.module';
import { ExtensionsModule } from '@alfresco/adf-extensions';
import { ContentMetadataHeaderComponent } from './components/content-metadata/content-metadata-header.component'; import { ContentMetadataHeaderComponent } from './components/content-metadata/content-metadata-header.component';
export const CONTENT_METADATA_DIRECTIVES = [ContentMetadataComponent, ContentMetadataCardComponent, ContentMetadataHeaderComponent] as const;
/** @deprecated use `...CONTENT_METADATA_DIRECTIVES` instead */
@NgModule({ @NgModule({
imports: [ imports: [...CONTENT_METADATA_DIRECTIVES],
CommonModule, exports: [...CONTENT_METADATA_DIRECTIVES]
MaterialModule,
CoreModule,
TagModule,
CategoriesModule,
ExtensionsModule,
ContentMetadataHeaderComponent
],
exports: [
ContentMetadataComponent,
ContentMetadataCardComponent,
ContentMetadataHeaderComponent
],
declarations: [
ContentMetadataComponent,
ContentMetadataCardComponent
]
}) })
export class ContentMetadataModule {} export class ContentMetadataModule {}

View File

@@ -83,7 +83,6 @@
data-automation-id="adf-share-link" data-automation-id="adf-share-link"
class="adf-share-link__input" class="adf-share-link__input"
matInput matInput
cdkFocusInitial
placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}" placeholder="{{ 'SHARE.PUBLIC-LINK' | translate }}"
[attr.aria-label]="'SHARE.PUBLIC-LINK' | translate" [attr.aria-label]="'SHARE.PUBLIC-LINK' | translate"
formControlName="sharedUrl" formControlName="sharedUrl"

View File

@@ -16,7 +16,7 @@
*/ */
import { TestBed, ComponentFixture } from '@angular/core/testing'; import { TestBed, ComponentFixture } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
import { of } from 'rxjs'; import { of } from 'rxjs';
import { NotificationService } from '@alfresco/adf-core'; import { NotificationService } from '@alfresco/adf-core';
import { NodesApiService, RenditionService } from '../common'; import { NodesApiService, RenditionService } from '../common';
@@ -33,7 +33,6 @@ import { MatSlideToggleHarness } from '@angular/material/slide-toggle/testing';
describe('ShareDialogComponent', () => { describe('ShareDialogComponent', () => {
let loader: HarnessLoader; let loader: HarnessLoader;
let node: NodeEntry; let node: NodeEntry;
let matDialog: MatDialog;
const notificationServiceMock = { const notificationServiceMock = {
openSnackMessage: jasmine.createSpy('openSnackMessage') openSnackMessage: jasmine.createSpy('openSnackMessage')
}; };
@@ -56,7 +55,7 @@ describe('ShareDialogComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule], imports: [ContentTestingModule, MatDialogModule, ShareDialogComponent],
providers: [ providers: [
{ provide: NotificationService, useValue: notificationServiceMock }, { provide: NotificationService, useValue: notificationServiceMock },
{ {
@@ -71,7 +70,6 @@ describe('ShareDialogComponent', () => {
fixture = TestBed.createComponent(ShareDialogComponent); fixture = TestBed.createComponent(ShareDialogComponent);
component = fixture.componentInstance; component = fixture.componentInstance;
matDialog = TestBed.inject(MatDialog);
sharedLinksApiService = TestBed.inject(SharedLinksApiService); sharedLinksApiService = TestBed.inject(SharedLinksApiService);
renditionService = TestBed.inject(RenditionService); renditionService = TestBed.inject(RenditionService);
nodesApiService = TestBed.inject(NodesApiService); nodesApiService = TestBed.inject(NodesApiService);
@@ -179,7 +177,8 @@ describe('ShareDialogComponent', () => {
}); });
it('should open a confirmation dialog when unshare button is triggered', async () => { it('should open a confirmation dialog when unshare button is triggered', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any); const dialog = fixture.debugElement.injector.get(MatDialog);
const openSpy = spyOn(dialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough(); spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
node.entry.properties['qshare:sharedId'] = 'sharedId'; node.entry.properties['qshare:sharedId'] = 'sharedId';
@@ -194,11 +193,12 @@ describe('ShareDialogComponent', () => {
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
await toggle.toggle(); await toggle.toggle();
expect(matDialog.open).toHaveBeenCalled(); expect(openSpy).toHaveBeenCalled();
}); });
it('should unshare file when confirmation dialog returns true', async () => { it('should unshare file when confirmation dialog returns true', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(true) } as any); const dialog = fixture.debugElement.injector.get(MatDialog);
spyOn(dialog, 'open').and.returnValue({ beforeClosed: () => of(true) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({})); spyOn(sharedLinksApiService, 'deleteSharedLink').and.returnValue(of({}));
node.entry.properties['qshare:sharedId'] = 'sharedId'; node.entry.properties['qshare:sharedId'] = 'sharedId';
@@ -208,6 +208,7 @@ describe('ShareDialogComponent', () => {
}; };
fixture.detectChanges(); fixture.detectChanges();
await fixture.whenStable();
const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId })); const toggle = await loader.getHarness(MatSlideToggleHarness.with({ selector: shareToggleId }));
await toggle.toggle(); await toggle.toggle();
@@ -216,7 +217,8 @@ describe('ShareDialogComponent', () => {
}); });
it('should not unshare file when confirmation dialog returns false', async () => { it('should not unshare file when confirmation dialog returns false', async () => {
spyOn(matDialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any); const dialog = fixture.debugElement.injector.get(MatDialog);
spyOn(dialog, 'open').and.returnValue({ beforeClosed: () => of(false) } as any);
spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough(); spyOn(sharedLinksApiService, 'deleteSharedLink').and.callThrough();
node.entry.properties['qshare:sharedId'] = 'sharedId'; node.entry.properties['qshare:sharedId'] = 'sharedId';

View File

@@ -16,17 +16,24 @@
*/ */
import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core'; import { Component, Inject, OnInit, ViewEncapsulation, ViewChild, OnDestroy } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialog, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { MatSlideToggleChange } from '@angular/material/slide-toggle'; import { MatSlideToggleChange, MatSlideToggleModule } from '@angular/material/slide-toggle';
import { FormControl, FormGroup, Validators } from '@angular/forms'; import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { ContentService } from '../common/services/content.service'; import { ContentService } from '../common/services/content.service';
import { SharedLinksApiService } from './services/shared-links-api.service'; import { SharedLinksApiService } from './services/shared-links-api.service';
import { SharedLinkBodyCreate } from '@alfresco/js-api'; import { SharedLinkBodyCreate } from '@alfresco/js-api';
import { ConfirmDialogComponent } from '@alfresco/adf-core'; import { ClipboardModule, ConfirmDialogComponent } from '@alfresco/adf-core';
import { ContentNodeShareSettings } from './content-node-share.settings'; import { ContentNodeShareSettings } from './content-node-share.settings';
import { RenditionService } from '../common/services/rendition.service'; import { RenditionService } from '../common/services/rendition.service';
import { format, add, endOfDay, isBefore } from 'date-fns'; import { format, add, endOfDay, isBefore } from 'date-fns';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatDatepickerModule } from '@angular/material/datepicker';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
interface SharedDialogFormProps { interface SharedDialogFormProps {
sharedUrl: FormControl<string>; sharedUrl: FormControl<string>;
@@ -35,6 +42,20 @@ interface SharedDialogFormProps {
@Component({ @Component({
selector: 'adf-share-dialog', selector: 'adf-share-dialog',
standalone: true,
imports: [
CommonModule,
TranslateModule,
MatIconModule,
MatDialogModule,
ReactiveFormsModule,
MatSlideToggleModule,
MatFormFieldModule,
MatDatepickerModule,
MatInputModule,
ClipboardModule,
MatButtonModule
],
templateUrl: './content-node-share.dialog.html', templateUrl: './content-node-share.dialog.html',
styleUrls: ['./content-node-share.dialog.scss'], styleUrls: ['./content-node-share.dialog.scss'],
host: { class: 'adf-share-dialog' }, host: { class: 'adf-share-dialog' },

View File

@@ -21,10 +21,12 @@ import { Component } from '@angular/core';
import { DOCUMENT } from '@angular/common'; import { DOCUMENT } from '@angular/common';
import { ContentTestingModule } from '../testing/content.testing.module'; import { ContentTestingModule } from '../testing/content.testing.module';
import { CoreModule } from '@alfresco/adf-core'; import { CoreModule } from '@alfresco/adf-core';
import { ContentNodeShareModule } from './content-node-share.module'; import { NodeSharedDirective } from '@alfresco/adf-content-services';
@Component({ @Component({
selector: 'adf-node-share-test-component', selector: 'adf-node-share-test-component',
standalone: true,
imports: [NodeSharedDirective],
template: ` template: `
<button <button
[disabled]="!shareRef.isFile" [disabled]="!shareRef.isFile"
@@ -51,8 +53,7 @@ describe('NodeSharedDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [CoreModule.forRoot(), ContentTestingModule, ContentNodeShareModule], imports: [CoreModule.forRoot(), ContentTestingModule, NodeShareTestComponent]
declarations: [NodeShareTestComponent]
}); });
fixture = TestBed.createComponent(NodeShareTestComponent); fixture = TestBed.createComponent(NodeShareTestComponent);
document = TestBed.inject(DOCUMENT); document = TestBed.inject(DOCUMENT);

View File

@@ -26,6 +26,7 @@ import { takeUntil } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[adf-share]', selector: '[adf-share]',
standalone: true,
exportAs: 'adfShare' exportAs: 'adfShare'
}) })
export class NodeSharedDirective implements OnChanges, OnDestroy { export class NodeSharedDirective implements OnChanges, OnDestroy {

View File

@@ -16,15 +16,14 @@
*/ */
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CoreModule } from '@alfresco/adf-core';
import { MaterialModule } from '../material.module';
import { ShareDialogComponent } from './content-node-share.dialog'; import { ShareDialogComponent } from './content-node-share.dialog';
import { NodeSharedDirective } from './content-node-share.directive'; import { NodeSharedDirective } from './content-node-share.directive';
export const CONTENT_NODE_SHARE_DIRECTIVES = [ShareDialogComponent, NodeSharedDirective] as const;
/** @deprecated use `...CONTENT_NODE_SHARE_DIRECTIVES` or import each directive individually */
@NgModule({ @NgModule({
imports: [CoreModule, CommonModule, MaterialModule], imports: [...CONTENT_NODE_SHARE_DIRECTIVES],
declarations: [ShareDialogComponent, NodeSharedDirective], exports: [...CONTENT_NODE_SHARE_DIRECTIVES]
exports: [ShareDialogComponent, NodeSharedDirective]
}) })
export class ContentNodeShareModule {} export class ContentNodeShareModule {}

View File

@@ -20,22 +20,19 @@ import { NgModule, ModuleWithProviders, APP_INITIALIZER } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CoreModule, SearchTextModule, provideTranslations } from '@alfresco/adf-core'; import { CoreModule, SearchTextModule, provideTranslations } from '@alfresco/adf-core';
import { MaterialModule } from './material.module'; import { MaterialModule } from './material.module';
import { TagModule } from './tag/tag.module'; import { CONTENT_TAG_DIRECTIVES } from './tag/tag.module';
import { DocumentListModule } from './document-list/document-list.module'; import { DocumentListModule } from './document-list/document-list.module';
import { UploadModule } from './upload/upload.module';
import { SearchModule } from './search/search.module'; import { SearchModule } from './search/search.module';
import { BREADCRUMB_DIRECTIVES } from './breadcrumb/breadcrumb.module'; import { BREADCRUMB_DIRECTIVES } from './breadcrumb/breadcrumb.module';
import { VersionManagerModule } from './version-manager/version-manager.module'; import { CONTENT_VERSION_DIRECTIVES } from './version-manager/version-manager.module';
import { ContentNodeSelectorModule } from './content-node-selector/content-node-selector.module'; import { ContentNodeSelectorModule } from './content-node-selector/content-node-selector.module';
import { ContentNodeShareModule } from './content-node-share/content-node-share.module'; import { CONTENT_NODE_SHARE_DIRECTIVES } from './content-node-share/content-node-share.module';
import { ContentDirectiveModule } from './directives/content-directive.module'; import { CONTENT_DIRECTIVES } from './directives/content-directive.module';
import { CONTENT_DIALOG_DIRECTIVES } from './dialogs/dialog.module'; import { CONTENT_DIALOG_DIRECTIVES } from './dialogs/dialog.module';
import { ContentMetadataModule } from './content-metadata/content-metadata.module'; import { CONTENT_METADATA_DIRECTIVES } from './content-metadata/content-metadata.module';
import { PermissionManagerModule } from './permission-manager/permission-manager.module'; import { CONTENT_PERMISSION_MANAGER_DIRECTIVES } from './permission-manager/permission-manager.module';
import { TreeViewModule } from './tree-view/tree-view.module';
import { ContentTypeModule } from './content-type/content-type.module'; import { ContentTypeModule } from './content-type/content-type.module';
import { AspectListModule } from './aspect-list/aspect-list.module'; import { AspectListModule } from './aspect-list/aspect-list.module';
import { VersionCompatibilityModule } from './version-compatibility/version-compatibility.module';
import { versionCompatibilityFactory } from './version-compatibility/version-compatibility-factory'; import { versionCompatibilityFactory } from './version-compatibility/version-compatibility-factory';
import { VersionCompatibilityService } from './version-compatibility/version-compatibility.service'; import { VersionCompatibilityService } from './version-compatibility/version-compatibility.service';
import { CONTENT_PIPES } from './pipes/content-pipe.module'; import { CONTENT_PIPES } from './pipes/content-pipe.module';
@@ -47,32 +44,35 @@ import { DropdownSitesComponent } from './content-node-selector/site-dropdown/si
import { CategoriesManagementComponent } from './category'; import { CategoriesManagementComponent } from './category';
import { TreeComponent } from './tree'; import { TreeComponent } from './tree';
import { NewVersionUploaderDialogComponent } from './new-version-uploader'; import { NewVersionUploaderDialogComponent } from './new-version-uploader';
import { VersionCompatibilityDirective } from './version-compatibility';
import { CONTENT_UPLOAD_DIRECTIVES } from './upload';
import { TreeViewComponent } from './tree-view';
@NgModule({ @NgModule({
imports: [ imports: [
...CONTENT_PIPES, ...CONTENT_PIPES,
CoreModule, CoreModule,
TagModule, ...CONTENT_TAG_DIRECTIVES,
CommonModule, CommonModule,
FormsModule, FormsModule,
ReactiveFormsModule, ReactiveFormsModule,
...CONTENT_DIALOG_DIRECTIVES, ...CONTENT_DIALOG_DIRECTIVES,
SearchModule, SearchModule,
DocumentListModule, DocumentListModule,
UploadModule, ...CONTENT_UPLOAD_DIRECTIVES,
MaterialModule, MaterialModule,
DropdownSitesComponent, DropdownSitesComponent,
...BREADCRUMB_DIRECTIVES, ...BREADCRUMB_DIRECTIVES,
ContentNodeSelectorModule, ContentNodeSelectorModule,
ContentNodeShareModule, ...CONTENT_NODE_SHARE_DIRECTIVES,
ContentMetadataModule, ...CONTENT_METADATA_DIRECTIVES,
ContentDirectiveModule, ...CONTENT_DIRECTIVES,
PermissionManagerModule, ...CONTENT_PERMISSION_MANAGER_DIRECTIVES,
VersionManagerModule, ...CONTENT_VERSION_DIRECTIVES,
TreeViewModule, TreeViewComponent,
ContentTypeModule, ContentTypeModule,
AspectListModule, AspectListModule,
VersionCompatibilityModule, VersionCompatibilityDirective,
NodeCommentsModule, NodeCommentsModule,
TreeComponent, TreeComponent,
SearchTextModule, SearchTextModule,
@@ -83,23 +83,23 @@ import { NewVersionUploaderDialogComponent } from './new-version-uploader';
providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')], providers: [provideTranslations('adf-content-services', 'assets/adf-content-services')],
exports: [ exports: [
...CONTENT_PIPES, ...CONTENT_PIPES,
TagModule, ...CONTENT_TAG_DIRECTIVES,
DocumentListModule, DocumentListModule,
UploadModule, ...CONTENT_UPLOAD_DIRECTIVES,
SearchModule, SearchModule,
DropdownSitesComponent, DropdownSitesComponent,
...BREADCRUMB_DIRECTIVES, ...BREADCRUMB_DIRECTIVES,
ContentNodeSelectorModule, ContentNodeSelectorModule,
ContentNodeShareModule, ...CONTENT_NODE_SHARE_DIRECTIVES,
ContentMetadataModule, ...CONTENT_METADATA_DIRECTIVES,
...CONTENT_DIALOG_DIRECTIVES, ...CONTENT_DIALOG_DIRECTIVES,
ContentDirectiveModule, ...CONTENT_DIRECTIVES,
PermissionManagerModule, ...CONTENT_PERMISSION_MANAGER_DIRECTIVES,
VersionManagerModule, ...CONTENT_VERSION_DIRECTIVES,
TreeViewModule, TreeViewComponent,
AspectListModule, AspectListModule,
ContentTypeModule, ContentTypeModule,
VersionCompatibilityModule, VersionCompatibilityDirective,
NodeCommentsModule, NodeCommentsModule,
TreeComponent, TreeComponent,
SearchTextModule, SearchTextModule,

View File

@@ -19,8 +19,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { mockFile, mockNode } from '../mock'; import { mockFile, mockNode } from '../mock';
import { ContentTestingModule } from '../testing/content.testing.module'; import { ContentTestingModule } from '../testing/content.testing.module';
import { UploadVersionButtonComponent } from '../upload';
import { VersionComparisonComponent, VersionListComponent, VersionUploadComponent } from '../version-manager';
import { NewVersionUploaderDataAction } from './models'; import { NewVersionUploaderDataAction } from './models';
import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog'; import { NewVersionUploaderDialogComponent } from './new-version-uploader.dialog';
@@ -45,7 +43,6 @@ describe('NewVersionUploaderDialog', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule, NewVersionUploaderDialogComponent], imports: [ContentTestingModule, NewVersionUploaderDialogComponent],
declarations: [VersionListComponent, VersionUploadComponent, UploadVersionButtonComponent, VersionComparisonComponent],
providers: [ providers: [
{ provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } }, { provide: MAT_DIALOG_DATA, useValue: { node: mockNode, showVersionsOnly, file: mockFile } },
{ {

View File

@@ -63,7 +63,7 @@ describe('AddPermissionDialog', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule], imports: [ContentTestingModule, AddPermissionDialogComponent],
providers: [ providers: [
{ provide: MatDialogRef, useValue: dialogRef }, { provide: MatDialogRef, useValue: dialogRef },
{ provide: MAT_DIALOG_DATA, useValue: data } { provide: MAT_DIALOG_DATA, useValue: data }

View File

@@ -16,13 +16,38 @@
*/ */
import { Component, Inject, ViewEncapsulation } from '@angular/core'; import { Component, Inject, ViewEncapsulation } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { NodeEntry, PermissionElement } from '@alfresco/js-api'; import { NodeEntry, PermissionElement } from '@alfresco/js-api';
import { AddPermissionDialogData } from './add-permission-dialog-data.interface'; import { AddPermissionDialogData } from './add-permission-dialog-data.interface';
import { MemberModel } from '../../models/member.model'; import { MemberModel } from '../../models/member.model';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { DataColumnComponent, DataColumnListComponent, DataTableComponent, DateColumnHeaderComponent } from '@alfresco/adf-core';
import { MatIconModule } from '@angular/material/icon';
import { AddPermissionPanelComponent } from './add-permission-panel.component';
import { UserIconColumnComponent } from '../user-icon-column/user-icon-column.component';
import { UserNameColumnComponent } from '../user-name-column/user-name-column.component';
import { UserRoleColumnComponent } from '../user-role-column/user-role-column.component';
@Component({ @Component({
selector: 'adf-add-permission-dialog', selector: 'adf-add-permission-dialog',
standalone: true,
imports: [
CommonModule,
MatDialogModule,
MatButtonModule,
TranslateModule,
DataTableComponent,
DataColumnListComponent,
DataColumnComponent,
DateColumnHeaderComponent,
MatIconModule,
AddPermissionPanelComponent,
UserIconColumnComponent,
UserNameColumnComponent,
UserRoleColumnComponent
],
templateUrl: './add-permission-dialog.component.html', templateUrl: './add-permission-dialog.component.html',
styleUrls: ['./add-permission-dialog.component.scss'], styleUrls: ['./add-permission-dialog.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
@@ -34,8 +59,7 @@ export class AddPermissionDialogComponent {
private existingMembers: PermissionElement[] = []; private existingMembers: PermissionElement[] = [];
currentSelection: NodeEntry[] = []; currentSelection: NodeEntry[] = [];
constructor(@Inject(MAT_DIALOG_DATA) public data: AddPermissionDialogData, constructor(@Inject(MAT_DIALOG_DATA) public data: AddPermissionDialogData, private dialogRef: MatDialogRef<AddPermissionDialogComponent>) {
private dialogRef: MatDialogRef<AddPermissionDialogComponent>) {
this.existingMembers = this.data.node.permissions.locallySet || []; this.existingMembers = this.data.node.permissions.locallySet || [];
} }
@@ -44,18 +68,19 @@ export class AddPermissionDialogComponent {
} }
onAddClicked() { onAddClicked() {
const selection = this.selectedMembers.filter(member => !member.readonly).map(member => member.toPermissionElement()); const selection = this.selectedMembers.filter((member) => !member.readonly).map((member) => member.toPermissionElement());
this.data.confirm.next(selection); this.data.confirm.next(selection);
this.data.confirm.complete(); this.data.confirm.complete();
} }
onSearchAddClicked() { onSearchAddClicked() {
const newMembers = this.currentSelection.map(item => MemberModel.parseFromSearchResult(item)) const newMembers = this.currentSelection
.filter(({id}) => !this.selectedMembers.find((member) => member.id === id)); .map((item) => MemberModel.parseFromSearchResult(item))
.filter(({ id }) => !this.selectedMembers.find((member) => member.id === id));
this.selectedMembers = this.selectedMembers.concat(newMembers); this.selectedMembers = this.selectedMembers.concat(newMembers);
this.selectedMembers.forEach((member) => { this.selectedMembers.forEach((member) => {
const existingMember = this.existingMembers.find(({authorityId}) => authorityId === member.id); const existingMember = this.existingMembers.find(({ authorityId }) => authorityId === member.id);
if (existingMember) { if (existingMember) {
member.role = existingMember.name; member.role = existingMember.name;
member.accessStatus = existingMember.accessStatus; member.accessStatus = existingMember.accessStatus;
@@ -82,8 +107,7 @@ export class AddPermissionDialogComponent {
} }
onBulkUpdate(role: string) { onBulkUpdate(role: string) {
this.selectedMembers.filter(member => !member.readonly) this.selectedMembers.filter((member) => !member.readonly).forEach((member) => (member.role = role));
.forEach(member => (member.role = role));
} }
onMemberDelete({ id }: MemberModel) { onMemberDelete({ id }: MemberModel) {
@@ -101,6 +125,6 @@ export class AddPermissionDialogComponent {
} }
isValid(): boolean { isValid(): boolean {
return this.selectedMembers.filter(({readonly}) => !readonly).length && this.selectedMembers.every(({role}) => !!role); return this.selectedMembers.filter(({ readonly }) => !readonly).length && this.selectedMembers.every(({ role }) => !!role);
} }
} }

View File

@@ -37,7 +37,7 @@ describe('AddPermissionPanelComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule] imports: [ContentTestingModule, AddPermissionPanelComponent]
}); });
fixture = TestBed.createComponent(AddPermissionPanelComponent); fixture = TestBed.createComponent(AddPermissionPanelComponent);
loader = TestbedHarnessEnvironment.loader(fixture); loader = TestbedHarnessEnvironment.loader(fixture);

View File

@@ -19,14 +19,33 @@ import { SearchConfigurationService } from '../../../search/services/search-conf
import { SearchService } from '../../../search/services/search.service'; import { SearchService } from '../../../search/services/search.service';
import { Node, NodeEntry } from '@alfresco/js-api'; import { Node, NodeEntry } from '@alfresco/js-api';
import { Component, EventEmitter, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { UntypedFormControl } from '@angular/forms'; import { ReactiveFormsModule, UntypedFormControl } from '@angular/forms';
import { debounceTime } from 'rxjs/operators'; import { debounceTime } from 'rxjs/operators';
import { SearchPermissionConfigurationService } from './search-config-permission.service'; import { SearchPermissionConfigurationService } from './search-config-permission.service';
import { SearchComponent } from '../../../search/components/search.component'; import { SearchComponent } from '../../../search/components/search.component';
import { MatSelectionList } from '@angular/material/list'; import { MatListModule, MatSelectionList } from '@angular/material/list';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { SearchModule } from '../../../search';
import { UserIconColumnComponent } from '../user-icon-column/user-icon-column.component';
@Component({ @Component({
selector: 'adf-add-permission-panel', selector: 'adf-add-permission-panel',
standalone: true,
imports: [
CommonModule,
MatFormFieldModule,
MatInputModule,
TranslateModule,
ReactiveFormsModule,
MatIconModule,
SearchModule,
MatListModule,
UserIconColumnComponent
],
templateUrl: './add-permission-panel.component.html', templateUrl: './add-permission-panel.component.html',
styleUrls: ['./add-permission-panel.component.scss'], styleUrls: ['./add-permission-panel.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,

View File

@@ -1,6 +1,4 @@
<adf-add-permission-panel <adf-add-permission-panel (select)="onSelect($event)"></adf-add-permission-panel>
(select)="onSelect($event)">
</adf-add-permission-panel>
<div id="adf-add-permission-actions"> <div id="adf-add-permission-actions">
<button mat-button <button mat-button
id="adf-add-permission-action-button" id="adf-add-permission-action-button"

View File

@@ -32,7 +32,7 @@ describe('AddPermissionComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule] imports: [ContentTestingModule, AddPermissionComponent]
}); });
nodePermissionService = TestBed.inject(NodePermissionService); nodePermissionService = TestBed.inject(NodePermissionService);
const response: any = { node: { id: 'fake-node', allowableOperations: ['updatePermissions'] }, roles: [{ label: 'Test', role: 'test' }] }; const response: any = { node: { id: 'fake-node', allowableOperations: ['updatePermissions'] }, roles: [{ label: 'Test', role: 'test' }] };

View File

@@ -21,9 +21,15 @@ import { NodePermissionService } from '../../services/node-permission.service';
import { RoleModel } from '../../models/role.model'; import { RoleModel } from '../../models/role.model';
import { ContentService } from '../../../common/services/content.service'; import { ContentService } from '../../../common/services/content.service';
import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum'; import { AllowableOperationsEnum } from '../../../common/models/allowable-operations.enum';
import { CommonModule } from '@angular/common';
import { AddPermissionPanelComponent } from './add-permission-panel.component';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
@Component({ @Component({
selector: 'adf-add-permission', selector: 'adf-add-permission',
standalone: true,
imports: [CommonModule, AddPermissionPanelComponent, MatButtonModule, TranslateModule],
templateUrl: './add-permission.component.html', templateUrl: './add-permission.component.html',
styleUrls: ['./add-permission.component.scss'], styleUrls: ['./add-permission.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
@@ -32,7 +38,6 @@ import { AllowableOperationsEnum } from '../../../common/models/allowable-operat
* @deprecated in 4.4.0, use adf-add-permission-panel instead. * @deprecated in 4.4.0, use adf-add-permission-panel instead.
*/ */
export class AddPermissionComponent implements OnInit { export class AddPermissionComponent implements OnInit {
/** ID of the target node. */ /** ID of the target node. */
@Input() @Input()
nodeId: string; nodeId: string;
@@ -49,11 +54,10 @@ export class AddPermissionComponent implements OnInit {
currentNode: Node; currentNode: Node;
currentNodeRoles: RoleModel[]; currentNodeRoles: RoleModel[];
constructor(private nodePermissionService: NodePermissionService, constructor(private nodePermissionService: NodePermissionService, private contentService: ContentService) {}
private contentService: ContentService) { }
ngOnInit(): void { ngOnInit(): void {
this.nodePermissionService.getNodeWithRoles(this.nodeId).subscribe(({node, roles }) => { this.nodePermissionService.getNodeWithRoles(this.nodeId).subscribe(({ node, roles }) => {
this.currentNode = node; this.currentNode = node;
this.currentNodeRoles = roles; this.currentNodeRoles = roles;
}); });
@@ -64,20 +68,22 @@ export class AddPermissionComponent implements OnInit {
} }
isAddEnabled(): boolean { isAddEnabled(): boolean {
return this.contentService.hasAllowableOperations(this.currentNode, AllowableOperationsEnum.UPDATEPERMISSIONS) && return (
this.selectedItems.length !== 0; this.contentService.hasAllowableOperations(this.currentNode, AllowableOperationsEnum.UPDATEPERMISSIONS) && this.selectedItems.length !== 0
);
} }
applySelection() { applySelection() {
if (this.contentService.hasAllowableOperations(this.currentNode, AllowableOperationsEnum.UPDATEPERMISSIONS)) { if (this.contentService.hasAllowableOperations(this.currentNode, AllowableOperationsEnum.UPDATEPERMISSIONS)) {
const permissions = this.transformNodeToPermissionElement(this.selectedItems, this.currentNodeRoles[0].role); const permissions = this.transformNodeToPermissionElement(this.selectedItems, this.currentNodeRoles[0].role);
this.nodePermissionService.updateNodePermissions(this.nodeId, permissions) this.nodePermissionService.updateNodePermissions(this.nodeId, permissions).subscribe(
.subscribe((node) => { (node) => {
this.success.emit(node); this.success.emit(node);
}, },
(error) => { (error) => {
this.error.emit(error); this.error.emit(error);
}); }
);
} }
} }

View File

@@ -24,13 +24,13 @@ import { AllowableOperationsEnum } from '../../common/models/allowable-operation
@Directive({ @Directive({
selector: 'button[adf-inherit-permission], mat-button-toggle[adf-inherit-permission]', selector: 'button[adf-inherit-permission], mat-button-toggle[adf-inherit-permission]',
standalone: true,
host: { host: {
role: 'button', role: 'button',
'(click)': 'onInheritPermissionClicked()' '(click)': 'onInheritPermissionClicked()'
} }
}) })
export class InheritPermissionDirective { export class InheritPermissionDirective {
/** ID of the node to add/remove inherited permissions. */ /** ID of the node to add/remove inherited permissions. */
@Input() @Input()
nodeId: string; nodeId: string;
@@ -43,21 +43,21 @@ export class InheritPermissionDirective {
@Output() @Output()
error: EventEmitter<any> = new EventEmitter<any>(); error: EventEmitter<any> = new EventEmitter<any>();
constructor(private nodeService: NodesApiService, constructor(private nodeService: NodesApiService, private contentService: ContentService) {}
private contentService: ContentService) {
}
onInheritPermissionClicked() { onInheritPermissionClicked() {
this.nodeService.getNode(this.nodeId).subscribe((node: Node) => { this.nodeService.getNode(this.nodeId).subscribe((node: Node) => {
if (this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATEPERMISSIONS)) { if (this.contentService.hasAllowableOperations(node, AllowableOperationsEnum.UPDATEPERMISSIONS)) {
const nodeBody = { permissions: { isInheritanceEnabled: !node?.permissions?.isInheritanceEnabled ?? false} }; const nodeBody = { permissions: { isInheritanceEnabled: !node?.permissions?.isInheritanceEnabled ?? false } };
this.nodeService.updateNode(this.nodeId, nodeBody, { include: ['permissions'] }).subscribe((nodeUpdated: Node) => { this.nodeService.updateNode(this.nodeId, nodeBody, { include: ['permissions'] }).subscribe(
this.updated.emit(nodeUpdated); (nodeUpdated: Node) => {
}, (error) => this.error.emit(error)); this.updated.emit(nodeUpdated);
},
(error) => this.error.emit(error)
);
} else { } else {
this.error.emit('PERMISSION_MANAGER.ERROR.NOT-ALLOWED'); this.error.emit('PERMISSION_MANAGER.ERROR.NOT-ALLOWED');
} }
}); });
} }
} }

View File

@@ -18,11 +18,14 @@
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'adf-node-path-column', selector: 'adf-node-path-column',
standalone: true,
imports: [CommonModule],
template: ` template: `
<span class="adf-user-name-column adf-datatable-cell-value" title="{{ displayText$ | async }}"> <span class="adf-user-name-column adf-datatable-cell-value" title="{{ displayText$ | async }}">
{{ displayText$ | async }} {{ displayText$ | async }}
</span> </span>
`, `,

View File

@@ -19,15 +19,47 @@ import { Component, EventEmitter, Input, OnChanges, Output, ViewEncapsulation }
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { PermissionDisplayModel } from '../../models/permission.model'; import { PermissionDisplayModel } from '../../models/permission.model';
import { RoleModel } from '../../models/role.model'; import { RoleModel } from '../../models/role.model';
import { CommonModule } from '@angular/common';
import {
DataColumnComponent,
DataColumnListComponent,
DataTableComponent,
DateColumnHeaderComponent,
EmptyContentComponent,
NoContentTemplateDirective
} from '@alfresco/adf-core';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { UserIconColumnComponent } from '../user-icon-column/user-icon-column.component';
import { UserNameColumnComponent } from '../user-name-column/user-name-column.component';
import { NodePathColumnComponent } from '../node-path-column/node-path-column.component';
import { UserRoleColumnComponent } from '../user-role-column/user-role-column.component';
@Component({ @Component({
selector: 'adf-permission-container', selector: 'adf-permission-container',
templateUrl: './permission-container.component.html', standalone: true,
styleUrls: ['./permission-container.component.scss'], imports: [
encapsulation: ViewEncapsulation.None CommonModule,
DataTableComponent,
DataColumnListComponent,
DataColumnComponent,
TranslateModule,
DateColumnHeaderComponent,
MatButtonModule,
MatIconModule,
NoContentTemplateDirective,
EmptyContentComponent,
UserIconColumnComponent,
UserNameColumnComponent,
NodePathColumnComponent,
UserRoleColumnComponent
],
templateUrl: './permission-container.component.html',
styleUrls: ['./permission-container.component.scss'],
encapsulation: ViewEncapsulation.None
}) })
export class PermissionContainerComponent implements OnChanges { export class PermissionContainerComponent implements OnChanges {
@Input() @Input()
node: Node; node: Node;
@@ -48,7 +80,7 @@ export class PermissionContainerComponent implements OnChanges {
/** Emitted when the permission is updated. */ /** Emitted when the permission is updated. */
@Output() @Output()
update = new EventEmitter<{role: string; permission: PermissionDisplayModel}>(); update = new EventEmitter<{ role: string; permission: PermissionDisplayModel }>();
@Output() @Output()
updateAll = new EventEmitter<string>(); updateAll = new EventEmitter<string>();

View File

@@ -1,8 +1,6 @@
<mat-card class="adf-permission-card" id="adf-permission-manager-card"> <mat-card class="adf-permission-card" id="adf-permission-manager-card">
<div *ngIf="(permissionList.data$ | async) === null && permissionList.loading$ | async" class="adf-permission-loader"> <div *ngIf="(permissionList.data$ | async) === null && permissionList.loading$ | async" class="adf-permission-loader">
<mat-progress-spinner [color]="'primary'" <mat-progress-spinner [color]="'primary'" [mode]="'indeterminate'"></mat-progress-spinner>
[mode]="'indeterminate'">
</mat-progress-spinner>
</div> </div>
<ng-container *ngIf="permissionList.error$ | async"> <ng-container *ngIf="permissionList.error$ | async">

View File

@@ -20,9 +20,30 @@ import { PermissionElement } from '@alfresco/js-api';
import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core';
import { PermissionDisplayModel } from '../../models/permission.model'; import { PermissionDisplayModel } from '../../models/permission.model';
import { PermissionListService } from './permission-list.service'; import { PermissionListService } from './permission-list.service';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { MatIconModule } from '@angular/material/icon';
import { MatSlideToggleModule } from '@angular/material/slide-toggle';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { PermissionContainerComponent } from '../permission-container/permission-container.component';
import { PopOverDirective } from '../pop-over.directive';
@Component({ @Component({
selector: 'adf-permission-list', selector: 'adf-permission-list',
standalone: true,
imports: [
CommonModule,
MatCardModule,
MatProgressSpinnerModule,
MatIconModule,
MatSlideToggleModule,
TranslateModule,
MatButtonModule,
PermissionContainerComponent,
PopOverDirective
],
templateUrl: './permission-list.component.html', templateUrl: './permission-list.component.html',
styleUrls: ['./permission-list.component.scss'], styleUrls: ['./permission-list.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
@@ -64,7 +85,7 @@ export class PermissionListComponent implements OnInit {
this.selectedPermissions = []; this.selectedPermissions = [];
} }
updatePermission({role, permission}) { updatePermission({ role, permission }) {
this.permissionList.updateRole(role, permission); this.permissionList.updateRole(role, permission);
} }

View File

@@ -22,6 +22,8 @@ import { By } from '@angular/platform-browser';
import { OverlayModule } from '@angular/cdk/overlay'; import { OverlayModule } from '@angular/cdk/overlay';
@Component({ @Component({
standalone: true,
imports: [PopOverDirective],
template: ` template: `
<div <div
[adf-pop-over]="popOver" [adf-pop-over]="popOver"
@@ -43,8 +45,7 @@ describe('PopOverDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [OverlayModule], imports: [OverlayModule, PopOverTestComponent]
declarations: [PopOverDirective, PopOverTestComponent]
}); });
fixture = TestBed.createComponent(PopOverTestComponent); fixture = TestBed.createComponent(PopOverTestComponent);
}); });

View File

@@ -15,17 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { AfterViewInit, Directive, ElementRef, HostListener, Input, OnDestroy, OnInit, TemplateRef, ViewContainerRef } from '@angular/core';
AfterViewInit,
Directive,
ElementRef,
HostListener,
Input,
OnDestroy,
OnInit,
TemplateRef,
ViewContainerRef
} from '@angular/core';
import { ConnectionPositionPair, Overlay, OverlayRef } from '@angular/cdk/overlay'; import { ConnectionPositionPair, Overlay, OverlayRef } from '@angular/cdk/overlay';
import { TemplatePortal } from '@angular/cdk/portal'; import { TemplatePortal } from '@angular/cdk/portal';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
@@ -34,8 +24,8 @@ import { ConfigurableFocusTrap, ConfigurableFocusTrapFactory } from '@angular/cd
@Directive({ @Directive({
selector: '[adf-pop-over]', selector: '[adf-pop-over]',
standalone: true,
exportAs: 'adfPopOver' exportAs: 'adfPopOver'
}) })
export class PopOverDirective implements OnInit, OnDestroy, AfterViewInit { export class PopOverDirective implements OnInit, OnDestroy, AfterViewInit {
get open(): boolean { get open(): boolean {
@@ -58,7 +48,7 @@ export class PopOverDirective implements OnInit, OnDestroy, AfterViewInit {
private overlay: Overlay, private overlay: Overlay,
private vcr: ViewContainerRef, private vcr: ViewContainerRef,
private focusTrapFactory: ConfigurableFocusTrapFactory private focusTrapFactory: ConfigurableFocusTrapFactory
) { } ) {}
ngOnInit(): void { ngOnInit(): void {
this.createOverlay(); this.createOverlay();

View File

@@ -15,19 +15,23 @@
* limitations under the License. * limitations under the License.
*/ */
import { User } from '@alfresco/adf-core'; import { InitialUsernamePipe, User } from '@alfresco/adf-core';
import { Group, NodeEntry } from '@alfresco/js-api'; import { Group, NodeEntry } from '@alfresco/js-api';
import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { NodePermissionService } from '../../services/node-permission.service'; import { NodePermissionService } from '../../services/node-permission.service';
import { CommonModule } from '@angular/common';
import { MatIconModule } from '@angular/material/icon';
@Component({ @Component({
selector: 'adf-user-icon-column', selector: 'adf-user-icon-column',
standalone: true,
imports: [CommonModule, MatIconModule, InitialUsernamePipe],
template: ` template: `
<div class="adf-cell-value" [attr.id]="group ? 'group-icon' : 'person-icon'" *ngIf="!isSelected"> <div class="adf-cell-value" [attr.id]="group ? 'group-icon' : 'person-icon'" *ngIf="!isSelected">
<ng-container *ngIf="displayText$ | async as user"> <ng-container *ngIf="displayText$ | async as user">
<mat-icon *ngIf="group" class="adf-group-icon">people_alt_outline</mat-icon> <mat-icon *ngIf="group" class="adf-group-icon">people_alt_outline</mat-icon>
<div *ngIf="!group" [outerHTML]="user | usernameInitials: 'adf-people-initial'"></div> <div *ngIf="!group" [outerHTML]="user | usernameInitials : 'adf-people-initial'"></div>
</ng-container> </ng-container>
</div> </div>
<div class="adf-cell-value" *ngIf="isSelected"> <div class="adf-cell-value" *ngIf="isSelected">

View File

@@ -20,9 +20,12 @@ import { BehaviorSubject } from 'rxjs';
import { Group, NodeEntry } from '@alfresco/js-api'; import { Group, NodeEntry } from '@alfresco/js-api';
import { NodePermissionService } from '../../services/node-permission.service'; import { NodePermissionService } from '../../services/node-permission.service';
import { EcmUserModel } from '../../../common/models/ecm-user.model'; import { EcmUserModel } from '../../../common/models/ecm-user.model';
import { CommonModule } from '@angular/common';
@Component({ @Component({
selector: 'adf-user-name-column', selector: 'adf-user-name-column',
standalone: true,
imports: [CommonModule],
template: ` template: `
<div class="adf-ellipsis-cell" [attr.data-automation-id]="displayText$ | async"> <div class="adf-ellipsis-cell" [attr.data-automation-id]="displayText$ | async">
<span class="adf-user-name-column" title="{{ displayText$ | async }}"> {{ displayText$ | async }}</span> <span class="adf-user-name-column" title="{{ displayText$ | async }}"> {{ displayText$ | async }}</span>

View File

@@ -17,9 +17,16 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { RoleModel } from '../../models/role.model'; import { RoleModel } from '../../models/role.model';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { TranslateModule } from '@ngx-translate/core';
import { LocalizedRolePipe } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-user-role-column', selector: 'adf-user-role-column',
standalone: true,
imports: [CommonModule, MatFormFieldModule, MatSelectModule, TranslateModule, LocalizedRolePipe],
template: ` template: `
<mat-form-field class="adf-role-selector-field" *ngIf="!readonly"> <mat-form-field class="adf-role-selector-field" *ngIf="!readonly">
<mat-select <mat-select

View File

@@ -15,17 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { CoreModule, InitialUsernamePipe, PipeModule } from '@alfresco/adf-core';
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';
import { PermissionListComponent } from './components/permission-list/permission-list.component'; import { PermissionListComponent } from './components/permission-list/permission-list.component';
import { AddPermissionComponent } from './components/add-permission/add-permission.component'; import { AddPermissionComponent } from './components/add-permission/add-permission.component';
import { AddPermissionDialogComponent } from './components/add-permission/add-permission-dialog.component'; import { AddPermissionDialogComponent } from './components/add-permission/add-permission-dialog.component';
import { InheritPermissionDirective } from './components/inherited-button.directive'; import { InheritPermissionDirective } from './components/inherited-button.directive';
import { AddPermissionPanelComponent } from './components/add-permission/add-permission-panel.component'; import { AddPermissionPanelComponent } from './components/add-permission/add-permission-panel.component';
import { SearchModule } from '../search/search.module';
import { UserNameColumnComponent } from './components/user-name-column/user-name-column.component'; import { UserNameColumnComponent } from './components/user-name-column/user-name-column.component';
import { UserIconColumnComponent } from './components/user-icon-column/user-icon-column.component'; import { UserIconColumnComponent } from './components/user-icon-column/user-icon-column.component';
import { UserRoleColumnComponent } from './components/user-role-column/user-role-column.component'; import { UserRoleColumnComponent } from './components/user-role-column/user-role-column.component';
@@ -33,32 +28,23 @@ import { NodePathColumnComponent } from './components/node-path-column/node-path
import { PopOverDirective } from './components/pop-over.directive'; import { PopOverDirective } from './components/pop-over.directive';
import { PermissionContainerComponent } from './components/permission-container/permission-container.component'; import { PermissionContainerComponent } from './components/permission-container/permission-container.component';
export const CONTENT_PERMISSION_MANAGER_DIRECTIVES = [
AddPermissionPanelComponent,
AddPermissionComponent,
AddPermissionDialogComponent,
NodePathColumnComponent,
PermissionContainerComponent,
PermissionListComponent,
UserNameColumnComponent,
UserIconColumnComponent,
UserRoleColumnComponent,
InheritPermissionDirective,
PopOverDirective
] as const;
/** @deprecated use `...CONTENT_PERMISSION_MANAGER_DIRECTIVES` or import the standalone components directly */
@NgModule({ @NgModule({
imports: [CoreModule, CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, SearchModule, PipeModule, InitialUsernamePipe], imports: [...CONTENT_PERMISSION_MANAGER_DIRECTIVES],
declarations: [ exports: [...CONTENT_PERMISSION_MANAGER_DIRECTIVES]
PermissionListComponent,
AddPermissionPanelComponent,
InheritPermissionDirective,
AddPermissionComponent,
AddPermissionDialogComponent,
UserNameColumnComponent,
UserIconColumnComponent,
UserRoleColumnComponent,
PopOverDirective,
NodePathColumnComponent,
PermissionContainerComponent
],
exports: [
PermissionListComponent,
AddPermissionPanelComponent,
InheritPermissionDirective,
AddPermissionComponent,
AddPermissionDialogComponent,
UserNameColumnComponent,
UserIconColumnComponent,
UserRoleColumnComponent,
PopOverDirective,
NodePathColumnComponent
]
}) })
export class PermissionManagerModule {} export class PermissionManagerModule {}

View File

@@ -16,13 +16,17 @@
*/ */
import { Component, OnInit, ViewEncapsulation } from '@angular/core'; import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { MatCheckboxChange } from '@angular/material/checkbox'; import { MatCheckboxChange, MatCheckboxModule } from '@angular/material/checkbox';
import { SearchWidget } from '../../models/search-widget.interface'; import { SearchWidget } from '../../models/search-widget.interface';
import { SearchWidgetSettings } from '../../models/search-widget-settings.interface'; import { SearchWidgetSettings } from '../../models/search-widget-settings.interface';
import { SearchQueryBuilderService } from '../../services/search-query-builder.service'; import { SearchQueryBuilderService } from '../../services/search-query-builder.service';
import { SearchFilterList } from '../../models/search-filter-list.model'; import { SearchFilterList } from '../../models/search-filter-list.model';
import { TranslationService } from '@alfresco/adf-core'; import { TranslationService } from '@alfresco/adf-core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
export interface SearchListOption { export interface SearchListOption {
name: string; name: string;
@@ -32,13 +36,14 @@ export interface SearchListOption {
@Component({ @Component({
selector: 'adf-search-check-list', selector: 'adf-search-check-list',
standalone: true,
imports: [CommonModule, MatCheckboxModule, TranslateModule, MatButtonModule, MatIconModule],
templateUrl: './search-check-list.component.html', templateUrl: './search-check-list.component.html',
styleUrls: ['./search-check-list.component.scss'], styleUrls: ['./search-check-list.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-search-check-list' } host: { class: 'adf-search-check-list' }
}) })
export class SearchCheckListComponent implements SearchWidget, OnInit { export class SearchCheckListComponent implements SearchWidget, OnInit {
id: string; id: string;
settings?: SearchWidgetSettings; settings?: SearchWidgetSettings;
context?: SearchQueryBuilderService; context?: SearchQueryBuilderService;
@@ -101,7 +106,7 @@ export class SearchCheckListComponent implements SearchWidget, OnInit {
updateDisplayValue(): void { updateDisplayValue(): void {
const displayValue = this.options.items const displayValue = this.options.items
.filter((option) => option.checked) .filter((option) => option.checked)
.map(({name}) => this.translationService.instant(name)) .map(({ name }) => this.translationService.instant(name))
.join(', '); .join(', ');
this.displayValue$.next(displayValue); this.displayValue$.next(displayValue);
} }
@@ -125,15 +130,12 @@ export class SearchCheckListComponent implements SearchWidget, OnInit {
} }
setValue(value: any) { setValue(value: any) {
this.options.items.filter((item) => value.includes(item.value)) this.options.items.filter((item) => value.includes(item.value)).map((item) => (item.checked = true));
.map((item) => item.checked = true);
this.submitValues(); this.submitValues();
} }
private getCheckedValues() { private getCheckedValues() {
return this.options.items return this.options.items.filter((option) => option.checked).map((option) => option.value);
.filter((option) => option.checked)
.map((option) => option.value);
} }
submitValues() { submitValues() {

View File

@@ -36,8 +36,7 @@ describe('SearchChipAutocompleteInputComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [SearchChipAutocompleteInputComponent], imports: [ContentTestingModule, SearchChipAutocompleteInputComponent]
imports: [ContentTestingModule]
}); });
fixture = TestBed.createComponent(SearchChipAutocompleteInputComponent); fixture = TestBed.createComponent(SearchChipAutocompleteInputComponent);

View File

@@ -29,15 +29,21 @@ import {
OnChanges OnChanges
} from '@angular/core'; } from '@angular/core';
import { ENTER } from '@angular/cdk/keycodes'; import { ENTER } from '@angular/cdk/keycodes';
import { FormControl } from '@angular/forms'; import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { MatAutocompleteSelectedEvent } from '@angular/material/autocomplete'; import { MatAutocompleteModule, MatAutocompleteSelectedEvent } from '@angular/material/autocomplete';
import { MatChipInputEvent } from '@angular/material/chips'; import { MatChipInputEvent, MatChipsModule } from '@angular/material/chips';
import { EMPTY, Observable, Subject, timer } from 'rxjs'; import { EMPTY, Observable, Subject, timer } from 'rxjs';
import { debounce, startWith, takeUntil, tap } from 'rxjs/operators'; import { debounce, startWith, takeUntil, tap } from 'rxjs/operators';
import { AutocompleteOption } from '../../models/autocomplete-option.interface'; import { AutocompleteOption } from '../../models/autocomplete-option.interface';
import { CommonModule } from '@angular/common';
import { MatFormFieldModule } from '@angular/material/form-field';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({ @Component({
selector: 'adf-search-chip-autocomplete-input', selector: 'adf-search-chip-autocomplete-input',
standalone: true,
imports: [CommonModule, MatFormFieldModule, MatChipsModule, TranslateModule, MatIconModule, ReactiveFormsModule, MatAutocompleteModule],
templateUrl: './search-chip-autocomplete-input.component.html', templateUrl: './search-chip-autocomplete-input.component.html',
styleUrls: ['./search-chip-autocomplete-input.component.scss'], styleUrls: ['./search-chip-autocomplete-input.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@@ -23,9 +23,12 @@ import { ContentTestingModule } from '../../../testing/content.testing.module';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatChipHarness, MatChipRemoveHarness } from '@angular/material/chips/testing'; import { MatChipHarness, MatChipRemoveHarness } from '@angular/material/chips/testing';
import { SearchChipListComponent } from './search-chip-list.component';
@Component({ @Component({
selector: 'adf-test-component', selector: 'adf-test-component',
standalone: true,
imports: [SearchChipListComponent],
template: ` <adf-search-chip-list [searchFilter]="searchFilter" [clearAll]="allowClear"> </adf-search-chip-list> ` template: ` <adf-search-chip-list [searchFilter]="searchFilter" [clearAll]="allowClear"> </adf-search-chip-list> `
}) })
class TestComponent { class TestComponent {
@@ -33,7 +36,7 @@ class TestComponent {
searchFilter = { searchFilter = {
selectedBuckets: [], selectedBuckets: [],
unselectFacetBucket: () => {} unselectFacetBucket: () => {}
}; } as any;
} }
describe('SearchChipListComponent', () => { describe('SearchChipListComponent', () => {
@@ -44,8 +47,7 @@ describe('SearchChipListComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule], imports: [ContentTestingModule, TestComponent]
declarations: [TestComponent]
}); });
fixture = TestBed.createComponent(TestComponent); fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -18,16 +18,21 @@
import { Component, ViewEncapsulation, Input } from '@angular/core'; import { Component, ViewEncapsulation, Input } from '@angular/core';
import { SearchFilterComponent } from '../../components/search-filter/search-filter.component'; import { SearchFilterComponent } from '../../components/search-filter/search-filter.component';
import { SearchFacetFiltersService } from '../../services/search-facet-filters.service'; import { SearchFacetFiltersService } from '../../services/search-facet-filters.service';
import { CommonModule } from '@angular/common';
import { MatChipsModule } from '@angular/material/chips';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({ @Component({
selector: 'adf-search-chip-list', selector: 'adf-search-chip-list',
standalone: true,
imports: [CommonModule, MatChipsModule, TranslateModule, MatIconModule],
templateUrl: './search-chip-list.component.html', templateUrl: './search-chip-list.component.html',
styleUrls: ['./search-chip-list.component.scss'], styleUrls: ['./search-chip-list.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-search-chip-list' } host: { class: 'adf-search-chip-list' }
}) })
export class SearchChipListComponent { export class SearchChipListComponent {
/** /**
* Search filter to supply the data for the chips. * Search filter to supply the data for the chips.
* Not required from 4.5.0 and later versions @deprecated * Not required from 4.5.0 and later versions @deprecated

View File

@@ -57,24 +57,32 @@ import { SearchFacetChipTabbedComponent } from './components/search-filter-chips
import { SearchFacetTabbedContentComponent } from './components/search-filter-chips/search-facet-chip-tabbed/search-facet-tabbed-content.component'; import { SearchFacetTabbedContentComponent } from './components/search-filter-chips/search-facet-chip-tabbed/search-facet-tabbed-content.component';
import { SearchInputComponent } from './components/search-input'; import { SearchInputComponent } from './components/search-input';
export const CONTENT_SEARCH_DIRECTIVES = [SearchCheckListComponent, SearchChipAutocompleteInputComponent, SearchChipListComponent] as const;
@NgModule({ @NgModule({
imports: [CommonModule, FormsModule, ReactiveFormsModule, MaterialModule, CoreModule, SearchTextModule, SearchInputComponent], imports: [
...CONTENT_SEARCH_DIRECTIVES,
CommonModule,
FormsModule,
ReactiveFormsModule,
MaterialModule,
CoreModule,
SearchTextModule,
SearchInputComponent
],
declarations: [ declarations: [
SearchComponent, SearchComponent,
SearchControlComponent, SearchControlComponent,
EmptySearchResultComponent, EmptySearchResultComponent,
SearchFilterComponent, SearchFilterComponent,
SearchFilterCardComponent, SearchFilterCardComponent,
SearchChipListComponent,
SearchWidgetContainerComponent, SearchWidgetContainerComponent,
SearchTextComponent, SearchTextComponent,
SearchChipAutocompleteInputComponent,
SearchFilterAutocompleteChipsComponent, SearchFilterAutocompleteChipsComponent,
SearchRadioComponent, SearchRadioComponent,
SearchSliderComponent, SearchSliderComponent,
SearchNumberRangeComponent, SearchNumberRangeComponent,
SearchPanelComponent, SearchPanelComponent,
SearchCheckListComponent,
SearchDatetimeRangeComponent, SearchDatetimeRangeComponent,
SearchSortingPickerComponent, SearchSortingPickerComponent,
SearchFilterContainerComponent, SearchFilterContainerComponent,
@@ -100,16 +108,14 @@ import { SearchInputComponent } from './components/search-input';
EmptySearchResultComponent, EmptySearchResultComponent,
SearchFilterComponent, SearchFilterComponent,
SearchFilterCardComponent, SearchFilterCardComponent,
SearchChipListComponent,
SearchWidgetContainerComponent, SearchWidgetContainerComponent,
SearchTextComponent, SearchTextComponent,
SearchChipAutocompleteInputComponent,
SearchFilterAutocompleteChipsComponent, SearchFilterAutocompleteChipsComponent,
SearchRadioComponent, SearchRadioComponent,
SearchSliderComponent, SearchSliderComponent,
SearchNumberRangeComponent, SearchNumberRangeComponent,
SearchPanelComponent, SearchPanelComponent,
SearchCheckListComponent, ...CONTENT_SEARCH_DIRECTIVES,
SearchDatetimeRangeComponent, SearchDatetimeRangeComponent,
SearchSortingPickerComponent, SearchSortingPickerComponent,
SearchFilterContainerComponent, SearchFilterContainerComponent,

View File

@@ -50,7 +50,7 @@ describe('TagActionsComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule] imports: [ContentTestingModule, TagActionsComponent]
}); });
fixture = TestBed.createComponent(TagActionsComponent); fixture = TestBed.createComponent(TagActionsComponent);
tagService = TestBed.inject(TagService); tagService = TestBed.inject(TagService);

View File

@@ -21,6 +21,14 @@ import { TagService } from './services/tag.service';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { TagPaging } from '@alfresco/js-api'; import { TagPaging } from '@alfresco/js-api';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { CommonModule } from '@angular/common';
import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { TranslateModule } from '@ngx-translate/core';
import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
/** /**
* *
@@ -29,13 +37,14 @@ import { takeUntil } from 'rxjs/operators';
@Component({ @Component({
selector: 'adf-tag-node-actions-list', selector: 'adf-tag-node-actions-list',
standalone: true,
imports: [CommonModule, MatListModule, MatIconModule, MatFormFieldModule, MatInputModule, TranslateModule, FormsModule, MatButtonModule],
templateUrl: './tag-actions.component.html', templateUrl: './tag-actions.component.html',
styleUrls: ['./tag-actions.component.scss'], styleUrls: ['./tag-actions.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-tag-node-actions-list' } host: { class: 'adf-tag-node-actions-list' }
}) })
export class TagActionsComponent implements OnChanges, OnInit, OnDestroy { export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
/** The identifier of a node. */ /** The identifier of a node. */
@Input() @Input()
nodeId: string; nodeId: string;
@@ -59,13 +68,10 @@ export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>(); private onDestroy$ = new Subject<boolean>();
constructor(private tagService: TagService, private translateService: TranslationService) { constructor(private tagService: TagService, private translateService: TranslationService) {}
}
ngOnInit() { ngOnInit() {
this.tagService.refresh this.tagService.refresh.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.refreshTag());
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => this.refreshTag());
} }
ngOnChanges() { ngOnChanges() {
@@ -79,15 +85,18 @@ export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
refreshTag() { refreshTag() {
if (this.nodeId) { if (this.nodeId) {
this.tagService.getTagsByNodeId(this.nodeId).subscribe((tagPaging: TagPaging) => { this.tagService.getTagsByNodeId(this.nodeId).subscribe(
this.tagsEntries = tagPaging.list.entries; (tagPaging: TagPaging) => {
this.disableAddTag = false; this.tagsEntries = tagPaging.list.entries;
this.result.emit(this.tagsEntries); this.disableAddTag = false;
}, () => { this.result.emit(this.tagsEntries);
this.tagsEntries = null; },
this.disableAddTag = true; () => {
this.result.emit(this.tagsEntries); this.tagsEntries = null;
}); this.disableAddTag = true;
this.result.emit(this.tagsEntries);
}
);
} }
} }
@@ -105,7 +114,7 @@ export class TagActionsComponent implements OnChanges, OnInit, OnDestroy {
searchTag(searchTagName: string) { searchTag(searchTagName: string) {
if (this.tagsEntries) { if (this.tagsEntries) {
return this.tagsEntries.find((currentTag) => (searchTagName === currentTag.entry.tag)); return this.tagsEntries.find((currentTag) => searchTagName === currentTag.entry.tag);
} }
} }

View File

@@ -50,7 +50,7 @@ describe('TagList', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule] imports: [ContentTestingModule, TagListComponent]
}); });
tagService = TestBed.inject(TagService); tagService = TestBed.inject(TagService);

View File

@@ -21,19 +21,24 @@ import { PaginationModel } from '@alfresco/adf-core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { TagEntry } from '@alfresco/js-api'; import { TagEntry } from '@alfresco/js-api';
import { CommonModule } from '@angular/common';
import { MatChipsModule } from '@angular/material/chips';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
/** /**
* This component provide a list of all the tag inside the ECM * This component provide a list of all the tag inside the ECM
*/ */
@Component({ @Component({
selector: 'adf-tag-list', selector: 'adf-tag-list',
standalone: true,
imports: [CommonModule, MatChipsModule, MatButtonModule, MatIconModule],
templateUrl: './tag-list.component.html', templateUrl: './tag-list.component.html',
styleUrls: ['./tag-list.component.scss'], styleUrls: ['./tag-list.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-tag-list' } host: { class: 'adf-tag-list' }
}) })
export class TagListComponent implements OnInit, OnDestroy { export class TagListComponent implements OnInit, OnDestroy {
/** Emitted when a tag is selected. */ /** Emitted when a tag is selected. */
@Output() @Output()
result = new EventEmitter(); result = new EventEmitter();
@@ -57,7 +62,6 @@ export class TagListComponent implements OnInit, OnDestroy {
private onDestroy$ = new Subject<boolean>(); private onDestroy$ = new Subject<boolean>();
constructor(private tagService: TagService) { constructor(private tagService: TagService) {
this.defaultPagination = { this.defaultPagination = {
skipCount: 0, skipCount: 0,
maxItems: this.size, maxItems: this.size,
@@ -66,12 +70,10 @@ export class TagListComponent implements OnInit, OnDestroy {
this.pagination = this.defaultPagination; this.pagination = this.defaultPagination;
this.tagService.refresh this.tagService.refresh.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
.pipe(takeUntil(this.onDestroy$)) this.tagsEntries = [];
.subscribe(() => { this.refreshTag(this.defaultPagination);
this.tagsEntries = []; });
this.refreshTag(this.defaultPagination);
});
} }
ngOnInit() { ngOnInit() {

View File

@@ -30,7 +30,7 @@ describe('TagNodeList', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [ContentTestingModule] imports: [ContentTestingModule, TagNodeListComponent]
}); });
fixture = TestBed.createComponent(TagNodeListComponent); fixture = TestBed.createComponent(TagNodeListComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -20,7 +20,7 @@ import { TagService } from './services/tag.service';
import { TagEntry } from '@alfresco/js-api'; import { TagEntry } from '@alfresco/js-api';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { Chip } from '@alfresco/adf-core'; import { Chip, DynamicChipListComponent } from '@alfresco/adf-core';
/** /**
* *
@@ -29,6 +29,8 @@ import { Chip } from '@alfresco/adf-core';
@Component({ @Component({
selector: 'adf-tag-node-list', selector: 'adf-tag-node-list',
standalone: true,
imports: [DynamicChipListComponent],
templateUrl: './tag-node-list.component.html', templateUrl: './tag-node-list.component.html',
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
@@ -63,9 +65,7 @@ export class TagNodeListComponent implements OnChanges, OnDestroy, OnInit {
} }
ngOnInit(): void { ngOnInit(): void {
this.tagService.refresh this.tagService.refresh.pipe(takeUntil(this.onDestroy$)).subscribe(() => this.refreshTag());
.pipe(takeUntil(this.onDestroy$))
.subscribe(() => this.refreshTag());
} }
ngOnDestroy(): void { ngOnDestroy(): void {

View File

@@ -15,34 +15,17 @@
* limitations under the License. * limitations under the License.
*/ */
import { CommonModule, NgForOf } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../material.module';
import { TagActionsComponent } from './tag-actions.component'; import { TagActionsComponent } from './tag-actions.component';
import { TagListComponent } from './tag-list.component'; import { TagListComponent } from './tag-list.component';
import { TagNodeListComponent } from './tag-node-list.component'; import { TagNodeListComponent } from './tag-node-list.component';
import { TagsCreatorComponent } from './tags-creator/tags-creator.component'; import { TagsCreatorComponent } from './tags-creator/tags-creator.component';
import { ContentDirectiveModule } from '../directives/content-directive.module';
import { MatChipsModule } from '@angular/material/chips';
import { MatIconModule } from '@angular/material/icon';
import { TranslateModule } from '@ngx-translate/core';
import { DynamicChipListModule } from '@alfresco/adf-core';
export const CONTENT_TAG_DIRECTIVES = [TagsCreatorComponent, TagActionsComponent, TagListComponent, TagNodeListComponent] as const;
/** @deprecated use `...CONTENT_TAG_DIRECTIVES` instead or import standalone components directly */
@NgModule({ @NgModule({
imports: [ imports: [...CONTENT_TAG_DIRECTIVES],
CommonModule, exports: [...CONTENT_TAG_DIRECTIVES]
ContentDirectiveModule,
MaterialModule,
FormsModule,
ReactiveFormsModule,
TranslateModule,
DynamicChipListModule,
MatChipsModule,
MatIconModule,
NgForOf
],
exports: [TagActionsComponent, TagListComponent, TagNodeListComponent, TagsCreatorComponent],
declarations: [TagActionsComponent, TagListComponent, TagNodeListComponent, TagsCreatorComponent]
}) })
export class TagModule {} export class TagModule {}

View File

@@ -20,22 +20,15 @@ import { TagsCreatorComponent } from './tags-creator.component';
import { NotificationService } from '@alfresco/adf-core'; import { NotificationService } from '@alfresco/adf-core';
import { By } from '@angular/platform-browser'; import { By } from '@angular/platform-browser';
import { TranslateModule } from '@ngx-translate/core'; import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon'; import { MatError } from '@angular/material/form-field';
import { MatError, MatFormFieldModule } from '@angular/material/form-field'; import { TagsCreatorMode, TagService } from '@alfresco/adf-content-services';
import { MatInputModule } from '@angular/material/input';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { ContentDirectiveModule, TagsCreatorMode, TagService } from '@alfresco/adf-content-services';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
import { EMPTY, of, throwError } from 'rxjs'; import { EMPTY, of, throwError } from 'rxjs';
import { DebugElement } from '@angular/core'; import { DebugElement } from '@angular/core';
import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { MatListModule } from '@angular/material/list';
import { HarnessLoader } from '@angular/cdk/testing'; import { HarnessLoader } from '@angular/cdk/testing';
import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing'; import { MatProgressSpinnerHarness } from '@angular/material/progress-spinner/testing';
import { MatChipOptionHarness } from '@angular/material/chips/testing'; import { MatChipOptionHarness } from '@angular/material/chips/testing';
import { MatChipsModule } from '@angular/material/chips';
describe('TagsCreatorComponent', () => { describe('TagsCreatorComponent', () => {
let fixture: ComponentFixture<TagsCreatorComponent>; let fixture: ComponentFixture<TagsCreatorComponent>;
@@ -46,20 +39,7 @@ describe('TagsCreatorComponent', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [TagsCreatorComponent], imports: [NoopAnimationsModule, TranslateModule.forRoot(), TagsCreatorComponent],
imports: [
ContentDirectiveModule,
MatButtonModule,
MatFormFieldModule,
MatIconModule,
MatInputModule,
MatProgressSpinnerModule,
MatListModule,
MatChipsModule,
NoopAnimationsModule,
ReactiveFormsModule,
TranslateModule.forRoot()
],
providers: [ providers: [
{ {
provide: TagService, provide: TagService,

View File

@@ -17,12 +17,21 @@
import { TagEntry, TagPaging } from '@alfresco/js-api'; import { TagEntry, TagPaging } from '@alfresco/js-api';
import { Component, ElementRef, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core'; import { Component, ElementRef, EventEmitter, HostBinding, Input, OnDestroy, OnInit, Output, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormControl, Validators } from '@angular/forms'; import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { debounce, distinctUntilChanged, finalize, first, map, takeUntil, tap } from 'rxjs/operators'; import { debounce, distinctUntilChanged, finalize, first, map, takeUntil, tap } from 'rxjs/operators';
import { EMPTY, forkJoin, Observable, Subject, timer } from 'rxjs'; import { EMPTY, forkJoin, Observable, Subject, timer } from 'rxjs';
import { NotificationService } from '@alfresco/adf-core'; import { NotificationService } from '@alfresco/adf-core';
import { TagsCreatorMode } from './tags-creator-mode'; import { TagsCreatorMode } from './tags-creator-mode';
import { TagService } from '../services/tag.service'; import { TagService } from '../services/tag.service';
import { CommonModule } from '@angular/common';
import { MatInputModule } from '@angular/material/input';
import { AutoFocusDirective } from '../../directives';
import { TranslateModule } from '@ngx-translate/core';
import { MatChipsModule } from '@angular/material/chips';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
interface TagNameControlErrors { interface TagNameControlErrors {
duplicatedExistingTag?: boolean; duplicatedExistingTag?: boolean;
@@ -42,6 +51,19 @@ const DEFAULT_TAGS_SORTING = {
*/ */
@Component({ @Component({
selector: 'adf-tags-creator', selector: 'adf-tags-creator',
standalone: true,
imports: [
CommonModule,
MatInputModule,
ReactiveFormsModule,
AutoFocusDirective,
TranslateModule,
MatChipsModule,
MatButtonModule,
MatIconModule,
MatListModule,
MatProgressSpinnerModule
],
templateUrl: './tags-creator.component.html', templateUrl: './tags-creator.component.html',
styleUrls: ['./tags-creator.component.scss'], styleUrls: ['./tags-creator.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@@ -18,7 +18,7 @@
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { TreeViewComponent } from './components/tree-view.component'; import { TreeViewComponent } from './components/tree-view.component';
/** @deprecated this module is deprecated and will be removed in future versions */ /** @deprecated use `TreeViewComponent` instead */
@NgModule({ @NgModule({
imports: [TreeViewComponent], imports: [TreeViewComponent],
exports: [TreeViewComponent] exports: [TreeViewComponent]

View File

@@ -16,7 +16,19 @@
*/ */
import { UserPreferencesService } from '@alfresco/adf-core'; import { UserPreferencesService } from '@alfresco/adf-core';
import { ChangeDetectorRef, Component, Input, Output, EventEmitter, OnDestroy, OnInit, ViewChild, HostBinding, ElementRef, ViewEncapsulation } from '@angular/core'; import {
ChangeDetectorRef,
Component,
Input,
Output,
EventEmitter,
OnDestroy,
OnInit,
ViewChild,
HostBinding,
ElementRef,
ViewEncapsulation
} from '@angular/core';
import { Subscription, merge, Subject } from 'rxjs'; import { Subscription, merge, Subject } from 'rxjs';
import { FileUploadingListComponent } from './file-uploading-list.component'; import { FileUploadingListComponent } from './file-uploading-list.component';
import { Direction } from '@angular/cdk/bidi'; import { Direction } from '@angular/cdk/bidi';
@@ -24,9 +36,17 @@ import { takeUntil, delay } from 'rxjs/operators';
import { UploadService } from '../../common/services/upload.service'; import { UploadService } from '../../common/services/upload.service';
import { FileModel, FileUploadStatus } from '../../common/models/file.model'; import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { FileUploadDeleteEvent, FileUploadCompleteEvent } from '../../common/events/file.event'; import { FileUploadDeleteEvent, FileUploadCompleteEvent } from '../../common/events/file.event';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
import { FileUploadingListRowComponent } from './file-uploading-list-row.component';
import { A11yModule } from '@angular/cdk/a11y';
@Component({ @Component({
selector: 'adf-file-uploading-dialog', selector: 'adf-file-uploading-dialog',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule, FileUploadingListComponent, FileUploadingListRowComponent, A11yModule],
templateUrl: './file-uploading-dialog.component.html', templateUrl: './file-uploading-dialog.component.html',
styleUrls: ['./file-uploading-dialog.component.scss'], styleUrls: ['./file-uploading-dialog.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
@@ -53,15 +73,11 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
@HostBinding('attr.adfUploadDialogRight') @HostBinding('attr.adfUploadDialogRight')
public get isPositionRight(): boolean { public get isPositionRight(): boolean {
return (this.direction === 'ltr' && this.position === 'right') return (this.direction === 'ltr' && this.position === 'right') || (this.direction === 'rtl' && this.position === 'left') || null;
|| (this.direction === 'rtl' && this.position === 'left')
|| null;
} }
@HostBinding('attr.adfUploadDialogLeft') @HostBinding('attr.adfUploadDialogLeft')
public get isPositionLeft(): boolean { public get isPositionLeft(): boolean {
return (this.direction === 'ltr' && this.position === 'left') return (this.direction === 'ltr' && this.position === 'left') || (this.direction === 'rtl' && this.position === 'right') || null;
|| (this.direction === 'rtl' && this.position === 'right')
|| null;
} }
filesUploadingList: FileModel[] = []; filesUploadingList: FileModel[] = [];
@@ -81,71 +97,56 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
private uploadService: UploadService, private uploadService: UploadService,
private changeDetector: ChangeDetectorRef, private changeDetector: ChangeDetectorRef,
private userPreferencesService: UserPreferencesService, private userPreferencesService: UserPreferencesService,
private elementRef: ElementRef) { private elementRef: ElementRef
} ) {}
ngOnInit() { ngOnInit() {
this.dialogActive this.dialogActive.pipe(delay(100), takeUntil(this.onDestroy$)).subscribe(() => {
.pipe( const element: any = this.elementRef.nativeElement.querySelector('#upload-dialog');
delay(100), if (element) {
takeUntil(this.onDestroy$) element.focus();
) }
.subscribe(() => { });
const element: any = this.elementRef.nativeElement.querySelector('#upload-dialog');
if (element) {
element.focus();
}
});
this.listSubscription = this.uploadService.queueChanged this.listSubscription = this.uploadService.queueChanged.pipe(takeUntil(this.onDestroy$)).subscribe((fileList) => {
.pipe(takeUntil(this.onDestroy$)) this.filesUploadingList = fileList;
.subscribe(fileList => {
this.filesUploadingList = fileList;
if (this.filesUploadingList.length && !this.isDialogActive) { if (this.filesUploadingList.length && !this.isDialogActive) {
this.isDialogActive = true; this.isDialogActive = true;
this.dialogActive.next(undefined); this.dialogActive.next(undefined);
} else { } else {
this.dialogActive.next(undefined); this.dialogActive.next(undefined);
} }
}); });
this.counterSubscription = merge( this.counterSubscription = merge(this.uploadService.fileUploadComplete, this.uploadService.fileUploadDeleted)
this.uploadService.fileUploadComplete,
this.uploadService.fileUploadDeleted
)
.pipe(takeUntil(this.onDestroy$)) .pipe(takeUntil(this.onDestroy$))
.subscribe((event: FileUploadCompleteEvent | FileUploadDeleteEvent) => { .subscribe((event: FileUploadCompleteEvent | FileUploadDeleteEvent) => {
this.totalCompleted = event.totalComplete; this.totalCompleted = event.totalComplete;
this.changeDetector.detectChanges(); this.changeDetector.detectChanges();
}); });
this.errorSubscription = this.uploadService.fileUploadError this.errorSubscription = this.uploadService.fileUploadError.pipe(takeUntil(this.onDestroy$)).subscribe((event) => {
.pipe(takeUntil(this.onDestroy$)) this.totalErrors = event.totalError;
.subscribe(event => { this.changeDetector.detectChanges();
this.totalErrors = event.totalError; });
this.changeDetector.detectChanges();
});
this.fileUploadSubscription = this.uploadService.fileUpload this.fileUploadSubscription = this.uploadService.fileUpload.pipe(takeUntil(this.onDestroy$)).subscribe(() => {
.pipe(takeUntil(this.onDestroy$)) this.changeDetector.detectChanges();
.subscribe(() => { });
this.changeDetector.detectChanges();
});
this.uploadService.fileDeleted this.uploadService.fileDeleted.pipe(takeUntil(this.onDestroy$)).subscribe((objId) => {
.pipe(takeUntil(this.onDestroy$)) if (this.filesUploadingList) {
.subscribe(objId => { const uploadedFile = this.filesUploadingList.find((file) => (file.data ? file.data.entry.id === objId : false));
if (this.filesUploadingList) { if (uploadedFile) {
const uploadedFile = this.filesUploadingList.find((file) => file.data ? file.data.entry.id === objId : false); uploadedFile.status = FileUploadStatus.Cancelled;
if (uploadedFile) { this.changeDetector.detectChanges();
uploadedFile.status = FileUploadStatus.Cancelled;
this.changeDetector.detectChanges();
}
} }
}); }
});
this.userPreferencesService.select('textOrientation') this.userPreferencesService
.select('textOrientation')
.pipe(takeUntil(this.onDestroy$)) .pipe(takeUntil(this.onDestroy$))
.subscribe((textOrientation: Direction) => { .subscribe((textOrientation: Direction) => {
this.direction = textOrientation; this.direction = textOrientation;
@@ -221,6 +222,6 @@ export class FileUploadingDialogComponent implements OnInit, OnDestroy {
} }
hasUploadInProgress(): boolean { hasUploadInProgress(): boolean {
return (!this.uploadList?.isUploadCompleted() && !this.uploadList?.isUploadCancelled()); return !this.uploadList?.isUploadCompleted() && !this.uploadList?.isUploadCancelled();
} }
} }

View File

@@ -14,7 +14,7 @@
<span *ngIf="isUploadVersion()" class="adf-file-uploading-row__version" tabindex="0" > <span *ngIf="isUploadVersion()" class="adf-file-uploading-row__version" tabindex="0" >
<mat-chip-option color="primary" <mat-chip-option color="primary"
[attr.aria-label]="'ADF_FILE_UPLOAD.ARIA-LABEL.VERSION' | translate: { version: versionNumber }" [attr.aria-label]="'ADF_FILE_UPLOAD.ARIA-LABEL.VERSION' | translate: { version: versionNumber }"
[title]="'version' + versionNumber" disabled [title]="'version' + versionNumber" [disabled]="true"
>{{ versionNumber }}</mat-chip-option> >{{ versionNumber }}</mat-chip-option>
</span> </span>

View File

@@ -17,9 +17,31 @@
import { FileModel, FileUploadStatus } from '../../common/models/file.model'; import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core'; import { Component, EventEmitter, Input, Output, ViewEncapsulation } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatIconModule } from '@angular/material/icon';
import { MatListModule } from '@angular/material/list';
import { FileSizePipe, IconComponent } from '@alfresco/adf-core';
import { MatChipsModule } from '@angular/material/chips';
import { TranslateModule } from '@ngx-translate/core';
import { ToggleIconDirective } from '../directives/toggle-icon.directive';
import { MatButtonModule } from '@angular/material/button';
import { FileUploadErrorPipe } from '../pipes/file-upload-error.pipe';
@Component({ @Component({
selector: 'adf-file-uploading-list-row', selector: 'adf-file-uploading-list-row',
standalone: true,
imports: [
CommonModule,
MatIconModule,
MatListModule,
IconComponent,
MatChipsModule,
TranslateModule,
ToggleIconDirective,
FileSizePipe,
MatButtonModule,
FileUploadErrorPipe
],
templateUrl: './file-uploading-list-row.component.html', templateUrl: './file-uploading-list-row.component.html',
styleUrls: ['./file-uploading-list-row.component.scss'], styleUrls: ['./file-uploading-list-row.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None

View File

@@ -15,23 +15,17 @@
* limitations under the License. * limitations under the License.
*/ */
import { import { TranslationService } from '@alfresco/adf-core';
TranslationService
} from '@alfresco/adf-core';
import { UploadService } from '../../common/services/upload.service'; import { UploadService } from '../../common/services/upload.service';
import { FileModel, FileUploadStatus } from '../../common/models/file.model'; import { FileModel, FileUploadStatus } from '../../common/models/file.model';
import { import { Component, ContentChild, Input, Output, TemplateRef, EventEmitter } from '@angular/core';
Component, import { CommonModule } from '@angular/common';
ContentChild,
Input,
Output,
TemplateRef,
EventEmitter
} from '@angular/core';
@Component({ @Component({
selector: 'adf-file-uploading-list', selector: 'adf-file-uploading-list',
standalone: true,
imports: [CommonModule],
templateUrl: './file-uploading-list.component.html', templateUrl: './file-uploading-list.component.html',
styleUrls: ['./file-uploading-list.component.scss'] styleUrls: ['./file-uploading-list.component.scss']
}) })
@@ -46,10 +40,7 @@ export class FileUploadingListComponent {
@Output() @Output()
error = new EventEmitter<any>(); error = new EventEmitter<any>();
constructor( constructor(private uploadService: UploadService, private translateService: TranslationService) {}
private uploadService: UploadService,
private translateService: TranslationService) {
}
/** /**
* Cancel file upload * Cancel file upload
@@ -79,14 +70,14 @@ export class FileUploadingListComponent {
this.uploadService.cancelUpload(file); this.uploadService.cancelUpload(file);
} }
this.files = this.files.filter(entry => entry !== file); this.files = this.files.filter((entry) => entry !== file);
} }
/** /**
* Calls the appropriate methods for each file, depending on state * Calls the appropriate methods for each file, depending on state
*/ */
cancelAllFiles(): void { cancelAllFiles(): void {
const filesToCancel = this.files.filter(file => this.isUploadingFile(file)); const filesToCancel = this.files.filter((file) => this.isUploadingFile(file));
if (filesToCancel.length > 0) { if (filesToCancel.length > 0) {
this.uploadService.cancelUpload(...filesToCancel); this.uploadService.cancelUpload(...filesToCancel);
@@ -103,10 +94,7 @@ export class FileUploadingListComponent {
!this.isUploadCancelled() && !this.isUploadCancelled() &&
Boolean(this.files.length) && Boolean(this.files.length) &&
!this.files.some( !this.files.some(
({ status }) => ({ status }) => status === FileUploadStatus.Starting || status === FileUploadStatus.Progress || status === FileUploadStatus.Pending
status === FileUploadStatus.Starting ||
status === FileUploadStatus.Progress ||
status === FileUploadStatus.Pending
) )
); );
} }
@@ -120,22 +108,14 @@ export class FileUploadingListComponent {
return ( return (
!!this.files.length && !!this.files.length &&
this.files.every( this.files.every(
({ status }) => ({ status }) => status === FileUploadStatus.Aborted || status === FileUploadStatus.Cancelled || status === FileUploadStatus.Deleted
status === FileUploadStatus.Aborted ||
status === FileUploadStatus.Cancelled ||
status === FileUploadStatus.Deleted
) )
); );
} }
private cancelNodeVersionInstances(file: FileModel) { private cancelNodeVersionInstances(file: FileModel) {
this.files this.files
.filter( .filter((item) => item.options.newVersion && item.data.entry.id === file.data.entry.id)
(item) =>
item.options.newVersion &&
item.data.entry.id === file.data.entry.id
)
.map((item) => { .map((item) => {
item.status = FileUploadStatus.Deleted; item.status = FileUploadStatus.Deleted;
}); });
@@ -145,23 +125,15 @@ export class FileUploadingListComponent {
let messageError: string = null; let messageError: string = null;
if (files.length === 1) { if (files.length === 1) {
messageError = this.translateService.instant( messageError = this.translateService.instant('FILE_UPLOAD.MESSAGES.REMOVE_FILE_ERROR', { fileName: files[0].name });
'FILE_UPLOAD.MESSAGES.REMOVE_FILE_ERROR',
{ fileName: files[0].name }
);
} else { } else {
messageError = this.translateService.instant( messageError = this.translateService.instant('FILE_UPLOAD.MESSAGES.REMOVE_FILES_ERROR', { total: files.length });
'FILE_UPLOAD.MESSAGES.REMOVE_FILES_ERROR',
{ total: files.length }
);
} }
this.error.emit(messageError); this.error.emit(messageError);
} }
private isUploadingFile(file: FileModel): boolean { private isUploadingFile(file: FileModel): boolean {
return file.status === FileUploadStatus.Pending || return file.status === FileUploadStatus.Pending || file.status === FileUploadStatus.Starting || file.status === FileUploadStatus.Progress;
file.status === FileUploadStatus.Starting ||
file.status === FileUploadStatus.Progress;
} }
} }

View File

@@ -25,9 +25,15 @@ import { Subject } from 'rxjs';
import { PermissionModel } from '../../document-list/models/permissions.model'; import { PermissionModel } from '../../document-list/models/permissions.model';
import { UploadBase } from './base-upload/upload-base'; import { UploadBase } from './base-upload/upload-base';
import { NodeAllowableOperationSubject } from '../../interfaces/node-allowable-operation-subject.interface'; import { NodeAllowableOperationSubject } from '../../interfaces/node-allowable-operation-subject.interface';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({ @Component({
selector: 'adf-upload-button', selector: 'adf-upload-button',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule],
templateUrl: './upload-button.component.html', templateUrl: './upload-button.component.html',
styleUrls: ['./upload-button.component.scss'], styleUrls: ['./upload-button.component.scss'],
viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }], viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadButtonComponent) }],

View File

@@ -23,9 +23,12 @@ import { AllowableOperationsEnum } from '../../common/models/allowable-operation
import { ContentService } from '../../common/services/content.service'; import { ContentService } from '../../common/services/content.service';
import { FileModel } from '../../common/models/file.model'; import { FileModel } from '../../common/models/file.model';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { FileDraggableDirective } from '../directives/file-draggable.directive';
@Component({ @Component({
selector: 'adf-upload-drag-area', selector: 'adf-upload-drag-area',
standalone: true,
imports: [FileDraggableDirective],
templateUrl: './upload-drag-area.component.html', templateUrl: './upload-drag-area.component.html',
styleUrls: ['./upload-drag-area.component.scss'], styleUrls: ['./upload-drag-area.component.scss'],
host: { class: 'adf-upload-drag-area' }, host: { class: 'adf-upload-drag-area' },

View File

@@ -21,25 +21,33 @@ import { Node } from '@alfresco/js-api';
import { UploadButtonComponent } from './upload-button.component'; import { UploadButtonComponent } from './upload-button.component';
import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum'; import { AllowableOperationsEnum } from '../../common/models/allowable-operations.enum';
import { FileModel } from '../../common/models/file.model'; import { FileModel } from '../../common/models/file.model';
import { CommonModule } from '@angular/common';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
import { MatIconModule } from '@angular/material/icon';
@Component({ @Component({
selector: 'adf-upload-version-button', selector: 'adf-upload-version-button',
standalone: true,
imports: [CommonModule, MatButtonModule, TranslateModule, MatIconModule],
templateUrl: './upload-button.component.html', templateUrl: './upload-button.component.html',
styleUrls: ['./upload-button.component.scss'], styleUrls: ['./upload-button.component.scss'],
viewProviders: [ viewProviders: [{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadVersionButtonComponent) }],
{ provide: EXTENDIBLE_COMPONENT, useExisting: forwardRef(() => UploadVersionButtonComponent) }
],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-upload-version-button' } host: { class: 'adf-upload-version-button' }
}) })
export class UploadVersionButtonComponent extends UploadButtonComponent implements OnChanges, OnInit { export class UploadVersionButtonComponent extends UploadButtonComponent implements OnChanges, OnInit {
/** (**Required**) The node to be versioned. */ /** (**Required**) The node to be versioned. */
@Input() @Input()
node: Node; node: Node;
protected createFileModel(file: File): FileModel { protected createFileModel(file: File): FileModel {
const fileModel = super.createFileModel(file, this.rootFolderId, ((file as any).webkitRelativePath || '').replace(/\/[^/]*$/, ''), this.node.id); const fileModel = super.createFileModel(
file,
this.rootFolderId,
((file as any).webkitRelativePath || '').replace(/\/[^/]*$/, ''),
this.node.id
);
if (!this.isFileAcceptable(fileModel)) { if (!this.isFileAcceptable(fileModel)) {
const message = this.translationService.instant('FILE_UPLOAD.VERSION.MESSAGES.INCOMPATIBLE_VERSION'); const message = this.translationService.instant('FILE_UPLOAD.VERSION.MESSAGES.INCOMPATIBLE_VERSION');

View File

@@ -21,10 +21,12 @@ import { FileDraggableDirective, INPUT_FOCUS_CSS_CLASS } from '../directives/fil
@Component({ @Component({
selector: 'adf-test-component', selector: 'adf-test-component',
standalone: true,
imports: [FileDraggableDirective],
template: ` template: `
<div id="test-container" [adf-file-draggable]="true"> <div id="test-container" [adf-file-draggable]="true">
<div id="test-content"></div> <div id="test-content"></div>
</div> </div>
` `
}) })
class TestComponent { class TestComponent {
@@ -42,10 +44,7 @@ describe('FileDraggableDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ imports: [TestComponent]
TestComponent,
FileDraggableDirective
]
}); });
fixture = TestBed.createComponent(TestComponent); fixture = TestBed.createComponent(TestComponent);
@@ -61,11 +60,12 @@ describe('FileDraggableDirective', () => {
fixture.destroy(); fixture.destroy();
}); });
const createEvent = (eventName: string): DragEvent => new DragEvent(eventName, { const createEvent = (eventName: string): DragEvent =>
bubbles: true, new DragEvent(eventName, {
cancelable: true, bubbles: true,
dataTransfer: new DataTransfer() cancelable: true,
}); dataTransfer: new DataTransfer()
});
const raiseEvent = (eventName: string): DragEvent => { const raiseEvent = (eventName: string): DragEvent => {
const event = createEvent(eventName); const event = createEvent(eventName);

View File

@@ -24,11 +24,11 @@ export const INPUT_FOCUS_CSS_CLASS = 'adf-file-draggable-input-focus';
export const DROP_EFFECT = 'copy'; export const DROP_EFFECT = 'copy';
@Directive({ @Directive({
selector: '[adf-file-draggable]' selector: '[adf-file-draggable]',
standalone: true
}) })
export class FileDraggableDirective implements OnInit, OnDestroy { export class FileDraggableDirective implements OnInit, OnDestroy {
files: File[];
files: File [];
/** Enables/disables drag-and-drop functionality. */ /** Enables/disables drag-and-drop functionality. */
@Input('adf-file-draggable') @Input('adf-file-draggable')

View File

@@ -21,9 +21,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
@Component({ @Component({
selector: 'adf-test-component', selector: 'adf-test-component',
template: ` standalone: true,
<button id="testButton" adf-toggle-icon>test</button> imports: [ToggleIconDirective],
` template: ` <button id="testButton" adf-toggle-icon>test</button> `
}) })
class TestComponent { class TestComponent {
@ViewChild(ToggleIconDirective) @ViewChild(ToggleIconDirective)
@@ -36,10 +36,7 @@ describe('ToggleIconDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
declarations: [ imports: [TestComponent]
TestComponent,
ToggleIconDirective
]
}); });
fixture = TestBed.createComponent(TestComponent); fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance; component = fixture.componentInstance;

View File

@@ -19,6 +19,7 @@ import { Directive, HostListener } from '@angular/core';
@Directive({ @Directive({
selector: '[adf-toggle-icon]', selector: '[adf-toggle-icon]',
standalone: true,
exportAs: 'toggleIcon' exportAs: 'toggleIcon'
}) })
export class ToggleIconDirective { export class ToggleIconDirective {

View File

@@ -15,9 +15,7 @@
* limitations under the License. * limitations under the License.
*/ */
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
import { FileUploadingDialogComponent } from './components/file-uploading-dialog.component'; import { FileUploadingDialogComponent } from './components/file-uploading-dialog.component';
import { FileUploadingListRowComponent } from './components/file-uploading-list-row.component'; import { FileUploadingListRowComponent } from './components/file-uploading-list-row.component';
import { FileUploadingListComponent } from './components/file-uploading-list.component'; import { FileUploadingListComponent } from './components/file-uploading-list.component';
@@ -25,33 +23,24 @@ import { UploadButtonComponent } from './components/upload-button.component';
import { UploadVersionButtonComponent } from './components/upload-version-button.component'; import { UploadVersionButtonComponent } from './components/upload-version-button.component';
import { UploadDragAreaComponent } from './components/upload-drag-area.component'; import { UploadDragAreaComponent } from './components/upload-drag-area.component';
import { FileUploadErrorPipe } from './pipes/file-upload-error.pipe'; import { FileUploadErrorPipe } from './pipes/file-upload-error.pipe';
import { CoreModule, FileSizePipe } from '@alfresco/adf-core';
import { FileDraggableDirective } from './directives/file-draggable.directive'; import { FileDraggableDirective } from './directives/file-draggable.directive';
import { ToggleIconDirective } from './directives/toggle-icon.directive'; import { ToggleIconDirective } from './directives/toggle-icon.directive';
import { A11yModule } from '@angular/cdk/a11y';
export const CONTENT_UPLOAD_DIRECTIVES = [
FileUploadErrorPipe,
FileDraggableDirective,
ToggleIconDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingListRowComponent,
FileUploadingListComponent,
FileUploadingDialogComponent
] as const;
/** @deprecated use `...CONTENT_UPLOAD_DIRECTIVES` instead or import standalone components directly */
@NgModule({ @NgModule({
imports: [CoreModule, CommonModule, MaterialModule, A11yModule, FileUploadErrorPipe, FileSizePipe], imports: [...CONTENT_UPLOAD_DIRECTIVES],
declarations: [ exports: [...CONTENT_UPLOAD_DIRECTIVES]
FileDraggableDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingDialogComponent,
FileUploadingListComponent,
FileUploadingListRowComponent,
ToggleIconDirective
],
exports: [
FileDraggableDirective,
UploadDragAreaComponent,
UploadButtonComponent,
UploadVersionButtonComponent,
FileUploadingDialogComponent,
FileUploadingListComponent,
FileUploadingListRowComponent,
FileUploadErrorPipe,
ToggleIconDirective
]
}) })
export class UploadModule {} export class UploadModule {}

View File

@@ -21,10 +21,10 @@ import { TestBed, ComponentFixture } from '@angular/core/testing';
import { VersionCompatibilityService } from './version-compatibility.service'; import { VersionCompatibilityService } from './version-compatibility.service';
import { VersionInfo } from '@alfresco/js-api'; import { VersionInfo } from '@alfresco/js-api';
import { VersionCompatibilityModule } from './version-compatibility.module';
import { RedirectAuthService } from '@alfresco/adf-core'; import { RedirectAuthService } from '@alfresco/adf-core';
import { EMPTY, of } from 'rxjs'; import { EMPTY, of } from 'rxjs';
import { HttpClientTestingModule } from '@angular/common/http/testing'; import { HttpClientTestingModule } from '@angular/common/http/testing';
import { VersionCompatibilityDirective } from '@alfresco/adf-content-services';
@Component({ @Component({
template: ` template: `
@@ -51,7 +51,7 @@ describe('VersionCompatibilityDirective', () => {
beforeEach(() => { beforeEach(() => {
TestBed.configureTestingModule({ TestBed.configureTestingModule({
imports: [VersionCompatibilityModule, HttpClientTestingModule], imports: [VersionCompatibilityDirective, HttpClientTestingModule],
declarations: [TestComponent], declarations: [TestComponent],
providers: [{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }] providers: [{ provide: RedirectAuthService, useValue: { onLogin: EMPTY, onTokenReceived: of() } }]
}); });

View File

@@ -20,10 +20,10 @@ import { VersionCompatibilityService } from './version-compatibility.service';
import { take } from 'rxjs/operators'; import { take } from 'rxjs/operators';
@Directive({ @Directive({
selector: '[adf-acs-version]' selector: '[adf-acs-version]',
standalone: true
}) })
export class VersionCompatibilityDirective { export class VersionCompatibilityDirective {
/** Minimum version required for component to work correctly . */ /** Minimum version required for component to work correctly . */
@Input('adf-acs-version') @Input('adf-acs-version')
set version(requiredVersion: string) { set version(requiredVersion: string) {
@@ -34,8 +34,7 @@ export class VersionCompatibilityDirective {
private templateRef: TemplateRef<any>, private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef, private viewContainer: ViewContainerRef,
private versionCompatibilityService: VersionCompatibilityService private versionCompatibilityService: VersionCompatibilityService
) { ) {}
}
private validateAcsVersion(requiredVersion: string) { private validateAcsVersion(requiredVersion: string) {
this.versionCompatibilityService.acsVersionInitialized$.pipe(take(1)).subscribe(() => { this.versionCompatibilityService.acsVersionInitialized$.pipe(take(1)).subscribe(() => {

View File

@@ -15,13 +15,12 @@
* limitations under the License. * limitations under the License.
*/ */
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { VersionCompatibilityDirective } from './version-compatibility.directive'; import { VersionCompatibilityDirective } from './version-compatibility.directive';
/** @deprecated use `VersionCompatibilityDirective` instead */
@NgModule({ @NgModule({
imports: [CommonModule], imports: [VersionCompatibilityDirective],
exports: [VersionCompatibilityDirective], exports: [VersionCompatibilityDirective]
declarations: [VersionCompatibilityDirective]
}) })
export class VersionCompatibilityModule {} export class VersionCompatibilityModule {}

View File

@@ -1,6 +1,6 @@
<div class="adf-version-comparison-content"> <div class="adf-version-comparison-content">
<div class="adf-version-current"> <div class="adf-version-current">
<p>{{'ADF_VERSION_COMPARISON.CURRENT_VERSION'|translate }}</p> <p>{{'ADF_VERSION_COMPARISON.CURRENT_VERSION' | translate }}</p>
<img [attr.aria-label]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate: <img [attr.aria-label]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate:
{ type: (node.content.mimeType | fileType | uppercase) | translate }" { type: (node.content.mimeType | fileType | uppercase) | translate }"
[attr.alt]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate: [attr.alt]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate:
@@ -10,7 +10,7 @@
</div> </div>
<span class="material-icons adf-version-arrow-icon">keyboard_arrow_right</span> <span class="material-icons adf-version-arrow-icon">keyboard_arrow_right</span>
<div class="adf-version-new"> <div class="adf-version-new">
<p>{{'ADF_VERSION_COMPARISON.NEW_VERSION'|translate }}</p> <p>{{'ADF_VERSION_COMPARISON.NEW_VERSION' | translate }}</p>
<img [attr.aria-label]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate: <img [attr.aria-label]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate:
{ type: (newFileVersion.type | fileType | uppercase) | translate }" { type: (newFileVersion.type | fileType | uppercase) | translate }"
[attr.alt]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate: [attr.alt]="'ADF_VERSION_COMPARISON.ACCESSIBILITY.ICON_TEXT' | translate:

View File

@@ -17,16 +17,19 @@
import { Component, Input, ViewEncapsulation } from '@angular/core'; import { Component, Input, ViewEncapsulation } from '@angular/core';
import { Node } from '@alfresco/js-api'; import { Node } from '@alfresco/js-api';
import { ThumbnailService } from '@alfresco/adf-core'; import { FileTypePipe, ThumbnailService } from '@alfresco/adf-core';
import { CommonModule } from '@angular/common';
import { TranslateModule } from '@ngx-translate/core';
@Component({ @Component({
selector: 'adf-version-comparison', selector: 'adf-version-comparison',
standalone: true,
imports: [CommonModule, TranslateModule, FileTypePipe],
templateUrl: './version-comparison.component.html', templateUrl: './version-comparison.component.html',
styleUrls: ['./version-comparison.component.scss'], styleUrls: ['./version-comparison.component.scss'],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class VersionComparisonComponent { export class VersionComparisonComponent {
/** Target node. */ /** Target node. */
@Input() @Input()
node: Node; node: Node;
@@ -35,7 +38,5 @@ export class VersionComparisonComponent {
@Input() @Input()
newFileVersion: File; newFileVersion: File;
constructor(public thumbnailService: ThumbnailService) { constructor(public thumbnailService: ThumbnailService) {}
}
} }

View File

@@ -24,7 +24,15 @@ import { ContentService } from '../common';
import { InfiniteScrollDatasource } from '../infinite-scroll-datasource'; import { InfiniteScrollDatasource } from '../infinite-scroll-datasource';
import { from, Observable, Subject } from 'rxjs'; import { from, Observable, Subject } from 'rxjs';
import { map, take, takeUntil } from 'rxjs/operators'; import { map, take, takeUntil } from 'rxjs/operators';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { CdkFixedSizeVirtualScroll, CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { CommonModule } from '@angular/common';
import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatListModule } from '@angular/material/list';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { TranslateModule } from '@ngx-translate/core';
import { MatButtonModule } from '@angular/material/button';
import { VersionCompatibilityDirective } from '../version-compatibility';
export class VersionListDataSource extends InfiniteScrollDatasource<VersionEntry> { export class VersionListDataSource extends InfiniteScrollDatasource<VersionEntry> {
constructor(private versionsApi: VersionsApi, private node: Node) { constructor(private versionsApi: VersionsApi, private node: Node) {
@@ -41,6 +49,20 @@ export class VersionListDataSource extends InfiniteScrollDatasource<VersionEntry
@Component({ @Component({
selector: 'adf-version-list', selector: 'adf-version-list',
standalone: true,
imports: [
CommonModule,
MatProgressBarModule,
MatListModule,
CdkVirtualScrollViewport,
CdkFixedSizeVirtualScroll,
CdkVirtualForOf,
MatIconModule,
MatMenuModule,
TranslateModule,
MatButtonModule,
VersionCompatibilityDirective
],
templateUrl: './version-list.component.html', templateUrl: './version-list.component.html',
styleUrls: ['./version-list.component.scss'], styleUrls: ['./version-list.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,

View File

@@ -1,7 +1,5 @@
<div class="adf-new-version-container"> <div class="adf-new-version-container">
<adf-version-comparison *ngIf="showVersionComparison" [node]="node" [newFileVersion]="newFileVersion"></adf-version-comparison> <adf-version-comparison *ngIf="showVersionComparison" [node]="node" [newFileVersion]="newFileVersion"></adf-version-comparison>
<div class="adf-new-version-uploader-container" id="adf-new-version-uploader-container" [@uploadToggle]="uploadState"> <div class="adf-new-version-uploader-container" id="adf-new-version-uploader-container" [@uploadToggle]="uploadState">
<table class="adf-version-upload" *ngIf="uploadState !== 'close' && !versionList.isLoading"> <table class="adf-version-upload" *ngIf="uploadState !== 'close' && !versionList.isLoading">
<tr> <tr>
@@ -19,20 +17,16 @@
</tr> </tr>
</table> </table>
</div> </div>
<div class="adf-version-list-container"> <div class="adf-version-list-container">
<div class="adf-version-list-table"> <div class="adf-version-list-table">
<div> <div>
<button mat-raised-button <button mat-raised-button
id="adf-show-version-upload-button" id="adf-show-version-upload-button"
(click)="toggleNewVersion()" color="primary" (click)="toggleNewVersion()" color="primary"
*ngIf="uploadState ==='close'">{{ *ngIf="uploadState ==='close'">{{ 'ADF_VERSION_LIST.ACTIONS.UPLOAD.ADD' | translate }}
'ADF_VERSION_LIST.ACTIONS.UPLOAD.ADD'|
translate }}
</button> </button>
</div> </div>
<div> <div>
<adf-version-list <adf-version-list
#versionList #versionList
[node]="node" [node]="node"

View File

@@ -22,29 +22,29 @@ import { trigger, state, style, animate, transition } from '@angular/animations'
import { ContentService } from '../common/services/content.service'; import { ContentService } from '../common/services/content.service';
import { NodesApiService } from '../common/services/nodes-api.service'; import { NodesApiService } from '../common/services/nodes-api.service';
import { FileUploadErrorEvent } from '../common/events/file.event'; import { FileUploadErrorEvent } from '../common/events/file.event';
import { CommonModule } from '@angular/common';
import { VersionComparisonComponent } from './version-comparison.component';
import { VersionUploadComponent } from './version-upload.component';
import { MatButtonModule } from '@angular/material/button';
import { TranslateModule } from '@ngx-translate/core';
@Component({ @Component({
selector: 'adf-version-manager', selector: 'adf-version-manager',
standalone: true,
imports: [CommonModule, VersionComparisonComponent, VersionUploadComponent, MatButtonModule, TranslateModule, VersionListComponent],
templateUrl: './version-manager.component.html', templateUrl: './version-manager.component.html',
styleUrls: ['./version-manager.component.scss'], styleUrls: ['./version-manager.component.scss'],
animations: [ animations: [
trigger('uploadToggle', [ trigger('uploadToggle', [
state('open', style({height: '175px', opacity: 1, visibility: 'visible'})), state('open', style({ height: '175px', opacity: 1, visibility: 'visible' })),
state('close', style({height: '0%', opacity: 0, visibility: 'hidden'})), state('close', style({ height: '0%', opacity: 0, visibility: 'hidden' })),
transition('open => close', [ transition('open => close', [style({ visibility: 'hidden' }), animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')]),
style({visibility: 'hidden'}), transition('close => open', [style({ visibility: 'visible' }), animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')])
animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')
]),
transition('close => open', [
style({visibility: 'visible'}),
animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')
])
]) ])
], ],
encapsulation: ViewEncapsulation.None encapsulation: ViewEncapsulation.None
}) })
export class VersionManagerComponent implements OnInit { export class VersionManagerComponent implements OnInit {
/** Target node to manage version history. */ /** Target node to manage version history. */
@Input() @Input()
node: Node; node: Node;
@@ -86,9 +86,7 @@ export class VersionManagerComponent implements OnInit {
uploadState: string = 'close'; uploadState: string = 'close';
constructor(private contentService: ContentService, constructor(private contentService: ContentService, private nodesApiService: NodesApiService) {}
private nodesApiService: NodesApiService) {
}
ngOnInit() { ngOnInit() {
if (this.newFileVersion) { if (this.newFileVersion) {

View File

@@ -15,23 +15,22 @@
* limitations under the License. * limitations under the License.
*/ */
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { NgModule } from '@angular/core'; import { NgModule } from '@angular/core';
import { MaterialModule } from '../material.module';
import { VersionUploadComponent } from './version-upload.component'; import { VersionUploadComponent } from './version-upload.component';
import { VersionManagerComponent } from './version-manager.component'; import { VersionManagerComponent } from './version-manager.component';
import { VersionListComponent } from './version-list.component'; import { VersionListComponent } from './version-list.component';
import { UploadModule } from '../upload/upload.module';
import { VersionCompatibilityModule } from '../version-compatibility/version-compatibility.module';
import { CoreModule, FileTypePipe } from '@alfresco/adf-core';
import { VersionComparisonComponent } from './version-comparison.component'; import { VersionComparisonComponent } from './version-comparison.component';
import { ScrollingModule } from '@angular/cdk/scrolling';
export const CONTENT_VERSION_DIRECTIVES = [
VersionUploadComponent,
VersionManagerComponent,
VersionListComponent,
VersionComparisonComponent
] as const;
/** @deprecated use `...CONTENT_VERSION_DIRECTIVES` instead */
@NgModule({ @NgModule({
imports: [CommonModule, MaterialModule, CoreModule, UploadModule, VersionCompatibilityModule, FormsModule, ScrollingModule, FileTypePipe], imports: [...CONTENT_VERSION_DIRECTIVES],
exports: [VersionUploadComponent, VersionManagerComponent, VersionListComponent, FormsModule, VersionComparisonComponent], exports: [...CONTENT_VERSION_DIRECTIVES]
declarations: [VersionUploadComponent, VersionManagerComponent, VersionListComponent, VersionComparisonComponent]
}) })
export class VersionManagerModule {} export class VersionManagerModule {}

View File

@@ -8,11 +8,12 @@
</mat-radio-button> </mat-radio-button>
</mat-radio-group> </mat-radio-group>
<mat-form-field class="adf-new-version-max-width" subscriptSizing="dynamic"> <mat-form-field class="adf-new-version-max-width" subscriptSizing="dynamic">
<mat-label>{{'ADF_VERSION_LIST.ACTIONS.UPLOAD.COMMENT' | translate}}</mat-label> <mat-label>{{'ADF_VERSION_LIST.ACTIONS.UPLOAD.COMMENT' | translate}}</mat-label>
<textarea matInput [(ngModel)]="comment" class="adf-new-version-text-area" id="adf-new-version-text-area" <textarea matInput
(change)="onCommentChange()"></textarea> [(ngModel)]="comment"
class="adf-new-version-text-area" id="adf-new-version-text-area"
(change)="onCommentChange()"></textarea>
</mat-form-field> </mat-form-field>
</div> </div>
<div class="adf-version-upload-buttons"> <div class="adf-version-upload-buttons">
<adf-upload-version-button *ngIf="showUploadButton" <adf-upload-version-button *ngIf="showUploadButton"

View File

@@ -22,16 +22,34 @@ import { takeUntil } from 'rxjs/operators';
import { ContentService } from '../common/services/content.service'; import { ContentService } from '../common/services/content.service';
import { UploadService } from '../common/services/upload.service'; import { UploadService } from '../common/services/upload.service';
import { FileUploadErrorEvent, FileUploadEvent } from '../common/events/file.event'; import { FileUploadErrorEvent, FileUploadEvent } from '../common/events/file.event';
import { CommonModule } from '@angular/common';
import { MatRadioModule } from '@angular/material/radio';
import { FormsModule } from '@angular/forms';
import { TranslateModule } from '@ngx-translate/core';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
import { UploadVersionButtonComponent } from '../upload';
@Component({ @Component({
selector: 'adf-version-upload', selector: 'adf-version-upload',
standalone: true,
imports: [
CommonModule,
MatRadioModule,
FormsModule,
TranslateModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
UploadVersionButtonComponent
],
templateUrl: './version-upload.component.html', templateUrl: './version-upload.component.html',
styleUrls: ['./version-upload.component.scss'], styleUrls: ['./version-upload.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
host: { class: 'adf-version-upload' } host: { class: 'adf-version-upload' }
}) })
export class VersionUploadComponent implements OnInit, OnDestroy { export class VersionUploadComponent implements OnInit, OnDestroy {
semanticVersion: string = 'minor'; semanticVersion: string = 'minor';
comment: string; comment: string;
uploadVersion: boolean = false; uploadVersion: boolean = false;
@@ -89,16 +107,13 @@ export class VersionUploadComponent implements OnInit, OnDestroy {
@Output() @Output()
uploadStarted = new EventEmitter<FileUploadEvent>(); uploadStarted = new EventEmitter<FileUploadEvent>();
constructor(private contentService: ContentService, private uploadService: UploadService) { constructor(private contentService: ContentService, private uploadService: UploadService) {}
}
ngOnInit() { ngOnInit() {
this.uploadService.fileUploadStarting this.uploadService.fileUploadStarting.pipe(takeUntil(this.onDestroy$)).subscribe((event: FileUploadEvent) => {
.pipe(takeUntil(this.onDestroy$)) this.disabled = true;
.subscribe((event: FileUploadEvent) => { this.uploadStarted.emit(event);
this.disabled = true; });
this.uploadStarted.emit(event);
});
} }
canUpload(): boolean { canUpload(): boolean {
@@ -143,8 +158,8 @@ export class VersionUploadComponent implements OnInit, OnDestroy {
} }
getNextMajorVersion(version: string): string { getNextMajorVersion(version: string): string {
const { major} = this.getParsedVersion(version); const { major } = this.getParsedVersion(version);
return `${major + 1 }.0`; return `${major + 1}.0`;
} }
private getParsedVersion(version: string) { private getParsedVersion(version: string) {