File

src/app/modules/public/module/offline/components/content-manager/content-manager.component.ts

Implements

OnInit OnDestroy

Metadata

Index

Properties
Methods

Constructor

constructor(contentManagerService: ContentManagerService, resourceService: ResourceService, toasterService: ToasterService, electronDialogService: ElectronDialogService, configService: ConfigService, activatedRoute: ActivatedRoute, router: Router, telemetryService: TelemetryService, navigationHelperService: NavigationHelperService, userService: UserService)
Parameters :
Name Type Optional
contentManagerService ContentManagerService No
resourceService ResourceService No
toasterService ToasterService No
electronDialogService ElectronDialogService No
configService ConfigService No
activatedRoute ActivatedRoute No
router Router No
telemetryService TelemetryService No
navigationHelperService NavigationHelperService No
userService UserService No

Methods

cancelDownloadContent
cancelDownloadContent(id)
Parameters :
Name Optional
id No
Returns : void
cancelImportContent
cancelImportContent(id)
Parameters :
Name Optional
id No
Returns : void
closeModal
closeModal(event: any)
Parameters :
Name Type Optional
event any No
Returns : void
contentManagerActions
contentManagerActions(type: string, action: string, id: string)
Parameters :
Name Type Optional
type string No
action string No
id string No
Returns : void
deleteLocalContentStatus
deleteLocalContentStatus(id)
Parameters :
Name Optional
id No
Returns : void
getButtonsInteractData
getButtonsInteractData(id, percentage)
Parameters :
Name Optional
id No
percentage No
getContentList
getContentList()
Returns : void
getContentPercentage
getContentPercentage(progressSize, totalSize)
Parameters :
Name Optional
progressSize No
totalSize No
Returns : number
getContentStatus
getContentStatus(content)
Parameters :
Name Optional
content No
Returns : string
getList
getList()
Returns : void
Private getSubscription
getSubscription(id)
Parameters :
Name Optional
id No
Returns : { next(apiResponse: any): void; error(err: any): void; }
getTelemetryInteractData
getTelemetryInteractData()
Async handleInsufficientMemoryError
handleInsufficientMemoryError(allContentList)
Parameters :
Name Optional
allContentList No
Returns : any
logTelemetry
logTelemetry(response: any)
Parameters :
Name Type Optional
response any No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
openContent
openContent(data)
Parameters :
Name Optional
data No
Returns : void
pauseDownloadContent
pauseDownloadContent(id)
Parameters :
Name Optional
id No
Returns : void
pauseImportContent
pauseImportContent(id)
Parameters :
Name Optional
id No
Returns : void
removeFromHandledFailedList
removeFromHandledFailedList(id)
Parameters :
Name Optional
id No
Returns : void
resumeDownloadContent
resumeDownloadContent(id)
Parameters :
Name Optional
id No
Returns : void
resumeImportContent
resumeImportContent(id)
Parameters :
Name Optional
id No
Returns : void
retryDownloadContent
retryDownloadContent(id)
Parameters :
Name Optional
id No
Returns : void
retryImportContent
retryImportContent(id)
Parameters :
Name Optional
id No
Returns : void
updateLocalStatus
updateLocalStatus(contentData, currentStatus)
Parameters :
Name Optional
contentData No
currentStatus No
Returns : void

Properties

Public activatedRoute
Type : ActivatedRoute
apiCallSubject
Default value : new Subject()
apiCallTimer
Default value : timer(1000, 3000).pipe(filter(data => !data || (this.callContentList)))
callContentList
Default value : false
callContentListTimer
Default value : false
cancelId
Type : string
completedCount
Type : number
Public configService
Type : ConfigService
Public contentManagerService
Type : ContentManagerService
contentResponse
Type : any
Default value : []
contentStatusObject
Type : object
Default value : {}
deletedContents
Type : string[]
Default value : []
drives
Type : []
Public electronDialogService
Type : ElectronDialogService
handledFailedList
Type : []
Default value : []
isOpen
Default value : true
isWindows
Default value : false
localStatusArr
Type : []
Default value : ['inProgress', 'inQueue', 'resume', 'resuming', 'pausing', 'canceling']
Public navigationHelperService
Type : NavigationHelperService
Public resourceService
Type : ResourceService
Public router
Type : Router
subscription
Type : any
suggestedDrive
Type : string
Public toasterService
Type : ToasterService
unHandledFailedList
Type : []
Default value : []
Public unsubscribe$
Default value : new Subject<void>()
Public userService
Type : UserService
visibility
Default value : true
import { Component, OnInit, OnDestroy } from '@angular/core';
import { ResourceService, ToasterService, ConfigService, NavigationHelperService } from '@sunbird/shared';
import { timer, Subject, combineLatest } from 'rxjs';
import { switchMap, map, filter, takeUntil } from 'rxjs/operators';
import * as _ from 'lodash-es';
import { ContentManagerService, ElectronDialogService } from '../../services';
import { Router, ActivatedRoute } from '@angular/router';
import { ILogEventInput, TelemetryService } from '@sunbird/telemetry';
import { UserService } from '../../../../../core/services/user/user.service';

