cleanup, removed motion log from client

This commit is contained in:
FinnStutzenstein 2019-01-24 11:15:52 +01:00
parent 390b46a863
commit 22182463a9
27 changed files with 90 additions and 230 deletions

View File

@ -314,11 +314,11 @@ export class PdfDocumentService {
*/
public async download(docDefinition: object, filename: string, metadata?: object): Promise<void> {
const doc = await this.getStandardPaper(docDefinition, metadata);
await new Promise<boolean>(resolve => {
await new Promise<void>(resolve => {
const pdf = pdfMake.createPdf(doc);
pdf.getBlob(blob => {
saveAs(blob, `${filename}.pdf`, { autoBOM: true });
resolve(true);
resolve();
});
});
}

View File

@ -131,7 +131,6 @@ export class SortingListComponent implements OnInit, OnDestroy {
if (this.array.length !== newValues.length || this.live) {
this.array = [];
this.array = newValues.map(val => val);
console.log(newValues);
} else if (this.array.length === 0) {
this.array.push(new EmptySelectable(this.translate));
}

View File

@ -57,7 +57,7 @@ export class Item extends BaseModel<Item> {
/**
* Gets the amount of waiting speakers
*/
public get speakerAmount(): number {
public get waitingSpeakerAmount(): number {
return this.speakers.filter(speaker => speaker.state === SpeakerState.WAITING).length;
}

View File

@ -1,18 +0,0 @@
import { Deserializer } from '../base/deserializer';
/**
* Representation of a Motion Log.
* TODO: better documentation
*
* @ignore
*/
export class MotionLog extends Deserializer {
public message_list: string[];
public person_id: number;
public time: string;
public message: string; // a pre-translated message in the servers' defined language
public constructor(input?: any) {
super(input);
}
}

View File

@ -1,5 +1,4 @@
import { MotionSubmitter } from './motion-submitter';
import { MotionLog } from './motion-log';
import { MotionComment } from './motion-comment';
import { AgendaBaseModel } from '../base/agenda-base-model';
import { SearchRepresentation } from '../../../core/services/search.service';
@ -40,7 +39,6 @@ export class Motion extends AgendaBaseModel {
public attachments_id: number[];
public polls: MotionPoll[];
public agenda_item_id: number;
public log_messages: MotionLog[];
public weight: number;
public sort_parent_id: number;
public created: string;
@ -107,13 +105,6 @@ export class Motion extends AgendaBaseModel {
public deserialize(input: any): void {
Object.assign(this, input);
this.log_messages = [];
if (input.log_messages instanceof Array) {
input.log_messages.forEach(logData => {
this.log_messages.push(new MotionLog(logData));
});
}
this.comments = [];
if (input.comments instanceof Array) {
input.comments.forEach(commentData => {

View File

@ -38,22 +38,22 @@ export class User extends BaseModel<User> implements Searchable {
public get full_name(): string {
let name = this.short_name;
const addition: string[] = [];
const additions: string[] = [];
// addition: add number and structure level
const structure_level = this.structure_level ? this.structure_level.trim() : '';
if (structure_level) {
addition.push(structure_level);
additions.push(structure_level);
}
const number = this.number ? this.number.trim() : null;
if (number) {
// TODO Translate
addition.push('No.' + ' ' + number);
additions.push('No. ' + number);
}
if (addition.length > 0) {
name += ' (' + addition.join(' · ') + ')';
if (additions.length > 0) {
name += ' (' + additions.join(' · ') + ')';
}
return name.trim();
}
@ -85,7 +85,9 @@ export class User extends BaseModel<User> implements Searchable {
let shortName = `${firstName} ${lastName}`;
if (!shortName) {
if (shortName.length <= 1) {
// We have at least one space from the concatination of
// first- and lastname.
shortName = this.username;
}
@ -93,11 +95,11 @@ export class User extends BaseModel<User> implements Searchable {
shortName = `${title} ${shortName}`;
}
return shortName || this.username;
return shortName;
}
public getTitle(): string {
return this.full_name || this.username;
return this.full_name;
}
public getListViewTitle(): string {

View File

@ -61,7 +61,7 @@
<mat-header-cell *matHeaderCellDef mat-sort-header>Speakers</mat-header-cell>
<mat-cell *matCellDef="let item">
<button mat-icon-button (click)="onSpeakerIcon(item)">
<mat-icon [matBadge]="item.speakerAmount > 0 ? item.speakerAmount : null" matBadgeColor="accent">
<mat-icon [matBadge]="item.waitingSpeakerAmount > 0 ? item.waitingSpeakerAmount : null" matBadgeColor="accent">
mic
</mat-icon>
</button>
@ -179,7 +179,7 @@
<!-- List of speakers for mobile -->
<button mat-menu-item (click)="onSpeakerIcon(item)" *ngIf="vp.isMobile">
<mat-icon [matBadge]="item.speakerAmount > 0 ? item.speakerAmount : null" matBadgeColor="accent">
<mat-icon [matBadge]="item.waitingSpeakerAmount > 0 ? item.waitingSpeakerAmount : null" matBadgeColor="accent">
mic
</mat-icon>
<span translate>List of speakers</span>

View File

@ -135,8 +135,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
this.speakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.WAITING);
this.finishedSpeakers = allSpeakers.filter(speaker => speaker.state === SpeakerState.FINISHED);
const currentSpeaker = allSpeakers.find(speaker => speaker.state === SpeakerState.CURRENT);
this.activeSpeaker = currentSpeaker ? currentSpeaker : null;
this.activeSpeaker = allSpeakers.find(speaker => speaker.state === SpeakerState.CURRENT);
}
});
}
@ -146,7 +145,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
* @param userId the user id to add to the list. No parameter adds the operators user as speaker.
*/
public addNewSpeaker(userId?: number): void {
this.itemRepo.addSpeaker(userId, this.viewItem.item).then(() => this.addSpeakerForm.reset(), this.raiseError);
this.itemRepo.addSpeaker(userId, this.viewItem).then(() => this.addSpeakerForm.reset(), this.raiseError);
}
/**
@ -162,33 +161,36 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
/**
* Click on the mic button to mark a speaker as speaking
*
* @param item the speaker marked in the list
*/
public onStartButton(item: ViewSpeaker): void {
this.itemRepo.startSpeaker(item.id, this.viewItem.item).then(null, this.raiseError);
this.itemRepo.startSpeaker(item.id, this.viewItem).then(null, this.raiseError);
}
/**
* Click on the mic-cross button
*/
public onStopButton(): void {
this.itemRepo.stopSpeaker(this.viewItem.item).then(null, this.raiseError);
this.itemRepo.stopCurrentSpeaker(this.viewItem).then(null, this.raiseError);
}
/**
* Click on the star button
*
* @param item
*/
public onMarkButton(item: ViewSpeaker): void {
this.itemRepo.markSpeaker(item.user.id, !item.marked, this.viewItem.item).then(null, this.raiseError);
this.itemRepo.markSpeaker(item.user.id, !item.marked, this.viewItem).then(null, this.raiseError);
}
/**
* Click on the X button
* @param item
*
* @param speaker
*/
public onDeleteButton(item?: ViewSpeaker): void {
this.itemRepo.deleteSpeaker(this.viewItem.item, item ? item.id : null).then(null, this.raiseError);
public onDeleteButton(speaker?: ViewSpeaker): void {
this.itemRepo.deleteSpeaker(this.viewItem, speaker ? speaker.id : null).then(null, this.raiseError);
}
/**
@ -235,15 +237,7 @@ export class SpeakerListComponent extends BaseViewComponent implements OnInit {
public async clearSpeakerList(): Promise<void> {
const content = this.translate.instant('This will clear all speakers from the list.');
if (await this.promptService.open('Are you sure?', content)) {
this.speakers.forEach(speaker => {
this.itemRepo.deleteSpeaker(this.viewItem.item, speaker.id);
});
this.finishedSpeakers.forEach(speaker => {
this.itemRepo.deleteSpeaker(this.viewItem.item, speaker.id);
});
if (this.activeSpeaker) {
this.itemRepo.deleteSpeaker(this.viewItem.item, this.activeSpeaker.id);
}
this.itemRepo.deleteAllSpeakers(this.viewItem);
}
}
}

View File

@ -1,6 +1,7 @@
import { BaseViewModel } from '../../base/base-view-model';
import { Item } from '../../../shared/models/agenda/item';
import { AgendaBaseModel } from '../../../shared/models/base/agenda-base-model';
import { Speaker } from 'app/shared/models/agenda/speaker';
export class ViewItem extends BaseViewModel {
private _item: Item;
@ -26,8 +27,8 @@ export class ViewItem extends BaseViewModel {
return this.item ? this.item.duration : null;
}
public get speakerAmount(): number {
return this.item ? this.item.speakerAmount : null;
public get waitingSpeakerAmount(): number {
return this.item ? this.item.waitingSpeakerAmount : null;
}
public get type(): number {
@ -37,6 +38,7 @@ export class ViewItem extends BaseViewModel {
public get closed(): boolean {
return this.item ? this.item.closed : null;
}
public get comment(): string {
if (this.item && this.item.comment) {
return this.item.comment;
@ -58,6 +60,13 @@ export class ViewItem extends BaseViewModel {
return '';
}
/**
* TODO: make the repository set the ViewSpeakers here.
*/
public get speakers(): Speaker[] {
return this.item ? this.item.speakers : [];
}
public constructor(item: Item, contentObject: AgendaBaseModel) {
super();
this._item = item;

View File

@ -43,7 +43,7 @@ export class ViewSpeaker extends BaseViewModel implements Selectable {
}
public get name(): string {
return this.user.full_name || this.user.username;
return this.user.full_name;
}
public get gender(): string {

View File

@ -96,87 +96,78 @@ export class AgendaRepositoryService extends BaseRepository<ViewItem, Item> {
* Sends the users ID to the server
* Might need another repo
*
* @param id {@link User} id of the new speaker
* @param agenda the target agenda item
* @param speakerId {@link User} id of the new speaker
* @param item the target agenda item
*/
public async addSpeaker(id: number, agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/manage_speaker/`;
await this.httpService.post<Identifiable>(restUrl, { user: id });
public async addSpeaker(speakerId: number, item: ViewItem): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/manage_speaker/`;
await this.httpService.post<Identifiable>(restUrl, { user: speakerId });
}
/**
* Sets the given speaker ID to Speak
*
* @param id the speakers id
* @param agenda the target agenda item
* @param speakerId the speakers id
* @param item the target agenda item
*/
public async startSpeaker(id: number, agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/speak/`;
await this.httpService.put(restUrl, { speaker: id });
public async startSpeaker(speakerId: number, item: ViewItem): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/speak/`;
await this.httpService.put(restUrl, { speaker: speakerId });
}
/**
* Stops the current speaker
*
* @param agenda the target agenda item
* @param item the target agenda item
*/
public async stopSpeaker(agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/speak/`;
await this.httpService.delete(restUrl);
}
/**
* Stops the current speaker
*
* @param agenda the target agenda item
*/
public async closeSpeakerList(agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/speak/`;
await this.httpService.delete(restUrl);
}
/**
* Stops the current speaker
*
* @param agenda the target agenda item
*/
public async openSpeakerList(agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/speak/`;
public async stopCurrentSpeaker(item: ViewItem): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/speak/`;
await this.httpService.delete(restUrl);
}
/**
* Marks the current speaker
*
* @param id {@link User} id of the new speaker
* @param speakerId {@link User} id of the new speaker
* @param mark determine if the user was marked or not
* @param agenda the target agenda item
* @param item the target agenda item
*/
public async markSpeaker(id: number, mark: boolean, agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/manage_speaker/`;
await this.httpService.patch(restUrl, { user: id, marked: mark });
public async markSpeaker(speakerId: number, mark: boolean, item: ViewItem): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/manage_speaker/`;
await this.httpService.patch(restUrl, { user: speakerId, marked: mark });
}
/**
* Deletes the given speaker for the agenda
* Deletes the given speaker for the agenda item
*
* @param id the speakers id
* @param agenda the target agenda item
* @param item the target agenda item
* @param speakerId (otional) the speakers id. If no id is given, the current operator
* is removed.
*/
public async deleteSpeaker(agenda: Item, id?: number): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/manage_speaker/`;
await this.httpService.delete(restUrl, { speaker: id });
public async deleteSpeaker(item: ViewItem, speakerId?: number): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/manage_speaker/`;
await this.httpService.delete(restUrl, speakerId ? { speaker: speakerId } : null);
}
/**
* Deletes all speakers of the given agenda item.
*
* @param item the target agenda item
*/
public async deleteAllSpeakers(item: ViewItem): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/manage_speaker/`;
await this.httpService.delete(restUrl, { speaker: item.speakers.map(speaker => speaker.id) });
}
/**
* Posts an (manually) sorted speaker list to the server
*
* @param ids array of speaker id numbers
* @param speakerIds array of speaker id numbers
* @param Item the target agenda item
*/
public async sortSpeakers(ids: number[], agenda: Item): Promise<void> {
const restUrl = `rest/agenda/item/${agenda.id}/sort_speakers/`;
await this.httpService.post(restUrl, { speakers: ids });
public async sortSpeakers(speakerIds: number[], item: Item): Promise<void> {
const restUrl = `rest/agenda/item/${item.id}/sort_speakers/`;
await this.httpService.post(restUrl, { speakers: speakerIds });
}
/**

View File

@ -65,7 +65,7 @@
</form>
</div>
<div class="reset-button">
<button mat-icon-button *ngIf="configItem.hasDefault" matTooltip="{{ 'Reset' | translate }}"
<button mat-icon-button *ngIf="configItem.defaultValue !== undefined" matTooltip="{{ 'Reset' | translate }}"
(click)="onResetButton()">
<mat-icon>replay</mat-icon>
</button>

View File

@ -137,7 +137,7 @@ export class ConfigFieldComponent extends BaseComponent implements OnInit {
* Triggers a reset to the default value (if a default value is present)
*/
public onResetButton(): void {
if (this.configItem.hasDefault) {
if (this.configItem.defaultValue !== undefined) {
this.onChange(this.configItem.defaultValue);
}
}

View File

@ -89,15 +89,7 @@ export class ViewConfig extends BaseViewModel {
return this._choices;
}
/**
* @returns true if a default value exists
*/
public get hasDefault(): boolean {
return this._defaultValue !== undefined;
}
public get defaultValue(): any {
// TODO type is ugly
return this._defaultValue;
}

View File

@ -116,6 +116,8 @@ export class ViewMediafile extends BaseViewModel {
public updateValues(update: Mediafile): void {
if (update instanceof Mediafile && this.mediafile.id === update.id) {
this._mediafile = update;
} else if (update instanceof User && this.uploader.id === update.id) {
this._uploader = update;
}
}

View File

@ -1,7 +1,4 @@
<os-head-bar>
<!-- Title -->
<div class="title-slot">
<h2 *ngIf="block && !editBlock">{{ block.title }}</h2>
@ -20,8 +17,6 @@
</form>
</div>
<!-- Menu -->
<div class="menu-slot">
<button type="button" mat-icon-button [matMenuTriggerFor]="motionBlockMenu">
@ -32,8 +27,6 @@
<div *ngIf="editBlock" class="extra-controls-slot on-transition-fade">
<button mat-button (click)="saveBlock()"><strong translate class="upper">Save</strong></button>
</div>
</os-head-bar>
<mat-card>

View File

@ -137,15 +137,6 @@
<!-- Personal note -->
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
<ng-container *ngTemplateOutlet="motionLogTemplate"></ng-container>
</ng-template>
<ng-template #motionLogTemplate>
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded = !motionLogExpanded">
<span translate>Show motion log</span>
</button>
<os-motion-log *ngIf="canShowLog && motionLogExpanded" [motion]="motion"></os-motion-log>
</ng-template>
<ng-template #desktopView>
@ -158,7 +149,6 @@
<os-motion-comments *ngIf="!editMotion" [motion]="motion"></os-motion-comments>
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
<ng-container *ngTemplateOutlet="motionLogTemplate"></ng-container>
</div>
<div class="desktop-right">
<!-- Content -->

View File

@ -98,22 +98,6 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
return this._motion;
}
/**
* @returns treu if the motion log is present and the user is allowed to see it
*/
public get canShowLog(): boolean {
if (
this.motion &&
!this.editMotion &&
this.perms.isAllowed('manage') &&
this.motion.motion.log_messages &&
this.motion.motion.log_messages.length
) {
return true;
}
return false;
}
/**
* @returns the current recommendation label (with extension)
*/

View File

@ -1,12 +0,0 @@
<os-meta-text-block showActionRow="true" icon="speaker_notes">
<ng-container class="meta-text-block-title">
<span translate>Motion log</span>
</ng-container>
<ng-container class="meta-text-block-content">
<div *ngFor="let message of motion.motion.log_messages">
<span class="small-messages">{{message.message}}</span>
</div>
</ng-container>
</os-meta-text-block>

View File

@ -1,3 +0,0 @@
.small-messages {
font-size: x-small;
}

View File

@ -1,27 +0,0 @@
// import { async, ComponentFixture, TestBed } from '@angular/core/testing';
// import { E2EImportsModule } from 'e2e-imports.module';
// import { MotionLogComponent } from './motion-log.component';
describe('MotionLogComponent skipped', () => {
// TODO testing fails if personalNotesModule (also having the MetaTextBlockComponent)
// is running its' test at the same time. One of the two tests fail, but run fine if tested
// separately; so this is some async duplication stuff
//
// let component: MotionLogComponent;
// let fixture: ComponentFixture<MotionLogComponent>;
// beforeEach(async(() => {
// TestBed.configureTestingModule({
// declarations: [MotionLogComponent],
// imports: [E2EImportsModule]
// }).compileComponents();
// }));
// beforeEach(() => {
// fixture = TestBed.createComponent(MotionLogComponent);
// component = fixture.componentInstance;
// fixture.detectChanges();
// });
// it('should create', () => {
// expect(component).toBeTruthy();
// });
});

View File

@ -1,25 +0,0 @@
import { Component, Input } from '@angular/core';
import { ViewMotion } from '../../models/view-motion';
/**
* Component showing the log messages of a motion
*/
@Component({
selector: 'os-motion-log',
templateUrl: './motion-log.component.html',
styleUrls: ['motion-log.component.scss']
})
export class MotionLogComponent {
public expanded = false;
/**
* The viewMotion to show the log messages for
*/
@Input()
public motion: ViewMotion;
/**
* empty constructor
*/
public constructor() {}
}

View File

@ -198,7 +198,7 @@ export class ViewMotion extends BaseProjectableModel {
}
public get agendaSpeakerAmount(): number {
return this.item ? this.item.speakerAmount : null;
return this.item ? this.item.waitingSpeakerAmount : null;
}
public get parent_id(): number {

View File

@ -22,7 +22,6 @@ import { MotionImportListComponent } from './components/motion-import-list/motio
import { ManageSubmittersComponent } from './components/manage-submitters/manage-submitters.component';
import { MotionPollComponent } from './components/motion-poll/motion-poll.component';
import { MotionPollDialogComponent } from './components/motion-poll/motion-poll-dialog.component';
import { MotionLogComponent } from './components/motion-log/motion-log.component';
@NgModule({
imports: [CommonModule, MotionsRoutingModule, SharedModule],
@ -45,8 +44,7 @@ import { MotionLogComponent } from './components/motion-log/motion-log.component
MotionImportListComponent,
ManageSubmittersComponent,
MotionPollComponent,
MotionPollDialogComponent,
MotionLogComponent
MotionPollDialogComponent
],
entryComponents: [
MotionChangeRecommendationComponent,

View File

@ -737,11 +737,11 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
* @returns the translated state with the extension attached
*/
public getExtendedStateLabel(motion: ViewMotion): string {
let rec = this.translate.instant(motion.state.name);
let state = this.translate.instant(motion.state.name);
if (motion.stateExtension && motion.state.show_state_extension_field) {
rec += ' ' + this.solveExtensionPlaceHolder(motion.stateExtension);
state += ' ' + this.solveExtensionPlaceHolder(motion.stateExtension);
}
return rec;
return state;
}
/**

View File

@ -103,7 +103,7 @@ export class PersonalNoteService {
);
this.subjects[model.collectionString][model.id] = subject;
}
return this.subjects[model.collectionString][model.id];
return this.subjects[model.collectionString][model.id].asObservable();
}
/**

View File

@ -36,11 +36,11 @@ export class ViewUser extends BaseProjectableModel {
}
public get full_name(): string {
return this.user ? this.user.full_name || this.username : null;
return this.user ? this.user.full_name : null;
}
public get short_name(): string {
return this.user ? this.user.short_name || this.username : null;
return this.user ? this.user.short_name : null;
}
public get email(): string {