frontend: enhance loading state management in recordings components
This commit is contained in:
parent
f8729e4240
commit
5f289d12b8
@ -101,7 +101,7 @@ export class RecordingListsComponent implements OnInit, OnChanges {
|
||||
@Output() recordingAction = new EventEmitter<RecordingTableAction>();
|
||||
@Output() filterChange = new EventEmitter<{ nameFilter: string; statusFilter: string }>();
|
||||
@Output() loadMore = new EventEmitter<{ nameFilter: string; statusFilter: string }>();
|
||||
@Output() refresh = new EventEmitter<void>();
|
||||
@Output() refresh = new EventEmitter<{ nameFilter: string; statusFilter: string }>();
|
||||
|
||||
// Filter controls
|
||||
nameFilterControl = new FormControl('');
|
||||
@ -284,6 +284,12 @@ export class RecordingListsComponent implements OnInit, OnChanges {
|
||||
this.loadMore.emit({ nameFilter, statusFilter });
|
||||
}
|
||||
|
||||
refreshRecordings() {
|
||||
const nameFilter = this.nameFilterControl.value || '';
|
||||
const statusFilter = this.statusFilterControl.value || '';
|
||||
this.refresh.emit({ nameFilter, statusFilter });
|
||||
}
|
||||
|
||||
// ===== FILTER METHODS =====
|
||||
|
||||
hasActiveFilters(): boolean {
|
||||
|
||||
@ -1,24 +1,25 @@
|
||||
@if (isLoading) {
|
||||
@if (showLoadingSpinner) {
|
||||
<!-- Enhanced Loading State with delay -->
|
||||
<div class="ov-page-loading">
|
||||
<div class="loading-content">
|
||||
<div class="loading-header">
|
||||
<div class="loading-title">
|
||||
<mat-icon class="ov-recording-icon loading-icon">video_library</mat-icon>
|
||||
<h1>Loading Recordings</h1>
|
||||
</div>
|
||||
<p class="loading-subtitle">Please wait while we fetch your recordings...</p>
|
||||
<!-- Loading State -->
|
||||
@if (isInitializing && showInitialLoader) {
|
||||
<div class="ov-page-loading">
|
||||
<div class="loading-content">
|
||||
<div class="loading-header">
|
||||
<div class="loading-title">
|
||||
<mat-icon class="ov-recording-icon loading-icon">video_library</mat-icon>
|
||||
<h1>Loading Recordings</h1>
|
||||
</div>
|
||||
<p class="loading-subtitle">Please wait while we fetch your recordings...</p>
|
||||
</div>
|
||||
|
||||
<div class="loading-spinner-container">
|
||||
<mat-spinner diameter="48"></mat-spinner>
|
||||
</div>
|
||||
<div class="loading-spinner-container">
|
||||
<mat-spinner diameter="48"></mat-spinner>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
} @else {
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (!isInitializing) {
|
||||
<div class="ov-page-container ov-mb-xxl">
|
||||
<!-- Recordings Header -->
|
||||
<div class="page-header">
|
||||
<div class="title">
|
||||
<mat-icon class="ov-recording-icon">video_library</mat-icon>
|
||||
@ -27,6 +28,7 @@
|
||||
<p class="subtitle">Manage all your meeting recordings, play, download, and share them with others.</p>
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="page-content">
|
||||
<ov-recording-lists
|
||||
[recordings]="recordings()"
|
||||
@ -38,7 +40,7 @@
|
||||
[showLoadMore]="hasMoreRecordings"
|
||||
(recordingAction)="onRecordingAction($event)"
|
||||
(loadMore)="loadMoreRecordings($event)"
|
||||
(refresh)="refreshRecordings()"
|
||||
(refresh)="refreshRecordings($event)"
|
||||
(filterChange)="refreshRecordings($event)"
|
||||
>
|
||||
</ov-recording-lists>
|
||||
|
||||
@ -16,8 +16,11 @@ import { ILogger, LoggerService } from 'openvidu-components-angular';
|
||||
})
|
||||
export class RecordingsComponent implements OnInit {
|
||||
recordings = signal<MeetRecordingInfo[]>([]);
|
||||
|
||||
// Loading state
|
||||
isInitializing = true;
|
||||
showInitialLoader = false;
|
||||
isLoading = false;
|
||||
showLoadingSpinner = false;
|
||||
|
||||
// Pagination
|
||||
hasMoreRecordings = false;
|
||||
@ -36,6 +39,10 @@ export class RecordingsComponent implements OnInit {
|
||||
|
||||
async ngOnInit() {
|
||||
const roomId = this.route.snapshot.queryParamMap.get('room-id');
|
||||
const delayLoader = setTimeout(() => {
|
||||
this.showInitialLoader = true;
|
||||
}, 200);
|
||||
|
||||
if (roomId) {
|
||||
// If a specific room ID is provided, filter recordings by that room
|
||||
await this.loadRecordings({ nameFilter: roomId, statusFilter: '' });
|
||||
@ -43,6 +50,10 @@ export class RecordingsComponent implements OnInit {
|
||||
// Load all recordings if no room ID is specified
|
||||
await this.loadRecordings();
|
||||
}
|
||||
|
||||
clearTimeout(delayLoader);
|
||||
this.showInitialLoader = false;
|
||||
this.isInitializing = false;
|
||||
}
|
||||
|
||||
async onRecordingAction(action: RecordingTableAction) {
|
||||
@ -68,16 +79,15 @@ export class RecordingsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async loadRecordings(filters?: { nameFilter: string; statusFilter: string }) {
|
||||
this.isLoading = true;
|
||||
const delaySpinner = setTimeout(() => {
|
||||
this.showLoadingSpinner = true;
|
||||
private async loadRecordings(filters?: { nameFilter: string; statusFilter: string }, refresh = false) {
|
||||
const delayLoader = setTimeout(() => {
|
||||
this.isLoading = true;
|
||||
}, 200);
|
||||
|
||||
try {
|
||||
const recordingFilters: MeetRecordingFilters = {
|
||||
maxItems: 50,
|
||||
nextPageToken: this.nextPageToken
|
||||
nextPageToken: !refresh ? this.nextPageToken : undefined
|
||||
};
|
||||
|
||||
// Apply room ID filter if provided
|
||||
@ -93,9 +103,14 @@ export class RecordingsComponent implements OnInit {
|
||||
filteredRecordings = response.recordings.filter((r) => r.status === filters.statusFilter);
|
||||
}
|
||||
|
||||
// Update recordings list
|
||||
const currentRecordings = this.recordings();
|
||||
this.recordings.set([...currentRecordings, ...filteredRecordings]);
|
||||
if (!refresh) {
|
||||
// Update recordings list
|
||||
const currentRecordings = this.recordings();
|
||||
this.recordings.set([...currentRecordings, ...filteredRecordings]);
|
||||
} else {
|
||||
// Replace recordings list
|
||||
this.recordings.set(filteredRecordings);
|
||||
}
|
||||
|
||||
// Update pagination
|
||||
this.nextPageToken = response.pagination.nextPageToken;
|
||||
@ -104,9 +119,8 @@ export class RecordingsComponent implements OnInit {
|
||||
this.notificationService.showAlert('Failed to load recordings');
|
||||
this.log.e('Error loading recordings:', error);
|
||||
} finally {
|
||||
clearTimeout(delayLoader);
|
||||
this.isLoading = false;
|
||||
clearTimeout(delaySpinner);
|
||||
this.showLoadingSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,10 +130,7 @@ export class RecordingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async refreshRecordings(filters?: { nameFilter: string; statusFilter: string }) {
|
||||
this.recordings.set([]);
|
||||
this.nextPageToken = undefined;
|
||||
this.hasMoreRecordings = false;
|
||||
await this.loadRecordings(filters);
|
||||
await this.loadRecordings(filters, true);
|
||||
}
|
||||
|
||||
private async playRecording(recording: MeetRecordingInfo) {
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
@if (isLoading && showLoadingSpinner) {
|
||||
@if (isInitializing && showInitialLoader) {
|
||||
<div class="recordings-loading-container fade-in">
|
||||
<div class="loading-card">
|
||||
<mat-icon class="ov-recording-icon loading-icon">video_library</mat-icon>
|
||||
@ -35,7 +35,7 @@
|
||||
}
|
||||
|
||||
<!-- Content -->
|
||||
@if (!isLoading || recordings().length > 0) {
|
||||
@if (!isInitializing) {
|
||||
<div class="recordings-content fade-in-delayed">
|
||||
<div class="section-content">
|
||||
<ov-recording-lists
|
||||
@ -46,7 +46,9 @@
|
||||
[showFilters]="false"
|
||||
[showSelection]="true"
|
||||
[showRoomInfo]="false"
|
||||
[showLoadMore]="hasMoreRecordings"
|
||||
(recordingAction)="onRecordingAction($event)"
|
||||
(loadMore)="loadMoreRecordings()"
|
||||
(refresh)="refreshRecordings()"
|
||||
class="recordings-list"
|
||||
>
|
||||
|
||||
@ -22,8 +22,10 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
roomName = '';
|
||||
canDeleteRecordings = false;
|
||||
|
||||
// Loading state
|
||||
isInitializing = true;
|
||||
showInitialLoader = false;
|
||||
isLoading = false;
|
||||
showLoadingSpinner = false;
|
||||
|
||||
// Pagination
|
||||
hasMoreRecordings = false;
|
||||
@ -45,8 +47,18 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
async ngOnInit() {
|
||||
this.roomId = this.route.snapshot.paramMap.get('room-id')!;
|
||||
this.canDeleteRecordings = this.recordingService.canDeleteRecordings();
|
||||
|
||||
// Load recordings
|
||||
const delayLoader = setTimeout(() => {
|
||||
this.showInitialLoader = true;
|
||||
}, 200);
|
||||
|
||||
await this.loadRecordings();
|
||||
|
||||
clearTimeout(delayLoader);
|
||||
this.showInitialLoader = false;
|
||||
this.isInitializing = false;
|
||||
|
||||
// Set room name based on recordings or roomId
|
||||
if (this.recordings()) {
|
||||
this.roomName = this.recordings()[0].roomName;
|
||||
@ -89,17 +101,16 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private async loadRecordings(statusFilter?: string) {
|
||||
this.isLoading = true;
|
||||
const delaySpinner = setTimeout(() => {
|
||||
this.showLoadingSpinner = true;
|
||||
private async loadRecordings(statusFilter?: string, refresh = false) {
|
||||
const delayLoader = setTimeout(() => {
|
||||
this.isLoading = true;
|
||||
}, 200);
|
||||
|
||||
try {
|
||||
const recordingFilters: MeetRecordingFilters = {
|
||||
roomId: this.roomId,
|
||||
maxItems: 50,
|
||||
nextPageToken: this.nextPageToken
|
||||
nextPageToken: !refresh ? this.nextPageToken : undefined
|
||||
};
|
||||
|
||||
const response = await this.recordingService.listRecordings(recordingFilters);
|
||||
@ -110,9 +121,14 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
filteredRecordings = response.recordings.filter((r) => r.status === statusFilter);
|
||||
}
|
||||
|
||||
// Update recordings list
|
||||
const currentRecordings = this.recordings();
|
||||
this.recordings.set([...currentRecordings, ...filteredRecordings]);
|
||||
if (!refresh) {
|
||||
// Update recordings list
|
||||
const currentRecordings = this.recordings();
|
||||
this.recordings.set([...currentRecordings, ...filteredRecordings]);
|
||||
} else {
|
||||
// Replace recordings list
|
||||
this.recordings.set(filteredRecordings);
|
||||
}
|
||||
|
||||
// Update pagination
|
||||
this.nextPageToken = response.pagination.nextPageToken;
|
||||
@ -121,9 +137,8 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
this.notificationService.showAlert('Failed to load recordings');
|
||||
this.log.e('Error loading recordings:', error);
|
||||
} finally {
|
||||
clearTimeout(delayLoader);
|
||||
this.isLoading = false;
|
||||
clearTimeout(delaySpinner);
|
||||
this.showLoadingSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -133,10 +148,7 @@ export class RoomRecordingsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async refreshRecordings() {
|
||||
this.recordings.set([]);
|
||||
this.nextPageToken = undefined;
|
||||
this.hasMoreRecordings = false;
|
||||
await this.loadRecordings();
|
||||
await this.loadRecordings(undefined, true);
|
||||
}
|
||||
|
||||
private async playRecording(recording: MeetRecordingInfo) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user