Add amendment list
Adds a new ListView to show all amendments. The list view can be acessed from both the motion list and the motion detail list
This commit is contained in:
parent
bfccf4cd2b
commit
13e1c01bb6
@ -6,7 +6,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { saveAs } from 'file-saver';
|
||||
|
||||
import { ProgressSnackBarComponent } from 'app/shared/components/progress-snack-bar/progress-snack-bar.component';
|
||||
import { ExportFormData } from 'app/site/motions/modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportInfo } from 'app/site/motions/services/motion-export.service';
|
||||
import { ConfigService } from '../ui-services/config.service';
|
||||
import { HttpService } from '../core-services/http.service';
|
||||
import { ProgressService } from '../ui-services/progress.service';
|
||||
@ -163,7 +163,7 @@ export class PdfDocumentService {
|
||||
private async getStandardPaper(
|
||||
documentContent: object,
|
||||
metadata?: object,
|
||||
exportInfo?: ExportFormData,
|
||||
exportInfo?: MotionExportInfo,
|
||||
imageUrls?: string[],
|
||||
customMargins?: [number, number, number, number],
|
||||
landscape?: boolean
|
||||
@ -308,7 +308,7 @@ export class PdfDocumentService {
|
||||
* @param lrMargin optionally overriding the margins
|
||||
* @returns the footer doc definition
|
||||
*/
|
||||
private getFooter(lrMargin?: [number, number], exportInfo?: ExportFormData): object {
|
||||
private getFooter(lrMargin?: [number, number], exportInfo?: MotionExportInfo): object {
|
||||
const columns = [];
|
||||
const showPageNr = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('page') : true;
|
||||
const showDate = exportInfo && exportInfo.pdfOptions ? exportInfo.pdfOptions.includes('date') : false;
|
||||
@ -399,7 +399,7 @@ export class PdfDocumentService {
|
||||
* @param filename the name of the file to use
|
||||
* @param metadata
|
||||
*/
|
||||
public download(docDefinition: object, filename: string, metadata?: object, exportInfo?: ExportFormData): void {
|
||||
public download(docDefinition: object, filename: string, metadata?: object, exportInfo?: MotionExportInfo): void {
|
||||
this.getStandardPaper(docDefinition, metadata, exportInfo).then(doc => {
|
||||
this.createPdf(doc, filename);
|
||||
});
|
||||
|
@ -497,6 +497,13 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns all amendments
|
||||
*/
|
||||
public getAllAmendmentsInstantly(): ViewMotion[] {
|
||||
return this.getViewModelList().filter(motion => !!motion.parent_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the amendments to a given motion
|
||||
*
|
||||
|
@ -146,17 +146,21 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
return this._filterStack;
|
||||
}
|
||||
|
||||
/**
|
||||
* The key to access stored valued
|
||||
*/
|
||||
private storageKey: string;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param name the name of the filter service
|
||||
* @param store storage service, to read saved filter variables
|
||||
*/
|
||||
public constructor(
|
||||
protected name: string,
|
||||
private store: StorageService,
|
||||
private OSStatus: OpenSlidesStatusService
|
||||
) {}
|
||||
public constructor(private store: StorageService, private OSStatus: OpenSlidesStatusService) {
|
||||
this.storageKey = this.constructor.name;
|
||||
console.log('storage-key: ', this.storageKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the filterService.
|
||||
@ -166,7 +170,7 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
public async initFilters(inputData: Observable<V[]>): Promise<void> {
|
||||
let storedFilter: OsFilter[] = null;
|
||||
if (!this.OSStatus.isInHistoryMode) {
|
||||
storedFilter = await this.store.get<OsFilter[]>('filter_' + this.name);
|
||||
storedFilter = await this.store.get<OsFilter[]>('filter_' + this.storageKey);
|
||||
}
|
||||
|
||||
if (storedFilter && this.isOsFilter(storedFilter)) {
|
||||
@ -237,7 +241,7 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
|
||||
let storedFilter = null;
|
||||
if (!this.OSStatus.isInHistoryMode) {
|
||||
storedFilter = await this.store.get<OsFilter[]>('filter_' + this.name);
|
||||
storedFilter = await this.store.get<OsFilter[]>('filter_' + this.storageKey);
|
||||
}
|
||||
|
||||
if (!!storedFilter) {
|
||||
@ -276,21 +280,19 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
* @param repo repository to create dynamic filters from
|
||||
* @param filter the OSFilter for the filter property
|
||||
* @param noneOptionLabel The label of the non option, if set
|
||||
* @param exexcludeIds Set if certain ID's should be excluded from filtering
|
||||
* @param filterFn custom filter function if required
|
||||
*/
|
||||
protected updateFilterForRepo(
|
||||
repo: BaseRepository<BaseViewModel, BaseModel, TitleInformation>,
|
||||
filter: OsFilter,
|
||||
noneOptionLabel?: string,
|
||||
excludeIds?: number[]
|
||||
filterFn?: (filter: BaseViewModel<any>) => boolean
|
||||
): void {
|
||||
repo.getViewModelListObservable().subscribe(viewModel => {
|
||||
if (viewModel && viewModel.length) {
|
||||
let filterProperties: (OsFilterOption | string)[];
|
||||
|
||||
filterProperties = viewModel
|
||||
.filter(model => (excludeIds && excludeIds.length ? !excludeIds.includes(model.id) : true))
|
||||
.map((model: HierarchyModel) => {
|
||||
filterProperties = viewModel.filter(filterFn ? filterFn : () => true).map((model: HierarchyModel) => {
|
||||
return {
|
||||
condition: model.id,
|
||||
label: model.getTitle(),
|
||||
@ -307,11 +309,13 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
};
|
||||
});
|
||||
|
||||
if (!!noneOptionLabel) {
|
||||
filterProperties.push('-');
|
||||
filterProperties.push({
|
||||
condition: null,
|
||||
label: noneOptionLabel
|
||||
});
|
||||
}
|
||||
|
||||
filter.options = filterProperties;
|
||||
this.setFilterDefinitions();
|
||||
@ -325,7 +329,7 @@ export abstract class BaseFilterListService<V extends BaseViewModel> {
|
||||
public storeActiveFilters(): void {
|
||||
this.updateFilteredData();
|
||||
if (!this.OSStatus.isInHistoryMode) {
|
||||
this.store.set('filter_' + this.name, this.filterDefinitions);
|
||||
this.store.set('filter_' + this.storageKey, this.filterDefinitions);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,7 @@ export class SearchValueSelectorComponent implements OnDestroy {
|
||||
* Placeholder of the List
|
||||
*/
|
||||
@Input()
|
||||
public listname: String;
|
||||
public listname: string;
|
||||
|
||||
/**
|
||||
* Name of the Form
|
||||
|
@ -22,7 +22,7 @@ export class AgendaFilterListService extends BaseFilterListService<ViewItem> {
|
||||
* @param translate Translation service
|
||||
*/
|
||||
public constructor(store: StorageService, OSStatus: OpenSlidesStatusService, private translate: TranslateService) {
|
||||
super('Agenda', store, OSStatus);
|
||||
super(store, OSStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -19,7 +19,7 @@ export class AssignmentFilterListService extends BaseFilterListService<ViewAssig
|
||||
* @param translate translate service
|
||||
*/
|
||||
public constructor(store: StorageService, OSStatus: OpenSlidesStatusService) {
|
||||
super('Assignments', store, OSStatus);
|
||||
super(store, OSStatus);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,19 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
|
||||
import { AmendmentListComponent } from './amendment-list.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
component: AmendmentListComponent,
|
||||
pathMatch: 'full'
|
||||
},
|
||||
{ path: ':id', component: AmendmentListComponent }
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class AmendmentListRoutingModule {}
|
@ -0,0 +1,107 @@
|
||||
<os-head-bar [nav]="false" [multiSelectMode]="isMultiSelect" goBack="true">
|
||||
<!-- Title -->
|
||||
<div class="title-slot"><h2 translate>Amendments</h2></div>
|
||||
|
||||
<!-- Menu -->
|
||||
<div class="menu-slot">
|
||||
<button type="button" mat-icon-button [matMenuTriggerFor]="amendmentListMenu">
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Multiselect info -->
|
||||
<div class="central-info-slot">
|
||||
<button mat-icon-button (click)="toggleMultiSelect()"><mat-icon>arrow_back</mat-icon></button>
|
||||
<span>{{ selectedRows.length }} </span><span translate>selected</span>
|
||||
</div>
|
||||
</os-head-bar>
|
||||
|
||||
<os-list-view-table
|
||||
[repo]="motionRepo"
|
||||
[sortService]="motionSortService"
|
||||
[filterService]="amendmentFilterService"
|
||||
[columns]="tableColumnDefinition"
|
||||
[filterProps]="filterProps"
|
||||
[multiSelect]="isMultiSelect"
|
||||
listStorageKey="amendments"
|
||||
[(selectedRows)]="selectedRows"
|
||||
(dataSourceChange)="onDataSourceChange($event)"
|
||||
>
|
||||
<!-- Meta -->
|
||||
<div *pblNgridCellDef="'meta'; row as motion" class="cell-slot fill">
|
||||
<a class="detail-link" [routerLink]="motion.getDetailStateURL()"></a>
|
||||
<div class="column-identifier innerTable">
|
||||
<!-- Identifier and line -->
|
||||
<div class="title-line">
|
||||
{{ motion.identifier }}
|
||||
(<span translate>Line</span> <span>{{ getChangeLines(motion) }}</span
|
||||
>)
|
||||
</div>
|
||||
|
||||
<!-- Submitter -->
|
||||
<div class="submitters-line">
|
||||
<span *ngIf="motion.submitters.length">
|
||||
<span translate>by</span>
|
||||
{{ motion.submitters }}
|
||||
</span>
|
||||
|
||||
<span *ngIf="motion.submitters.length">
|
||||
·
|
||||
</span>
|
||||
<span translate>Sequential number</span>
|
||||
{{ motion.id }}
|
||||
</div>
|
||||
|
||||
<!-- State -->
|
||||
<div>
|
||||
<mat-basic-chip *ngIf="motion.state" [ngClass]="motion.stateCssColor" [disabled]="true">
|
||||
{{ motionRepo.getExtendedStateLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
|
||||
<!-- Reco -->
|
||||
<div class="spacer-top-3" *ngIf="motion.recommendation && motion.state.next_states_id.length > 0">
|
||||
<mat-basic-chip class="bluegrey" [disabled]="true">
|
||||
{{ this.motionRepo.getExtendedRecommendationLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Summary -->
|
||||
<div *pblNgridCellDef="'summary'; row as motion" class="cell-slot fill">
|
||||
<div class="innerTable">
|
||||
<div class="motion-text" [innerHtml]="sanitizeText(getAmendmentSummary(motion))"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- List of Speakers -->
|
||||
<div *pblNgridCellDef="'speakers'; row as motion" class="cell-slot fill">
|
||||
<os-speaker-button [object]="motion"></os-speaker-button>
|
||||
</div>
|
||||
</os-list-view-table>
|
||||
|
||||
<mat-menu #amendmentListMenu="matMenu">
|
||||
<div *ngIf="!isMultiSelect">
|
||||
<div *osPerms="'motions.can_manage'">
|
||||
<button mat-menu-item (click)="toggleMultiSelect()">
|
||||
<mat-icon>library_add</mat-icon>
|
||||
<span translate>Multiselect</span>
|
||||
</button>
|
||||
</div>
|
||||
<button mat-menu-item (click)="openExportDialog()">
|
||||
<mat-icon>archive</mat-icon>
|
||||
<span translate>Export</span>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="isMultiSelect">
|
||||
<button mat-menu-item (click)="selectAll()">
|
||||
<mat-icon>done_all</mat-icon>
|
||||
<span translate>Select all</span>
|
||||
</button>
|
||||
<button mat-menu-item [disabled]="!selectedRows.length" (click)="deselectAll()">
|
||||
<mat-icon>clear</mat-icon>
|
||||
<span translate>Deselect all</span>
|
||||
</button>
|
||||
</div>
|
||||
</mat-menu>
|
@ -0,0 +1,2 @@
|
||||
@import '~assets/styles/motion-styles-common';
|
||||
@import 'app/site/motions/styles/motion-list-styles.scss';
|
@ -0,0 +1,27 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { AmendmentListComponent } from './amendment-list.component';
|
||||
|
||||
describe('AmendmentListComponent', () => {
|
||||
let component: AmendmentListComponent;
|
||||
let fixture: ComponentFixture<AmendmentListComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [AmendmentListComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AmendmentListComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,189 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatDialog, MatSnackBar } from '@angular/material';
|
||||
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||
|
||||
import { AmendmentFilterListService } from '../../services/amendment-filter-list.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { DiffLinesInParagraph } from 'app/core/ui-services/diff.service';
|
||||
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
||||
import { ItemVisibilityChoices } from 'app/shared/models/agenda/item';
|
||||
import { largeDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||
import { BaseListViewComponent } from 'app/site/base/base-list-view';
|
||||
import { MotionExportDialogComponent } from '../shared-motion/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportInfo, MotionExportService } from '../../services/motion-export.service';
|
||||
import { MotionSortListService } from '../../services/motion-sort-list.service';
|
||||
import { ViewMotion } from '../../models/view-motion';
|
||||
|
||||
/**
|
||||
* Shows all the amendments in the NGrid table
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-amendment-list',
|
||||
templateUrl: './amendment-list.component.html',
|
||||
styleUrls: ['./amendment-list.component.scss']
|
||||
})
|
||||
export class AmendmentListComponent extends BaseListViewComponent<ViewMotion> implements OnInit {
|
||||
private parentMotionId: number;
|
||||
/**
|
||||
* Hold item visibility
|
||||
*/
|
||||
public itemVisibility = ItemVisibilityChoices;
|
||||
|
||||
/**
|
||||
* To hold the motions line length
|
||||
*/
|
||||
private motionLineLength: number;
|
||||
|
||||
/**
|
||||
* Column defintiion
|
||||
*/
|
||||
public tableColumnDefinition: PblColumnDefinition[] = [
|
||||
{
|
||||
prop: 'meta',
|
||||
minWidth: 250,
|
||||
width: '15%'
|
||||
},
|
||||
{
|
||||
prop: 'summary',
|
||||
width: 'auto'
|
||||
},
|
||||
{
|
||||
prop: 'speakers',
|
||||
width: this.singleButtonWidth
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* To filter stuff
|
||||
*/
|
||||
public filterProps = ['submitters', 'title', 'identifier'];
|
||||
|
||||
/**
|
||||
*
|
||||
* @param titleService set the title
|
||||
* @param translate translate stuff
|
||||
* @param matSnackBar show errors
|
||||
* @param storage store and recall
|
||||
* @param motionRepo get the motions
|
||||
* @param motionSortService the default motion sorter
|
||||
*
|
||||
* @param configService get config vars
|
||||
*/
|
||||
public constructor(
|
||||
titleService: Title,
|
||||
translate: TranslateService,
|
||||
matSnackBar: MatSnackBar,
|
||||
storage: StorageService,
|
||||
route: ActivatedRoute,
|
||||
public motionRepo: MotionRepositoryService,
|
||||
public motionSortService: MotionSortListService,
|
||||
public amendmentFilterService: AmendmentFilterListService,
|
||||
private sanitizer: DomSanitizer,
|
||||
private configService: ConfigService,
|
||||
private dialog: MatDialog,
|
||||
private motionExport: MotionExportService,
|
||||
private linenumberingService: LinenumberingService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar, storage);
|
||||
super.setTitle('Amendments');
|
||||
this.canMultiSelect = true;
|
||||
this.parentMotionId = parseInt(route.snapshot.params.id, 10);
|
||||
}
|
||||
|
||||
/**
|
||||
* Observe the line length
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.configService.get<number>('motions_line_length').subscribe(lineLength => {
|
||||
this.motionLineLength = lineLength;
|
||||
});
|
||||
|
||||
if (!!this.parentMotionId) {
|
||||
this.amendmentFilterService.clearAllFilters();
|
||||
this.amendmentFilterService.parentMotionId = this.parentMotionId;
|
||||
} else {
|
||||
this.amendmentFilterService.parentMotionId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to get amendment paragraphs of a given motion
|
||||
*
|
||||
* @param amendment the get the paragraphs from
|
||||
* @returns DiffLinesInParagraph-List
|
||||
*/
|
||||
private getDiffLines(amendment: ViewMotion): DiffLinesInParagraph[] {
|
||||
if (amendment.isParagraphBasedAmendment()) {
|
||||
return this.motionRepo.getAmendmentParagraphs(amendment, this.motionLineLength, false);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the lines of the amendments
|
||||
* If an amendments has multiple changes, they will be printed like an array of strings
|
||||
*
|
||||
* @param amendment the motion to create the amendment to
|
||||
* @return The lines of the amendment
|
||||
*/
|
||||
public getChangeLines(amendment: ViewMotion): string {
|
||||
const diffLines = this.getDiffLines(amendment);
|
||||
|
||||
if (!!diffLines) {
|
||||
return diffLines
|
||||
.map(diffLine => {
|
||||
if (diffLine.diffLineTo === diffLine.diffLineFrom + 1) {
|
||||
return '' + diffLine.diffLineFrom;
|
||||
} else {
|
||||
return `${diffLine.diffLineFrom} - ${diffLine.diffLineTo - 1}`;
|
||||
}
|
||||
})
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formulate the amendment summary
|
||||
*
|
||||
* @param amendment the motion to create the amendment to
|
||||
* @returns the amendments as string, if they are multiple they gonna be separated by `[...]`
|
||||
*/
|
||||
public getAmendmentSummary(amendment: ViewMotion): string {
|
||||
const diffLines = this.getDiffLines(amendment);
|
||||
if (!!diffLines) {
|
||||
return diffLines
|
||||
.map(diffLine => {
|
||||
return this.linenumberingService.stripLineNumbers(diffLine.text);
|
||||
})
|
||||
.join('[...]');
|
||||
}
|
||||
}
|
||||
|
||||
// todo put in own file
|
||||
public openExportDialog(): void {
|
||||
const exportDialogRef = this.dialog.open(MotionExportDialogComponent, {
|
||||
...largeDialogSettings,
|
||||
data: this.dataSource
|
||||
});
|
||||
|
||||
exportDialogRef
|
||||
.afterClosed()
|
||||
.subscribe((exportInfo: MotionExportInfo) =>
|
||||
this.motionExport.evaluateExportRequest(
|
||||
exportInfo,
|
||||
this.isMultiSelect ? this.selectedRows : this.dataSource.filteredData
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public sanitizeText(text: string): SafeHtml {
|
||||
return this.sanitizer.bypassSecurityTrustHtml(text);
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { AmendmentListRoutingModule } from './amendment-list-routing.module';
|
||||
import { AmendmentListComponent } from './amendment-list.component';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { SharedMotionModule } from '../shared-motion/shared-motion.module';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AmendmentListComponent],
|
||||
imports: [CommonModule, AmendmentListRoutingModule, SharedModule, SharedMotionModule]
|
||||
})
|
||||
export class AmendmentListModule {}
|
@ -452,9 +452,12 @@
|
||||
<!-- Ammendments -->
|
||||
<div *ngIf="!editMotion && amendments && amendments.length > 0">
|
||||
<h4 translate>Amendments</h4>
|
||||
<div *ngFor="let amendment of amendments">
|
||||
<a [routerLink]="amendment.getDetailStateURL()">{{ amendment.identifierOrTitle }}</a>
|
||||
</div>
|
||||
<a *ngIf="amendments.length === 1" [routerLink]="['/motions/amendments', motion.id]">
|
||||
{{ amendments.length }} <span translate>Amendment</span>
|
||||
</a>
|
||||
<a *ngIf="amendments.length > 1" [routerLink]="['/motions/amendments', motion.id]">
|
||||
{{ amendments.length }} <span translate>Amendments</span></a
|
||||
>
|
||||
</div>
|
||||
|
||||
<!-- motion polls -->
|
||||
|
@ -600,6 +600,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
this.repo.amendmentsTo(motionId).subscribe((amendments: ViewMotion[]): void => {
|
||||
this.amendments = amendments;
|
||||
this.recalcUnifiedChanges();
|
||||
|
@ -104,10 +104,11 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- TODO: These two now appear twice. Might be an own component -->
|
||||
<!-- Workflow state -->
|
||||
<div class="ellipsis-overflow white">
|
||||
<mat-basic-chip *ngIf="motion.state" [ngClass]="motion.stateCssColor" [disabled]="true">
|
||||
{{ getStateLabel(motion) }}
|
||||
{{ this.motionRepo.getExtendedStateLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
|
||||
@ -117,7 +118,7 @@
|
||||
class="ellipsis-overflow white spacer-top-3"
|
||||
>
|
||||
<mat-basic-chip class="bluegrey" [disabled]="true">
|
||||
{{ getRecommendationLabel(motion) }}
|
||||
{{ motionRepo.getExtendedRecommendationLabel(motion) }}
|
||||
</mat-basic-chip>
|
||||
</div>
|
||||
</div>
|
||||
@ -219,6 +220,14 @@
|
||||
<span translate>Multiselect</span>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="perms.isAllowed('manage') || hasAmendments()">
|
||||
<button mat-menu-item routerLink="amendments">
|
||||
<!-- color_lens -->
|
||||
<!-- format_paint -->
|
||||
<mat-icon>color_lens</mat-icon>
|
||||
<span translate>Amendments</span>
|
||||
</button>
|
||||
</div>
|
||||
<div *ngIf="perms.isAllowed('manage')">
|
||||
<button mat-menu-item routerLink="call-list">
|
||||
<mat-icon>sort</mat-icon>
|
||||
|
@ -1,4 +1,5 @@
|
||||
@import '~assets/styles/tables.scss';
|
||||
@import '~app/site/motions/styles/motion-list-styles.scss';
|
||||
|
||||
// Determine the distance between the top edge to the start of the table content
|
||||
$text-margin-top: 10px;
|
||||
@ -27,9 +28,6 @@ $text-margin-top: 10px;
|
||||
margin-top: $text-margin-top;
|
||||
|
||||
.title-line {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
|
||||
.attached-files {
|
||||
.mat-icon {
|
||||
display: inline-flex;
|
||||
@ -45,10 +43,6 @@ $text-margin-top: 10px;
|
||||
padding-right: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.submitters-line {
|
||||
font-size: 90%;
|
||||
}
|
||||
}
|
||||
|
||||
.column-state {
|
||||
|
@ -8,7 +8,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { PblColumnDefinition } from '@pebula/ngrid';
|
||||
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { PdfError } from 'app/core/pdf-services/pdf-document.service';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
@ -24,18 +23,12 @@ import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||
import { ViewMotionBlock } from 'app/site/motions/models/view-motion-block';
|
||||
import { ViewWorkflow } from 'app/site/motions/models/view-workflow';
|
||||
import { LocalPermissionsService } from 'app/site/motions/services/local-permissions.service';
|
||||
import { MotionCsvExportService } from 'app/site/motions/services/motion-csv-export.service';
|
||||
import { MotionExportInfo, MotionExportService } from 'app/site/motions/services/motion-export.service';
|
||||
import { MotionFilterListService } from 'app/site/motions/services/motion-filter-list.service';
|
||||
import { MotionMultiselectService } from 'app/site/motions/services/motion-multiselect.service';
|
||||
import { MotionPdfExportService } from 'app/site/motions/services/motion-pdf-export.service';
|
||||
import { MotionSortListService } from 'app/site/motions/services/motion-sort-list.service';
|
||||
import { MotionXlsxExportService } from 'app/site/motions/services/motion-xlsx-export.service';
|
||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||
import {
|
||||
ExportFormData,
|
||||
FileFormat,
|
||||
MotionExportDialogComponent
|
||||
} from '../motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportDialogComponent } from '../../../shared-motion/motion-export-dialog/motion-export-dialog.component';
|
||||
|
||||
interface TileCategoryInformation {
|
||||
filter: string;
|
||||
@ -208,12 +201,10 @@ export class MotionListComponent extends BaseListViewComponent<ViewMotion> imple
|
||||
private categoryRepo: CategoryRepositoryService,
|
||||
private workflowRepo: WorkflowRepositoryService,
|
||||
public motionRepo: MotionRepositoryService,
|
||||
private motionCsvExport: MotionCsvExportService,
|
||||
private pdfExport: MotionPdfExportService,
|
||||
private dialog: MatDialog,
|
||||
public multiselectService: MotionMultiselectService,
|
||||
public perms: LocalPermissionsService,
|
||||
private motionXlsxExport: MotionXlsxExportService
|
||||
private motionExport: MotionExportService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar, storage);
|
||||
this.canMultiSelect = true;
|
||||
@ -358,37 +349,14 @@ export class MotionListComponent extends BaseListViewComponent<ViewMotion> imple
|
||||
data: this.dataSource
|
||||
});
|
||||
|
||||
exportDialogRef.afterClosed().subscribe((exportInfo: ExportFormData) => {
|
||||
if (exportInfo && exportInfo.format) {
|
||||
const data = this.isMultiSelect ? this.selectedRows : this.dataSource.filteredData;
|
||||
if (exportInfo.format === FileFormat.PDF) {
|
||||
try {
|
||||
this.pdfExport.exportMotionCatalog(data, exportInfo);
|
||||
} catch (err) {
|
||||
if (err instanceof PdfError) {
|
||||
this.raiseError(err.message);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} else if (exportInfo.format === FileFormat.CSV) {
|
||||
const content = [];
|
||||
const comments = [];
|
||||
if (exportInfo.content) {
|
||||
content.push(...exportInfo.content);
|
||||
}
|
||||
if (exportInfo.metaInfo) {
|
||||
content.push(...exportInfo.metaInfo);
|
||||
}
|
||||
if (exportInfo.comments) {
|
||||
comments.push(...exportInfo.comments);
|
||||
}
|
||||
this.motionCsvExport.exportMotionList(data, content, comments, exportInfo.crMode);
|
||||
} else if (exportInfo.format === FileFormat.XLSX) {
|
||||
this.motionXlsxExport.exportMotionList(data, exportInfo.metaInfo, exportInfo.comments);
|
||||
}
|
||||
}
|
||||
});
|
||||
exportDialogRef
|
||||
.afterClosed()
|
||||
.subscribe((exportInfo: MotionExportInfo) =>
|
||||
this.motionExport.evaluateExportRequest(
|
||||
exportInfo,
|
||||
this.isMultiSelect ? this.selectedRows : this.dataSource.filteredData
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -404,26 +372,6 @@ export class MotionListComponent extends BaseListViewComponent<ViewMotion> imple
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a motion's current recommendation label
|
||||
*
|
||||
* @param motion
|
||||
* @returns the current recommendation label (with extension)
|
||||
*/
|
||||
public getRecommendationLabel(motion: ViewMotion): string {
|
||||
return this.motionRepo.getExtendedRecommendationLabel(motion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch a motion's current state label
|
||||
*
|
||||
* @param motion
|
||||
* @returns the current state label (with extension)
|
||||
*/
|
||||
public getStateLabel(motion: ViewMotion): string {
|
||||
return this.motionRepo.getExtendedStateLabel(motion);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function saves the selected view by changes.
|
||||
*
|
||||
@ -495,6 +443,13 @@ export class MotionListComponent extends BaseListViewComponent<ViewMotion> imple
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns if there are amendments or not
|
||||
*/
|
||||
public hasAmendments(): boolean {
|
||||
return !!this.motionRepo.getAllAmendmentsInstantly().length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if categories are available.
|
||||
*
|
||||
|
@ -4,7 +4,6 @@ import { RouterModule, Routes } from '@angular/router';
|
||||
import { MotionListComponent } from './components/motion-list/motion-list.component';
|
||||
|
||||
const routes: Routes = [{ path: '', component: MotionListComponent, pathMatch: 'full' }];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
|
@ -2,13 +2,12 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { MotionExportDialogComponent } from './components/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionListRoutingModule } from './motion-list-routing.module';
|
||||
import { MotionListComponent } from './components/motion-list/motion-list.component';
|
||||
import { SharedMotionModule } from '../shared-motion/shared-motion.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MotionListRoutingModule, SharedModule],
|
||||
declarations: [MotionListComponent, MotionExportDialogComponent],
|
||||
entryComponents: [MotionExportDialogComponent]
|
||||
imports: [CommonModule, MotionListRoutingModule, SharedModule, SharedMotionModule],
|
||||
declarations: [MotionListComponent]
|
||||
})
|
||||
export class MotionListModule {}
|
||||
|
@ -11,29 +11,7 @@ import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { ChangeRecoMode, LineNumberingMode } from 'app/site/motions/models/view-motion';
|
||||
import { ViewMotionCommentSection } from 'app/site/motions/models/view-motion-comment-section';
|
||||
import { motionImportExportHeaderOrder, noMetaData } from 'app/site/motions/motion-import-export-order';
|
||||
import { InfoToExport } from 'app/site/motions/services/motion-pdf.service';
|
||||
|
||||
/**
|
||||
* Determine the possible file format
|
||||
*/
|
||||
export enum FileFormat {
|
||||
PDF = 1,
|
||||
CSV,
|
||||
XLSX
|
||||
}
|
||||
|
||||
/**
|
||||
* Shape the structure of the dialog data
|
||||
*/
|
||||
export interface ExportFormData {
|
||||
format?: FileFormat;
|
||||
lnMode?: LineNumberingMode;
|
||||
crMode?: ChangeRecoMode;
|
||||
content?: string[];
|
||||
metaInfo?: InfoToExport[];
|
||||
pdfOptions?: string[];
|
||||
comments?: number[];
|
||||
}
|
||||
import { ExportFileFormat, MotionExportInfo } from 'app/site/motions/services/motion-export.service';
|
||||
|
||||
/**
|
||||
* Dialog component to determine exporting.
|
||||
@ -57,7 +35,7 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
/**
|
||||
* to use the format in the template
|
||||
*/
|
||||
public fileFormat = FileFormat;
|
||||
public fileFormat = ExportFileFormat;
|
||||
|
||||
/**
|
||||
* The form that contains the export information.
|
||||
@ -67,8 +45,8 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
/**
|
||||
* The default export values in contrast to the restored values
|
||||
*/
|
||||
private defaults: ExportFormData = {
|
||||
format: FileFormat.PDF,
|
||||
private defaults: MotionExportInfo = {
|
||||
format: ExportFileFormat.PDF,
|
||||
content: ['text', 'reason'],
|
||||
pdfOptions: ['toc', 'page'],
|
||||
metaInfo: ['submitters', 'state', 'recommendation', 'category', 'origin', 'tags', 'motion_block', 'polls', 'id']
|
||||
@ -130,26 +108,26 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
* Observes the form for changes to react dynamically
|
||||
*/
|
||||
public ngOnInit(): void {
|
||||
this.exportForm.valueChanges.pipe(auditTime(500)).subscribe((value: ExportFormData) => {
|
||||
this.exportForm.valueChanges.pipe(auditTime(500)).subscribe((value: MotionExportInfo) => {
|
||||
this.store.set('motion_export_selection', value);
|
||||
});
|
||||
|
||||
this.exportForm.get('format').valueChanges.subscribe((value: FileFormat) => this.onFormatChange(value));
|
||||
this.exportForm.get('format').valueChanges.subscribe((value: ExportFileFormat) => this.onFormatChange(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* React to changes on the file format
|
||||
* @param format
|
||||
*/
|
||||
private onFormatChange(format: FileFormat): void {
|
||||
private onFormatChange(format: ExportFileFormat): void {
|
||||
// XLSX cannot have "content"
|
||||
if (format === FileFormat.XLSX) {
|
||||
if (format === ExportFileFormat.XLSX) {
|
||||
this.disableControl('content');
|
||||
} else {
|
||||
this.enableControl('content');
|
||||
}
|
||||
|
||||
if (format === FileFormat.CSV || format === FileFormat.XLSX) {
|
||||
if (format === ExportFileFormat.CSV || format === ExportFileFormat.XLSX) {
|
||||
this.disableControl('lnMode');
|
||||
this.disableControl('crMode');
|
||||
this.disableControl('pdfOptions');
|
||||
@ -165,7 +143,7 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
this.votingResultButton.disabled = true;
|
||||
}
|
||||
|
||||
if (format === FileFormat.PDF) {
|
||||
if (format === ExportFileFormat.PDF) {
|
||||
this.enableControl('lnMode');
|
||||
this.enableControl('crMode');
|
||||
this.enableControl('pdfOptions');
|
||||
@ -222,7 +200,7 @@ export class MotionExportDialogComponent implements OnInit {
|
||||
});
|
||||
|
||||
// restore selection or set default
|
||||
this.store.get<ExportFormData>('motion_export_selection').then(restored => {
|
||||
this.store.get<MotionExportInfo>('motion_export_selection').then(restored => {
|
||||
if (!!restored) {
|
||||
this.exportForm.patchValue(restored);
|
||||
} else {
|
@ -0,0 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { MotionExportDialogComponent } from './motion-export-dialog/motion-export-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, SharedModule],
|
||||
declarations: [MotionExportDialogComponent],
|
||||
entryComponents: [MotionExportDialogComponent]
|
||||
})
|
||||
export class SharedMotionModule {}
|
@ -52,6 +52,11 @@ const routes: Routes = [
|
||||
loadChildren: () => import('./modules/motion-detail/motion-detail.module').then(m => m.MotionDetailModule),
|
||||
data: { basePerm: 'motions.can_create' }
|
||||
},
|
||||
{
|
||||
path: 'amendments',
|
||||
loadChildren: () => import('./modules/amendment-list/amendment-list.module').then(m => m.AmendmentListModule),
|
||||
data: { basePerm: 'motions.can_see' }
|
||||
},
|
||||
{
|
||||
path: ':id',
|
||||
loadChildren: () => import('./modules/motion-detail/motion-detail.module').then(m => m.MotionDetailModule),
|
||||
|
@ -2,9 +2,8 @@ import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { MotionsRoutingModule } from './motions-routing.module';
|
||||
import { SharedModule } from '../../shared/shared.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, MotionsRoutingModule, SharedModule]
|
||||
imports: [CommonModule, MotionsRoutingModule]
|
||||
})
|
||||
export class MotionsModule {}
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { AmendmentFilterListService } from './amendment-filter-list.service';
|
||||
|
||||
describe('AmendmentFilterService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: AmendmentFilterListService = TestBed.get(AmendmentFilterListService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,96 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { OpenSlidesStatusService } from 'app/core/core-services/openslides-status.service';
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { StorageService } from 'app/core/core-services/storage.service';
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { MotionBlockRepositoryService } from 'app/core/repositories/motions/motion-block-repository.service';
|
||||
import { MotionCommentSectionRepositoryService } from 'app/core/repositories/motions/motion-comment-section-repository.service';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { WorkflowRepositoryService } from 'app/core/repositories/motions/workflow-repository.service';
|
||||
import { TagRepositoryService } from 'app/core/repositories/tags/tag-repository.service';
|
||||
import { OsFilter } from 'app/core/ui-services/base-filter-list.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { MotionFilterListService } from './motion-filter-list.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
|
||||
/**
|
||||
* Filter the list of Amendments
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AmendmentFilterListService extends MotionFilterListService {
|
||||
/**
|
||||
* Private acessor for an amendment id
|
||||
*/
|
||||
private _parentMotionId: number;
|
||||
|
||||
/**
|
||||
* publicly get an amendment id
|
||||
*/
|
||||
public set parentMotionId(id: number) {
|
||||
this._parentMotionId = id;
|
||||
}
|
||||
|
||||
private motionFilterOptions: OsFilter = {
|
||||
property: 'parent_id',
|
||||
label: 'Motion',
|
||||
options: []
|
||||
};
|
||||
|
||||
public constructor(
|
||||
store: StorageService,
|
||||
OSStatus: OpenSlidesStatusService,
|
||||
categoryRepo: CategoryRepositoryService,
|
||||
motionBlockRepo: MotionBlockRepositoryService,
|
||||
commentRepo: MotionCommentSectionRepositoryService,
|
||||
tagRepo: TagRepositoryService,
|
||||
workflowRepo: WorkflowRepositoryService,
|
||||
translate: TranslateService,
|
||||
operator: OperatorService,
|
||||
configService: ConfigService,
|
||||
motionRepo: MotionRepositoryService
|
||||
) {
|
||||
super(
|
||||
store,
|
||||
OSStatus,
|
||||
categoryRepo,
|
||||
motionBlockRepo,
|
||||
commentRepo,
|
||||
tagRepo,
|
||||
workflowRepo,
|
||||
translate,
|
||||
operator,
|
||||
configService
|
||||
);
|
||||
|
||||
this.updateFilterForRepo(motionRepo, this.motionFilterOptions, null, (model: ViewMotion) =>
|
||||
motionRepo.hasAmendments(model)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override from base filter list service
|
||||
*
|
||||
* @returns the list of Motions which only contains view motions
|
||||
*/
|
||||
protected preFilter(motions: ViewMotion[]): ViewMotion[] {
|
||||
return motions.filter(motion => {
|
||||
if (!!this._parentMotionId) {
|
||||
return motion.parent_id === this._parentMotionId;
|
||||
} else {
|
||||
return !!motion.parent_id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently, no filters for the amendment list, except the pre-filter
|
||||
*/
|
||||
protected getFilterDefinitions(): OsFilter[] {
|
||||
return [this.motionFilterOptions].concat(super.getFilterDefinitions());
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { MotionExportService } from './motion-export.service';
|
||||
|
||||
describe('MotionExportService', () => {
|
||||
beforeEach(() =>
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: MotionExportService = TestBed.get(MotionExportService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,80 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { PdfError } from 'app/core/pdf-services/pdf-document.service';
|
||||
import { MotionCsvExportService } from './motion-csv-export.service';
|
||||
import { MotionPdfExportService } from './motion-pdf-export.service';
|
||||
import { InfoToExport } from './motion-pdf.service';
|
||||
import { MotionXlsxExportService } from './motion-xlsx-export.service';
|
||||
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../models/view-motion';
|
||||
|
||||
/**
|
||||
* Determine the possible file format
|
||||
*/
|
||||
export enum ExportFileFormat {
|
||||
PDF = 1,
|
||||
CSV,
|
||||
XLSX
|
||||
}
|
||||
|
||||
/**
|
||||
* Shape the structure of the dialog data
|
||||
*/
|
||||
export interface MotionExportInfo {
|
||||
format?: ExportFileFormat;
|
||||
lnMode?: LineNumberingMode;
|
||||
crMode?: ChangeRecoMode;
|
||||
content?: string[];
|
||||
metaInfo?: InfoToExport[];
|
||||
pdfOptions?: string[];
|
||||
comments?: number[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic layer to unify any motion export
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MotionExportService {
|
||||
public constructor(
|
||||
private pdfExport: MotionPdfExportService,
|
||||
private csvExport: MotionCsvExportService,
|
||||
private xlsxExport: MotionXlsxExportService
|
||||
) {}
|
||||
|
||||
public evaluateExportRequest(exportInfo: MotionExportInfo, data: ViewMotion[]): void {
|
||||
if (!!exportInfo.format) {
|
||||
if (exportInfo.format === ExportFileFormat.PDF) {
|
||||
try {
|
||||
this.pdfExport.exportMotionCatalog(data, exportInfo);
|
||||
} catch (err) {
|
||||
if (err instanceof PdfError) {
|
||||
console.error('PDFError: ', err);
|
||||
/**
|
||||
* TODO: Has been this.raiseError(err.message) before. Central error treatment
|
||||
*/
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
} else if (exportInfo.format === ExportFileFormat.CSV) {
|
||||
const content = [];
|
||||
const comments = [];
|
||||
if (exportInfo.content) {
|
||||
content.push(...exportInfo.content);
|
||||
}
|
||||
if (exportInfo.metaInfo) {
|
||||
content.push(...exportInfo.metaInfo);
|
||||
}
|
||||
if (exportInfo.comments) {
|
||||
comments.push(...exportInfo.comments);
|
||||
}
|
||||
this.csvExport.exportMotionList(data, content, comments, exportInfo.crMode);
|
||||
} else if (exportInfo.format === ExportFileFormat.XLSX) {
|
||||
this.xlsxExport.exportMotionList(data, exportInfo.metaInfo, exportInfo.comments);
|
||||
}
|
||||
} else {
|
||||
throw new Error('No export format was provided');
|
||||
}
|
||||
}
|
||||
}
|
@ -134,7 +134,7 @@ export class MotionFilterListService extends BaseFilterListService<ViewMotion> {
|
||||
private operator: OperatorService,
|
||||
private config: ConfigService
|
||||
) {
|
||||
super('Motion', store, OSStatus);
|
||||
super(store, OSStatus);
|
||||
this.getWorkflowConfig();
|
||||
|
||||
this.updateFilterForRepo(categoryRepo, this.categoryFilterOptions, this.translate.instant('No category set'));
|
||||
|
@ -7,7 +7,7 @@ import { BorderType, PdfDocumentService, PdfError, StyleType } from 'app/core/pd
|
||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportInfo } from './motion-export.service';
|
||||
import { MotionPdfService } from './motion-pdf.service';
|
||||
import { ViewCategory } from '../models/view-category';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
@ -56,7 +56,7 @@ export class MotionPdfCatalogService {
|
||||
* @param commentsToExport
|
||||
* @returns pdfmake doc definition as object
|
||||
*/
|
||||
public motionListToDocDef(motions: ViewMotion[], exportInfo: ExportFormData): object {
|
||||
public motionListToDocDef(motions: ViewMotion[], exportInfo: MotionExportInfo): object {
|
||||
let doc = [];
|
||||
const motionDocList = [];
|
||||
|
||||
|
@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { PdfDocumentService } from 'app/core/pdf-services/pdf-document.service';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||
import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportInfo } from './motion-export.service';
|
||||
import { MotionPdfCatalogService } from './motion-pdf-catalog.service';
|
||||
import { MotionPdfService } from './motion-pdf.service';
|
||||
import { ViewMotion } from '../models/view-motion';
|
||||
@ -41,7 +41,7 @@ export class MotionPdfExportService {
|
||||
* @param lnMode the desired line numbering mode
|
||||
* @param crMode the desired change recomendation mode
|
||||
*/
|
||||
public exportSingleMotion(motion: ViewMotion, exportInfo?: ExportFormData): void {
|
||||
public exportSingleMotion(motion: ViewMotion, exportInfo?: MotionExportInfo): void {
|
||||
const doc = this.motionPdfService.motionToDocDef(motion, exportInfo);
|
||||
const filename = `${this.translate.instant('Motion')} ${motion.identifierOrTitle}`;
|
||||
const metadata = {
|
||||
@ -60,7 +60,7 @@ export class MotionPdfExportService {
|
||||
* @param infoToExport Determine the meta info to export
|
||||
* @param commentsToExport Comments (by id) to export
|
||||
*/
|
||||
public exportMotionCatalog(motions: ViewMotion[], exportInfo: ExportFormData): void {
|
||||
public exportMotionCatalog(motions: ViewMotion[], exportInfo: MotionExportInfo): void {
|
||||
const doc = this.pdfCatalogService.motionListToDocDef(motions, exportInfo);
|
||||
const filename = this.translate.instant(this.configService.instant<string>('motions_export_title'));
|
||||
const metadata = {
|
||||
|
@ -13,7 +13,7 @@ import { LinenumberingService } from 'app/core/ui-services/linenumbering.service
|
||||
import { CalculablePollKey } from 'app/core/ui-services/poll.service';
|
||||
import { ViewUnifiedChange, ViewUnifiedChangeType } from 'app/shared/models/motions/view-unified-change';
|
||||
import { getRecommendationTypeName } from 'app/shared/utils/recommendation-type-names';
|
||||
import { ExportFormData } from '../modules/motion-list/components/motion-export-dialog/motion-export-dialog.component';
|
||||
import { MotionExportInfo } from './motion-export.service';
|
||||
import { MotionPollService } from './motion-poll.service';
|
||||
import { ChangeRecoMode, LineNumberingMode, ViewMotion } from '../models/view-motion';
|
||||
import { ViewMotionAmendedParagraph } from '../models/view-motion-amended-paragraph';
|
||||
@ -92,7 +92,7 @@ export class MotionPdfService {
|
||||
* @param commentsToExport comments to chose for export. If 'allcomments' is set in infoToExport, this selection will be ignored and all comments exported
|
||||
* @returns doc def for the motion
|
||||
*/
|
||||
public motionToDocDef(motion: ViewMotion, exportInfo?: ExportFormData): object {
|
||||
public motionToDocDef(motion: ViewMotion, exportInfo?: MotionExportInfo): object {
|
||||
let lnMode = exportInfo && exportInfo.lnMode ? exportInfo.lnMode : null;
|
||||
let crMode = exportInfo && exportInfo.crMode ? exportInfo.crMode : null;
|
||||
const infoToExport = exportInfo ? exportInfo.metaInfo : null;
|
||||
|
@ -0,0 +1,8 @@
|
||||
.title-line {
|
||||
font-weight: 500;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.submitters-line {
|
||||
font-size: 90%;
|
||||
}
|
@ -35,8 +35,13 @@ export class UserFilterListService extends BaseFilterListService<ViewUser> {
|
||||
groupRepo: GroupRepositoryService,
|
||||
private translate: TranslateService
|
||||
) {
|
||||
super('User', store, OSStatus);
|
||||
this.updateFilterForRepo(groupRepo, this.userGroupFilterOptions, this.translate.instant('Default'), [1]);
|
||||
super(store, OSStatus);
|
||||
this.updateFilterForRepo(
|
||||
groupRepo,
|
||||
this.userGroupFilterOptions,
|
||||
this.translate.instant('Default'),
|
||||
(model: ViewUser) => model.id !== 1
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user