diff --git a/client/src/app/shared/models/agenda/item.ts b/client/src/app/shared/models/agenda/item.ts index bef67ef1f..e08e46081 100644 --- a/client/src/app/shared/models/agenda/item.ts +++ b/client/src/app/shared/models/agenda/item.ts @@ -62,14 +62,15 @@ export class Item extends ProjectableBaseModel { } /** - * Return the type as string + * Gets the string representation of the item type + * @returns The visibility for this item, as defined in {@link itemVisibilityChoices} */ public get verboseType(): string { - if (this.type) { - return itemVisibilityChoices.find(visibilityType => visibilityType.key === this.type).name; - } else { + if (!this.type) { return ''; } + const type = itemVisibilityChoices.find(choice => choice.key === this.type); + return type ? type.name : ''; } public getTitle(): string { diff --git a/client/src/app/shared/models/base/agenda-base-model.ts b/client/src/app/shared/models/base/agenda-base-model.ts index 38abdb1c4..09819069c 100644 --- a/client/src/app/shared/models/base/agenda-base-model.ts +++ b/client/src/app/shared/models/base/agenda-base-model.ts @@ -33,11 +33,20 @@ export abstract class AgendaBaseModel extends ProjectableBaseModel implements Ag return this.getAgendaTitle() + ' (' + this.getVerboseName() + ')'; } + /** + * @returns the (optional) descriptive text to be exported in the CSV. + * May be overridden by inheriting classes + */ + public getCSVExportText(): string { + return ''; + } + /** * Should return a string representation of the object, so there can be searched for. */ public abstract formatForSearch(): SearchRepresentation; + /** * Should return the URL to the detail view. Used for the agenda, that the * user can navigate to the content object. diff --git a/client/src/app/shared/models/topics/topic.ts b/client/src/app/shared/models/topics/topic.ts index f935455c6..33b03fad7 100644 --- a/client/src/app/shared/models/topics/topic.ts +++ b/client/src/app/shared/models/topics/topic.ts @@ -37,4 +37,12 @@ export class Topic extends AgendaBaseModel { public getDetailStateURL(): string { return `/agenda/topics/${this.id}`; } + + /** + * Returns the text to be inserted in csv exports + * @override + */ + public getCSVExportText(): string { + return this.text; + } } diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html index 7fb15ed2a..b056f42c4 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html @@ -103,6 +103,10 @@ Numbering +
diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts index e6d134581..55093befc 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts @@ -8,6 +8,8 @@ import { ViewItem } from '../../models/view-item'; import { ListViewBaseComponent } from 'app/site/base/list-view-base'; import { AgendaRepositoryService } from '../../services/agenda-repository.service'; import { PromptService } from '../../../../core/services/prompt.service'; + +import { AgendaCsvExportService } from '../../services/agenda-csv-export.service'; import { ItemInfoDialogComponent } from '../item-info-dialog/item-info-dialog.component'; import { ViewportService } from 'app/core/services/viewport.service'; import { DurationService } from 'app/site/core/services/duration.service'; @@ -47,6 +49,7 @@ export class AgendaListComponent extends ListViewBaseComponent impleme * @param config read out config values * @param vp determine the viewport * @param durationService Converts numbers to readable duration strings + * @param csvExport Handles the exporting into csv */ public constructor( titleService: Title, @@ -59,7 +62,8 @@ export class AgendaListComponent extends ListViewBaseComponent impleme private dialog: MatDialog, private config: ConfigService, public vp: ViewportService, - public durationService: DurationService + public durationService: DurationService, + private csvExport: AgendaCsvExportService ) { super(titleService, translate, matSnackBar); @@ -213,4 +217,11 @@ export class AgendaListComponent extends ListViewBaseComponent impleme } return list; } + + /** + * Export all items as CSV + */ + public csvExportItemList(): void { + this.csvExport.exportItemList(this.dataSource.data); + } } diff --git a/client/src/app/site/agenda/models/view-item.ts b/client/src/app/site/agenda/models/view-item.ts index b82dc8c4f..3c4be1932 100644 --- a/client/src/app/site/agenda/models/view-item.ts +++ b/client/src/app/site/agenda/models/view-item.ts @@ -34,17 +34,22 @@ export class ViewItem extends BaseViewModel { return this.item ? this.item.type : null; } - public get verboseType(): string { - return this.item.verboseType; - } - - public get comment(): string { - return this.item ? this.item.comment : null; - } - public get closed(): boolean { return this.item ? this.item.closed : null; } + public get comment(): string { + if (this.item && this.item.comment) { + return this.item.comment; + } + return ''; + } + + public get verboseType() : string { + if (this.item && this.item.verboseType) { + return this.item.verboseType; + } + return ''; + } public constructor(item: Item, contentObject: AgendaBaseModel) { super(); diff --git a/client/src/app/site/agenda/services/agenda-csv-export.service.spec.ts b/client/src/app/site/agenda/services/agenda-csv-export.service.spec.ts new file mode 100644 index 000000000..5720f7837 --- /dev/null +++ b/client/src/app/site/agenda/services/agenda-csv-export.service.spec.ts @@ -0,0 +1,20 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { E2EImportsModule } from 'e2e-imports.module'; +import { AgendaCsvExportService } from './agenda-csv-export.service'; + +describe('AgendaCsvExportService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule], + providers: [AgendaCsvExportService] + }); + }); + + it('should be created', inject( + [AgendaCsvExportService], + (service: AgendaCsvExportService) => { + expect(service).toBeTruthy(); + } + )); +}); diff --git a/client/src/app/site/agenda/services/agenda-csv-export.service.ts b/client/src/app/site/agenda/services/agenda-csv-export.service.ts new file mode 100644 index 000000000..cbf9aaec7 --- /dev/null +++ b/client/src/app/site/agenda/services/agenda-csv-export.service.ts @@ -0,0 +1,41 @@ +import { Injectable } from '@angular/core'; + +import { TranslateService } from '@ngx-translate/core'; + +import { CsvExportService } from 'app/core/services/csv-export.service'; +import { ViewItem } from '../models/view-item'; + +/** + * Exports CSVs for Agendas. Collect all CSV types here to have them in one place. + */ +@Injectable({ + providedIn: 'root' +}) +export class AgendaCsvExportService { + + /** + * Does nothing. + * + * @param csvExport CsvExportService + * @param translate TranslateService + */ + public constructor(private csvExport: CsvExportService, private translate: TranslateService) {} + + /** + * Export all Agendas as CSV + * + * @param Agendas Agendas to export + */ + public exportItemList(items: ViewItem[]): void { + this.csvExport.export(items, + [ + { label: 'Title', map: viewItem => viewItem.getTitle() }, + { label: 'Text', map: viewItem => viewItem.contentObject ? viewItem.contentObject.getCSVExportText() : '' }, + { label: 'Duration', property: 'duration' }, + { label: 'Comment', property: 'comment' }, + { label: 'Item type', property: 'verboseType' } + ], + this.translate.instant('Agenda') + '.csv' + ); + } +}