Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance motion forward #3925

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TreeIdNode } from 'src/app/infrastructure/definitions/tree';
import { NullablePartial } from 'src/app/infrastructure/utils';
import { AgendaListTitle } from 'src/app/site/pages/meetings/pages/agenda';
import { ViewMotion } from 'src/app/site/pages/meetings/pages/motions';
import { MotionFormatResult } from 'src/app/site/pages/meetings/pages/motions/services/common/motion-format.service';
import { TreeService } from 'src/app/ui/modules/sorting/modules/sorting-tree/services';

import { Motion } from '../../../../domain/models/motions/motion';
Expand Down Expand Up @@ -56,13 +57,23 @@ export class MotionRepositoryService extends BaseAgendaItemAndListOfSpeakersCont
return this.sendBulkActionToBackend(MotionAction.CREATE, payload);
}

public async createForwarded(meetingIds: Id[], ...motions: any[]): Promise<{ success: number; partial: number }> {
public async createForwarded(
meetingIds: Id[],
useOriginalSubmitter: boolean,
useOriginalNumber: boolean,
useOriginalVersion: boolean,
...motions: MotionFormatResult[]
): Promise<{ success: number; partial: number }> {
const payloads: any[][] = [];
motions.forEach(motion => {
payloads.push(
meetingIds.map(id => {
return {
meeting_id: id,
use_original_submitter: useOriginalSubmitter,
use_original_number: useOriginalNumber,
with_amendments: useOriginalVersion,
with_change_recommendations: useOriginalVersion,
...motion
};
})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,55 +1,127 @@
<div mat-dialog-title>
{{ data.motion.length > 1 ? 'Forward motions' : ('Forwarding of motion' | translate) }}
@if (data.motion.length === 1) {
<span>{{ data.motion[0].number }}</span>
}
</div>
<mat-dialog-content>
@if (data.motion.length === 1) {
<span>
<div class="state-margin">
{{ 'State' | translate }}:
<b>{{ data.motion[0].state.name }} {{ data.motion[0].state_extension }}</b>
</span>
}
@if (data.motion.length === 1 && activeMeetingCommitteeName) {
<br />
<b>{{ data.motion[0].state.name }}</b>
</div>
}
@if (activeMeetingCommitteeName) {
<span>
{{ 'Submitter (in target meeting)' | translate }}:
<b>{{ activeMeetingCommitteeName }}</b>
</span>
}
<div class="motion-forward-meeting-list">
@for (committee of committeesObservable | async; track committee) {
@if (committee.meetings?.length) {
<div>
<h4>{{ committee.name }}</h4>
@for (meeting of committee.meetings; track meeting) {
<div>
<mat-checkbox
[disabled]="isActiveMeeting(meeting) || hasAlreadyBeenForwardedTo(meeting)"
[value]="meeting.id"
[(ngModel)]="checkboxStateMap[meeting.id]"
(change)="onChangeCheckbox($event)"
>
{{ meeting.name }}
@if (meeting.start_time || meeting.end_time) {
<table mat-table [dataSource]="['motion_version', 'submitter', 'identifier', 'meeting']">
<!-- Label in front-->
<ng-container matColumnDef="label">
<td *matCellDef="let rowName" mat-cell>
@if (rowName === 'motion_version') {
<span>{{ 'Motion version' | translate }}</span>
} @else if (rowName === 'submitter') {
<span>{{ 'Submitter' | translate }}</span>
} @else if (rowName === 'identifier') {
<span>{{ 'Identifier' | translate }}</span>
} @else if (rowName === 'meeting') {
<span>{{ 'Meetings' | translate }}</span>
}
</td>
</ng-container>

<!-- radio checks -->
<ng-container matColumnDef="radio">
<td *matCellDef="let rowName" mat-cell>
@if (rowName === 'motion_version') {
<span>
<mat-radio-group class="motion-forward-radio-group" [(ngModel)]="useOriginalVersion">
<mat-radio-button [value]="true">
{{ 'Original motion text with amendments/change recommendations' | translate }}
</mat-radio-button>
<mat-radio-button [value]="false">
{{ 'Final version' | translate }}
</mat-radio-button>
</mat-radio-group>
</span>
} @else if (rowName === 'submitter') {
<span>
<mat-radio-group class="motion-forward-radio-group" [(ngModel)]="useOriginalSubmitter">
<mat-radio-button [value]="true">
{{ 'original submitter name' | translate }}
@if (data.motion.length === 1 && data.motion[0].submitterNames.length > 0) {
<span>
<os-comma-separated-listing [list]="data.motion[0].submitterNames">
<ng-template let-submitter>
<b>{{ submitter }}</b>
</ng-template>
</os-comma-separated-listing>
</span>
} @else if (data.motion.length === 1 && data.motion[0].submitterNames.length === 0) {
<span>
<b>{{ showActiveMeetingName() }}</b>
</span>
}
</mat-radio-button>
<mat-radio-button [value]="false">
{{ 'committee name' | translate }}
@if (activeMeetingCommitteeName) {
<span>
<b>({{ activeMeetingCommitteeName }})</b>
</span>
}
</mat-radio-button>
</mat-radio-group>
</span>
} @else if (rowName === 'identifier') {
<span>
<mat-radio-group class="motion-forward-radio-group" [(ngModel)]="useOriginalNumber">
<mat-radio-button [value]="true">
{{ 'original identifier' | translate }}
@if (data.motion.length === 1) {
<span>
&nbsp;&middot;&nbsp;
<os-meeting-time
[endTime]="meeting.end_time"
[startTime]="meeting.start_time"
></os-meeting-time>
<b>{{ data.motion[0].number }}</b>
</span>
}
</mat-checkbox>
</div>
}
</div>
}
}
</div>
</mat-radio-button>
<mat-radio-button [value]="false">
{{ 'without identifier' | translate }}
</mat-radio-button>
</mat-radio-group>
</span>
} @else if (rowName === 'meeting') {
<span class="motion-forward-meeting-list">
@for (committee of committeesObservable | async; track committee) {
@if (committee.meetings?.length) {
<div>
<h4>{{ committee.name }}</h4>
@for (meeting of committee.meetings; track meeting) {
<div>
<mat-checkbox
[disabled]="
isActiveMeeting(meeting) || hasAlreadyBeenForwardedTo(meeting)
"
[value]="meeting.id"
[(ngModel)]="checkboxStateMap[meeting.id]"
(change)="onChangeCheckbox($event)"
>
{{ meeting.name }}
@if (meeting.start_time || meeting.end_time) {
<span>
&nbsp;&middot;&nbsp;
<os-meeting-time
[endTime]="meeting.end_time"
[startTime]="meeting.start_time"
></os-meeting-time>
</span>
}
</mat-checkbox>
</div>
}
</div>
}
}
</span>
}
</td>
</ng-container>

<tr *matRowDef="let myRowData; columns: ['label', 'radio']" mat-row></tr>
</table>
</mat-dialog-content>
<mat-dialog-actions>
<button color="primary" mat-button [disabled]="!selectedMeetings?.size" (click)="onSaveClicked()">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,13 @@
height: 33vh;
overflow-y: auto;
}

.motion-forward-radio-group {
display: flex;
flex-direction: column;
align-items: flex-start;
}

.state-margin {
margin-bottom: 4px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@ import { Component, Inject, OnInit } from '@angular/core';
import { MatCheckboxChange } from '@angular/material/checkbox';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { BehaviorSubject, Observable } from 'rxjs';
import { Id } from 'src/app/domain/definitions/key-types';
import { Id, Ids } from 'src/app/domain/definitions/key-types';
import { GetForwardingMeetingsPresenter, GetForwardingMeetingsPresenterMeeting } from 'src/app/gateways/presenter';
import { ActiveMeetingService } from 'src/app/site/pages/meetings/services/active-meeting.service';

import { ViewMotion } from '../../../../view-models';

export interface MotionForwardDialogReturnData {
meetingIds: Ids;
useOriginalSubmitter: boolean;
useOriginalNumber: boolean;
useOriginalVersion: boolean;
}

@Component({
selector: `os-motion-forward-dialog`,
templateUrl: `./motion-forward-dialog.component.html`,
Expand All @@ -25,12 +32,16 @@ export class MotionForwardDialogComponent implements OnInit {
return this.activeMeeting.meeting?.committee?.name;
}

public useOriginalSubmitter = true;
public useOriginalNumber = true;
public useOriginalVersion = true;

private readonly committeesSubject = new BehaviorSubject<GetForwardingMeetingsPresenter[]>([]);

public constructor(
@Inject(MAT_DIALOG_DATA)
public data: { motion: ViewMotion[]; forwardingMeetings: GetForwardingMeetingsPresenter[] },
private dialogRef: MatDialogRef<MotionForwardDialogComponent, Id[]>,
private dialogRef: MatDialogRef<MotionForwardDialogComponent, MotionForwardDialogReturnData>,
private activeMeeting: ActiveMeetingService
) {}

Expand All @@ -41,7 +52,12 @@ export class MotionForwardDialogComponent implements OnInit {
}

public onSaveClicked(): void {
this.dialogRef.close(Array.from(this.selectedMeetings));
this.dialogRef.close({
meetingIds: Array.from(this.selectedMeetings),
useOriginalSubmitter: this.useOriginalSubmitter,
useOriginalNumber: this.useOriginalNumber,
useOriginalVersion: this.useOriginalVersion
});
}

public onChangeCheckbox({ source, checked }: MatCheckboxChange): void {
Expand All @@ -60,6 +76,10 @@ export class MotionForwardDialogComponent implements OnInit {
return false;
}

public showActiveMeetingName(): string {
return this.activeMeeting?.meeting?.name;
}

private initStateMap(): void {
const meetings = this.committeesSubject.value.flatMap(committee => committee.meetings)!;
for (const meeting of meetings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ import { FormsModule } from '@angular/forms';
import { MatButtonModule } from '@angular/material/button';
import { MatCheckboxModule } from '@angular/material/checkbox';
import { MatDialogModule } from '@angular/material/dialog';
import { MatRadioModule } from '@angular/material/radio';
import { MatTableModule } from '@angular/material/table';
import { OpenSlidesTranslationModule } from 'src/app/site/modules/translations';
import { CommaSeparatedListingModule } from 'src/app/ui/modules/comma-separated-listing';
import { IconContainerModule } from 'src/app/ui/modules/icon-container';
import { MeetingTimeModule } from 'src/app/ui/modules/meeting-time/meeting-time.module';

Expand All @@ -17,9 +20,12 @@ import { MotionForwardDialogComponent } from './components/motion-forward-dialog
MatCheckboxModule,
MatDialogModule,
MatButtonModule,
MatRadioModule,
MatTableModule,
FormsModule,
IconContainerModule,
MeetingTimeModule,
CommaSeparatedListingModule,
OpenSlidesTranslationModule.forChild()
]
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,20 @@ import { BaseDialogService } from 'src/app/ui/base/base-dialog-service';
import { getMotionForwardDataSubscriptionConfig } from '../../../motions.subscription';
import { MotionFormatService } from '../../../services/common/motion-format.service';
import { ViewMotion } from '../../../view-models';
import { MotionForwardDialogComponent } from '../components/motion-forward-dialog/motion-forward-dialog.component';
import {
MotionForwardDialogComponent,
MotionForwardDialogReturnData
} from '../components/motion-forward-dialog/motion-forward-dialog.component';
import { MotionForwardDialogModule } from '../motion-forward-dialog.module';

@Injectable({
providedIn: MotionForwardDialogModule
})
export class MotionForwardDialogService extends BaseDialogService<MotionForwardDialogComponent, ViewMotion[], Ids> {
export class MotionForwardDialogService extends BaseDialogService<
MotionForwardDialogComponent,
ViewMotion[],
MotionForwardDialogReturnData
> {
public get forwardingCommitteesObservable(): Observable<(Partial<ViewCommittee> & Selectable)[]> {
return this._forwardingCommitteesSubject;
}
Expand Down Expand Up @@ -57,7 +64,9 @@ export class MotionForwardDialogService extends BaseDialogService<MotionForwardD
return !!this._forwardingMeetings.length;
}

public async open(data: ViewMotion[]): Promise<MatDialogRef<MotionForwardDialogComponent, Ids>> {
public async open(
data: ViewMotion[]
): Promise<MatDialogRef<MotionForwardDialogComponent, MotionForwardDialogReturnData>> {
await this.updateForwardMeetings();

const module = await import(`../motion-forward-dialog.module`).then(m => m.MotionForwardDialogModule);
Expand All @@ -77,15 +86,25 @@ export class MotionForwardDialogService extends BaseDialogService<MotionForwardD
return;
}
const dialogRef = await this.open(toForward);
const toMeetingIds = (await firstValueFrom(dialogRef.afterClosed())) as Ids;
const dialogData = (await firstValueFrom(dialogRef.afterClosed())) as MotionForwardDialogReturnData;
const toMeetingIds = dialogData?.meetingIds as Ids;
if (toMeetingIds) {
try {
const motionIds = toForward.map(motion => motion.id);
await this.modelRequest.fetch(getMotionForwardDataSubscriptionConfig(...motionIds));
const forwardMotions = toForward.map(motion =>
this.formatService.formatMotionForForward(this.repo.getViewModel(motion.id))
this.formatService.formatMotionForForward(
this.repo.getViewModel(motion.id),
dialogData.useOriginalVersion
)
);
const result = await this.repo.createForwarded(
toMeetingIds,
dialogData.useOriginalSubmitter,
dialogData.useOriginalNumber,
dialogData.useOriginalVersion,
...forwardMotions
);
const result = await this.repo.createForwarded(toMeetingIds, ...forwardMotions);
this.snackbar.open(this.createForwardingSuccessMessage(motions.length, result), `Ok`);
} catch (e: any) {
this.snackbar.open(e.toString(), `Ok`);
Expand Down
Loading