Made File export menus dynamic and based on the available file transformers (no POM)

This commit is contained in:
George Kalampokis 2023-12-19 18:09:09 +02:00
parent 3e97d0fdd1
commit 8f6d0cc33d
31 changed files with 215 additions and 151 deletions

View File

@ -1,22 +1,24 @@
package eu.eudat.model.file; package eu.eudat.model.file;
import eu.eudat.file.transformer.model.file.FileFormat;
import java.util.List; import java.util.List;
public class TransformerCacheModel { public class TransformerCacheModel {
private List<String> formats; private List<FileFormat> formats;
public TransformerCacheModel() { public TransformerCacheModel() {
} }
public TransformerCacheModel(List<String> formats) { public TransformerCacheModel(List<FileFormat> formats) {
this.formats = formats; this.formats = formats;
} }
public List<String> getFormats() { public List<FileFormat> getFormats() {
return formats; return formats;
} }
public void setFormats(List<String> formats) { public void setFormats(List<FileFormat> formats) {
this.formats = formats; this.formats = formats;
} }
} }

View File

@ -5,6 +5,7 @@ import eu.eudat.file.transformer.model.DescriptionFileTransformerModel;
import eu.eudat.file.transformer.model.DmpFileTransformerModel; import eu.eudat.file.transformer.model.DmpFileTransformerModel;
import eu.eudat.file.transformer.model.ExtraPropertiesModel; import eu.eudat.file.transformer.model.ExtraPropertiesModel;
import eu.eudat.file.transformer.model.file.FileEnvelope; import eu.eudat.file.transformer.model.file.FileEnvelope;
import eu.eudat.file.transformer.model.file.FileFormat;
import eu.eudat.utilities.webclient.WebClientUtils; import eu.eudat.utilities.webclient.WebClientUtils;
import org.springframework.core.ParameterizedTypeReference; import org.springframework.core.ParameterizedTypeReference;
import org.springframework.web.reactive.function.client.WebClient; import org.springframework.web.reactive.function.client.WebClient;
@ -43,8 +44,8 @@ public class TransformerRepository implements FileTransformerExecutor {
} }
@Override @Override
public List<String> getSupportedFileFormats() { public List<FileFormat> getSupportedFileFormats() {
return transformerClient.get().uri("/formats").exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<List<String>>() {})).block(); return transformerClient.get().uri("/formats").exchangeToMono(mono -> mono.bodyToMono(new ParameterizedTypeReference<List<FileFormat>>() {})).block();
} }

View File

@ -24,7 +24,7 @@ public interface DescriptionService {
void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException; void clone(UUID dmpId, UUID descriptionId) throws InvalidApplicationException;
ResponseEntity<byte[]> export(UUID id, DescriptionServiceImpl.DescriptionExportType exportType) throws InvalidApplicationException, IOException; ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException;
} }

View File

@ -582,32 +582,16 @@ public class DescriptionServiceImpl implements DescriptionService {
//region file export //region file export
public enum DescriptionExportType {
Word, Pdf, Xml;
}
@Override @Override
public ResponseEntity<byte[]> export(UUID id, DescriptionExportType exportType) throws InvalidApplicationException, IOException { public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
String type = switch(exportType) { String type = exportType;
case Word -> "docx";
case Pdf -> "pdf";
case Xml -> "xml";
};
FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, type); FileEnvelope fileEnvelope = this.fileTransformerService.exportDescription(id, type);
headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename());
byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath());
switch (exportType){ headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
case Xml -> { return new ResponseEntity<>(data, headers, HttpStatus.OK);
headers.setContentType(MediaType.APPLICATION_XML);
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
case Word, Pdf -> {
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
}
return ResponseEntity.badRequest().body(new byte[]{});
} }
//endregion //endregion

View File

