diff --git a/client/src/app/core/ui-services/projection-dialog.service.ts b/client/src/app/core/ui-services/projection-dialog.service.ts index f59350bb0..0f44623c7 100644 --- a/client/src/app/core/ui-services/projection-dialog.service.ts +++ b/client/src/app/core/ui-services/projection-dialog.service.ts @@ -36,7 +36,6 @@ export class ProjectionDialogService { } else { descriptor = obj; } - const dialogRef = this.dialog.open< ProjectionDialogComponent, ProjectorElementBuildDeskriptor, diff --git a/client/src/app/shared/components/projection-dialog/projection-dialog.component.scss b/client/src/app/shared/components/projection-dialog/projection-dialog.component.scss index 4f28b3d89..ed019cb6c 100644 --- a/client/src/app/shared/components/projection-dialog/projection-dialog.component.scss +++ b/client/src/app/shared/components/projection-dialog/projection-dialog.component.scss @@ -5,8 +5,13 @@ mat-dialog-content { div.projectors { padding: 15px 0; + mat-checkbox { + padding: 0 10px; + } + .right { float: right; + padding-right: 10px; } } } diff --git a/client/src/app/shared/components/projector-button/projector-button.component.ts b/client/src/app/shared/components/projector-button/projector-button.component.ts index f8fb91fcb..dad433ed8 100644 --- a/client/src/app/shared/components/projector-button/projector-button.component.ts +++ b/client/src/app/shared/components/projector-button/projector-button.component.ts @@ -24,7 +24,7 @@ export class ProjectorButtonComponent implements OnInit { /** * The object to project. */ - private _object: Projectable | ProjectorElementBuildDeskriptor; + private _object: Projectable | ProjectorElementBuildDeskriptor | null; public get object(): Projectable | ProjectorElementBuildDeskriptor { return this._object; @@ -35,10 +35,7 @@ export class ProjectorButtonComponent implements OnInit { if (isProjectable(obj) || isProjectorElementBuildDeskriptor(obj)) { this._object = obj; } else { - console.error( - 'Your model for the projectorbutton is not projectable and not' + 'a projectorElementBuildDescriptor!', - obj - ); + this.object = null; } } @@ -62,7 +59,9 @@ export class ProjectorButtonComponent implements OnInit { */ public onClick(event: Event): void { event.stopPropagation(); - this.projectionDialogService.openProjectDialogFor(this.object); + if (this.object) { + this.projectionDialogService.openProjectDialogFor(this.object); + } } /** diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html index 0a7cd0a25..d30c5acf2 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.html @@ -28,6 +28,16 @@ + + + Projector + +
+ +
+
+
+ Topic diff --git a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts index c93caaab3..a5a97aaa4 100644 --- a/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts +++ b/client/src/app/site/agenda/components/agenda-list/agenda-list.component.ts @@ -54,6 +54,7 @@ export class AgendaListComponent extends ListViewBaseComponent impleme * @param titleService Setting the browser tab title * @param translate translations * @param matSnackBar Shows errors and messages + * @param operator The current user * @param route Angulars ActivatedRoute * @param router Angulars router * @param repo the agenda repository, @@ -66,12 +67,12 @@ export class AgendaListComponent extends ListViewBaseComponent impleme * @param filterService: service for filtering data * @param agendaPdfService: service for preparing a pdf of the agenda * @param pdfService: Service for exporting a pdf - * @param operator the current user */ public constructor( titleService: Title, translate: TranslateService, matSnackBar: MatSnackBar, + private operator: OperatorService, private route: ActivatedRoute, private router: Router, private repo: ItemRepositoryService, @@ -83,8 +84,7 @@ export class AgendaListComponent extends ListViewBaseComponent impleme private csvExport: AgendaCsvExportService, public filterService: AgendaFilterListService, private agendaPdfService: AgendaPdfService, - private pdfService: PdfDocumentService, - private operator: OperatorService + private pdfService: PdfDocumentService ) { super(titleService, translate, matSnackBar); @@ -238,11 +238,14 @@ export class AgendaListComponent extends ListViewBaseComponent impleme * @returns an array of strings with the dialogs to show */ public getColumnDefinition(): string[] { - const list = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop; - if (this.isMultiSelect) { - return ['selector'].concat(list); + let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop; + if (this.operator.hasPerms('core.can_manage_projector')) { + columns = ['projector'].concat(columns); } - return list; + if (this.isMultiSelect) { + columns = ['selector'].concat(columns); + } + return columns; } /** diff --git a/client/src/app/site/agenda/models/view-topic.ts b/client/src/app/site/agenda/models/view-topic.ts index 7ff96d190..1e02bd80e 100644 --- a/client/src/app/site/agenda/models/view-topic.ts +++ b/client/src/app/site/agenda/models/view-topic.ts @@ -96,7 +96,16 @@ export class ViewTopic extends BaseAgendaViewModel { } public getSlide(): ProjectorElementBuildDeskriptor { - throw new Error('TODO'); + return { + getBasicProjectorElement: () => ({ + name: Topic.COLLECTIONSTRING, + id: this.id, + getIdentifiers: () => ['name', 'id'] + }), + slideOptions: [], + projectionDefaultName: 'topics', + getTitle: () => this.getTitle() + }; } public hasAttachments(): boolean { diff --git a/client/src/app/site/assignments/models/view-assignment.ts b/client/src/app/site/assignments/models/view-assignment.ts index fb829c399..5e5e3131e 100644 --- a/client/src/app/site/assignments/models/view-assignment.ts +++ b/client/src/app/site/assignments/models/view-assignment.ts @@ -80,6 +80,15 @@ export class ViewAssignment extends BaseAgendaViewModel { } public getSlide(): ProjectorElementBuildDeskriptor { - throw new Error('TODO'); + return { + getBasicProjectorElement: () => ({ + name: Assignment.COLLECTIONSTRING, + id: this.id, + getIdentifiers: () => ['name', 'id'] + }), + slideOptions: [], + projectionDefaultName: 'assignments', + getTitle: () => this.getTitle() + }; } } diff --git a/client/src/app/site/base/projectable.ts b/client/src/app/site/base/projectable.ts index 0011317fc..182f6c58a 100644 --- a/client/src/app/site/base/projectable.ts +++ b/client/src/app/site/base/projectable.ts @@ -5,6 +5,7 @@ import { SlideOptions } from './slide-options'; export function isProjectorElementBuildDeskriptor(obj: any): obj is ProjectorElementBuildDeskriptor { const deskriptor = obj; return ( + !!deskriptor && deskriptor.slideOptions !== undefined && deskriptor.getBasicProjectorElement !== undefined && deskriptor.getTitle !== undefined @@ -23,7 +24,11 @@ export interface ProjectorElementBuildDeskriptor { } export function isProjectable(obj: any): obj is Projectable { - return (obj).getSlide !== undefined; + if (obj) { + return (obj).getSlide !== undefined; + } else { + return false; + } } /** diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide-data.ts b/client/src/app/slides/agenda/topic/topics-topic-slide-data.ts new file mode 100644 index 000000000..dfa23048b --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide-data.ts @@ -0,0 +1,4 @@ +export interface TopicsTopicSlideData { + title: string; + text: string; +} diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.component.html b/client/src/app/slides/agenda/topic/topics-topic-slide.component.html new file mode 100644 index 000000000..1def91c3f --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide.component.html @@ -0,0 +1,5 @@ +
+

{{ data.data.title }}

+ +
+
diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.component.scss b/client/src/app/slides/agenda/topic/topics-topic-slide.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.component.spec.ts b/client/src/app/slides/agenda/topic/topics-topic-slide.component.spec.ts new file mode 100644 index 000000000..2edf21d5e --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide.component.spec.ts @@ -0,0 +1,26 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { TopicsTopicSlideComponent } from './topics-topic-slide.component'; +import { E2EImportsModule } from 'e2e-imports.module'; + +describe('TopicsTopicSlideComponent', () => { + let component: TopicsTopicSlideComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [E2EImportsModule], + declarations: [TopicsTopicSlideComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TopicsTopicSlideComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.component.ts b/client/src/app/slides/agenda/topic/topics-topic-slide.component.ts new file mode 100644 index 000000000..8267de3b7 --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide.component.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; +import { BaseSlideComponent } from 'app/slides/base-slide-component'; +import { TopicsTopicSlideData } from './topics-topic-slide-data'; + +@Component({ + selector: 'os-topic-slide', + templateUrl: './topics-topic-slide.component.html', + styleUrls: ['./topics-topic-slide.component.scss'] +}) +export class TopicsTopicSlideComponent extends BaseSlideComponent { + public constructor() { + super(); + } +} diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.module.spec.ts b/client/src/app/slides/agenda/topic/topics-topic-slide.module.spec.ts new file mode 100644 index 000000000..6661ad8f1 --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide.module.spec.ts @@ -0,0 +1,13 @@ +import { TopicsTopicSlideModule } from './topics-topic-slide.module'; + +describe('TopicsTopicSlideModule', () => { + let topicsTopicSlideModule: TopicsTopicSlideModule; + + beforeEach(() => { + topicsTopicSlideModule = new TopicsTopicSlideModule(); + }); + + it('should create an instance', () => { + expect(topicsTopicSlideModule).toBeTruthy(); + }); +}); diff --git a/client/src/app/slides/agenda/topic/topics-topic-slide.module.ts b/client/src/app/slides/agenda/topic/topics-topic-slide.module.ts new file mode 100644 index 000000000..1e30afea4 --- /dev/null +++ b/client/src/app/slides/agenda/topic/topics-topic-slide.module.ts @@ -0,0 +1,7 @@ +import { NgModule } from '@angular/core'; + +import { makeSlideModule } from 'app/slides/base-slide-module'; +import { TopicsTopicSlideComponent } from './topics-topic-slide.component'; + +@NgModule(makeSlideModule(TopicsTopicSlideComponent)) +export class TopicsTopicSlideModule {} diff --git a/client/src/app/slides/all-slides.ts b/client/src/app/slides/all-slides.ts index dddc056df..82ba5eaca 100644 --- a/client/src/app/slides/all-slides.ts +++ b/client/src/app/slides/all-slides.ts @@ -8,6 +8,16 @@ import { SlideManifest } from './slide-manifest'; * is no such thing as "dynamic update" in this case.. */ export const allSlides: SlideManifest[] = [ + { + slide: 'topics/topic', + path: 'topics/topic', + loadChildren: './slides/agenda/topic/topics-topic-slide.module#TopicsTopicSlideModule', + scaleable: true, + scrollable: true, + verboseName: 'Topic', + elementIdentifiers: ['name', 'id'], + canBeMappedToModel: true + }, { slide: 'motions/motion', path: 'motions/motion', diff --git a/client/src/app/slides/users/user/users-user-slide.component.scss b/client/src/app/slides/users/user/users-user-slide.component.scss index 3e34e6385..e69de29bb 100644 --- a/client/src/app/slides/users/user/users-user-slide.component.scss +++ b/client/src/app/slides/users/user/users-user-slide.component.scss @@ -1,9 +0,0 @@ -#outer { - position: absolute; - right: 0; - top: 0; - background-color: green; - height: 30px; - margin: 10px; - z-index: 2; -} diff --git a/openslides/topics/projector.py b/openslides/topics/projector.py index 6c6b6663f..43f7906a8 100644 --- a/openslides/topics/projector.py +++ b/openslides/topics/projector.py @@ -1,6 +1,10 @@ from typing import Any, Dict -from ..utils.projector import AllData, register_projector_slide +from ..utils.projector import ( + AllData, + ProjectorElementException, + register_projector_slide, +) # Important: All functions have to be prune. This means, that thay can only @@ -12,8 +16,22 @@ from ..utils.projector import AllData, register_projector_slide def topic_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: """ Topic slide. + + The returned dict can contain the following fields: + * title + * text """ - return {"error": "TODO"} + topic_id = element.get("id") + + if topic_id is None: + raise ProjectorElementException("id is required for topic slide") + + try: + topic = all_data["topics/topic"][topic_id] + except KeyError: + raise ProjectorElementException(f"topic with id {topic_id} does not exist") + + return {"title": topic["title"], "text": topic["text"]} def register_projector_slides() -> None: