frontend: add auto-deletion policies selection when creating new rooms

This commit is contained in:
juancarmore 2025-09-03 12:22:51 +02:00
parent 87594dfe17
commit 0b3c0e9e42
5 changed files with 185 additions and 10 deletions

View File

@ -32,9 +32,16 @@
max-width: 600px;
min-height: 450px;
max-height: 450px;
overflow-y: auto;
display: flex;
flex-direction: column;
justify-content: center;
justify-content: flex-start;
}
.step-content > :first-child {
margin: auto 0;
width: 100%;
min-height: min-content;
}
.wizard-footer {

View File

@ -4,9 +4,7 @@
<mat-icon class="ov-room-icon step-icon">video_chat</mat-icon>
<div class="step-title-group">
<h3 class="step-title">Room Details</h3>
<p class="step-description">
Configure your room's details including name and automatic deletion date
</p>
<p class="step-description">Configure your room's details including name and automatic deletion date</p>
</div>
</header>
@ -59,8 +57,8 @@
<mat-hint>Optional. Room will be automatically deleted on this date and time.</mat-hint>
</mat-form-field>
@if (hasDateSelected) {
<!-- Time Selection (only shown when date is selected) -->
@if (roomDetailsForm.get('autoDeletionDate')?.value) {
<div class="time-selection-container">
<div class="time-selection-row">
<mat-form-field appearance="outline" class="time-field">
@ -89,6 +87,7 @@
<mat-icon matSuffix class="ov-settings-icon">access_time</mat-icon>
</mat-form-field>
</div>
@if (!roomDetailsForm.hasError('minFutureDateTime')) {
<div class="time-hint">
<mat-icon class="hint-icon material-symbols-outlined material-icons">auto_delete</mat-icon>
@ -97,6 +96,46 @@
} @else {
<mat-error> Deletion date and time must be at least one hour in the future </mat-error>
}
<!-- Auto-deletion Policies Section -->
<div class="auto-deletion-policies">
<h4 class="policies-title">
<mat-icon class="policies-icon">policy</mat-icon>
Auto-deletion Policies
</h4>
<p class="policies-description">
Configure how the room should be handled during auto-deletion if there are active meetings
or recordings.
</p>
<div class="policies-row">
<mat-form-field appearance="outline" class="policy-field">
<mat-label>With Active Meeting Policy</mat-label>
<mat-select formControlName="autoDeletionPolicyWithMeeting">
@for (option of meetingPolicyOptions; track option.value) {
<mat-option [value]="option.value">
{{ option.label }}
</mat-option>
}
</mat-select>
<mat-icon matSuffix class="ov-settings-icon">groups</mat-icon>
<mat-hint>{{ getMeetingPolicyDescription() }}</mat-hint>
</mat-form-field>
<mat-form-field appearance="outline" class="policy-field">
<mat-label>With Recordings Policy</mat-label>
<mat-select formControlName="autoDeletionPolicyWithRecordings">
@for (option of recordingPolicyOptions; track option.value) {
<mat-option [value]="option.value">
{{ option.label }}
</mat-option>
}
</mat-select>
<mat-icon matSuffix class="ov-settings-icon">video_library</mat-icon>
<mat-hint>{{ getRecordingPolicyDescription() }}</mat-hint>
</mat-form-field>
</div>
</div>
</div>
}
</form>

View File

@ -108,6 +108,51 @@
}
}
// Auto-deletion policies styling
.auto-deletion-policies {
margin-top: var(--ov-meet-spacing-lg);
.policies-title {
display: flex;
align-items: center;
gap: var(--ov-meet-spacing-xs);
margin: 0 0 var(--ov-meet-spacing-xs) 0;
font-size: var(--ov-meet-font-size-md);
font-weight: var(--ov-meet-font-weight-medium);
color: var(--ov-meet-text-primary);
.policies-icon {
@include ov-icon(sm);
color: var(--ov-meet-primary);
}
}
.policies-description {
margin: 0 0 var(--ov-meet-spacing-md) 0;
font-size: var(--ov-meet-font-size-sm);
color: var(--ov-meet-text-secondary);
line-height: var(--ov-meet-line-height-relaxed);
}
.policies-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: var(--ov-meet-spacing-md);
.policy-field {
width: 100%;
::ng-deep {
.mat-mdc-form-field-hint {
font-size: var(--ov-meet-font-size-xs);
color: var(--ov-meet-text-hint);
line-height: var(--ov-meet-line-height-tight);
}
}
}
}
}
.time-hint {
display: flex;
align-items: center;
@ -163,6 +208,13 @@
display: none; // Hide separator in mobile vertical layout
}
}
.auto-deletion-policies {
.policies-row {
grid-template-columns: 1fr;
gap: var(--ov-meet-spacing-sm);
}
}
}
}
}

View File

