From 42f8b74d8e4ba4383abc2b91d2c9467447dfc60f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emanuel=20Sch=C3=BCtze?= Date: Sat, 26 Jan 2019 20:37:49 +0100 Subject: [PATCH] Projector templates - Projector base template - Projection button - projection dialog - motion slide (template and motions/projector.py) - user slide (template and users/projector.py) - motion and user list view with projector column permission check. --- .../services/projection-dialog.service.ts | 1 - .../projection-dialog.component.html | 37 +++++------ .../projection-dialog.component.scss | 7 +-- .../projector-button.component.html | 3 +- .../projector-button.component.scss | 8 +++ .../projector-button.component.ts | 19 +++++- .../mediafile-list.component.ts | 4 +- .../motion-list/motion-list.component.html | 13 ++-- .../motion-list/motion-list.component.ts | 27 ++++---- .../app/site/motions/models/view-motion.ts | 4 +- .../projector/projector.component.html | 21 +++++-- .../projector/projector.component.scss | 63 ++++++++++++++++--- .../projector/projector.component.ts | 8 +++ .../slide-container.component.scss | 3 + .../slide-container.component.ts | 4 +- .../user-list/user-list.component.html | 10 +-- .../user-list/user-list.component.scss | 4 ++ .../user-list/user-list.component.ts | 27 +++++++- .../clock/core-clock-slide.component.scss | 8 ++- .../motion/motions-motion-slide-data.ts | 12 ++++ .../motions-motion-slide.component.html | 35 ++++++++++- .../motions-motion-slide.component.scss | 16 ++++- .../users/user/users-user-slide-data.ts | 2 +- .../user/users-user-slide.component.html | 4 +- client/src/styles.scss | 58 +++++++++++++++-- openslides/agenda/projector.py | 8 ++- openslides/core/projector.py | 2 +- openslides/core/views.py | 4 +- openslides/motions/projector.py | 22 ++----- openslides/users/projector.py | 22 ++++++- tests/unit/motions/test_projector.py | 2 - 31 files changed, 347 insertions(+), 111 deletions(-) diff --git a/client/src/app/core/services/projection-dialog.service.ts b/client/src/app/core/services/projection-dialog.service.ts index d0e878789..33a6448e2 100644 --- a/client/src/app/core/services/projection-dialog.service.ts +++ b/client/src/app/core/services/projection-dialog.service.ts @@ -45,7 +45,6 @@ export class ProjectionDialogService extends OpenSlidesComponent { ProjectorElementBuildDeskriptor, ProjectionDialogReturnType >(ProjectionDialogComponent, { - minWidth: '500px', maxHeight: '90vh', data: descriptor }); diff --git a/client/src/app/shared/components/projection-dialog/projection-dialog.component.html b/client/src/app/shared/components/projection-dialog/projection-dialog.component.html index eb3458e78..2ef53e9ad 100644 --- a/client/src/app/shared/components/projection-dialog/projection-dialog.component.html +++ b/client/src/app/shared/components/projection-dialog/projection-dialog.component.html @@ -1,23 +1,19 @@ -

{{ projectorElementBuildDescriptor.getTitle() }}

+

Project + Motion + {{ projectorElementBuildDescriptor.getTitle() }}?

- - Projectors - -
- - {{ projector.name | translate }} - - - videocam - -
-
-
- - - Slide options - - +
+ + {{ projector.name | translate }} + + + videocam + +
+ + + +
@@ -33,8 +29,7 @@
- - +
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 a30f3b39e..4f28b3d89 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 @@ -1,15 +1,12 @@ mat-dialog-content { overflow: inherit; + min-width: auto; div.projectors { - padding: 15px; + padding: 15px 0; .right { float: right; } } - - mat-card { - margin-bottom: 10px; - } } diff --git a/client/src/app/shared/components/projector-button/projector-button.component.html b/client/src/app/shared/components/projector-button/projector-button.component.html index ac70297d1..2ae95b6d4 100644 --- a/client/src/app/shared/components/projector-button/projector-button.component.html +++ b/client/src/app/shared/components/projector-button/projector-button.component.html @@ -1,3 +1,4 @@ - diff --git a/client/src/app/shared/components/projector-button/projector-button.component.scss b/client/src/app/shared/components/projector-button/projector-button.component.scss index e69de29bb..afe39ac65 100644 --- a/client/src/app/shared/components/projector-button/projector-button.component.scss +++ b/client/src/app/shared/components/projector-button/projector-button.component.scss @@ -0,0 +1,8 @@ +.projectorbutton-active { + color: white !important; +} + +.projectorbutton-inactive { + background-color: white; + color: grey; +} 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 531b0f4e2..4696d9d04 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 @@ -1,6 +1,7 @@ import { Component, OnInit, Input } from '@angular/core'; import { Projectable, ProjectorElementBuildDeskriptor } from 'app/site/base/projectable'; import { ProjectionDialogService } from 'app/core/services/projection-dialog.service'; +import { ProjectorService } from '../../../core/services/projector.service'; /** */ @@ -16,7 +17,10 @@ export class ProjectorButtonComponent implements OnInit { /** * The consotructor */ - public constructor(private projectionDialogService: ProjectionDialogService) {} + public constructor( + private projectionDialogService: ProjectionDialogService, + private projectorService: ProjectorService + ) {} /** * Initialization function @@ -27,4 +31,17 @@ export class ProjectorButtonComponent implements OnInit { event.stopPropagation(); this.projectionDialogService.openProjectDialogFor(this.object); } + + /** + * + * + * @returns true, if the object is projected on one projector. + */ + public isProjected(): boolean { + if (this.object) { + return this.projectorService.isProjected(this.object); + } else { + return false; + } + } } diff --git a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.ts b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.ts index 455a27c84..81cbea14a 100644 --- a/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.ts +++ b/client/src/app/site/mediafiles/components/mediafile-list/mediafile-list.component.ts @@ -36,12 +36,12 @@ export class MediafileListComponent extends ListViewBaseComponent public fontActions: string[]; /** - * Columns to display in Mediafile table when fill width is available + * Columns to display in Mediafile table when desktop view is available */ public displayedColumnsDesktop: string[] = ['title', 'info', 'indicator', 'menu']; /** - * Columns to display in Mediafile table when fill width is available + * Columns to display in Mediafile table when mobile view is available */ public displayedColumnsMobile: string[] = ['title', 'menu']; diff --git a/client/src/app/site/motions/components/motion-list/motion-list.component.html b/client/src/app/site/motions/components/motion-list/motion-list.component.html index 329c1526e..95fdf776a 100644 --- a/client/src/app/site/motions/components/motion-list/motion-list.component.html +++ b/client/src/app/site/motions/components/motion-list/motion-list.component.html @@ -27,16 +27,16 @@ - - + + {{ isSelected(motion) ? 'check_circle' : '' }} - Projector - + Projector + @@ -84,13 +84,14 @@ grey: motion.state.css_class === 'default', lightblue: motion.state.css_class === 'primary' }" + [disabled]="true" > {{ getStateLabel(motion) }} - - {{ getRecommendationLabel(motion) }} + + {{ getRecommendationLabel(motion) }} diff --git a/client/src/app/site/motions/components/motion-list/motion-list.component.ts b/client/src/app/site/motions/components/motion-list/motion-list.component.ts index ce15e2cd4..1f1f65208 100644 --- a/client/src/app/site/motions/components/motion-list/motion-list.component.ts +++ b/client/src/app/site/motions/components/motion-list/motion-list.component.ts @@ -25,6 +25,8 @@ import { WorkflowState } from '../../../../shared/models/motions/workflow-state' import { WorkflowRepositoryService } from '../../services/workflow-repository.service'; import { MotionPdfExportService } from '../../services/motion-pdf-export.service'; import { MotionExportDialogComponent } from '../motion-export-dialog/motion-export-dialog.component'; +import { OperatorService } from '../../../../core/services/operator.service'; +import { ViewportService } from '../../../../core/services/viewport.service'; /** * Component that displays all the motions in a Table using DataSource. @@ -36,18 +38,14 @@ import { MotionExportDialogComponent } from '../motion-export-dialog/motion-expo }) export class MotionListComponent extends ListViewBaseComponent implements OnInit { /** - * Use for minimal width. Please note the 'selector' row for multiSelect mode, - * to be able to display an indicator for the state of selection - * TODO: Remove projector, if columnsToDisplayFullWidth is used.. + * Columns to display in table when desktop view is available */ - public columnsToDisplayMinWidth = ['projector', 'identifier', 'title', 'state', 'speakers']; + public displayedColumnsDesktop: string[] = ['identifier', 'title', 'state', 'speakers']; /** - * Use for maximal width. Please note the 'selector' row for multiSelect mode, - * to be able to display an indicator for the state of selection - * TODO: Needs vp.desktop check + * Columns to display in table when mobile view is available */ - public columnsToDisplayFullWidth = ['projector', 'identifier', 'title', 'state', 'speakers']; + public displayedColumnsMobile = ['identifier', 'title']; /** * Value of the configuration variable `motions_statutes_enabled` - are statutes enabled? @@ -82,6 +80,7 @@ export class MotionListComponent extends ListViewBaseComponent imple * @param userRepo * @param sortService * @param filterService + * @param vp * @param perms LocalPermissionService */ public constructor( @@ -97,8 +96,10 @@ export class MotionListComponent extends ListViewBaseComponent imple private workflowRepo: WorkflowRepositoryService, private motionRepo: MotionRepositoryService, private motionCsvExport: MotionCsvExportService, + private operator: OperatorService, private pdfExport: MotionPdfExportService, private dialog: MatDialog, + private vp: ViewportService, public multiselectService: MotionMultiselectService, public sortService: MotionSortListService, public filterService: MotionFilterListService, @@ -221,10 +222,14 @@ export class MotionListComponent extends ListViewBaseComponent imple * Returns current definitions for the listView table */ public getColumnDefinition(): string[] { - if (this.isMultiSelect) { - return ['selector'].concat(this.columnsToDisplayMinWidth); + let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop; + if (this.operator.hasPerms('core.can_manage_projector')) { + columns = ['projector'].concat(columns); } - return this.columnsToDisplayMinWidth; + if (this.isMultiSelect) { + columns = ['selector'].concat(columns); + } + return columns; } /** diff --git a/client/src/app/site/motions/models/view-motion.ts b/client/src/app/site/motions/models/view-motion.ts index 86a56e38e..33582ee08 100644 --- a/client/src/app/site/motions/models/view-motion.ts +++ b/client/src/app/site/motions/models/view-motion.ts @@ -318,7 +318,7 @@ export class ViewMotion extends BaseProjectableModel { public getTitle(): string { if (this.identifier) { - return this.identifier + ' - ' + this.title; + return 'Motion ' + this.identifier; } return this.title; } @@ -480,7 +480,7 @@ export class ViewMotion extends BaseProjectableModel { } ], projectionDefaultName: 'motions', - getTitle: () => this.getTitle() + getTitle: () => this.identifier }; } diff --git a/client/src/app/site/projector/components/projector/projector.component.html b/client/src/app/site/projector/components/projector/projector.component.html index a7ed7087d..f899c60ca 100644 --- a/client/src/app/site/projector/components/projector/projector.component.html +++ b/client/src/app/site/projector/components/projector/projector.component.html @@ -1,8 +1,15 @@
-
-
- Header Title + @@ -10,8 +17,12 @@
-
diff --git a/client/src/app/site/projector/components/projector/projector.component.scss b/client/src/app/site/projector/components/projector/projector.component.scss index 8526f1c44..5f8936b64 100644 --- a/client/src/app/site/projector/components/projector/projector.component.scss +++ b/client/src/app/site/projector/components/projector/projector.component.scss @@ -9,29 +9,76 @@ transform-origin: left top; overflow: hidden; - .header { + #header { position: absolute; top: 0; left: 0; - color: white; width: 100%; - height: 50px; + height: 70px; + box-shadow: 0 0 7px rgba(0, 0, 0, 0.6); + background-repeat: no-repeat; + background-size: 100% 100%; + margin-bottom: 20px; z-index: 1; + + #logo { + padding-left: 50px; + padding-top: 10px; + height: 50px; + margin-right: 25px; + float: left; + } + + #eventdata { + padding-left: 50px; + padding-top: 12px; + height: 50px; + overflow: hidden; + line-height: 1.1; + + .event-name { + font-size: 26px; + font-weight: 400; + + &.titleonly { + padding-top: 12px; + } + } + + .event-description { + font-size: 18px; + opacity: 0.8; + } + } } .content { width: 100%; height: 100%; position: absolute; top: 0; - left: 0; + left: 50px; + right: 50px; } - .footer { - position: absolute; - color: white; + + #footer { + position: fixed; width: 100%; - height: 50px; + height: 35px; bottom: 0; z-index: 1; + + .footertext { + font-size: 16px; + padding-left: 50px; + padding-right: 50px; + padding-top: 5px; + overflow: hidden; + text-align: right; + } + + span { + opacity: 0.8; + } } } } diff --git a/client/src/app/site/projector/components/projector/projector.component.ts b/client/src/app/site/projector/components/projector/projector.component.ts index 5a11e4eb4..1993b3beb 100644 --- a/client/src/app/site/projector/components/projector/projector.component.ts +++ b/client/src/app/site/projector/components/projector/projector.component.ts @@ -132,6 +132,10 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy { public enableHeaderAndFooter = true; public enableTitle = true; public enableLogo = true; + public eventName; + public eventDescription; + public eventDate; + public eventLocation; /** * Listen to all related config variables. Register the resizeSubject. @@ -166,6 +170,10 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy { this.configService .get('projector_background_color') .subscribe(val => (this.projectorStyle['background-color'] = val)); + this.configService.get('general_event_name').subscribe(val => (this.eventName = val)); + this.configService.get('general_event_description').subscribe(val => (this.eventDescription = val)); + this.configService.get('general_event_date').subscribe(val => (this.eventDate = val)); + this.configService.get('general_event_location').subscribe(val => (this.eventLocation = val)); // Watches for resizing of the container. this.resizeSubject.subscribe(() => { diff --git a/client/src/app/site/projector/components/slide-container/slide-container.component.scss b/client/src/app/site/projector/components/slide-container/slide-container.component.scss index 0e8c9aad9..2f5906446 100644 --- a/client/src/app/site/projector/components/slide-container/slide-container.component.scss +++ b/client/src/app/site/projector/components/slide-container/slide-container.component.scss @@ -1,3 +1,6 @@ +#slide { + width: calc(100% - 100px); +} ::ng-deep #slide { z-index: 5; height: 100%; diff --git a/client/src/app/site/projector/components/slide-container/slide-container.component.ts b/client/src/app/site/projector/components/slide-container/slide-container.component.ts index c73ab9bee..c8653e53f 100644 --- a/client/src/app/site/projector/components/slide-container/slide-container.component.ts +++ b/client/src/app/site/projector/components/slide-container/slide-container.component.ts @@ -95,7 +95,7 @@ export class SlideContainerComponent extends BaseComponent { */ public slideStyle: { 'font-size': string; 'margin-top': string } = { 'font-size': '100%', - 'margin-top': '50px' + 'margin-top': '100px' }; /** @@ -124,7 +124,7 @@ export class SlideContainerComponent extends BaseComponent { let value = this._scroll; value *= -50; if (this.headerEnabled) { - value += 50; // Default offset for the header + value += 100; // Default offset for the header } this.slideStyle['margin-top'] = `${value}px`; } else { diff --git a/client/src/app/site/users/components/user-list/user-list.component.html b/client/src/app/site/users/components/user-list/user-list.component.html index d8bd8bb9f..59b0034e1 100644 --- a/client/src/app/site/users/components/user-list/user-list.component.html +++ b/client/src/app/site/users/components/user-list/user-list.component.html @@ -25,16 +25,16 @@ - - + + {{ isSelected(user) ? 'check_circle' : '' }} - Projector - + Projector + @@ -49,7 +49,7 @@ Group -
+
people {{ user.groups }} diff --git a/client/src/app/site/users/components/user-list/user-list.component.scss b/client/src/app/site/users/components/user-list/user-list.component.scss index 7897b07cf..d30857b94 100644 --- a/client/src/app/site/users/components/user-list/user-list.component.scss +++ b/client/src/app/site/users/components/user-list/user-list.component.scss @@ -9,6 +9,10 @@ } .os-listview-table { + .mat-column-projector { + padding-right: 15px; + } + .mat-column-name { flex: 1 0 200px; } diff --git a/client/src/app/site/users/components/user-list/user-list.component.ts b/client/src/app/site/users/components/user-list/user-list.component.ts index 7d6e39b6f..18a8b9160 100644 --- a/client/src/app/site/users/components/user-list/user-list.component.ts +++ b/client/src/app/site/users/components/user-list/user-list.component.ts @@ -14,6 +14,8 @@ import { UserRepositoryService } from '../../services/user-repository.service'; import { ViewUser } from '../../models/view-user'; import { UserFilterListService } from '../../services/user-filter-list.service'; import { UserSortListService } from '../../services/user-sort-list.service'; +import { ViewportService } from '../../../../core/services/viewport.service'; +import { OperatorService } from '../../../../core/services/operator.service'; /** * Component for the user list view. @@ -25,6 +27,16 @@ import { UserSortListService } from '../../services/user-sort-list.service'; styleUrls: ['./user-list.component.scss'] }) export class UserListComponent extends ListViewBaseComponent implements OnInit { + /** + * Columns to display in table when desktop view is available + */ + public displayedColumnsDesktop: string[] = ['name', 'group']; + + /** + * Columns to display in table when mobile view is available + */ + public displayedColumnsMobile = ['name']; + /** * Stores the observed configuration if the presence view is available to administrators */ @@ -48,6 +60,8 @@ export class UserListComponent extends ListViewBaseComponent implement * @param groupRepo: The user group repository * @param router the router service * @param route the local route + * @param operator + * @param vp * @param csvExport CSV export Service, * @param promptService * @param groupRepo @@ -64,6 +78,8 @@ export class UserListComponent extends ListViewBaseComponent implement private choiceService: ChoiceService, private router: Router, private route: ActivatedRoute, + private operator: OperatorService, + private vp: ViewportService, protected csvExport: CsvExportService, private promptService: PromptService, public filterService: UserFilterListService, @@ -243,10 +259,15 @@ export class UserListComponent extends ListViewBaseComponent implement * @returns column definition */ public getColumnDefinition(): string[] { - // TODO: no projector in mobile view. - const columns = ['projector', 'name', 'group', 'presence']; + let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop; + if (this.operator.hasPerms('core.can_manage_projector')) { + columns = ['projector'].concat(columns); + } + if (this.operator.hasPerms('users.can_manage')) { + columns = columns.concat(['presence']); + } if (this.isMultiSelect) { - return ['selector'].concat(columns); + columns = ['selector'].concat(columns); } return columns; } diff --git a/client/src/app/slides/core/clock/core-clock-slide.component.scss b/client/src/app/slides/core/clock/core-clock-slide.component.scss index fea915978..67fdfa6fc 100644 --- a/client/src/app/slides/core/clock/core-clock-slide.component.scss +++ b/client/src/app/slides/core/clock/core-clock-slide.component.scss @@ -6,10 +6,16 @@ height: 30px; margin: 12px; z-index: 2; + padding-right: 50px; + padding-top: 5px; + + mat-icon { + padding-top: 5px; + } span { padding-left: 5px; - font-size: 16px; + font-size: 24px; float: right; } } diff --git a/client/src/app/slides/motions/motion/motions-motion-slide-data.ts b/client/src/app/slides/motions/motion/motions-motion-slide-data.ts index 9de7b2f40..75b2f650e 100644 --- a/client/src/app/slides/motions/motion/motions-motion-slide-data.ts +++ b/client/src/app/slides/motions/motion/motions-motion-slide-data.ts @@ -1,3 +1,15 @@ export interface MotionsMotionSlideData { + identifier: string; title: string; + text: string; + reason?: string; + is_child: boolean; + show_meta_box: boolean; + submitter?: string[]; + recommender?: string; + recommendation?: string; + recommendation_extension?: string; + amendment_paragraphs: { paragraph: string }[]; + change_recommendations: object[]; + modified_final_version?: string; } diff --git a/client/src/app/slides/motions/motion/motions-motion-slide.component.html b/client/src/app/slides/motions/motion/motions-motion-slide.component.html index 73d736376..73f494852 100644 --- a/client/src/app/slides/motions/motion/motions-motion-slide.component.html +++ b/client/src/app/slides/motions/motion/motions-motion-slide.component.html @@ -1,4 +1,35 @@
- Motion Slide -

{{ data.data.title }}

+ + +
+ +
+

{{ data.data.title }}

+

Motion {{ data.data.identifier }}

+
+ + +
+ + +
+ + +
+

Reason

+
+
+
diff --git a/client/src/app/slides/motions/motion/motions-motion-slide.component.scss b/client/src/app/slides/motions/motion/motions-motion-slide.component.scss index 05920c613..d7ca3f8c2 100644 --- a/client/src/app/slides/motions/motion/motions-motion-slide.component.scss +++ b/client/src/app/slides/motions/motion/motions-motion-slide.component.scss @@ -1,3 +1,15 @@ -div { - background-color: red; +#sidebox { + width: 260px; + right: 0; + margin-top: 50px; + background: #d3d3d3; + border-radius: 7px 0 0 7px; + padding: 3px 7px 10px 10px; + position: fixed; + z-index: 5; + + h3 { + margin-top: 10px; + margin-bottom: 0px; + } } diff --git a/client/src/app/slides/users/user/users-user-slide-data.ts b/client/src/app/slides/users/user/users-user-slide-data.ts index 2d7b8a59c..34df2beb5 100644 --- a/client/src/app/slides/users/user/users-user-slide-data.ts +++ b/client/src/app/slides/users/user/users-user-slide-data.ts @@ -1,3 +1,3 @@ export interface UsersUserSlideData { - test: string; + user: string; } diff --git a/client/src/app/slides/users/user/users-user-slide.component.html b/client/src/app/slides/users/user/users-user-slide.component.html index 6b555d8ce..63ee3cc1d 100644 --- a/client/src/app/slides/users/user/users-user-slide.component.html +++ b/client/src/app/slides/users/user/users-user-slide.component.html @@ -1,3 +1,3 @@ -
- User Slide +
+

{{ data.data.user }}

diff --git a/client/src/styles.scss b/client/src/styles.scss index 09625db31..2ddc0baf0 100644 --- a/client/src/styles.scss +++ b/client/src/styles.scss @@ -41,7 +41,9 @@ body { h1, h2, h3, -.title-font { +.title-font, +.slidetitle h1, +.slidetitle h2 { font-family: OSFont Condensed, Fira Sans Condensed, Roboto-condensed, Arial, Helvetica, sans-serif; } @@ -232,6 +234,15 @@ mat-card { .os-listview-table { @extend %os-table; + /* multi select column */ + .mat-column-selector { + flex: 0 0 60px; + } + /* projector button column */ + .mat-column-projector { + flex: 0 0 40px; + overflow: visible; + } /** hide mat header row */ .mat-header-row { display: none; @@ -242,6 +253,7 @@ mat-card { @extend %os-table; } + /* TODO: find a better way to get more vertical space in (empty/small) tables for maximize filter dialog */ mat-paginator { min-height: 800px; @@ -292,10 +304,6 @@ mat-expansion-panel { display: none; } -.icon-cell { - flex: 0 0 40px; -} - // ngx-file-drop requires the custom style in the global css file .file-drop-style { margin: auto; @@ -565,6 +573,7 @@ button.mat-menu-item.selected { flex: 1; min-width: 0px; } + .filter-imports { max-width: 50%; } @@ -574,3 +583,42 @@ button.mat-menu-item.selected { font-weight: 500; font-size: 16px; } + + +/*** Projector slides ***/ + +#slide { + + h3 { + color: #222; + margin-bottom: 10px + } + + .slidetitle { + border-bottom: 5px solid #d3d3d3; + margin-bottom: 40px; + + h1 { + font-size: 2.25em; + line-height: 1.1em; + margin-bottom: 0; + padding-bottom: 0; + } + h2 { + color: #9a9898; + margin-top: 10px; + margin-bottom: 0px; + font-size: 28px; + font-weight: normal; + display: block; + } + } + + ul, ol { + margin: 0 0 10px 0; + } + + hr { + margin: 10px 0; + } +} diff --git a/openslides/agenda/projector.py b/openslides/agenda/projector.py index 3b0c72321..731d76f0a 100644 --- a/openslides/agenda/projector.py +++ b/openslides/agenda/projector.py @@ -107,5 +107,9 @@ def current_list_of_speakers_slide( def register_projector_slides() -> None: register_projector_slide("agenda/item-list", items_slide) register_projector_slide("agenda/list-of-speakers", list_of_speakers_slide) - register_projector_slide("agenda/current-list-of-speakers", current_list_of_speakers_slide) - register_projector_element("agenda/current-list-of-speakers-overlay", current_list_of_speakers_slide) + register_projector_slide( + "agenda/current-list-of-speakers", current_list_of_speakers_slide + ) + register_projector_slide( + "agenda/current-list-of-speakers-overlay", current_list_of_speakers_slide + ) diff --git a/openslides/core/projector.py b/openslides/core/projector.py index ac814b363..a2564f535 100644 --- a/openslides/core/projector.py +++ b/openslides/core/projector.py @@ -54,4 +54,4 @@ def clock_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: def register_projector_slides() -> None: register_projector_slide("core/countdown", countdown_slide) register_projector_slide("core/projector-message", message_slide) - register_projector_element("core/clock", clock_slide) + register_projector_slide("core/clock", clock_slide) diff --git a/openslides/core/views.py b/openslides/core/views.py index 278fe053d..4ce5720e6 100644 --- a/openslides/core/views.py +++ b/openslides/core/views.py @@ -173,7 +173,9 @@ class ProjectorViewSet(ModelViewSet): elements = request.data.get("elements") preview = request.data.get("preview") history_element = request.data.get("append_to_history") - delete_last_history_element = request.data.get("delete_last_history_element", False) + delete_last_history_element = request.data.get( + "delete_last_history_element", False + ) changed_data = {} if elements is not None: diff --git a/openslides/motions/projector.py b/openslides/motions/projector.py index d58980bdd..1ae69fb88 100644 --- a/openslides/motions/projector.py +++ b/openslides/motions/projector.py @@ -45,12 +45,11 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: * show_meta_box * reason * modified_final_version - * state - * state_extension * recommendation * recommendation_extension + * recommender + * change_recommendations * submitter - * poll """ mode = element.get("mode") motion_id = element.get("id") @@ -81,11 +80,6 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: return_value["modified_final_version"] = motion["modified_final_version"] if show_meta_box: - state = get_state(all_data, motion, motion["state_id"]) - return_value["state"] = state["name"] - if state["show_state_extension_field"]: - return_value["state_extension"] = motion["state_extension"] - if ( not get_config(all_data, "motions_disable_recommendation_on_projector") and motion["recommendation_id"] @@ -101,6 +95,9 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: "recommendation_extension" ] + return_value["recommender"] = get_config( + all_data, "motions_recommendations_by" + ) return_value["change_recommendations"] = motion["change_recommendations"] return_value["submitter"] = [ @@ -110,15 +107,6 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: ) ] - for poll in motion["polls"][::-1]: - if poll["has_votes"]: - return_value["poll"] = { - "yes": poll["yes"], - "no": poll["no"], - "abstain": poll["abstain"], - } - break - return return_value diff --git a/openslides/users/projector.py b/openslides/users/projector.py index c65d40547..a383d1bfb 100644 --- a/openslides/users/projector.py +++ b/openslides/users/projector.py @@ -1,6 +1,10 @@ from typing import Any, Dict, List -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 user_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]: """ User slide. + + The returned dict can contain the following fields: + * user """ - return {"error": "TODO"} + user_id = element.get("id") + + if user_id is None: + return {"error": "id is required for user slide"} + + try: + user = all_data["users/user"][user_id] + except KeyError: + raise ProjectorElementException(f"user with id {user_id} does not exist") + + return_value = {"user": get_user_name(all_data, user["id"])} + return return_value def get_user_name(all_data: AllData, user_id: int) -> str: diff --git a/tests/unit/motions/test_projector.py b/tests/unit/motions/test_projector.py index eb91a2df5..e372748b5 100644 --- a/tests/unit/motions/test_projector.py +++ b/tests/unit/motions/test_projector.py @@ -166,7 +166,5 @@ def test_motion_slide(all_data): "is_child": False, "show_meta_box": True, "reason": "", - "state": "submitted", "submitter": ["Administrator"], - "poll": {"yes": "10.000000", "no": "-1.000000", "abstain": "20.000000"}, }