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

View File

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

View File

@ -5,19 +5,19 @@
</div> </div>
</os-head-bar> </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 --> <!-- title column -->
<ng-container matColumnDef="title"> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Topic </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Topic</mat-header-cell>
<mat-cell *matCellDef="let item"> {{item.getListTitle()}} </mat-cell> <mat-cell *matCellDef="let item">{{ item.getListTitle() }}</mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="duration"> <ng-container matColumnDef="duration">
<mat-header-cell *matHeaderCellDef mat-sort-header> Duration </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Duration</mat-header-cell>
<mat-cell *matCellDef="let item"> {{item.duration}} </mat-cell> <mat-cell *matCellDef="let item">{{ item.duration }}</mat-cell>
</ng-container> </ng-container>
<mat-header-row *matHeaderRowDef="['title', 'duration']"></mat-header-row> <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-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator> <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 translate>minutes</span> -->
<span>&nbsp;(</span> <span translate>Start time</span> <span>:&nbsp;{{ speaker.begin_time }})</span> <span>&nbsp;(</span> <span translate>Start time</span> <span>:&nbsp;{{ speaker.begin_time }})</span>
</div> </div>
<button <button mat-stroked-button matTooltip="{{ 'Remove' | translate }}"
mat-stroked-button *osPerms="'agenda.can_manage_list_of_speakers'" (click)="onDeleteButton(speaker)">
matTooltip="{{ 'Remove' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'"
(click)="onDeleteButton(speaker)"
>
<mat-icon>close</mat-icon> <mat-icon>close</mat-icon>
</button> </button>
</mat-list-item> </mat-list-item>
@ -42,12 +38,8 @@
<mat-icon class="speaking-icon">play_arrow</mat-icon> <mat-icon class="speaking-icon">play_arrow</mat-icon>
<span class="speaking-name">{{ activeSpeaker }}</span> <span class="speaking-name">{{ activeSpeaker }}</span>
<button <button mat-stroked-button matTooltip="{{ 'End speech' | translate }}"
mat-stroked-button *osPerms="'agenda.can_manage_list_of_speakers'" (click)="onStopButton()">
matTooltip="{{ 'End speech' | translate }}"
*osPerms="'agenda.can_manage_list_of_speakers'"
(click)="onStopButton()"
>
<mat-icon>mic_off</mat-icon> <mat-icon>mic_off</mat-icon>
<span translate>Stop</span> <span translate>Stop</span>
</button> </button>
@ -61,17 +53,13 @@
<ng-template let-item> <ng-template let-item>
<div class="speak-action-buttons"> <div class="speak-action-buttons">
<mat-button-toggle-group> <mat-button-toggle-group>
<mat-button-toggle <mat-button-toggle matTooltip="{{ 'Begin speech' | translate }}"
matTooltip="{{ 'Begin speech' | translate }}" (click)="onStartButton(item)">
(click)="onStartButton(item)"
>
<mat-icon>mic</mat-icon> <mat-icon>mic</mat-icon>
<span translate>Start</span> <span translate>Start</span>
</mat-button-toggle> </mat-button-toggle>
<mat-button-toggle <mat-button-toggle matTooltip="{{ 'Mark speaker' | translate }}"
matTooltip="{{ 'Mark speaker' | translate }}" (click)="onMarkButton(item)">
(click)="onMarkButton(item)"
>
<mat-icon>{{ item.marked ? 'star' : 'star_border' }}</mat-icon> <mat-icon>{{ item.marked ? 'star' : 'star_border' }}</mat-icon>
</mat-button-toggle> </mat-button-toggle>
<mat-button-toggle matTooltip="{{ 'Remove' | translate }}" (click)="onDeleteButton(item)"> <mat-button-toggle matTooltip="{{ 'Remove' | translate }}" (click)="onDeleteButton(item)">

View File

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

View File

@ -12,31 +12,31 @@
</div> </div>
</os-head-bar> </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 --> <!-- name column -->
<ng-container matColumnDef="title"> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Title </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
<mat-cell *matCellDef="let assignment"> {{assignment.getTitle()}} </mat-cell> <mat-cell *matCellDef="let assignment">{{ assignment.getTitle() }}</mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="phase"> <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-cell *matCellDef="let assignment">
<mat-chip-list> <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-chip-list>
</mat-cell> </mat-cell>
</ng-container> </ng-container>
<ng-container matColumnDef="candidates"> <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-cell *matCellDef="let assignment">
<mat-chip-list> <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-chip-list>
</mat-cell> </mat-cell>
</ng-container> </ng-container>
<mat-header-row *matHeaderRowDef="['title', 'phase', 'candidates']"></mat-header-row> <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-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator> <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({ @Component({
selector: 'os-assignment-list', selector: 'os-assignment-list',
templateUrl: './assignment-list.component.html', templateUrl: './assignment-list.component.html',
styleUrls: ['./assignment-list.component.css'] styleUrls: ['./assignment-list.component.scss']
}) })
export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignment> implements OnInit { export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignment> implements OnInit {
/** /**

View File

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

View File

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

View File

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

View File

@ -2,7 +2,8 @@
<mat-spinner *ngIf="inProcess"></mat-spinner> <mat-spinner *ngIf="inProcess"></mat-spinner>
<form [formGroup]="loginForm" class="login-form" (ngSubmit)="formLogin()"> <form [formGroup]="loginForm" class="login-form" (ngSubmit)="formLogin()">
<mat-form-field> <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> </mat-form-field>
<br> <br>
<mat-form-field> <mat-form-field>
@ -15,13 +16,15 @@
<!-- forgot password button --> <!-- forgot password button -->
<br> <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 --> <!-- login button -->
<br> <br>
<!-- TODO: Next to each other...--> <!-- TODO: Next to each other...-->
<button mat-raised-button color="primary" class='login-button' type="submit" translate>Login</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()" <button mat-raised-button *ngIf="areGuestsEnabled()" color="primary" class="login-button" type="button"
translate>Login as Guest</button> (click)="guestLogin()" translate>
Login as Guest
</button>
</form> </form>
</div> </div>

View File

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

View File

@ -1,7 +1,7 @@
<!-- The actual form --> <!-- The actual form -->
<header> <header>
<mat-toolbar class="login-logo-bar" color="primary"> <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> </mat-toolbar>
</header> </header>
<main> <main>

View File

@ -8,7 +8,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<br> <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> type="submit" translate>Reset password</button>
<button mat-button class="back-button" routerLink="/login" translate>Back to login</button> <button mat-button class="back-button" routerLink="/login" translate>Back to login</button>
</form> </form>

View File

@ -8,7 +8,7 @@
</mat-error> </mat-error>
</mat-form-field> </mat-form-field>
<br> <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> type="submit" translate>Reset password</button>
<button mat-button class="back-button" routerLink="/login" translate>Back to login</button> <button mat-button class="back-button" routerLink="/login" translate>Back to login</button>
</form> </form>

View File

@ -12,25 +12,26 @@
</div> </div>
</os-head-bar> </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 --> <!-- name column -->
<ng-container matColumnDef="title"> <ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file"> {{file.title}} </mat-cell> <mat-cell (click)="selectFile(file)" *matCellDef="let file">{{ file.title }}</mat-cell>
</ng-container> </ng-container>
<!-- prefix column --> <!-- prefix column -->
<ng-container matColumnDef="info"> <ng-container matColumnDef="info">
<mat-header-cell *matHeaderCellDef mat-sort-header> Group </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Group</mat-header-cell>
<mat-cell (click)='selectFile(file)' *matCellDef="let file"> <mat-cell (click)="selectFile(file)" *matCellDef="let file">
{{file.type}} {{ file.type }}
<br> <br>
{{file.size}} {{ file.size }}
</mat-cell> </mat-cell>
</ng-container> </ng-container>
<!-- prefix column --> <!-- prefix column -->
<ng-container matColumnDef="download"> <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-cell (click)="download(file)" *matCellDef="let file">
<mat-icon>save_alt</mat-icon> <mat-icon>save_alt</mat-icon>
</mat-cell> </mat-cell>
@ -43,7 +44,7 @@
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator> <mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator>
<mat-menu #mediafilesMenu="matMenu"> <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> <mat-icon>delete</mat-icon>
<span translate>Delete all files</span> <span translate>Delete all files</span>
</button> </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> <div class="text"></div>
<ul class="change-recommendation-list" *ngIf="showChangeRecommendations"> <ul class="change-recommendation-list" *ngIf="showChangeRecommendations">
<li *ngFor="let reco of changeRecommendations" <li *ngFor="let reco of changeRecommendations" [title]="reco.getTitle()"
[title]="reco.getTitle()" [style.top]="calcRecoTop(reco)" [style.height]="calcRecoHeight(reco)"
[style.top]="calcRecoTop(reco)" [class.delete]="recoIsDeletion(reco)" [class.insert]="recoIsInsertion(reco)"
[style.height]="calcRecoHeight(reco)" [class.replace]="recoIsReplacement(reco)" (click)="gotoReco(reco)"></li>
[class.delete]="recoIsDeletion(reco)"
[class.insert]="recoIsInsertion(reco)"
[class.replace]="recoIsReplacement(reco)"
(click)="gotoReco(reco)"
></li>
</ul> </ul>

View File

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

View File

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

View File

@ -60,7 +60,14 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
super.setTitle('Motions'); super.setTitle('Motions');
this.initTable(); this.initTable();
this.repo.getViewModelListObservable().subscribe(newMotions => { 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()"> <os-head-bar [nav]="false" [mainButton]="true" (mainEvent)="onPlusButton()">
<!-- Title --> <!-- Title -->
<div class="title-slot"> <div class="title-slot">
<h2 translate>Statute paragraphs</h2> <h2 translate>Statute paragraphs</h2>
@ -11,10 +10,8 @@
<mat-icon>more_vert</mat-icon> <mat-icon>more_vert</mat-icon>
</button> </button>
</div> </div>
</os-head-bar> </os-head-bar>
<div class="head-spacer"></div> <div class="head-spacer"></div>
<mat-card *ngIf="statuteParagraphToCreate"> <mat-card *ngIf="statuteParagraphToCreate">
<mat-card-title translate>Create new statute paragraph</mat-card-title> <mat-card-title translate>Create new statute paragraph</mat-card-title>
@ -48,6 +45,7 @@
</button> </button>
</mat-card-actions> </mat-card-actions>
</mat-card> </mat-card>
<mat-accordion class="os-card"> <mat-accordion class="os-card">
<mat-expansion-panel *ngFor="let statuteParagraph of this.statuteParagraphs" (opened)="openId = statuteParagraph.id" <mat-expansion-panel *ngFor="let statuteParagraph of this.statuteParagraphs" (opened)="openId = statuteParagraph.id"
(closed)="panelClosed(statuteParagraph)" [expanded]="openId === statuteParagraph.id" multiple="false"> (closed)="panelClosed(statuteParagraph)" [expanded]="openId === statuteParagraph.id" multiple="false">
@ -103,6 +101,7 @@
</mat-action-row> </mat-action-row>
</mat-expansion-panel> </mat-expansion-panel>
</mat-accordion> </mat-accordion>
<mat-card *ngIf="statuteParagraphs.length === 0"> <mat-card *ngIf="statuteParagraphs.length === 0">
<mat-card-content> <mat-card-content>
<div class="no-content" translate>No statute paragraphs</div> <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; 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 { public get category(): Category {
return this._category; return this._category;
} }
@ -133,7 +141,9 @@ export class ViewMotion extends BaseViewModel {
} }
public get possibleRecommendations(): WorkflowState[] { 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 { public get origin(): string {
@ -179,10 +189,9 @@ export class ViewMotion extends BaseViewModel {
this.highlightedLine = null; this.highlightedLine = null;
} }
// TODO aware of issues here?
public getTitle(): string { public getTitle(): string {
if (this.category) { if (this.identifier) {
return this.category.prefix + ' - ' + this.title; return this.identifier + ' - ' + this.title;
} }
return 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 { MotionCommentSectionListComponent } from './components/motion-comment-section-list/motion-comment-section-list.component';
import { StatuteParagraphListComponent } from './components/statute-paragraph-list/statute-paragraph-list.component'; import { StatuteParagraphListComponent } from './components/statute-paragraph-list/statute-paragraph-list.component';
import { SpeakerListComponent } from '../agenda/components/speaker-list/speaker-list.component'; import { SpeakerListComponent } from '../agenda/components/speaker-list/speaker-list.component';
import { CallListComponent } from './components/call-list/call-list.component';
const routes: Routes = [ const routes: Routes = [
{ path: '', component: MotionListComponent }, { path: '', component: MotionListComponent },
{ path: 'category', component: CategoryListComponent }, { path: 'category', component: CategoryListComponent },
{ path: 'comment-section', component: MotionCommentSectionListComponent }, { path: 'comment-section', component: MotionCommentSectionListComponent },
{ path: 'statute-paragraphs', component: StatuteParagraphListComponent }, { path: 'statute-paragraphs', component: StatuteParagraphListComponent },
{ path: 'call-list', component: CallListComponent },
{ path: 'new', component: MotionDetailComponent }, { path: 'new', component: MotionDetailComponent },
{ path: ':id', component: MotionDetailComponent }, { path: ':id', component: MotionDetailComponent },
{ path: ':id/speakers', component: SpeakerListComponent } { 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 { MotionCommentsComponent } from './components/motion-comments/motion-comments.component';
import { MetaTextBlockComponent } from './components/meta-text-block/meta-text-block.component'; import { MetaTextBlockComponent } from './components/meta-text-block/meta-text-block.component';
import { PersonalNoteComponent } from './components/personal-note/personal-note.component'; import { PersonalNoteComponent } from './components/personal-note/personal-note.component';
import { CallListComponent } from './components/call-list/call-list.component';
@NgModule({ @NgModule({
imports: [CommonModule, MotionsRoutingModule, SharedModule], imports: [CommonModule, MotionsRoutingModule, SharedModule],
@ -28,7 +29,8 @@ import { PersonalNoteComponent } from './components/personal-note/personal-note.
MotionDetailDiffComponent, MotionDetailDiffComponent,
MotionCommentsComponent, MotionCommentsComponent,
MetaTextBlockComponent, MetaTextBlockComponent,
PersonalNoteComponent PersonalNoteComponent,
CallListComponent
], ],
entryComponents: [ entryComponents: [
MotionChangeRecommendationComponent, MotionChangeRecommendationComponent,

View File

@ -149,6 +149,16 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
return this.configService.get('motions_recommendations_by'); 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 * Format the motion text using the line numbering and change
* reco algorithm. * 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 --> <!-- Title -->
<div class="title-slot"> <div class="title-slot">
<h2 *ngIf="!editTag && !newTag" translate>Tags</h2> <h2 *ngIf="!editTag && !newTag" translate>Tags</h2>
<form *ngIf="editTag" [formGroup]="tagForm" (ngSubmit)="saveTag()" (keydown)="keyDownFunction($event)"> <form *ngIf="editTag" [formGroup]="tagForm" (ngSubmit)="saveTag()" (keydown)="keyDownFunction($event)">
<mat-form-field> <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-error *ngIf="tagForm.invalid" translate>Required</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
@ -20,13 +21,13 @@
</div> </div>
</os-head-bar> </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"> <ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let tag"> {{tag.getTitle()}} </mat-cell> <mat-cell *matCellDef="let tag">{{ tag.getTitle() }}</mat-cell>
</ng-container> </ng-container>
<mat-header-row *matHeaderRowDef="['name']"></mat-header-row> <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-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator> <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 --> <!-- Title -->
<div class="title-slot"> <div class="title-slot">
<h2 *ngIf="!editGroup && !newGroup" translate>Groups</h2> <h2 *ngIf="!editGroup && !newGroup" translate>Groups</h2>
<form *ngIf="editGroup" [formGroup]="groupForm" (ngSubmit)="saveGroup()" (keydown)="keyDownFunction($event)"> <form *ngIf="editGroup" [formGroup]="groupForm" (ngSubmit)="saveGroup()" (keydown)="keyDownFunction($event)">
<mat-form-field> <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-error *ngIf="groupForm.invalid" translate>Required</mat-error>
</mat-form-field> </mat-form-field>
</form> </form>
@ -35,7 +36,7 @@
</mat-expansion-panel-header> </mat-expansion-panel-header>
<div class="scrollable-perm-matrix"> <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> <ng-container matColumnDef="perm" sticky>
<mat-header-cell *matHeaderCellDef translate>Permissions</mat-header-cell> <mat-header-cell *matHeaderCellDef translate>Permissions</mat-header-cell>
<mat-cell *matCellDef="let perm"> <mat-cell *matCellDef="let perm">
@ -53,7 +54,7 @@
<mat-cell *matCellDef="let perm"> <mat-cell *matCellDef="let perm">
<div class="inner-table"> <div class="inner-table">
<mat-checkbox *ngIf="group.id !== 2" [checked]="group.hasPermission(perm.value)" <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> <mat-checkbox *ngIf="group.id === 2" [checked]="true" [disabled]="true"></mat-checkbox>
</div> </div>
</mat-cell> </mat-cell>

View File

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

View File

@ -12,7 +12,7 @@
</div> </div>
</os-head-bar> </os-head-bar>
<div class='custom-table-header on-transition-fade'> <div class="custom-table-header on-transition-fade">
<button mat-button> <button mat-button>
<span translate>SORT</span> <span translate>SORT</span>
</button> </button>
@ -21,27 +21,27 @@
</button> </button>
</div> </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 --> <!-- name column -->
<ng-container matColumnDef="name"> <ng-container matColumnDef="name">
<mat-header-cell *matHeaderCellDef mat-sort-header> Name </mat-header-cell> <mat-header-cell *matHeaderCellDef mat-sort-header>Name</mat-header-cell>
<mat-cell *matCellDef="let user"> {{user.full_name}} </mat-cell> <mat-cell *matCellDef="let user">{{ user.full_name }}</mat-cell>
</ng-container> </ng-container>
<!-- prefix column --> <!-- prefix column -->
<ng-container matColumnDef="group"> <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"> <mat-cell *matCellDef="let user">
<div class='groupsCell'> <div class='groupsCell'>
<span *ngIf="user.groups.length > 0"> <span *ngIf="user.groups.length > 0">
<mat-icon>people</mat-icon> <mat-icon>people</mat-icon>
{{user.groups}} {{ user.groups }}
</span> </span>
<br *ngIf="user.groups && user.structureLevel"> <br *ngIf="user.groups && user.structureLevel">
<span *ngIf="user.structureLevel"> <span *ngIf="user.structureLevel">
<mat-icon>flag</mat-icon> <mat-icon>flag</mat-icon>
{{user.structure_level}} {{ user.structure_level }}
</span> </span>
</div> </div>
</mat-cell> </mat-cell>
@ -49,7 +49,7 @@
<!-- Presence column --> <!-- Presence column -->
<ng-container matColumnDef="presence"> <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"> <mat-cell *matCellDef="let user">
<div *ngIf="user.is_active"> <div *ngIf="user.is_active">
<mat-icon>check_box</mat-icon> <mat-icon>check_box</mat-icon>
@ -59,7 +59,7 @@
</ng-container> </ng-container>
<mat-header-row *matHeaderRowDef="['name', 'group', 'presence']"></mat-header-row> <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-table>
<mat-paginator class="on-transition-fade" [pageSizeOptions]="[25, 50, 75, 100, 125]"></mat-paginator> <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 Note: This view is not tested! Maybe needs to be refactored. Add documentation
abou the data to be send. abou the data to be send.
""" """
raise ValidationError({'detail': _('This view needs testing and refactoring!')})
nodes = request.data.get('nodes', []) nodes = request.data.get('nodes', [])
sort_parent_id = request.data.get('sort_parent_id') sort_parent_id = request.data.get('sort_parent_id')
motions = [] motions = []