@Component({
  selector: 'app-content-manager',
  templateUrl: './content-manager.component.html',
  styleUrls: ['./content-manager.component.scss']
})
export class ContentManagerComponent implements OnInit, OnDestroy {

  contentResponse: any = [];
  isOpen = true;
  callContentList = false;
  callContentListTimer = false;
  contentStatusObject = {};
  subscription: any;
  public unsubscribe$ = new Subject<void>();
  localStatusArr = ['inProgress', 'inQueue', 'resume', 'resuming', 'pausing', 'canceling'];
  cancelId: string;
  apiCallTimer = timer(1000, 3000).pipe(filter(data => !data || (this.callContentList)));
  apiCallSubject = new Subject();
  completedCount: number;
  handledFailedList = [];
  unHandledFailedList = [];
  deletedContents: string [] = [];
  isWindows = false;
  suggestedDrive: string;
  drives: [];
  visibility = true;

  constructor(public contentManagerService: ContentManagerService,
    public resourceService: ResourceService, public toasterService: ToasterService,
    public electronDialogService: ElectronDialogService,
    public configService: ConfigService,
    public activatedRoute: ActivatedRoute,
    public router: Router,
    private telemetryService: TelemetryService,
    public navigationHelperService: NavigationHelperService,
    public userService: UserService
    ) {
    this.getList();
    document.addEventListener('content:import', (event) => {
      this.isOpen = true;
      this.apiCallSubject.next();
    });
  }

  ngOnInit() {
      // Subscribing to delete event to remove it from content manager list
      this.contentManagerService.deletedContent.pipe(takeUntil(this.unsubscribe$)).subscribe((deletedIds: string[]) => {
        this.isOpen = true;
        this.apiCallSubject.next();
      });
    // Call download list initially
    this.apiCallSubject.next();

    // Call content list when clicked on add to library
    this.contentManagerService.downloadEvent
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe(data => {
        this.isOpen = true;
        this.apiCallSubject.next();
      });

      this.contentManagerService.downloadFailEvent
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe(popupInfo => {
        this.unHandledFailedList.push({name: popupInfo.failedContentName});
        this.isWindows = popupInfo.isWindows;

        /* istanbul ignore else */
        if (popupInfo.isWindows && popupInfo.drives) {
          this.drives = popupInfo.drives;
        }
      });

    this.navigationHelperService.handleCMvisibility.
      pipe(takeUntil(this.unsubscribe$)).subscribe(hideCM => {
        this.visibility = !hideCM;
      });
  }

  getList() {
    // tslint:disable-next-line: deprecation
    combineLatest(this.apiCallTimer, this.apiCallSubject, (data1, data2) => true)
      .pipe(takeUntil(this.unsubscribe$), filter(() => this.isOpen), switchMap(() => this.contentManagerService.getContentList()),
        map((resp: any) => {
          this.callContentList = false;
          let completedCount = 0;
          _.forEach(_.get(resp, 'result.response.contents'), (value) => {
            const data = this.contentStatusObject[value.id];
            if (data) { value.status = data.currentStatus; }
            if (_.includes(this.localStatusArr, value.status)) {
              this.callContentList = true;
            }
            if (value.status === 'completed') {
              completedCount += 1;
            }
          });
          if ((completedCount > this.completedCount) && this.completedCount !== undefined) {
            this.contentManagerService.completeEvent.emit();
          }
          this.completedCount = completedCount;
          return _.get(resp, 'result.response.contents');
        })).subscribe((apiResponse: any) => {
          this.handleInsufficientMemoryError(apiResponse);
          this.contentResponse = _.filter(apiResponse, (o) => {
            if (o.status !== 'canceled' && o.addedUsing === 'download') {
              const statusMsg = this.getContentStatus(o.contentDownloadList);
              o.status = statusMsg ? statusMsg : o.status;
            }
            return o.status !== 'canceled';
          });
        });
  }

