Skip to content

Commit 15d1ecc

Browse files
tanemluTanja Ulmen
andauthored
#408 Added List View to Progress Dashboard (hobbyfarm#231)
* moved ProgressComponent into subfolder renamed progressComponent into ProgressCardComponent * generated progress-list component with angular cli * added empty progress-list to sessions dashboard added dummy table * added table to end of the progress dashboard * added progress colour to table * ui changes to list-view * Added action button * progress info overlay enabled * added filter function * changed table structure * added view to settings * added clarity table, fixed colors, added service * changed sort fields * modifications for angular 17 --------- Co-authored-by: Tanja Ulmen <[email protected]>
1 parent 99d4202 commit 15d1ecc

20 files changed

+491
-81
lines changed

src/app/app.module.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@ import { AlertComponent } from './alert/alert.component';
4646
import { VmtemplatesComponent } from './configuration/vmtemplates/vmtemplates.component';
4747
import { EditVmtemplateComponent } from './configuration/vmtemplates/edit-vmtemplate/edit-vmtemplate.component';
4848
import { AppConfigService } from './app-config.service';
49-
import { ProgressComponent } from './progress/progress.component';
49+
import { ProgressCardComponent } from './progress/progress-card/progress-card.component';
50+
import { ProgressListComponent } from './progress/progress-list/progress-list.component';
5051
import { ProgressInfoComponent } from './progress/progress-info/progress-info.component';
5152
import { EventUserListComponent } from './dashboards/progress-dashboard/event-user-list/event-user-list.component';
5253
import { IntervalTimer } from './IntervalTimer/interval-timer.component';
@@ -169,6 +170,7 @@ import { TooltipDirective } from './directives/tooltip.directive';
169170
import { TooltipComponent } from './tooltip/tooltip.component';
170171
import { ScrollingModule } from '@angular/cdk/scrolling';
171172
import { AuthnService } from './data/authn.service';
173+
import { SessionProgressService } from './progress/session-progress.service';
172174

173175
ClarityIcons.addIcons(
174176
plusIcon,
@@ -268,7 +270,8 @@ export function jwtOptionsFactory(): JwtConfig {
268270
VmtemplatesComponent,
269271
EditVmtemplateComponent,
270272
ProgressInfoComponent,
271-
ProgressComponent,
273+
ProgressCardComponent,
274+
ProgressListComponent,
272275
EventUserListComponent,
273276
IntervalTimer,
274277
ProgressDashboardComponent,
@@ -360,6 +363,7 @@ export function jwtOptionsFactory(): JwtConfig {
360363
GargantuaClientFactory,
361364
AppConfigService,
362365
ProgressService,
366+
SessionProgressService,
363367
PredefinedServiceService,
364368
ThemeService,
365369
TypedSettingsService,

src/app/configuration/settings/settings.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
DEFAULT_ALERT_ERROR_DURATION,
1212
DEFAULT_ALERT_SUCCESS_DURATION,
1313
} from 'src/app/alert/alert';
14+
import { ProgressViewMode } from 'src/app/data/ProgressViewMode';
1415

1516
@Component({
1617
selector: 'app-settings',
@@ -28,6 +29,7 @@ export class SettingsComponent implements OnInit {
2829
scopesLoading = true;
2930

3031
readonly FormGroupType = FormGroupType; // Reference to TypedInputTypes enum for template use
32+
public progress_view_mode: ProgressViewMode = "cardView"
3133

3234
@ViewChild('alert') alert: AlertComponent;
3335

src/app/dashboards/progress-dashboard/progress-dashboard.component.html

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,37 @@
1919
>Whether finished sessions should be included.
2020
</clr-control-helper>
2121
</clr-toggle-container>
22+
<clr-radio-container id="selectViewToggle" clrInline>
23+
<clr-radio-wrapper>
24+
<input
25+
checked
26+
type="radio"
27+
clrRadio
28+
value="cardView"
29+
[formControl]="progressViewModeControl"
30+
/>
31+
<label>Card View</label>
32+
</clr-radio-wrapper>
33+
<clr-radio-wrapper>
34+
<input
35+
type="radio"
36+
clrRadio
37+
value="listView"
38+
[formControl]="progressViewModeControl"
39+
/>
40+
<label>List View</label>
41+
</clr-radio-wrapper>
42+
</clr-radio-container>
2243
<clr-toggle-container id="hideUsernamesToggle">
2344
<clr-toggle-wrapper>
2445
<input
2546
type="checkbox"
2647
clrToggle
2748
name="hideUsernames"
2849
[(ngModel)]="hide_usernames_status"
29-
(ngModelChange)="saveSettings($event)"
50+
(ngModelChange)="
51+
saveSettings({ hide_usernames_status: $event })
52+
"
3053
/>
3154
<label>Hide Usernames</label>
3255
</clr-toggle-wrapper>
@@ -109,24 +132,47 @@
109132
<interval-timer (intervalElapsed)="refresh()"></interval-timer>
110133
</div>
111134
</div>
112-
<div class="clr-row">
113-
@if (currentProgress.length > 0) {
114-
@for (p of filteredProgress; track p) {
115-
<div class="clr-col-12 clr-col-sm-6 clr-col-md-4 clr-col-lg-3">
116-
<progress-card
117-
[progress]="p"
118-
[pause]="pause"
119-
[hideUsername]="hide_usernames_status"
120-
(nameClickedEvent)="filterName($event)"
121-
></progress-card>
135+
@if (progressViewModeControl.value === "cardView") {
136+
<div class="clr-row">
137+
@if (currentProgress && currentProgress.length > 0) {
138+
@for (p of filteredProgress; track p) {
139+
<div class="clr-col-12 clr-col-sm-6 clr-col-md-4 clr-col-lg-3">
140+
<progress-card
141+
[progress]="p"
142+
[pause]="pause"
143+
[hideUsername]="hide_usernames_status"
144+
(nameClickedEvent)="filterName($event)"
145+
></progress-card>
146+
</div>
147+
}
148+
} @else {
149+
<div class="clr-col-12">
150+
<p>No sessions found.</p>
122151
</div>
123152
}
124-
} @else {
125-
<div class="clr-col-12">
126-
<p>No sessions found.</p>
127-
</div>
128-
}
129-
</div>
153+
</div>
154+
}
155+
@if (progressViewModeControl.value === "listView") {
156+
<div class="clr-row">
157+
<ng-container>
158+
@if (currentProgress && currentProgress.length > 0) {
159+
<div class="flex-container">
160+
<progress-list
161+
[progressList]="filteredProgress"
162+
[pause]="pause"
163+
[hideUsername]="hide_usernames_status"
164+
(nameClickedEvent)="filterName($event)"
165+
>
166+
</progress-list>
167+
</div>
168+
} @else {
169+
<div class="clr-col-12">
170+
<p>No sessions found.</p>
171+
</div>
172+
}
173+
</ng-container>
174+
</div>
175+
}
130176
</div>
131177

132178
<event-user-list

src/app/dashboards/progress-dashboard/progress-dashboard.component.scss

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,11 @@ svg circle {
120120
stroke: red;
121121
}
122122
}
123+
124+
.flex-container {
125+
display: flex;
126+
width: 100%;
127+
flex-direction: column;
128+
margin-top: 20px;
129+
}
130+

src/app/dashboards/progress-dashboard/progress-dashboard.component.ts

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import { ScenarioService } from '../../data/scenario.service';
88
import { CourseService } from '../../data/course.service';
99
import { EventUserListComponent } from './event-user-list/event-user-list.component';
1010
import { JwtHelperService } from '@auth0/angular-jwt';
11-
import { combineLatest, Subject, takeUntil } from 'rxjs';
11+
import { combineLatest, distinctUntilChanged, Subject, takeUntil } from 'rxjs';
1212
import { User } from '../../data/user';
1313
import { Settings, SettingsService } from 'src/app/data/settings.service';
14-
import { FormGroup } from '@angular/forms';
14+
import { FormControl, FormGroup } from '@angular/forms';
1515

1616
@Component({
1717
selector: 'progress-dashboard',
1818
templateUrl: './progress-dashboard.component.html',
1919
styleUrls: ['./progress-dashboard.component.scss'],
2020
})
21+
2122
export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges {
2223
@Input()
2324
selectedEvent: ScheduledEventBase;
@@ -30,6 +31,7 @@ export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges
3031
public users: User[] = [];
3132
public settingsForm: FormGroup;
3233
public hide_usernames_status: boolean = false;
34+
public progressViewModeControl = new FormControl<'cardView' | 'listView'>('cardView');
3335
private settings_service$ = new Subject<Readonly<Settings>>();
3436

3537
public pauseCall: boolean = false; // Stop refreshing if we are looking at a progress
@@ -53,7 +55,7 @@ export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges
5355
public progressService: ProgressService,
5456
public scheduledeventService: ScheduledeventService,
5557
public helper: JwtHelperService,
56-
public settingsService: SettingsService
58+
public settingsService: SettingsService,
5759
) {}
5860

5961
ngOnInit() {
@@ -63,13 +65,25 @@ export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges
6365
.subscribe(
6466
({
6567
hide_usernames_status = false,
68+
progress_view_mode = 'cardView'
6669
}) => {
6770
this.settingsForm.patchValue({
68-
hide_usernames_status
71+
hide_usernames_status,
72+
progress_view_mode
6973
});
7074
this.hide_usernames_status = this.settingsForm.get('hide_usernames_status')?.value
75+
this.progressViewModeControl.setValue(this.settingsForm.get('progress_view_mode')?.value)
7176
},
7277
);
78+
this.progressViewModeControl.valueChanges
79+
.pipe(distinctUntilChanged())
80+
.subscribe((value) => {
81+
if (value === 'cardView') {
82+
this.setCardView();
83+
} else if (value === 'listView') {
84+
this.setListView();
85+
}
86+
});
7387
this.refresh();
7488
}
7589

@@ -121,6 +135,17 @@ export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges
121135
this.filter();
122136
}
123137

138+
setCardView() {
139+
//this.progressViewModeService.setCardView();
140+
this.saveSettings({ progress_view_mode: 'cardView' })
141+
}
142+
143+
setListView() {
144+
//this.progressViewModeService.setListView();
145+
this.saveSettings({ progress_view_mode: 'listView' })
146+
147+
}
148+
124149
openUserList() {
125150
this.userList.openModal();
126151
}
@@ -171,16 +196,15 @@ export class ProgressDashboardComponent implements OnInit, OnDestroy, OnChanges
171196
});
172197
}
173198

174-
saveSettings(newHideUsernamesStatus: boolean) {
199+
saveSettings(update: Partial<Settings>) {
175200
if (this.settingsForm.value) {
176-
this.settingsService.update({hide_usernames_status: newHideUsernamesStatus}).subscribe({
201+
this.settingsService.update(update).subscribe({
177202
next: () => {
178-
console.log('Saved Settings.');
179203
},
180204
error: (err) => {
181205
console.error('Error while saving settings:', err);
182-
}
183-
})
206+
},
207+
});
184208
}
185209
}
186210

src/app/data/ProgressViewMode.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type ProgressViewMode = 'cardView' | 'listView';

src/app/data/forms.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
FormControl,
55
FormGroup,
66
} from '@angular/forms';
7+
import { ProgressViewMode } from './ProgressViewMode';
78

