Merge pull request #4002 from FinnStutzenstein/aufrufliste

first work on the call list
This commit is contained in:
Jochen Saalfeld 2018-11-09 10:28:03 +01:00 committed by GitHub
commit 41caddd976
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 308 additions and 193 deletions

View File

@ -32,7 +32,7 @@
<!-- Main action button - desktop -->
<button mat-mini-fab color="accent" class="on-transition-fade" *ngIf="mainButton && !editMode && !vp.isMobile"
(click)="sendMainEvent()">
<mat-icon>{{ buttonIcon }}</mat-icon>
<mat-icon>{{ mainButtonIcon }}</mat-icon>
</button>
<!-- Save button -->
@ -47,5 +47,5 @@
<!-- Main action button - mobile-->
<button mat-fab class="head-button on-transition-fade" *ngIf="mainButton && !editMode && vp.isMobile" (click)=sendMainEvent()>
<mat-icon>{{ buttonIcon }}</mat-icon>
<mat-icon>{{ mainButtonIcon }}</mat-icon>
</button>

View File

@ -10,9 +10,6 @@ import { MainMenuService } from '../../../core/services/main-menu.service';
*
* Will translate the title automatically.
*
* Use `PlusButton=true` and `(plusButtonClicked)=myFunction()` if a plus button is needed
*
*
* ## Examples:
*
* ### Usage of the selector:
@ -21,7 +18,7 @@ import { MainMenuService } from '../../../core/services/main-menu.service';
* <os-head-bar
* [nav]="false"
* [mainButton]="opCanEdit()"
* [buttonIcon]="edit"
* [mainButtonIcon]="edit"
* [editMode]="editMotion"
* (mainEvent)="setEditMode(!editMotion)"
* (saveEvent)="saveMotion()">
@ -56,7 +53,7 @@ export class HeadBarComponent {
* Custom icon if necessary
*/
@Input()
public buttonIcon = 'add';
public mainButtonIcon = 'add';
/**
* Determine edit mode

View File

@ -5,19 +5,19 @@
</div>
</os-head-bar>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<!-- title column -->
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Topic </mat-header-cell>
<mat-cell *matCellDef="let item"> {{item.getListTitle()}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Topic</mat-header-cell>
<mat-cell *matCellDef="let item">{{ item.getListTitle() }}</mat-cell>
</ng-container>
<ng-container matColumnDef="duration">
<mat-header-cell *matHeaderCellDef mat-sort-header> Duration </mat-header-cell>
<mat-cell *matCellDef="let item"> {{item.duration}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Duration</mat-header-cell>
<mat-cell *matCellDef="let item">{{ item.duration }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['title', 'duration']"></mat-header-row>
<mat-row (click)='selectAgendaItem(row)' *matRowDef="let row; columns: ['title', 'duration']"></mat-row>
<mat-row (click)="selectAgendaItem(row)" *matRowDef="let row; columns: ['title', 'duration']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -25,12 +25,8 @@
<!-- <span translate>minutes</span> -->
<span>&nbsp;(</span> <span translate>Start time</span> <span>:&nbsp;{{ speaker.begin_time }})</span>
</div>
<button
mat-stroked-button
matTooltip="{{ 'Remove' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'"
(click)="onDeleteButton(speaker)"
>
<button mat-stroked-button matTooltip="{{ 'Remove' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'" (click)="onDeleteButton(speaker)">
<mat-icon>close</mat-icon>
</button>
</mat-list-item>
@ -42,12 +38,8 @@
<mat-icon class="speaking-icon">play_arrow</mat-icon>
<span class="speaking-name">{{ activeSpeaker }}</span>
<button
mat-stroked-button
matTooltip="{{ 'End speech' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'"
(click)="onStopButton()"
>
<button mat-stroked-button matTooltip="{{ 'End speech' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'" (click)="onStopButton()">
<mat-icon>mic_off</mat-icon>
<span translate>Stop</span>
</button>
@ -61,17 +53,13 @@
<ng-template let-item>
<div class="speak-action-buttons">
<mat-button-toggle-group>
<mat-button-toggle
matTooltip="{{ 'Begin speech' | translate }}"
(click)="onStartButton(item)"
>
<mat-button-toggle matTooltip="{{ 'Begin speech' | translate }}"
(click)="onStartButton(item)">
<mat-icon>mic</mat-icon>
<span translate>Start</span>
</mat-button-toggle>
<mat-button-toggle
matTooltip="{{ 'Mark speaker' | translate }}"
(click)="onMarkButton(item)"
>
<mat-button-toggle matTooltip="{{ 'Mark speaker' | translate }}"
(click)="onMarkButton(item)">
<mat-icon>{{ item.marked ? 'star' : 'star_border' }}</mat-icon>
</mat-button-toggle>
<mat-button-toggle matTooltip="{{ 'Remove' | translate }}" (click)="onDeleteButton(item)">

View File

@ -1,10 +1,5 @@
<os-head-bar
[nav]="false"
[goBack]="true"
[editMode]="editTopic"
(mainEvent)="setEditMode(!editTopic)"
(saveEvent)="saveTopic()"
>
<os-head-bar [nav]="false" [goBack]="true" [editMode]="editTopic"
(mainEvent)="setEditMode(!editTopic)" (saveEvent)="saveTopic()">
<!-- Title -->
<div class="title-slot">
<h2>
@ -47,21 +42,15 @@
<form *ngIf="editTopic" [formGroup]="topicForm" (ngSubmit)="saveTopic()" (keydown)="keyDownFunction($event)">
<div>
<mat-form-field>
<input
type="text"
matInput
osAutofocus
required
formControlName="title"
placeholder="{{ 'Title' | translate}}"
/>
<input type="text" matInput osAutofocus required
formControlName="title" placeholder="{{ 'Title' | translate}}"/>
<mat-error *ngIf="topicForm.invalid" translate>A name is required</mat-error>
</mat-form-field>
</div>
<div>
<mat-form-field>
<textarea matInput formControlName="text" placeholder="{{ 'Description ' | translate}}"></textarea>
<textarea matInput formControlName="text" placeholder="{{ 'Description ' | translate }}"></textarea>
</mat-form-field>
</div>

View File

@ -12,31 +12,31 @@
</div>
</os-head-bar>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<!-- name column -->
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Title </mat-header-cell>
<mat-cell *matCellDef="let assignment"> {{assignment.getTitle()}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
<mat-cell *matCellDef="let assignment">{{ assignment.getTitle() }}</mat-cell>
</ng-container>
<ng-container matColumnDef="phase">
<mat-header-cell *matHeaderCellDef mat-sort-header> Phase </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Phase</mat-header-cell>
<mat-cell *matCellDef="let assignment">
<mat-chip-list>
<mat-chip color="primary" selected>{{assignment.phase}} </mat-chip>
<mat-chip color="primary" selected>{{ assignment.phase }}</mat-chip>
</mat-chip-list>
</mat-cell>
</ng-container>
<ng-container matColumnDef="candidates">
<mat-header-cell *matHeaderCellDef mat-sort-header> Candidates </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Candidates</mat-header-cell>
<mat-cell *matCellDef="let assignment">
<mat-chip-list>
<mat-chip color="accent" selected>{{assignment.candidateAmount}}</mat-chip>
<mat-chip color="accent" selected>{{ assignment.candidateAmount }}</mat-chip>
</mat-chip-list>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['title', 'phase', 'candidates']"></mat-header-row>
<mat-row (click)='selectAssignment(row)' *matRowDef="let row; columns: ['title', 'phase', 'candidates']"></mat-row>
<mat-row (click)="selectAssignment(row)" *matRowDef="let row; columns: ['title', 'phase', 'candidates']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -13,7 +13,7 @@ import { MatSnackBar } from '@angular/material';
@Component({
selector: 'os-assignment-list',
templateUrl: './assignment-list.component.html',
styleUrls: ['./assignment-list.component.css']
styleUrls: ['./assignment-list.component.scss']
})
export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignment> implements OnInit {
/**

View File

@ -6,7 +6,6 @@
<mat-card class="os-card">
<div class="app-content" translate>
<h4> {{welcomeTitle | translate}} </h4>
<span> {{welcomeText | translate}} </span>

View File

@ -1,6 +1,5 @@
<form class="config-form-group" [formGroup]="form" *ngIf="configItem.inputType !== 'boolean'">
<mat-form-field>
<!-- Decides which input-type to take (i.e) date, select, textarea, input) -->
<ng-container [ngSwitch]="configItem.inputType">
<ng-container *ngSwitchCase="'datetimepicker'">
@ -50,9 +49,9 @@
<input matInput formControlName="value" [value]="configItem.value" [errorStateMatcher]="matcher"
[type]="formType(configItem.inputType)">
</ng-template>
</mat-form-field>
</form>
<div class="config-form-group" *ngIf="configItem.inputType === 'boolean'">
<mat-checkbox [checked]="configItem.value" (change)="onChange($event.checked)">
{{ configItem.label | translate }}

View File

@ -1,5 +1,4 @@
<main>
<mat-card class="os-card">
<h2 translate>Legal notice</h2>
</mat-card>

View File

@ -2,7 +2,8 @@
<mat-spinner *ngIf="inProcess"></mat-spinner>
<form [formGroup]="loginForm" class="login-form" (ngSubmit)="formLogin()">
<mat-form-field>
<input matInput osAutofocus required placeholder="User name" formControlName="username" [errorStateMatcher]="parentErrorStateMatcher">
<input matInput osAutofocus required placeholder="User name"
formControlName="username" [errorStateMatcher]="parentErrorStateMatcher">
</mat-form-field>
<br>
<mat-form-field>
@ -15,13 +16,15 @@
<!-- forgot password button -->
<br>
<button type="button" class='forgot-password-button' (click)="resetPassword()" mat-button>Forgot Password?</button>
<button type="button" class="forgot-password-button" (click)="resetPassword()" mat-button>Forgot Password?</button>
<!-- login button -->
<br>
<!-- TODO: Next to each other...-->
<button mat-raised-button color="primary" class='login-button' type="submit" translate>Login</button>
<button mat-raised-button *ngIf="areGuestsEnabled()" color="primary" class='login-button' type="button" (click)="guestLogin()"
translate>Login as Guest</button>
<button mat-raised-button color="primary" class="login-button" type="submit" translate>Login</button>
<button mat-raised-button *ngIf="areGuestsEnabled()" color="primary" class="login-button" type="button"
(click)="guestLogin()" translate>
Login as Guest
</button>
</form>
</div>

View File

@ -1,5 +1,4 @@
<main>
<mat-card class="os-card">
<h2 translate>Privacy Policy</h2>
</mat-card>

View File

@ -1,7 +1,7 @@
<!-- The actual form -->
<header>
<mat-toolbar class="login-logo-bar" color="primary">
<img src='/assets/img/openslides-logo-h-dark-transparent.svg' alt='OpenSlides-logo'>
<img src="/assets/img/openslides-logo-h-dark-transparent.svg" alt="OpenSlides-logo">
</mat-toolbar>
</header>
<main>

View File

@ -8,7 +8,7 @@
</mat-error>
</mat-form-field>
<br>
<button mat-raised-button color="primary" class='submit-button' [disabled]="newPasswordForm.invalid"
<button mat-raised-button color="primary" class="submit-button" [disabled]="newPasswordForm.invalid"
type="submit" translate>Reset password</button>
<button mat-button class="back-button" routerLink="/login" translate>Back to login</button>
</form>

View File

@ -8,7 +8,7 @@
</mat-error>
</mat-form-field>
<br>
<button mat-raised-button color="primary" class='submit-button' [disabled]="resetPasswordForm.invalid"
<button mat-raised-button color="primary" class="submit-button" [disabled]="resetPasswordForm.invalid"
type="submit" translate>Reset password</button>
<button mat-button class="back-button" routerLink="/login" translate>Back to login</button>
</form>

View File

@ -12,25 +12,26 @@
</div>
</os-head-bar>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<!-- name column -->
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file"> {{file.title}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell (click)="selectFile(file)" *matCellDef="let file">{{ file.title }}</mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef mat-sort-header> Group </mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file">
{{file.type}}
<mat-header-cell *matHeaderCellDef mat-sort-header>Group</mat-header-cell>
<mat-cell (click)="selectFile(file)" *matCellDef="let file">
{{ file.type }}
<br>
{{file.size}}
{{ file.size }}
</mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="download">
<mat-header-cell *matHeaderCellDef mat-sort-header> Download </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Download</mat-header-cell>
<mat-cell (click)="download(file)" *matCellDef="let file">
<mat-icon>save_alt</mat-icon>
</mat-cell>
@ -43,7 +44,7 @@
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>
<mat-menu #mediafilesMenu="matMenu">
<button mat-menu-item class='red-warning-text' (click)="deleteAllFiles()">
<button mat-menu-item class="red-warning-text" (click)="deleteAllFiles()">
<mat-icon>delete</mat-icon>
<span translate>Delete all files</span>
</button>

View File

@ -0,0 +1,26 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CallListComponent } from './call-list.component';
import { E2EImportsModule } from 'e2e-imports.module';
describe('CallListComponent', () => {
let component: CallListComponent;
let fixture: ComponentFixture<CallListComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [E2EImportsModule],
declarations: [CallListComponent]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CallListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,17 @@
<os-head-bar [nav]="false">
<!-- Title -->
<div class="title-slot">
<h2 translate>Call list</h2>
</div>
<div class="menu-slot">
<button mat-button (click)="save()">
<strong translate class="upper">Save</strong>
</button>
</div>
</os-head-bar>
<mat-card>
<os-sorting-list #sorter [input]="motions">
</os-sorting-list>
</mat-card>

View File

@ -0,0 +1,68 @@
import { Component, ViewChild } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { TranslateService } from '@ngx-translate/core';
import { BaseViewComponent } from '../../../base/base-view';
import { MatSnackBar } from '@angular/material';
import { MotionRepositoryService } from '../../services/motion-repository.service';
import { ViewMotion } from '../../models/view-motion';
import { SortingListComponent } from '../../../../shared/components/sorting-list/sorting-list.component';
import { Router, ActivatedRoute } from '@angular/router';
/**
* Sort view for the call list.
*/
@Component({
selector: 'os-call-list',
templateUrl: './call-list.component.html'
})
export class CallListComponent extends BaseViewComponent {
/**
* All motions sorted first by weight, then by id.
*/
public motions: ViewMotion[];
/**
* The sort component
*/
@ViewChild('sorter')
public sorter: SortingListComponent;
/**
* Updates the motions member, and sorts it.
* @param title
* @param translate
* @param matSnackBar
* @param motionRepo
*/
public constructor(
title: Title,
translate: TranslateService,
matSnackBar: MatSnackBar,
private motionRepo: MotionRepositoryService,
private router: Router,
private route: ActivatedRoute
) {
super(title, translate, matSnackBar);
this.motionRepo.getViewModelListObservable().subscribe(motions => {
this.motions = motions.sort((a, b) => {
if (a.weight !== b.weight) {
return a.weight - b.weight;
} else {
return a.id - b.id;
}
});
});
}
/**
* Saves the new motion order to the server.
*/
public save(): void {
this.motionRepo.sortMotions(this.sorter.array.map(s => ({ id: s.id }))).then(() => {
this.router.navigate(['../'], { relativeTo: this.route });
}, this.raiseError);
}
}

View File

@ -1,12 +1,7 @@
<div class="text"></div>
<ul class="change-recommendation-list" *ngIf="showChangeRecommendations">
<li *ngFor="let reco of changeRecommendations"
[title]="reco.getTitle()"
[style.top]="calcRecoTop(reco)"
[style.height]="calcRecoHeight(reco)"
[class.delete]="recoIsDeletion(reco)"
[class.insert]="recoIsInsertion(reco)"
[class.replace]="recoIsReplacement(reco)"
(click)="gotoReco(reco)"
></li>
<li *ngFor="let reco of changeRecommendations" [title]="reco.getTitle()"
[style.top]="calcRecoTop(reco)" [style.height]="calcRecoHeight(reco)"
[class.delete]="recoIsDeletion(reco)" [class.insert]="recoIsInsertion(reco)"
[class.replace]="recoIsReplacement(reco)" (click)="gotoReco(reco)"></li>
</ul>

View File

@ -1,5 +1,5 @@
<os-head-bar [mainButton]="opCanEdit()" buttonIcon="edit" [nav]="false" [editMode]="editMotion" (mainEvent)="setEditMode(!editMotion)"
(saveEvent)="saveMotion()">
<os-head-bar [mainButton]="opCanEdit()" mainButtonIcon="edit" [nav]="false" [editMode]="editMotion"
(mainEvent)="setEditMode(!editMotion)" (saveEvent)="saveMotion()">
<!-- Title -->
<div class="title-slot">
@ -73,7 +73,7 @@
<h2 *ngIf="editMotion">{{ contentForm.get("title").value }}</h2>
</div>
<ng-container *ngIf="vp.isMobile ; then mobileView; else desktopView"></ng-container>
<ng-container *ngIf="vp.isMobile; then mobileView; else desktopView"></ng-container>
<ng-template #mobileView>
<mat-accordion multi='true' class='on-transition-fade'>
@ -298,7 +298,6 @@
<textarea matInput placeholder="{{ 'Motion text' | translate }}" formControlName='text' [value]='motionCopy.text' required></textarea>
</mat-form-field>
<!-- Reason -->
<div *ngIf="motion && motion.reason || editMotion">
<h5 *ngIf="!editMotion" translate>Reason</h5>

View File

@ -12,7 +12,7 @@
</div>
</os-head-bar>
<div class='custom-table-header on-transition-fade'>
<div class="custom-table-header on-transition-fade">
<button mat-button>
<span translate>SORT</span>
</button>
@ -21,13 +21,13 @@
</button>
</div>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<!-- identifier column -->
<ng-container matColumnDef="identifier">
<mat-header-cell *matHeaderCellDef mat-sort-header>Identifier</mat-header-cell>
<mat-cell *matCellDef="let motion">
<div class='innerTable'>
{{motion.identifier}}
<div class="innerTable">
{{ motion.identifier }}
</div>
</mat-cell>
</ng-container>
@ -36,12 +36,12 @@
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
<mat-cell *matCellDef="let motion">
<div class='innerTable'>
<span class='motion-list-title'>{{motion.title}}</span>
<div class="innerTable">
<span class="motion-list-title">{{ motion.title }}</span>
<br>
<span class='motion-list-from'>
<span class="motion-list-from">
<span translate>by</span>
{{motion.submitters}}
{{ motion.submitters }}
</span>
</div>
</mat-cell>
@ -51,20 +51,19 @@
<ng-container matColumnDef="state">
<mat-header-cell *matHeaderCellDef mat-sort-header>State</mat-header-cell>
<mat-cell *matCellDef="let motion">
<div *ngIf='isDisplayIcon(motion.state) && motion.state' class='innerTable'>
<mat-icon>{{getStateIcon(motion.state)}}</mat-icon>
<div *ngIf="isDisplayIcon(motion.state) && motion.state" class="innerTable">
<mat-icon>{{ getStateIcon(motion.state) }}</mat-icon>
</div>
</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="columnsToDisplayMinWidth"></mat-header-row>
<mat-row (click)='selectMotion(row)' *matRowDef="let row; columns: columnsToDisplayMinWidth"></mat-row>
<mat-row (click)="selectMotion(row)" *matRowDef="let row; columns: columnsToDisplayMinWidth"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>
<mat-menu #motionListMenu="matMenu">
<button mat-menu-item (click)="downloadMotions()">
<mat-icon>archive</mat-icon>
<span translate>Export ...</span>
@ -85,4 +84,8 @@
<span translate>Statute paragraphs</span>
</button>
<button mat-menu-item *osPerms="'motions.can_manage'" routerLink="call-list">
<mat-icon>sort</mat-icon>
<span translate>Call list</span>
</button>
</mat-menu>

View File

@ -60,7 +60,14 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
super.setTitle('Motions');
this.initTable();
this.repo.getViewModelListObservable().subscribe(newMotions => {
this.dataSource.data = newMotions;
// TODO: This is for testing purposes. Can be removed with #3963
this.dataSource.data = newMotions.sort((a, b) => {
if (a.weight !== b.weight) {
return a.weight - b.weight;
} else {
return a.id - b.id;
}
});
});
}

