Skip to content

Commit

Permalink
Feature: Add option to hide management page (#45)
Browse files Browse the repository at this point in the history
* add option to hide management page

Signed-off-by: Sebastian Kaupe <[email protected]>

* updates documentation and includes proper way to set daily default severity value

Signed-off-by: Sebastian Kaupe <[email protected]>

---------

Signed-off-by: Sebastian Kaupe <[email protected]>
  • Loading branch information
snkaupe authored Dec 12, 2024
1 parent c8b2e6b commit b5a6060
Show file tree
Hide file tree
Showing 14 changed files with 79 additions and 39 deletions.
13 changes: 8 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

This is the web UI for the SCS statuspage.

**This project is currently in the technical preview stage. Do not use in production.**

The status page is a simple web application that allows users to check if all services and components of a SCS installation are currently in a working state. Furthermore, it allows to read updates on ongoing and past incidents.

## Using the Status Page
Expand Down Expand Up @@ -73,7 +71,13 @@ You will find a configuration file named `config.json` in the `src/assets` direc
// Backup color in case an unmapped severity value has been found
"unknownColor": "lightsteelblue",
// A short text to be displayed above the components
"aboutText": "This is the status page for the SCS project. It displays incidents impacting any of the important components of this SCS stack."
"aboutText": "This is the status page for the SCS project. It displays incidents impacting any of the important components of this SCS stack.",
// Number of days to look into the future for maintenance events
"maintenancePreviewDays": 30,
// Hide the outdated management page
"hideManagementPage": true,
// Severity value used for days without incidents
"dayDefaultSeverity": 1
}
```

Expand Down Expand Up @@ -106,7 +110,7 @@ Once your environment has been set up, you have to create and customize the `con
"dexId": "status-page-web",
```

You will also have to modify the files of the KinD deployment itself as follows:
You will also have to modify the files of the KinD deployment itself as follows:

- `kubernetes/environments/kind/api/api.env`
- add `http://localhost:4200` to the `STATUS_PAGE_SERVER_ALLOWED_ORIGINS` variable, if not already in place.
Expand All @@ -124,4 +128,3 @@ To create a build, simply run `ng build` and check the resulting `dist` director
## HTML Prototype

The `html-prototype` directory contains a static HTML prototype for the page, based upon Mustache templates and incident data generated by a simple Python script. It gives an impression of how the site is supposed to look and handle once done.

28 changes: 15 additions & 13 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,21 @@ The SPA expects a configuration file called `config.json` to be present in the `

The following table explains all settings available in the configuration file. Explanations for non-basic field types can be found below the table.

| Configuration Key | Description | Type | Default |
| ---------------------- | ------------------------------------------------------------- | ------ | -------------------------------- |
| apiServerUrl | The URL of the API server supplying data. | String | empty |
| redirectUrl | URL you are being redirected to after Dex. | String | empty |
| dexUrl | The URL of your Dex server. | String | empty |
| dexId | ID your application uses for Dex. | String | empty |
| noOfDays | Number of days to display incidents for. | Number | 90 |
| dateFormat | The format to use for dates displayed. | Format | "YYYY-MM-DD HH:mm:ss z" |
| longDateFormat | Long format for dates, including day names. | Format | "dddd, Do MMMM YYYY, HH:mm:ss z" |
| severities | Maps severities to colors to use. | Object | see below |
| unknownColor | Color to use for unknown severity values. | Color | "lightsteelblue" |
| aboutText | Short text that appears in the "About" section. | String | empty |
| maintenancePreviewDays | Number of days in the future to check for maintenance events. | number | 30 |
| Configuration Key | Description | Type | Default |
| ---------------------- | ------------------------------------------------------------- | ------- | -------------------------------- |
| apiServerUrl | The URL of the API server supplying data. | String | empty |
| redirectUrl | URL you are being redirected to after Dex. | String | empty |
| dexUrl | The URL of your Dex server. | String | empty |
| dexId | ID your application uses for Dex. | String | empty |
| noOfDays | Number of days to display incidents for. | Number | 90 |
| dateFormat | The format to use for dates displayed. | Format | "YYYY-MM-DD HH:mm:ss z" |
| longDateFormat | Long format for dates, including day names. | Format | "dddd, Do MMMM YYYY, HH:mm:ss z" |
| severities | Maps severities to colors to use. | Object | see below |
| unknownColor | Color to use for unknown severity values. | Color | "lightsteelblue" |
| aboutText | Short text that appears in the "About" section. | String | empty |
| maintenancePreviewDays | Number of days in the future to check for maintenance events. | number | 30 |
| hideManagementPage | Makes the old management page inaccessible. | Boolean | true |
| dayDefaultSeverity | Severity value used for days where no incidents occured | Number | 1 |

The `severities` map contains one entry for each severity level specified in the API server. The default configuration included in the template file looks like this:

Expand Down
2 changes: 1 addition & 1 deletion src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const routes: Routes = [
component: IncidentDetailsViewComponent
},
{
path: "manage",
path: "manage",
component: ManagementViewComponent,
canActivate: [autoLoginPartialRoutesGuard]
},
Expand Down
6 changes: 5 additions & 1 deletion src/app/components/footer/footer.component.css
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,8 @@ a.auth-link {

span#user-info {
margin-right: 1.5rem;
}
}

span#user-info:last-child {
margin-right: 0;
}
2 changes: 1 addition & 1 deletion src/app/components/footer/footer.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@
<div id="admin-section">
<a class="auth-link" tabindex="0" (click)="login()" (keypress)="handleKeyPress($event)" *ngIf="!authenticated().isAuthenticated">Login</a>
<span id="user-info" *ngIf="authenticated().isAuthenticated">Logged in as {{ userData().userData ? userData().userData.name : "unknown" }}</span>
<a [routerLink]="['manage']" *ngIf="authenticated().isAuthenticated">Manage Incidents</a>
<a [routerLink]="['manage']" *ngIf="!config.hideManagementPage && authenticated().isAuthenticated">Manage Incidents</a>
</div>
</footer>
6 changes: 5 additions & 1 deletion src/app/components/footer/footer.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserSettingsService } from '../../services/user-settings.service';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { OidcSecurityService } from 'angular-auth-oidc-client';
import { AppConfigService } from '../../services/app-config.service';

@Component({
selector: 'app-footer',
Expand All @@ -18,7 +19,10 @@ export class FooterComponent {
protected readonly userData = this.oidcSecurityService.userData;
protected readonly authenticated = this.oidcSecurityService.authenticated;

constructor(public userSettings: UserSettingsService) {}
constructor(
public userSettings: UserSettingsService,
public config: AppConfigService
) {}

login(): void {
this.oidcSecurityService.authorize();
Expand Down
2 changes: 1 addition & 1 deletion src/app/model/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export type ImpactTypeId = string;
export type DayString = string;
export type ShortDayString = string;

export type Severity = number;
export type SeverityValue = number;

export const SHORT_DAY_FORMAT: string = "YYYY-MM-DD";
11 changes: 7 additions & 4 deletions src/app/model/daily-status.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import dayjs, { Dayjs } from "dayjs";
import { Impact, Incident } from "../../external/lib/status-page-api/angular-client";
import { IncidentId, SHORT_DAY_FORMAT, ShortDayString } from "./base";
import { IncidentId, SeverityValue, SHORT_DAY_FORMAT, ShortDayString } from "./base";

export class DailyStatus {

Expand All @@ -9,14 +9,17 @@ export class DailyStatus {
private _topLevelIncident?: [IncidentId, Incident] = undefined;
private _topLevelImpact?: Impact = undefined;

private _severity: number = 1;
private _severity: SeverityValue = 1;

constructor(day: ShortDayString | Dayjs) {
constructor(day: ShortDayString | Dayjs, defaultSeverity?: SeverityValue) {
if (day instanceof dayjs) {
this.day = day.format(SHORT_DAY_FORMAT);
} else {
this.day = <ShortDayString> day;
}
if (defaultSeverity) {
this._severity = defaultSeverity;
}
}

addIncident(incidentId: IncidentId, incident: Incident, impact: Impact) {
Expand All @@ -33,7 +36,7 @@ export class DailyStatus {
}
}

get overallSeverity(): number {
get overallSeverity(): SeverityValue {
return this._severity;
}

Expand Down
11 changes: 10 additions & 1 deletion src/app/pages/management-view/management-view.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Observable } from 'rxjs';
import { IconProviderService } from '../../services/icon-provider.service';
import { formatQueryDate } from '../../util/util';
import { ToastrService } from 'ngx-toastr';
import { AppConfigService } from '../../services/app-config.service';

const DT_FORMAT = "YYYY-MM-DDTHH:mm";

Expand Down Expand Up @@ -92,10 +93,18 @@ export class ManagementViewComponent implements OnInit{
private security: OidcSecurityService,
private router: Router,
private incidentService: IncidentService,
private toastr: ToastrService
private toastr: ToastrService,
private config: AppConfigService
) {}

async ngOnInit(): Promise<void> {
if (this.config.hideManagementPage) {
// Make management page inaccessible even when accessed using the URL directly.
// It would be better if we could remove the route entirely from the router, but
// my attempts to do so during service initialization have been unfruitful. It only
// results parts of the Router instance being undefined when needed.
this.router.navigate([""]);
}
this.security.checkAuth().subscribe(async response => {
if (!response.isAuthenticated) {
console.log(`Unauthenticated, potential error: ${response.errorMessage}`);
Expand Down
15 changes: 13 additions & 2 deletions src/app/services/app-config.service.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Inject, Injectable, InjectionToken } from '@angular/core';
import { SeverityValue } from '../model/base';

interface Severity {
start: number;
end: number;
start: SeverityValue;
end: SeverityValue;
color: string;
colorblind: string;
}
Expand All @@ -19,6 +20,8 @@ class Config {
unknownColor: string = "lightsteelblue";
aboutText: string = "";
maintenancePreviewDays: number = 30;
hideManagementPage: boolean = true;
dayDefaultSeverity: SeverityValue = 1;

constructor() {
this.severities.set("maintenance", {
Expand Down Expand Up @@ -105,6 +108,14 @@ export class AppConfigService {
get maintenancePreviewDays(): number {
return this.config.maintenancePreviewDays;
}

get hideManagementPage(): boolean {
return this.config.hideManagementPage;
}

get dayDefaultSeverity(): SeverityValue {
return this.config.dayDefaultSeverity;
}
}

export const CONFIG_JSON: InjectionToken<any> = new InjectionToken("CONFIG_JSON"); // eslint-disable-line @typescript-eslint/no-explicit-any
2 changes: 1 addition & 1 deletion src/app/services/data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ export class DataService {
this.components.forEach((component, componentId) => {
// Create daily data for each component
for (const [day, incidents] of this.incidentsByDay) {
const dailyData = new DailyStatus(day);
const dailyData = new DailyStatus(day, this.config.dayDefaultSeverity);
for (const incident of incidents) {
// Check if the incident affects this component
const affectingImpacts = incident[1].affects?.filter(c => c.reference === componentId) ?? [];
Expand Down
12 changes: 6 additions & 6 deletions src/app/services/util.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { DailyStatus } from '../model/daily-status';
import { UserSettingsService } from './user-settings.service';
import { Impact, Incident, IncidentUpdate } from '../../external/lib/status-page-api/angular-client';
import { DataService } from './data.service';
import { ComponentId, IncidentId, Severity, ShortDayString } from '../model/base';
import { ComponentId, IncidentId, SeverityValue, ShortDayString } from '../model/base';

@Injectable({
providedIn: 'root'
Expand All @@ -32,7 +32,7 @@ export class UtilService {
return dayjs(dt).format(this.config.longDateFormat);
}

severityName(severity: Severity): string {
severityName(severity: SeverityValue): string {
for (const s of this.config.severities.entries()) {
if (severity >= s[1].start && severity <= s[1].end) {
return s[0];
Expand All @@ -41,7 +41,7 @@ export class UtilService {
return "unknown";
}

severityColor(severity: Severity): string {
severityColor(severity: SeverityValue): string {
for (const s of this.config.severities.values()) {
if (severity >= s.start && severity <= s.end) {
if (this.userSettings.useColorblindColors) {
Expand All @@ -53,15 +53,15 @@ export class UtilService {
return this.config.unknownColor;
}

severityColorStyle(severity: Severity): string {
severityColorStyle(severity: SeverityValue): string {
return `color: ${this.severityColor(severity)}`;
}

currentDaySeverity(componentId: ComponentId): Severity {
currentDaySeverity(componentId: ComponentId): SeverityValue {
return this.severityForDay(componentId, this.dataService.currentDay);
}

severityForDay(componentId: ComponentId, date: ShortDayString): Severity {
severityForDay(componentId: ComponentId, date: ShortDayString): SeverityValue {
const currentDayStatus = this.dayState(componentId, date);
if (!currentDayStatus) {
console.error(`Missing DailyStatus object for day ${date}`);
Expand Down
4 changes: 3 additions & 1 deletion src/assets/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@
},
"unknownColor": "lightsteelblue",
"aboutText": "This is the status page for the SCS project. It displays incidents impacting any of the important components of this SCS stack.",
"maintenancePreviewDays": 30
"maintenancePreviewDays": 30,
"hideManagementPage": true,
"dayDefaultSeverity": 1
}
4 changes: 3 additions & 1 deletion src/assets/config.tmpl.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@
},
"unknownColor": "lightsteelblue",
"aboutText": "${STATUS_PAGE_WEB_ABOUT_TEXT}",
"maintenancePreviewDays": ${STATUS_PAGE_WEB_MAINTENANCE_PREVIEW_DAYS}
"maintenancePreviewDays": ${STATUS_PAGE_WEB_MAINTENANCE_PREVIEW_DAYS},
"hideManagementPage": true,
"dayDefaultSeverity": 1
}

0 comments on commit b5a6060

Please sign in to comment.