  getContentStatus(content) {
    const notCompleted = _.find(content, c => {
      return (!_.includes(['COMPLETE', 'EXTRACT'], c.step));
    });
    if (!notCompleted) {
      const extracting = _.find(content, c => {
        return c.step === 'EXTRACT';
      });
      if (extracting) { return 'extract'; }
    }
  }

  async handleInsufficientMemoryError(allContentList) {
    const noSpaceContentList = _.filter(allContentList, (content) =>
      content.failedCode === 'LOW_DISK_SPACE' && content.status === 'failed');

    if (noSpaceContentList.length) {
      const failedContent = _.differenceBy(noSpaceContentList, this.handledFailedList, 'id');

      if (failedContent[0]) {
        this.logTelemetry(failedContent[0]);
      }

      const popupInfo: any = {
        failedContentName: failedContent,
      };

      try {
        const response: any = await this.contentManagerService.getSuggestedDrive(popupInfo);
        this.unHandledFailedList = response.failedContentName;
        this.isWindows = response.isWindows;

        if (response.isWindows && response.drives) {
          this.drives = response.drives;
        }
      } catch (error) {
        this.unHandledFailedList = popupInfo.failedContentName;
      }
    }
  }

  removeFromHandledFailedList(id) {
    this.handledFailedList = _.filter(this.handledFailedList, (content) => content.id !== id);
  }

  closeModal(event: any) {
    this.handledFailedList.push(...this.unHandledFailedList);
    this.unHandledFailedList = [];
    this.isWindows = false;

    /* istanbul ignore else */
    if (event.selectedDrive) {
      const req = {
        request: {
          path: event.selectedDrive.name
        }
      };

      this.contentManagerService.changeContentLocation(req).subscribe(response => {
        this.toasterService.success(this.resourceService.messages.stmsg.contentLocationChanged);
      }, error => {
        this.toasterService.error(this.resourceService.messages.fmsg.m0097);
      });
    }
  }

  contentManagerActions(type: string, action: string, id: string) {
    // Unique download/import Id
    switch (`${action.toUpperCase()}_${type.toUpperCase()}`) {
      case 'PAUSE_IMPORT':
        this.pauseImportContent(id);
        break;
      case 'RESUME_IMPORT':
        this.resumeImportContent(id);
        break;
      case 'CANCEL_IMPORT':
        this.cancelImportContent(id);
        break;
      case 'RETRY_IMPORT':
        this.retryImportContent(id);
        break;
      case 'PAUSE_DOWNLOAD':
        this.pauseDownloadContent(id);
        break;
      case 'RESUME_DOWNLOAD':
        this.resumeDownloadContent(id);
        break;
      case 'CANCEL_DOWNLOAD':
        this.cancelDownloadContent(id);
        break;
      case 'RETRY_DOWNLOAD':
        this.retryDownloadContent(id);
        break;
    }
  }

  updateLocalStatus(contentData, currentStatus) {
    this.contentStatusObject[contentData.id] = {
      currentStatus: currentStatus,
      previousState: contentData.status
    };
    const data = _.find(this.contentResponse, { id: contentData.id });
    data.status = currentStatus;
  }

  private getSubscription(id) {
    const _this = this;
    return ({
      next(apiResponse: any) {
        _this.deleteLocalContentStatus(id);
        _this.apiCallSubject.next();
        _this.removeFromHandledFailedList(id);
      },
      error(err) {
        _this.deleteLocalContentStatus(id);
        _this.toasterService.error(_this.resourceService.messages.fmsg.m0097);
        _this.apiCallSubject.next();
        _this.removeFromHandledFailedList(id);
      }
    });
  }

