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.
This commit is contained in:
parent
965d23be50
commit
42f8b74d8e
@ -45,7 +45,6 @@ export class ProjectionDialogService extends OpenSlidesComponent {
|
|||||||
ProjectorElementBuildDeskriptor,
|
ProjectorElementBuildDeskriptor,
|
||||||
ProjectionDialogReturnType
|
ProjectionDialogReturnType
|
||||||
>(ProjectionDialogComponent, {
|
>(ProjectionDialogComponent, {
|
||||||
minWidth: '500px',
|
|
||||||
maxHeight: '90vh',
|
maxHeight: '90vh',
|
||||||
data: descriptor
|
data: descriptor
|
||||||
});
|
});
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
<h2 mat-dialog-title>{{ projectorElementBuildDescriptor.getTitle() }}</h2>
|
<h2 mat-dialog-title translate>Project
|
||||||
|
<span *ngIf="projectorElementBuildDescriptor.projectionDefaultName === 'motions'" translate>Motion</span>
|
||||||
|
{{ projectorElementBuildDescriptor.getTitle() }}?</h2>
|
||||||
<mat-dialog-content>
|
<mat-dialog-content>
|
||||||
<mat-card>
|
|
||||||
<mat-card-title> <span translate>Projectors</span> </mat-card-title>
|
|
||||||
<mat-card-content>
|
|
||||||
<div class="projectors" *ngFor="let projector of projectors" [ngClass]="isProjectedOn(projector) ? 'projected' : ''">
|
<div class="projectors" *ngFor="let projector of projectors" [ngClass]="isProjectedOn(projector) ? 'projected' : ''">
|
||||||
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
||||||
{{ projector.name | translate }}
|
{{ projector.name | translate }}
|
||||||
@ -11,13 +10,10 @@
|
|||||||
<mat-icon>videocam</mat-icon>
|
<mat-icon>videocam</mat-icon>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
|
||||||
</mat-card>
|
<mat-divider></mat-divider>
|
||||||
<mat-card *ngIf="options.length > 0">
|
|
||||||
<mat-card-title>
|
<div *ngIf="options.length > 0">
|
||||||
<span translate>Slide options</span>
|
|
||||||
</mat-card-title>
|
|
||||||
<mat-card-content>
|
|
||||||
<div *ngFor="let option of options">
|
<div *ngFor="let option of options">
|
||||||
<div *ngIf="isDecisionOption(option)">
|
<div *ngIf="isDecisionOption(option)">
|
||||||
<mat-checkbox [checked]="projectorElement[option.key]" (change)="projectorElement[option.key] = !projectorElement[option.key]">
|
<mat-checkbox [checked]="projectorElement[option.key]" (change)="projectorElement[option.key] = !projectorElement[option.key]">
|
||||||
@ -33,8 +29,7 @@
|
|||||||
</mat-radio-group>
|
</mat-radio-group>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</div>
|
||||||
</mat-card>
|
|
||||||
</mat-dialog-content>
|
</mat-dialog-content>
|
||||||
<mat-dialog-actions>
|
<mat-dialog-actions>
|
||||||
<button mat-button (click)="onOk()" color="primary" translate>OK</button>
|
<button mat-button (click)="onOk()" color="primary" translate>OK</button>
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
mat-dialog-content {
|
mat-dialog-content {
|
||||||
overflow: inherit;
|
overflow: inherit;
|
||||||
|
min-width: auto;
|
||||||
|
|
||||||
div.projectors {
|
div.projectors {
|
||||||
padding: 15px;
|
padding: 15px 0;
|
||||||
|
|
||||||
.right {
|
.right {
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mat-card {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
<button type="button" mat-icon-button (click)="onClick($event)">
|
<button type="button" mat-mini-fab (click)="onClick($event)"
|
||||||
|
[ngClass]="isProjected() ? 'projectorbutton-active' : 'projectorbutton-inactive'">
|
||||||
<mat-icon>videocam</mat-icon>
|
<mat-icon>videocam</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
.projectorbutton-active {
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.projectorbutton-inactive {
|
||||||
|
background-color: white;
|
||||||
|
color: grey;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import { Component, OnInit, Input } from '@angular/core';
|
import { Component, OnInit, Input } from '@angular/core';
|
||||||
import { Projectable, ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
import { Projectable, ProjectorElementBuildDeskriptor } from 'app/site/base/projectable';
|
||||||
import { ProjectionDialogService } from 'app/core/services/projection-dialog.service';
|
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
|
* The consotructor
|
||||||
*/
|
*/
|
||||||
public constructor(private projectionDialogService: ProjectionDialogService) {}
|
public constructor(
|
||||||
|
private projectionDialogService: ProjectionDialogService,
|
||||||
|
private projectorService: ProjectorService
|
||||||
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialization function
|
* Initialization function
|
||||||
@ -27,4 +31,17 @@ export class ProjectorButtonComponent implements OnInit {
|
|||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
this.projectionDialogService.openProjectDialogFor(this.object);
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,12 @@ export class MediafileListComponent extends ListViewBaseComponent<ViewMediafile>
|
|||||||
public fontActions: string[];
|
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'];
|
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'];
|
public displayedColumnsMobile: string[] = ['title', 'menu'];
|
||||||
|
|
||||||
|
@ -27,16 +27,16 @@
|
|||||||
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
||||||
<!-- Selector column -->
|
<!-- Selector column -->
|
||||||
<ng-container matColumnDef="selector">
|
<ng-container matColumnDef="selector">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="checkbox-cell"></mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header></mat-header-cell>
|
||||||
<mat-cell *matCellDef="let motion" class="checkbox-cell">
|
<mat-cell *matCellDef="let motion">
|
||||||
<mat-icon>{{ isSelected(motion) ? 'check_circle' : '' }}</mat-icon>
|
<mat-icon>{{ isSelected(motion) ? 'check_circle' : '' }}</mat-icon>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Projector column -->
|
<!-- Projector column -->
|
||||||
<ng-container matColumnDef="projector">
|
<ng-container matColumnDef="projector">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="icon-cell">Projector</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let motion" class="icon-cell">
|
<mat-cell *matCellDef="let motion">
|
||||||
<os-projector-button [object]="motion"></os-projector-button>
|
<os-projector-button [object]="motion"></os-projector-button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -84,13 +84,14 @@
|
|||||||
grey: motion.state.css_class === 'default',
|
grey: motion.state.css_class === 'default',
|
||||||
lightblue: motion.state.css_class === 'primary'
|
lightblue: motion.state.css_class === 'primary'
|
||||||
}"
|
}"
|
||||||
|
[disabled]="true"
|
||||||
>
|
>
|
||||||
{{ getStateLabel(motion) }}
|
{{ getStateLabel(motion) }}
|
||||||
</mat-basic-chip>
|
</mat-basic-chip>
|
||||||
|
|
||||||
<!-- recommendation -->
|
<!-- recommendation -->
|
||||||
<span *ngIf="motion.recommendation">
|
<span *ngIf="motion.recommendation && motion.state.next_states_id.length > 0">
|
||||||
<mat-basic-chip class="bluegrey"> {{ getRecommendationLabel(motion) }} </mat-basic-chip>
|
<mat-basic-chip class="bluegrey" [disabled]="true">{{ getRecommendationLabel(motion) }} </mat-basic-chip>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
|
@ -25,6 +25,8 @@ import { WorkflowState } from '../../../../shared/models/motions/workflow-state'
|
|||||||
import { WorkflowRepositoryService } from '../../services/workflow-repository.service';
|
import { WorkflowRepositoryService } from '../../services/workflow-repository.service';
|
||||||
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
import { MotionPdfExportService } from '../../services/motion-pdf-export.service';
|
||||||
import { MotionExportDialogComponent } from '../motion-export-dialog/motion-export-dialog.component';
|
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.
|
* 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<ViewMotion> implements OnInit {
|
export class MotionListComponent extends ListViewBaseComponent<ViewMotion> implements OnInit {
|
||||||
/**
|
/**
|
||||||
* Use for minimal width. Please note the 'selector' row for multiSelect mode,
|
* Columns to display in table when desktop view is available
|
||||||
* to be able to display an indicator for the state of selection
|
|
||||||
* TODO: Remove projector, if columnsToDisplayFullWidth is used..
|
|
||||||
*/
|
*/
|
||||||
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,
|
* Columns to display in table when mobile view is available
|
||||||
* to be able to display an indicator for the state of selection
|
|
||||||
* TODO: Needs vp.desktop check
|
|
||||||
*/
|
*/
|
||||||
public columnsToDisplayFullWidth = ['projector', 'identifier', 'title', 'state', 'speakers'];
|
public displayedColumnsMobile = ['identifier', 'title'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Value of the configuration variable `motions_statutes_enabled` - are statutes enabled?
|
* Value of the configuration variable `motions_statutes_enabled` - are statutes enabled?
|
||||||
@ -82,6 +80,7 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
|||||||
* @param userRepo
|
* @param userRepo
|
||||||
* @param sortService
|
* @param sortService
|
||||||
* @param filterService
|
* @param filterService
|
||||||
|
* @param vp
|
||||||
* @param perms LocalPermissionService
|
* @param perms LocalPermissionService
|
||||||
*/
|
*/
|
||||||
public constructor(
|
public constructor(
|
||||||
@ -97,8 +96,10 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
|||||||
private workflowRepo: WorkflowRepositoryService,
|
private workflowRepo: WorkflowRepositoryService,
|
||||||
private motionRepo: MotionRepositoryService,
|
private motionRepo: MotionRepositoryService,
|
||||||
private motionCsvExport: MotionCsvExportService,
|
private motionCsvExport: MotionCsvExportService,
|
||||||
|
private operator: OperatorService,
|
||||||
private pdfExport: MotionPdfExportService,
|
private pdfExport: MotionPdfExportService,
|
||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
|
private vp: ViewportService,
|
||||||
public multiselectService: MotionMultiselectService,
|
public multiselectService: MotionMultiselectService,
|
||||||
public sortService: MotionSortListService,
|
public sortService: MotionSortListService,
|
||||||
public filterService: MotionFilterListService,
|
public filterService: MotionFilterListService,
|
||||||
@ -221,10 +222,14 @@ export class MotionListComponent extends ListViewBaseComponent<ViewMotion> imple
|
|||||||
* Returns current definitions for the listView table
|
* Returns current definitions for the listView table
|
||||||
*/
|
*/
|
||||||
public getColumnDefinition(): string[] {
|
public getColumnDefinition(): string[] {
|
||||||
if (this.isMultiSelect) {
|
let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop;
|
||||||
return ['selector'].concat(this.columnsToDisplayMinWidth);
|
if (this.operator.hasPerms('core.can_manage_projector')) {
|
||||||
|
columns = ['projector'].concat(columns);
|
||||||
}
|
}
|
||||||
return this.columnsToDisplayMinWidth;
|
if (this.isMultiSelect) {
|
||||||
|
columns = ['selector'].concat(columns);
|
||||||
|
}
|
||||||
|
return columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,7 +318,7 @@ export class ViewMotion extends BaseProjectableModel {
|
|||||||
|
|
||||||
public getTitle(): string {
|
public getTitle(): string {
|
||||||
if (this.identifier) {
|
if (this.identifier) {
|
||||||
return this.identifier + ' - ' + this.title;
|
return 'Motion ' + this.identifier;
|
||||||
}
|
}
|
||||||
return this.title;
|
return this.title;
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ export class ViewMotion extends BaseProjectableModel {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
projectionDefaultName: 'motions',
|
projectionDefaultName: 'motions',
|
||||||
getTitle: () => this.getTitle()
|
getTitle: () => this.identifier
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,15 @@
|
|||||||
<div id="container" [osResized]="resizeSubject" [ngStyle]="containerStyle" #container>
|
<div id="container" [osResized]="resizeSubject" [ngStyle]="containerStyle" #container>
|
||||||
<div id="projector" [ngStyle]="projectorStyle">
|
<div id="projector" [ngStyle]="projectorStyle">
|
||||||
<div class="header" [ngStyle]="headerFooterStyle" *ngIf="enableHeaderAndFooter">
|
<div id="header" [ngStyle]="headerFooterStyle" *ngIf="enableHeaderAndFooter">
|
||||||
<div *ngIf="enableTitle">
|
<!-- TODO: Logo <img *ngIf="enableLogo" id="logo"> -->
|
||||||
Header Title
|
<div *ngIf="enableTitle" id="eventdata">
|
||||||
|
<div
|
||||||
|
*ngIf="eventName"
|
||||||
|
class="event-name"
|
||||||
|
[ngClass]="!eventDescription ? 'titleonly' : ''"
|
||||||
|
[innerHTML]="eventName"
|
||||||
|
></div>
|
||||||
|
<div *ngIf="eventDescription" class="event-description" [innerHTML]="eventDescription"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -10,8 +17,12 @@
|
|||||||
<os-slide-container [slideData]="slide" [scroll]="scroll" [scale]="scale"></os-slide-container>
|
<os-slide-container [slideData]="slide" [scroll]="scroll" [scale]="scale"></os-slide-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="footer" [ngStyle]="headerFooterStyle" *ngIf="enableHeaderAndFooter">
|
<div id="footer" [ngStyle]="headerFooterStyle" *ngIf="enableHeaderAndFooter">
|
||||||
Footer
|
<div class="footertext">
|
||||||
|
<span *ngIf="eventDate"> {{ eventDate }} </span>
|
||||||
|
<span *ngIf="eventDate && eventLocation"> | </span>
|
||||||
|
<span *ngIf="eventLocation"> {{ eventLocation }} </span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,29 +9,76 @@
|
|||||||
transform-origin: left top;
|
transform-origin: left top;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.header {
|
#header {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
color: white;
|
|
||||||
width: 100%;
|
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;
|
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 {
|
.content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 50px;
|
||||||
|
right: 50px;
|
||||||
}
|
}
|
||||||
.footer {
|
|
||||||
position: absolute;
|
#footer {
|
||||||
color: white;
|
position: fixed;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 50px;
|
height: 35px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
z-index: 1;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,6 +132,10 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
public enableHeaderAndFooter = true;
|
public enableHeaderAndFooter = true;
|
||||||
public enableTitle = true;
|
public enableTitle = true;
|
||||||
public enableLogo = true;
|
public enableLogo = true;
|
||||||
|
public eventName;
|
||||||
|
public eventDescription;
|
||||||
|
public eventDate;
|
||||||
|
public eventLocation;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listen to all related config variables. Register the resizeSubject.
|
* Listen to all related config variables. Register the resizeSubject.
|
||||||
@ -166,6 +170,10 @@ export class ProjectorComponent extends BaseComponent implements OnDestroy {
|
|||||||
this.configService
|
this.configService
|
||||||
.get<string>('projector_background_color')
|
.get<string>('projector_background_color')
|
||||||
.subscribe(val => (this.projectorStyle['background-color'] = val));
|
.subscribe(val => (this.projectorStyle['background-color'] = val));
|
||||||
|
this.configService.get<string>('general_event_name').subscribe(val => (this.eventName = val));
|
||||||
|
this.configService.get<string>('general_event_description').subscribe(val => (this.eventDescription = val));
|
||||||
|
this.configService.get<string>('general_event_date').subscribe(val => (this.eventDate = val));
|
||||||
|
this.configService.get<string>('general_event_location').subscribe(val => (this.eventLocation = val));
|
||||||
|
|
||||||
// Watches for resizing of the container.
|
// Watches for resizing of the container.
|
||||||
this.resizeSubject.subscribe(() => {
|
this.resizeSubject.subscribe(() => {
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#slide {
|
||||||
|
width: calc(100% - 100px);
|
||||||
|
}
|
||||||
::ng-deep #slide {
|
::ng-deep #slide {
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -95,7 +95,7 @@ export class SlideContainerComponent extends BaseComponent {
|
|||||||
*/
|
*/
|
||||||
public slideStyle: { 'font-size': string; 'margin-top': string } = {
|
public slideStyle: { 'font-size': string; 'margin-top': string } = {
|
||||||
'font-size': '100%',
|
'font-size': '100%',
|
||||||
'margin-top': '50px'
|
'margin-top': '100px'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -124,7 +124,7 @@ export class SlideContainerComponent extends BaseComponent {
|
|||||||
let value = this._scroll;
|
let value = this._scroll;
|
||||||
value *= -50;
|
value *= -50;
|
||||||
if (this.headerEnabled) {
|
if (this.headerEnabled) {
|
||||||
value += 50; // Default offset for the header
|
value += 100; // Default offset for the header
|
||||||
}
|
}
|
||||||
this.slideStyle['margin-top'] = `${value}px`;
|
this.slideStyle['margin-top'] = `${value}px`;
|
||||||
} else {
|
} else {
|
||||||
|
@ -25,16 +25,16 @@
|
|||||||
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
<mat-table class="os-listview-table on-transition-fade" [dataSource]="dataSource" matSort>
|
||||||
<!-- Selector column -->
|
<!-- Selector column -->
|
||||||
<ng-container matColumnDef="selector">
|
<ng-container matColumnDef="selector">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="icon-cell"></mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header></mat-header-cell>
|
||||||
<mat-cell *matCellDef="let user" (click)="selectItem(user, $event)" class="icon-cell">
|
<mat-cell *matCellDef="let user" (click)="selectItem(user, $event)">
|
||||||
<mat-icon>{{ isSelected(user) ? 'check_circle' : '' }}</mat-icon>
|
<mat-icon>{{ isSelected(user) ? 'check_circle' : '' }}</mat-icon>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<!-- Projector column -->
|
<!-- Projector column -->
|
||||||
<ng-container matColumnDef="projector">
|
<ng-container matColumnDef="projector">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header class="icon-cell">Projector</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Projector</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let user" class="icon-cell">
|
<mat-cell *matCellDef="let user">
|
||||||
<os-projector-button [object]="user"></os-projector-button>
|
<os-projector-button [object]="user"></os-projector-button>
|
||||||
</mat-cell>
|
</mat-cell>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
@ -49,7 +49,7 @@
|
|||||||
<ng-container matColumnDef="group">
|
<ng-container matColumnDef="group">
|
||||||
<mat-header-cell *matHeaderCellDef mat-sort-header>Group</mat-header-cell>
|
<mat-header-cell *matHeaderCellDef mat-sort-header>Group</mat-header-cell>
|
||||||
<mat-cell *matCellDef="let user">
|
<mat-cell *matCellDef="let user">
|
||||||
<div class="groupsCell">
|
<div class='groupsCell'>
|
||||||
<span *ngIf="user.groups && user.groups.length">
|
<span *ngIf="user.groups && user.groups.length">
|
||||||
<mat-icon>people</mat-icon>
|
<mat-icon>people</mat-icon>
|
||||||
{{ user.groups }}
|
{{ user.groups }}
|
||||||
|
@ -9,6 +9,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.os-listview-table {
|
.os-listview-table {
|
||||||
|
.mat-column-projector {
|
||||||
|
padding-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
.mat-column-name {
|
.mat-column-name {
|
||||||
flex: 1 0 200px;
|
flex: 1 0 200px;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import { UserRepositoryService } from '../../services/user-repository.service';
|
|||||||
import { ViewUser } from '../../models/view-user';
|
import { ViewUser } from '../../models/view-user';
|
||||||
import { UserFilterListService } from '../../services/user-filter-list.service';
|
import { UserFilterListService } from '../../services/user-filter-list.service';
|
||||||
import { UserSortListService } from '../../services/user-sort-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.
|
* Component for the user list view.
|
||||||
@ -25,6 +27,16 @@ import { UserSortListService } from '../../services/user-sort-list.service';
|
|||||||
styleUrls: ['./user-list.component.scss']
|
styleUrls: ['./user-list.component.scss']
|
||||||
})
|
})
|
||||||
export class UserListComponent extends ListViewBaseComponent<ViewUser> implements OnInit {
|
export class UserListComponent extends ListViewBaseComponent<ViewUser> 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
|
* Stores the observed configuration if the presence view is available to administrators
|
||||||
*/
|
*/
|
||||||
@ -48,6 +60,8 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
|||||||
* @param groupRepo: The user group repository
|
* @param groupRepo: The user group repository
|
||||||
* @param router the router service
|
* @param router the router service
|
||||||
* @param route the local route
|
* @param route the local route
|
||||||
|
* @param operator
|
||||||
|
* @param vp
|
||||||
* @param csvExport CSV export Service,
|
* @param csvExport CSV export Service,
|
||||||
* @param promptService
|
* @param promptService
|
||||||
* @param groupRepo
|
* @param groupRepo
|
||||||
@ -64,6 +78,8 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
|||||||
private choiceService: ChoiceService,
|
private choiceService: ChoiceService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
|
private operator: OperatorService,
|
||||||
|
private vp: ViewportService,
|
||||||
protected csvExport: CsvExportService,
|
protected csvExport: CsvExportService,
|
||||||
private promptService: PromptService,
|
private promptService: PromptService,
|
||||||
public filterService: UserFilterListService,
|
public filterService: UserFilterListService,
|
||||||
@ -243,10 +259,15 @@ export class UserListComponent extends ListViewBaseComponent<ViewUser> implement
|
|||||||
* @returns column definition
|
* @returns column definition
|
||||||
*/
|
*/
|
||||||
public getColumnDefinition(): string[] {
|
public getColumnDefinition(): string[] {
|
||||||
// TODO: no projector in mobile view.
|
let columns = this.vp.isMobile ? this.displayedColumnsMobile : this.displayedColumnsDesktop;
|
||||||
const columns = ['projector', 'name', 'group', 'presence'];
|
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) {
|
if (this.isMultiSelect) {
|
||||||
return ['selector'].concat(columns);
|
columns = ['selector'].concat(columns);
|
||||||
}
|
}
|
||||||
return columns;
|
return columns;
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,16 @@
|
|||||||
height: 30px;
|
height: 30px;
|
||||||
margin: 12px;
|
margin: 12px;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
padding-right: 50px;
|
||||||
|
padding-top: 5px;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
span {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
font-size: 16px;
|
font-size: 24px;
|
||||||
float: right;
|
float: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
export interface MotionsMotionSlideData {
|
export interface MotionsMotionSlideData {
|
||||||
|
identifier: string;
|
||||||
title: 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;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,35 @@
|
|||||||
<div *ngIf="data">
|
<div *ngIf="data">
|
||||||
Motion Slide
|
<div id="sidebox" *ngIf="data.data.show_meta_box">
|
||||||
|
<!-- Submitters -->
|
||||||
|
<h3 translate>Submitters</h3>
|
||||||
|
<span *ngFor="let submitter of data.data.submitter; let last = last">
|
||||||
|
{{ submitter }}<span *ngIf="!last">, </span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<!-- Recommendation -->
|
||||||
|
<div *ngIf="data.data.recommendation && data.data.recommender">
|
||||||
|
<h3>{{ data.data.recommender }}</h3>
|
||||||
|
{{ data.data.recommendation | translate }} {{ data.data.recommendation_extension }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div [ngStyle]="{'width': data.data.show_meta_box ? 'calc(100% - 250px)' : '100%'}">
|
||||||
|
<!-- Title -->
|
||||||
|
<div class="slidetitle">
|
||||||
<h1>{{ data.data.title }}</h1>
|
<h1>{{ data.data.title }}</h1>
|
||||||
|
<h2><span translate>Motion</span> {{ data.data.identifier }}</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Text (original) -->
|
||||||
|
<div *ngIf="!data.data.is_child" [innerHTML]="data.data.text"></div>
|
||||||
|
|
||||||
|
<!-- Amendment text -->
|
||||||
|
<div *ngIf="data.data.is_child" [innerHTML]="data.data.amendment_paragraphs[0]"></div>
|
||||||
|
|
||||||
|
<!-- Reason -->
|
||||||
|
<div *ngIf="data.data.reason">
|
||||||
|
<h3 translate>Reason</h3>
|
||||||
|
<div [innerHTML]="data.data.reason"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,3 +1,15 @@
|
|||||||
div {
|
#sidebox {
|
||||||
background-color: red;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export interface UsersUserSlideData {
|
export interface UsersUserSlideData {
|
||||||
test: string;
|
user: string;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
<div id="outer">
|
<div *ngIf="data">
|
||||||
User Slide
|
<h1>{{ data.data.user }}</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -41,7 +41,9 @@ body {
|
|||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
h3,
|
h3,
|
||||||
.title-font {
|
.title-font,
|
||||||
|
.slidetitle h1,
|
||||||
|
.slidetitle h2 {
|
||||||
font-family: OSFont Condensed, Fira Sans Condensed, Roboto-condensed, Arial, Helvetica, sans-serif;
|
font-family: OSFont Condensed, Fira Sans Condensed, Roboto-condensed, Arial, Helvetica, sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,6 +234,15 @@ mat-card {
|
|||||||
.os-listview-table {
|
.os-listview-table {
|
||||||
@extend %os-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 */
|
/** hide mat header row */
|
||||||
.mat-header-row {
|
.mat-header-row {
|
||||||
display: none;
|
display: none;
|
||||||
@ -242,6 +253,7 @@ mat-card {
|
|||||||
@extend %os-table;
|
@extend %os-table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* TODO: find a better way to get more vertical space in (empty/small) tables for maximize filter dialog */
|
/* TODO: find a better way to get more vertical space in (empty/small) tables for maximize filter dialog */
|
||||||
mat-paginator {
|
mat-paginator {
|
||||||
min-height: 800px;
|
min-height: 800px;
|
||||||
@ -292,10 +304,6 @@ mat-expansion-panel {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.icon-cell {
|
|
||||||
flex: 0 0 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ngx-file-drop requires the custom style in the global css file
|
// ngx-file-drop requires the custom style in the global css file
|
||||||
.file-drop-style {
|
.file-drop-style {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
@ -565,6 +573,7 @@ button.mat-menu-item.selected {
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0px;
|
min-width: 0px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter-imports {
|
.filter-imports {
|
||||||
max-width: 50%;
|
max-width: 50%;
|
||||||
}
|
}
|
||||||
@ -574,3 +583,42 @@ button.mat-menu-item.selected {
|
|||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 16px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -107,5 +107,9 @@ def current_list_of_speakers_slide(
|
|||||||
def register_projector_slides() -> None:
|
def register_projector_slides() -> None:
|
||||||
register_projector_slide("agenda/item-list", items_slide)
|
register_projector_slide("agenda/item-list", items_slide)
|
||||||
register_projector_slide("agenda/list-of-speakers", list_of_speakers_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_slide(
|
||||||
register_projector_element("agenda/current-list-of-speakers-overlay", current_list_of_speakers_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
|
||||||
|
)
|
||||||
|
@ -54,4 +54,4 @@ def clock_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
def register_projector_slides() -> None:
|
def register_projector_slides() -> None:
|
||||||
register_projector_slide("core/countdown", countdown_slide)
|
register_projector_slide("core/countdown", countdown_slide)
|
||||||
register_projector_slide("core/projector-message", message_slide)
|
register_projector_slide("core/projector-message", message_slide)
|
||||||
register_projector_element("core/clock", clock_slide)
|
register_projector_slide("core/clock", clock_slide)
|
||||||
|
@ -173,7 +173,9 @@ class ProjectorViewSet(ModelViewSet):
|
|||||||
elements = request.data.get("elements")
|
elements = request.data.get("elements")
|
||||||
preview = request.data.get("preview")
|
preview = request.data.get("preview")
|
||||||
history_element = request.data.get("append_to_history")
|
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 = {}
|
changed_data = {}
|
||||||
if elements is not None:
|
if elements is not None:
|
||||||
|
@ -45,12 +45,11 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
* show_meta_box
|
* show_meta_box
|
||||||
* reason
|
* reason
|
||||||
* modified_final_version
|
* modified_final_version
|
||||||
* state
|
|
||||||
* state_extension
|
|
||||||
* recommendation
|
* recommendation
|
||||||
* recommendation_extension
|
* recommendation_extension
|
||||||
|
* recommender
|
||||||
|
* change_recommendations
|
||||||
* submitter
|
* submitter
|
||||||
* poll
|
|
||||||
"""
|
"""
|
||||||
mode = element.get("mode")
|
mode = element.get("mode")
|
||||||
motion_id = element.get("id")
|
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"]
|
return_value["modified_final_version"] = motion["modified_final_version"]
|
||||||
|
|
||||||
if show_meta_box:
|
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 (
|
if (
|
||||||
not get_config(all_data, "motions_disable_recommendation_on_projector")
|
not get_config(all_data, "motions_disable_recommendation_on_projector")
|
||||||
and motion["recommendation_id"]
|
and motion["recommendation_id"]
|
||||||
@ -101,6 +95,9 @@ def motion_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]:
|
|||||||
"recommendation_extension"
|
"recommendation_extension"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
return_value["recommender"] = get_config(
|
||||||
|
all_data, "motions_recommendations_by"
|
||||||
|
)
|
||||||
return_value["change_recommendations"] = motion["change_recommendations"]
|
return_value["change_recommendations"] = motion["change_recommendations"]
|
||||||
|
|
||||||
return_value["submitter"] = [
|
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
|
return return_value
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
from typing import Any, Dict, List
|
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
|
# 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]:
|
def user_slide(all_data: AllData, element: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
User slide.
|
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:
|
def get_user_name(all_data: AllData, user_id: int) -> str:
|
||||||
|
@ -166,7 +166,5 @@ def test_motion_slide(all_data):
|
|||||||
"is_child": False,
|
"is_child": False,
|
||||||
"show_meta_box": True,
|
"show_meta_box": True,
|
||||||
"reason": "",
|
"reason": "",
|
||||||
"state": "submitted",
|
|
||||||
"submitter": ["Administrator"],
|
"submitter": ["Administrator"],
|
||||||
"poll": {"yes": "10.000000", "no": "-1.000000", "abstain": "20.000000"},
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user