diff --git a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts index a38d01441f..a9324dbc30 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts +++ b/src/applications/content-entries-app/entries/bulk-actions/bulk-actions.component.ts @@ -164,7 +164,7 @@ export class BulkActionsComponent implements OnInit, OnDestroy { this._browserService.setAppStatus({isBusy: false, errorMessage: this._appLocalization.get('applications.content.bulkActions.error')}); } ); - } + }; if (this.selectedEntries.length > environment.modules.contentEntries.bulkActionsLimit){ this._browserService.confirm( diff --git a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts index 9b9cc5f926..6c9e8ba2d7 100644 --- a/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts +++ b/src/applications/content-entries-app/entries/bulk-actions/services/bulk-delete.service.ts @@ -26,7 +26,7 @@ export class BulkDeleteService extends BulkActionBaseService<{}> { this.transmit(requests, true).subscribe( result => { - observer.next({}) + observer.next({}); observer.complete(); }, error => { diff --git a/src/applications/content-entries-app/entries/entries-list.component.ts b/src/applications/content-entries-app/entries/entries-list.component.ts index 8821b4ba7f..501d679510 100644 --- a/src/applications/content-entries-app/entries/entries-list.component.ts +++ b/src/applications/content-entries-app/entries/entries-list.component.ts @@ -157,7 +157,6 @@ export class EntriesListComponent implements OnInit, OnDestroy { ); break; default: - alert("Selected Action: " + event.action + "\nEntry ID: " + event.entryID); break; } } diff --git a/src/applications/content-playlists-app/content-playlists-app.module.ts b/src/applications/content-playlists-app/content-playlists-app.module.ts index bc719d006c..230458a101 100644 --- a/src/applications/content-playlists-app/content-playlists-app.module.ts +++ b/src/applications/content-playlists-app/content-playlists-app.module.ts @@ -30,8 +30,6 @@ import { PopupWidgetModule } from '@kaltura-ng/kaltura-ui/popup-widget'; import { ContentPlaylistsComponent } from './content-playlists.component'; import { PlaylistsComponentsList } from './playlists/playlists-components-list'; import { PlaylistComponentsList } from './playlist/playlist-components-list'; -import { PlaylistsStore } from './playlists/playlists-store/playlists-store.service'; -import { PlaylistStore } from './playlist/playlist-store.service'; import { PlaylistCanDeactivate } from './playlist/playlist-can-deactivate.service'; @NgModule({ @@ -63,12 +61,11 @@ import { PlaylistCanDeactivate } from './playlist/playlist-can-deactivate.servic PlaylistsComponentsList, PlaylistComponentsList ], - exports: [], - providers: [ - PlaylistsStore, - PlaylistStore, - PlaylistCanDeactivate - ], + exports: [ + ], + providers : [ + PlaylistCanDeactivate + ] }) export class ContentPlaylistsAppModule { } diff --git a/src/applications/content-playlists-app/content-playlists-app.routes.ts b/src/applications/content-playlists-app/content-playlists-app.routes.ts index 4aa40879ed..e5fd772081 100644 --- a/src/applications/content-playlists-app/content-playlists-app.routes.ts +++ b/src/applications/content-playlists-app/content-playlists-app.routes.ts @@ -1,5 +1,6 @@ import { Route } from '@angular/router'; +import { ContentPlaylistsComponent } from './content-playlists.component'; import { PlaylistsListComponent } from './playlists/playlists-list.component'; import { PlaylistComponent } from './playlist/playlist.component'; import { PlaylistMetadataComponent } from './playlist/playlist-metadata/playlist-metadata.component'; @@ -8,16 +9,21 @@ import { PlaylistSections } from './playlist/playlist-sections'; import { PlaylistCanDeactivate } from './playlist/playlist-can-deactivate.service'; export const routing: Route[] = [ - {path: '', redirectTo: 'list', pathMatch: 'full'}, - {path: 'list', component: PlaylistsListComponent}, - {path: 'playlist/:id', canDeactivate: [PlaylistCanDeactivate], component: PlaylistComponent, - data : { - playlistRoute : true - }, - children : [ - { path: '', redirectTo: 'content', pathMatch: 'full' }, - { path: 'metadata', component: PlaylistMetadataComponent, data : { sectionKey : PlaylistSections.Metadata } }, - { path: 'content', component: PlaylistContentComponent, data : { sectionKey : PlaylistSections.Content } } - ] - } + { + path: '', component: ContentPlaylistsComponent, + children: [ + { path: '', redirectTo: 'list', pathMatch: 'full' }, + { path: 'list', component: PlaylistsListComponent }, + { path: 'playlist/:id', canDeactivate: [PlaylistCanDeactivate], component: PlaylistComponent, + data: { + playlistRoute: true + }, + children: [ + { path: '', redirectTo: 'content', pathMatch: 'full'}, + { path: 'metadata', component: PlaylistMetadataComponent, data: { sectionKey: PlaylistSections.Metadata } }, + { path: 'content', component: PlaylistContentComponent, data: { sectionKey: PlaylistSections.Content } } + ] + } + ] + } ]; diff --git a/src/applications/content-playlists-app/content-playlists.component.ts b/src/applications/content-playlists-app/content-playlists.component.ts index 296985ecd5..6a3565f0dc 100644 --- a/src/applications/content-playlists-app/content-playlists.component.ts +++ b/src/applications/content-playlists-app/content-playlists.component.ts @@ -1,9 +1,11 @@ import { Component } from '@angular/core'; +import { PlaylistsStore } from './playlists/playlists-store/playlists-store.service'; @Component({ selector: 'kPlaylists', templateUrl: './content-playlists.component.html', - styleUrls: ['./content-playlists.component.scss'] + styleUrls: ['./content-playlists.component.scss'], + providers: [PlaylistsStore] }) export class ContentPlaylistsComponent {} diff --git a/src/applications/content-playlists-app/playlist/playlist-components-list.ts b/src/applications/content-playlists-app/playlist/playlist-components-list.ts index 473848fc75..400eafd645 100644 --- a/src/applications/content-playlists-app/playlist/playlist-components-list.ts +++ b/src/applications/content-playlists-app/playlist/playlist-components-list.ts @@ -3,6 +3,7 @@ import { PlaylistContentComponent } from './playlist-content/playlist-content.co import { PlaylistSectionsList } from "./playlist-sections-list/playlist-sections-list.component"; import { PlaylistComponent } from './playlist.component'; import { PlaylistDetailsComponent } from './playlist-details/playlist-details.component'; +import { PlaylistEntriesTableComponent } from './playlist-entries-table/playlist-entries-table.component'; import { ModerationPipe } from './pipes/moderation.pipe'; @@ -12,5 +13,6 @@ export const PlaylistComponentsList = [ PlaylistSectionsList, PlaylistComponent, PlaylistDetailsComponent, + PlaylistEntriesTableComponent, ModerationPipe ]; diff --git a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.html b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.html index 9b79f008d0..59cc0fab23 100644 --- a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.html +++ b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.html @@ -1 +1,18 @@ -

{{'applications.content.playlistDetails.sections.content' | translate}}

+ +
+
+ + + {{(_playlistStore.entries$ | async)?.totalCount}} {{'applications.content.playlists.playlists' | translate}} +
+ +
+
diff --git a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.scss b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.scss index e69de29bb2..9a755e91b0 100644 --- a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.scss +++ b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.scss @@ -0,0 +1,23 @@ +@import 'app-theme/_variables.scss'; + +.kContentDetails { + width: 100%; + + .kPlaylistsTableFilters { + width: 100%; + height: 66px; + background-color: white; + flex: 0 0 auto; + align-items: center; + display: flex; + + .kAddPlaylistBtn { + margin-left: 14px; + height: 36px; + } + + .kSelectedPlaylistsNum{ + padding-left: 16px; + } + } +} diff --git a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.ts b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.ts index cbea21ec89..75301ddf36 100644 --- a/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.ts +++ b/src/applications/content-playlists-app/playlist/playlist-content/playlist-content.component.ts @@ -1,4 +1,5 @@ import { Component, AfterViewInit, OnInit, OnDestroy } from '@angular/core'; +import { PlaylistStore } from '../playlist-store.service'; @Component({ selector: 'kPlaylistContent', @@ -7,7 +8,7 @@ import { Component, AfterViewInit, OnInit, OnDestroy } from '@angular/core'; }) export class PlaylistContentComponent implements AfterViewInit, OnInit, OnDestroy { - constructor() {} + constructor(public _playlistStore: PlaylistStore) {} ngOnInit() {} diff --git a/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.html b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.html new file mode 100644 index 0000000000..4cb30cc84c --- /dev/null +++ b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.html @@ -0,0 +1,51 @@ + +
+ + + + +
+ +
+
+
+ + + {{entry[col.field]}} + + + + +
{{entry[col.field]}}
+
+
+ + + {{entry[col.field] | kDate}} + + + + + + {{entry[col.field]}} + + + + +
+ +
+
+
+
+
+
diff --git a/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.scss b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.scss new file mode 100644 index 0000000000..3110015b91 --- /dev/null +++ b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.scss @@ -0,0 +1,44 @@ +@import 'app-theme/_variables.scss'; + +.kPlaylistEntriesTable { + background-color: white; + overflow-y: hidden; + position: absolute; + padding: 0px; + + .kThumbnailHolder { + overflow: hidden; + position: relative; + width: 80px; + height: 46px; + background-color: $kGrayscale6; + white-space: nowrap; + text-align: center; + border-radius: 3px; + cursor: pointer; + + img { + position:absolute; + left: -100%; + right: -100%; + top: -100%; + bottom: -100%; + margin: auto; + width: 80px; + height: auto; + border-radius: 3px; + } + } + + .kEntriesTableActions { + width: 100%; + text-align: center; + button { + color: grey !important; + background-color: rgba(0, 0, 0, 0) !important; + border: none !important; + font-size: 16px !important; + outline: 0; + } + } +} diff --git a/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.ts b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.ts new file mode 100644 index 0000000000..d6e2fc6e64 --- /dev/null +++ b/src/applications/content-playlists-app/playlist/playlist-entries-table/playlist-entries-table.component.ts @@ -0,0 +1,60 @@ +import { Component, Input, Output, EventEmitter, AfterViewInit, OnInit, OnDestroy, ViewChild, ChangeDetectorRef } from '@angular/core'; +import { ISubscription } from 'rxjs/Subscription'; +import { MenuItem, DataTable, Menu } from 'primeng/primeng'; +import { AppLocalization } from '@kaltura-ng/kaltura-common'; +import { AreaBlockerMessage } from '@kaltura-ng/kaltura-ui'; +import { KalturaMediaType } from 'kaltura-typescript-client/types/KalturaMediaType'; +import { KalturaMediaEntry } from 'kaltura-typescript-client/types/KalturaMediaEntry'; +import { KalturaEntryStatus } from 'kaltura-typescript-client/types/KalturaEntryStatus'; +import { PlaylistStore } from "../playlist-store.service"; + +@Component({ + selector: 'kPlaylistEntriesTable', + templateUrl: './playlist-entries-table.component.html', + styleUrls: ['./playlist-entries-table.component.scss'] +}) +export class PlaylistEntriesTableComponent implements AfterViewInit, OnInit, OnDestroy { + public _entries: any[] = []; + private _deferredEntries : any[]; + public _deferredLoading = true; + public rowTrackBy: Function = (index: number, item: any) => {return item.id}; + + @Input() set entries(data: any[]) { + if (!this._deferredLoading) { + this._entries = []; + this.cdRef.detectChanges(); + this._entries = data; + this.cdRef.detectChanges(); + } else { + this._deferredEntries = data + } + } + + constructor( + private appLocalization: AppLocalization, + public playlistStore: PlaylistStore, + private cdRef: ChangeDetectorRef + ) {} + ngOnInit() { + /*this.playlistStore.entries$ + .subscribe(response => { + + });*/ + } + + ngAfterViewInit() { + if (this._deferredLoading) { + // use timeout to allow the DOM to render before setting the data to the datagrid. This prevents the screen from hanging during datagrid rendering of the data. + setTimeout(()=> { + this._deferredLoading = false; + this._entries = this._deferredEntries; + this._deferredEntries = null; + }, 0); + } + } + + ngOnDestroy() { + + } +} + diff --git a/src/applications/content-playlists-app/playlist/playlist-metadata/playlist-metadata.component.scss b/src/applications/content-playlists-app/playlist/playlist-metadata/playlist-metadata.component.scss index 77e20ac7c2..f2032e8244 100644 --- a/src/applications/content-playlists-app/playlist/playlist-metadata/playlist-metadata.component.scss +++ b/src/applications/content-playlists-app/playlist/playlist-metadata/playlist-metadata.component.scss @@ -1,16 +1,14 @@ @import 'app-theme/_variables.scss'; .kMetadataDetails { - padding: 18px 8px 0 12px; + padding: 26px 8px 8px 20px; overflow-y: auto; width: 100%; .kSchemaTitle { color: $kGrayscale1; font-size: 18px; - font-weight: 700; - padding-top: 30px; - padding-bottom: 12px; + font-weight: bold; } /deep/ { diff --git a/src/applications/content-playlists-app/playlist/playlist-store.service.ts b/src/applications/content-playlists-app/playlist/playlist-store.service.ts index 89c3008731..d8c3fbd872 100644 --- a/src/applications/content-playlists-app/playlist/playlist-store.service.ts +++ b/src/applications/content-playlists-app/playlist/playlist-store.service.ts @@ -14,26 +14,31 @@ import { KalturaTagFilter } from 'kaltura-typescript-client/types/KalturaTagFilt import { KalturaTaggedObjectType } from 'kaltura-typescript-client/types/KalturaTaggedObjectType'; import { KalturaFilterPager } from 'kaltura-typescript-client/types/KalturaFilterPager'; import { PlaylistSections } from './playlist-sections'; +import { KalturaMultiRequest } from 'kaltura-typescript-client'; +import { PlaylistExecuteAction } from 'kaltura-typescript-client/types/PlaylistExecuteAction'; +import { KalturaBaseEntry } from 'kaltura-typescript-client/types/KalturaBaseEntry'; @Injectable() export class PlaylistStore implements OnDestroy { - private _sectionsState = new BehaviorSubject<{ - metadata: {isValid: boolean, isDirty?: boolean}, + private _sectionsState = new BehaviorSubject<{ + metadata: {isValid: boolean, isDirty?: boolean}, content: {isValid: boolean, isDirty?: boolean} - }>({ - metadata: {isValid: true, isDirty: false}, + }>({ + metadata: {isValid: true, isDirty: false}, content: {isValid: true, isDirty: false} - }); - private _loadPlaylistSubscription : ISubscription; + }); + private _loadPlaylistSubscription : ISubscription; private _sectionToRouteMapping : { [key : number] : string} = {}; - private _activeSection = new BehaviorSubject<{ section: PlaylistSections}>({section: null}); - private _playlist = new BehaviorSubject<{ playlist: KalturaPlaylist}>({playlist: null}); - private _state = new BehaviorSubject<{ isBusy: boolean, error?: { message: string, origin?: 'reload' | 'save'}}>({isBusy: false}); + private _activeSection = new BehaviorSubject<{ section: PlaylistSections}>({section: null}); + private _playlist = new BehaviorSubject<{ playlist: KalturaPlaylist}>({playlist: null}); + private _state = new BehaviorSubject<{ isBusy: boolean, error?: { message: string, origin?: 'reload' | 'save'}}>({isBusy: false}); + private _entries = new BehaviorSubject({items: [], totalCount: 0}); - public playlist$ = this._playlist.asObservable(); + public entries$ = this._entries.asObservable(); + public playlist$ = this._playlist.asObservable(); public activeSection$ = this._activeSection.asObservable(); - public sectionsState$ = this._sectionsState.asObservable(); - public state$ = this._state.asObservable(); + public sectionsState$ = this._sectionsState.asObservable(); + public state$ = this._state.asObservable(); private _getPlaylistId() : string { @@ -44,19 +49,19 @@ export class PlaylistStore implements OnDestroy { return this._playlist.getValue().playlist; } - constructor( - private _router: Router, - private _playlistRoute: ActivatedRoute, - private _kalturaServerClient: KalturaClient, - private _appLocalization: AppLocalization, + constructor( + private _router: Router, + private _playlistRoute: ActivatedRoute, + private _kalturaServerClient: KalturaClient, + private _appLocalization: AppLocalization, private _browserService : BrowserService - ) { - this._mapSections(); + ) { + this._mapSections(); - this._onRouterEvents(); + this._onRouterEvents(); this._activeSection.next({section: this._playlistRoute.snapshot.firstChild.data.sectionKey}); - } + } public openSection(sectionId: PlaylistSections): void { const navigatePath = this._sectionToRouteMapping[sectionId]; @@ -82,57 +87,69 @@ export class PlaylistStore implements OnDestroy { }); } - private _onRouterEvents() : void { - this._router.events - .cancelOnDestroy(this) - .subscribe( - event => { - if (event instanceof NavigationEnd) { - const currentPlaylistId = this._playlistRoute.snapshot.params.id; - const playlist = this._playlist.getValue(); - if (!playlist.playlist || (playlist.playlist && playlist.playlist.id !== currentPlaylistId)) { - this._loadPlaylist(currentPlaylistId); - } else { + private _onRouterEvents() : void { + this._router.events + .cancelOnDestroy(this) + .subscribe( + event => { + if (event instanceof NavigationEnd) { + const currentPlaylistId = this._playlistRoute.snapshot.params.id; + const playlist = this._playlist.getValue(); + if (!playlist.playlist || (playlist.playlist && playlist.playlist.id !== currentPlaylistId)) { + this._loadPlaylist(currentPlaylistId); + } else { this._activeSection.next({section: this._playlistRoute.snapshot.firstChild.data.sectionKey}); } - } - } - ) - } - - private _loadPlaylist(id : string) : void { - if (this._loadPlaylistSubscription) { - this._loadPlaylistSubscription.unsubscribe(); - this._loadPlaylistSubscription = null; - } - - this._state.next({isBusy: true}); - - this._loadPlaylistSubscription = this._kalturaServerClient.request(new PlaylistGetAction({id})) - .cancelOnDestroy(this) - .subscribe( - response => { - if (response instanceof KalturaPlaylist) { - this._playlist.next({playlist: response}); - this._state.next({isBusy: false}); - } else { - this._state.next({ - isBusy: true, - error: { - message: this._appLocalization.get('applications.content.playlistDetails.errors.playlistTypeNotSupported'), - origin: 'reload' - } - }); - } - }, - error => { - this._state.next({ - isBusy: true, - error: {message: error.message, origin: 'reload'} - }); - } - ); - } + } + } + ) + } + + private _loadPlaylist(id : string) : void { + if (this._loadPlaylistSubscription) { + this._loadPlaylistSubscription.unsubscribe(); + this._loadPlaylistSubscription = null; + } + + this._state.next({isBusy: true}); + + this._loadPlaylistSubscription = this._kalturaServerClient.multiRequest( + new KalturaMultiRequest( + new PlaylistGetAction({id}), + new PlaylistExecuteAction({id}) + )) + .cancelOnDestroy(this) + .subscribe( + data => { + data.forEach(response => { + if (response.result instanceof KalturaPlaylist) { + this._playlist.next({playlist: response.result}); + this._state.next({isBusy: false}); + } else if(response.result.length >= 1 && response.result[0] instanceof KalturaBaseEntry) { + this._entries.next({ + items: response.result, + totalCount: response.result.length + }); + } else { + this._state.next({ + isBusy: true, + error: { + message: this._appLocalization.get('applications.content.playlistDetails.errors.playlistTypeNotSupported'), + origin: 'reload' + } + }); + } + }); + }, + error => { + this._state.next({ + isBusy: true, + error: {message: error.message, origin: 'reload'} + }); + } + ); + + } public updateSectionState(section: PlaylistSections, state : {isValid?: boolean, isDirty?: boolean}) : void { const sections = Object.assign({}, this._sectionsState.getValue()); @@ -177,11 +194,11 @@ export class PlaylistStore implements OnDestroy { }); } else { let id: string = this._getPlaylistId(), - playlist: KalturaPlaylist = new KalturaPlaylist({ - name: this._playlist.getValue().playlist.name, - description: this._playlist.getValue().playlist.description, - tags: this._playlist.getValue().playlist.tags - }); + playlist: KalturaPlaylist = new KalturaPlaylist({ + name: this._playlist.getValue().playlist.name, + description: this._playlist.getValue().playlist.description, + tags: this._playlist.getValue().playlist.tags + }); this._state.next({isBusy: true}); this._kalturaServerClient.request( @@ -315,9 +332,10 @@ export class PlaylistStore implements OnDestroy { }); } - ngOnDestroy() { - this._loadPlaylistSubscription && this._loadPlaylistSubscription.unsubscribe(); - this._state.complete(); - this._playlist.complete(); - } + ngOnDestroy() { + this._loadPlaylistSubscription && this._loadPlaylistSubscription.unsubscribe(); + this._state.complete(); + this._playlist.complete(); + } } + diff --git a/src/applications/content-playlists-app/playlist/playlist.component.scss b/src/applications/content-playlists-app/playlist/playlist.component.scss index 393fa90772..16c35ef9fb 100644 --- a/src/applications/content-playlists-app/playlist/playlist.component.scss +++ b/src/applications/content-playlists-app/playlist/playlist.component.scss @@ -93,7 +93,6 @@ border-top-right-radius: 3px; flex: 1 1 auto; margin-right: 28px; - padding: 8px; } .kPlaylistDetailsPreview { margin-left: auto; diff --git a/src/applications/content-playlists-app/playlists/bulk-service/bulk-delete.service.ts b/src/applications/content-playlists-app/playlists/bulk-service/bulk-delete.service.ts new file mode 100644 index 0000000000..0416dadd0f --- /dev/null +++ b/src/applications/content-playlists-app/playlists/bulk-service/bulk-delete.service.ts @@ -0,0 +1,79 @@ +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs/Observable'; +import { PlaylistsStore } from '../playlists-store/playlists-store.service'; +import { PlaylistDeleteAction } from 'kaltura-typescript-client/types/PlaylistDeleteAction'; +import { KalturaRequest, KalturaMultiRequest, KalturaMultiResponse } from 'kaltura-typescript-client'; +import { environment } from 'app-environment'; +import { KalturaClient } from '@kaltura-ng/kaltura-client'; +import { BehaviorSubject } from 'rxjs/BehaviorSubject'; + +@Injectable() +export class BulkDeleteService { + private _stateDelete = new BehaviorSubject<{loading : boolean}>({ loading : false}); + public stateDelete$ = this._stateDelete.asObservable(); + + constructor( + public _playlistsStore: PlaylistsStore, + public _kalturaServerClient: KalturaClient + ) {} + + public deletePlaylist(ids: string[]): Observable{ + return Observable.create(observer =>{ + this._stateDelete.next({loading: true}); + let requests: PlaylistDeleteAction[] = []; + if(ids && ids.length > 0) { + ids.forEach(id => requests.push(new PlaylistDeleteAction({ id: id }))); + + this._transmit(requests, true).subscribe( + () => { + this._stateDelete.next({loading: false}); + observer.next({}); + observer.complete(); + }, + error => { + this._stateDelete.next({loading: false}); + observer.error(error); + } + ); + } else { + this._stateDelete.next({loading: false}); + observer.next({}); + observer.complete(); + } + }); + } + + private _transmit(requests : KalturaRequest[], chunk : boolean) : Observable<{}> { + let maxRequestsPerMultiRequest = requests.length; + if (chunk){ + maxRequestsPerMultiRequest = environment.modules.contentPlaylists.bulkActionsLimit; + } + + let multiRequests: Observable[] = []; + let mr :KalturaMultiRequest = new KalturaMultiRequest(); + + let counter = 0; + for (let i = 0; i < requests.length; i++){ + if (counter === maxRequestsPerMultiRequest){ + multiRequests.push(this._kalturaServerClient.multiRequest(mr)); + mr = new KalturaMultiRequest(); + counter = 0; + } + mr.requests.push(requests[i]); + counter++; + } + + multiRequests.push(this._kalturaServerClient.multiRequest(mr)); + + return Observable.forkJoin(multiRequests) + .map(responses => { + const mergedResponses = [].concat.apply([], responses); + let hasFailure = mergedResponses.filter(function ( response ) {return response.error}).length > 0; + if (hasFailure) { + throw new Error("error"); + } else { + return {}; + } + }); + } +} diff --git a/src/applications/content-playlists-app/playlists/pipes/playlist-type.pipe.ts b/src/applications/content-playlists-app/playlists/pipes/playlist-type.pipe.ts index b89a7feea2..073abaeb24 100644 --- a/src/applications/content-playlists-app/playlists/pipes/playlist-type.pipe.ts +++ b/src/applications/content-playlists-app/playlists/pipes/playlist-type.pipe.ts @@ -28,7 +28,7 @@ export class PlaylistTypePipe implements PipeTransform { break; default: className = 'kIconUnknown'; - playlistType = this.appLocalization.get("applications.content.playlistType.unknown");; + playlistType = this.appLocalization.get("applications.content.playlistType.unknown"); break; } } diff --git a/src/applications/content-playlists-app/playlists/playlists-list.component.html b/src/applications/content-playlists-app/playlists/playlists-list.component.html index ba42180c8a..63edb790ac 100644 --- a/src/applications/content-playlists-app/playlists/playlists-list.component.html +++ b/src/applications/content-playlists-app/playlists/playlists-list.component.html @@ -1,68 +1,70 @@ -
-
-
- - - {{(_playlistsStore.playlists$ | async)?.totalCount}} {{'applications.content.playlists.playlists' | translate}} + +
+
+
+ + + {{(_playlistsStore.playlists$ | async)?.totalCount}} {{'applications.content.playlists.playlists' | translate}} -
- - • {{_selectedPlaylists.length}} {{'applications.content.playlists.selected' | translate}} - - {{'applications.content.playlists.cancel' | translate}} -
-
- -
-
- -
- - -
- {{item.label}} - -
-
-
- +
+ + • {{_selectedPlaylists.length}} {{'applications.content.playlists.selected' | translate}} + + {{'applications.content.playlists.cancel' | translate}} +
+
+ +
+
+ +
+ + +
+ {{item.label}} + +
+
+
+ -
- - {{'applications.content.paginator.showRows' | translate}} -
-
-
+
+ + {{'applications.content.paginator.showRows' | translate}} +
+
+
+ ({ busy : false, errorMessage : null}); - public state$ = this._state.asObservable(); public _blockerMessage: AreaBlockerMessage = null; - public _msgs: Message[] = []; + private _loading: boolean = false; _filter = { pageIndex : 0, @@ -55,8 +50,7 @@ export class PlaylistsListComponent implements OnInit, OnDestroy { sortDirection : SortDirection.Desc }; - public showLoader = true; - public _selectedPlaylists: any[] = []; + public _selectedPlaylists: KalturaPlaylist[] = []; private querySubscription : ISubscription; public activeFilters: Filter[] = []; @@ -64,7 +58,8 @@ export class PlaylistsListComponent implements OnInit, OnDestroy { public _playlistsStore: PlaylistsStore, private appLocalization: AppLocalization, private router: Router, - private _browserService : BrowserService + private _browserService : BrowserService, + public _bulkDeleteService : BulkDeleteService ) {} removeTag(tag: Filter){ @@ -107,30 +102,66 @@ export class PlaylistsListComponent implements OnInit, OnDestroy { message: ` ${this.appLocalization.get('applications.content.playlists.confirmDelete', {0:''})}
${this.appLocalization.get('applications.content.playlists.playlistId', { 0: event.playlistID })}
- ${this.appLocalization.get('applications.content.playlists.deleteNote', {0:''})}`, + ${this.appLocalization.get('applications.content.playlists.deleteNote', {0:'this', 1:''})}`, accept: () => { - this.deletePlaylist(event.playlistID); + this.deleteCurrentPlaylist(event.playlistID); } } ); break; default: - alert("Selected Action: " + event.action + "\nPlaylist ID: " + event.playlistID); break; } } - private deletePlaylist(playlistIds: any): void{ - this._state.next({busy: true, errorMessage: null}); - this._blockerMessage = null; - // Array.isArray(playlistIds)? playlistIds.map(id => id.id) : playlistIds - this._playlistsStore.deletePlaylist(playlistIds) + private deletePlaylist(ids: string[]): void { + const execute = () => { + this._bulkDeleteService.deletePlaylist(ids) + .cancelOnDestroy(this) + .subscribe( + () => { + this._loading = false; + this._playlistsStore.reload(true); + this.clearSelection(); + }, + error => { + this._blockerMessage = new AreaBlockerMessage({ + message: this.appLocalization.get('applications.content.bulkActions.errorPlaylists'), + buttons: [{ + label: this.appLocalization.get('app.common.ok'), + action: () => { + this._blockerMessage = null; + this._loading = false; + } + }] + }); + } + ); + }; + + if(ids.length > environment.modules.contentEntries.bulkActionsLimit) { + this._browserService.confirm( + { + header: this.appLocalization.get('applications.content.bulkActions.note'), + message: this.appLocalization.get('applications.content.bulkActions.confirmPlaylsts', {"0": ids.length}), + accept: () => { + execute(); + } + } + ); + } else{ + execute(); + } + } + + private deleteCurrentPlaylist(playlistId: string): void { + this._loading = true; + this._playlistsStore.deletePlaylist(playlistId) + .cancelOnDestroy(this) .subscribe( - result => { - this._state.next({busy: false, errorMessage: null}); - this._msgs = []; - this._msgs.push({severity: 'success', summary: '', detail: this.appLocalization.get('applications.content.playlists.deleted')}); - this.clearSelection(); + () => { + this._loading = false; + this._playlistsStore.reload(true); }, error => { this._blockerMessage = new AreaBlockerMessage( @@ -140,14 +171,14 @@ export class PlaylistsListComponent implements OnInit, OnDestroy { { label: this.appLocalization.get('app.common.retry'), action: () => { - this.deletePlaylist(playlistIds); + this.deleteCurrentPlaylist(playlistId); } }, { label: this.appLocalization.get('app.common.cancel'), action: () => { this._blockerMessage = null; - this._state.next({busy: false, errorMessage: null}); + this._loading = false; } } ] @@ -276,19 +307,20 @@ export class PlaylistsListComponent implements OnInit, OnDestroy { this._selectedPlaylists = []; } - deletePlaylists(selectedPlaylists) { - let playlistsToDelete = selectedPlaylists.map((playlist, index) => { - return `${index + 1}: ${playlist.name}`; - }); + deletePlaylists(selectedPlaylists: KalturaPlaylist[]) { + let playlistsToDelete = selectedPlaylists.map((playlist, index) => `${index + 1}: ${playlist.name}`), + playlists: string = selectedPlaylists.length <= 10 ? playlistsToDelete.join(',').replace(/,/gi, '
') + '
' : ''; this._browserService.confirm( { header: this.appLocalization.get('applications.content.playlists.deletePlaylist'), message: ` ${this.appLocalization.get('applications.content.playlists.confirmDelete', {0: selectedPlaylists.length > 1 ? 's': ''})}
- ${playlistsToDelete.join(',').replace(/,/gi, '
')}
- ${this.appLocalization.get('applications.content.playlists.deleteNote', {0: selectedPlaylists.length > 1 ? 's': ''})}`, + ${playlists} + ${this.appLocalization.get('applications.content.playlists.deleteNote', {0: selectedPlaylists.length > 1 ? 'these' : 'this', 1: selectedPlaylists.length > 1 ? 's': ''})}`, accept: () => { - // this.deletePlaylist(selectedPlaylists); + setTimeout(()=> { + this.deletePlaylist(selectedPlaylists.map(playlist => playlist.id)); + }, 0); } } ); diff --git a/src/applications/content-playlists-app/playlists/playlists-store/playlists-store.service.ts b/src/applications/content-playlists-app/playlists/playlists-store/playlists-store.service.ts index 6170d7b35c..a99029f327 100644 --- a/src/applications/content-playlists-app/playlists/playlists-store/playlists-store.service.ts +++ b/src/applications/content-playlists-app/playlists/playlists-store/playlists-store.service.ts @@ -13,15 +13,14 @@ import { KalturaPlaylistFilter } from 'kaltura-typescript-client/types/KalturaPl import { KalturaFilterPager } from 'kaltura-typescript-client/types/KalturaFilterPager'; import { KalturaDetachedResponseProfile } from 'kaltura-typescript-client/types/KalturaDetachedResponseProfile'; import { KalturaResponseProfileType } from 'kaltura-typescript-client/types/KalturaResponseProfileType'; +import { PlaylistDeleteAction } from 'kaltura-typescript-client/types/PlaylistDeleteAction'; import 'rxjs/add/operator/subscribeOn'; import 'rxjs/add/operator/map'; import 'rxjs/add/observable/throw'; import { KalturaPlaylist } from 'kaltura-typescript-client/types/KalturaPlaylist'; -import { BrowserService } from "app-shared/kmc-shell/providers/browser.service"; -import { BaseEntryDeleteAction } from 'kaltura-typescript-client/types/BaseEntryDeleteAction'; -import {PlaylistDeleteAction} from "kaltura-typescript-client/types/PlaylistDeleteAction"; +import { BrowserService } from 'app-shared/kmc-shell/providers/browser.service'; export enum SortDirection { Desc, @@ -42,8 +41,7 @@ export interface QueryData @Injectable() export class PlaylistsStore implements OnDestroy { - private _playlistsSource = new BehaviorSubject({items: [], totalCount: 0}); - private _playlists = new BehaviorSubject({items: [], totalCount: 0}); + private _playlistsSource = new BehaviorSubject<{items: KalturaPlaylist[], totalCount: number}>({items: [], totalCount: 0}); private _stateSource = new BehaviorSubject<{loading : boolean, errorMessage : string}>({ loading : false, errorMessage : null}); private _querySource = new BehaviorSubject({ pageIndex: 1, @@ -55,7 +53,6 @@ export class PlaylistsStore implements OnDestroy { createdAfter : null }); private requestSubscription : ISubscription = null; - private _destoryed: boolean = false; public playlists$ = this._playlistsSource.asObservable(); public state$ = this._stateSource.asObservable(); @@ -63,7 +60,8 @@ export class PlaylistsStore implements OnDestroy { constructor( private kalturaServerClient: KalturaClient, - private browserService: BrowserService + private browserService: BrowserService, + public _kalturaServerClient: KalturaClient ) { const defaultPageSize = this.browserService.getFromLocalStorage("playlists.list.pageSize"); if (defaultPageSize !== null) { @@ -97,7 +95,6 @@ export class PlaylistsStore implements OnDestroy { if(this.requestSubscription) { this.requestSubscription.unsubscribe(); } - this._destoryed = true; } public reload(force : boolean) : void; @@ -201,33 +198,24 @@ export class PlaylistsStore implements OnDestroy { } } - public deletePlaylist(playlistId: any): Observable{ - + public deletePlaylist(id: string) { return Observable.create(observer => { let subscription: ISubscription; - if (playlistId && playlistId.length) { - subscription = this.kalturaServerClient.request(new PlaylistDeleteAction({id: playlistId})).subscribe( - () => { - if (!this._destoryed) { - this.reload(true); - } - observer.next(); - observer.complete(); - }, - error =>{ - observer.error(error); - } - ); - } else { - observer.error(new Error('missing playlistId argument')); - } + subscription = this._kalturaServerClient.request(new PlaylistDeleteAction({id})).subscribe( + () => { + observer.next(); + observer.complete(); + }, + error =>{ + observer.error(error); + } + ); return ()=>{ if (subscription) { subscription.unsubscribe(); } } }); - } } diff --git a/src/environments/environment.ts b/src/environments/environment.ts index f3a2ad0c51..fa37de617b 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -112,7 +112,8 @@ export const environment = { "bulkActionsLimit": 50 }, "contentPlaylists" : { - "createdAtDateRange" : "2005:2030" + "createdAtDateRange" : "2005:2030", + "bulkActionsLimit": 2 } }, "entriesShared": { diff --git a/src/i18n/en.json b/src/i18n/en.json index 6c00d71e3c..a3ce72522a 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -79,7 +79,7 @@ "addPlaylist": "Add Playlist", "addEntry": "Add Entry", "refresh": "Refresh", - "deleteNote": "Please note: the playlist{{0}} will be permanently deleted from your account." + "deleteNote": "Please note: {{0}} playlist{{1}} will be permanently deleted from your account." }, "filters": { "activeFilters": "Active Filters:", @@ -202,9 +202,11 @@ "delete": "Delete", "apply": "Apply to all selected entries", "error": "An error occurred during entries update.", + "errorPlaylists": "An error occurred during playlists update.", "updated": "Entries updated successfully", "note": "Update Note", "confirm": "Are you sure you want to update {{0}} entries? It could take a while...", + "confirmPlaylsts": "Are you sure you want to update {{0}} playlists? It could take a while...", "deleteEntries": "Delete Entries", "deleteConfirm": "Are you sure you want to delete the selected entries?", "deleteNote": "Please note: the selected entries will be permanently deleted from your account."