diff --git a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.html b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.html index ebdcf1c79..25d52ae68 100644 --- a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.html +++ b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.html @@ -357,7 +357,7 @@
- + - {{ category.getTitle() | translate }} @@ -366,7 +366,7 @@ - + - {{ block.getTitle() | translate }} @@ -375,12 +375,30 @@ - + {{ tag.getTitle() | translate }} + + + + + + {{ state.getTitle() | translate }} + + + + + + + + + {{ state.recommendation_label | translate }} + + +
diff --git a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts index d818a6fe7..63234c973 100644 --- a/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts +++ b/client/src/app/site/motions/modules/motion-list/components/motion-list/motion-list.component.ts @@ -60,17 +60,27 @@ interface InfoDialog { /** * The motion block id */ - motionBlock: number; + motion_block_id: number; /** * The category id */ - category: number; + category_id: number; /** * The motions tag ids */ - tags: number[]; + tags_id: number[]; + + /** + * The id of the state + */ + state_id: number; + + /** + * The id of the recommendation + */ + recommendation_id: number; } /** @@ -98,6 +108,11 @@ export class MotionListComponent extends BaseListViewComponent imple */ public selectedView: MotionListviewType; + /** + * The motion, the user has currently selected in the quick-edit-dialog. + */ + public selectedMotion: ViewMotion = null; + /** * Columns to display in table when desktop view is available * Define the columns to show @@ -394,46 +409,48 @@ export class MotionListComponent extends BaseListViewComponent imple * Opens a dialog to edit some meta information about a motion. * * @param motion the ViewMotion whose content is edited. - * @param ev a MouseEvent. */ public async openEditInfo(motion: ViewMotion): Promise { - if (!this.isMultiSelect && this.perms.isAllowed('change_metadata')) { - // The interface holding the current information from motion. - this.infoDialog = { - title: motion.title, - motionBlock: motion.motion_block_id, - category: motion.category_id, - tags: motion.tags_id - }; - - // Copies the interface to check, if changes were made. - const copyDialog = { ...this.infoDialog }; - - const dialogRef = this.dialog.open(this.motionInfoDialog, infoDialogSettings); - - dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => { - if (event.key === 'Enter' && event.shiftKey) { - dialogRef.close(this.infoDialog); - } - }); - - // After closing the dialog: Goes through the fields and check if they are changed - // TODO: Logic like this should be handled in a service - dialogRef.afterClosed().subscribe(async (result: InfoDialog) => { - if (result) { - const partialUpdate = { - category_id: result.category !== copyDialog.category ? result.category : undefined, - motion_block_id: result.motionBlock !== copyDialog.motionBlock ? result.motionBlock : undefined, - tags_id: - JSON.stringify(result.tags) !== JSON.stringify(copyDialog.tags) ? result.tags : undefined - }; - // TODO: "only update if different" was another repo-todo - if (!Object.keys(partialUpdate).every(key => partialUpdate[key] === undefined)) { - await this.motionRepo.update(partialUpdate, motion).catch(this.raiseError); - } - } - }); + if (this.isMultiSelect || !this.perms.isAllowed('change_metadata')) { + return; } + + this.selectedMotion = motion; + // The interface holding the current information from motion. + this.infoDialog = { + title: motion.title, + motion_block_id: motion.motion_block_id, + category_id: motion.category_id, + tags_id: motion.tags_id, + state_id: motion.state_id, + recommendation_id: motion.recommendation_id + }; + + const dialogRef = this.dialog.open(this.motionInfoDialog, infoDialogSettings); + dialogRef.keydownEvents().subscribe((event: KeyboardEvent) => { + if (event.key === 'Enter' && event.shiftKey) { + dialogRef.close(this.infoDialog); + } + }); + + const result: InfoDialog = await dialogRef.afterClosed().toPromise(); + if (result) { + delete result.title; // Do not update the title! + + try { + await this.motionRepo.patch(result, motion); + if (result.state_id !== motion.state_id) { + await this.motionRepo.setState(motion, result.state_id); + } + if (result.recommendation_id !== motion.recommendation_id) { + await this.motionRepo.setRecommendation(motion, result.recommendation_id); + } + } catch (e) { + this.raiseError(e); + } + } + + this.selectedMotion = null; } /** diff --git a/openslides/motions/serializers.py b/openslides/motions/serializers.py index de68e0eb4..c3397cf22 100644 --- a/openslides/motions/serializers.py +++ b/openslides/motions/serializers.py @@ -425,7 +425,9 @@ class MotionSerializer(ModelSerializer): text = CharField(allow_blank=True, required=False) # This will be checked # during validation title = CharField(max_length=255) - amendment_paragraphs = AmendmentParagraphsJSONSerializerField(required=False) + amendment_paragraphs = AmendmentParagraphsJSONSerializerField( + required=False, allow_null=True + ) workflow_id = IntegerField( min_value=1, required=False, validators=[validate_workflow_field] ) @@ -496,7 +498,7 @@ class MotionSerializer(ModelSerializer): data["reason"] = validate_html(data["reason"]) # The motion text is only needed, if it is not a paragraph based amendment. - if "amendment_paragraphs" in data: + if data.get("amendment_paragraphs") is not None: data["amendment_paragraphs"] = list( map( lambda entry: validate_html(entry)