  pauseDownloadContent(id) {
    this.contentManagerService.pauseDownloadContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  resumeDownloadContent(id) {
    this.contentManagerService.resumeDownloadContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  cancelDownloadContent(id) {
    this.contentManagerService.cancelDownloadContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  retryDownloadContent(id) {
    this.contentManagerService.retryDownloadContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  pauseImportContent(id) {
    this.contentManagerService.pauseImportContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  resumeImportContent(id) {
    this.contentManagerService.resumeImportContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  cancelImportContent(id) {
    this.contentManagerService.cancelImportContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  retryImportContent(id) {
    this.contentManagerService.retryImportContent(id).pipe(takeUntil(this.unsubscribe$)).subscribe(this.getSubscription(id));
  }

  deleteLocalContentStatus(id) {
    delete this.contentStatusObject[id];
  }

  getContentPercentage(progressSize, totalSize) {
    return (progressSize / totalSize) * 100;
  }

  openContent(data) {
    const { contentId, mimeType, status } = data;
    if (status === 'completed') {
      let path;
      if (mimeType === this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.collection) {
        if (typeof _.get(data, 'trackable') === 'string') {
          try {
            data.trackable = JSON.parse(data.trackable);
          } catch (error) {
            console.error('Error while json parse', error);
          }
        }

        if (_.toUpper(_.get(data, 'contentType')) === 'COURSE' || _.toUpper(_.get(data, 'trackable.enabled')) === 'YES') {
          path = this.userService.loggedIn ? 'learn/course' : 'explore-course/course';
        } else {
          path = 'play/collection';
        }
      } else if(mimeType === this.configService.appConfig.PLAYER_CONFIG.MIME_TYPE.questionset) {
        path = 'resources/play/questionset';
      } else {
        path = 'play/content';
      }

      this.router.navigate([path, contentId]);
    }
  }

  getTelemetryInteractData() {
    const pageId = _.get(this.activatedRoute, 'snapshot.root.firstChild.data.telemetry.env') ||
      _.get(this.activatedRoute, 'snapshot.data.telemetry.env') ||
      _.get(this.activatedRoute.snapshot.firstChild, 'children[0].data.telemetry.env');
    return {
      id: this.isOpen ? 'content-manager-close' : 'content-manager-open',
      type: 'click',
      pageid: pageId
    };
  }

  getButtonsInteractData(id, percentage) {
    const pageId = _.get(this.activatedRoute, 'snapshot.root.firstChild.data.telemetry.env') ||
      _.get(this.activatedRoute, 'snapshot.data.telemetry.env') ||
      _.get(this.activatedRoute.snapshot.firstChild, 'children[0].data.telemetry.env');
    const interactData = {
      id: id,
      type: 'click',
      pageid: pageId
    };

    if (percentage) {
      interactData['extra'] = {
        percentage: percentage
      };
    }
    return interactData;
  }

  getContentList() {
    if (this.isOpen) {
      this.apiCallSubject.next();
    }
  }

  logTelemetry(response: any) {
    const input: ILogEventInput = {
      context: {
        env: _.get(this.activatedRoute, 'snapshot.root.firstChild.data.telemetry.env') ||
        _.get(this.activatedRoute, 'snapshot.data.telemetry.env') ||
        _.get(this.activatedRoute.snapshot.firstChild, 'children[0].data.telemetry.env')
      },
      object: {
        id: response.id,
        type: response.contentType || 'content',
        ver: `${response.pkgVersion || ''}`
      },
      edata: {
        type: 'api_call',
        level: 'WARN',
        message: response.failedReason
      }
    };

    this.telemetryService.log(input);
  }

  ngOnDestroy() {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }
}
<mat-accordion class="sb-mat-accordion sb-desktop-content-manager"
  [ngClass]="{'sb-single-pannel-accordion-fixed': isOpen === true, 'hide': visibility === false}"
  *ngIf="contentResponse?.length"> 
  <mat-expansion-panel [expanded]="isOpen" (click)="getContentList()">
    <mat-expansion-panel-header>
      <mat-panel-title class="sb-mat-accordion__title" appTelemetryInteract [telemetryInteractEdata]="getTelemetryInteractData()">
        {{resourceService?.frmelmnts?.lbl?.contentManager}}
      </mat-panel-title>
    </mat-expansion-panel-header>
    <div *ngIf="contentResponse" class="sb-mat-accordion__content">
      <div class="sb-single-pannel-accordion-list-item flex-ai-center text-left"
        *ngFor="let data of contentResponse">
        <i class="check circle icon success-icon mr-8 fs-1-429" *ngIf="data.status === 'completed'"></i>
        <div class="download-details-container" [ngClass]="{'cursor-pointer': data.status === 'completed'}" tabindex="0"
          (click)="openContent(data)">
          <div class="d-flex flex-ai-center flex-w-wrap">
            <div class="download-text mr-auto">{{data.name}}</div>

            <!-- Buttons -->
            <button *ngIf="cancelId !== data.id && (data.status === 'pausing' || data.status === 'inProgress')"
              type="button" class="sb-btn sb-btn-xs sb-btn-outline-primary ml-8" tabindex="0"
              (click)="contentManagerActions(data.addedUsing, 'Pause', data.id); updateLocalStatus(data, 'pausing');"
              [disabled]="data.status === 'pausing'" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('pause', data.downloadedSize)"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.pause}}
            </button>

            <button
              *ngIf="cancelId !== data.id && (data.status === 'paused' || data.status === 'resume' || data.status === 'resuming')"
              type="button" class="sb-btn sb-btn-xs sb-btn-outline-primary ml-8" tabindex="0"
              (click)="contentManagerActions(data.addedUsing, 'Resume', data.id); updateLocalStatus(data, 'resuming');"
              [disabled]="data.status === 'resuming'  || data.status === 'resume'" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('resume', data.downloadedSize)"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.resume}}
            </button>

            <button
              *ngIf="(data.status === 'inProgress' || data.status === 'inQueue' || data.status === 'paused') && cancelId !== data.id"
              type="button" class="sb-btn sb-btn-xs sb-btn-outline-error ml-8" tabindex="0"
              (click)="cancelId = data.id;" [disabled]="data.status === 'canceling'" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('cancel', data.downloadedSize)"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.cancel}}
            </button>

            <button *ngIf="data.status === 'failed' || data.status === 'retrying'" type="button"
              class="sb-btn sb-btn-xs sb-btn-outline-warning ml-8" tabindex="0"
              (click)="contentManagerActions(data.addedUsing, 'Retry', data.id); updateLocalStatus(data, 'retrying');"
              [disabled]="data.status === 'retrying'" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('retry', data.downloadedSize)"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.retry}}
            </button>

            <!-- Buttons -->
          </div>

          <!-- File details -->
          <div class="info-text" *ngIf="data.totalSize && data.status !== 'inProgress'">{{data.totalSize | filesize}}
          </div>

          <div *ngIf="data.addedUsing === 'download' && data.status === 'inProgress'" class="info-text">
            {{resourceService?.frmelmnts?.lbl?.downloading}}&nbsp;{{data.totalSize | filesize}}</div>

          <div *ngIf="data.addedUsing === 'import' && data.status === 'inProgress'" class="info-text">
            {{resourceService?.frmelmnts?.lbl?.uploading}}</div>
          <!-- File details -->

          <!-- Progress bar -->
          <mat-progress-bar *ngIf="data.status === 'inProgress' && data.addedUsing === 'download'" mode="determinate" [value]="getContentPercentage(data.downloadedSize, data.totalSize)" class="my-0 mr-0"></mat-progress-bar>
          
          <mat-progress-bar *ngIf="data.status === 'inProgress' && data.addedUsing === 'import'" mode="determinate" [value]="data.downloadedSize" class="my-0 mr-0"></mat-progress-bar>

          <!-- Progress bar -->

          <!-- Content status -->
          <div *ngIf="data.status === 'paused' && data.addedUsing === 'import'" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.lbl?.uploadPaused}} </div>

          <div *ngIf="data.status === 'retrying' && data.addedUsing === 'download'" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.btn?.resuming}} </div>

          <div *ngIf="data.status === 'paused' && data.addedUsing === 'download'" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.lbl?.downloadPaused}} </div>