@ -9,7 +9,12 @@ import { MatInputModule } from '@angular/material/input';
import { MatSelectModule } from '@angular/material/select';
import { MatTooltipModule } from '@angular/material/tooltip';
import { RoomWizardStateService } from '@lib/services';
import { MeetRoomOptions } from '@lib/typings/ce';
import {
MeetRoomAutoDeletionPolicy,
MeetRoomDeletionPolicyWithMeeting,
MeetRoomDeletionPolicyWithRecordings,
MeetRoomOptions
} from '@lib/typings/ce';
import { Subject, takeUntil } from 'rxjs';
@Component({
@ -36,6 +41,32 @@ export class RoomWizardRoomDetailsComponent implements OnDestroy {
hours = Array.from({ length: 24 }, (_, i) => ({ value: i, display: i.toString().padStart(2, '0') }));
minutes = Array.from({ length: 60 }, (_, i) => ({ value: i, display: i.toString().padStart(2, '0') }));
meetingPolicyOptions = [
{
value: MeetRoomDeletionPolicyWithMeeting.FORCE,
label: 'Force',
description:
'The meeting will be ended, and the room will be deleted without waiting for participants to leave.'
},
{
value: MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
label: 'When meeting ends',
description: 'The room will be deleted when the meeting ends.'
}
];
recordingPolicyOptions = [
{
value: MeetRoomDeletionPolicyWithRecordings.FORCE,
label: 'Force',
description: 'The room and its recordings will be deleted.'
},
{
value: MeetRoomDeletionPolicyWithRecordings.CLOSE,
label: 'Close',
description: 'The room will be closed instead of deleted, maintaining its recordings.'
}
];
private destroy$ = new Subject<void>();
constructor(private wizardService: RoomWizardStateService) {
@ -54,20 +85,29 @@ export class RoomWizardRoomDetailsComponent implements OnDestroy {
private saveFormData(formValue: any) {
let autoDeletionDateTime: number | undefined = undefined;
let autoDeletionPolicy: MeetRoomAutoDeletionPolicy | undefined = undefined;
// If date is selected, combine it with time
// If date is selected
if (formValue.autoDeletionDate) {
// Combine date with time
const date = new Date(formValue.autoDeletionDate);
date.setHours(formValue.autoDeletionHour || 23);
date.setMinutes(formValue.autoDeletionMinute || 59);
date.setSeconds(0);
date.setMilliseconds(0);
autoDeletionDateTime = date.getTime();
// Set auto deletion policy
autoDeletionPolicy = {
withMeeting: formValue.autoDeletionPolicyWithMeeting,
withRecordings: formValue.autoDeletionPolicyWithRecordings
};
}
const stepData: Partial<MeetRoomOptions> = {
roomName: formValue.roomName,
autoDeletionDate: autoDeletionDateTime
autoDeletionDate: autoDeletionDateTime,
autoDeletionPolicy
};
// Always save to wizard state (including when values are cleared)
@ -115,4 +155,16 @@ export class RoomWizardRoomDetailsComponent implements OnDestroy {
autoDeletionMinute: 59
});
}
getMeetingPolicyDescription(): string {
const selectedValue = this.roomDetailsForm.get('autoDeletionPolicyWithMeeting')?.value;
const option = this.meetingPolicyOptions.find((opt) => opt.value === selectedValue);
return option?.description || '';
}
getRecordingPolicyDescription(): string {
const selectedValue = this.roomDetailsForm.get('autoDeletionPolicyWithRecordings')?.value;
const option = this.recordingPolicyOptions.find((opt) => opt.value === selectedValue);
return option?.description || '';
}
}

View File

@ -1,7 +1,13 @@
import { computed, Injectable, signal } from '@angular/core';
import { AbstractControl, FormBuilder, ValidationErrors, Validators } from '@angular/forms';
import { WizardNavigationConfig, WizardStep } from '@lib/models';
import { MeetRecordingAccess, MeetRoomOptions, MeetRoomPreferences } from '@lib/typings/ce';
import {
MeetRecordingAccess,
MeetRoomDeletionPolicyWithMeeting,
MeetRoomDeletionPolicyWithRecordings,
MeetRoomOptions,
MeetRoomPreferences
} from '@lib/typings/ce';
// Default room preferences following the app's defaults
const DEFAULT_PREFERENCES: MeetRoomPreferences = {
@ -101,6 +107,22 @@ export class RoomWizardStateService {
disabled: editMode
},
editMode ? [] : [Validators.min(0), Validators.max(59)]
],
autoDeletionPolicyWithMeeting: [
{
value:
initialRoomOptions.autoDeletionPolicy?.withMeeting ||
MeetRoomDeletionPolicyWithMeeting.WHEN_MEETING_ENDS,
disabled: editMode
}
],
autoDeletionPolicyWithRecordings: [
{
value:
initialRoomOptions.autoDeletionPolicy?.withRecordings ||
MeetRoomDeletionPolicyWithRecordings.CLOSE,
disabled: editMode
}
]
},
{
@ -204,6 +226,9 @@ export class RoomWizardStateService {
if ('autoDeletionDate' in stepData) {
updatedOptions.autoDeletionDate = stepData.autoDeletionDate;
}
if ('autoDeletionPolicy' in stepData) {
updatedOptions.autoDeletionPolicy = stepData.autoDeletionPolicy;
}
break;
case 'recording':