@ -23,10 +23,6 @@ import java.util.UUID;
public interface DmpService { public interface DmpService {
enum DmpExportType {
Word, Pdf, Json, Xml;
}
Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException; Dmp persist(DmpPersist model, FieldSet fields) throws MyForbiddenException, MyValidationException, MyApplicationException, MyNotFoundException, InvalidApplicationException, JsonProcessingException;
void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException; void deleteAndSave(UUID id) throws MyForbiddenException, InvalidApplicationException, IOException;
@ -38,7 +34,7 @@ public interface DmpService {
List<DmpUser> assignUsers(UUID dmp, List<DmpUserPersist> model, FieldSet fields) throws InvalidApplicationException; List<DmpUser> assignUsers(UUID dmp, List<DmpUserPersist> model, FieldSet fields) throws InvalidApplicationException;
Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException; Dmp removeUser(DmpUserRemovePersist model, FieldSet fields) throws InvalidApplicationException;
ResponseEntity<byte[]> export(UUID id, DmpExportType exportType) throws InvalidApplicationException, IOException; ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException;
void inviteUsers(UUID id, DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException; void inviteUsers(UUID id, DmpUserInvitePersist model) throws InvalidApplicationException, JAXBException;

View File

@ -456,33 +456,15 @@ public class DmpServiceImpl implements DmpService {
} }
@Override @Override
public ResponseEntity<byte[]> export(UUID id, DmpExportType exportType) throws InvalidApplicationException, IOException { public ResponseEntity<byte[]> export(UUID id, String exportType) throws InvalidApplicationException, IOException {
HttpHeaders headers = new HttpHeaders(); HttpHeaders headers = new HttpHeaders();
String type = switch(exportType) { String type = exportType;
case Word -> "docx";
case Pdf -> "pdf";
case Json -> "json";
case Xml -> "xml";
};
FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, type); FileEnvelope fileEnvelope = this.fileTransformerService.exportDmp(id, type);
headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename()); headers.add("Content-Disposition", "attachment;filename=" + fileEnvelope.getFilename());
byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath()); byte[] data = Files.readAllBytes(fileEnvelope.getFile().toPath());
switch (exportType){ headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
case Xml -> { return new ResponseEntity<>(data, headers, HttpStatus.OK);
headers.setContentType(MediaType.APPLICATION_XML);
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
case Json -> {
headers.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
case Word, Pdf -> {
headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
return new ResponseEntity<>(data, headers, HttpStatus.OK);
}
}
return ResponseEntity.badRequest().body(new byte[]{});
} }
private DmpEntity patchAndSave(DmpPersist model) throws JsonProcessingException, InvalidApplicationException { private DmpEntity patchAndSave(DmpPersist model) throws JsonProcessingException, InvalidApplicationException {

View File

@ -12,6 +12,7 @@ import eu.eudat.file.transformer.model.DmpFileTransformerModel;
import eu.eudat.file.transformer.model.ExtraPropertiesModel; import eu.eudat.file.transformer.model.ExtraPropertiesModel;
import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Field; import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Field;
import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Rule; import eu.eudat.file.transformer.model.descriptiontemplatedefinition.Rule;
import eu.eudat.file.transformer.model.file.FileFormat;
import eu.eudat.model.*; import eu.eudat.model.*;
import eu.eudat.model.builder.DescriptionBuilder; import eu.eudat.model.builder.DescriptionBuilder;
import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpBuilder;
@ -116,15 +117,15 @@ public class FileTransformerService {
} }
public List<String> getAvailableConfigurations() { public List<FileFormat> getAvailableConfigurations() {
TransformerCacheModel configs = fileTransformerConfigurationCache.lookup("base"); TransformerCacheModel configs = fileTransformerConfigurationCache.lookup("base");
if (configs == null) { if (configs == null) {
List<String> configurations = new ArrayList<>(); List<FileFormat> configurations = new ArrayList<>();
//GK: So much for lazy loading //GK: So much for lazy loading
List<TransformerRepository> repositories = transformerProperties.getSources().stream().map(depositSource -> getRepository(depositSource.getCodes().get(0))).toList(); List<TransformerRepository> repositories = transformerProperties.getSources().stream().map(depositSource -> getRepository(depositSource.getCodes().get(0))).toList();
repositories.forEach((client) -> { repositories.forEach((client) -> {
List<String> repositoryConfigs = client.getSupportedFileFormats(); List<FileFormat> repositoryConfigs = client.getSupportedFileFormats();
if (repositoryConfigs != null && !repositoryConfigs.isEmpty()) { if (repositoryConfigs != null && !repositoryConfigs.isEmpty()) {
configurations.addAll(repositoryConfigs); configurations.addAll(repositoryConfigs);
} }

View File

@ -6,6 +6,7 @@ import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.commons.enums.DmpAccessType; import eu.eudat.commons.enums.DmpAccessType;
import eu.eudat.commons.enums.DmpStatus; import eu.eudat.commons.enums.DmpStatus;
import eu.eudat.commons.enums.IsActive; import eu.eudat.commons.enums.IsActive;
import eu.eudat.file.transformer.model.file.FileFormat;
import eu.eudat.model.Description; import eu.eudat.model.Description;
import eu.eudat.model.Dmp; import eu.eudat.model.Dmp;
import eu.eudat.model.PublicDescription; import eu.eudat.model.PublicDescription;
@ -22,6 +23,7 @@ import eu.eudat.service.description.DescriptionService;
import eu.eudat.service.description.DescriptionServiceImpl; import eu.eudat.service.description.DescriptionServiceImpl;
import eu.eudat.service.dmp.DmpService; import eu.eudat.service.dmp.DmpService;
import eu.eudat.service.elastic.ElasticQueryHelperService; import eu.eudat.service.elastic.ElasticQueryHelperService;
import eu.eudat.service.transformer.FileTransformerService;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
import gr.cite.tools.data.censor.CensorFactory; import gr.cite.tools.data.censor.CensorFactory;
@ -64,14 +66,15 @@ public class DescriptionController {
private final MessageSource messageSource; private final MessageSource messageSource;
private final ElasticQueryHelperService elasticQueryHelperService; private final ElasticQueryHelperService elasticQueryHelperService;
private final FileTransformerService fileTransformerService;
public DescriptionController( public DescriptionController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
DescriptionService descriptionService, DescriptionService descriptionService,
CensorFactory censorFactory, CensorFactory censorFactory,
QueryFactory queryFactory, QueryFactory queryFactory,
MessageSource messageSource, MessageSource messageSource,
ElasticQueryHelperService elasticQueryHelperService) { ElasticQueryHelperService elasticQueryHelperService, FileTransformerService fileTransformerService) {
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.auditService = auditService; this.auditService = auditService;
this.descriptionService = descriptionService; this.descriptionService = descriptionService;
@ -79,6 +82,7 @@ public class DescriptionController {
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
this.elasticQueryHelperService = elasticQueryHelperService; this.elasticQueryHelperService = elasticQueryHelperService;
this.fileTransformerService = fileTransformerService;
} }
@PostMapping("public/query") @PostMapping("public/query")
@ -189,7 +193,12 @@ public class DescriptionController {
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException { public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException {
logger.debug(new MapLogEntry("exporting description")); logger.debug(new MapLogEntry("exporting description"));
return this.descriptionService.export(id, DescriptionServiceImpl.DescriptionExportType.valueOf(exportType)); return this.descriptionService.export(id, exportType);
}
@GetMapping("/export/formats")
public List<FileFormat> getAvailableExportFormats() {
return this.fileTransformerService.getAvailableConfigurations();
} }
} }

View File

@ -4,6 +4,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import eu.eudat.audit.AuditableAction; import eu.eudat.audit.AuditableAction;
import eu.eudat.authorization.AuthorizationFlags; import eu.eudat.authorization.AuthorizationFlags;
import eu.eudat.data.DmpEntity; import eu.eudat.data.DmpEntity;
import eu.eudat.file.transformer.model.file.FileFormat;
import eu.eudat.model.Dmp; import eu.eudat.model.Dmp;
import eu.eudat.model.DmpUser; import eu.eudat.model.DmpUser;
import eu.eudat.model.builder.DmpBuilder; import eu.eudat.model.builder.DmpBuilder;
@ -62,19 +63,22 @@ public class DmpController {
private final MessageSource messageSource; private final MessageSource messageSource;
private final FileTransformerService fileTransformerService;
public DmpController( public DmpController(
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
DmpService dmpService, DmpService dmpService,
CensorFactory censorFactory, CensorFactory censorFactory,
QueryFactory queryFactory, QueryFactory queryFactory,
MessageSource messageSource) { MessageSource messageSource, FileTransformerService fileTransformerService) {
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.auditService = auditService; this.auditService = auditService;
this.dmpService = dmpService; this.dmpService = dmpService;
this.censorFactory = censorFactory; this.censorFactory = censorFactory;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;
this.fileTransformerService = fileTransformerService;
} }
@PostMapping("query") @PostMapping("query")
@ -203,7 +207,12 @@ public class DmpController {
public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException { public ResponseEntity<byte[]> export(@PathVariable("id") UUID id, @PathVariable("type") String exportType) throws InvalidApplicationException, IOException {
logger.debug(new MapLogEntry("exporting dmp")); logger.debug(new MapLogEntry("exporting dmp"));
return this.dmpService.export(id, DmpService.DmpExportType.valueOf(exportType)); return this.dmpService.export(id, exportType);
}
@GetMapping("/export/formats")
public List<FileFormat> getAvailableExportFormats() {
return this.fileTransformerService.getAvailableConfigurations();
} }
@PostMapping("{id}/invite-users") @PostMapping("{id}/invite-users")

View File

@ -11,6 +11,7 @@ import eu.eudat.model.persist.EntityDoiPersist;
import eu.eudat.model.result.QueryResult; import eu.eudat.model.result.QueryResult;
import eu.eudat.query.EntityDoiQuery; import eu.eudat.query.EntityDoiQuery;
import eu.eudat.query.lookup.EntityDoiLookup; import eu.eudat.query.lookup.EntityDoiLookup;
import eu.eudat.service.deposit.DepositService;
import eu.eudat.service.entitydoi.EntityDoiService; import eu.eudat.service.entitydoi.EntityDoiService;
import gr.cite.tools.auditing.AuditService; import gr.cite.tools.auditing.AuditService;
import gr.cite.tools.data.builder.BuilderFactory; import gr.cite.tools.data.builder.BuilderFactory;
@ -43,6 +44,7 @@ public class EntityDoiController {
private final AuditService auditService; private final AuditService auditService;
private final EntityDoiService entityDoiService; private final EntityDoiService entityDoiService;
private final DepositService repositoryDepositService;
private final CensorFactory censorFactory; private final CensorFactory censorFactory;
@ -54,12 +56,13 @@ public class EntityDoiController {
BuilderFactory builderFactory, BuilderFactory builderFactory,
AuditService auditService, AuditService auditService,
EntityDoiService entityDoiService, EntityDoiService entityDoiService,
CensorFactory censorFactory, DepositService repositoryDepositService, CensorFactory censorFactory,
QueryFactory queryFactory, QueryFactory queryFactory,
MessageSource messageSource) { MessageSource messageSource) {
this.builderFactory = builderFactory; this.builderFactory = builderFactory;
this.auditService = auditService; this.auditService = auditService;
this.entityDoiService = entityDoiService; this.entityDoiService = entityDoiService;
this.repositoryDepositService = repositoryDepositService;
this.censorFactory = censorFactory; this.censorFactory = censorFactory;
this.queryFactory = queryFactory; this.queryFactory = queryFactory;
this.messageSource = messageSource; this.messageSource = messageSource;

View File

@ -13,6 +13,7 @@ import { catchError, map } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { ConfigurationService } from '../configuration/configuration.service'; import { ConfigurationService } from '../configuration/configuration.service';
import { BaseHttpV2Service } from '../http/base-http-v2.service'; import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Injectable() @Injectable()
export class DescriptionService { export class DescriptionService {
@ -76,13 +77,17 @@ export class DescriptionService {
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
public downloadPDF(id: string): Observable<HttpResponse<Blob>> { // public downloadPDF(id: string): Observable<HttpResponse<Blob>> {
return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: this.headers }); // return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: this.headers });
// }
public download(id: string, format: string): Observable<HttpResponse<Blob>> {
//let headerDocx: HttpHeaders = this.headers.set('Content-Type', 'application/msword')
return this.httpClient.get(`${this.apiBase}/${id}/export/${format}`, { responseType: 'blob', observe: 'response', headers: this.headers });
} }
public downloadDOCX(id: string): Observable<HttpResponse<Blob>> { public getExportFormats(): Observable<FileFormat[]> {
let headerDocx: HttpHeaders = this.headers.set('Content-Type', 'application/msword') return this.httpClient.get<FileFormat[]>(`${this.apiBase}/export/formats`);
return this.httpClient.get(`${this.apiBase}/${id}/export/Word`, { responseType: 'blob', observe: 'response', headers: headerDocx });
} }
// //

View File

@ -34,6 +34,7 @@ import { BaseHttpV2Service } from '../http/base-http-v2.service';
import { BaseHttpService } from '../http/base-http.service'; import { BaseHttpService } from '../http/base-http.service';
import { DmpStatus } from '@app/core/common/enum/dmp-status'; import { DmpStatus } from '@app/core/common/enum/dmp-status';
import { DmpDescriptionTemplateLookup } from '@app/core/query/dmp-description-template.lookup'; import { DmpDescriptionTemplateLookup } from '@app/core/query/dmp-description-template.lookup';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Injectable() @Injectable()
export class DmpServiceNew { export class DmpServiceNew {
@ -125,9 +126,9 @@ export class DmpServiceNew {
catchError((error: any) => throwError(error))); catchError((error: any) => throwError(error)));
} }
public downloadDocx(id: string): Observable<HttpResponse<Blob>> { public download(id: string, format: string): Observable<HttpResponse<Blob>> {
let headerDoc: HttpHeaders = this.headers.set('Content-Type', 'application/msword') //let headerDoc: HttpHeaders = this.headers.set('Content-Type', 'application/msword')
return this.httpClient.get(`${this.apiBase}/${id}/export/Word`, { responseType: 'blob', observe: 'response', headers: headerDoc }); return this.httpClient.get(`${this.apiBase}/${id}/export/${format}`, { responseType: 'blob', observe: 'response', headers: this.headers });
} }
public downloadPDF(id: string): Observable<HttpResponse<Blob>> { public downloadPDF(id: string): Observable<HttpResponse<Blob>> {
@ -135,6 +136,10 @@ export class DmpServiceNew {
return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: headerPdf }); return this.httpClient.get(`${this.apiBase}/${id}/export/Pdf`, { responseType: 'blob', observe: 'response', headers: headerPdf });
} }
public getExportFormats(): Observable<FileFormat[]> {
return this.httpClient.get<FileFormat[]>(`${this.apiBase}/export/formats`);
}
// public downloadJson(id: string): Observable<HttpResponse<Blob>> { // public downloadJson(id: string): Observable<HttpResponse<Blob>> {
// return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' }); // return this.httpClient.get(this.actionUrl + 'rda/' + id, { responseType: 'blob', observe: 'response' });
// } // }

View File

@ -37,7 +37,7 @@ export class MatomoService {
} }
} }
trackDownload(category: "dmps" | "datasets" | "descriptions", type: "docx" | "pdf" | "xml" | "json", id: string): void { trackDownload(category: "dmps" | "datasets" | "descriptions", type: string, id: string): void {
if (this.configurationService.matomoEnabled) { if (this.configurationService.matomoEnabled) {
var principalid = this.authService.userId(); var principalid = this.authService.userId();
if (principalid != null) { this.matomoTracker.setUserId(principalid.toString()); } if (principalid != null) { this.matomoTracker.setUserId(principalid.toString()); }

View File

@ -24,8 +24,8 @@
<button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button>
</div> </div>
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component *ngIf="item.dmp" [showDivider]="i != (listingItems.length - 1)" [dmp]="item.dmp" [isPublic]="isPublic"></app-dmp-listing-item-component> <app-dmp-listing-item-component *ngIf="item.dmp" [showDivider]="i != (listingItems.length - 1)" [fileFormats]="fileFormats" [dmp]="item.dmp" [isPublic]="isPublic"></app-dmp-listing-item-component>
<app-description-listing-item-component *ngIf="item.description" [showDivider]="i != (listingItems.length - 1)" [description]="item.description" [isPublic]="isPublic" ></app-description-listing-item-component> <app-description-listing-item-component *ngIf="item.description" [showDivider]="i != (listingItems.length - 1)" [fileFormats]="fileFormats" [description]="item.description" [isPublic]="isPublic" ></app-description-listing-item-component>
</div> </div>
<div class="text-muted d-flex justify-content-center mt-5" *ngIf="!hasMoreActivity && listingItems && listingItems.length > 0"> <div class="text-muted d-flex justify-content-center mt-5" *ngIf="!hasMoreActivity && listingItems && listingItems.length > 0">
{{'GENERAL.ACTIONS.NO-MORE-AVAILABLE' | translate}} {{'GENERAL.ACTIONS.NO-MORE-AVAILABLE' | translate}}

View File

@ -16,6 +16,8 @@ import { BaseComponent } from '@common/base/base.component';
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { AuthService } from '../../../core/services/auth/auth.service'; import { AuthService } from '../../../core/services/auth/auth.service';
import { FileFormat } from '@app/core/model/file/file-format.model';
import { DmpServiceNew } from '@app/core/services/dmp/dmp.service';
@Component({ @Component({
selector: 'app-drafts', selector: 'app-drafts',
@ -27,6 +29,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
listingItems: RecentActivityItem[]; listingItems: RecentActivityItem[];
fileFormats: FileFormat[] = [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
@ -49,7 +52,8 @@ export class DraftsComponent extends BaseComponent implements OnInit {
private authentication: AuthService, private authentication: AuthService,
private dashboardService: DashboardService, private dashboardService: DashboardService,
private location: Location, private location: Location,
private matomoService: MatomoService private matomoService: MatomoService,
private dmpServiceNew: DmpServiceNew
) { ) {
super(); super();
} }
@ -84,6 +88,7 @@ export class DraftsComponent extends BaseComponent implements OnInit {
this.updateUrl(); this.updateUrl();
} }
}); });
this.dmpServiceNew.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
this.refresh(); this.refresh();
} }

View File

@ -26,7 +26,7 @@
<button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button>
</div> </div>
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component *ngIf="item.dmp" [showDivider]="i != (listingItems.length - 1)" [dmp]="item.dmp" [isPublic]="isPublic"></app-dmp-listing-item-component> <app-dmp-listing-item-component *ngIf="item.dmp" [showDivider]="i != (listingItems.length - 1)" [fileFormats]="fileFormats" [dmp]="item.dmp" [isPublic]="isPublic"></app-dmp-listing-item-component>
<app-description-listing-item-component *ngIf="item.description" [showDivider]="i != (listingItems.length - 1)" [description]="item.description" [isPublic]="isPublic" ></app-description-listing-item-component> <app-description-listing-item-component *ngIf="item.description" [showDivider]="i != (listingItems.length - 1)" [description]="item.description" [isPublic]="isPublic" ></app-description-listing-item-component>
</div> </div>
<div class="text-muted d-flex justify-content-center mt-5" *ngIf="!hasMoreActivity && allRecentActivities && allRecentActivities.length > 0"> <div class="text-muted d-flex justify-content-center mt-5" *ngIf="!hasMoreActivity && allRecentActivities && allRecentActivities.length > 0">
@ -35,4 +35,4 @@
<div *ngIf="allRecentActivities && allRecentActivities.length > 0 && (allRecentActivities.length >= startIndex + pageSize) && hasMoreActivity" class="d-flex justify-content-center"> <div *ngIf="allRecentActivities && allRecentActivities.length > 0 && (allRecentActivities.length >= startIndex + pageSize) && hasMoreActivity" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadNextOrPrevious()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadNextOrPrevious()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
</div> </div>
</div> </div>

View File

@ -7,10 +7,12 @@ import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-it
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description } from '@app/core/model/description/description'; import { Description } from '@app/core/model/description/description';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp'; import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { FileFormat } from '@app/core/model/file/file-format.model';
import { DmpReference, Reference } from '@app/core/model/reference/reference'; import { DmpReference, Reference } from '@app/core/model/reference/reference';
import { RecentActivityItemLookup } from '@app/core/query/recent-activity-item-lookup.lookup'; import { RecentActivityItemLookup } from '@app/core/query/recent-activity-item-lookup.lookup';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import { DashboardService } from '@app/core/services/dashboard/dashboard.service'; import { DashboardService } from '@app/core/services/dashboard/dashboard.service';
import { DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { BaseComponent } from '@common/base/base.component'; import { BaseComponent } from '@common/base/base.component';
@ -27,6 +29,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
listingItems: RecentActivityItem[]; listingItems: RecentActivityItem[];
fileFormats: FileFormat[] = [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
@ -50,7 +53,8 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
private authentication: AuthService, private authentication: AuthService,
private dashboardService: DashboardService, private dashboardService: DashboardService,
private location: Location, private location: Location,
private matomoService: MatomoService private matomoService: MatomoService,
private dmpServiceNew: DmpServiceNew
) { ) {
super(); super();
} }
@ -85,6 +89,7 @@ export class RecentEditedActivityComponent extends BaseComponent implements OnIn
this.updateUrl(); this.updateUrl();
} }
}); });
this.dmpServiceNew.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
this.refresh(); this.refresh();
} }

View File

@ -24,7 +24,7 @@
<button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadNextOrPrevious(false)">{{'GENERAL.ACTIONS.LOAD-LESS' | translate}}</button>
</div> </div>
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component> <app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [fileFormats]="" [isPublic]="isPublic"></app-dmp-listing-item-component>
</div> </div>
<!-- <div *ngFor="let activity of listingItems"> <!-- <div *ngFor="let activity of listingItems">
<div class="dmp-card"> <div class="dmp-card">
@ -104,4 +104,4 @@
<div *ngIf="listingItems && listingItems.length > 0 && listingItems.length >= pageSize && hasMoreResults" class="d-flex justify-content-center"> <div *ngIf="listingItems && listingItems.length > 0 && listingItems.length >= pageSize && hasMoreResults" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadNextOrPrevious()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadNextOrPrevious()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>
</div> </div>
</div> </div>

View File

@ -7,9 +7,11 @@ import { RecentActivityItem } from '@app/core/model/dashboard/recent-activity-it
import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing'; import { DatasetListingModel } from '@app/core/model/dataset/dataset-listing';
import { Description } from '@app/core/model/description/description'; import { Description } from '@app/core/model/description/description';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp'; import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { FileFormat } from '@app/core/model/file/file-format.model';
import { RecentActivityItemLookup } from '@app/core/query/recent-activity-item-lookup.lookup'; import { RecentActivityItemLookup } from '@app/core/query/recent-activity-item-lookup.lookup';
import { AuthService } from '@app/core/services/auth/auth.service'; import { AuthService } from '@app/core/services/auth/auth.service';
import { DashboardService } from '@app/core/services/dashboard/dashboard.service'; import { DashboardService } from '@app/core/services/dashboard/dashboard.service';
import { DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { MatomoService } from '@app/core/services/matomo/matomo-service'; import { MatomoService } from '@app/core/services/matomo/matomo-service';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model'; import { DmpEditorModel } from '@app/ui/dmp/editor/dmp-editor.model';
@ -26,6 +28,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
lookup: RecentActivityItemLookup = new RecentActivityItemLookup(); lookup: RecentActivityItemLookup = new RecentActivityItemLookup();
pageSize: number = 5; pageSize: number = 5;
fileFormats: FileFormat[] = [];
@Output() totalCountDmps: EventEmitter<any> = new EventEmitter(); @Output() totalCountDmps: EventEmitter<any> = new EventEmitter();
@ -61,6 +64,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
private dashboardService: DashboardService, private dashboardService: DashboardService,
private location: Location, private location: Location,
private matomoService: MatomoService, private matomoService: MatomoService,
private dmpServiceNew: DmpServiceNew
) { ) {
super(); super();
} }
@ -95,6 +99,7 @@ export class RecentEditedDmpActivityComponent extends BaseComponent implements O
this.updateUrl(); this.updateUrl();
} }
}); });
this.dmpServiceNew.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
if (this.isAuthenticated()) { if (this.isAuthenticated()) {
this.refresh(); this.refresh();
} }

View File

@ -63,7 +63,7 @@
</div> </div>
<div class="col-md-12 col-sm-12 col-md-9"> <div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-description-listing-item-component [isPublic]="isPublic" [description]="item" [showDivider]="i != (listingItems.length - 1)"></app-description-listing-item-component> <app-description-listing-item-component [isPublic]="isPublic" [description]="item" [fileFormats]="fileFormats" [showDivider]="i != (listingItems.length - 1)"></app-description-listing-item-component>
</div> </div>
<div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center"> <div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'DESCRIPTION-LISTING.ACTIONS.LOAD-MORE' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadMore()">{{'DESCRIPTION-LISTING.ACTIONS.LOAD-MORE' | translate}}</button>
@ -75,4 +75,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -13,6 +13,7 @@ import { DataTableRequest } from '@app/core/model/data-table/data-table-request'
import { DescriptionTemplate } from '@app/core/model/description-template/description-template'; import { DescriptionTemplate } from '@app/core/model/description-template/description-template';
import { Description, DescriptionReference } from '@app/core/model/description/description'; import { Description, DescriptionReference } from '@app/core/model/description/description';
import { Dmp, DmpUser } from '@app/core/model/dmp/dmp'; import { Dmp, DmpUser } from '@app/core/model/dmp/dmp';
import { FileFormat } from '@app/core/model/file/file-format.model';
import { DmpReference, Reference } from '@app/core/model/reference/reference'; import { DmpReference, Reference } from '@app/core/model/reference/reference';
import { DescriptionLookup } from '@app/core/query/description.lookup'; import { DescriptionLookup } from '@app/core/query/description.lookup';
import { DmpLookup } from '@app/core/query/dmp.lookup'; import { DmpLookup } from '@app/core/query/dmp.lookup';
@ -70,6 +71,7 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
order = RecentActivityOrder; order = RecentActivityOrder;
dmpText: string; dmpText: string;
descriptionText: string; descriptionText: string;
fileFormats: FileFormat[] = [];
constructor( constructor(
private descriptionService: DescriptionService, private descriptionService: DescriptionService,
@ -137,6 +139,9 @@ export class DescriptionListingComponent extends BaseComponent implements OnInit
this.lookup.page = { size: this.pageSize, offset: 0 }; this.lookup.page = { size: this.pageSize, offset: 0 };
this.refresh(this.lookup); this.refresh(this.lookup);
}); });
this.descriptionService.getExportFormats().pipe(takeUntil(this._destroyed))
.subscribe(result => this.fileFormats = result);
} }
ngAfterContentChecked(): void { ngAfterContentChecked(): void {

View File

@ -24,7 +24,7 @@
</div> </div>
</a> </a>
<div class="description-card-actions"> <div class="description-card-actions">
<a class="col-auto border-right pointer" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DESCRIPTION-LISTING.ACTIONS.EXPORT' | translate}}</a> <a class="col-auto border-right pointer" *ngIf="fileFormats.length > 0" [matMenuTriggerFor]="exportMenu"><span class="material-icons icon-align pr-2">open_in_new</span>{{'DESCRIPTION-LISTING.ACTIONS.EXPORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmp.id, description.dmp.label)"><span class="material-icons icon-align pr-2">group_add</span>{{'DESCRIPTION-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a> <a class="col-auto border-right pointer" *ngIf="isUserOwner" (click)="openShareDialog(description.dmp.id, description.dmp.label)"><span class="material-icons icon-align pr-2">group_add</span>{{'DESCRIPTION-LISTING.ACTIONS.INVITE-SHORT' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="copyToDmp(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}</a> <a class="col-auto border-right pointer" *ngIf="isAuthenticated()" (click)="copyToDmp(description)"><span class="material-icons icon-align pr-2">file_copy</span>{{'DESCRIPTION-LISTING.ACTIONS.COPY-DESCRIPTION' | translate}}</a>
<a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}</a> <a class="col-auto border-right pointer" *ngIf="isAuthenticated() && isUserDescriptionRelated()" (click)="deleteClicked(description.id)"><span class="material-icons icon-align pr-2">delete</span>{{ 'DESCRIPTION-LISTING.ACTIONS.DELETE' | translate }}</a>
@ -39,17 +39,20 @@
</mat-menu> </mat-menu>
<mat-menu #exportMenu="matMenu" xPosition="before"> <mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(description)"> <div *ngFor="let format of fileFormats">
<i class="fa fa-file-pdf-o pr-2"></i> <button mat-menu-item (click)="download(description, format.format)">
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> <i class="fa pr-2" [ngClass]="format.icon"></i>
</button> <!-- <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> -->
<button mat-menu-item (click)="downloadDOCX(description)"> <span>{{format.formatName}}</span>
</button>
</div>
<!-- <button mat-menu-item *ngIf="fileFormats.includes('docx')" (click)="downloadDOCX(description)">
<i class="fa fa-file-word-o pr-2"></i> <i class="fa fa-file-word-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.DOC' | translate}}</span>
</button> </button>
<button mat-menu-item (click)="downloadXML(description)"> <button mat-menu-item *ngIf="fileFormats.includes('xml')" (click)="downloadXML(description)">
<i class="fa fa-file-code-o pr-2"></i> <i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button> </button> -->
</mat-menu> </mat-menu>
</div> </div>