          <div *ngIf="(data.status === 'resuming' || data.status === 'resume')" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.btn?.resuming}} </div>

          <div *ngIf="data.status === 'pausing'" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.btn?.pausing}} </div>

          <div *ngIf="data.status === 'canceling'" class="fs-0-785 sb-color-primary">
            {{resourceService?.frmelmnts?.btn?.canceling}} </div>
          <div *ngIf="data.status === 'completed'" class="fs-0-785 sb-color-success">
            {{resourceService?.frmelmnts?.btn?.completed}} </div>
          <div *ngIf="data.status === 'extract'" class="fs-0-785 sb-color-success">
            {{resourceService?.frmelmnts?.desktop?.lbl?.completing}} </div>
          <div *ngIf="data.addedUsing === 'download' && data.status === 'failed'" class="fs-0-785 sb-color-error">
            {{resourceService?.frmelmnts?.lbl?.downloadFailed}} </div>

          <div *ngIf="data.addedUsing === 'import' && data.status === 'failed'" class="fs-0-785 sb-color-error">
            {{resourceService?.frmelmnts?.lbl?.uploadFailed}} </div>

          <div *ngIf="data.addedUsing === 'import' && data.status === 'inQueue'" class="fs-0-785 sb-color-warning">
            {{resourceService?.frmelmnts?.lbl?.waitingForUpload}} </div>

          <div *ngIf="data.addedUsing === 'download' && data.status === 'inQueue'" class="fs-0-785 sb-color-warning">
            {{resourceService?.frmelmnts?.lbl?.waitingForDownload}} </div>
          <!-- Content status -->

          <!-- Cancel confirmation message -->
          <div class="d-flex flex-ai-center mt-8 ml-0"
            *ngIf="cancelId === data.id && (data.status !== 'completed' && data.status !== 'failed')">
            <div *ngIf="data.addedUsing === 'import'" class="fs-1 font-weight-bold sb-color-error mr-auto">
              {{resourceService?.frmelmnts?.lbl?.cancelUpload}}
            </div>
            <div *ngIf="data.addedUsing === 'download'" class="fs-1 font-weight-bold sb-color-error mr-auto">
              {{resourceService?.frmelmnts?.lbl?.cancelDownload}}
            </div>
            <button tabindex="0"
              (click)="contentManagerActions(data.addedUsing, 'Cancel', data.id); updateLocalStatus(data, 'canceling'); cancelId = '';"
              class="sb-btn sb-btn-xs sb-btn-outline-primary ml-8" type="button" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('confirm-cancel', getContentPercentage(data.downloadedSize, data.totalSize))"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.yes}} </button>
            <button tabindex="0" (click)="cancelId = '';" class="sb-btn sb-btn-xs sb-btn-outline-error ml-8"
              type="button" appTelemetryInteract
              [telemetryInteractEdata]="getButtonsInteractData('deny-cancel', getContentPercentage(data.downloadedSize, data.totalSize))"
              [telemetryInteractCdata]="[{ 'type': data.addedUsing, 'id': data.id }]"
              [telemetryInteractObject]="{id:data.contentId, type: 'Content', ver:data.pkgVersion ? data.pkgVersion : ''}">
              {{resourceService?.frmelmnts?.btn?.no}} </button>
          </div>
          <!-- Cancel confirmation message -->
        </div>
      </div>
    </div>
  </mat-expansion-panel>