View File

@ -1,5 +1,4 @@
<os-head-bar [nav]="false" [mainButton]="true" (mainEvent)="onPlusButton()">
<!-- Title -->
<div class="title-slot">
<h2 translate>Statute paragraphs</h2>
@ -11,10 +10,8 @@
<mat-icon>more_vert</mat-icon>
</button>
</div>
</os-head-bar>
<div class="head-spacer"></div>
<mat-card *ngIf="statuteParagraphToCreate">
<mat-card-title translate>Create new statute paragraph</mat-card-title>
@ -48,6 +45,7 @@
</button>
</mat-card-actions>
</mat-card>
<mat-accordion class="os-card">
<mat-expansion-panel *ngFor="let statuteParagraph of this.statuteParagraphs" (opened)="openId = statuteParagraph.id"
(closed)="panelClosed(statuteParagraph)" [expanded]="openId === statuteParagraph.id" multiple="false">
@ -103,6 +101,7 @@
</mat-action-row>
</mat-expansion-panel>
</mat-accordion>
<mat-card *ngIf="statuteParagraphs.length === 0">
<mat-card-content>
<div class="no-content" translate>No statute paragraphs</div>

View File

@ -84,6 +84,14 @@ export class ViewMotion extends BaseViewModel {
return this.motion ? this.motion.reason : null;
}
public get weight(): number {
return this.motion ? this.motion.weight : null;
}
public get sort_parent_id(): number {
return this.motion ? this.motion.sort_parent_id : null;
}
public get category(): Category {
return this._category;
}
@ -133,7 +141,9 @@ export class ViewMotion extends BaseViewModel {
}
public get possibleRecommendations(): WorkflowState[] {
return this.workflow ? this.workflow.states.filter(recommendation => recommendation.recommendation_label !== undefined) : null;
return this.workflow
? this.workflow.states.filter(recommendation => recommendation.recommendation_label !== undefined)
: null;
}
public get origin(): string {
@ -179,10 +189,9 @@ export class ViewMotion extends BaseViewModel {
this.highlightedLine = null;
}
// TODO aware of issues here?
public getTitle(): string {
if (this.category) {
return this.category.prefix + ' - ' + this.title;
if (this.identifier) {
return this.identifier + ' - ' + this.title;
}
return this.title;
}

View File

@ -6,12 +6,14 @@ import { CategoryListComponent } from './components/category-list/category-list.
import { MotionCommentSectionListComponent } from './components/motion-comment-section-list/motion-comment-section-list.component';
import { StatuteParagraphListComponent } from './components/statute-paragraph-list/statute-paragraph-list.component';
import { SpeakerListComponent } from '../agenda/components/speaker-list/speaker-list.component';
import { CallListComponent } from './components/call-list/call-list.component';
const routes: Routes = [
{ path: '', component: MotionListComponent },
{ path: 'category', component: CategoryListComponent },
{ path: 'comment-section', component: MotionCommentSectionListComponent },
{ path: 'statute-paragraphs', component: StatuteParagraphListComponent },
{ path: 'call-list', component: CallListComponent },
{ path: 'new', component: MotionDetailComponent },
{ path: ':id', component: MotionDetailComponent },
{ path: ':id/speakers', component: SpeakerListComponent }

View File

@ -14,6 +14,7 @@ import { MotionDetailDiffComponent } from './components/motion-detail-diff/motio
import { MotionCommentsComponent } from './components/motion-comments/motion-comments.component';
import { MetaTextBlockComponent } from './components/meta-text-block/meta-text-block.component';
import { PersonalNoteComponent } from './components/personal-note/personal-note.component';
import { CallListComponent } from './components/call-list/call-list.component';
@NgModule({
imports: [CommonModule, MotionsRoutingModule, SharedModule],
@ -28,7 +29,8 @@ import { PersonalNoteComponent } from './components/personal-note/personal-note.
MotionDetailDiffComponent,
MotionCommentsComponent,
MetaTextBlockComponent,
PersonalNoteComponent
PersonalNoteComponent,
CallListComponent
],
entryComponents: [
MotionChangeRecommendationComponent,

View File

@ -149,6 +149,16 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
return this.configService.get('motions_recommendations_by');
}
/**
* Sorts motions for the call list by the given list of ids (as identifiables with
* the format `{id: <id>}`).
* @param motionIds all motion ids in the new order.
*/
public async sortMotions(motionIds: Identifiable[]): Promise<void> {
const url = '/rest/motions/motion/sort/';
await this.httpService.post(url, { nodes: motionIds });
}
/**
* Format the motion text using the line numbering and change
* reco algorithm.

View File

@ -1,11 +1,12 @@
<os-head-bar [mainButton]="true" [nav]="true" [editMode]="editTag" (mainEvent)="setEditMode(!editTag)" (saveEvent)="saveTag()">
<os-head-bar [mainButton]="true" [nav]="true" [editMode]="editTag"
(mainEvent)="setEditMode(!editTag)" (saveEvent)="saveTag()">
<!-- Title -->
<div class="title-slot">
<h2 *ngIf="!editTag && !newTag" translate>Tags</h2>
<form *ngIf="editTag" [formGroup]="tagForm" (ngSubmit)="saveTag()" (keydown)="keyDownFunction($event)">
<mat-form-field>
<input type="text" matInput osAutofocus required formControlName="name" placeholder="{{ 'New tag name' | translate}}">
<input type="text" matInput osAutofocus required formControlName="name"
placeholder="{{ 'New tag name' | translate}}">
<mat-error *ngIf="tagForm.invalid" translate>Required</mat-error>
</mat-form-field>
</form>
@ -20,13 +21,13 @@
</div>
</os-head-bar>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let tag"> {{tag.getTitle()}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let tag">{{ tag.getTitle() }}</mat-cell>
</ng-container>
<mat-header-row *matHeaderRowDef="['name']"></mat-header-row>
<mat-row (click)='selectTag(row)' *matRowDef="let row; columns: ['name']"></mat-row>
<mat-row (click)="selectTag(row)" *matRowDef="let row; columns: ['name']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -1,12 +1,13 @@
<os-head-bar [mainButton]="true" [nav]="false" [editMode]="editGroup" (mainEvent)="setEditMode(!editGroup)" (saveEvent)="saveGroup()">
<os-head-bar [mainButton]="true" [nav]="false" [editMode]="editGroup"
(mainEvent)="setEditMode(!editGroup)" (saveEvent)="saveGroup()">
<!-- Title -->
<div class="title-slot">
<h2 *ngIf="!editGroup && !newGroup" translate>Groups</h2>
<form *ngIf="editGroup" [formGroup]="groupForm" (ngSubmit)="saveGroup()" (keydown)="keyDownFunction($event)">
<mat-form-field>
<input type="text" matInput osAutofocus required formControlName="name" placeholder="{{ 'New group name' | translate}}">
<input type="text" matInput osAutofocus required formControlName="name"
placeholder="{{ 'New group name' | translate}}">
<mat-error *ngIf="groupForm.invalid" translate>Required</mat-error>
</mat-form-field>
</form>
@ -35,7 +36,7 @@
</mat-expansion-panel-header>
<div class="scrollable-perm-matrix">
<table mat-table class='on-transition-fade' [dataSource]="getTableDataSource(app.permissions)">
<table mat-table class="on-transition-fade" [dataSource]="getTableDataSource(app.permissions)">
<ng-container matColumnDef="perm" sticky>
<mat-header-cell *matHeaderCellDef translate>Permissions</mat-header-cell>
<mat-cell *matCellDef="let perm">
@ -53,7 +54,7 @@
<mat-cell *matCellDef="let perm">
<div class="inner-table">
<mat-checkbox *ngIf="group.id !== 2" [checked]="group.hasPermission(perm.value)"
(change)='togglePerm(group, perm.value)'></mat-checkbox>
(change)="togglePerm(group, perm.value)"></mat-checkbox>
<mat-checkbox *ngIf="group.id === 2" [checked]="true" [disabled]="true"></mat-checkbox>
</div>
</mat-cell>

View File

@ -1,16 +1,15 @@
<os-head-bar [mainButton]="isAllowed('manage')" buttonIcon="edit" [nav]="false" [editMode]="editUser" (mainEvent)="setEditMode(!editUser)"
(saveEvent)="saveUser()">
<os-head-bar [mainButton]="isAllowed('manage')" mainButtonIcon="edit" [nav]="false" [editMode]="editUser"
(mainEvent)="setEditMode(!editUser)" (saveEvent)="saveUser()">
<!-- Title -->
<div class="title-slot">
<h2 *ngIf='editUser'>
{{personalInfoForm.get('title').value}}
{{personalInfoForm.get('first_name').value}}
{{personalInfoForm.get('last_name').value}}
<h2 *ngIf="editUser">
{{ personalInfoForm.get('title').value }}
{{ personalInfoForm.get('first_name').value }}
{{ personalInfoForm.get('last_name').value }}
</h2>
<h2 *ngIf='!editUser'>
{{user.full_name}}
<h2 *ngIf="!editUser">
{{ user.full_name }}
</h2>
</div>
@ -22,7 +21,7 @@
</div>
<mat-menu #userExtraMenu="matMenu">
<button mat-menu-item class="red-warning-text" (click)='deleteUserButton()'>
<button mat-menu-item class="red-warning-text" (click)="deleteUserButton()">
<mat-icon>delete</mat-icon>
<span translate>Delete</span>
</button>
@ -30,34 +29,34 @@
</os-head-bar>
<mat-card class="os-card" *osPerms="'users.can_see_name'">
<form [ngClass]="{'mat-form-field-enabled': editUser}" [formGroup]='personalInfoForm' (ngSubmit)='saveUser()' *ngIf="user">
<form [ngClass]="{'mat-form-field-enabled': editUser}" [formGroup]="personalInfoForm" (ngSubmit)="saveUser()" *ngIf="user">
<!-- <h3 translate>Personal Data</h3> -->
<div *ngIf='isAllowed("seeName")'>
<div *ngIf="isAllowed('seeName')">
<!-- Title -->
<mat-form-field class='form30 distance force-min-with' *ngIf='user.title || editUser && isAllowed("manage")'>
<input type='text' matInput osAutofocus placeholder='{{"Title" | translate}}' formControlName='title'
[value]='user.title'>
<mat-form-field class="form30 distance force-min-with" *ngIf="user.title || editUser && isAllowed('manage')">
<input type="text" matInput osAutofocus placeholder="{{ 'Title' | translate }}" formControlName="title"
[value]="user.title">
</mat-form-field>
<!-- First name -->
<mat-form-field class='form30 distance force-min-with' *ngIf='user.first_name || editUser && isAllowed("manage")'>
<input type='text' matInput placeholder='{{"Given name" | translate}}' formControlName='first_name'
[value]='user.first_name'>
<mat-form-field class="form30 distance force-min-with" *ngIf="user.first_name || editUser && isAllowed('manage')">
<input type="text" matInput placeholder="{{ 'Given name' | translate }}" formControlName="first_name"
[value]="user.first_name">
</mat-form-field>
<!-- Last name -->
<mat-form-field class='form30 force-min-with' *ngIf='user.last_name || editUser && isAllowed("manage")'>
<input type='text' matInput placeholder='{{"Surname" | translate}}' formControlName='last_name'
[value]='user.last_name'>
<mat-form-field class="form30 force-min-with" *ngIf="user.last_name || editUser && isAllowed('manage')">
<input type="text" matInput placeholder="{{ 'Surname' | translate }}" formControlName="last_name"
[value]="user.last_name">
</mat-form-field>
</div>
<div *ngIf='isAllowed("seePersonal")'>
<div *ngIf="isAllowed('seePersonal')">
<!-- E-Mail -->
<mat-form-field class='form100' *ngIf="user.email || editUser">
<input type='email' matInput placeholder='{{"Email" | translate}}' name="email" formControlName='email'
[value]='user.email'>
<mat-error *ngIf="personalInfoForm.get('email').hasError('email')">
<mat-form-field class="form100" *ngIf="user.email || editUser">
<input type="email" matInput placeholder="{{ 'Email' | translate }}" name="email" formControlName="email"
[value]="user.email">
<mat-error *ngIf="personalInfoForm.get('email').hasError('email')" translate>
Please enter a valid email address
</mat-error>
</mat-form-field>
@ -65,79 +64,83 @@
<div>
<!-- Strucuture Level -->
<mat-form-field class='form70 distance' *ngIf='user.structure_level || editUser && isAllowed("manage")'>
<input type='text' matInput placeholder='{{"Structure level" | translate}}' formControlName='structure_level'
[value]='user.structure_level'>
<mat-form-field class="form70 distance" *ngIf="user.structure_level || editUser && isAllowed('manage')">
<input type="text" matInput placeholder="{{ 'Structure level' | translate }}" formControlName="structure_level"
[value]="user.structure_level">
</mat-form-field>
<!-- Partizipant Number -->
<mat-form-field class='form20 force-min-with' *ngIf='user.participant_number || editUser && isAllowed("manage")'>
<input type='text' matInput placeholder='{{"Participant number" | translate}}' formControlName='number'
[value]='user.participant_number'>
<mat-form-field class="form20 force-min-with" *ngIf="user.participant_number || editUser && isAllowed('manage')">
<input type="text" matInput placeholder="{{ 'Participant number' | translate }}" formControlName="number"
[value]="user.participant_number">
</mat-form-field>
</div>
<div>
<!-- Groups -->
<mat-form-field class='form100' *ngIf="user.groups && user.groups.length > 0 || editUser">
<mat-select placeholder='{{"Groups" | translate}}' formControlName='groups_id' multiple>
<mat-option *ngFor="let group of groups" [value]="group.id">{{group}}</mat-option>
<mat-form-field class="form100" *ngIf="user.groups && user.groups.length > 0 || editUser">
<mat-select placeholder="{{ 'Groups' | translate }}" formControlName="groups_id" multiple>
<mat-option *ngFor="let group of groups" [value]="group.id">{{ group }}</mat-option>
</mat-select>
</mat-form-field>
</div>
<div *ngIf='isAllowed("manage")'>
<div *ngIf="isAllowed('manage')">
<!-- Initial Password -->
<mat-form-field class='form100'>
<input matInput placeholder='{{"Initial password" | translate}}' formControlName='default_password'
[value]='user.default_password'>
<mat-form-field class="form100">
<input matInput placeholder="{{ 'Initial password' | translate }}" formControlName="default_password"
[value]="user.default_password">
<mat-hint align="end">Generate</mat-hint>
<button type="button" mat-button matSuffix mat-icon-button [disabled]='!newUser' (click)='generatePassword()'>
<button type="button" mat-button matSuffix mat-icon-button [disabled]="!newUser"
(click)="generatePassword()">
<mat-icon>sync_problem</mat-icon>
</button>
</mat-form-field>
</div>
<div *ngIf='isAllowed("seePersonal")'>
<div *ngIf="isAllowed('seePersonal')">
<!-- About me -->
<!-- TODO: Needs Rich Text Editor -->
<mat-form-field class='form100' *ngIf="user.about_me || editUser">
<textarea formControlName='about_me' matInput placeholder='{{"About me" | translate}}' [value]='user.about_me'></textarea>
<mat-form-field class="form100" *ngIf="user.about_me || editUser">
<textarea formControlName="about_me" matInput placeholder="{{ 'About me' | translate }}"
[value]="user.about_me"></textarea>
</mat-form-field>
</div>
<div *ngIf='isAllowed("seePersonal")'>
<div *ngIf="isAllowed('seePersonal')">
<!-- username -->
<mat-form-field class='form100' *ngIf="user.username || editUser">
<input type='text' matInput placeholder='{{"Username" | translate}}' formControlName='username' [value]='user.username'>
<mat-form-field class="form100" *ngIf="user.username || editUser">
<input type="text" matInput placeholder="{{ 'Username' | translate }}" formControlName="username"
[value]="user.username">
</mat-form-field>
</div>
<div *ngIf='isAllowed("seeExtra")'>
<div *ngIf="isAllowed('seeExtra')">
<!-- Comment -->
<mat-form-field class='form100' *ngIf="user.comment || editUser">
<input matInput placeholder='{{"Comment"| translate}}' formControlName='comment' [value]='user.comment'>
<mat-form-field class="form100" *ngIf="user.comment || editUser">
<input matInput placeholder="{{ 'Comment' | translate }}" formControlName="comment" [value]="user.comment">
<mat-hint translate>Only for internal notes.</mat-hint>
</mat-form-field>
</div>
<div *ngIf='isAllowed("seeExtra")'>
<div *ngIf="isAllowed('seeExtra')">
<!-- Present? -->
<mat-checkbox formControlName='is_present' matTooltip='{{"Designates whether this user is in the room." | translate}} '
[value]='user.is_present'>
<mat-checkbox formControlName="is_present"
matTooltip="{{ 'Designates whether this user is in the room.' | translate }}" [value]="user.is_present">
<span translate>Is present</span>
</mat-checkbox>
<!-- Active? -->
<mat-checkbox *osPerms="'users.can_see_extra_data'" formControlName='is_active' matTooltip='{{"Designates whether this user should be treated as active. Unselect this instead of deleting the account." | translate}}'
[value]='user.is_active'>
<mat-checkbox *osPerms="'users.can_see_extra_data'" formControlName="is_active" [value]="user.is_active"
matTooltip="{{ 'Designates whether this user should be treated as active. Unselect this instead of deleting the account.' | translate }}">
<span translate>Is active</span>
</mat-checkbox>
<!-- Commitee? -->
<mat-checkbox formControlName='is_committee' matTooltip='{{"Designates whether this user should be treated as a committee." | translate}}'
[value]='user.is_committee'>
<mat-checkbox formControlName="is_committee" [value]="user.is_committee"
matTooltip="{{ 'Designates whether this user should be treated as a committee.' | translate }}">
<span translate>Is a committee</span>
</mat-checkbox>
</div>
</form>
</mat-card>

View File

@ -12,7 +12,7 @@
</div>
</os-head-bar>
<div class='custom-table-header on-transition-fade'>
<div class="custom-table-header on-transition-fade">
<button mat-button>
<span translate>SORT</span>
</button>
@ -21,27 +21,27 @@
</button>
</div>
<mat-table class='os-listview-table on-transition-fade' [dataSource]="dataSource" matSort>
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
<!-- name column -->
<ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.full_name}} </mat-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let user">{{ user.full_name }}</mat-cell>
</ng-container>
<!-- prefix column -->
<ng-container matColumnDef="group">
<mat-header-cell *matHeaderCellDef mat-sort-header> Group </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Group</mat-header-cell>
<mat-cell *matCellDef="let user">
<div class='groupsCell'>
<span *ngIf="user.groups.length > 0">
<mat-icon>people</mat-icon>
{{user.groups}}
{{ user.groups }}
</span>
<br *ngIf="user.groups && user.structureLevel">
<span *ngIf="user.structureLevel">
<mat-icon>flag</mat-icon>
{{user.structure_level}}
{{ user.structure_level }}
</span>
</div>
</mat-cell>
@ -49,7 +49,7 @@
<!-- Presence column -->
<ng-container matColumnDef="presence">
<mat-header-cell *matHeaderCellDef mat-sort-header> Presence </mat-header-cell>
<mat-header-cell *matHeaderCellDef mat-sort-header>Presence</mat-header-cell>
<mat-cell *matCellDef="let user">
<div *ngIf="user.is_active">
<mat-icon>check_box</mat-icon>
@ -59,7 +59,7 @@
</ng-container>
<mat-header-row *matHeaderRowDef="['name', 'group', 'presence']"></mat-header-row>
<mat-row (click)='selectUser(row)' *matRowDef="let row; columns: ['name', 'group', 'presence']"></mat-row>
<mat-row (click)="selectUser(row)" *matRowDef="let row; columns: ['name', 'group', 'presence']"></mat-row>
</mat-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>

View File

@ -289,7 +289,6 @@ class MotionViewSet(ModelViewSet):
Note: This view is not tested! Maybe needs to be refactored. Add documentation
abou the data to be send.
"""
raise ValidationError({'detail': _('This view needs testing and refactoring!')})
nodes = request.data.get('nodes', [])
sort_parent_id = request.data.get('sort_parent_id')
motions = []