diff --git a/client/src/app/site/pages/base-media/mediafiles.html b/client/src/app/site/pages/base-media/mediafiles.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/client/src/app/site/pages/base-media/mediafiles.ts b/client/src/app/site/pages/base-media/mediafiles.ts new file mode 100644 index 0000000000..bac761890a --- /dev/null +++ b/client/src/app/site/pages/base-media/mediafiles.ts @@ -0,0 +1,295 @@ +import { ChangeDetectorRef, Component, inject, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { Id } from 'src/app/domain/definitions/key-types'; +import { OML } from 'src/app/domain/definitions/organization-permission'; +import { Permission } from 'src/app/domain/definitions/permission'; +import { Mediafile } from 'src/app/domain/models/mediafiles/mediafile'; +import { FontPlace, LogoDisplayNames, LogoPlace } from 'src/app/domain/models/mediafiles/mediafile.constants'; +import { BaseListViewComponent } from 'src/app/site/base/base-list-view.component'; +import { ViewMediafile } from 'src/app/site/pages/meetings/pages/mediafiles'; +import { MediafileListExportService } from 'src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/services/mediafile-list-export.service/mediafile-list-export.service'; +import { MediafileCommonService } from 'src/app/site/pages/meetings/pages/mediafiles/services/mediafile-common.service'; +import { MediafileControllerService } from 'src/app/site/pages/meetings/pages/mediafiles/services/mediafile-controller.service'; +import { OperatorService } from 'src/app/site/services/operator.service'; +import { ViewPortService } from 'src/app/site/services/view-port.service'; + +import { FileListComponent } from '../../../ui/modules/file-list/components/file-list/file-list.component'; +import { ModelData } from '../../services/autoupdate/utils'; +import { MEDIAFILES_SUBSCRIPTION } from '../meetings/pages/mediafiles/mediafiles.subscription'; +import { ActiveMeetingIdService } from '../meetings/services/active-meeting-id.service'; +import { MeetingComponentServiceCollectorService } from '../meetings/services/meeting-component-service-collector.service'; +import { MeetingSettingsService } from '../meetings/services/meeting-settings.service'; +import { ORGANIZATION_SUBSCRIPTION } from '../organization/organization.subscription'; +import { ORGANIZATION_MEDIAFILE_LIST_SUBSCRIPTION } from '../organization/pages/mediafiles/mediafiles.subscription'; + +@Component({ templateUrl: `./mediafiles.html` }) +export abstract class MediafileListeComponent + extends BaseListViewComponent + implements OnInit, OnDestroy +{ + @ViewChild(FileListComponent) + public readonly fileListComponent!: FileListComponent; + + public get activeMeetingId(): Id | null { + return this.activeMeetingIdService.meetingId; + } + + protected get activeMeetingIdService(): ActiveMeetingIdService { + return this.componentServiceCollector.activeMeetingIdService; + } + + protected get meetingSettingsService(): MeetingSettingsService { + return this.componentServiceCollector.meetingSettingsService; + } + + /** + * Holds the file to edit + */ + public fileToEdit!: ViewMediafile; + + public newDirectoryForm: UntypedFormGroup; + + public logoPlaces: LogoPlace[]; + public logoDisplayNames = LogoDisplayNames; + + /** + * The form to edit Files + */ + public fileEditForm: UntypedFormGroup | null = null; + + //public isUsedAsLogoFn = (file: ViewMediafile) => this.isUsedAs(file, true); + public isUsedAsLogoFn = (_file: ViewMediafile): boolean => false; + public isUsedAsFontFn = (_file: ViewMediafile): boolean => false; + + public folderSubscription: Subscription | null = null; + public directorySubscription: Subscription | null = null; + public directory: ViewMediafile | null = null; + public directoryChain: ViewMediafile[] = []; + + public directoryObservable: Observable; + public directorySubject: BehaviorSubject = new BehaviorSubject([]); + + public route = inject(ActivatedRoute); + public repo = inject(MediafileControllerService); + public exporter = inject(MediafileListExportService); + public vp = inject(ViewPortService); + public operator = inject(OperatorService); + public formBuilder = inject(UntypedFormBuilder); + public cd = inject(ChangeDetectorRef); + public commonService = inject(MediafileCommonService); + public override componentServiceCollector = inject(MeetingComponentServiceCollectorService); + + /** + * @return true if the user can manage media files + */ + public get canEdit(): boolean { + return ( + this.operator.hasOrganizationPermissions(OML.can_manage_organization) || + this.operator.hasPerms(Permission.mediafileCanManage) + ); + } + + public get shouldShowFileMenuFn(): (file?: ViewMediafile) => boolean { + return (file?) => (file ? this.showFileMenu(file) : this.showFileMenu()); + } + + public constructor(protected override translate: TranslateService) { + super(); + this.canMultiSelect = true; + + this.newDirectoryForm = this.formBuilder.group({ + title: [``, Validators.required] + }); + this.directoryObservable = this.directorySubject as Observable; + } + + /** + * Init. + * Set the title, make the edit Form and observe Mediafiles + */ + public ngOnInit(): void { + super.setTitle(`Files`); + + const directoryId = +this.route.snapshot.params?.[`id`] || null; + this.changeDirectory(directoryId); + } + + public async changeDirectory(directoryId: number | null, isOrgaLevel = true): Promise { + let mediafilesSubscribed: boolean | ModelData; + if (isOrgaLevel) { + mediafilesSubscribed = ( + await Promise.all([ + this.modelRequestService.subscriptionGotData(ORGANIZATION_SUBSCRIPTION), + this.modelRequestService.subscriptionGotData(ORGANIZATION_MEDIAFILE_LIST_SUBSCRIPTION) + ]) + ).some(val => !!val); + } else { + mediafilesSubscribed = await this.modelRequestService.subscriptionGotData(MEDIAFILES_SUBSCRIPTION); + } + + if (!mediafilesSubscribed) { + setTimeout(() => this.changeDirectory(directoryId), 50); + return; + } + + this.clearSubscriptions(); + + // pipe the directory observable to the directorySubject so that the actual observable which + // is given to the file list does not change + this.folderSubscription = this.repo.getDirectoryObservable(directoryId).subscribe(this.directorySubject); + + if (directoryId) { + this.directorySubscription = this.repo.getViewModelObservable(directoryId).subscribe(newDirectory => { + this.directory = newDirectory; + this.commonService.navigateToDirectoryPage(this.directory, directoryChain => { + this.directoryChain = directoryChain; + }); + }); + } else { + this.directory = null; + this.commonService.navigateToDirectoryPage( + this.directory, + directoryChain => { + this.directoryChain = directoryChain; + }, + true + ); + } + } + + public override ngOnDestroy(): void { + super.ngOnDestroy(); + this.cd.detach(); + } + + public override selectAll(): void { + this.fileListComponent.selectAll(); + } + + public override deselectAll(): void { + this.fileListComponent.deselectAll(); + } + + public onSelect(files: ViewMediafile[]): void { + this.selectedRows = files; + } + + public onMove(files: ViewMediafile[]): void { + this.fileListComponent.openMoveDialog(files); + } + + public onMainEvent(): void { + this.commonService.navigateToUploadPage(this.directory?.id); + } + + /** + * Click on the edit button in the file menu + * + * @param file the selected file + */ + public onEditFile(file: ViewMediafile, isOrgaLevel: boolean): void { + if (!this.isMultiSelect) { + this.fileToEdit = file; + + if (isOrgaLevel) { + this.fileEditForm = this.formBuilder.group({ + title: [file.title, Validators.required] + }); + } else { + this.fileEditForm = this.formBuilder.group({ + title: [file.title, Validators.required], + access_group_ids: [file.access_group_ids] + }); + } + } + } + + /** + * Click on the save button in edit mode + */ + public async onSaveFile(value: Partial | null): Promise { + if (value) { + await this.repo.update(value, this.fileToEdit); + } + } + + public async deleteSelected(): Promise { + await this.commonService.handleDeleteSelected(this.selectedRows, () => this.deselectAll()); + } + + public createNewFolder(templateRef: TemplateRef): void { + this.commonService + .handleCreateNewFolder(this.newDirectoryForm, this.directory, templateRef) + .catch(this.raiseError); + } + + public clearSubscriptions(): void { + if (this.folderSubscription) { + this.folderSubscription.unsubscribe(); + this.folderSubscription = null; + } + if (this.directorySubscription) { + this.directorySubscription.unsubscribe(); + this.directorySubscription = null; + } + } + + private isUsedAs(file: ViewMediafile, isOrgaLevel: boolean): boolean { + const places = this.logoPlaces; + return places.some(place => this.isMediafileUsed(file, place, isOrgaLevel)); + } + + public isMediafileUsed(file: ViewMediafile, place: LogoPlace | string, isOrgaLevel: boolean): boolean { + const mediafile = this.repo.getViewModel(file.id)!; + if (isOrgaLevel) { + if (file.isImage() && !Object.keys(LogoDisplayNames).includes(place)) { + return false; + } + return mediafile.token === place; + } else { + if (mediafile.isFont()) { + return mediafile.used_as_font_in_meeting_id(place as FontPlace) === this.activeMeetingId; + } + if (mediafile.isImage()) { + return mediafile.used_as_logo_in_meeting_id(place as LogoPlace) === this.activeMeetingId; + } + return false; + } + } + + /** + * Sends a delete request to the repository. + * + * @param file the file to delete + */ + public async onDeleteFile(file: ViewMediafile): Promise { + await this.commonService.handleDeleteFile(file, id => this.changeDirectory(id)); + } + + public downloadMultiple(isOrgaLevel: boolean, mediafiles: ViewMediafile[] = this.directorySubject.value): void { + let eventName = ``; + if (!isOrgaLevel) { + eventName = this.meetingSettingsService.instant(`name`); + } + const dirName = this.directory?.title ?? this.translate.instant(`Files`); + const archiveName = `${eventName} - ${dirName}`.trim(); + this.exporter.downloadArchive(archiveName, mediafiles); + } + + /** + * Determine if the given file has any extra option to show. + * @param file the file to check + * @returns wether the extra menu should be accessible + */ + public showFileMenu(file?: ViewMediafile): boolean { + return ( + (file?.isProjectable() && this.operator.hasPerms(Permission.projectorCanManage)) || + (file?.isFont() && this.operator.hasPerms(Permission.meetingCanManageLogosAndFonts)) || + (file?.isImage() && this.operator.hasPerms(Permission.meetingCanManageLogosAndFonts)) || + this.canEdit + ); + } +} diff --git a/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.html b/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.html index 672c6c2da9..0ba4757e38 100644 --- a/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.html +++ b/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.html @@ -44,7 +44,7 @@

{{ 'Files' | translate }}

[isMultiSelect]="isMultiSelect" [shouldShowFileMenuFn]="shouldShowFileMenuFn" [sourceFiles]="directoryObservable" - (beforeEditing)="onEditFile($event.file)" + (beforeEditing)="onEditFile($event.file, isOrgaLevel)" (deleted)="onDeleteFile($event.file)" (directoryChanged)="changeDirectory($event.directoryId)" (saved)="onSaveFile($event.update)" @@ -55,7 +55,7 @@

{{ 'Files' | translate }}

@if (canEdit && directory && directory.has_inherited_access_groups) { - @@ -124,7 +124,7 @@

{{ 'Files' | translate }}

library_add {{ 'Multiselect' | translate }} - @@ -141,7 +141,11 @@

{{ 'Files' | translate }}

{{ 'Deselect all' | translate }} - diff --git a/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.ts b/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.ts index c90c4f2877..e7c93d09a8 100644 --- a/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.ts +++ b/client/src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/components/mediafile-list/mediafile-list.component.ts @@ -1,29 +1,16 @@ -import { ChangeDetectorRef, Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; +import { Component, inject, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Validators } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, map, Observable, Subscription } from 'rxjs'; +import { map, Observable } from 'rxjs'; import { Permission } from 'src/app/domain/definitions/permission'; -import { Mediafile } from 'src/app/domain/models/mediafiles/mediafile'; -import { - FontDisplayNames, - FontPlace, - LogoDisplayNames, - LogoPlace -} from 'src/app/domain/models/mediafiles/mediafile.constants'; -import { BaseMeetingListViewComponent } from 'src/app/site/pages/meetings/base/base-meeting-list-view.component'; +import { FontDisplayNames, FontPlace, LogoPlace } from 'src/app/domain/models/mediafiles/mediafile.constants'; import { ViewMediafile } from 'src/app/site/pages/meetings/pages/mediafiles'; -import { MediafileControllerService } from 'src/app/site/pages/meetings/pages/mediafiles/services/mediafile-controller.service'; import { MediaManageService } from 'src/app/site/pages/meetings/services/media-manage.service'; -import { OperatorService } from 'src/app/site/services/operator.service'; -import { ViewPortService } from 'src/app/site/services/view-port.service'; import { FileListComponent } from 'src/app/ui/modules/file-list/components/file-list/file-list.component'; +import { MediafileListeComponent } from '../../../../../../../base-media/mediafiles'; import { InteractionService } from '../../../../../interaction/services/interaction.service'; import { ViewGroup } from '../../../../../participants/modules/groups/view-models/view-group'; -import { MEDIAFILES_SUBSCRIPTION } from '../../../../mediafiles.subscription'; -import { MediafileCommonService } from '../../../../services/mediafile-common.service'; -import { MediafileListExportService } from '../../services/mediafile-list-export.service/mediafile-list-export.service'; import { MediafileListGroupService } from '../../services/mediafile-list-group.service'; @Component({ @@ -31,42 +18,16 @@ import { MediafileListGroupService } from '../../services/mediafile-list-group.s templateUrl: `./mediafile-list.component.html`, styleUrls: [`./mediafile-list.component.scss`] }) -export class MediafileListComponent extends BaseMeetingListViewComponent implements OnInit, OnDestroy { +export class MediafileListComponent extends MediafileListeComponent implements OnInit, OnDestroy { @ViewChild(FileListComponent) - public readonly fileListComponent!: FileListComponent; + public fontPlaces: string[]; - /** - * Reference to the template for edit-dialog - */ - @ViewChild(`fileEditDialog`, { static: true }) - private readonly _fileEditDialog: TemplateRef | null = null; + protected readonly isOrgaLevel = false; - public logoPlaces: string[]; - public logoDisplayNames = LogoDisplayNames; - public fontPlaces: string[]; public fontDisplayNames = FontDisplayNames; - /** - * Holds the file to edit - */ - public fileToEdit!: ViewMediafile; - - public newDirectoryForm: UntypedFormGroup; public groupsBehaviorSubject: Observable; - public sortFn = (groupA: ViewGroup, groupB: ViewGroup): number => groupA.weight - groupB.weight; - - /** - * @return true if the user can manage media files - */ - public get canEdit(): boolean { - return this.operator.hasPerms(Permission.mediafileCanManage); - } - - public get shouldShowFileMenuFn(): (file: ViewMediafile) => boolean { - return file => this.showFileMenu(file); - } - /** * Determine if the file menu should generally be accessible, according to the users permission */ @@ -79,38 +40,16 @@ export class MediafileListComponent extends BaseMeetingListViewComponent { return this.interactionService.isConfStateNone.pipe(map(isNone => !isNone)); } - private folderSubscription: Subscription | null = null; - private directorySubscription: Subscription | null = null; - public directory: ViewMediafile | null = null; - public directoryChain: ViewMediafile[] = []; + private mediaManage = inject(MediaManageService); + private groupRepo = inject(MediafileListGroupService); + private interactionService = inject(InteractionService); - public directoryObservable: Observable; - private directorySubject: BehaviorSubject = new BehaviorSubject([]); - - public constructor( - protected override translate: TranslateService, - private route: ActivatedRoute, - public repo: MediafileControllerService, - private exporter: MediafileListExportService, - private mediaManage: MediaManageService, - public vp: ViewPortService, - private operator: OperatorService, - private formBuilder: UntypedFormBuilder, - private groupRepo: MediafileListGroupService, - private cd: ChangeDetectorRef, - private commonService: MediafileCommonService, - private interactionService: InteractionService - ) { - super(); + public constructor(protected override translate: TranslateService) { + super(translate); this.canMultiSelect = true; this.logoPlaces = this.mediaManage.allLogoPlaces; @@ -124,11 +63,13 @@ export class MediafileListComponent extends BaseMeetingListViewComponent; } + public sortFn = (groupA: ViewGroup, groupB: ViewGroup): number => groupA.weight - groupB.weight; + /** * Init. * Set the title, make the edit Form and observe Mediafiles */ - public ngOnInit(): void { + public override ngOnInit(): void { super.setTitle(`Files`); const directoryId = +this.route.snapshot.params?.[`id`] || null; @@ -141,123 +82,8 @@ export class MediafileListComponent extends BaseMeetingListViewComponent { - const mediafilesSubscribed = await this.modelRequestService.subscriptionGotData(MEDIAFILES_SUBSCRIPTION); - if (!mediafilesSubscribed) { - setTimeout(() => this.changeDirectory(directoryId), 50); - return; - } - - this.clearSubscriptions(); - - // pipe the directory observable to the directorySubject so that the actual observable which - // is given to the file list does not change - this.folderSubscription = this.repo.getDirectoryObservable(directoryId).subscribe(this.directorySubject); - - if (directoryId) { - this.directorySubscription = this.repo.getViewModelObservable(directoryId).subscribe(newDirectory => { - this.directory = newDirectory; - this.commonService.navigateToDirectoryPage(this.directory, directoryChain => { - this.directoryChain = directoryChain; - }); - }); - } else { - this.directory = null; - this.commonService.navigateToDirectoryPage( - this.directory, - directoryChain => { - this.directoryChain = directoryChain; - }, - true - ); - } - } - - public onMainEvent(): void { - this.commonService.navigateToUploadPage(this.directory?.id); - } - - public triggerEdit(file: ViewMediafile): void { - this.fileListComponent.onEditFile(file, this._fileEditDialog); - } - - /** - * Click on the edit button in the file menu - * - * @param file the selected file - */ - public onEditFile(file: ViewMediafile): void { - if (!this.isMultiSelect) { - this.fileToEdit = file; - - this.fileEditForm = this.formBuilder.group({ - title: [file.title, Validators.required], - access_group_ids: [[...file.access_group_ids]] - }); - } - } - - /** - * Click on the save button in edit mode - */ - public async onSaveFile(value: Partial | null): Promise { - if (value) { - await this.repo.update(value, this.fileToEdit); - } - } - - /** - * Sends a delete request to the repository. - * - * @param file the file to delete - */ - public async onDeleteFile(file: ViewMediafile): Promise { - await this.commonService.handleDeleteFile(file, id => this.changeDirectory(id)); - } - - public async deleteSelected(): Promise { - await this.commonService.handleDeleteSelected(this.selectedRows, () => this.deselectAll()); + public override async changeDirectory(directoryId: number | null): Promise { + return super.changeDirectory(directoryId, this.isOrgaLevel); } /** @@ -292,21 +118,8 @@ export class MediafileListComponent extends BaseMeetingListViewComponent): void { - this.commonService - .handleCreateNewFolder(this.newDirectoryForm, this.directory, templateRef) - .catch(this.raiseError); - } - - public downloadMultiple(mediafiles: ViewMediafile[] = this.directorySubject.value): void { - const eventName = this.meetingSettingsService.instant(`name`); - const dirName = this.directory?.title ?? this.translate.instant(`Files`); - const archiveName = `${eventName} - ${dirName}`.trim(); - this.exporter.downloadArchive(archiveName, mediafiles); - } - private async toggleLogoUsage(file: ViewMediafile, place: LogoPlace): Promise { - if (this.isMediafileUsed(file, place)) { + if (this.isMediafileUsed(file, place, this.isOrgaLevel)) { await this.mediaManage.unsetLogo(place); } else { await this.mediaManage.setLogo(place, file); @@ -314,21 +127,10 @@ export class MediafileListComponent extends BaseMeetingListViewComponent { - if (this.isMediafileUsed(file, place)) { + if (this.isMediafileUsed(file, place, this.isOrgaLevel)) { await this.mediaManage.unsetFont(place); } else { await this.mediaManage.setFont(place, file); } } - - private clearSubscriptions(): void { - if (this.folderSubscription) { - this.folderSubscription.unsubscribe(); - this.folderSubscription = null; - } - if (this.directorySubscription) { - this.directorySubscription.unsubscribe(); - this.directorySubscription = null; - } - } } diff --git a/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.html b/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.html index babd5401c7..c7147189bc 100644 --- a/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.html +++ b/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.html @@ -60,7 +60,7 @@

{{ 'Files' | translate }}

library_add {{ 'Multiselect' | translate }} - @@ -77,7 +77,11 @@

{{ 'Files' | translate }}

{{ 'Deselect all' | translate }} - @@ -142,7 +146,7 @@

{{ 'Edit details for' | translate }}

(click)="toggleMediafileUsage($event, mediafile, place)" > - {{ isMediafileUsed(mediafile, place) ? 'check_box' : 'check_box_outline_blank' }} + {{ isMediafileUsed(mediafile, place, isOrgaLevel) ? 'check_box' : 'check_box_outline_blank' }} {{ getDisplayNameForPlace(place) | translate }} diff --git a/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.ts b/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.ts index 01bb91e8f2..9c160f5a61 100644 --- a/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.ts +++ b/client/src/app/site/pages/organization/pages/mediafiles/modules/organization-mediafile-list/components/organization-mediafile-list/organization-mediafile-list.component.ts @@ -1,30 +1,12 @@ -import { - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - OnDestroy, - OnInit, - TemplateRef, - ViewChild -} from '@angular/core'; -import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; +import { ChangeDetectionStrategy, Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Validators } from '@angular/forms'; import { TranslateService } from '@ngx-translate/core'; -import { BehaviorSubject, Observable, Subscription } from 'rxjs'; -import { OML } from 'src/app/domain/definitions/organization-permission'; -import { Mediafile } from 'src/app/domain/models/mediafiles/mediafile'; +import { Observable } from 'rxjs'; import { LogoDisplayNames, LogoPlace } from 'src/app/domain/models/mediafiles/mediafile.constants'; -import { BaseListViewComponent } from 'src/app/site/base/base-list-view.component'; import { ViewMediafile } from 'src/app/site/pages/meetings/pages/mediafiles'; -import { MediafileListExportService } from 'src/app/site/pages/meetings/pages/mediafiles/modules/mediafile-list/services/mediafile-list-export.service/mediafile-list-export.service'; -import { MediafileCommonService } from 'src/app/site/pages/meetings/pages/mediafiles/services/mediafile-common.service'; -import { MediafileControllerService } from 'src/app/site/pages/meetings/pages/mediafiles/services/mediafile-controller.service'; -import { ORGANIZATION_SUBSCRIPTION } from 'src/app/site/pages/organization/organization.subscription'; -import { OperatorService } from 'src/app/site/services/operator.service'; -import { ViewPortService } from 'src/app/site/services/view-port.service'; import { FileListComponent } from 'src/app/ui/modules/file-list/components/file-list/file-list.component'; -import { ORGANIZATION_MEDIAFILE_LIST_SUBSCRIPTION } from '../../../../mediafiles.subscription'; +import { MediafileListeComponent } from '../../../../../../../base-media/mediafiles'; @Component({ selector: `os-organization-mediafile-list`, @@ -32,35 +14,13 @@ import { ORGANIZATION_MEDIAFILE_LIST_SUBSCRIPTION } from '../../../../mediafiles styleUrls: [`./organization-mediafile-list.component.scss`], changeDetection: ChangeDetectionStrategy.OnPush }) -export class OrganizationMediafileListComponent - extends BaseListViewComponent - implements OnInit, OnDestroy -{ +export class OrganizationMediafileListComponent extends MediafileListeComponent implements OnInit, OnDestroy { @ViewChild(FileListComponent) - public readonly fileListComponent!: FileListComponent; + public override logoPlaces: LogoPlace[] = [`web_header`]; - /** - * Holds the file to edit - */ - public fileToEdit!: ViewMediafile; - - public newDirectoryForm: UntypedFormGroup; + protected updatingLogoAndFontSettings = false; - public logoPlaces: LogoPlace[] = [`web_header`]; - public logoDisplayNames = LogoDisplayNames; - - public updatingLogoAndFontSettings = false; - - /** - * @return true if the user can manage media files - */ - public get canEdit(): boolean { - return this.operator.hasOrganizationPermissions(OML.can_manage_organization); - } - - public get shouldShowFileMenuFn(): (file: ViewMediafile) => boolean { - return () => this.showFileMenu(); - } + public readonly isOrgaLevel = true; /** * Determine if the file menu should generally be accessible, according to the users permission @@ -69,34 +29,8 @@ export class OrganizationMediafileListComponent return this.canEdit; } - /** - * The form to edit Files - */ - public fileEditForm: UntypedFormGroup | null = null; - - public isUsedAsLogoFn = (file: ViewMediafile): boolean => this.isUsedAs(file); - public isUsedAsFontFn = (_file: ViewMediafile): boolean => false; - - private folderSubscription: Subscription | null = null; - private directorySubscription: Subscription | null = null; - public directory: ViewMediafile | null = null; - public directoryChain: ViewMediafile[] = []; - - public directoryObservable: Observable; - private directorySubject: BehaviorSubject = new BehaviorSubject([]); - - public constructor( - protected override translate: TranslateService, - private route: ActivatedRoute, - public repo: MediafileControllerService, - private exporter: MediafileListExportService, - public vp: ViewPortService, - private operator: OperatorService, - private formBuilder: UntypedFormBuilder, - private cd: ChangeDetectorRef, - private commonService: MediafileCommonService - ) { - super(); + public constructor(protected override translate: TranslateService) { + super(translate); this.canMultiSelect = true; this.newDirectoryForm = this.formBuilder.group({ @@ -109,7 +43,7 @@ export class OrganizationMediafileListComponent * Init. * Set the title, make the edit Form and observe Mediafiles */ - public ngOnInit(): void { + public override ngOnInit(): void { super.setTitle(`Files`); const directoryId = +this.route.snapshot.params?.[`id`] || null; @@ -122,14 +56,6 @@ export class OrganizationMediafileListComponent this.cd.detach(); } - public isMediafileUsed(file: ViewMediafile, place: LogoPlace): boolean { - const mediafile = this.repo.getViewModel(file.id)!; - if (file.isImage() && !Object.keys(LogoDisplayNames).includes(place)) { - return false; - } - return mediafile.token === place; - } - public async toggleMediafileUsage(event: Event, mediafile: ViewMediafile, place: LogoPlace): Promise { // prohibits automatic closing event.stopPropagation(); @@ -158,69 +84,8 @@ export class OrganizationMediafileListComponent return `${prefix} ${LogoDisplayNames[place].toLowerCase()}`; } - public override selectAll(): void { - this.fileListComponent.selectAll(); - } - - public override deselectAll(): void { - this.fileListComponent.deselectAll(); - } - - public onSelect(files: ViewMediafile[]): void { - this.selectedRows = files; - } - - public onMove(files: ViewMediafile[]): void { - this.fileListComponent.openMoveDialog(files); - } - - /** - * Determine if the given file has any extra option to show. - * @returns wether the extra menu should be accessible - */ - public showFileMenu(): boolean { - return this.canEdit; - } - - public async changeDirectory(directoryId: number | null): Promise { - const mediafilesSubscribed = ( - await Promise.all([ - this.modelRequestService.subscriptionGotData(ORGANIZATION_SUBSCRIPTION), - this.modelRequestService.subscriptionGotData(ORGANIZATION_MEDIAFILE_LIST_SUBSCRIPTION) - ]) - ).some(val => !!val); - if (!mediafilesSubscribed) { - setTimeout(() => this.changeDirectory(directoryId), 50); - return; - } - - this.clearSubscriptions(); - - // pipe the directory observable to the directorySubject so that the actual observable which - // is given to the file list does not change - this.folderSubscription = this.repo.getDirectoryObservable(directoryId).subscribe(this.directorySubject); - - if (directoryId) { - this.directorySubscription = this.repo.getViewModelObservable(directoryId).subscribe(newDirectory => { - this.directory = newDirectory; - this.commonService.navigateToDirectoryPage(this.directory, directoryChain => { - this.directoryChain = directoryChain; - }); - }); - } else { - this.directory = null; - this.commonService.navigateToDirectoryPage( - this.directory, - directoryChain => { - this.directoryChain = directoryChain; - }, - true - ); - } - } - - public onMainEvent(): void { - this.commonService.navigateToUploadPage(this.directory?.id); + public override async changeDirectory(directoryId: number | null): Promise { + return super.changeDirectory(directoryId, this.isOrgaLevel); } /** @@ -228,63 +93,7 @@ export class OrganizationMediafileListComponent * * @param file the selected file */ - public onEditFile(file: ViewMediafile): void { - if (!this.isMultiSelect) { - this.fileToEdit = file; - - this.fileEditForm = this.formBuilder.group({ - title: [file.title, Validators.required] - }); - } - } - - /** - * Click on the save button in edit mode - */ - public async onSaveFile(value: Partial | null): Promise { - if (value) { - await this.repo.update(value, this.fileToEdit); - } - } - - /** - * Sends a delete request to the repository. - * - * @param file the file to delete - */ - public async onDeleteFile(file: ViewMediafile): Promise { - await this.commonService.handleDeleteFile(file, id => this.changeDirectory(id)); - } - - public async deleteSelected(): Promise { - await this.commonService.handleDeleteSelected(this.selectedRows, () => this.deselectAll()); - } - - public createNewFolder(templateRef: TemplateRef): void { - this.commonService - .handleCreateNewFolder(this.newDirectoryForm, this.directory, templateRef) - .catch(this.raiseError); - } - - public downloadMultiple(mediafiles: ViewMediafile[] = this.directorySubject.value): void { - const dirName = this.directory?.title ?? this.translate.instant(`Files`); - const archiveName = `${dirName}`.trim(); - this.exporter.downloadArchive(archiveName, mediafiles); - } - - private clearSubscriptions(): void { - if (this.folderSubscription) { - this.folderSubscription.unsubscribe(); - this.folderSubscription = null; - } - if (this.directorySubscription) { - this.directorySubscription.unsubscribe(); - this.directorySubscription = null; - } - } - - private isUsedAs(file: ViewMediafile): boolean { - const places = this.logoPlaces; - return places.some(place => this.isMediafileUsed(file, place)); + public override onEditFile(file: ViewMediafile): void { + super.onEditFile(file, this.isOrgaLevel); } }