View File

@ -28,6 +28,7 @@ import { DmpService, DmpServiceNew } from '@app/core/services/dmp/dmp.service';
import { ReferenceService } from '@app/core/services/reference/reference.service'; import { ReferenceService } from '@app/core/services/reference/reference.service';
import { ReferenceType } from '@app/core/common/enum/reference-type'; import { ReferenceType } from '@app/core/common/enum/reference-type';
import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component'; import { DescriptionCopyDialogComponent } from '../../description-copy-dialog/description-copy-dialog.component';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Component({ @Component({
selector: 'app-description-listing-item-component', selector: 'app-description-listing-item-component',
@ -39,6 +40,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
@Input() description: Description; @Input() description: Description;
@Input() showDivider: boolean = true; @Input() showDivider: boolean = true;
@Input() isPublic: boolean = false; @Input() isPublic: boolean = false;
@Input() fileFormats: FileFormat[] = [];
@Output() onClick: EventEmitter<Description> = new EventEmitter(); @Output() onClick: EventEmitter<Description> = new EventEmitter();
isDraft: boolean; isDraft: boolean;
@ -48,6 +50,7 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
dmpAccessTypeEnum = DmpAccessType; dmpAccessTypeEnum = DmpAccessType;
referenceTypeEnum = ReferenceType; referenceTypeEnum = ReferenceType;
constructor( constructor(
private router: Router, private router: Router,
public enumUtils: EnumUtils, public enumUtils: EnumUtils,
@ -103,27 +106,27 @@ export class DescriptionListingItemComponent extends BaseComponent implements On
return this.isPublic ? [`/explore-plans/publicOverview/${this.description.dmp.id}`] : [`/plans/edit/${this.description.dmp.id}`]; return this.isPublic ? [`/explore-plans/publicOverview/${this.description.dmp.id}`] : [`/plans/edit/${this.description.dmp.id}`];
} }
downloadPDF(description: Description): void { // downloadPDF(description: Description): void {
this.descriptionService.downloadPDF(description.id.toString()) // this.descriptionService.downloadPDF(description.id.toString())
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/pdf' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "pdf", description.id.toString());
// });
// }
download(description: Description, format: string): void {
this.descriptionService.download(description.id.toString(), format)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); const blob = new Blob([response.body], { type: 'application/octet-stream' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('descriptions', "pdf", description.id.toString()); this.matomoService.trackDownload('descriptions', format, description.id.toString());
});
}
downloadDOCX(description: Description): void {
this.descriptionService.downloadDOCX(description.id.toString())
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('descriptions', "docx", description.id.toString());
}); });
} }

