Merge pull request #4609 from MaximilianKrambach/exportImportOrder
sort import/export columns for motions
This commit is contained in:
commit
16ea66e9ed
@ -887,6 +887,7 @@ export class MotionRepositoryService extends BaseAgendaContentObjectRepository<V
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -61,7 +61,7 @@ export abstract class BaseImportService<V extends BaseViewModel> {
|
||||
/**
|
||||
* The headers expected in the CSV matching import properties (in order)
|
||||
*/
|
||||
public expectedHeader: (string)[];
|
||||
public expectedHeader: string[];
|
||||
|
||||
/**
|
||||
* The minimimal number of header entries needed to successfully create an entry
|
||||
|
@ -13,9 +13,10 @@
|
||||
<span translate>Required comma or semicolon separated values with these column header names in the first row:</span>
|
||||
<br />
|
||||
<div class="code red-warning-text">
|
||||
<span translate>Identifier</span>, <span translate>Title</span>, <span translate>Text</span>,
|
||||
<span translate>Reason</span>, <span translate>Submitter</span>, <span translate>Category</span>,
|
||||
<span translate>Origin</span>, <span translate>Motion block</span>
|
||||
<span *ngFor="let header of this.expectedHeader; let last = last">
|
||||
<span translate>{{ header }}</span
|
||||
><span *ngIf="!last">, </span>
|
||||
</span>
|
||||
</div>
|
||||
<ul>
|
||||
<li translate>
|
||||
|
@ -17,6 +17,22 @@ import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
templateUrl: './motion-import-list.component.html'
|
||||
})
|
||||
export class MotionImportListComponent extends BaseImportListComponent<ViewMotion> {
|
||||
/**
|
||||
* Fetach a list of the headers expected by the importer, and prepare them
|
||||
* to be translateable (upper case)
|
||||
*
|
||||
* @returns a list of strings matching the expected headers
|
||||
*/
|
||||
public get expectedHeader(): string[] {
|
||||
return this.importer.expectedHeader.map(header => {
|
||||
if (header === 'motion_block') {
|
||||
return 'Motion block';
|
||||
} else {
|
||||
return header.charAt(0).toUpperCase() + header.slice(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for list view bases
|
||||
*
|
||||
|
@ -52,7 +52,7 @@
|
||||
<mat-button-toggle value="category"> <span translate>Category</span> </mat-button-toggle>
|
||||
<mat-button-toggle value="tags"> <span translate>Tags</span> </mat-button-toggle>
|
||||
<mat-button-toggle value="origin"> <span translate>Origin</span> </mat-button-toggle>
|
||||
<mat-button-toggle value="block"> <span translate>Motion block</span> </mat-button-toggle>
|
||||
<mat-button-toggle value="motion_block"> <span translate>Motion block</span> </mat-button-toggle>
|
||||
<mat-button-toggle value="polls" #votingResultButton>
|
||||
<span translate>Voting result</span>
|
||||
</mat-button-toggle>
|
||||
|
@ -52,7 +52,7 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
'category',
|
||||
'origin',
|
||||
'tags',
|
||||
'block',
|
||||
'motion_block',
|
||||
'polls',
|
||||
'id'
|
||||
];
|
||||
|
@ -223,7 +223,8 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion, Motio
|
||||
result.comments
|
||||
);
|
||||
} else if (result.format === 'csv') {
|
||||
this.motionCsvExport.exportMotionList(data, result.content, result.metaInfo);
|
||||
const content = ['identifier', ...result.content, ...result.metaInfo];
|
||||
this.motionCsvExport.exportMotionList(data, content);
|
||||
} else if (result.format === 'xlsx') {
|
||||
this.motionXlsxExport.exportMotionList(data, result.metaInfo);
|
||||
}
|
||||
|
23
client/src/app/site/motions/motion-import-export-order.ts
Normal file
23
client/src/app/site/motions/motion-import-export-order.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Defines the column order for csv/xlsx export/import of motions.
|
||||
*/
|
||||
export const motionImportExportHeaderOrder: string[] = [
|
||||
'id',
|
||||
'identifier',
|
||||
'title',
|
||||
'text',
|
||||
'reason',
|
||||
'submitters',
|
||||
'category',
|
||||
'origin',
|
||||
'motion_block',
|
||||
'tags',
|
||||
'recommendation',
|
||||
'state'
|
||||
];
|
||||
|
||||
/**
|
||||
* Subset of {@link motionImportExportHeaderOrder} properties that are
|
||||
* restricted to export only due to database or workflow limitations
|
||||
*/
|
||||
export const motionExportOnly: string[] = ['id', 'recommendation', 'state', 'tags'];
|
@ -7,7 +7,7 @@ import {
|
||||
CsvColumnDefinitionProperty,
|
||||
CsvColumnDefinitionMap
|
||||
} from 'app/core/ui-services/csv-export.service';
|
||||
import { InfoToExport } from './motion-pdf.service';
|
||||
import { motionImportExportHeaderOrder } from '../motion-import-export-order';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
||||
@ -35,10 +35,10 @@ export class MotionCsvExportService {
|
||||
*
|
||||
* @param motions Motions to export
|
||||
* @param contentToExport content properties to export
|
||||
* @param infoToExport meta info to export
|
||||
*/
|
||||
public exportMotionList(motions: ViewMotion[], contentToExport: string[], infoToExport: InfoToExport[]): void {
|
||||
const propertyList = ['identifier', 'title'].concat(contentToExport, infoToExport);
|
||||
public exportMotionList(motions: ViewMotion[], contentToExport: string[]): void {
|
||||
// reorders the exported properties according to motionImportExportHeaderOrder
|
||||
const propertyList = motionImportExportHeaderOrder.filter(property => contentToExport.includes(property));
|
||||
const exportProperties: (
|
||||
| CsvColumnDefinitionProperty<ViewMotion>
|
||||
| CsvColumnDefinitionMap<ViewMotion>)[] = propertyList.map(option => {
|
||||
@ -52,6 +52,11 @@ export class MotionCsvExportService {
|
||||
label: 'state',
|
||||
map: motion => this.motionRepo.getExtendedStateLabel(motion)
|
||||
};
|
||||
} else if (option === 'motion_block') {
|
||||
return {
|
||||
label: 'Motion block',
|
||||
map: motion => (motion.motion_block ? motion.motion_block.getTitle() : '')
|
||||
};
|
||||
} else {
|
||||
return { property: option } as CsvColumnDefinitionProperty<ViewMotion>;
|
||||
}
|
||||
@ -83,6 +88,7 @@ export class MotionCsvExportService {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO does not reflect updated export order. any more. Hard coded for now
|
||||
public exportDummyMotion(): void {
|
||||
const headerRow = ['Identifier', 'Title', 'Text', 'Reason', 'Submitters', 'Category', 'Origin', 'Motion block'];
|
||||
const rows = [
|
||||
|
@ -4,15 +4,16 @@ import { MatSnackBar } from '@angular/material';
|
||||
import { Papa } from 'ngx-papaparse';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { BaseImportService, NewEntry } from 'app/core/ui-services/base-import.service';
|
||||
import { Category } from 'app/shared/models/motions/category';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { CreateMotion } from '../models/create-motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
import { motionExportOnly, motionImportExportHeaderOrder } from '../motion-import-export-order';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
||||
import { ViewCsvCreateMotion, CsvMapping } from '../models/view-csv-create-motion';
|
||||
import { BaseImportService, NewEntry } from 'app/core/ui-services/base-import.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
||||
/**
|
||||
@ -74,17 +75,7 @@ export class MotionImportService extends BaseImportService<ViewMotion> {
|
||||
matSnackbar: MatSnackBar
|
||||
) {
|
||||
super(translate, papa, matSnackbar);
|
||||
|
||||
this.expectedHeader = [
|
||||
'identifier',
|
||||
'title',
|
||||
'text',
|
||||
'reason',
|
||||
'submitters',
|
||||
'category',
|
||||
'origin',
|
||||
'motion_block'
|
||||
];
|
||||
this.expectedHeader = motionImportExportHeaderOrder.filter(head => !motionExportOnly.includes(head));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -22,7 +22,7 @@ export type InfoToExport =
|
||||
| 'state'
|
||||
| 'recommendation'
|
||||
| 'category'
|
||||
| 'block'
|
||||
| 'motion_block'
|
||||
| 'origin'
|
||||
| 'tags'
|
||||
| 'polls'
|
||||
@ -274,7 +274,7 @@ export class MotionPdfService {
|
||||
}
|
||||
|
||||
// motion block
|
||||
if (motion.motion_block && (!infoToExport || infoToExport.includes('block'))) {
|
||||
if (motion.motion_block && (!infoToExport || infoToExport.includes('motion_block'))) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: `${this.translate.instant('Motion block')}:`,
|
||||
|
@ -3,6 +3,7 @@ import { Injectable } from '@angular/core';
|
||||
import { Workbook } from 'exceljs/dist/exceljs.min.js';
|
||||
|
||||
import { InfoToExport } from './motion-pdf.service';
|
||||
import { motionImportExportHeaderOrder } from '../motion-import-export-order';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
@ -51,7 +52,9 @@ export class MotionXlsxExportService {
|
||||
*/
|
||||
public exportMotionList(motions: ViewMotion[], infoToExport: InfoToExport[]): void {
|
||||
const workbook = new Workbook();
|
||||
const properties = ['identifier', 'title'].concat(infoToExport);
|
||||
const propertyList = ['identifier', 'title'].concat(infoToExport);
|
||||
// reorders the exported properties according to motionImportExportHeaderOrder
|
||||
const properties = motionImportExportHeaderOrder.filter(property => propertyList.includes(property));
|
||||
const worksheet = workbook.addWorksheet(this.translate.instant('Motions'), {
|
||||
pageSetup: {
|
||||
paperSize: 9,
|
||||
@ -63,14 +66,13 @@ export class MotionXlsxExportService {
|
||||
}
|
||||
});
|
||||
|
||||
// if the ID was exported as well, shift it to the first position
|
||||
if (properties[properties.length - 1] === 'id') {
|
||||
properties.unshift(properties.pop());
|
||||
}
|
||||
|
||||
worksheet.columns = properties.map(property => {
|
||||
const propertyHeader =
|
||||
property === 'motion_block'
|
||||
? 'Motion block'
|
||||
: property.charAt(0).toLocaleUpperCase() + property.slice(1);
|
||||
return {
|
||||
header: this.translate.instant(property.charAt(0).toLocaleUpperCase() + property.slice(1))
|
||||
header: this.translate.instant(propertyHeader)
|
||||
};
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user