Show latest meaningfull poll results in autopilot
Shows the latest meaningfull poll result in autopilot The last published poll result from the corresponding content object
This commit is contained in:
parent
2943c969ab
commit
10614ca57b
@ -1,5 +1,5 @@
|
|||||||
<div *ngIf="poll">
|
<div *ngIf="poll">
|
||||||
<table class="assignment-result-table">
|
<table class="assignment-result-table" *ngIf="hasResults && canSeeResults">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="voting-option">{{ 'Candidates' | translate }}</th>
|
<th class="voting-option">{{ 'Candidates' | translate }}</th>
|
||||||
@ -51,4 +51,18 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<!-- No results yet -->
|
||||||
|
<div *ngIf="!hasResults">
|
||||||
|
<i>
|
||||||
|
{{ 'No results yet.' | translate }}
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Has results, but user cannot see -->
|
||||||
|
<div *ngIf="hasResults && !canSeeResults">
|
||||||
|
<i>
|
||||||
|
{{ 'Counting of votes is in progress ...' | translate }}
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { BaseComponent } from 'app/base.component';
|
||||||
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
|
import { AssignmentPollMethod } from 'app/shared/models/assignments/assignment-poll';
|
||||||
|
import { PollState } from 'app/shared/models/poll/base-poll';
|
||||||
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
||||||
import { AssignmentPollService } from 'app/site/assignments/modules/assignment-poll/services/assignment-poll.service';
|
import { AssignmentPollService } from 'app/site/assignments/modules/assignment-poll/services/assignment-poll.service';
|
||||||
import { PollData, PollTableData, VotingResult } from 'app/site/polls/services/poll.service';
|
import { PollData, PollTableData, VotingResult } from 'app/site/polls/services/poll.service';
|
||||||
@ -10,16 +16,18 @@ import { PollData, PollTableData, VotingResult } from 'app/site/polls/services/p
|
|||||||
templateUrl: './assignment-poll-detail-content.component.html',
|
templateUrl: './assignment-poll-detail-content.component.html',
|
||||||
styleUrls: ['./assignment-poll-detail-content.component.scss']
|
styleUrls: ['./assignment-poll-detail-content.component.scss']
|
||||||
})
|
})
|
||||||
export class AssignmentPollDetailContentComponent {
|
export class AssignmentPollDetailContentComponent extends BaseComponent {
|
||||||
@Input()
|
@Input()
|
||||||
public poll: ViewAssignmentPoll | PollData;
|
public poll: ViewAssignmentPoll | PollData;
|
||||||
|
|
||||||
public constructor(private pollService: AssignmentPollService) {}
|
|
||||||
|
|
||||||
private get method(): string {
|
private get method(): string {
|
||||||
return this.poll.pollmethod;
|
return this.poll.pollmethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get state(): PollState {
|
||||||
|
return this.poll.state;
|
||||||
|
}
|
||||||
|
|
||||||
public get showYHeader(): boolean {
|
public get showYHeader(): boolean {
|
||||||
return this.isMethodY || this.isMethodYN || this.isMethodYNA;
|
return this.isMethodY || this.isMethodYN || this.isMethodYNA;
|
||||||
}
|
}
|
||||||
@ -44,10 +52,35 @@ export class AssignmentPollDetailContentComponent {
|
|||||||
return this.method === AssignmentPollMethod.YNA;
|
return this.method === AssignmentPollMethod.YNA;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get isFinished(): boolean {
|
||||||
|
return this.state === PollState.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPublished(): boolean {
|
||||||
|
return this.state === PollState.Published;
|
||||||
|
}
|
||||||
|
|
||||||
public get tableData(): PollTableData[] {
|
public get tableData(): PollTableData[] {
|
||||||
return this.pollService.generateTableData(this.poll);
|
return this.pollService.generateTableData(this.poll);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get hasResults(): boolean {
|
||||||
|
return this.isFinished || this.isPublished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get canSeeResults(): boolean {
|
||||||
|
return this.operator.hasPerms(this.permission.assignmentsCanManage) || this.isPublished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
titleService: Title,
|
||||||
|
translateService: TranslateService,
|
||||||
|
private pollService: AssignmentPollService,
|
||||||
|
private operator: OperatorService
|
||||||
|
) {
|
||||||
|
super(titleService, translateService);
|
||||||
|
}
|
||||||
|
|
||||||
public getVoteClass(votingResult: VotingResult): string {
|
public getVoteClass(votingResult: VotingResult): string {
|
||||||
const votingClass = votingResult.vote;
|
const votingClass = votingResult.vote;
|
||||||
if (this.isMethodN && votingClass === 'no') {
|
if (this.isMethodN && votingClass === 'no') {
|
||||||
|
@ -74,7 +74,9 @@ export class ChartsComponent extends BaseViewComponentDirective {
|
|||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
public set data(inputData: ChartData) {
|
public set data(inputData: ChartData) {
|
||||||
this.progressInputData(inputData);
|
if (inputData) {
|
||||||
|
this.progressInputData(inputData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -85,6 +87,9 @@ export class ChartsComponent extends BaseViewComponentDirective {
|
|||||||
return {
|
return {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
|
animation: {
|
||||||
|
duration: 0
|
||||||
|
},
|
||||||
tooltips: {
|
tooltips: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
@ -96,6 +101,9 @@ export class ChartsComponent extends BaseViewComponentDirective {
|
|||||||
return {
|
return {
|
||||||
responsive: true,
|
responsive: true,
|
||||||
maintainAspectRatio: false,
|
maintainAspectRatio: false,
|
||||||
|
animation: {
|
||||||
|
duration: 0
|
||||||
|
},
|
||||||
tooltips: {
|
tooltips: {
|
||||||
enabled: false
|
enabled: false
|
||||||
},
|
},
|
||||||
|
@ -1,39 +1,55 @@
|
|||||||
<div class="result-wrapper" *ngIf="hasVotes">
|
<div class="result-wrapper" *ngIf="poll">
|
||||||
<!-- result table -->
|
<ng-container *ngIf="hasResults && canSeeResults">
|
||||||
<table class="result-table">
|
<!-- result table -->
|
||||||
<tbody>
|
<table class="result-table">
|
||||||
<tr>
|
<tbody>
|
||||||
<th></th>
|
<tr>
|
||||||
<th colspan="2">{{ 'Votes' | translate }}</th>
|
<th></th>
|
||||||
</tr>
|
<th colspan="2">{{ 'Votes' | translate }}</th>
|
||||||
<tr *ngFor="let row of getTableData()" [class]="row.votingOption">
|
</tr>
|
||||||
<!-- YNA/Valid etc -->
|
<tr *ngFor="let row of tableData; trackBy: trackByIndex" [class]="row.votingOption">
|
||||||
<td>
|
<!-- YNA/Valid etc -->
|
||||||
<os-icon-container *ngIf="row.value[0].icon" [icon]="row.value[0].icon" [size]="iconSize">
|
<td>
|
||||||
{{ row.votingOption | pollKeyVerbose | translate }}
|
<os-icon-container *ngIf="row.value[0].icon" [icon]="row.value[0].icon" [size]="iconSize">
|
||||||
</os-icon-container>
|
{{ row.votingOption | pollKeyVerbose | translate }}
|
||||||
<span *ngIf="!row.value[0].icon">
|
</os-icon-container>
|
||||||
{{ row.votingOption | pollKeyVerbose | translate }}
|
<span *ngIf="!row.value[0].icon">
|
||||||
</span>
|
{{ row.votingOption | pollKeyVerbose | translate }}
|
||||||
</td>
|
</span>
|
||||||
|
</td>
|
||||||
|
|
||||||
<!-- Percent numbers -->
|
<!-- Percent numbers -->
|
||||||
<td class="result-cell-definition">
|
<td class="result-cell-definition">
|
||||||
<span *ngIf="row.value[0].showPercent">
|
<span *ngIf="row.value[0].showPercent">
|
||||||
{{ row.value[0].amount | pollPercentBase: poll:'motion' }}
|
{{ row.value[0].amount | pollPercentBase: poll:'motion' }}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<!-- Voices -->
|
<!-- Voices -->
|
||||||
<td class="result-cell-definition">
|
<td class="result-cell-definition">
|
||||||
{{ row.value[0].amount | parsePollNumber }}
|
{{ row.value[0].amount | parsePollNumber }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<!-- Chart -->
|
<!-- Chart -->
|
||||||
<div class="doughnut-chart" *ngIf="showChart">
|
<div class="doughnut-chart">
|
||||||
<os-charts type="doughnut" [data]="chartData | async"></os-charts>
|
<os-charts type="doughnut" [data]="chartData"></os-charts>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<!-- No results yet -->
|
||||||
|
<div *ngIf="!hasResults">
|
||||||
|
<i>
|
||||||
|
{{ 'No results yet.' | translate }}
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Has results, but user cannot see -->
|
||||||
|
<div *ngIf="hasResults && !canSeeResults">
|
||||||
|
<i>
|
||||||
|
{{ 'Counting of votes is in progress ...' | translate }}
|
||||||
|
</i>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
|
||||||
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { BaseComponent } from 'app/base.component';
|
||||||
|
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||||
|
import { PollState } from 'app/shared/models/poll/base-poll';
|
||||||
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
|
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
|
||||||
import { MotionPollService } from 'app/site/motions/services/motion-poll.service';
|
import { MotionPollService } from 'app/site/motions/services/motion-poll.service';
|
||||||
import { PollData, PollTableData } from 'app/site/polls/services/poll.service';
|
import { PollData, PollTableData } from 'app/site/polls/services/poll.service';
|
||||||
@ -10,31 +14,65 @@ import { ChartData } from '../charts/charts.component';
|
|||||||
@Component({
|
@Component({
|
||||||
selector: 'os-motion-poll-detail-content',
|
selector: 'os-motion-poll-detail-content',
|
||||||
templateUrl: './motion-poll-detail-content.component.html',
|
templateUrl: './motion-poll-detail-content.component.html',
|
||||||
styleUrls: ['./motion-poll-detail-content.component.scss']
|
styleUrls: ['./motion-poll-detail-content.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class MotionPollDetailContentComponent implements OnInit {
|
export class MotionPollDetailContentComponent extends BaseComponent {
|
||||||
@Input()
|
private _poll: ViewMotionPoll | PollData;
|
||||||
public poll: ViewMotionPoll | PollData;
|
|
||||||
|
public chartData: ChartData;
|
||||||
|
public tableData: PollTableData[];
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
public chartData: BehaviorSubject<ChartData>;
|
public set poll(pollData: ViewMotionPoll | PollData) {
|
||||||
|
this._poll = pollData;
|
||||||
|
this.setTableData();
|
||||||
|
this.setChartData();
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get poll(): ViewMotionPoll | PollData {
|
||||||
|
return this._poll;
|
||||||
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
public iconSize: 'large' | 'gigantic' = 'large';
|
public iconSize: 'large' | 'gigantic' = 'large';
|
||||||
|
|
||||||
public get hasVotes(): boolean {
|
private get state(): PollState {
|
||||||
return this.poll && !!this.poll.options;
|
return this.poll.state;
|
||||||
}
|
}
|
||||||
|
|
||||||
public constructor(private motionPollService: MotionPollService) {}
|
public get hasResults(): boolean {
|
||||||
|
return this.isFinished || this.isPublished;
|
||||||
public ngOnInit(): void {}
|
|
||||||
|
|
||||||
public getTableData(): PollTableData[] {
|
|
||||||
return this.motionPollService.generateTableData(this.poll);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get showChart(): boolean {
|
public get isFinished(): boolean {
|
||||||
return this.motionPollService.showChart(this.poll) && this.chartData && !!this.chartData.value;
|
return this.state === PollState.Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPublished(): boolean {
|
||||||
|
return this.state === PollState.Published;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get canSeeResults(): boolean {
|
||||||
|
return this.operator.hasPerms(this.permission.motionsCanManagePolls) || this.isPublished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
titleService: Title,
|
||||||
|
translate: TranslateService,
|
||||||
|
private pollService: MotionPollService,
|
||||||
|
private cd: ChangeDetectorRef,
|
||||||
|
private operator: OperatorService
|
||||||
|
) {
|
||||||
|
super(titleService, translate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setTableData(): void {
|
||||||
|
this.tableData = this.pollService.generateTableData(this.poll);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setChartData(): void {
|
||||||
|
this.chartData = this.pollService.generateChartData(this.poll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,22 +28,17 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="assignment-result-wrapper" *ngIf="poll && poll.stateHasVotes">
|
<div class="assignment-result-wrapper" *ngIf="poll">
|
||||||
<!-- Result Table -->
|
<!-- Result Table -->
|
||||||
<os-assignment-poll-detail-content [poll]="poll"></os-assignment-poll-detail-content>
|
<os-assignment-poll-detail-content [poll]="poll"></os-assignment-poll-detail-content>
|
||||||
|
|
||||||
<!-- Result Chart -->
|
<!-- Result Chart -->
|
||||||
<div class="chart-wrapper">
|
<div class="chart-wrapper" *ngIf="showResults && poll.stateHasVotes">
|
||||||
<os-charts
|
<os-charts class="assignment-result-chart" [labels]="candidatesLabels" [data]="chartData"></os-charts>
|
||||||
class="assignment-result-chart"
|
|
||||||
*ngIf="chartDataSubject.value"
|
|
||||||
[labels]="candidatesLabels"
|
|
||||||
[data]="chartDataSubject | async"
|
|
||||||
></os-charts>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Single Votes Table -->
|
<!-- Single Votes Table -->
|
||||||
<div class="named-result-table" *ngIf="poll.type === 'named'">
|
<div class="named-result-table" *ngIf="showResults && poll.stateHasVotes && poll.type === 'named'">
|
||||||
<h3>{{ 'Single votes' | translate }}</h3>
|
<h3>{{ 'Single votes' | translate }}</h3>
|
||||||
<os-list-view-table
|
<os-list-view-table
|
||||||
class="single-votes-table"
|
class="single-votes-table"
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
@ -12,6 +12,7 @@ import { AssignmentVoteRepositoryService } from 'app/core/repositories/assignmen
|
|||||||
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
import { GroupRepositoryService } from 'app/core/repositories/users/group-repository.service';
|
||||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||||
|
import { ChartData } from 'app/shared/components/charts/charts.component';
|
||||||
import { VoteValue } from 'app/shared/models/poll/base-vote';
|
import { VoteValue } from 'app/shared/models/poll/base-vote';
|
||||||
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
||||||
import { BasePollDetailComponentDirective } from 'app/site/polls/components/base-poll-detail.component';
|
import { BasePollDetailComponentDirective } from 'app/site/polls/components/base-poll-detail.component';
|
||||||
@ -22,6 +23,7 @@ import { AssignmentPollService } from '../../services/assignment-poll.service';
|
|||||||
selector: 'os-assignment-poll-detail',
|
selector: 'os-assignment-poll-detail',
|
||||||
templateUrl: './assignment-poll-detail.component.html',
|
templateUrl: './assignment-poll-detail.component.html',
|
||||||
styleUrls: ['./assignment-poll-detail.component.scss'],
|
styleUrls: ['./assignment-poll-detail.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
encapsulation: ViewEncapsulation.None
|
encapsulation: ViewEncapsulation.None
|
||||||
})
|
})
|
||||||
export class AssignmentPollDetailComponent extends BasePollDetailComponentDirective<
|
export class AssignmentPollDetailComponent extends BasePollDetailComponentDirective<
|
||||||
@ -38,6 +40,14 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponentDirect
|
|||||||
|
|
||||||
public isVoteWeightActive: boolean;
|
public isVoteWeightActive: boolean;
|
||||||
|
|
||||||
|
public get showResults(): boolean {
|
||||||
|
return this.hasPerms() || this.poll.isPublished;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get chartData(): ChartData {
|
||||||
|
return this.pollService.generateChartData(this.poll);
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
@ -51,7 +61,8 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponentDirect
|
|||||||
protected pollService: AssignmentPollService,
|
protected pollService: AssignmentPollService,
|
||||||
votesRepo: AssignmentVoteRepositoryService,
|
votesRepo: AssignmentVoteRepositoryService,
|
||||||
protected operator: OperatorService,
|
protected operator: OperatorService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
protected cd: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
title,
|
title,
|
||||||
@ -64,7 +75,8 @@ export class AssignmentPollDetailComponent extends BasePollDetailComponentDirect
|
|||||||
pollDialog,
|
pollDialog,
|
||||||
pollService,
|
pollService,
|
||||||
votesRepo,
|
votesRepo,
|
||||||
operator
|
operator,
|
||||||
|
cd
|
||||||
);
|
);
|
||||||
configService
|
configService
|
||||||
.get<boolean>('users_activate_vote_weight')
|
.get<boolean>('users_activate_vote_weight')
|
||||||
|
@ -12,9 +12,7 @@
|
|||||||
<div class="italic spacer-bottom-20">
|
<div class="italic spacer-bottom-20">
|
||||||
<span *osPerms="'assignments.can_manage'; and: poll.type === 'pseudoanonymous'">
|
<span *osPerms="'assignments.can_manage'; and: poll.type === 'pseudoanonymous'">
|
||||||
<button mat-icon-button color="warn" (click)="openVotingWarning()">
|
<button mat-icon-button color="warn" (click)="openVotingWarning()">
|
||||||
<mat-icon>
|
<mat-icon> warning </mat-icon>
|
||||||
warning
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
<span *ngIf="poll.type !== 'analog'"> {{ poll.typeVerbose | translate }} · </span>
|
<span *ngIf="poll.type !== 'analog'"> {{ poll.typeVerbose | translate }} · </span>
|
||||||
@ -64,19 +62,8 @@
|
|||||||
|
|
||||||
<!-- Chart / Table -->
|
<!-- Chart / Table -->
|
||||||
<div *ngIf="poll.stateHasVotes" class="poll-result-wrapper">
|
<div *ngIf="poll.stateHasVotes" class="poll-result-wrapper">
|
||||||
<div *osPerms="'assignments.can_manage'; or: poll.isPublished">
|
<os-assignment-poll-detail-content routerLink="/assignments/polls/{{ poll.id }}" [poll]="poll">
|
||||||
<os-assignment-poll-detail-content
|
</os-assignment-poll-detail-content>
|
||||||
routerLink="/assignments/polls/{{ poll.id }}"
|
|
||||||
[poll]="poll"
|
|
||||||
></os-assignment-poll-detail-content>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Cannot see unpublished -->
|
|
||||||
<div *osPerms="'assignments.can_manage'; complement: true">
|
|
||||||
<span *ngIf="poll.isFinished">
|
|
||||||
{{ 'Counting of votes is in progress ...' | translate }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Poll progress bar -->
|
<!-- Poll progress bar -->
|
||||||
@ -95,9 +82,7 @@
|
|||||||
matTooltip="{{ 'More' | translate }}"
|
matTooltip="{{ 'More' | translate }}"
|
||||||
*ngIf="poll.isPublished"
|
*ngIf="poll.isPublished"
|
||||||
>
|
>
|
||||||
<mat-icon class="small-icon">
|
<mat-icon class="small-icon"> visibility </mat-icon>
|
||||||
visibility
|
|
||||||
</mat-icon>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnInit, ViewChild } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
@ -90,7 +90,8 @@ export class CinemaComponent extends BaseViewComponentDirective implements OnIni
|
|||||||
private projectorService: ProjectorService,
|
private projectorService: ProjectorService,
|
||||||
private projectorRepo: ProjectorRepositoryService,
|
private projectorRepo: ProjectorRepositoryService,
|
||||||
private closService: CurrentListOfSpeakersService,
|
private closService: CurrentListOfSpeakersService,
|
||||||
private listOfSpeakersRepo: ListOfSpeakersRepositoryService
|
private listOfSpeakersRepo: ListOfSpeakersRepositoryService,
|
||||||
|
private cd: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(title, translate, snackBar);
|
super(title, translate, snackBar);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,32 @@
|
|||||||
<mat-card class="os-card" *ngFor="let poll of polls; trackBy: identifyPoll">
|
<ng-container
|
||||||
<p class="subtitle-text">
|
*ngFor="let poll of polls; trackBy: identifyPoll"
|
||||||
<a [routerLink]="getPollDetailLink(poll)" [state]="{ back: 'true' }">{{ getPollVoteTitle(poll) }}</a>
|
[ngTemplateOutlet]="pollArea"
|
||||||
</p>
|
[ngTemplateOutletContext]="{ poll: poll, last: false }"
|
||||||
|
></ng-container>
|
||||||
|
|
||||||
<div *ngIf="poll.pollClassType === 'motion'">
|
<ng-container
|
||||||
<os-motion-poll-vote [poll]="poll" *ngIf="poll.canBeVotedFor()"></os-motion-poll-vote>
|
*ngIf="lastPublishedPoll && !hasProjectedModelOpenPolls"
|
||||||
</div>
|
[ngTemplateOutlet]="pollArea"
|
||||||
|
[ngTemplateOutletContext]="{ poll: lastPublishedPoll, last: true }"
|
||||||
|
></ng-container>
|
||||||
|
|
||||||
<div *ngIf="poll.pollClassType === 'assignment'">
|
<ng-template #pollArea let-poll="poll" let-last="last">
|
||||||
<os-assignment-poll-vote [poll]="poll" *ngIf="poll.canBeVotedFor()"></os-assignment-poll-vote>
|
<mat-card class="os-card">
|
||||||
</div>
|
<p class="subtitle-text">
|
||||||
</mat-card>
|
<a [routerLink]="getPollDetailLink(poll)" [state]="{ back: 'true' }">{{ getPollVoteTitle(poll) }}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div *ngIf="poll.pollClassType === 'motion'">
|
||||||
|
<os-motion-poll-vote [poll]="poll" *ngIf="poll.canBeVotedFor() && !last"></os-motion-poll-vote>
|
||||||
|
<os-motion-poll-detail-content [poll]="lastPublishedPoll" *ngIf="last"></os-motion-poll-detail-content>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div *ngIf="poll.pollClassType === 'assignment'">
|
||||||
|
<os-assignment-poll-vote [poll]="poll" *ngIf="poll.canBeVotedFor() && !last"></os-assignment-poll-vote>
|
||||||
|
<os-assignment-poll-detail-content
|
||||||
|
[poll]="lastPublishedPoll"
|
||||||
|
*ngIf="last"
|
||||||
|
></os-assignment-poll-detail-content>
|
||||||
|
</div>
|
||||||
|
</mat-card>
|
||||||
|
</ng-template>
|
||||||
|
@ -1,25 +1,52 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { map } from 'rxjs/operators';
|
import { map } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { ViewAssignment } from 'app/site/assignments/models/view-assignment';
|
||||||
|
import { ViewAssignmentPoll } from 'app/site/assignments/models/view-assignment-poll';
|
||||||
import { BaseViewComponentDirective } from 'app/site/base/base-view';
|
import { BaseViewComponentDirective } from 'app/site/base/base-view';
|
||||||
import { BaseViewModel } from 'app/site/base/base-view-model';
|
import { BaseViewModel } from 'app/site/base/base-view-model';
|
||||||
|
import { ViewMotion } from 'app/site/motions/models/view-motion';
|
||||||
|
import { ViewMotionPoll } from 'app/site/motions/models/view-motion-poll';
|
||||||
import { ViewBasePoll } from 'app/site/polls/models/view-base-poll';
|
import { ViewBasePoll } from 'app/site/polls/models/view-base-poll';
|
||||||
import { PollListObservableService } from 'app/site/polls/services/poll-list-observable.service';
|
import { PollListObservableService } from 'app/site/polls/services/poll-list-observable.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'os-poll-collection',
|
selector: 'os-poll-collection',
|
||||||
templateUrl: './poll-collection.component.html',
|
templateUrl: './poll-collection.component.html',
|
||||||
styleUrls: ['./poll-collection.component.scss']
|
styleUrls: ['./poll-collection.component.scss'],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
})
|
})
|
||||||
export class PollCollectionComponent extends BaseViewComponentDirective implements OnInit {
|
export class PollCollectionComponent extends BaseViewComponentDirective implements OnInit {
|
||||||
public polls: ViewBasePoll[];
|
public polls: ViewBasePoll[];
|
||||||
|
|
||||||
|
public lastPublishedPoll: ViewBasePoll;
|
||||||
|
|
||||||
|
private _currentProjection: BaseViewModel<any>;
|
||||||
|
|
||||||
|
public get currentProjection(): BaseViewModel<any> {
|
||||||
|
return this._currentProjection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLEANUP: This function belongs to "HasViewPolls"/ ViewModelWithPolls
|
||||||
|
*/
|
||||||
|
public get hasProjectedModelOpenPolls(): boolean {
|
||||||
|
if (this.currentProjection instanceof ViewMotion || this.currentProjection instanceof ViewAssignment) {
|
||||||
|
const currPolls: ViewMotionPoll[] | ViewAssignmentPoll[] = this.currentProjection.polls;
|
||||||
|
return currPolls.some((p: ViewMotionPoll | ViewAssignmentPoll) => p.isStarted);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
private currentProjection: BaseViewModel<any>;
|
public set currentProjection(viewModel: BaseViewModel<any>) {
|
||||||
|
this._currentProjection = viewModel;
|
||||||
|
this.updateLastPublished();
|
||||||
|
}
|
||||||
|
|
||||||
private get showExtendedTitle(): boolean {
|
private get showExtendedTitle(): boolean {
|
||||||
const areAllPollsSameModel = this.polls.every(
|
const areAllPollsSameModel = this.polls.every(
|
||||||
@ -27,7 +54,7 @@ export class PollCollectionComponent extends BaseViewComponentDirective implemen
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (this.currentProjection && areAllPollsSameModel) {
|
if (this.currentProjection && areAllPollsSameModel) {
|
||||||
return this.polls[0].getContentObject() !== this.currentProjection;
|
return this.polls[0]?.getContentObject() !== this.currentProjection;
|
||||||
} else {
|
} else {
|
||||||
return !areAllPollsSameModel;
|
return !areAllPollsSameModel;
|
||||||
}
|
}
|
||||||
@ -37,7 +64,8 @@ export class PollCollectionComponent extends BaseViewComponentDirective implemen
|
|||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
snackBar: MatSnackBar,
|
snackBar: MatSnackBar,
|
||||||
private pollService: PollListObservableService
|
private pollService: PollListObservableService,
|
||||||
|
private cd: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(title, translate, snackBar);
|
super(title, translate, snackBar);
|
||||||
}
|
}
|
||||||
@ -46,9 +74,17 @@ export class PollCollectionComponent extends BaseViewComponentDirective implemen
|
|||||||
this.subscriptions.push(
|
this.subscriptions.push(
|
||||||
this.pollService
|
this.pollService
|
||||||
.getViewModelListObservable()
|
.getViewModelListObservable()
|
||||||
.pipe(map(polls => polls.filter(poll => poll.canBeVotedFor())))
|
.pipe(
|
||||||
|
map(polls => {
|
||||||
|
return polls.filter(poll => {
|
||||||
|
return poll.canBeVotedFor();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
)
|
||||||
.subscribe(polls => {
|
.subscribe(polls => {
|
||||||
this.polls = polls;
|
this.polls = polls;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
this.updateLastPublished();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -57,6 +93,10 @@ export class PollCollectionComponent extends BaseViewComponentDirective implemen
|
|||||||
return poll.id;
|
return poll.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getPollDetailLink(poll: ViewBasePoll): string {
|
||||||
|
return poll.parentLink;
|
||||||
|
}
|
||||||
|
|
||||||
public getPollVoteTitle(poll: ViewBasePoll): string {
|
public getPollVoteTitle(poll: ViewBasePoll): string {
|
||||||
const contentObject = poll.getContentObject();
|
const contentObject = poll.getContentObject();
|
||||||
const listTitle = contentObject.getListTitle();
|
const listTitle = contentObject.getListTitle();
|
||||||
@ -70,7 +110,35 @@ export class PollCollectionComponent extends BaseViewComponentDirective implemen
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getPollDetailLink(poll: ViewBasePoll): string {
|
/**
|
||||||
return poll.parentLink;
|
* Helper function to detect new latest published polls and set them.
|
||||||
|
*/
|
||||||
|
private updateLastPublished(): void {
|
||||||
|
const lastPublished = this.getLastfinshedPoll(this.currentProjection);
|
||||||
|
if (lastPublished !== this.lastPublishedPoll) {
|
||||||
|
this.lastPublishedPoll = lastPublished;
|
||||||
|
this.cd.markForCheck();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CLEANUP: This function belongs to "HasViewPolls"/ ViewModelWithPolls
|
||||||
|
* *class* (is an interface right now)
|
||||||
|
*
|
||||||
|
* @param viewModel
|
||||||
|
*/
|
||||||
|
private getLastfinshedPoll(viewModel: BaseViewModel): ViewBasePoll {
|
||||||
|
if (viewModel instanceof ViewMotion || viewModel instanceof ViewAssignment) {
|
||||||
|
let currPolls: ViewMotionPoll[] | ViewAssignmentPoll[] = viewModel.polls;
|
||||||
|
/**
|
||||||
|
* Although it should, since the union type could use `.filter
|
||||||
|
* without any problem, without an any cast it will not work
|
||||||
|
*/
|
||||||
|
currPolls = (currPolls as any[])
|
||||||
|
.filter((p: ViewMotionPoll | ViewAssignmentPoll) => p.stateHasVotes)
|
||||||
|
.reverse();
|
||||||
|
return currPolls[0];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import { ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
|||||||
import { Searchable } from 'app/site/base/searchable';
|
import { Searchable } from 'app/site/base/searchable';
|
||||||
import { SlideOptions } from 'app/site/base/slide-options';
|
import { SlideOptions } from 'app/site/base/slide-options';
|
||||||
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
import { ViewMediafile } from 'app/site/mediafiles/models/view-mediafile';
|
||||||
|
import { HasViewPolls } from 'app/site/polls/models/has-view-polls';
|
||||||
import { ViewTag } from 'app/site/tags/models/view-tag';
|
import { ViewTag } from 'app/site/tags/models/view-tag';
|
||||||
import { ViewUser } from 'app/site/users/models/view-user';
|
import { ViewUser } from 'app/site/users/models/view-user';
|
||||||
import { AmendmentType } from '../motions.constants';
|
import { AmendmentType } from '../motions.constants';
|
||||||
@ -355,7 +356,7 @@ export class ViewMotion
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TIMotionRelations {
|
interface TIMotionRelations extends HasViewPolls<ViewMotionPoll> {
|
||||||
category?: ViewCategory;
|
category?: ViewCategory;
|
||||||
submitters: ViewSubmitter[];
|
submitters: ViewSubmitter[];
|
||||||
supporters?: ViewUser[];
|
supporters?: ViewUser[];
|
||||||
@ -369,7 +370,6 @@ interface TIMotionRelations {
|
|||||||
amendments?: ViewMotion[];
|
amendments?: ViewMotion[];
|
||||||
changeRecommendations?: ViewMotionChangeRecommendation[];
|
changeRecommendations?: ViewMotionChangeRecommendation[];
|
||||||
diffLines?: DiffLinesInParagraph[];
|
diffLines?: DiffLinesInParagraph[];
|
||||||
polls: ViewMotionPoll[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ViewMotion extends MotionWithoutNestedModels, TIMotionRelations {}
|
export interface ViewMotion extends MotionWithoutNestedModels, TIMotionRelations {}
|
||||||
|
@ -29,68 +29,63 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p *ngIf="!poll.hasVotes || !poll.stateHasVotes">{{ 'No results yet.' | translate }}</p>
|
<os-motion-poll-detail-content [poll]="poll"></os-motion-poll-detail-content>
|
||||||
|
|
||||||
<div *ngIf="poll.stateHasVotes && (hasPerms() || poll.isPublished)">
|
<!-- Named table: only show if votes are present -->
|
||||||
<os-motion-poll-detail-content [poll]="poll" [chartData]="chartDataSubject">
|
<div class="named-result-table" *ngIf="showResults && poll.stateHasVotes && poll.type === 'named'">
|
||||||
</os-motion-poll-detail-content>
|
<h2>{{ 'Single votes' | translate }}</h2>
|
||||||
|
<os-list-view-table
|
||||||
|
*ngIf="votesDataObservable"
|
||||||
|
class="single-votes-table"
|
||||||
|
[listObservable]="votesDataObservable"
|
||||||
|
[columns]="columnDefinition"
|
||||||
|
[filterProps]="filterProps"
|
||||||
|
[allowProjector]="false"
|
||||||
|
[fullScreen]="true"
|
||||||
|
[vScrollFixed]="-1"
|
||||||
|
listStorageKey="motion-poll-vote"
|
||||||
|
>
|
||||||
|
<!-- Header -->
|
||||||
|
<div *pblNgridHeaderCellDef="'*'; col as col">
|
||||||
|
{{ col.label | translate }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Named table: only show if votes are present -->
|
<!-- Content -->
|
||||||
<div class="named-result-table" *ngIf="poll.type === 'named'">
|
<div *pblNgridCellDef="'user'; row as vote">
|
||||||
<h2>{{ 'Single votes' | translate }}</h2>
|
<div *ngIf="vote.user">
|
||||||
<os-list-view-table
|
{{ vote.user.getShortName() }}
|
||||||
*ngIf="votesDataObservable"
|
|
||||||
class="single-votes-table"
|
|
||||||
[listObservable]="votesDataObservable"
|
|
||||||
[columns]="columnDefinition"
|
|
||||||
[filterProps]="filterProps"
|
|
||||||
[allowProjector]="false"
|
|
||||||
[fullScreen]="true"
|
|
||||||
[vScrollFixed]="-1"
|
|
||||||
listStorageKey="motion-poll-vote"
|
|
||||||
>
|
|
||||||
<!-- Header -->
|
|
||||||
<div *pblNgridHeaderCellDef="'*'; col as col">
|
|
||||||
{{ col.label | translate }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Content -->
|
<div class="user-subtitle">
|
||||||
<div *pblNgridCellDef="'user'; row as vote">
|
<!-- Level and number -->
|
||||||
<div *ngIf="vote.user">
|
<div *ngIf="vote.user.getLevelAndNumber()">
|
||||||
{{ vote.user.getShortName() }}
|
{{ vote.user.getLevelAndNumber() }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="user-subtitle">
|
<!-- Vote weight -->
|
||||||
<!-- Level and number -->
|
<div *ngIf="isVoteWeightActive">
|
||||||
<div *ngIf="vote.user.getLevelAndNumber()">
|
{{ 'Vote weight' | translate }}: {{ vote.user.vote_weight }}
|
||||||
{{ vote.user.getLevelAndNumber() }}
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Vote weight -->
|
<!-- Delegation -->
|
||||||
<div *ngIf="isVoteWeightActive">
|
<div *ngIf="userHasVoteDelegation(vote.user)">
|
||||||
{{ 'Vote weight' | translate }}: {{ vote.user.vote_weight }}
|
<span>
|
||||||
</div>
|
({{ 'represented by' | translate }}
|
||||||
|
{{ getUsersVoteDelegation(vote.user).getShortName().trim() }})
|
||||||
<!-- Delegation -->
|
</span>
|
||||||
<div *ngIf="userHasVoteDelegation(vote.user)">
|
|
||||||
<span>
|
|
||||||
({{ 'represented by' | translate }}
|
|
||||||
{{ getUsersVoteDelegation(vote.user).getShortName().trim() }})
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="!vote.user">{{ 'Anonymous' | translate }}</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div *pblNgridCellDef="'vote'; row as vote" class="vote-cell">
|
<div *ngIf="!vote.user">{{ 'Anonymous' | translate }}</div>
|
||||||
<div class="vote-cell-icon-container" [ngClass]="voteOptionStyle[vote.value].css">
|
|
||||||
<mat-icon>{{ voteOptionStyle[vote.value].icon }}</mat-icon>
|
|
||||||
</div>
|
|
||||||
<div>{{ vote.valueVerbose | translate }}</div>
|
|
||||||
</div>
|
|
||||||
</os-list-view-table>
|
|
||||||
<div *ngIf="!votesDataObservable">
|
|
||||||
{{ 'The individual votes were anonymized.' | translate }}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div *pblNgridCellDef="'vote'; row as vote" class="vote-cell">
|
||||||
|
<div class="vote-cell-icon-container" [ngClass]="voteOptionStyle[vote.value].css">
|
||||||
|
<mat-icon>{{ voteOptionStyle[vote.value].icon }}</mat-icon>
|
||||||
|
</div>
|
||||||
|
<div>{{ vote.valueVerbose | translate }}</div>
|
||||||
|
</div>
|
||||||
|
</os-list-view-table>
|
||||||
|
<div *ngIf="!votesDataObservable">
|
||||||
|
{{ 'The individual votes were anonymized.' | translate }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { ChangeDetectionStrategy, Component, ViewEncapsulation } from '@angular/core';
|
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewEncapsulation } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
@ -44,6 +44,10 @@ export class MotionPollDetailComponent extends BasePollDetailComponentDirective<
|
|||||||
|
|
||||||
public isVoteWeightActive: boolean;
|
public isVoteWeightActive: boolean;
|
||||||
|
|
||||||
|
public get showResults(): boolean {
|
||||||
|
return this.hasPerms() || this.poll.isPublished;
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
title: Title,
|
title: Title,
|
||||||
translate: TranslateService,
|
translate: TranslateService,
|
||||||
@ -57,7 +61,8 @@ export class MotionPollDetailComponent extends BasePollDetailComponentDirective<
|
|||||||
votesRepo: MotionVoteRepositoryService,
|
votesRepo: MotionVoteRepositoryService,
|
||||||
configService: ConfigService,
|
configService: ConfigService,
|
||||||
protected operator: OperatorService,
|
protected operator: OperatorService,
|
||||||
private router: Router
|
private router: Router,
|
||||||
|
protected cd: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
title,
|
title,
|
||||||
@ -70,7 +75,8 @@ export class MotionPollDetailComponent extends BasePollDetailComponentDirective<
|
|||||||
pollDialog,
|
pollDialog,
|
||||||
pollService,
|
pollService,
|
||||||
votesRepo,
|
votesRepo,
|
||||||
operator
|
operator,
|
||||||
|
cd
|
||||||
);
|
);
|
||||||
configService
|
configService
|
||||||
.get<boolean>('users_activate_vote_weight')
|
.get<boolean>('users_activate_vote_weight')
|
||||||
|
@ -23,9 +23,7 @@
|
|||||||
<div class="italic spacer-bottom-20">
|
<div class="italic spacer-bottom-20">
|
||||||
<span *osPerms="'motions.can_manage_polls'; and: poll.type === 'pseudoanonymous'">
|
<span *osPerms="'motions.can_manage_polls'; and: poll.type === 'pseudoanonymous'">
|
||||||
<button mat-icon-button color="warn" (click)="openVotingWarning()">
|
<button mat-icon-button color="warn" (click)="openVotingWarning()">
|
||||||
<mat-icon>
|
<mat-icon>warning</mat-icon>
|
||||||
warning
|
|
||||||
</mat-icon>
|
|
||||||
</button>
|
</button>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
@ -42,7 +40,12 @@
|
|||||||
|
|
||||||
<!-- Change state button -->
|
<!-- Change state button -->
|
||||||
<div *osPerms="'motions.can_manage_polls'; and: !hideChangeState">
|
<div *osPerms="'motions.can_manage_polls'; and: !hideChangeState">
|
||||||
<button mat-stroked-button [ngClass]="pollStateActions[poll.state].css" (click)="changeState(poll.nextState)" [disabled]="stateChangePending">
|
<button
|
||||||
|
mat-stroked-button
|
||||||
|
[ngClass]="pollStateActions[poll.state].css"
|
||||||
|
(click)="changeState(poll.nextState)"
|
||||||
|
[disabled]="stateChangePending"
|
||||||
|
>
|
||||||
<mat-icon> {{ pollStateActions[poll.state].icon }}</mat-icon>
|
<mat-icon> {{ pollStateActions[poll.state].icon }}</mat-icon>
|
||||||
<span class="next-state-label">
|
<span class="next-state-label">
|
||||||
<ng-container *ngIf="!stateChangePending">
|
<ng-container *ngIf="!stateChangePending">
|
||||||
@ -66,9 +69,7 @@
|
|||||||
<!-- Detail link -->
|
<!-- Detail link -->
|
||||||
<div class="poll-detail-button-wrapper">
|
<div class="poll-detail-button-wrapper">
|
||||||
<a mat-icon-button [routerLink]="pollLink" matTooltip="{{ 'More' | translate }}" *ngIf="poll.isPublished">
|
<a mat-icon-button [routerLink]="pollLink" matTooltip="{{ 'More' | translate }}" *ngIf="poll.isPublished">
|
||||||
<mat-icon class="small-icon">
|
<mat-icon class="small-icon">visibility</mat-icon>
|
||||||
visibility
|
|
||||||
</mat-icon>
|
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
@ -82,34 +83,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #viewTemplate>
|
<ng-template #viewTemplate>
|
||||||
<!-- Result Chart and legend -->
|
<os-motion-poll-detail-content [poll]="poll" [routerLink]="pollLink"></os-motion-poll-detail-content>
|
||||||
<div class="poll-chart-wrapper" *osPerms="'motions.can_manage_polls'; or: poll.isPublished">
|
|
||||||
<div class="vote-legend" [routerLink]="pollLink">
|
|
||||||
|
|
||||||
<!-- any (click)-binding in an *ngFor-loop of dynamic length will break the view on iOS.
|
|
||||||
Therefore, we have to provide the trackBy-function here.
|
|
||||||
I suppose there would be debug output, but i-devices are not giving any.
|
|
||||||
The error-handling-service (PR #5131) might be helpful here. Nothing easy to find. -->
|
|
||||||
<div *ngFor="let row of reducedPollTableData; trackBy: trackByIndex" [class]="row.votingOption">
|
|
||||||
<os-icon-container [icon]="row.value[0].icon" size="large">
|
|
||||||
{{ row.value[0].amount | parsePollNumber }}
|
|
||||||
<span *ngIf="row.value[0].showPercent">
|
|
||||||
{{ row.value[0].amount | pollPercentBase: poll:'motion' }}
|
|
||||||
</span>
|
|
||||||
</os-icon-container>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="doughnut-chart" [routerLink]="pollLink">
|
|
||||||
<os-charts *ngIf="showChart" type="doughnut" [data]="chartDataSubject | async"></os-charts>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- In Progress hint -->
|
|
||||||
<div class="motion-couting-in-progress-hint" *osPerms="'motions.can_manage_polls'; complement: true">
|
|
||||||
<span *ngIf="poll.isFinished">
|
|
||||||
{{ 'Counting of votes is in progress ...' | translate }}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
<ng-template #emptyTemplate>
|
<ng-template #emptyTemplate>
|
||||||
|
@ -15,7 +15,6 @@ import { MotionPollDialogService } from 'app/site/motions/services/motion-poll-d
|
|||||||
import { MotionPollPdfService } from 'app/site/motions/services/motion-poll-pdf.service';
|
import { MotionPollPdfService } from 'app/site/motions/services/motion-poll-pdf.service';
|
||||||
import { MotionPollService } from 'app/site/motions/services/motion-poll.service';
|
import { MotionPollService } from 'app/site/motions/services/motion-poll.service';
|
||||||
import { BasePollComponent } from 'app/site/polls/components/base-poll.component';
|
import { BasePollComponent } from 'app/site/polls/components/base-poll.component';
|
||||||
import { PollTableData } from 'app/site/polls/services/poll.service';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component to show a motion-poll.
|
* Component to show a motion-poll.
|
||||||
@ -29,8 +28,6 @@ export class MotionPollComponent extends BasePollComponent<ViewMotionPoll, Motio
|
|||||||
@Input()
|
@Input()
|
||||||
public set poll(value: ViewMotionPoll) {
|
public set poll(value: ViewMotionPoll) {
|
||||||
this.initPoll(value);
|
this.initPoll(value);
|
||||||
const chartData = this.pollService.generateChartData(value);
|
|
||||||
this.chartDataSubject.next(chartData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public get poll(): ViewMotionPoll {
|
public get poll(): ViewMotionPoll {
|
||||||
@ -41,16 +38,6 @@ export class MotionPollComponent extends BasePollComponent<ViewMotionPoll, Motio
|
|||||||
return `/motions/polls/${this.poll.id}`;
|
return `/motions/polls/${this.poll.id}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get showChart(): boolean {
|
|
||||||
return this.pollService.showChart(this.poll);
|
|
||||||
}
|
|
||||||
|
|
||||||
public get reducedPollTableData(): PollTableData[] {
|
|
||||||
return this.pollService
|
|
||||||
.generateTableData(this.poll)
|
|
||||||
.filter(data => ['yes', 'no', 'abstain', 'votesinvalid'].includes(data.votingOption));
|
|
||||||
}
|
|
||||||
|
|
||||||
public get showPoll(): boolean {
|
public get showPoll(): boolean {
|
||||||
if (this.poll) {
|
if (this.poll) {
|
||||||
if (
|
if (
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Directive, OnInit } from '@angular/core';
|
import { ChangeDetectorRef, Directive, OnInit } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
@ -70,11 +70,6 @@ export abstract class BasePollDetailComponentDirective<V extends ViewBasePoll, S
|
|||||||
*/
|
*/
|
||||||
public labels: Label[] = [];
|
public labels: Label[] = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* Subject, that holds the data for the chart.
|
|
||||||
*/
|
|
||||||
public chartDataSubject: BehaviorSubject<ChartData> = new BehaviorSubject(null);
|
|
||||||
|
|
||||||
// The observable for the votes-per-user table
|
// The observable for the votes-per-user table
|
||||||
public votesDataObservable: Observable<BaseVoteData[]>;
|
public votesDataObservable: Observable<BaseVoteData[]>;
|
||||||
|
|
||||||
@ -106,7 +101,8 @@ export abstract class BasePollDetailComponentDirective<V extends ViewBasePoll, S
|
|||||||
protected pollDialog: BasePollDialogService<V, S>,
|
protected pollDialog: BasePollDialogService<V, S>,
|
||||||
protected pollService: S,
|
protected pollService: S,
|
||||||
protected votesRepo: BaseRepository<ViewBaseVote, BaseVote, object>,
|
protected votesRepo: BaseRepository<ViewBaseVote, BaseVote, object>,
|
||||||
protected operator: OperatorService
|
protected operator: OperatorService,
|
||||||
|
protected cd: ChangeDetectorRef
|
||||||
) {
|
) {
|
||||||
super(title, translate, matSnackbar);
|
super(title, translate, matSnackbar);
|
||||||
this.setup();
|
this.setup();
|
||||||
@ -187,14 +183,6 @@ export abstract class BasePollDetailComponentDirective<V extends ViewBasePoll, S
|
|||||||
*/
|
*/
|
||||||
protected abstract createVotesData(): void;
|
protected abstract createVotesData(): void;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes data for the shown chart.
|
|
||||||
* Could be overwritten to implement custom chart data.
|
|
||||||
*/
|
|
||||||
protected initChartData(): void {
|
|
||||||
this.chartDataSubject.next(this.pollService.generateChartData(this.poll));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper-function to search for this poll and display data or create a new one.
|
* Helper-function to search for this poll and display data or create a new one.
|
||||||
*/
|
*/
|
||||||
@ -206,8 +194,8 @@ export abstract class BasePollDetailComponentDirective<V extends ViewBasePoll, S
|
|||||||
if (poll) {
|
if (poll) {
|
||||||
this.poll = poll;
|
this.poll = poll;
|
||||||
this.createVotesData();
|
this.createVotesData();
|
||||||
this.initChartData();
|
|
||||||
this.optionsLoaded.resolve();
|
this.optionsLoaded.resolve();
|
||||||
|
this.cd.markForCheck();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { ViewBasePoll } from './view-base-poll';
|
import { ViewBasePoll } from './view-base-poll';
|
||||||
|
|
||||||
export interface HasViewPolls<T extends ViewBasePoll> {
|
export interface HasViewPolls<T extends ViewBasePoll> {
|
||||||
polls: T[];
|
polls?: T[];
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
MajorityMethod,
|
MajorityMethod,
|
||||||
PercentBase,
|
PercentBase,
|
||||||
PollColor,
|
PollColor,
|
||||||
|
PollState,
|
||||||
PollType,
|
PollType,
|
||||||
VOTE_UNDOCUMENTED
|
VOTE_UNDOCUMENTED
|
||||||
} from 'app/shared/models/poll/base-poll';
|
} from 'app/shared/models/poll/base-poll';
|
||||||
@ -104,6 +105,7 @@ export const PollMajorityMethod: CalculableMajorityMethod[] = [
|
|||||||
export interface PollData {
|
export interface PollData {
|
||||||
pollmethod: string;
|
pollmethod: string;
|
||||||
type: string;
|
type: string;
|
||||||
|
state: PollState;
|
||||||
onehundred_percent_base: string;
|
onehundred_percent_base: string;
|
||||||
options: PollDataOption[];
|
options: PollDataOption[];
|
||||||
votesvalid: number;
|
votesvalid: number;
|
||||||
|
@ -7,6 +7,6 @@
|
|||||||
<h2 class="poll-title">{{ data.data.poll.title }}</h2>
|
<h2 class="poll-title">{{ data.data.poll.title }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="data.data.poll.state === PollState.Published">
|
<div *ngIf="data.data.poll.state === PollState.Published">
|
||||||
<os-motion-poll-detail-content [poll]="pollData" [chartData]="chartDataSubject" iconSize="gigantic"></os-motion-poll-detail-content>
|
<os-motion-poll-detail-content [poll]="pollData" iconSize="gigantic"></os-motion-poll-detail-content>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
Loading…
Reference in New Issue
Block a user