View File

@ -117,6 +117,15 @@
{{ 'DESCRIPTION-OVERVIEW.ACTIONS.EXPORT' | translate }}</p> {{ 'DESCRIPTION-OVERVIEW.ACTIONS.EXPORT' | translate }}</p>
</div> </div>
<mat-menu #exportMenu="matMenu" xPosition="before"> <mat-menu #exportMenu="matMenu" xPosition="before">
<div *ngFor="let format of fileFormats">
<button mat-menu-item (click)="download(description.id, format.format)">
<i class="fa pr-2" [ngClass]="format.icon"></i>
<!-- <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> -->
<span>{{format.formatName}}</span>
</button>
</div>
</mat-menu>
<!-- <mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(description.id)"> <button mat-menu-item (click)="downloadPDF(description.id)">
<i class="fa fa-file-pdf-o pr-2"></i> <i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
@ -129,7 +138,7 @@
<i class="fa fa-file-code-o pr-2"></i> <i class="fa fa-file-code-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.XML' | translate}}</span>
</button> </button>
</mat-menu> </mat-menu> -->
</div> </div>
<div class="frame mb-3 pt-4 pl-3 pr-3 pb-1"> <div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3"> <div class="row ml-0 mr-0 pl-4 pb-3">
@ -163,4 +172,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -29,11 +29,12 @@ import { Oauth2DialogService } from '@app/ui/misc/oauth2-dialog/service/oauth2-d
import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from '@common/modules/confirmation-dialog/confirmation-dialog.component';
import { Guid } from '@common/types/guid'; import { Guid } from '@common/types/guid';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { filter, takeUntil } from 'rxjs/operators'; import { filter, take, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component'; import { DescriptionCopyDialogComponent } from '../description-copy-dialog/description-copy-dialog.component';
import { EnumUtils } from '@app/core/services/utilities/enum-utils.service'; import { EnumUtils } from '@app/core/services/utilities/enum-utils.service';
import * as FileSaver from 'file-saver'; import * as FileSaver from 'file-saver';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Component({ @Component({
@ -58,6 +59,7 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
referenceTypeEnum = ReferenceType; referenceTypeEnum = ReferenceType;
dmpStatusEnum = DmpStatus; dmpStatusEnum = DmpStatus;
dmpUserRoleEnum = DmpUserRole; dmpUserRoleEnum = DmpUserRole;
fileFormats: FileFormat[] = [];
constructor( constructor(
private route: ActivatedRoute, private route: ActivatedRoute,
@ -138,6 +140,8 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
}); });
} }
}); });
this.descriptionService.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
} }
checkLockStatus(id: Guid) { checkLockStatus(id: Guid) {
@ -291,27 +295,27 @@ export class DescriptionOverviewComponent extends BaseComponent implements OnIni
return path + reference; return path + reference;
} }
downloadPDF(id: string) { // downloadPDF(id: string) {
this.descriptionService.downloadPDF(id) // this.descriptionService.downloadPDF(id)
// .pipe(takeUntil(this._destroyed))
// .subscribe(response => {
// const blob = new Blob([response.body], { type: 'application/pdf' });
// const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
// FileSaver.saveAs(blob, filename);
// this.matomoService.trackDownload('descriptions', "pdf", id);
// });
// }
download(id: string, format: string) {
this.descriptionService.download(id, format)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); const blob = new Blob([response.body], { type: 'application/octet-stream' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('descriptions', "pdf", id); this.matomoService.trackDownload('descriptions', format, id);
});
}
downloadDocx(id: string) {
this.descriptionService.downloadDOCX(id)
.pipe(takeUntil(this._destroyed))
.subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('descriptions', "docx", id);
}); });
} }