89
export type ChartDetailsFormGroup = FormGroup<{
910
observationPeriod: FormControl<'daily' | 'weekly' | 'monthly'>;
@@ -71,6 +72,7 @@ export type SettingFormGroup = FormGroup<{
7172
>;
7273
hide_usernames_status: FormControl<boolean>;
7374
theme: FormControl<'dark' | 'light' | 'system'>;
75+
progress_view_mode: FormControl<ProgressViewMode>;
7476
}>;
7577

7678
// This object type maps VMTemplate names to the number of requested VMs
@@ -188,10 +190,14 @@ export function isChartDetailsFormGroup(
188190
return (
189191
formGroup instanceof FormGroup &&
190192
formGroup.controls.observationPeriod instanceof FormControl &&
191-
['daily', 'weekly', 'monthly'].includes(formGroup.controls.observationPeriod.value) &&
193+
['daily', 'weekly', 'monthly'].includes(
194+
formGroup.controls.observationPeriod.value,
195+
) &&
192196
formGroup.controls.scenarios instanceof FormControl &&
193197
Array.isArray(formGroup.controls.scenarios.value) &&
194-
formGroup.controls.scenarios.value.every((item) => typeof item === 'string') &&
198+
formGroup.controls.scenarios.value.every(
199+
(item) => typeof item === 'string',
200+
) &&
195201
formGroup.controls.startDate instanceof FormControl &&
196202
typeof formGroup.controls.startDate.value === 'string' &&
197203
formGroup.controls.endDate instanceof FormControl &&
@@ -200,7 +206,7 @@ export function isChartDetailsFormGroup(
200206
}
201207

202208
export function isGenericFormControl(
203-
control: AbstractControl
209+
control: AbstractControl,
204210
): control is GenericFormControl {
205211
return (
206212
control instanceof FormControl &&
@@ -210,17 +216,15 @@ export function isGenericFormControl(
210216
);
211217
}
212218

213-
export function isGenericFormArray(
214-
control: any
215-
): control is GenericFormArray {
219+
export function isGenericFormArray(control: any): control is GenericFormArray {
216220
return (
217221
control instanceof FormArray &&
218222
control.controls.every(
219223
(ctrl) =>
220224
ctrl instanceof FormControl &&
221225
(typeof ctrl.value === 'string' ||
222226
typeof ctrl.value === 'number' ||
223-
typeof ctrl.value === 'boolean')
227+
typeof ctrl.value === 'boolean'),
224228
)
225229
);
226230
}

src/app/data/settings.service.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Injectable } from '@angular/core';
22
import { HttpErrorResponse, HttpParams } from '@angular/common/http';
3+
import { ProgressViewMode } from './ProgressViewMode';
34
import { Subject, concat, throwError } from 'rxjs';
45
import {
56
catchError,
@@ -21,6 +22,7 @@ export interface Settings {
2122
terminal_theme: (typeof themes)[number]['id'];
2223
hide_usernames_status: boolean;
2324
theme: 'dark' | 'light' | 'system';
25+
progress_view_mode: ProgressViewMode;
2426
}
2527

2628
/**
@@ -40,8 +42,15 @@ export class SettingsService {
4042
validators: [Validators.required],
4143
nonNullable: true,
4244
}),
43-
hide_usernames_status: new FormControl<boolean>(false, {nonNullable: true}),
44-
theme: new FormControl<'dark' | 'light' | 'system'>('system', {nonNullable: true}),
45+
hide_usernames_status: new FormControl<boolean>(false, {
46+
nonNullable: true,
47+
}),
48+
progress_view_mode: new FormControl<ProgressViewMode>('cardView', {
49+
nonNullable: true,
50+
}),
51+
theme: new FormControl<'dark' | 'light' | 'system'>('system', {
52+
nonNullable: true,
53+
}),
4554
});
4655

4756
fetch() {
@@ -54,6 +63,7 @@ export class SettingsService {
5463
terminal_theme: themes[0].id,
5564
hide_usernames_status: false,
5665
theme: 'system',
66+
progress_view_mode: 'cardView',
5767
} as Settings),
5868
),
5969
tap((s: Settings) => {

0 commit comments

Comments
 (0)