diff --git a/apps/red-ui/src/app/common/service/permissions.service.ts b/apps/red-ui/src/app/common/service/permissions.service.ts index 4e59f3634..7fa07806c 100644 --- a/apps/red-ui/src/app/common/service/permissions.service.ts +++ b/apps/red-ui/src/app/common/service/permissions.service.ts @@ -194,7 +194,8 @@ export class PermissionsService { if (!fileStatus) { fileStatus = this._appStateService.activeFile; } - return fileStatus.status === 'APPROVED' && this.isManagerAndOwner(); + const project = this._appStateService.getProjectById(fileStatus.projectId); + return fileStatus.status === 'APPROVED' && this.isManagerAndOwner(project); } canDeleteProject(project?: ProjectWrapper) { diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html index 4a3c4cbea..42e3a3a62 100644 --- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.html @@ -152,12 +152,18 @@ icon="red:refresh" > + +
- - diff --git a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts index 283736669..6a6625700 100644 --- a/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts +++ b/apps/red-ui/src/app/screens/project-listing-screen/project-listing-screen.component.ts @@ -1,9 +1,9 @@ import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; -import { Project } from '@redaction/red-ui-http'; +import { FileManagementControllerService, Project } from '@redaction/red-ui-http'; import { AppStateService } from '../../state/app-state.service'; import { UserService } from '../../user/user.service'; import { DoughnutChartConfig } from '../../components/simple-doughnut-chart/simple-doughnut-chart.component'; -import { groupBy, humanize } from '../../utils/functions'; +import { computerize, groupBy, humanize } from '../../utils/functions'; import { DialogService } from '../../dialogs/dialog.service'; import { FilterModel } from '../../common/filter/model/filter.model'; import { @@ -25,6 +25,7 @@ import { StatusSorter } from '../../common/sorters/status-sorter'; import { Router } from '@angular/router'; import { FormBuilder, FormGroup } from '@angular/forms'; import { debounce } from '../../utils/debounce'; +import { download } from '../../utils/file-download-utils'; @Component({ selector: 'redaction-project-listing-screen', @@ -60,7 +61,8 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { private readonly _router: Router, public readonly sortingService: SortingService, public readonly translateChartService: TranslateChartService, - private readonly _formBuilder: FormBuilder + private readonly _formBuilder: FormBuilder, + private readonly _fileManagementControllerService: FileManagementControllerService ) { this.searchForm = this._formBuilder.group({ query: [''] @@ -257,7 +259,12 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { const filters = [ { values: this.statusFilters, checker: projectStatusChecker }, { values: this.peopleFilters, checker: projectMemberChecker }, - { values: this.needsWorkFilters, checker: annotationFilterChecker, matchAll: true, checkerArgs: this.permissionsService } + { + values: this.needsWorkFilters, + checker: annotationFilterChecker, + matchAll: true, + checkerArgs: this.permissionsService + } ]; return getFilteredEntities(this.appStateService.allProjects, filters); } @@ -282,4 +289,18 @@ export class ProjectListingScreenComponent implements OnInit, OnDestroy { this._calculateData(); }); } + + // Download Files + public downloadRedactedFiles($event: MouseEvent, project: ProjectWrapper) { + $event.stopPropagation(); + this._fileManagementControllerService + .downloadRedactedFiles({ fileIds: project.files.map((file) => file.fileId) }, project.projectId, false, 'response') + .subscribe((data) => { + download(data, 'redacted_files_' + computerize(project.name) + '.zip'); + }); + } + + public canDownloadRedactedFiles(project: ProjectWrapper) { + return project.files.reduce((acc, file) => acc && this.permissionsService.canDownloadRedactedFile(file), true); + } } diff --git a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html index 48fc4f4cc..0a353e0d5 100644 --- a/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html +++ b/apps/red-ui/src/app/screens/project-overview-screen/project-overview-screen.component.html @@ -69,6 +69,15 @@ tooltipPosition="below" icon="red:refresh" > + + + file.fileId) }, + this.appStateService.activeProjectId, + false, + 'response' + ) + .subscribe((data) => { + download(data, 'redacted_files_' + computerize(this.appStateService.activeProject.name) + '.zip'); + }); + } + + public get canDownloadRedactedFiles() { + return this.appStateService.activeProject.files.reduce((acc, file) => acc && this.permissionsService.canDownloadRedactedFile(file), true); + } } diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 3304587a5..5cc05496c 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -77,6 +77,9 @@ "assign": { "action": "Assign Owner & Members" }, + "download-files": { + "action": "Download Redacted Files" + }, "table-header": { "title": "{{length}} active projects", "bulk-select": "Toggle Selection", @@ -155,7 +158,8 @@ "edit": "Edit", "delete": "Delete", "assign": "Assign Owner & Members", - "upload-document": "Upload Document" + "upload-document": "Upload Document", + "download-redacted-files": "Download Redacted Files" }, "download-redacted-file": "Download Redacted File", "download-redacted-files": "Download Redacted Files",