Add leftover changes for 3.1
Adds various changes for a more complete 3.1 release - cleaner "current slide" description in projector detail (grid with ellipsis) - show the previously projected slides as ordered lists under the accordion - fix a bug where everyone could access the projection manage view (although it was unfunctional without the correct permissions) - assignment list now uses the correct ellipsis - fixes a bug where the lable "list of speakers" was not translated on the projector slide - Show a lock on the "list of speaker"-slide if it has been closed - enable dialog tests that have previously been disabled
This commit is contained in:
parent
50ce5e7d61
commit
c9cf99d0e4
@ -63,7 +63,8 @@ export abstract class BaseIsAgendaItemAndListOfSpeakersContentObjectRepository<
|
||||
}
|
||||
|
||||
public getAgendaSlideTitle(titleInformation: T): string {
|
||||
const numberPrefix = titleInformation.agenda_item_number() ? `${titleInformation.agenda_item_number()} · ` : '';
|
||||
const itemNumber = titleInformation.agenda_item_number();
|
||||
const numberPrefix = itemNumber ? `${itemNumber} · ` : '';
|
||||
return numberPrefix + this.getTitle(titleInformation);
|
||||
}
|
||||
|
||||
|
@ -237,7 +237,7 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
|
||||
|
||||
public getTitle = (titleInformation: MotionTitleInformation) => {
|
||||
if (titleInformation.identifier) {
|
||||
return titleInformation.identifier + ': ' + titleInformation.title;
|
||||
return `${titleInformation.identifier}: ${titleInformation.title}`;
|
||||
} else {
|
||||
return titleInformation.title;
|
||||
}
|
||||
@ -255,9 +255,9 @@ export class MotionRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCo
|
||||
const numberPrefix = titleInformation.agenda_item_number() ? `${titleInformation.agenda_item_number()} · ` : '';
|
||||
// if the identifier is set, the title will be 'Motion <identifier>'.
|
||||
if (titleInformation.identifier) {
|
||||
return numberPrefix + this.translate.instant('Motion') + ' ' + titleInformation.identifier;
|
||||
return `${numberPrefix} ${this.translate.instant('Motion')} ${titleInformation.identifier}`;
|
||||
} else {
|
||||
return numberPrefix + titleInformation.title;
|
||||
return `${numberPrefix} ${titleInformation.title}`;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -52,8 +52,8 @@ export class TopicRepositoryService extends BaseIsAgendaItemAndListOfSpeakersCon
|
||||
}
|
||||
|
||||
public getTitle = (titleInformation: TopicTitleInformation) => {
|
||||
if (titleInformation.agenda_item_number()) {
|
||||
return titleInformation.agenda_item_number() + ' · ' + titleInformation.title;
|
||||
if (titleInformation.agenda_item_number && titleInformation.agenda_item_number()) {
|
||||
return `${titleInformation.agenda_item_number()} · ${titleInformation.title}`;
|
||||
} else {
|
||||
return titleInformation.title;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
<!-- Title -->
|
||||
<h2 mat-dialog-title>{{ data.title | translate }}</h2>
|
||||
<h2 mat-dialog-title *ngIf="data">{{ data.title | translate }}</h2>
|
||||
|
||||
<form [formGroup]="selectForm">
|
||||
<form [formGroup]="selectForm" *ngIf="data">
|
||||
<!-- Content -->
|
||||
<div mat-dialog-content *ngIf="data.choices">
|
||||
<os-search-value-selector
|
||||
|
@ -1,26 +1,34 @@
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
|
||||
// import { ChoiceDialogComponent } from './choice-dialog.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { ChoiceDialogComponent } from './choice-dialog.component';
|
||||
|
||||
describe('ChoiceDialogComponent', () => {
|
||||
// let component: ChoiceDialogComponent;
|
||||
// let fixture: ComponentFixture<ChoiceDialogComponent>;
|
||||
let component: ChoiceDialogComponent;
|
||||
let fixture: ComponentFixture<ChoiceDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: null
|
||||
}
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
// TODO: You cannot create this component in the standard way. Needs different testing.
|
||||
beforeEach(() => {
|
||||
/*fixture = TestBed.createComponent(PromptDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();*/
|
||||
fixture = TestBed.createComponent(ChoiceDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
/*it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});*/
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@ -73,7 +73,7 @@ export class ChoiceDialogComponent {
|
||||
* @returns true if there is a selection chosen
|
||||
*/
|
||||
public get hasSelection(): boolean {
|
||||
if (this.data.choices) {
|
||||
if (this.data && this.data.choices) {
|
||||
if (this.selectForm.get('select').value) {
|
||||
return !!this.selectForm.get('select').value || !!this.selectForm.get('select').value.length;
|
||||
} else {
|
||||
|
@ -1,23 +1,29 @@
|
||||
<h2 mat-dialog-title>
|
||||
<span translate>Project selection?</span>
|
||||
</h2>
|
||||
<div class="element-name">{{ projectorElementBuildDescriptor.getDialogTitle() }}</div>
|
||||
<div class="element-name" *ngIf="projectorElementBuildDescriptor">
|
||||
{{ projectorElementBuildDescriptor.getDialogTitle() }}
|
||||
</div>
|
||||
|
||||
<mat-dialog-content>
|
||||
<div class="projectors"
|
||||
<div
|
||||
class="projectors"
|
||||
*ngFor="let projector of projectors"
|
||||
[ngClass]="isProjectedOn(projector) ? 'projected' : ''">
|
||||
[ngClass]="isProjectedOn(projector) ? 'projected' : ''"
|
||||
>
|
||||
<mat-checkbox [checked]="isProjectorSelected(projector)" (change)="toggleProjector(projector)">
|
||||
{{ projector.name | translate }}
|
||||
</mat-checkbox>
|
||||
<span *ngIf="isProjectedOn(projector)" class="right">
|
||||
<mat-icon matTooltip="{{ 'Is already projected' | translate }}" matTooltipPosition="above">videocam</mat-icon>
|
||||
<mat-icon matTooltip="{{ 'Is already projected' | translate }}" matTooltipPosition="above"
|
||||
>videocam</mat-icon
|
||||
>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
<div *ngIf="options.length > 0">
|
||||
<div *ngIf="options && options.length">
|
||||
<div *ngFor="let option of options">
|
||||
<div *ngIf="isDecisionOption(option)" class="spacer-top-10 spacer-left-10">
|
||||
<mat-checkbox
|
||||
|
@ -1,26 +1,34 @@
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
|
||||
// import { ProjectionDialogComponent } from './prjection-dialog.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { ProjectionDialogComponent } from './projection-dialog.component';
|
||||
|
||||
describe('ProjectionDialogComponent', () => {
|
||||
// let component: ProjectionDialogComponent;
|
||||
// let fixture: ComponentFixture<ProjectionDialogComponent>;
|
||||
let component: ProjectionDialogComponent;
|
||||
let fixture: ComponentFixture<ProjectionDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: null
|
||||
}
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
// TODO: You cannot create this component in the standard way. Needs different testing.
|
||||
beforeEach(() => {
|
||||
/*fixture = TestBed.createComponent(ProjectionDialogComponent);
|
||||
fixture = TestBed.createComponent(ProjectionDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();*/
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
/*it('should create', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});*/
|
||||
});
|
||||
});
|
||||
|
@ -38,26 +38,28 @@ export class ProjectionDialogComponent {
|
||||
this.projectors = this.DS.getAll<Projector>('core/projector');
|
||||
// TODO: Maybe watch. But this may not be necessary for the short living time of this dialog.
|
||||
|
||||
this.selectedProjectors = this.projectorService.getProjectorsWhichAreProjecting(
|
||||
this.projectorElementBuildDescriptor
|
||||
);
|
||||
|
||||
// Add default projector, if the projectable is not projected on it.
|
||||
if (this.projectorElementBuildDescriptor.projectionDefaultName) {
|
||||
const defaultProjector: Projector = this.projectorService.getProjectorForDefault(
|
||||
this.projectorElementBuildDescriptor.projectionDefaultName
|
||||
if (projectorElementBuildDescriptor) {
|
||||
this.selectedProjectors = this.projectorService.getProjectorsWhichAreProjecting(
|
||||
this.projectorElementBuildDescriptor
|
||||
);
|
||||
if (defaultProjector && !this.selectedProjectors.includes(defaultProjector)) {
|
||||
this.selectedProjectors.push(defaultProjector);
|
||||
|
||||
// Add default projector, if the projectable is not projected on it.
|
||||
if (this.projectorElementBuildDescriptor.projectionDefaultName) {
|
||||
const defaultProjector: Projector = this.projectorService.getProjectorForDefault(
|
||||
this.projectorElementBuildDescriptor.projectionDefaultName
|
||||
);
|
||||
if (defaultProjector && !this.selectedProjectors.includes(defaultProjector)) {
|
||||
this.selectedProjectors.push(defaultProjector);
|
||||
}
|
||||
}
|
||||
|
||||
// Set option defaults
|
||||
this.projectorElementBuildDescriptor.slideOptions.forEach(option => {
|
||||
this.optionValues[option.key] = option.default;
|
||||
});
|
||||
|
||||
this.options = this.projectorElementBuildDescriptor.slideOptions;
|
||||
}
|
||||
|
||||
// Set option defaults
|
||||
this.projectorElementBuildDescriptor.slideOptions.forEach(option => {
|
||||
this.optionValues[option.key] = option.default;
|
||||
});
|
||||
|
||||
this.options = this.projectorElementBuildDescriptor.slideOptions;
|
||||
}
|
||||
|
||||
public toggleProjector(projector: Projector): void {
|
||||
|
@ -1,6 +1,8 @@
|
||||
<h2 mat-dialog-title>{{ data.title }}</h2>
|
||||
<mat-dialog-content [innerHTML]="data.content"></mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="true" color="warn">{{ 'Yes' | translate }}</button>
|
||||
<button mat-button [mat-dialog-close]="false">{{ 'Cancel' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
<div *ngIf="data">
|
||||
<h2 mat-dialog-title>{{ data.title }}</h2>
|
||||
<mat-dialog-content [innerHTML]="data.content"></mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button [mat-dialog-close]="true" color="warn">{{ 'Yes' | translate }}</button>
|
||||
<button mat-button [mat-dialog-close]="false">{{ 'Cancel' | translate }}</button>
|
||||
</mat-dialog-actions>
|
||||
</div>
|
||||
|
@ -1,26 +1,34 @@
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
|
||||
// import { PromptDialogComponent } from './prompt-dialog.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { PromptDialogComponent } from './prompt-dialog.component';
|
||||
|
||||
describe('PromptDialogComponent', () => {
|
||||
// let component: PromptDialogComponent;
|
||||
// let fixture: ComponentFixture<PromptDialogComponent>;
|
||||
let component: PromptDialogComponent;
|
||||
let fixture: ComponentFixture<PromptDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: null
|
||||
}
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
// TODO: You cannot create this component in the standard way. Needs different testing.
|
||||
beforeEach(() => {
|
||||
/*fixture = TestBed.createComponent(PromptDialogComponent);
|
||||
fixture = TestBed.createComponent(PromptDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();*/
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
/*it('should create', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});*/
|
||||
});
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
<h1 mat-dialog-title>{{ 'Edit details for' | translate }} {{ item.getTitle() }}</h1>
|
||||
<h1 mat-dialog-title *ngIf="item">{{ 'Edit details for' | translate }} {{ item.getTitle() }}</h1>
|
||||
<div mat-dialog-content>
|
||||
<form class="item-dialog-form" [formGroup]="agendaInfoForm" (keydown)="onKeyDown($event)">
|
||||
<!-- Visibility -->
|
||||
|
@ -1,26 +1,35 @@
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
|
||||
|
||||
// import { ItemInfoDialogComponent } from './item-info-dialog.component';
|
||||
import { E2EImportsModule } from 'e2e-imports.module';
|
||||
|
||||
import { ItemInfoDialogComponent } from './item-info-dialog.component';
|
||||
|
||||
describe('ItemInfoDialogComponent', () => {
|
||||
// let component: ItemInfoDialogComponent;
|
||||
// let fixture: ComponentFixture<ItemInfoDialogComponent>;
|
||||
let component: ItemInfoDialogComponent;
|
||||
let fixture: ComponentFixture<ItemInfoDialogComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [E2EImportsModule]
|
||||
imports: [E2EImportsModule],
|
||||
declarations: [ItemInfoDialogComponent],
|
||||
providers: [
|
||||
{ provide: MatDialogRef, useValue: {} },
|
||||
{
|
||||
provide: MAT_DIALOG_DATA,
|
||||
useValue: null
|
||||
}
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
// TODO: You cannot create this component in the standard way. Needs different testing.
|
||||
beforeEach(() => {
|
||||
/*fixture = TestBed.createComponent(ItemInfoDialogComponent);
|
||||
fixture = TestBed.createComponent(ItemInfoDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();*/
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
/*it('should create', () => {
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});*/
|
||||
});
|
||||
});
|
||||
|
@ -38,8 +38,7 @@ export class ItemInfoDialogComponent {
|
||||
public formBuilder: FormBuilder,
|
||||
public durationService: DurationService,
|
||||
public dialogRef: MatDialogRef<ItemInfoDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public item: ViewItem
|
||||
@Inject(MAT_DIALOG_DATA) public item: ViewItem
|
||||
) {
|
||||
this.agendaInfoForm = this.formBuilder.group({
|
||||
type: [''],
|
||||
@ -49,10 +48,12 @@ export class ItemInfoDialogComponent {
|
||||
});
|
||||
|
||||
// load current values
|
||||
this.agendaInfoForm.get('type').setValue(item.type);
|
||||
this.agendaInfoForm.get('durationText').setValue(this.durationService.durationToString(item.duration, 'h'));
|
||||
this.agendaInfoForm.get('item_number').setValue(item.item_number);
|
||||
this.agendaInfoForm.get('comment').setValue(item.comment);
|
||||
if (item) {
|
||||
this.agendaInfoForm.get('type').setValue(item.type);
|
||||
this.agendaInfoForm.get('durationText').setValue(this.durationService.durationToString(item.duration, 'h'));
|
||||
this.agendaInfoForm.get('item_number').setValue(item.item_number);
|
||||
this.agendaInfoForm.get('comment').setValue(item.comment);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -168,7 +168,7 @@
|
||||
[input]="assignment.assignment_related_users"
|
||||
[live]="true"
|
||||
[count]="true"
|
||||
[enable]="hasPerms('addOthers')"
|
||||
[enable]="hasPerms('manage')"
|
||||
(sortEvent)="onSortingChange($event)"
|
||||
>
|
||||
<!-- implicit item references into the component using ng-template slot -->
|
||||
@ -177,6 +177,7 @@
|
||||
<button
|
||||
mat-icon-button
|
||||
matTooltip="{{ 'Remove candidate' | translate }}"
|
||||
*osPerms="'assignments.can_manage'"
|
||||
(click)="removeUser(item)"
|
||||
>
|
||||
<mat-icon>clear</mat-icon>
|
||||
|
@ -244,7 +244,7 @@ export class AssignmentDetailComponent extends BaseViewComponent implements OnIn
|
||||
} else {
|
||||
return (
|
||||
this.assignment.isSearchingForCandidates &&
|
||||
this.operator.hasPerms('assignments.can_nominate_others') &&
|
||||
this.operator.hasPerms('assignments.can_nominate_other') &&
|
||||
!this.assignment.isFinished
|
||||
);
|
||||
}
|
||||
|
@ -34,11 +34,11 @@
|
||||
<!-- Title -->
|
||||
<div *pblNgridCellDef="'title'; row as assignment; rowContext as rowContext" class="cell-slot fill">
|
||||
<a class="detail-link" [routerLink]="assignment.id" *ngIf="!isMultiSelect"></a>
|
||||
<div>
|
||||
<div class="innerTable">
|
||||
<div class="title-line ellipsis-overflow">
|
||||
{{ assignment.getListTitle() }}
|
||||
</div>
|
||||
<mat-chip-list *ngIf="vp.isMobile">
|
||||
<mat-chip-list class="ellipsis-overflow" *ngIf="vp.isMobile">
|
||||
<mat-chip color="primary" selected>
|
||||
{{ assignment.phaseString | translate }}
|
||||
</mat-chip>
|
||||
|
@ -7,7 +7,7 @@
|
||||
'project title buttons'
|
||||
'project controls controls';
|
||||
grid-gap: 10px;
|
||||
grid-template-columns: min-content auto auto;
|
||||
grid-template-columns: min-content auto min-content;
|
||||
}
|
||||
|
||||
// could be in a shared scss
|
||||
@ -28,6 +28,7 @@
|
||||
.action-buttons {
|
||||
grid-area: buttons;
|
||||
text-align: right;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.timer {
|
||||
|
@ -9,10 +9,6 @@ describe('MessageDialogComponent', () => {
|
||||
let component: MessageDialogComponent;
|
||||
let fixture: ComponentFixture<MessageDialogComponent>;
|
||||
|
||||
// const dialogData: MessageData = {
|
||||
// text: ''
|
||||
// };
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MessageDialogComponent],
|
||||
|
@ -1,13 +1,46 @@
|
||||
<os-head-bar [nav]="false" [hasMainButton]="true" mainButtonIcon="edit" [goBack]="true" (mainEvent)="editProjector()">
|
||||
<os-head-bar
|
||||
[nav]="false"
|
||||
[hasMainButton]="canManage()"
|
||||
mainButtonIcon="edit"
|
||||
[goBack]="true"
|
||||
(mainEvent)="editProjector()"
|
||||
>
|
||||
<!-- Title -->
|
||||
<div class="title-slot">
|
||||
<h2>{{ projector?.name | translate }}</h2>
|
||||
</div>
|
||||
|
||||
<!-- Menu -->
|
||||
<div class="menu-slot">
|
||||
<button
|
||||
*osPerms="'core.can_manage_projector'"
|
||||
type="button"
|
||||
mat-icon-button
|
||||
[matMenuTriggerFor]="projectorExtraMenu"
|
||||
>
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-menu #projectorExtraMenu="matMenu">
|
||||
<!-- Button for set reference projector -->
|
||||
<button mat-menu-item (click)="onSetAsClosRef()" *ngIf="projector" [disabled]="projector.isReferenceProjector">
|
||||
<mat-icon *ngIf="projector.isReferenceProjector">star</mat-icon>
|
||||
<mat-icon *ngIf="!projector.isReferenceProjector">star_border</mat-icon>
|
||||
<span>{{ 'Set as reference projector' | translate }}</span>
|
||||
</button>
|
||||
|
||||
<!-- delete -->
|
||||
<button mat-menu-item class="red-warning-text" (click)="onDeleteProjectorButton()">
|
||||
<mat-icon>delete</mat-icon>
|
||||
<span translate>Delete</span>
|
||||
</button>
|
||||
</mat-menu>
|
||||
</os-head-bar>
|
||||
|
||||
<os-grid-layout *ngIf="projector">
|
||||
<os-tile [preferredSize]="projectorTileSizeLeft">
|
||||
<div *ngIf="projector" class="column-left">
|
||||
<div *ngIf="projector" class="projector-detail-wrapper column-left">
|
||||
<a [routerLink]="['/projector', projector.id]">
|
||||
<div id="projector">
|
||||
<os-projector [projector]="projector"></os-projector>
|
||||
@ -16,18 +49,30 @@
|
||||
<!-- Controls under the projector preview -->
|
||||
<div *osPerms="'core.can_manage_projector'" class="control-group projector-controls">
|
||||
<!-- scale down -->
|
||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Down)"
|
||||
matTooltip="{{ 'Zoom out' | translate }}">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="scale(scrollScaleDirection.Down)"
|
||||
matTooltip="{{ 'Zoom out' | translate }}"
|
||||
>
|
||||
<mat-icon>zoom_out</mat-icon>
|
||||
</button>
|
||||
<!-- scale up -->
|
||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Up)"
|
||||
matTooltip="{{ 'Zoom in' | translate }}">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="scale(scrollScaleDirection.Up)"
|
||||
matTooltip="{{ 'Zoom in' | translate }}"
|
||||
>
|
||||
<mat-icon>zoom_in</mat-icon>
|
||||
</button>
|
||||
<!-- reset button -->
|
||||
<button type="button" mat-icon-button (click)="scale(scrollScaleDirection.Reset)"
|
||||
matTooltip="{{ 'Reset' | translate }}">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="scale(scrollScaleDirection.Reset)"
|
||||
matTooltip="{{ 'Reset' | translate }}"
|
||||
>
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
<!-- scaling indicator -->
|
||||
@ -73,8 +118,12 @@
|
||||
<mat-icon>arrow_downward</mat-icon>
|
||||
</button>
|
||||
<!-- reset button -->
|
||||
<button type="button" mat-icon-button (click)="scroll(scrollScaleDirection.Reset)"
|
||||
matTooltip="{{ 'Reset' | translate }}">
|
||||
<button
|
||||
type="button"
|
||||
mat-icon-button
|
||||
(click)="scroll(scrollScaleDirection.Reset)"
|
||||
matTooltip="{{ 'Reset' | translate }}"
|
||||
>
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
<!-- scroll indicator -->
|
||||
@ -113,18 +162,20 @@
|
||||
<mat-list>
|
||||
<mat-list-item
|
||||
*ngFor="let element of projector.non_stable_elements"
|
||||
class="currentElement backgroundColorAccent"
|
||||
class="current-element backgroundColorAccent"
|
||||
>
|
||||
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
</button>
|
||||
{{ getSlideTitle(element) }}
|
||||
<div class="button-right">
|
||||
<div>
|
||||
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="emelent-grid">
|
||||
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
||||
<mat-icon>videocam</mat-icon>
|
||||
</button>
|
||||
|
||||
<span class="ellipsis-overflow current-element-text">
|
||||
{{ getSlideTitle(element) }}
|
||||
</span>
|
||||
|
||||
<button type="button" mat-icon-button (click)="unprojectCurrent(element)">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</mat-list-item>
|
||||
</mat-list>
|
||||
@ -178,16 +229,6 @@
|
||||
</mat-action-row>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<!-- Previous Slides -->
|
||||
<mat-expansion-panel *ngIf="projector.elements_history.length" class="previous-slides">
|
||||
<mat-expansion-panel-header>
|
||||
<span translate>Previous slides</span>
|
||||
</mat-expansion-panel-header>
|
||||
<p *ngFor="let elements of projector.elements_history; let i = index">
|
||||
{{ i + 1 }}. {{ getSlideTitle(elements[0]) }}
|
||||
</p>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<!-- countdowns -->
|
||||
<mat-expansion-panel>
|
||||
<mat-expansion-panel-header>
|
||||
@ -287,14 +328,16 @@
|
||||
</mat-list>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<!-- File display controls -->
|
||||
<!--<mat-expansion-panel>
|
||||
<mat-expansion-panel *ngIf="projector.elements_history.length">
|
||||
<mat-expansion-panel-header>
|
||||
<span translate>Media controls</span>
|
||||
<span translate>Previous slides</span>
|
||||
</mat-expansion-panel-header>
|
||||
<os-presentation-control [projector]="projector">
|
||||
</os-presentation-control>
|
||||
</mat-expansion-panel>-->
|
||||
<ol>
|
||||
<li *ngFor="let elements of projector.elements_history">
|
||||
{{ getSlideTitle(elements[0]) }}
|
||||
</li>
|
||||
</ol>
|
||||
</mat-expansion-panel>
|
||||
|
||||
<os-presentation-control [projector]="projector"> </os-presentation-control>
|
||||
</mat-accordion>
|
||||
|
@ -1,8 +1,9 @@
|
||||
@import '~assets/styles/drag.scss';
|
||||
|
||||
#projector {
|
||||
width: 100%; /*1000px;*/
|
||||
border: 1px solid lightgrey;
|
||||
.projector-detail-wrapper {
|
||||
#projector {
|
||||
border: 1px solid lightgrey;
|
||||
}
|
||||
}
|
||||
|
||||
.column-left {
|
||||
@ -32,22 +33,29 @@
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.currentElement {
|
||||
.current-element {
|
||||
margin-bottom: 20px;
|
||||
box-shadow: 0px 3px 10px 0px rgba(0, 0, 0, 0.25);
|
||||
|
||||
.button-right {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
.emelent-grid {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
grid-gap: 5px;
|
||||
grid-template-columns: min-content 1fr min-content;
|
||||
.mat-icon-button {
|
||||
display: inherit;
|
||||
}
|
||||
.current-element-text {
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.queue,
|
||||
.previous-slides {
|
||||
.queue {
|
||||
box-shadow: none !important;
|
||||
background: none !important;
|
||||
margin-bottom: 20px;
|
||||
|
||||
.queue-element {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { timer } from 'rxjs';
|
||||
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { ProjectorService } from 'app/core/core-services/projector.service';
|
||||
import { CountdownRepositoryService } from 'app/core/repositories/projector/countdown-repository.service';
|
||||
import { ProjectorMessageRepositoryService } from 'app/core/repositories/projector/projector-message-repository.service';
|
||||
@ -16,6 +17,7 @@ import {
|
||||
ScrollScaleDirection
|
||||
} from 'app/core/repositories/projector/projector-repository.service';
|
||||
import { DurationService } from 'app/core/ui-services/duration.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { SizeObject } from 'app/shared/components/tile/tile.component';
|
||||
import { Countdown } from 'app/shared/models/core/countdown';
|
||||
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||
@ -92,7 +94,9 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni
|
||||
private currentListOfSpeakersSlideService: CurrentListOfSpeakersSlideService,
|
||||
private currentSpeakerChyronService: CurrentSpeakerChyronSlideService,
|
||||
private durationService: DurationService,
|
||||
private cd: ChangeDetectorRef
|
||||
private cd: ChangeDetectorRef,
|
||||
private promptService: PromptService,
|
||||
private opertator: OperatorService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
|
||||
@ -135,6 +139,32 @@ export class ProjectorDetailComponent extends BaseViewComponent implements OnIni
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler to set the current reference projector
|
||||
* TODO: same with projector list entry
|
||||
*/
|
||||
public onSetAsClosRef(): void {
|
||||
this.repo.setReferenceProjector(this.projector.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the delete Projector button
|
||||
* TODO: same with projector list entry
|
||||
*/
|
||||
public async onDeleteProjectorButton(): Promise<void> {
|
||||
const title = this.translate.instant('Are you sure you want to delete this projector?');
|
||||
if (await this.promptService.open(title, this.projector.name)) {
|
||||
this.repo.delete(this.projector).catch(this.raiseError);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns true if the operator can manage
|
||||
*/
|
||||
public canManage(): boolean {
|
||||
return this.opertator.hasPerms('core.can_manage_projector');
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the scroll
|
||||
*
|
||||
|
@ -8,18 +8,23 @@
|
||||
(click)="onSetAsClosRef()"
|
||||
matTooltip="{{ 'Sets this projector as the reference for the current list of speakers' | translate }}"
|
||||
>
|
||||
<mat-icon *ngIf="this.projector.isReferenceProjector">star</mat-icon>
|
||||
<mat-icon *ngIf="!this.projector.isReferenceProjector">star_border</mat-icon>
|
||||
<mat-icon *ngIf="projector.isReferenceProjector">star</mat-icon>
|
||||
<mat-icon *ngIf="!projector.isReferenceProjector">star_border</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button (click)="editProjector()" matTooltip="{{ 'Edit projector' | translate }}">
|
||||
<mat-icon>edit</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button color="warn" (click)="onDeleteButton()" matTooltip="{{ 'Delete projector' | translate }}">
|
||||
<button
|
||||
mat-icon-button
|
||||
color="warn"
|
||||
(click)="onDeleteButton()"
|
||||
matTooltip="{{ 'Delete projector' | translate }}"
|
||||
>
|
||||
<mat-icon>delete</mat-icon>
|
||||
</button>
|
||||
</ng-container>
|
||||
<ng-container class="meta-text-block-content">
|
||||
<a class="no-markup" [routerLink]="['/projectors/detail', projector.id]">
|
||||
<a class="no-markup" [routerLink]="getDetailLink()">
|
||||
<div class="projector">
|
||||
<os-projector [projector]="projector"></os-projector>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@ import { Title } from '@angular/platform-browser';
|
||||
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
|
||||
import { OperatorService } from 'app/core/core-services/operator.service';
|
||||
import { ProjectorRepositoryService } from 'app/core/repositories/projector/projector-repository.service';
|
||||
import { PromptService } from 'app/core/ui-services/prompt.service';
|
||||
import { largeDialogSettings } from 'app/shared/utils/dialog-settings';
|
||||
@ -54,7 +55,8 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
||||
matSnackBar: MatSnackBar,
|
||||
private repo: ProjectorRepositoryService,
|
||||
private promptService: PromptService,
|
||||
private dialogService: MatDialog
|
||||
private dialogService: MatDialog,
|
||||
private operator: OperatorService
|
||||
) {
|
||||
super(titleService, translate, matSnackBar);
|
||||
}
|
||||
@ -78,6 +80,19 @@ export class ProjectorListEntryComponent extends BaseViewComponent implements On
|
||||
this.repo.setReferenceProjector(this.projector.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the detail link by permission.
|
||||
* Without manage permission, the user should see the full screen projector
|
||||
* and not the detail view
|
||||
*/
|
||||
public getDetailLink(): string {
|
||||
if (this.operator.hasPerms('core.can_can_manage_projector')) {
|
||||
return `/projectors/detail/${this.projector.id}`;
|
||||
} else {
|
||||
return `/projector/${this.projector.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the projector.
|
||||
*/
|
||||
|
@ -13,7 +13,7 @@ const routes: Routes = [
|
||||
{
|
||||
path: 'detail/:id',
|
||||
component: ProjectorDetailComponent,
|
||||
data: { basePerm: 'core.can_see_projector' }
|
||||
data: { basePerm: 'core.can_can_manage_projector' }
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -7,6 +7,11 @@ export interface CommonListOfSpeakersSlideData {
|
||||
waiting?: SlideSpeaker[];
|
||||
current?: SlideSpeaker;
|
||||
finished?: SlideSpeaker[];
|
||||
title_information?: object;
|
||||
title_information?: {
|
||||
_agenda_item_number: string;
|
||||
agend_item_number: () => string;
|
||||
[key: string]: any;
|
||||
};
|
||||
content_object_collection?: string;
|
||||
closed?: boolean;
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
<div *ngIf="data">
|
||||
<div class="slidetitle">
|
||||
<h1 translate>List of speakers</h1>
|
||||
<h1 translate>
|
||||
List of speakers
|
||||
<mat-icon *ngIf="data.data.closed">lock</mat-icon>
|
||||
</h1>
|
||||
<h2>
|
||||
{{ getTitle() }}
|
||||
<span *ngIf="getSpeakersCount() > 0 && !hideAmountOfSpeakers">
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
import { CollectionStringMapperService } from 'app/core/core-services/collection-string-mapper.service';
|
||||
import { SlideData } from 'app/core/core-services/projector-data.service';
|
||||
import { isBaseIsAgendaItemContentObjectRepository } from 'app/core/repositories/base-is-agenda-item-content-object-repository';
|
||||
import { ConfigService } from 'app/core/ui-services/config.service';
|
||||
import { ProjectorElement } from 'app/shared/models/core/projector';
|
||||
import { BaseSlideComponent } from 'app/slides/base-slide-component';
|
||||
import { CommonListOfSpeakersSlideData } from './common-list-of-speakers-slide-data';
|
||||
|
||||
@ -13,6 +15,21 @@ import { CommonListOfSpeakersSlideData } from './common-list-of-speakers-slide-d
|
||||
})
|
||||
export class CommonListOfSpeakersSlideComponent extends BaseSlideComponent<CommonListOfSpeakersSlideData>
|
||||
implements OnInit {
|
||||
@Input()
|
||||
public set data(value: SlideData<CommonListOfSpeakersSlideData, ProjectorElement>) {
|
||||
// In the case of projected references without ListOfSpeakers Slide
|
||||
if (Object.entries(value.data).length) {
|
||||
value.data.title_information.agenda_item_number = () => value.data.title_information._agenda_item_number;
|
||||
this._data = value;
|
||||
}
|
||||
}
|
||||
|
||||
public get data(): SlideData<CommonListOfSpeakersSlideData, ProjectorElement> {
|
||||
return this._data;
|
||||
}
|
||||
|
||||
private _data: SlideData<CommonListOfSpeakersSlideData, ProjectorElement>;
|
||||
|
||||
/**
|
||||
* Boolean, whether the amount of speakers should be shown.
|
||||
*/
|
||||
|
@ -123,7 +123,7 @@ async def get_list_of_speakers_slide_data(
|
||||
list_of_speakers["content_object"]["id"]
|
||||
].get("agenda_item_id")
|
||||
if agenda_item_id:
|
||||
title_information["agenda_item_number"] = all_data["agenda/item"][
|
||||
title_information["_agenda_item_number"] = all_data["agenda/item"][
|
||||
agenda_item_id
|
||||
]["item_number"]
|
||||
|
||||
@ -169,6 +169,7 @@ async def get_list_of_speakers_slide_data(
|
||||
"finished": speakers_finished,
|
||||
"content_object_collection": list_of_speakers["content_object"]["collection"],
|
||||
"title_information": title_information,
|
||||
"closed": list_of_speakers["closed"],
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user