Merge pull request #4811 from FinnStutzenstein/recommendationReferencingMotions
Show from recommendation referencing motions
This commit is contained in:
commit
7943d15dae
@ -458,7 +458,8 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
|
|||||||
await this.httpService.delete(url);
|
await this.httpService.delete(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns an observable returning the amendments to a given motion
|
/**
|
||||||
|
* Returns an observable returning the amendments to a given motion
|
||||||
*
|
*
|
||||||
* @param {number} motionId
|
* @param {number} motionId
|
||||||
* @returns {Observable<ViewMotion[]>}
|
* @returns {Observable<ViewMotion[]>}
|
||||||
@ -473,6 +474,33 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an observable for all motions, that referencing the given motion (via id)
|
||||||
|
* in the recommendation.
|
||||||
|
*/
|
||||||
|
public getRecommendationReferencingMotions(motionId: number): Observable<ViewMotion[]> {
|
||||||
|
return this.getViewModelListObservable().pipe(
|
||||||
|
map((motions: ViewMotion[]): ViewMotion[] => {
|
||||||
|
return motions.filter((motion: ViewMotion): boolean => {
|
||||||
|
if (!motion.recommendationExtension) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check, if this motion has the motionId in it's recommendation
|
||||||
|
const placeholderRegex = /\[motion:(\d+)\]/g;
|
||||||
|
let match;
|
||||||
|
while ((match = placeholderRegex.exec(motion.recommendationExtension))) {
|
||||||
|
if (parseInt(match[1], 10) === motionId) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the amendments to a given motion
|
* Returns the amendments to a given motion
|
||||||
*
|
*
|
||||||
|
@ -296,7 +296,7 @@ export class ViewMotion extends BaseViewModelWithAgendaItemAndListOfSpeakers<Mot
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns the current recommendation extension if the workwlof allows for extenstion fields
|
* @returns the current recommendation extension if the workflow allows for extenstion fields
|
||||||
*/
|
*/
|
||||||
public get recommendationExtension(): string {
|
public get recommendationExtension(): string {
|
||||||
if (this.recommendation && this.recommendation.show_recommendation_extension_field) {
|
if (this.recommendation && this.recommendation.show_recommendation_extension_field) {
|
||||||
|
@ -329,6 +329,14 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- recommendation referencing motions -->
|
||||||
|
<div *ngIf="!editMotion && recommendationReferencingMotions.length > 0">
|
||||||
|
<h4 translate>Recommendation-referencing motions</h4>
|
||||||
|
<div *ngFor="let motion of recommendationReferencingMotions">
|
||||||
|
<a [routerLink]="motion.getDetailStateURL()">{{ motion.identifierOrTitle }}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Category -->
|
<!-- Category -->
|
||||||
<!-- Disabled during "new motion" since changing has no effect -->
|
<!-- Disabled during "new motion" since changing has no effect -->
|
||||||
<div *ngIf="!editMotion && categoryObserver.value.length">
|
<div *ngIf="!editMotion && categoryObserver.value.length">
|
||||||
|
@ -371,6 +371,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
|||||||
*/
|
*/
|
||||||
private navigationSubscription: Subscription;
|
private navigationSubscription: Subscription;
|
||||||
|
|
||||||
|
public recommendationReferencingMotions: ViewMotion[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs the detail view.
|
* Constructs the detail view.
|
||||||
*
|
*
|
||||||
@ -614,6 +616,9 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit,
|
|||||||
this.amendments = amendments;
|
this.amendments = amendments;
|
||||||
this.recalcUnifiedChanges();
|
this.recalcUnifiedChanges();
|
||||||
}),
|
}),
|
||||||
|
this.repo
|
||||||
|
.getRecommendationReferencingMotions(motionId)
|
||||||
|
.subscribe(motions => (this.recommendationReferencingMotions = motions)),
|
||||||
this.changeRecoRepo
|
this.changeRecoRepo
|
||||||
.getChangeRecosOfMotionObservable(motionId)
|
.getChangeRecosOfMotionObservable(motionId)
|
||||||
.subscribe((recos: ViewMotionChangeRecommendation[]) => {
|
.subscribe((recos: ViewMotionChangeRecommendation[]) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ChangeRecoMode, LineNumberingMode } from 'app/site/motions/models/view-motion';
|
import { ChangeRecoMode, LineNumberingMode, MotionTitleInformation } from 'app/site/motions/models/view-motion';
|
||||||
import { ReferencedMotions } from '../base/base-motion-slide';
|
import { ReferencedMotions } from '../base/base-motion-slide';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -66,6 +66,7 @@ export interface MotionSlideData {
|
|||||||
recommender?: string;
|
recommender?: string;
|
||||||
recommendation?: string;
|
recommendation?: string;
|
||||||
recommendation_extension?: string;
|
recommendation_extension?: string;
|
||||||
|
recommendation_referencing_motions?: MotionTitleInformation[];
|
||||||
referenced_motions?: ReferencedMotions;
|
referenced_motions?: ReferencedMotions;
|
||||||
base_motion?: MotionSlideDataBaseMotion;
|
base_motion?: MotionSlideDataBaseMotion;
|
||||||
base_statute?: MotionSlideDataBaseStatute;
|
base_statute?: MotionSlideDataBaseStatute;
|
||||||
|
@ -11,6 +11,14 @@
|
|||||||
<h3>{{ data.data.recommender }}</h3>
|
<h3>{{ data.data.recommender }}</h3>
|
||||||
{{ getRecommendationLabel() }}
|
{{ getRecommendationLabel() }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- recommendation referencing motions -->
|
||||||
|
<div *ngIf="data.data.recommendation_referencing_motions">
|
||||||
|
<h3 translate>Recommendation-referencing motions</h3>
|
||||||
|
<div *ngFor="let titleInformation of data.data.recommendation_referencing_motions">
|
||||||
|
{{ getIdentifierOrTitle(titleInformation) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div [ngStyle]="{width: data.data.show_meta_box ? 'calc(100% - 250px)' : '100%'}">
|
<div [ngStyle]="{width: data.data.show_meta_box ? 'calc(100% - 250px)' : '100%'}">
|
||||||
|
@ -4,7 +4,7 @@ import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
|
|||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
import { MotionSlideData, MotionSlideDataAmendment } from './motion-slide-data';
|
import { MotionSlideData, MotionSlideDataAmendment } from './motion-slide-data';
|
||||||
import { ChangeRecoMode, LineNumberingMode } from 'app/site/motions/models/view-motion';
|
import { ChangeRecoMode, LineNumberingMode, MotionTitleInformation } from 'app/site/motions/models/view-motion';
|
||||||
import { DiffLinesInParagraph, DiffService, LineRange } from 'app/core/ui-services/diff.service';
|
import { DiffLinesInParagraph, DiffService, LineRange } from 'app/core/ui-services/diff.service';
|
||||||
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
import { LinenumberingService } from 'app/core/ui-services/linenumbering.service';
|
||||||
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
|
import { ViewUnifiedChange } from 'app/shared/models/motions/view-unified-change';
|
||||||
@ -118,6 +118,10 @@ export class MotionSlideComponent extends BaseMotionSlideComponent<MotionSlideDa
|
|||||||
super(translate, motionRepo);
|
super(translate, motionRepo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getIdentifierOrTitle(titleInformation: MotionTitleInformation): string {
|
||||||
|
return this.motionRepo.getIdentifierOrTitle(titleInformation);
|
||||||
|
}
|
||||||
|
|
||||||
public getRecommendationLabel(): string {
|
public getRecommendationLabel(): string {
|
||||||
let recommendation = this.translate.instant(this.data.data.recommendation);
|
let recommendation = this.translate.instant(this.data.data.recommendation);
|
||||||
if (this.data.data.recommendation_extension) {
|
if (this.data.data.recommendation_extension) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import re
|
import re
|
||||||
from typing import Any, Dict, Optional
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from ..users.projector import get_user_name
|
from ..users.projector import get_user_name
|
||||||
from ..utils.projector import (
|
from ..utils.projector import (
|
||||||
@ -228,6 +228,7 @@ async def motion_slide(
|
|||||||
return_value["modified_final_version"] = motion["modified_final_version"]
|
return_value["modified_final_version"] = motion["modified_final_version"]
|
||||||
|
|
||||||
if show_meta_box:
|
if show_meta_box:
|
||||||
|
# Add recommendation, if enabled in config (and the motion has one)
|
||||||
if (
|
if (
|
||||||
not await get_config(
|
not await get_config(
|
||||||
all_data, "motions_disable_recommendation_on_projector"
|
all_data, "motions_disable_recommendation_on_projector"
|
||||||
@ -254,6 +255,7 @@ async def motion_slide(
|
|||||||
all_data, "motions_recommendations_by"
|
all_data, "motions_recommendations_by"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Add submitters
|
||||||
return_value["submitter"] = [
|
return_value["submitter"] = [
|
||||||
await get_user_name(all_data, submitter["user_id"])
|
await get_user_name(all_data, submitter["user_id"])
|
||||||
for submitter in sorted(
|
for submitter in sorted(
|
||||||
@ -261,9 +263,50 @@ async def motion_slide(
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Add recommendation-referencing motions
|
||||||
|
return_value[
|
||||||
|
"recommendation_referencing_motions"
|
||||||
|
] = await get_recommendation_referencing_motions(all_data, motion_id)
|
||||||
|
|
||||||
return return_value
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
async def get_recommendation_referencing_motions(
|
||||||
|
all_data: AllData, motion_id: int
|
||||||
|
) -> Optional[List[Dict[str, Any]]]:
|
||||||
|
"""
|
||||||
|
Returns all title information for motions, that are referencing
|
||||||
|
the given motion (by id) in their recommendation. If there are no
|
||||||
|
motions, None is returned (instead of []).
|
||||||
|
"""
|
||||||
|
recommendation_referencing_motions = []
|
||||||
|
for motion in all_data["motions/motion"].values():
|
||||||
|
# Motion must have a recommendation and a recommendaiton extension
|
||||||
|
if not motion["recommendation_id"] or not motion["recommendation_extension"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# The recommendation must allow the extension field (there might be left-overs
|
||||||
|
# in a motions recommendation extension..)
|
||||||
|
recommendation = await get_state(all_data, motion, "recommendation_id")
|
||||||
|
if not recommendation["show_recommendation_extension_field"]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Find referenced motion ids
|
||||||
|
referenced_ids = [
|
||||||
|
int(id)
|
||||||
|
for id in motion_placeholder_regex.findall(
|
||||||
|
motion["recommendation_extension"]
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# if one of the referenced ids is the given motion, add the current motion.
|
||||||
|
if motion_id in referenced_ids:
|
||||||
|
recommendation_referencing_motions.append(
|
||||||
|
{"title": motion["title"], "identifier": motion["identifier"]}
|
||||||
|
)
|
||||||
|
return recommendation_referencing_motions or None
|
||||||
|
|
||||||
|
|
||||||
async def motion_block_slide(
|
async def motion_block_slide(
|
||||||
all_data: AllData, element: Dict[str, Any], projector_id: int
|
all_data: AllData, element: Dict[str, Any], projector_id: int
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
@ -297,6 +297,7 @@ async def test_motion_slide(all_data):
|
|||||||
"line_length": 90,
|
"line_length": 90,
|
||||||
"line_numbering_mode": "none",
|
"line_numbering_mode": "none",
|
||||||
"preamble": "The assembly may decide:",
|
"preamble": "The assembly may decide:",
|
||||||
|
"recommendation_referencing_motions": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -322,6 +323,7 @@ async def test_amendment_slide(all_data):
|
|||||||
"line_length": 90,
|
"line_length": 90,
|
||||||
"line_numbering_mode": "none",
|
"line_numbering_mode": "none",
|
||||||
"preamble": "The assembly may decide:",
|
"preamble": "The assembly may decide:",
|
||||||
|
"recommendation_referencing_motions": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -347,4 +349,5 @@ async def test_statute_amendment_slide(all_data):
|
|||||||
"line_length": 90,
|
"line_length": 90,
|
||||||
"line_numbering_mode": "none",
|
"line_numbering_mode": "none",
|
||||||
"preamble": "The assembly may decide:",
|
"preamble": "The assembly may decide:",
|
||||||
|
"recommendation_referencing_motions": None,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user