Basic assignment and poll slide
This commit is contained in:
parent
d0c6fd1dd1
commit
55dd2d1d6f
@ -15,6 +15,8 @@ import { ProjectionDialogService } from 'app/core/ui-services/projection-dialog.
|
||||
*
|
||||
* Use the input [object] to specify the object to project. It can either be
|
||||
* a Projectable or a ProjectorElementBuildDeskriptor
|
||||
*
|
||||
* For useage in menues set `menuItem=true`.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'os-projector-button',
|
||||
|
@ -28,18 +28,28 @@
|
||||
>
|
||||
</os-sort-filter-bar>
|
||||
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
||||
<!-- slector column -->
|
||||
<!-- selector column -->
|
||||
<ng-container matColumnDef="selector">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="icon-cell"></mat-header-cell>
|
||||
<mat-cell *matCellDef="let assignment" class="icon-cell">
|
||||
<mat-icon>{{ isSelected(assignment) ? 'check_circle' : '' }}</mat-icon>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- projector column -->
|
||||
<ng-container matColumnDef="projector">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
|
||||
<mat-cell *matCellDef="let assignment">
|
||||
<os-projector-button [object]="assignment"></os-projector-button>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- name column -->
|
||||
<ng-container matColumnDef="title">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Title</mat-header-cell>
|
||||
<mat-cell *matCellDef="let assignment">{{ assignment.getListTitle() }}</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<!-- phase column-->
|
||||
<ng-container matColumnDef="phase">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Phase</mat-header-cell>
|
||||
@ -57,6 +67,7 @@
|
||||
<span translate>Deselect all</span>
|
||||
</button>
|
||||
</ng-container>
|
||||
|
||||
<!-- candidates column -->
|
||||
<ng-container matColumnDef="candidates">
|
||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Candidates</mat-header-cell>
|
||||
|
@ -116,9 +116,12 @@ export class AssignmentListComponent extends ListViewBaseComponent<ViewAssignmen
|
||||
* @returns a list of string matching the columns
|
||||
*/
|
||||
public getColumnDefintion(): string[] {
|
||||
const list = ['title', 'phase', 'candidates'];
|
||||
let list = ['title', 'phase', 'candidates'];
|
||||
if (this.operator.hasPerms('core.can_manage_projector')) {
|
||||
list = ['projector'].concat(list);
|
||||
}
|
||||
if (this.isMultiSelect) {
|
||||
return ['selector'].concat(list);
|
||||
list = ['selector'].concat(list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
@ -28,11 +28,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div *osPerms="'core.can_manage_projector'">
|
||||
<button mat-menu-item>
|
||||
<mat-icon>videocam</mat-icon>
|
||||
<span translate>Project</span>
|
||||
<!-- os-projector-button ?-->
|
||||
</button>
|
||||
<os-projector-button menuItem=true [object]="poll"></os-projector-button>
|
||||
</div>
|
||||
<div *osPerms="'assignments.can_manage'">
|
||||
<mat-divider></mat-divider>
|
||||
|
@ -5,8 +5,9 @@ import { AssignmentPoll } from 'app/shared/models/assignments/assignment-poll';
|
||||
import { AssignmentPollMethod } from '../services/assignment-poll.service';
|
||||
import { ViewAssignmentPollOption } from './view-assignment-poll-option';
|
||||
import { AssignmentPollOption } from 'app/shared/models/assignments/assignment-poll-option';
|
||||
import { Projectable, ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||
|
||||
export class ViewAssignmentPoll implements Identifiable, Updateable {
|
||||
export class ViewAssignmentPoll implements Identifiable, Updateable, Projectable {
|
||||
private _assignmentPoll: AssignmentPoll;
|
||||
private _assignmentPollOptions: ViewAssignmentPollOption[];
|
||||
|
||||
@ -81,6 +82,14 @@ export class ViewAssignmentPoll implements Identifiable, Updateable {
|
||||
this.options.forEach(option => option.updateDependencies(update));
|
||||
}
|
||||
|
||||
public getTitle(): string {
|
||||
return 'TODO';
|
||||
}
|
||||
|
||||
public getListTitle(): string {
|
||||
return this.getTitle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy with deep-copy on all changing numerical values,
|
||||
* but intact uncopied references to the users
|
||||
@ -98,4 +107,18 @@ export class ViewAssignmentPoll implements Identifiable, Updateable {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
public getSlide(): ProjectorElementBuildDeskriptor {
|
||||
return {
|
||||
getBasicProjectorElement: options => ({
|
||||
name: 'assignments/poll',
|
||||
assignment_id: this.assignment_id,
|
||||
poll_id: this.id,
|
||||
getIdentifiers: () => ['name', 'assignment_id', 'poll_id']
|
||||
}),
|
||||
slideOptions: [],
|
||||
projectionDefaultName: 'assignments',
|
||||
getDialogTitle: () => 'TODO'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ import { ViewAssignmentPoll } from '../models/view-assignment-poll';
|
||||
|
||||
type AssignmentPollValues = 'auto' | 'votes' | 'yesnoabstain' | 'yesno';
|
||||
export type AssignmentPollMethod = 'yn' | 'yna' | 'votes';
|
||||
type AssignmentPercentBase = 'YES_NO_ABSTAIN' | 'YES_NO' | 'VALID' | 'CAST' | 'DISABLED';
|
||||
export type AssignmentPercentBase = 'YES_NO_ABSTAIN' | 'YES_NO' | 'VALID' | 'CAST' | 'DISABLED';
|
||||
|
||||
/**
|
||||
* Service class for assignment polls.
|
||||
|
@ -82,6 +82,11 @@ export const allSlidesDynamicConfiguration: (SlideDynamicConfiguration & Slide)[
|
||||
scaleable: true,
|
||||
scrollable: true
|
||||
},
|
||||
{
|
||||
slide: 'assignments/poll',
|
||||
scaleable: true,
|
||||
scrollable: true
|
||||
},
|
||||
{
|
||||
slide: 'mediafiles/mediafile',
|
||||
scaleable: true,
|
||||
|
@ -115,6 +115,14 @@ export const allSlides: SlideManifest[] = [
|
||||
elementIdentifiers: ['name', 'id'],
|
||||
canBeMappedToModel: true
|
||||
},
|
||||
{
|
||||
slide: 'assignments/poll',
|
||||
path: 'assignments/poll',
|
||||
loadChildren: './slides/assignments/poll/poll-slide.module#PollSlideModule',
|
||||
verboseName: 'Poll',
|
||||
elementIdentifiers: ['name', 'assignment_id', 'poll_id'],
|
||||
canBeMappedToModel: false
|
||||
},
|
||||
{
|
||||
slide: 'mediafiles/mediafile',
|
||||
path: 'mediafiles/mediafile',
|
||||
|
@ -1,3 +1,10 @@
|
||||
export interface AssignmentSlideData {
|
||||
user: string;
|
||||
title: string;
|
||||
description: string;
|
||||
phase: number;
|
||||
open_posts: number;
|
||||
assignment_related_users: {
|
||||
user: string;
|
||||
elected: boolean;
|
||||
}[];
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { AssignmentSlideData } from './assignment-slide-data';
|
||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-assignment-slide',
|
||||
@ -9,6 +10,20 @@ import { AssignmentSlideData } from './assignment-slide-data';
|
||||
styleUrls: ['./assignment-slide.component.scss']
|
||||
})
|
||||
export class AssignmentSlideComponent extends BaseSlideComponent<AssignmentSlideData> {
|
||||
// TODO: Remove the following block, if not needed.
|
||||
// This is just for debugging to get a console statement with all recieved
|
||||
// data from the server
|
||||
private _data: SlideData<AssignmentSlideData>;
|
||||
@Input()
|
||||
public set data(data: SlideData<AssignmentSlideData>) {
|
||||
this._data = data;
|
||||
console.log('Data: ', data);
|
||||
}
|
||||
public get data(): SlideData<AssignmentSlideData> {
|
||||
return this._data;
|
||||
}
|
||||
// UNTIL HERE
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
import { AssignmentSlideModule } from './assignment-slide.module';
|
||||
|
||||
describe('UsersUserSlideModule', () => {
|
||||
let usersUserSlideModule: AssignmentSlideModule;
|
||||
describe('AssignmentSlideModule', () => {
|
||||
let assignmentSlideModule: AssignmentSlideModule;
|
||||
|
||||
beforeEach(() => {
|
||||
usersUserSlideModule = new AssignmentSlideModule();
|
||||
assignmentSlideModule = new AssignmentSlideModule();
|
||||
});
|
||||
|
||||
it('should create an instance', () => {
|
||||
expect(usersUserSlideModule).toBeTruthy();
|
||||
expect(assignmentSlideModule).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
17
client/src/app/slides/assignments/poll/poll-slide-data.ts
Normal file
17
client/src/app/slides/assignments/poll/poll-slide-data.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { AssignmentPercentBase, AssignmentPollMethod } from 'app/site/assignments/services/assignment-poll.service';
|
||||
|
||||
export interface PollSlideData {
|
||||
title: string;
|
||||
assignments_poll_100_percent_base: AssignmentPercentBase;
|
||||
poll: {
|
||||
published: boolean;
|
||||
description?: string;
|
||||
has_votes?: boolean;
|
||||
pollmethod?: AssignmentPollMethod;
|
||||
votesno?: string; // TODO: same conversion needed as for the PollModel
|
||||
votesabstain?: string;
|
||||
votesvalid?: string;
|
||||
votesinvalid?: string;
|
||||
votescast?: string;
|
||||
};
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
<div *ngIf="data">
|
||||
<h1>TODO</h1>
|
||||
</div>
|
@ -0,0 +1,26 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { PollSlideComponent } from './poll-slide.component';
|
||||
import { E2EImportsModule } from '../../../../e2e-imports.module';
|
||||
|
||||
describe('PollSlideComponent', () => {
|
||||
let component: PollSlideComponent;
|
||||
let fixture: ComponentFixture<PollSlideComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [PollSlideComponent]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PollSlideComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { PollSlideData } from './poll-slide-data';
|
||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
||||
|
||||
@Component({
|
||||
selector: 'os-poll-slide',
|
||||
templateUrl: './poll-slide.component.html',
|
||||
styleUrls: ['./poll-slide.component.scss']
|
||||
})
|
||||
export class PollSlideComponent extends BaseSlideComponent<PollSlideData> {
|
||||
// TODO: Remove the following block, if not needed.
|
||||
// This is just for debugging to get a console statement with all recieved
|
||||
// data from the server
|
||||
private _data: SlideData<PollSlideData>;
|
||||
@Input()
|
||||
public set data(data: SlideData<PollSlideData>) {
|
||||
this._data = data;
|
||||
console.log('Data: ', data);
|
||||
}
|
||||
public get data(): SlideData<PollSlideData> {
|
||||
return this._data;
|
||||
}
|
||||
// UNTIL HERE
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
import { PollSlideModule } from './poll-slide.module';
|
||||
|
||||
describe('PollSlideModule', () => {
|
||||
let pollSlideModule: PollSlideModule;
|
||||
|
||||
beforeEach(() => {
|
||||
pollSlideModule = new PollSlideModule();
|
||||
});
|
||||
|
||||
it('should create an instance', () => {
|
||||
expect(pollSlideModule).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { makeSlideModule } from 'app/slides/base-slide-module';
|
||||
import { PollSlideComponent } from './poll-slide.component';
|
||||
|
||||
@NgModule(makeSlideModule(PollSlideComponent))
|
||||
export class PollSlideModule {}
|
@ -1,6 +1,12 @@
|
||||
from typing import Any, Dict
|
||||
from typing import Any, Dict, List
|
||||
|
||||
from ..utils.projector import AllData, register_projector_slide
|
||||
from ..users.projector import get_user_name
|
||||
from ..utils.projector import (
|
||||
AllData,
|
||||
ProjectorElementException,
|
||||
get_config,
|
||||
register_projector_slide,
|
||||
)
|
||||
|
||||
|
||||
# Important: All functions have to be prune. This means, that thay can only
|
||||
@ -8,15 +14,95 @@ from ..utils.projector import AllData, register_projector_slide
|
||||
# side effects.
|
||||
|
||||
|
||||
def get_assignment(all_data: AllData, id: Any) -> Dict[str, Any]:
|
||||
if id is None:
|
||||
raise ProjectorElementException("id is required for assignment slide")
|
||||
|
||||
try:
|
||||
assignment = all_data["assignments/assignment"][id]
|
||||
except KeyError:
|
||||
raise ProjectorElementException(f"assignment with id {id} does not exist")
|
||||
return assignment
|
||||
|
||||
|
||||
async def assignment_slide(
|
||||
all_data: AllData, element: Dict[str, Any], projector_id: int
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Assignment slide.
|
||||
"""
|
||||
poll_id = element.get("tree") # noqa
|
||||
return {"error": "TODO"}
|
||||
assignment = get_assignment(all_data, element.get("id"))
|
||||
|
||||
assignment_related_users: List[Dict[str, Any]] = [
|
||||
{
|
||||
"user": await get_user_name(all_data, aru["user_id"]),
|
||||
"elected": aru["elected"],
|
||||
}
|
||||
for aru in sorted(
|
||||
assignment["assignment_related_users"], key=lambda aru: aru["weight"]
|
||||
)
|
||||
]
|
||||
|
||||
return {
|
||||
"title": assignment["title"],
|
||||
"phase": assignment["phase"],
|
||||
"open_posts": assignment["open_posts"],
|
||||
"description": assignment["description"],
|
||||
"assignment_related_users": assignment_related_users,
|
||||
}
|
||||
|
||||
|
||||
async def poll_slide(
|
||||
all_data: AllData, element: Dict[str, Any], projector_id: int
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Poll slide.
|
||||
"""
|
||||
assignment = get_assignment(all_data, element.get("assignment_id"))
|
||||
|
||||
# get poll
|
||||
poll_id = element.get("poll_id")
|
||||
if poll_id is None:
|
||||
raise ProjectorElementException("id is required for poll slide")
|
||||
|
||||
poll = None
|
||||
for p in assignment["polls"]:
|
||||
if p["id"] == poll_id:
|
||||
poll = p
|
||||
break
|
||||
if poll is None:
|
||||
raise ProjectorElementException(f"poll with id {poll_id} does not exist")
|
||||
|
||||
poll_data = {"published": poll["published"]}
|
||||
|
||||
if poll["published"]:
|
||||
poll_data["description"] = poll["description"]
|
||||
poll_data["has_votes"] = poll["has_votes"]
|
||||
poll_data["pollmethod"] = poll["pollmethod"]
|
||||
poll_data["votesno"] = poll["votesno"]
|
||||
poll_data["votesabstain"] = poll["votesabstain"]
|
||||
poll_data["votesvalid"] = poll["votesvalid"]
|
||||
poll_data["votesinvalid"] = poll["votesinvalid"]
|
||||
poll_data["votescast"] = poll["votescast"]
|
||||
|
||||
poll_data["options"] = [
|
||||
{
|
||||
"user": await get_user_name(all_data, option["user_id"]),
|
||||
"is_elected": option["is_elected"],
|
||||
"votes": option["votes"],
|
||||
}
|
||||
for option in sorted(poll["options"], key=lambda option: option["weight"])
|
||||
]
|
||||
|
||||
return {
|
||||
"title": assignment["title"],
|
||||
"assignments_poll_100_percent_base": await get_config(
|
||||
all_data, "assignments_poll_100_percent_base"
|
||||
),
|
||||
"poll": poll_data,
|
||||
}
|
||||
|
||||
|
||||
def register_projector_slides() -> None:
|
||||
register_projector_slide("assignments/assignment", assignment_slide)
|
||||
register_projector_slide("assignments/poll", poll_slide)
|
||||
|
Loading…
Reference in New Issue
Block a user