motion detail imrovements
This commit is contained in:
parent
24cf01b03f
commit
53a8392e33
@ -2,6 +2,7 @@ import { Deserializer } from '../base/deserializer';
|
||||
|
||||
/**
|
||||
* Representation of a Motion Log.
|
||||
* TODO: better documentation
|
||||
*
|
||||
* @ignore
|
||||
*/
|
||||
@ -9,7 +10,7 @@ export class MotionLog extends Deserializer {
|
||||
public message_list: string[];
|
||||
public person_id: number;
|
||||
public time: string;
|
||||
public message: string;
|
||||
public message: string; // a pre-translated message in the servers' defined language
|
||||
|
||||
public constructor(input?: any) {
|
||||
super(input);
|
||||
|
@ -106,9 +106,17 @@
|
||||
</os-head-bar>
|
||||
|
||||
<!-- Title -->
|
||||
<h1 class="title-left on-transition-fade" *ngIf="motion && !editMotion">
|
||||
<div class="title-left on-transition-fade" *ngIf="motion && !editMotion">
|
||||
<div class="title-line">
|
||||
<h1>
|
||||
{{ motion.title }}
|
||||
</h1>
|
||||
<button mat-icon-button color="primary" (click)="toggleFavorite()">
|
||||
<mat-icon>{{ motion.star ? 'star' : 'star_border' }}</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<span class="main-nav-color title-font"><span translate>Sequential number</span> {{ motion.id }}</span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="vp.isMobile; then mobileView; else desktopView"></ng-container>
|
||||
|
||||
@ -145,6 +153,10 @@
|
||||
|
||||
<os-motion-comments *ngIf="!editMotion" [motion]="motion"></os-motion-comments>
|
||||
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
|
||||
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded =!motionLogExpanded">
|
||||
<span translate>Show motion log</span>
|
||||
</button>
|
||||
<os-motion-log *ngIf="motionLogExpanded" [motion]="motion"></os-motion-log>
|
||||
</mat-accordion>
|
||||
</ng-template>
|
||||
|
||||
@ -158,6 +170,10 @@
|
||||
|
||||
<os-motion-comments *ngIf="!editMotion" [motion]="motion"></os-motion-comments>
|
||||
<os-personal-note *ngIf="!editMotion" [motion]="motion"></os-personal-note>
|
||||
<button mat-button *ngIf="canShowLog" (click)="motionLogExpanded =!motionLogExpanded">
|
||||
<span translate>Show motion log</span>
|
||||
</button>
|
||||
<os-motion-log *ngIf="motionLogExpanded" [motion]="motion"></os-motion-log>
|
||||
</div>
|
||||
<div class="desktop-right ">
|
||||
<!-- Content -->
|
||||
@ -264,6 +280,9 @@
|
||||
: ('not set' | translate)
|
||||
}}
|
||||
</mat-basic-chip>
|
||||
<button mat-button *ngIf="canFollowRecommendation()" (click)="onFollowRecButton()">
|
||||
<span translate>Follow recommendation</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Category -->
|
||||
@ -310,12 +329,14 @@
|
||||
<div *ngIf="!editMotion">
|
||||
<os-motion-poll *ngFor="let poll of motion.motion.polls; let i = index" [rawPoll]="poll" [pollIndex]="i">
|
||||
</os-motion-poll>
|
||||
<button mat-button *ngIf="perms.isAllowed('createpoll', motion)" (click)="createPoll()">
|
||||
<div class="create-poll-button" *ngIf="perms.isAllowed('createpoll', motion)">
|
||||
<button mat-button (click)="createPoll()">
|
||||
<mat-icon class="main-nav-color">poll</mat-icon>
|
||||
<span translate>Create poll</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #contentTemplate>
|
||||
@ -467,7 +488,7 @@
|
||||
<!-- Attachments -->
|
||||
<div *ngIf="motion.hasAttachments() || editMotion" class="content-field">
|
||||
<div *ngIf="!editMotion">
|
||||
<h3>{{ "Attachments" | translate }}<mat-icon>attach_file</mat-icon></h3>
|
||||
<h3>{{ 'Attachments' | translate }}<mat-icon>attach_file</mat-icon></h3>
|
||||
<mat-list dense>
|
||||
<mat-list-item *ngFor="let file of motion.attachments">
|
||||
<a [routerLink]="" (click)="onClickAttacment(file)">{{ file.title }}</a>
|
||||
|
@ -263,3 +263,14 @@ span {
|
||||
.main-nav-color {
|
||||
color: rgba(0, 0, 0, 0.54);
|
||||
}
|
||||
|
||||
.title-line {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.create-poll-button {
|
||||
margin-top: 10px;
|
||||
button {
|
||||
padding: 0px;
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ import { PromptService } from 'app/core/services/prompt.service';
|
||||
import { AgendaRepositoryService } from 'app/site/agenda/services/agenda-repository.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
||||
import { PersonalNoteService } from '../../services/personal-note.service';
|
||||
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||
|
||||
/**
|
||||
* Component for the motion detail view
|
||||
@ -77,6 +79,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public newMotion = false;
|
||||
|
||||
/**
|
||||
* Toggle to expand/hide the motion log.
|
||||
*/
|
||||
public motionLogExpanded = false;
|
||||
|
||||
/**
|
||||
* Sets the motions, e.g. via an autoupdate. Reload important things here:
|
||||
* - Reload the recommendation. Not changed with autoupdates, but if the motion is loaded this needs to run.
|
||||
@ -93,6 +100,21 @@ 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.motion.motion.log_messages &&
|
||||
this.motion.motion.log_messages.length
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the target motion. Accessed via the getter and setter.
|
||||
*/
|
||||
@ -260,6 +282,11 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
*/
|
||||
public highlightedLine: number;
|
||||
|
||||
/**
|
||||
* The personal notes' content for this motion
|
||||
*/
|
||||
public personalNoteContent: PersonalNoteContent;
|
||||
|
||||
/**
|
||||
* Constuct the detail view.
|
||||
*
|
||||
@ -281,6 +308,7 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
* @param sanitizer For making HTML SafeHTML
|
||||
* @param promptService ensure safe deletion
|
||||
* @param pdfExport export the motion to pdf
|
||||
* @param personalNoteService: personal comments and favorite marker
|
||||
*/
|
||||
public constructor(
|
||||
title: Title,
|
||||
@ -301,7 +329,8 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
private configService: ConfigService,
|
||||
private sanitizer: DomSanitizer,
|
||||
private promptService: PromptService,
|
||||
private pdfExport: MotionPdfExportService
|
||||
private pdfExport: MotionPdfExportService,
|
||||
private personalNoteService: PersonalNoteService
|
||||
) {
|
||||
super(title, translate, matSnackBar);
|
||||
|
||||
@ -433,6 +462,9 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
this.repo.getViewModelObservable(motionId).subscribe(newViewMotion => {
|
||||
if (newViewMotion) {
|
||||
this.motion = newViewMotion;
|
||||
this.personalNoteService.getPersonalNoteObserver(this.motion.motion).subscribe(pn => {
|
||||
this.personalNoteContent = pn;
|
||||
});
|
||||
this.patchForm(this.motion);
|
||||
}
|
||||
});
|
||||
@ -956,4 +988,32 @@ export class MotionDetailComponent extends BaseViewComponent implements OnInit {
|
||||
public async createPoll(): Promise<void> {
|
||||
await this.repo.createPoll(this.motion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a recommendation can be followed. Checks for permissions and additionally if a recommentadion is present
|
||||
*/
|
||||
public get canFollowRecommendation(): boolean {
|
||||
if (
|
||||
this.perms.isAllowed('createPoll', this.motion) &&
|
||||
this.motion.recommendation &&
|
||||
this.motion.recommendation.recommendation_label
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the 'follow recommendation' button
|
||||
*/
|
||||
public onFollowRecButton(): void {
|
||||
this.repo.followRecommendation(this.motion);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles the favorite status
|
||||
*/
|
||||
public async toggleFavorite(): Promise<void> {
|
||||
this.personalNoteService.setPersonalNoteStar(this.motion.motion, !this.motion.star);
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,12 @@
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
|
||||
<mat-cell *matCellDef="let motion">
|
||||
<div class="innerTable">
|
||||
<span class="motion-list-title">{{ motion.title }}</span>
|
||||
<span class="motion-list-title">{{ motion.title }}
|
||||
<span>
|
||||
<mat-icon inline>{{ motion.star ? 'star' : 'star_border' }}</mat-icon>
|
||||
</span>
|
||||
</span>
|
||||
|
||||
<!-- attachments -->
|
||||
<span class="attached-files" *ngIf="motion.hasAttachments()">
|
||||
<!-- <mat-basic-chip class="bluegrey"> <mat-icon>attach_file</mat-icon> </mat-basic-chip> -->
|
||||
|
@ -0,0 +1,12 @@
|
||||
<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>
|
@ -0,0 +1,3 @@
|
||||
.small-messages {
|
||||
font-size: x-small;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// 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();
|
||||
// });
|
||||
});
|
@ -0,0 +1,25 @@
|
||||
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() {}
|
||||
}
|
@ -1,15 +1,16 @@
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { Category } from '../../../shared/models/motions/category';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { BaseModel } from '../../../shared/models/base/base-model';
|
||||
import { BaseViewModel } from '../../base/base-view-model';
|
||||
import { ViewMotionCommentSection } from './view-motion-comment-section';
|
||||
import { MotionComment } from '../../../shared/models/motions/motion-comment';
|
||||
import { Category } from '../../../shared/models/motions/category';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { MotionComment } from '../../../shared/models/motions/motion-comment';
|
||||
import { PersonalNoteContent } from 'app/shared/models/users/personal-note';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { ViewMotionCommentSection } from './view-motion-comment-section';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
|
||||
/**
|
||||
* The line numbering mode for the motion detail view.
|
||||
@ -48,6 +49,7 @@ export class ViewMotion extends BaseViewModel {
|
||||
protected _item: Item;
|
||||
protected _block: MotionBlock;
|
||||
protected _attachments: Mediafile[];
|
||||
public personalNote: PersonalNoteContent;
|
||||
|
||||
/**
|
||||
* Is set by the repository; this is the order of the flat call list given by
|
||||
@ -230,6 +232,24 @@ export class ViewMotion extends BaseViewModel {
|
||||
return this.motion.comments.map(comment => comment.section_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter to query the 'favorite'/'star' status of the motions
|
||||
*
|
||||
* @returns the current state
|
||||
*/
|
||||
public get star(): boolean {
|
||||
return this.personalNote && this.personalNote.star ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Queries if any personal comments are rpesent
|
||||
*
|
||||
* @returns true if personalContent is present and has notes
|
||||
*/
|
||||
public get hasNotes(): boolean {
|
||||
return this.personalNote && this.personalNote.note ? true : false;
|
||||
}
|
||||
|
||||
public constructor(
|
||||
motion?: Motion,
|
||||
category?: Category,
|
||||
|
@ -22,6 +22,7 @@ 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],
|
||||
@ -44,7 +45,8 @@ import { MotionPollDialogComponent } from './components/motion-poll/motion-poll-
|
||||
MotionImportListComponent,
|
||||
ManageSubmittersComponent,
|
||||
MotionPollComponent,
|
||||
MotionPollDialogComponent
|
||||
MotionPollDialogComponent,
|
||||
MotionLogComponent
|
||||
],
|
||||
entryComponents: [
|
||||
MotionChangeRecommendationComponent,
|
||||
|
@ -26,7 +26,7 @@ export class MotionFilterListService extends FilterListService<Motion, ViewMotio
|
||||
this.motionBlockFilterOptions,
|
||||
this.recommendationFilterOptions,
|
||||
this.motionCommentFilterOptions
|
||||
];
|
||||
].concat(this.staticFilterOptions);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,6 +66,39 @@ export class MotionFilterListService extends FilterListService<Motion, ViewMotio
|
||||
options: []
|
||||
};
|
||||
|
||||
public staticFilterOptions = [
|
||||
{
|
||||
property: 'star',
|
||||
label: 'Favorites',
|
||||
isActive: false,
|
||||
options: [
|
||||
{
|
||||
condition: true,
|
||||
label: 'Is favorite'
|
||||
},
|
||||
{
|
||||
condition: false,
|
||||
label: 'Is not favorite'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
property: 'hasNotes',
|
||||
label: 'Personal notes',
|
||||
isActive: false,
|
||||
options: [
|
||||
{
|
||||
condition: true,
|
||||
label: 'Has notes'
|
||||
},
|
||||
{
|
||||
condition: false,
|
||||
label: 'Does not have notes'
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor. Subscribes to a variety of Repository to dynamically update
|
||||
* the available filters
|
||||
|
@ -3,32 +3,33 @@ import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap, map } from 'rxjs/operators';
|
||||
|
||||
import { DataSendService } from '../../../core/services/data-send.service';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { Category } from '../../../shared/models/motions/category';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
import { ChangeRecoMode, ViewMotion } from '../models/view-motion';
|
||||
import { BaseRepository } from '../../base/base-repository';
|
||||
import { Category } from '../../../shared/models/motions/category';
|
||||
import { ChangeRecoMode, ViewMotion } from '../models/view-motion';
|
||||
import { CollectionStringModelMapperService } from '../../../core/services/collectionStringModelMapper.service';
|
||||
import { CreateMotion } from '../models/create-motion';
|
||||
import { DataSendService } from '../../../core/services/data-send.service';
|
||||
import { DataStoreService } from '../../../core/services/data-store.service';
|
||||
import { LinenumberingService } from './linenumbering.service';
|
||||
import { DiffLinesInParagraph, DiffService, LineRange, ModificationType } from './diff.service';
|
||||
import { ViewChangeReco } from '../models/view-change-reco';
|
||||
import { HttpService } from 'app/core/services/http.service';
|
||||
import { Identifiable } from '../../../shared/models/base/identifiable';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
import { LinenumberingService } from './linenumbering.service';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { Motion } from '../../../shared/models/motions/motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { MotionChangeReco } from '../../../shared/models/motions/motion-change-reco';
|
||||
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
|
||||
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||
import { PersonalNoteService } from './personal-note.service';
|
||||
import { TreeService } from 'app/core/services/tree.service';
|
||||
import { User } from '../../../shared/models/users/user';
|
||||
import { ViewChangeReco } from '../models/view-change-reco';
|
||||
import { ViewMotionAmendedParagraph } from '../models/view-motion-amended-paragraph';
|
||||
import { ViewUnifiedChange } from '../models/view-unified-change';
|
||||
import { ViewStatuteParagraph } from '../models/view-statute-paragraph';
|
||||
import { Identifiable } from '../../../shared/models/base/identifiable';
|
||||
import { CollectionStringModelMapperService } from '../../../core/services/collectionStringModelMapper.service';
|
||||
import { HttpService } from 'app/core/services/http.service';
|
||||
import { Item } from 'app/shared/models/agenda/item';
|
||||
import { OSTreeSortEvent } from 'app/shared/components/sorting-tree/sorting-tree.component';
|
||||
import { TreeService } from 'app/core/services/tree.service';
|
||||
import { ViewMotionAmendedParagraph } from '../models/view-motion-amended-paragraph';
|
||||
import { CreateMotion } from '../models/create-motion';
|
||||
import { MotionBlock } from 'app/shared/models/motions/motion-block';
|
||||
import { Mediafile } from 'app/shared/models/mediafiles/mediafile';
|
||||
import { MotionPoll } from 'app/shared/models/motions/motion-poll';
|
||||
import { Workflow } from '../../../shared/models/motions/workflow';
|
||||
import { WorkflowState } from '../../../shared/models/motions/workflow-state';
|
||||
|
||||
/**
|
||||
* Repository Services for motions (and potentially categories)
|
||||
@ -56,6 +57,7 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
* @param httpService OpenSlides own Http service
|
||||
* @param lineNumbering Line numbering for motion text
|
||||
* @param diff Display changes in motion text as diff.
|
||||
* @param personalNoteService service fo personal notes
|
||||
*/
|
||||
public constructor(
|
||||
DS: DataStoreService,
|
||||
@ -64,7 +66,8 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
private httpService: HttpService,
|
||||
private readonly lineNumbering: LinenumberingService,
|
||||
private readonly diff: DiffService,
|
||||
private treeService: TreeService
|
||||
private treeService: TreeService,
|
||||
private personalNoteService: PersonalNoteService
|
||||
) {
|
||||
super(DS, mapperService, Motion, [Category, User, Workflow, Item, MotionBlock, Mediafile]);
|
||||
}
|
||||
@ -106,6 +109,10 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
let virtualWeightCounter = 0;
|
||||
while (!(m = iterator.next()).done) {
|
||||
m.value.callListWeight = virtualWeightCounter++;
|
||||
const motion = m.value;
|
||||
this.personalNoteService
|
||||
.getPersonalNoteObserver(motion.motion)
|
||||
.subscribe(note => (motion.personalNote = note));
|
||||
}
|
||||
})
|
||||
);
|
||||
@ -651,7 +658,7 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a haap request to delete the given poll
|
||||
* Sends a http request to delete the given poll
|
||||
*
|
||||
* @param poll
|
||||
*/
|
||||
@ -659,4 +666,16 @@ export class MotionRepositoryService extends BaseRepository<ViewMotion, Motion>
|
||||
const url = '/rest/motions/motion-poll/' + poll.id + '/';
|
||||
await this.httpService.delete(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals the acceptance of the current recommendation to the server
|
||||
*
|
||||
* @param motion A ViewMotion
|
||||
*/
|
||||
public async followRecommendation(motion: ViewMotion): Promise<void> {
|
||||
if (motion.recommendation_id) {
|
||||
const restPath = `/rest/motions/motion/${motion.id}/follow_recommendation/`;
|
||||
await this.httpService.post(restPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -127,4 +127,19 @@ export class PersonalNoteService {
|
||||
await this.http.put(`rest/users/personal-note/${pnObject.id}/`, pnObject);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the 'favorite' status of a personal note, without changing other information
|
||||
*
|
||||
* @param model
|
||||
* @param star The new status to set
|
||||
*/
|
||||
public async setPersonalNoteStar(model: BaseModel, star: boolean): Promise<void> {
|
||||
let content: PersonalNoteContent = this.getPersonalNoteContent(model.collectionString, model.id);
|
||||
if (!content) {
|
||||
content = { note: null, star: star };
|
||||
}
|
||||
content.star = star;
|
||||
return this.savePersonalNote(model, content);
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,8 @@ body {
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3 {
|
||||
h3,
|
||||
.title-font {
|
||||
font-family: Fira Sans Condensed, Roboto-condensed, Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user