View File

@ -47,7 +47,7 @@
</div> </div>
<div class="col-md-12 col-sm-12 col-md-9"> <div class="col-md-12 col-sm-12 col-md-9">
<div *ngFor="let item of listingItems; let i = index"> <div *ngFor="let item of listingItems; let i = index">
<app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [isPublic]="isPublic"></app-dmp-listing-item-component> <app-dmp-listing-item-component [showDivider]="i != (listingItems.length - 1)" [dmp]="item" [fileFormats]="fileFormats" [isPublic]="isPublic"></app-dmp-listing-item-component>
</div> </div>
<div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center"> <div *ngIf="listingItems && listingItems.length > 0 && this.lookup?.page?.offset < this.totalCount - 1 && this.pageSize < this.totalCount - 1" class="d-flex justify-content-center">
<button type="button" class="btn-load-more" (click)="loadMore()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button> <button type="button" class="btn-load-more" (click)="loadMore()">{{'GENERAL.ACTIONS.LOAD-MORE' | translate}}</button>

View File

@ -27,6 +27,7 @@ import { TranslateService } from '@ngx-translate/core';
import { NgDialogAnimationService } from "ng-dialog-animation"; import { NgDialogAnimationService } from "ng-dialog-animation";
import { debounceTime, takeUntil } from 'rxjs/operators'; import { debounceTime, takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Component({ @Component({
selector: 'app-dmp-listing-component', selector: 'app-dmp-listing-component',
@ -44,6 +45,7 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
isPublic: boolean = false; isPublic: boolean = false;
hasListingItems = null; hasListingItems = null;
pageSize: number = 5; pageSize: number = 5;
fileFormats: FileFormat[] = [];
public formGroup = new UntypedFormBuilder().group({ public formGroup = new UntypedFormBuilder().group({
like: new UntypedFormControl(), like: new UntypedFormControl(),
order: new UntypedFormControl() order: new UntypedFormControl()
@ -106,6 +108,8 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
this.formGroup.get('order').valueChanges this.formGroup.get('order').valueChanges
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(x => this.refresh(this.lookup)); .subscribe(x => this.refresh(this.lookup));
this.dmpServiceNew.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
} }
public dashboardTour: GuidedTour = { public dashboardTour: GuidedTour = {
@ -316,4 +320,4 @@ export class DmpListingComponent extends BaseComponent implements OnInit { //IBr
public hasLikeCriteria(): boolean { public hasLikeCriteria(): boolean {
return this.lookup.like !== undefined && this.lookup.like !== null; return this.lookup.like !== undefined && this.lookup.like !== null;
} }
} }

View File

@ -38,7 +38,17 @@
<a class="col-auto pointer" *ngIf="isAuthenticated()" [matMenuTriggerFor]="actionsMenu"><span class="material-icons icon-align pl-2">more_horiz</span></a> <a class="col-auto pointer" *ngIf="isAuthenticated()" [matMenuTriggerFor]="actionsMenu"><span class="material-icons icon-align pl-2">more_horiz</span></a>
</div> </div>
<mat-menu #exportMenu="matMenu" xPosition="before"> <mat-menu #exportMenu="matMenu" xPosition="before">
<div *ngFor="let format of fileFormats">
<button mat-menu-item (click)="download(dmp.id, format.format)">
<i class="fa pr-2" [ngClass]="format.icon"></i>
<!-- <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> -->
<span>{{format.formatName}}</span>
</button>
</div>
</mat-menu>
<!-- <mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dmp.id)"> <button mat-menu-item (click)="downloadPDF(dmp.id)">
<i class="fa fa-file-pdf-o pr-2"></i> <i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
@ -55,7 +65,7 @@
<i class="fa fa-file-o pr-2"></i> <i class="fa fa-file-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span>
</button> </button>
</mat-menu> </mat-menu> -->
<mat-menu #actionsMenu="matMenu" xPosition="before"> <mat-menu #actionsMenu="matMenu" xPosition="before">
<button *ngIf="isUserOwner(dmp)" mat-menu-item (click)="cloneOrNewVersionClicked(dmp, true)"> <button *ngIf="isUserOwner(dmp)" mat-menu-item (click)="cloneOrNewVersionClicked(dmp, true)">
<mat-icon>queue</mat-icon>{{'DMP-LISTING.ACTIONS.NEW-VERSION' | translate}} <mat-icon>queue</mat-icon>{{'DMP-LISTING.ACTIONS.NEW-VERSION' | translate}}
@ -67,4 +77,4 @@
<mat-icon>delete</mat-icon>{{ 'DMP-LISTING.ACTIONS.DELETE' | translate }} <mat-icon>delete</mat-icon>{{ 'DMP-LISTING.ACTIONS.DELETE' | translate }}
</button> </button>
</mat-menu> </mat-menu>
</div> </div>

View File

@ -23,6 +23,7 @@ import { takeUntil } from 'rxjs/operators';
import { DmpStatus } from '../../../../core/common/enum/dmp-status'; import { DmpStatus } from '../../../../core/common/enum/dmp-status';
import { AuthService } from '../../../../core/services/auth/auth.service'; import { AuthService } from '../../../../core/services/auth/auth.service';
import * as FileSaver from 'file-saver'; import * as FileSaver from 'file-saver';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Component({ @Component({
selector: 'app-dmp-listing-item-component', selector: 'app-dmp-listing-item-component',
@ -34,6 +35,7 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
@Input() dmp: Dmp; @Input() dmp: Dmp;
@Input() showDivider: boolean = true; @Input() showDivider: boolean = true;
@Input() isPublic: boolean; @Input() isPublic: boolean;
@Input() fileFormats: FileFormat[] = [];
@Output() onClick: EventEmitter<Dmp> = new EventEmitter(); @Output() onClick: EventEmitter<Dmp> = new EventEmitter();
isDraft: boolean; isDraft: boolean;
@ -191,30 +193,30 @@ export class DmpListingItemComponent extends BaseComponent implements OnInit {
// }); // });
} }
downloadDocx(id: Guid) { download(id: Guid, format: string) {
// TODO: Add this // TODO: Add this
this.dmpService.downloadDocx(id.toString()) this.dmpService.download(id.toString(), format)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); const blob = new Blob([response.body], { type: 'application/octet-stream' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id.toString()); this.matomoService.trackDownload('dmps', format, id.toString());
}); });
} }
downloadPDF(id: Guid) { // downloadPDF(id: Guid) {
this.dmpService.downloadPDF(id.toString()) // this.dmpService.downloadPDF(id.toString())
.pipe(takeUntil(this._destroyed)) // .pipe(takeUntil(this._destroyed))
.subscribe(response => { // .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/pdf' }); // const blob = new Blob([response.body], { type: 'application/pdf' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); // const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename); // FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "pdf", id.toString()); // this.matomoService.trackDownload('dmps', "pdf", id.toString());
}); // });
} // }
downloadJson(id: Guid) { downloadJson(id: Guid) {
// TODO: Add this // TODO: Add this

View File

@ -143,7 +143,7 @@
<hr class="hr-line"> <hr class="hr-line">
</div> </div>
</div> </div>
<app-dmp-deposit-dropdown *ngIf="(hasDoi(dmp) || moreDeposit()) && isFinalizedDmp(dmp) && !this.isPublicView && isUserOwner" [inputRepos]="inputRepos" [dmp]="dmp" (outputReposEmitter)="afterDeposit($event)"></app-dmp-deposit-dropdown> <app-dmp-deposit-dropdown *ngIf="(hasDoi(dmp) || moreDeposit()) && isFinalizedDmp(dmp) && !this.isPublicView && isUserOwner && inputRepos.length > 0" [inputRepos]="inputRepos" [dmp]="dmp" (outputReposEmitter)="afterDeposit($event)"></app-dmp-deposit-dropdown>
<div *ngIf="isFinalizedDmp(dmp) && hasDoi(dmp) && !isPublishedDmp(dmp) && isUserOwner" (click)="reverseFinalization()" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center"> <div *ngIf="isFinalizedDmp(dmp) && hasDoi(dmp) && !isPublishedDmp(dmp) && isUserOwner" (click)="reverseFinalization()" class="row ml-0 mr-0 pl-4 pb-3 d-flex align-items-center">
<button mat-mini-fab class="frame-btn"> <button mat-mini-fab class="frame-btn">
<mat-icon class="mat-mini-fab-icon">unarchive</mat-icon> <mat-icon class="mat-mini-fab-icon">unarchive</mat-icon>
@ -165,6 +165,15 @@
</p> </p>
</div> </div>
<mat-menu #exportMenu="matMenu" xPosition="before"> <mat-menu #exportMenu="matMenu" xPosition="before">
<div *ngFor="let format of fileFormats">
<button mat-menu-item (click)="download(dmp.id, format.format)">
<i class="fa pr-2" [ngClass]="format.icon"></i>
<!-- <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> -->
<span>{{format.formatName}}</span>
</button>
</div>
</mat-menu>
<!-- <mat-menu #exportMenu="matMenu" xPosition="before">
<button mat-menu-item (click)="downloadPDF(dmp.id)"> <button mat-menu-item (click)="downloadPDF(dmp.id)">
<i class="fa fa-file-pdf-o pr-2"></i> <i class="fa fa-file-pdf-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.PDF' | translate}}</span>
@ -181,7 +190,7 @@
<i class="fa fa-file-o pr-2"></i> <i class="fa fa-file-o pr-2"></i>
<span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span> <span>{{'GENERAL.FILE-TYPES.JSON' | translate}}</span>
</button> </button>
</mat-menu> </mat-menu> -->
</div> </div>
<div class="frame mb-3 pt-4 pl-3 pr-3 pb-1"> <div class="frame mb-3 pt-4 pl-3 pr-3 pb-1">
<div class="row ml-0 mr-0 pl-4 pb-3"> <div class="row ml-0 mr-0 pl-4 pb-3">
@ -215,4 +224,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -36,6 +36,7 @@ import { TranslateService } from '@ngx-translate/core';
import { takeUntil } from 'rxjs/operators'; import { takeUntil } from 'rxjs/operators';
import { nameof } from 'ts-simple-nameof'; import { nameof } from 'ts-simple-nameof';
import * as FileSaver from 'file-saver'; import * as FileSaver from 'file-saver';
import { FileFormat } from '@app/core/model/file/file-format.model';
@Component({ @Component({
selector: 'app-dmp-overview', selector: 'app-dmp-overview',
@ -56,6 +57,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
textMessage: any; textMessage: any;
pastVersions: Dmp[]; //TODO: get these from the backend pastVersions: Dmp[]; //TODO: get these from the backend
selectedModel: EntityDoi; selectedModel: EntityDoi;
fileFormats: FileFormat[] = [];
@ViewChild('doi') @ViewChild('doi')
doi: ElementRef; doi: ElementRef;
@ -153,6 +155,7 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
}); });
} }
}); });
this.dmpService.getExportFormats().pipe(takeUntil(this._destroyed)).subscribe(result => this.fileFormats = result);
this.depositRepositoriesService.getAvailableRepos() this.depositRepositoriesService.getAvailableRepos()
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe( .subscribe(
@ -355,15 +358,15 @@ export class DmpOverviewComponent extends BaseComponent implements OnInit {
// }); // });
} }
downloadDocx(id: string) { download(id: string, format: string) {
this.dmpService.downloadDocx(id) this.dmpService.download(id, format)
.pipe(takeUntil(this._destroyed)) .pipe(takeUntil(this._destroyed))
.subscribe(response => { .subscribe(response => {
const blob = new Blob([response.body], { type: 'application/msword' }); const blob = new Blob([response.body], { type: 'application/octet-stream' });
const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition')); const filename = this.fileUtils.getFilenameFromContentDispositionHeader(response.headers.get('Content-Disposition'));
FileSaver.saveAs(blob, filename); FileSaver.saveAs(blob, filename);
this.matomoService.trackDownload('dmps', "docx", id); this.matomoService.trackDownload('dmps', format, id);
}); });
} }