</mat-accordion>



<app-content-manager-info-pop-up *ngIf="unHandledFailedList?.length" [showContentChangeWarning]="isWindows"
  [failedList]="unHandledFailedList" [drives]="drives" (dismissed)="closeModal($event)">
</app-content-manager-info-pop-up>

./content-manager.component.scss

@use "@project-sunbird/sb-styles/assets/mixins/mixins" as *;
.sb-desktop-content-manager {
    z-index: 999;
    position: fixed;
    bottom: 0px;
    right: 2rem;
    width: 100%;
    max-width: 30rem;
    left: auto;
  }
  
  .mat-accordion>.mat-expansion-panel-spacing:last-child,
  .mat-accordion>*:last-child:not(.mat-expansion-panel) .mat-expansion-panel-spacing {
    box-shadow: var(--sbt-box-shadow-6px);
  }
  
  .sb-desktop-content-manager.sb-mat-accordion .mat-expansion-panel .mat-expansion-panel-header {
    background: var(--primary-color);
    border-radius: 0;
    height:3rem !important;
    &:hover {
      background: var(--primary-color);
    }
  }
  
  
  .sb-desktop-content-manager.sb-mat-accordion .mat-expansion-panel {
    border-radius: var(--sbt-bradius-24) var(--sbt-bradius-24) 0 0 !important;
  }
  
  .sb-desktop-content-manager.sb-mat-accordion .mat-expansion-panel-header-title,
  .sb-desktop-content-manager.sb-mat-accordion .mat-expansion-indicator::after,
  .mat-expansion-indicator::after {
    color: var(--white);
  }
  
  .sb-desktop-content-manager.sb-mat-accordion .sb-single-pannel-accordion-list-item:last-child {
    border-bottom: 0rem solid var(--gray-100);
  }
  
  :host ::ng-deep {
      .sb-desktop-content-manager{
      .mat-expansion-indicator::after {
          color: var(--white);
        }
        .mat-expansion-panel-body {
          padding: 0 0px 0px;
      }
      .sb-mat-accordion__content {
        max-height: calc(100vh - 30vh);
        overflow-y: auto;
      }
  }
  }
Legend
Html element
Component
Html element with directive

results matching ""

    No results matching ""