Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow to set PoO for others #3324

Merged
merged 13 commits into from
Feb 22, 2024
2 changes: 2 additions & 0 deletions client/src/app/domain/models/meetings/meeting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export class Settings {
public list_of_speakers_can_set_contribution_self!: boolean;
public list_of_speakers_speaker_note_for_everyone!: boolean;
public list_of_speakers_closing_disables_point_of_order!: boolean;
public list_of_speakers_can_create_point_of_order_for_others!: boolean;

public list_of_speakers_default_structure_level_time: number;
public list_of_speakers_enable_interposed_question: boolean;
Expand Down Expand Up @@ -338,6 +339,7 @@ export class Meeting extends BaseModel<Meeting> {
`list_of_speakers_show_first_contribution`,
`list_of_speakers_enable_point_of_order_speakers`,
`list_of_speakers_enable_point_of_order_categories`,
`list_of_speakers_can_create_point_of_order_for_others`,
`list_of_speakers_closing_disables_point_of_order`,
`list_of_speakers_enable_pro_contra_speech`,
`list_of_speakers_can_set_contribution_self`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,10 +305,14 @@ export class ListOfSpeakersContentComponent extends BaseMeetingComponent impleme
try {
const result = await firstValueFrom(dialogRef.afterClosed());
if (result) {
await this.speakerRepo.create(this.listOfSpeakers, this._currentUser!.id, {
pointOfOrder: true,
...result
});
await this.speakerRepo.create(
this.listOfSpeakers,
result.speaker ? result.speaker.userId : this._currentUser!.id,
{
pointOfOrder: true,
...result
}
);
}
} catch (e) {
this.raiseError(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ <h2 mat-dialog-title>
</h2>

<form class="edit-form" [formGroup]="editForm" (ngSubmit)="onOk()">
<!-- Search for speakers -->
<mat-dialog-content *ngIf="canManage && canSetPoOsForOthers">
<os-participant-search-selector
[nonSelectableUserIds]="nonAvailableUserIds"
[shouldReset]="false"
placeholder="{{ 'Select or search new speaker for point of order' | translate }}"
(userSelected)="selectUser($event)"
></os-participant-search-selector>
</mat-dialog-content>
<mat-dialog-content>
<mat-form-field *ngIf="showCategorySelect">
<mat-label>{{ 'Possible points of order' | translate }}</mat-label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,43 @@ import {
MatLegacyDialogRef as MatDialogRef
} from '@angular/material/legacy-dialog';
import { BehaviorSubject, combineLatest, map } from 'rxjs';
import { Permission } from 'src/app/domain/definitions/permission';
import { ViewListOfSpeakers, ViewPointOfOrderCategory } from 'src/app/site/pages/meetings/pages/agenda';
import { ActiveMeetingService } from 'src/app/site/pages/meetings/services/active-meeting.service';
import { MeetingSettingsService } from 'src/app/site/pages/meetings/services/meeting-settings.service';
import { ViewUser } from 'src/app/site/pages/meetings/view-models/view-user';
import { OperatorService } from 'src/app/site/services/operator.service';

import { UserSelectionData } from '../../../../../participant-search-selector';

@Component({
selector: `os-point-of-order-dialog`,
templateUrl: `./point-of-order-dialog.component.html`,
styleUrls: [`./point-of-order-dialog.component.scss`]
})
export class PointOfOrderDialogComponent {
/**
* To check permissions in templates using permission.[...]
*/
public readonly permission = Permission;

public get canManage(): boolean {
return this.operator.hasPerms(this.permission.listOfSpeakersCanManage);
}

public get canSetPoOsForOthers(): boolean {
return this.meetingSettingsService.instant(`list_of_speakers_can_create_point_of_order_for_others`) ?? false;
}

public users: ViewUser[] = [];
public nonAvailableUserIds: number[] = [];

public speaker: ViewUser;

private get onlyPresentUsers(): boolean {
return this.meetingSettingsService.instant(`list_of_speakers_present_users_only`) ?? false;
}

public editForm: UntypedFormGroup;

public readonly MAX_LENGTH = 80;
Expand All @@ -29,13 +56,17 @@ export class PointOfOrderDialogComponent {

private _showCategorySelect = false;

private _currentUser: ViewUser | null = null;

public constructor(
public readonly dialogRef: MatDialogRef<PointOfOrderDialogComponent>,
@Inject(MAT_DIALOG_DATA)
public readonly listOfSpeakers: ViewListOfSpeakers,
private fb: UntypedFormBuilder,
private meetingSettings: MeetingSettingsService,
private activeMeeting: ActiveMeetingService
private activeMeeting: ActiveMeetingService,
private operator: OperatorService,
private meetingSettingsService: MeetingSettingsService
) {
this.activeMeeting.meeting.point_of_order_categories_as_observable
.pipe(
Expand All @@ -50,9 +81,11 @@ export class PointOfOrderDialogComponent {

this.editForm = this.fb.group({
note: [``, [Validators.maxLength(this.MAX_LENGTH)]],
category: []
category: [],
speaker: []
});

this.operator.userObservable.subscribe(user => (this._currentUser = user));
combineLatest([
this.meetingSettings.get(`list_of_speakers_enable_point_of_order_categories`),
this.categoriesSubject
Expand All @@ -70,20 +103,43 @@ export class PointOfOrderDialogComponent {
this.editForm.updateValueAndValidity();
this._showCategorySelect = show;
});

this.filterNonAvailableUsers();
}

public onOk(): void {
if (!this.editForm.valid) {
return;
}
const note = this.editForm.value.note || undefined;
const speaker = this.editForm.value.speaker || undefined;
const point_of_order_category_id = this._showCategorySelect
? this.editForm.value.category || undefined
: undefined;
this.dialogRef.close({ note, point_of_order_category_id });
this.dialogRef.close({ note, point_of_order_category_id, speaker });
}

public onCancel(): void {
this.dialogRef.close();
}

/**
* Creates an array of users who currently shouldn't be selectable for the speaker list.
*/
private filterNonAvailableUsers() {
const nonAvailableUsers = this.users
.filter(user => !(!this.onlyPresentUsers || user?.isPresentInMeeting()))
.map(user => user?.id)
.filter(user => !!user);
this.nonAvailableUserIds = nonAvailableUsers;
}

public selectUser(data: UserSelectionData): UserSelectionData {
if (!data.userId) {
data.userId = this.operator.operatorId;
}
this.speaker = this.users.find(speaker => speaker.id === data.userId);
this.editForm.value.speaker = data;
return data;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { MatLegacyDialogModule as MatDialogModule } from '@angular/material/lega
import { MatSelectModule } from '@angular/material/select';
import { OpenSlidesTranslationModule } from 'src/app/site/modules/translations';

import { ParticipantSearchSelectorModule } from '../../../participant-search-selector';
import { PointOfOrderDialogComponent } from './components/point-of-order-dialog/point-of-order-dialog.component';

@NgModule({
Expand All @@ -20,7 +21,8 @@ import { PointOfOrderDialogComponent } from './components/point-of-order-dialog/
MatInputModule,
MatSelectModule,
ReactiveFormsModule,
OpenSlidesTranslationModule.forChild()
OpenSlidesTranslationModule.forChild(),
ParticipantSearchSelectorModule
]
})
export class PointOfOrderDialogModule {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@ import { infoDialogSettings } from 'src/app/infrastructure/utils/dialog-settings
import { ViewListOfSpeakers } from 'src/app/site/pages/meetings/pages/agenda';
import { BaseDialogService } from 'src/app/ui/base/base-dialog-service';

import { UserSelectionData } from '../../../../participant-search-selector';
import { PointOfOrderDialogComponent } from '../components/point-of-order-dialog/point-of-order-dialog.component';
import { PointOfOrderDialogModule } from '../point-of-order-dialog.module';

interface PointOfOrderResult {
note: string;
point_of_order_category_id: number;
speaker?: UserSelectionData;
}

@Injectable({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ export class ParticipantSearchSelectorComponent extends BaseUiComponent implemen
@Output()
public userSelected = new EventEmitter<UserSelectionData>();

@Input()
public shouldReset = true;

/**
* Subject that holds the currently selectable users.
*/
Expand Down Expand Up @@ -90,15 +93,17 @@ export class ParticipantSearchSelectorComponent extends BaseUiComponent implemen
public ngOnInit(): void {
this.userSortService.initSorting();
this.subscriptions.push(
// ovserve changes to the form
// observe changes to the form
this.usersForm.valueChanges.subscribe(async formResult => {
// resetting a form triggers a form.next(null) - check if user_id
if (formResult?.userId && typeof formResult?.userId === `number`) {
await this.processSelectedUser(formResult.userId);
this.usersForm.reset();
if (this.shouldReset) {
this.usersForm.reset();
}
}
}),
//The list should be updated when the participants have been edited
// The list should be updated when the participants have been edited
this.userRepo
.getSortedViewModelListObservable(this.userSortService.repositorySortingKey)
.subscribe(users => {
Expand Down Expand Up @@ -146,7 +151,9 @@ export class ParticipantSearchSelectorComponent extends BaseUiComponent implemen

private processSelectedUser(userId: number): void {
if (this._filteredUsersSubject.value.some(user => user.id === userId)) {
this.removeUserFromSelectorList(userId);
if (this.shouldReset) {
this.removeUserFromSelectorList(userId);
}
this.emitSelectedUser({ userId: userId });
} else {
throw new Error(`Tried to select an unselectable user`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,12 @@ export const meetingSettings: SettingsGroup[] = fillInSettingsDefaults([
label: _(`Enable interposed questions`),
type: `boolean`
},
{
key: `list_of_speakers_can_create_point_of_order_for_others`,
label: _(`Enable point of orders for other participants`),
helpText: _(`Requires permission to manage lists of speakers`),
type: `boolean`
},
{
key: `list_of_speakers_intervention_time`,
label: _(`Intervention speaking time in seconds`),
Expand Down
2 changes: 1 addition & 1 deletion client/src/meta
Submodule meta updated 1 files
+9 −0 models.yml