Merge pull request #4257 from GabrielInTheWorld/4217
Adds notifications if multiple users want to edit the same motion
This commit is contained in:
commit
46e9c83423
@ -15,7 +15,7 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
|
|||||||
/**
|
/**
|
||||||
* A reference to the current error snack bar.
|
* A reference to the current error snack bar.
|
||||||
*/
|
*/
|
||||||
private errorSnackBar: MatSnackBarRef<SimpleSnackBar>;
|
private messageSnackBar: MatSnackBarRef<SimpleSnackBar>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor for bas elist views
|
* Constructor for bas elist views
|
||||||
@ -27,6 +27,14 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
|
|||||||
super(titleService, translate);
|
super(titleService, translate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens the snack bar with the given message.
|
||||||
|
* This snack bar will only dismiss if the user clicks the 'OK'-button.
|
||||||
|
*/
|
||||||
|
protected raiseWarning = (message: string): void => {
|
||||||
|
this.messageSnackBar = this.matSnackBar.open(message, this.translate.instant('OK'));
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens an error snack bar with the given error message.
|
* Opens an error snack bar with the given error message.
|
||||||
* This is implemented as an arrow function to capture the called `this`. You can use this function
|
* This is implemented as an arrow function to capture the called `this`. You can use this function
|
||||||
@ -34,17 +42,27 @@ export abstract class BaseViewComponent extends BaseComponent implements OnDestr
|
|||||||
* @param message The message to show.
|
* @param message The message to show.
|
||||||
*/
|
*/
|
||||||
protected raiseError = (message: string): void => {
|
protected raiseError = (message: string): void => {
|
||||||
this.errorSnackBar = this.matSnackBar.open(message, this.translate.instant('OK'), {
|
this.messageSnackBar = this.matSnackBar.open(message, this.translate.instant('OK'), {
|
||||||
duration: 0
|
duration: 0
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to manually close the snack bar if it will not automatically close
|
||||||
|
* or it should close in a previous step.
|
||||||
|
*/
|
||||||
|
protected closeSnackBar(): void {
|
||||||
|
if (this.matSnackBar) {
|
||||||
|
this.matSnackBar.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* automatically dismisses the error snack bar, if the component is destroyed.
|
* automatically dismisses the error snack bar, if the component is destroyed.
|
||||||
*/
|
*/
|
||||||
public ngOnDestroy(): void {
|
public ngOnDestroy(): void {
|
||||||
if (this.errorSnackBar) {
|
if (this.messageSnackBar) {
|
||||||
this.errorSnackBar.dismiss();
|
this.messageSnackBar.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { Component, OnInit, ElementRef, HostListener, TemplateRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, ElementRef, HostListener, TemplateRef } from '@angular/core';
|
||||||
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
|
import { DomSanitizer, SafeHtml, Title } from '@angular/platform-browser';
|
||||||
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';
|
||||||
import { MatDialog, MatSnackBar, MatCheckboxChange, ErrorStateMatcher } from '@angular/material';
|
import { MatDialog, MatSnackBar, MatCheckboxChange, ErrorStateMatcher } from '@angular/material';
|
||||||
@ -7,7 +7,6 @@ import { MatDialog, MatSnackBar, MatCheckboxChange, ErrorStateMatcher } from '@a
|
|||||||
import { BehaviorSubject, Subscription } from 'rxjs';
|
import { BehaviorSubject, Subscription } from 'rxjs';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
|
||||||
import { BaseViewComponent } from '../../../base/base-view';
|
import { BaseViewComponent } from '../../../base/base-view';
|
||||||
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
import { CategoryRepositoryService } from 'app/core/repositories/motions/category-repository.service';
|
||||||
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
|
import { ChangeRecommendationRepositoryService } from 'app/core/repositories/motions/change-recommendation-repository.service';
|
||||||
@ -16,7 +15,9 @@ import { CreateMotion } from '../../models/create-motion';
|
|||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { DataStoreService } from 'app/core/core-services/data-store.service';
|
import { DataStoreService } from 'app/core/core-services/data-store.service';
|
||||||
import { DiffLinesInParagraph, LineRange } from 'app/core/ui-services/diff.service';
|
import { DiffLinesInParagraph, LineRange } from 'app/core/ui-services/diff.service';
|
||||||
|
import { ItemRepositoryService } from 'app/core/repositories/agenda/item-repository.service';
|
||||||
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
|
import { itemVisibilityChoices, Item } from 'app/shared/models/agenda/item';
|
||||||
|
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
||||||
import { LocalPermissionsService } from '../../services/local-permissions.service';
|
import { LocalPermissionsService } from '../../services/local-permissions.service';
|
||||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||||
import { Motion } from 'app/shared/models/motions/motion';
|
import { Motion } from 'app/shared/models/motions/motion';
|
||||||
@ -27,27 +28,30 @@ import {
|
|||||||
} from '../motion-change-recommendation/motion-change-recommendation.component';
|
} from '../motion-change-recommendation/motion-change-recommendation.component';
|
||||||
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
||||||
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
import { MotionRepositoryService } from 'app/core/repositories/motions/motion-repository.service';
|
||||||
|
import { NotifyService } from 'app/core/core-services/notify.service';
|
||||||
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||||
import { PersonalNoteService } from 'app/core/ui-services/personal-note.service';
|
import { PersonalNoteService } from 'app/core/ui-services/personal-note.service';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
|
import { StatuteParagraphRepositoryService } from 'app/core/repositories/motions/statute-paragraph-repository.service';
|
||||||
import { ViewMotionChangeRecommendation } from '../../models/view-change-recommendation';
|
|
||||||
import { ViewCreateMotion } from '../../models/view-create-motion';
|
|
||||||
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
|
||||||
import { ViewUnifiedChange } from '../../../../shared/models/motions/view-unified-change';
|
|
||||||
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
|
|
||||||
import { Workflow } from 'app/shared/models/motions/workflow';
|
|
||||||
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
|
||||||
import { Tag } from 'app/shared/models/core/tag';
|
import { Tag } from 'app/shared/models/core/tag';
|
||||||
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
import { UserRepositoryService } from 'app/core/repositories/users/user-repository.service';
|
||||||
import { ViewMotionBlock } from '../../models/view-motion-block';
|
import { ViewMotionBlock } from '../../models/view-motion-block';
|
||||||
import { ViewWorkflow, StateCssClassMapping } from '../../models/view-workflow';
|
import { ViewWorkflow, StateCssClassMapping } from '../../models/view-workflow';
|
||||||
import { ViewUser } from 'app/site/users/models/view-user';
|
import { ViewUser } from 'app/site/users/models/view-user';
|
||||||
import { ViewCategory } from '../../models/view-category';
|
import { ViewCategory } from '../../models/view-category';
|
||||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
import { ViewCreateMotion } from '../../models/view-create-motion';
|
||||||
import { ViewItem } from 'app/site/agenda/models/view-item';
|
import { ViewItem } from 'app/site/agenda/models/view-item';
|
||||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
import { ViewportService } from 'app/core/ui-services/viewport.service';
|
||||||
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
import { ViewModelStoreService } from 'app/core/core-services/view-model-store.service';
|
||||||
|
import { ViewMotionChangeRecommendation } from '../../models/view-change-recommendation';
|
||||||
|
import { ViewMotionNotificationEditMotion, TypeOfNotificationViewMotion } from '../../models/view-motion-notify';
|
||||||
|
import { ViewStatuteParagraph } from '../../models/view-statute-paragraph';
|
||||||
|
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||||
|
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
|
||||||
|
|
||||||
|
import { Workflow } from 'app/shared/models/motions/workflow';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component for the motion detail view
|
* Component for the motion detail view
|
||||||
@ -57,7 +61,7 @@ import { ViewModelStoreService } from 'app/core/core-services/view-model-store.s
|
|||||||
templateUrl: './motion-detail.component.html',
|
templateUrl: './motion-detail.component.html',
|
||||||
styleUrls: ['./motion-detail.component.scss']
|
styleUrls: ['./motion-detail.component.scss']
|
||||||
})
|
})
|
||||||
export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
export class MotionDetailComponent extends BaseViewComponent implements OnInit, OnDestroy {
|
||||||
/**
|
/**
|
||||||
* Motion content. Can be a new version
|
* Motion content. Can be a new version
|
||||||
*/
|
*/
|
||||||
@ -320,6 +324,23 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
*/
|
*/
|
||||||
public newStateExtension = '';
|
public newStateExtension = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constant to identify the notification-message.
|
||||||
|
*/
|
||||||
|
public NOTIFICATION_EDIT_MOTION = 'notifyEditMotion';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array to recognize, if there are other persons working on the same
|
||||||
|
* motion and see, if those persons leave the editing-view.
|
||||||
|
*/
|
||||||
|
private otherWorkOnMotion: string[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The variable to hold the subscription for notifications in editing-view.
|
||||||
|
* Necessary to unsubscribe after leaving the editing-view.
|
||||||
|
*/
|
||||||
|
private editNotificationSubscription: Subscription;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constuct the detail view.
|
* Constuct the detail view.
|
||||||
*
|
*
|
||||||
@ -327,7 +348,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
* @param translate
|
* @param translate
|
||||||
* @param matSnackBar
|
* @param matSnackBar
|
||||||
* @param vp the viewport service
|
* @param vp the viewport service
|
||||||
* @param op Operator Service
|
* @param operator Operator Service
|
||||||
|
* @param perms local permissions
|
||||||
* @param router to navigate back to the motion list and to an existing motion
|
* @param router to navigate back to the motion list and to an existing motion
|
||||||
* @param route determine if this is a new or an existing motion
|
* @param route determine if this is a new or an existing motion
|
||||||
* @param formBuilder For reactive forms. Form Group and Form Control
|
* @param formBuilder For reactive forms. Form Group and Form Control
|
||||||
@ -345,13 +367,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
* @param personalNoteService: personal comments and favorite marker
|
* @param personalNoteService: personal comments and favorite marker
|
||||||
* @param linenumberingService The line numbering service
|
* @param linenumberingService The line numbering service
|
||||||
* @param categoryRepo Repository for categories
|
* @param categoryRepo Repository for categories
|
||||||
|
* @param viewModelStore accessing view models
|
||||||
|
* @param categoryRepo access the category repository
|
||||||
* @param userRepo Repository for users
|
* @param userRepo Repository for users
|
||||||
|
* @param notifyService: NotifyService work with notification
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
matSnackBar: MatSnackBar,
|
matSnackBar: MatSnackBar,
|
||||||
public vp: ViewportService,
|
public vp: ViewportService,
|
||||||
|
private operator: OperatorService,
|
||||||
public perms: LocalPermissionsService,
|
public perms: LocalPermissionsService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -371,7 +397,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
private linenumberingService: LinenumberingService,
|
private linenumberingService: LinenumberingService,
|
||||||
private viewModelStore: ViewModelStoreService,
|
private viewModelStore: ViewModelStoreService,
|
||||||
private categoryRepo: CategoryRepositoryService,
|
private categoryRepo: CategoryRepositoryService,
|
||||||
private userRepo: UserRepositoryService
|
private userRepo: UserRepositoryService,
|
||||||
|
private notifyService: NotifyService
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackBar);
|
super(title, translate, matSnackBar);
|
||||||
|
|
||||||
@ -474,6 +501,10 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ngOnDestroy(): void {
|
||||||
|
this.unsubscribeEditNotifications(TypeOfNotificationViewMotion.TYPE_CLOSING_EDITING_MOTION);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges amendments and change recommendations and sorts them by the line numbers.
|
* Merges amendments and change recommendations and sorts them by the line numbers.
|
||||||
* Called each time one of these arrays changes.
|
* Called each time one of these arrays changes.
|
||||||
@ -738,6 +769,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
this.createMotion();
|
this.createMotion();
|
||||||
} else {
|
} else {
|
||||||
this.updateMotionFromForm();
|
this.updateMotionFromForm();
|
||||||
|
// When saving the changes, notify other users if they edit the same motion.
|
||||||
|
this.unsubscribeEditNotifications(TypeOfNotificationViewMotion.TYPE_SAVING_EDITING_MOTION);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -988,10 +1021,17 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
if (mode) {
|
if (mode) {
|
||||||
this.motionCopy = this.motion.copy();
|
this.motionCopy = this.motion.copy();
|
||||||
this.patchForm(this.motionCopy);
|
this.patchForm(this.motionCopy);
|
||||||
|
this.editNotificationSubscription = this.listenToEditNotification();
|
||||||
|
this.sendEditNotification(TypeOfNotificationViewMotion.TYPE_BEGIN_EDITING_MOTION);
|
||||||
}
|
}
|
||||||
if (!mode && this.newMotion) {
|
if (!mode && this.newMotion) {
|
||||||
this.router.navigate(['./motions/']);
|
this.router.navigate(['./motions/']);
|
||||||
}
|
}
|
||||||
|
// If the user cancels the work on this motion,
|
||||||
|
// notify the users who are still editing the same motion
|
||||||
|
if (!mode && !this.newMotion) {
|
||||||
|
this.unsubscribeEditNotifications(TypeOfNotificationViewMotion.TYPE_CLOSING_EDITING_MOTION);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1250,6 +1290,104 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
|||||||
this.repo.followRecommendation(this.motion);
|
this.repo.followRecommendation(this.motion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to send a notification, so that other persons can recognize editing the same motion, if they're doing.
|
||||||
|
*
|
||||||
|
* @param type TypeOfNotificationViewMotion defines the type of the notification which is sent.
|
||||||
|
* @param user Optional userId. If set the function will send a notification to the given userId.
|
||||||
|
*/
|
||||||
|
private sendEditNotification(type: TypeOfNotificationViewMotion, user?: number): void {
|
||||||
|
const content: ViewMotionNotificationEditMotion = {
|
||||||
|
motionId: this.motion.id,
|
||||||
|
senderId: this.operator.viewUser.id,
|
||||||
|
senderName: this.operator.viewUser.short_name,
|
||||||
|
type: type
|
||||||
|
};
|
||||||
|
if (user) {
|
||||||
|
this.notifyService.sendToUsers(this.NOTIFICATION_EDIT_MOTION, content, user);
|
||||||
|
} else {
|
||||||
|
this.notifyService.sendToAllUsers<ViewMotionNotificationEditMotion>(this.NOTIFICATION_EDIT_MOTION, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to listen to notifications if the user edits this motion.
|
||||||
|
* Handles the notification messages.
|
||||||
|
*
|
||||||
|
* @returns A subscription, only if the user wants to edit this motion, to listen to notifications.
|
||||||
|
*/
|
||||||
|
private listenToEditNotification(): Subscription {
|
||||||
|
return this.notifyService.getMessageObservable(this.NOTIFICATION_EDIT_MOTION).subscribe(message => {
|
||||||
|
const content = <ViewMotionNotificationEditMotion>message.content;
|
||||||
|
if (this.operator.viewUser.id !== content.senderId && content.motionId === this.motion.id) {
|
||||||
|
let warning = '';
|
||||||
|
|
||||||
|
switch (content.type) {
|
||||||
|
case TypeOfNotificationViewMotion.TYPE_BEGIN_EDITING_MOTION:
|
||||||
|
case TypeOfNotificationViewMotion.TYPE_ALSO_EDITING_MOTION: {
|
||||||
|
if (!this.otherWorkOnMotion.includes(content.senderName)) {
|
||||||
|
this.otherWorkOnMotion.push(content.senderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
warning = `${this.translate.instant('Following users are currently editing this motion:')} ${
|
||||||
|
this.otherWorkOnMotion
|
||||||
|
}`;
|
||||||
|
if (content.type === TypeOfNotificationViewMotion.TYPE_BEGIN_EDITING_MOTION) {
|
||||||
|
this.sendEditNotification(
|
||||||
|
TypeOfNotificationViewMotion.TYPE_ALSO_EDITING_MOTION,
|
||||||
|
message.senderUserId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeOfNotificationViewMotion.TYPE_CLOSING_EDITING_MOTION: {
|
||||||
|
this.recognizeOtherWorkerOnMotion(content.senderName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TypeOfNotificationViewMotion.TYPE_SAVING_EDITING_MOTION: {
|
||||||
|
warning = `${content.senderName} ${this.translate.instant(
|
||||||
|
'has saved his work on this motion.'
|
||||||
|
)}`;
|
||||||
|
// Wait, to prevent overlapping snack bars
|
||||||
|
setTimeout(() => this.recognizeOtherWorkerOnMotion(content.senderName), 2000);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (warning !== '') {
|
||||||
|
this.raiseWarning(warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to handle leaving persons and
|
||||||
|
* recognize if there is no other person editing the same motion anymore.
|
||||||
|
*
|
||||||
|
* @param senderId The id of the sender who has left the editing-view.
|
||||||
|
*/
|
||||||
|
private recognizeOtherWorkerOnMotion(senderName: string): void {
|
||||||
|
this.otherWorkOnMotion = this.otherWorkOnMotion.filter(value => value !== senderName);
|
||||||
|
if (this.otherWorkOnMotion.length === 0) {
|
||||||
|
this.closeSnackBar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to unsubscribe the notification subscription.
|
||||||
|
* Before unsubscribing a notification will send with the reason.
|
||||||
|
*
|
||||||
|
* @param unsubscriptionReason The reason for the unsubscription.
|
||||||
|
*/
|
||||||
|
private unsubscribeEditNotifications(unsubscriptionReason: TypeOfNotificationViewMotion): void {
|
||||||
|
if (!!this.editNotificationSubscription && !this.editNotificationSubscription.closed) {
|
||||||
|
this.sendEditNotification(unsubscriptionReason);
|
||||||
|
this.closeSnackBar();
|
||||||
|
this.editNotificationSubscription.unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the favorite status
|
* Toggles the favorite status
|
||||||
*/
|
*/
|
||||||
|
52
client/src/app/site/motions/models/view-motion-notify.ts
Normal file
52
client/src/app/site/motions/models/view-motion-notify.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Enum to define different types of notifications.
|
||||||
|
*/
|
||||||
|
export enum TypeOfNotificationViewMotion {
|
||||||
|
/**
|
||||||
|
* Type to declare editing a motion.
|
||||||
|
*/
|
||||||
|
TYPE_BEGIN_EDITING_MOTION = 'typeBeginEditingMotion',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type if the edit-view is closing.
|
||||||
|
*/
|
||||||
|
TYPE_CLOSING_EDITING_MOTION = 'typeClosingEditingMotion',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type if changes are saved.
|
||||||
|
*/
|
||||||
|
TYPE_SAVING_EDITING_MOTION = 'typeSavingEditingMotion',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type to declare if another person is also editing the same motion.
|
||||||
|
*/
|
||||||
|
TYPE_ALSO_EDITING_MOTION = 'typeAlsoEditingMotion'
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Class to specify the notifications for editing a motion.
|
||||||
|
*/
|
||||||
|
export interface ViewMotionNotificationEditMotion {
|
||||||
|
/**
|
||||||
|
* The id of the motion the user wants to edit.
|
||||||
|
* Necessary to identify if users edit the same motion.
|
||||||
|
*/
|
||||||
|
motionId: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The id of the sender.
|
||||||
|
* Necessary if this differs from senderUserId.
|
||||||
|
*/
|
||||||
|
senderId: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the sender.
|
||||||
|
* To show the names of the other editors
|
||||||
|
*/
|
||||||
|
senderName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of the notification.
|
||||||
|
* Separates if the user is beginning the work or closing the edit-view.
|
||||||
|
*/
|
||||||
|
type: TypeOfNotificationViewMotion;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user