Skip to content

Commit

Permalink
feat(admin): instance config
Browse files Browse the repository at this point in the history
  • Loading branch information
esoadamo committed Aug 29, 2024
1 parent 0abadb3 commit f649cbd
Show file tree
Hide file tree
Showing 19 changed files with 317 additions and 10 deletions.
101 changes: 101 additions & 0 deletions src/api/backend/api/default.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { AchievementGrantRequest } from '../model/achievementGrantRequest';
import { AchievementGrantResponse } from '../model/achievementGrantResponse';
import { AchievementResponse } from '../model/achievementResponse';
import { AchievementsResponse } from '../model/achievementsResponse';
import { AdminInstanceConfig } from '../model/adminInstanceConfig';
import { AdminInstanceConfigResponse } from '../model/adminInstanceConfigResponse';
import { AdminTaskCreationRequest } from '../model/adminTaskCreationRequest';
import { AdminTaskDeployResponse } from '../model/adminTaskDeployResponse';
import { AdminTaskMergeResponse } from '../model/adminTaskMergeResponse';
Expand Down Expand Up @@ -2969,6 +2971,105 @@ export class DefaultService {
);
}

/**
*
*
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public instanceConfigGetAll(observe?: 'body', reportProgress?: boolean): Observable<AdminInstanceConfigResponse>;
public instanceConfigGetAll(observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<AdminInstanceConfigResponse>>;
public instanceConfigGetAll(observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<AdminInstanceConfigResponse>>;
public instanceConfigGetAll(observe: any = 'body', reportProgress: boolean = false ): Observable<any> {

let headers = this.defaultHeaders;

// authentication (ksi) required
if (this.configuration.accessToken) {
const accessToken = typeof this.configuration.accessToken === 'function'
? this.configuration.accessToken()
: this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}

// to determine the Accept header
let httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}

// to determine the Content-Type header
const consumes: string[] = [
];

return this.httpClient.request<AdminInstanceConfigResponse>('get',`${this.basePath}/admin/instanceConfig`,
{
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}

/**
*
*
* @param body
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public instanceConfigSetSingle(body: AdminInstanceConfig, observe?: 'body', reportProgress?: boolean): Observable<string>;
public instanceConfigSetSingle(body: AdminInstanceConfig, observe?: 'response', reportProgress?: boolean): Observable<HttpResponse<string>>;
public instanceConfigSetSingle(body: AdminInstanceConfig, observe?: 'events', reportProgress?: boolean): Observable<HttpEvent<string>>;
public instanceConfigSetSingle(body: AdminInstanceConfig, observe: any = 'body', reportProgress: boolean = false ): Observable<any> {

if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling instanceConfigSetSingle.');
}

let headers = this.defaultHeaders;

// authentication (ksi) required
if (this.configuration.accessToken) {
const accessToken = typeof this.configuration.accessToken === 'function'
? this.configuration.accessToken()
: this.configuration.accessToken;
headers = headers.set('Authorization', 'Bearer ' + accessToken);
}

// to determine the Accept header
let httpHeaderAccepts: string[] = [
'application/json'
];
const httpHeaderAcceptSelected: string | undefined = this.configuration.selectHeaderAccept(httpHeaderAccepts);
if (httpHeaderAcceptSelected != undefined) {
headers = headers.set('Accept', httpHeaderAcceptSelected);
}

// to determine the Content-Type header
const consumes: string[] = [
'application/json'
];
const httpContentTypeSelected: string | undefined = this.configuration.selectHeaderContentType(consumes);
if (httpContentTypeSelected != undefined) {
headers = headers.set('Content-Type', httpContentTypeSelected);
}

return this.httpClient.request<string>('post',`${this.basePath}/admin/instanceConfig`,
{
body: body,
withCredentials: this.configuration.withCredentials,
headers: headers,
observe: observe,
reportProgress: reportProgress
}
);
}

/**
*
*
Expand Down
16 changes: 16 additions & 0 deletions src/api/backend/model/adminInstanceConfig.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* web-backend-swagger
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/

export interface AdminInstanceConfig {
key: string;
value: string;
}
16 changes: 16 additions & 0 deletions src/api/backend/model/adminInstanceConfigResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* web-backend-swagger
* No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen)
*
* OpenAPI spec version: 1.0.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { AdminInstanceConfig } from './adminInstanceConfig';

export interface AdminInstanceConfigResponse {
config: Array<AdminInstanceConfig>;
}
2 changes: 2 additions & 0 deletions src/api/backend/model/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export * from './achievementGrantRequest';
export * from './achievementGrantResponse';
export * from './achievementResponse';
export * from './achievementsResponse';
export * from './adminInstanceConfig';
export * from './adminInstanceConfigResponse';
export * from './adminTask';
export * from './adminTaskCreation';
export * from './adminTaskCreationRequest';
Expand Down
2 changes: 2 additions & 0 deletions src/app/components/admin/admin-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { PageAdminMonitorComponent } from './page-admin-monitor/page-admin-monit
import { PageAdminEmailComponent } from './page-admin-email/page-admin-email.component';
import {PageAdminDiscussionComponent} from './page-admin-discussion/page-admin-discussion.component';
import {PageAdminAchievementsComponent} from './page-admin-achievements/page-admin-achievements.component';
import {PageAdminInstanceConfigComponent} from './page-admin-instance-config/page-admin-instance-config.component';

const routes: Routes = [
{path: '', component: PageAdminRootComponent},
Expand All @@ -15,6 +16,7 @@ const routes: Routes = [
{path: ROUTES.admin.email, component: PageAdminEmailComponent},
{path: ROUTES.admin.discussion, component: PageAdminDiscussionComponent},
{path: ROUTES.admin.achievements, component: PageAdminAchievementsComponent},
{path: ROUTES.admin.instanceConfig, component: PageAdminInstanceConfigComponent},
];

@NgModule({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
<a class="nav-btn" [routerLink]="['/', routes.routes.admin._, routes.routes.admin.achievements]" routerLinkActive="active" (click)="hideFullMenu($event)">
{{'admin.navbar.achievement' | translate}}
</a>
<a *ngIf="userService.isAdmin$ | async" class="nav-btn" [routerLink]="['/', routes.routes.admin._, routes.routes.admin.instanceConfig]" routerLinkActive="active" (click)="hideFullMenu($event)">
{{'admin.navbar.instance-config' | translate}}
</a>
<ng-container *ngIf="oldFrontendUrl">
<a *ngFor="let oldLink of oldFrontendButtons"
class="nav-btn"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class AdminSidebarComponent implements OnInit, OnDestroy {

constructor(
public routes: RoutesService,
private userService: UserService,
public userService: UserService,
private router: Router,
public window: WindowService,
public icon: IconService
Expand Down
9 changes: 6 additions & 3 deletions src/app/components/admin/admin.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import { SharedModule } from '../shared/shared.module';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { PageAdminEmailComponent } from './page-admin-email/page-admin-email.component';
import { QuillModule } from 'ngx-quill';
import { ReactiveFormsModule } from '@angular/forms';
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
import { AccordionModule } from 'ngx-bootstrap/accordion';
import { PageAdminDiscussionComponent } from './page-admin-discussion/page-admin-discussion.component';
import { AdminWaveSelectorComponent } from './shared/admin-wave-selector/admin-wave-selector.component';
import { PageAdminAchievementsComponent } from './page-admin-achievements/page-admin-achievements.component';
import { PageAdminInstanceConfigComponent } from './page-admin-instance-config/page-admin-instance-config.component';


@NgModule({
Expand All @@ -29,7 +30,8 @@ import { PageAdminAchievementsComponent } from './page-admin-achievements/page-a
PageAdminEmailComponent,
PageAdminDiscussionComponent,
AdminWaveSelectorComponent,
PageAdminAchievementsComponent
PageAdminAchievementsComponent,
PageAdminInstanceConfigComponent
],
imports: [
CommonModule,
Expand All @@ -39,7 +41,8 @@ import { PageAdminAchievementsComponent } from './page-admin-achievements/page-a
TooltipModule,
QuillModule,
ReactiveFormsModule,
AccordionModule
AccordionModule,
FormsModule
]
})
export class AdminModule { }
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<ksi-admin-sidebar></ksi-admin-sidebar>
<div class="content-container">
<div class="content">
<h2 class="title">{{'admin.instance-config.title'|translate}}</h2>

<table class="table table-striped table-responsive-md tasks-table" ksiTheme>
<thead>
<tr class="table-head-row">
<th scope="col">{{'admin.instance-config.key' | translate}}</th>
<th scope="col">{{'admin.instance-config.value' | translate}}</th>
<th scope="col">{{'admin.instance-config.actions' | translate}}</th>
</tr>
</thead>
<tbody>
<tr *ngFor="let config of (config$ | async)">
<td>{{config.key}}</td>
<td>
<span *ngIf="config.value">
{{config.value}}
</span>
<span *ngIf="!config.value">
<i>{{'admin.instance-config.null-value' | translate}}</i>
</span>
</td>
<td>
<button class="btn btn-outline-primary" (click)="editConfig(config)">{{'admin.instance-config.edit' | translate}}</button>
</td>
</tbody>
</table>
</div>
</div>

<ng-template #modalEditConfig>
<form class="form" *ngIf="editedConfig">
<div class="form-group">
<label for="key">{{'admin.instance-config.key' | translate}}</label>
<input type="text" class="form-control" id="key" name="key" [(ngModel)]="editedConfig.key" disabled>
</div>
<div class="form-group">
<label for="value">{{'admin.instance-config.value' | translate}}</label>
<input type="text" class="form-control" id="value" name="value" [(ngModel)]="editedConfig.value">
</div>
<button [disabled]="!editedConfig" type="submit" class="btn btn-primary" (click)="saveConfig(editedConfig)">{{'admin.instance-config.save' | translate}}</button>
</form>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@import "src/app/styles/vars";
@import "src/app/styles/mixins";

@include page-admin;

:host {
.content {
justify-self: center;

> .title {
margin: $ksi-margin;
text-align: center;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { PageAdminInstanceConfigComponent } from './page-admin-instance-config.component';

describe('PageAdminInstanceConfigComponent', () => {
let component: PageAdminInstanceConfigComponent;
let fixture: ComponentFixture<PageAdminInstanceConfigComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PageAdminInstanceConfigComponent ]
})
.compileComponents();
});

beforeEach(() => {
fixture = TestBed.createComponent(PageAdminInstanceConfigComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import {Component, OnInit, ChangeDetectionStrategy, ViewChild, TemplateRef} from '@angular/core';
import {BackendService, KsiTitleService, ModalService} from '../../../services';
import {BehaviorSubject, Subject} from 'rxjs';
import {AdminInstanceConfig} from '../../../../api/backend';
import {OpenedTemplate} from '../../../models';

@Component({
selector: 'ksi-page-admin-instance-config',
templateUrl: './page-admin-instance-config.component.html',
styleUrls: ['./page-admin-instance-config.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class PageAdminInstanceConfigComponent implements OnInit {
private configSubject: Subject<AdminInstanceConfig[]> = new BehaviorSubject(([] as AdminInstanceConfig[]));
config$ = this.configSubject.asObservable();

editedConfig: AdminInstanceConfig | null = null;
@ViewChild('modalEditConfig', {static: true})
modalEditConfig: TemplateRef<unknown>;
modalEditConfigInstance: OpenedTemplate | null = null;

constructor(
private title: KsiTitleService,
private backend: BackendService,
private modal: ModalService
) { }

ngOnInit(): void {
this.title.subtitle = 'admin.root.instance-config.title';
this.refreshConfig();
}

private refreshConfig(): void {
this.backend.http.instanceConfigGetAll().subscribe((response) => {
this.configSubject.next(response.config);
});
}

editConfig(config: AdminInstanceConfig): void {
this.editedConfig = config;
this.modalEditConfigInstance = this.modal.showModalTemplate(this.modalEditConfig, 'admin.root.instance-config.edit-config');
}

saveConfig(editedConfig: AdminInstanceConfig | null): void {
if (editedConfig) {
this.editedConfig = null;
this.backend.http.instanceConfigSetSingle(editedConfig).subscribe(() => {
this.refreshConfig();
this.modalEditConfigInstance?.template.instance.close();
this.modalEditConfigInstance = null;
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,13 @@ export class AdminSectionCardComponent implements OnInit {
}

ngOnInit(): void {

// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
this.relativeUrl = ROUTES.admin[this.name];
this.relativeUrl = ROUTES.admin[this.toCamelCase(this.name)];
}

private toCamelCase(str: string): string {
return str.replace(/-./g, match => match.charAt(1).toUpperCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ <h2 class="title">{{'admin.root.title'|translate}}</h2>
<ksi-admin-section-card name="email"></ksi-admin-section-card>
<ksi-admin-section-card name="discussion"></ksi-admin-section-card>
<ksi-admin-section-card name="achievements"></ksi-admin-section-card>
<ksi-admin-section-card name="instance-config" *ngIf="userService.isAdmin$ | async"></ksi-admin-section-card>
</div>
</div>
</div>
Loading

0 comments on commit f649cbd

Please sign in to comment.