Skip to content

Commit

Permalink
feat(plugin-store): Make Plugins editable
Browse files Browse the repository at this point in the history
  • Loading branch information
ewuerger committed Aug 25, 2023
1 parent e43a007 commit dea2e67
Show file tree
Hide file tree
Showing 19 changed files with 460 additions and 10 deletions.
30 changes: 28 additions & 2 deletions frontend/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { NgModule } from '@angular/core';
import { Data, RouterModule, Routes } from '@angular/router';
import { CreatePluginComponent } from 'src/app/plugins/store/create-plugin/create-plugin.component';
import { PluginStoreOverviewComponent } from 'src/app/plugins/store/plugin-store-overview/plugin-store-overview.component';
import { PluginWrapperComponent } from './plugins/store/plugin-wrapper/plugin-wrapper.component';
import { PluginDetailsComponent } from './plugins/store/plugin-detail/plugin-details.component';
import { JobRunOverviewComponent } from 'src/app/projects/models/backup-settings/job-run-overview/job-run-overview.component';
import { PipelineRunWrapperComponent } from 'src/app/projects/models/backup-settings/pipeline-runs/wrapper/pipeline-run-wrapper/pipeline-run-wrapper.component';
import { ViewLogsDialogComponent } from 'src/app/projects/models/backup-settings/view-logs-dialog/view-logs-dialog.component';
Expand Down Expand Up @@ -74,11 +76,11 @@ const routes: Routes = [
},
{
path: 'plugins',
data: { breadcrumb: 'Plugins' },
data: { breadcrumb: 'Plugins', redirect: '/plugins' },
children: [
{
path: '',
data: { breadcrumb: undefined },
data: { breadcrumb: "overview" },
component: PluginStoreOverviewComponent,
},
{
Expand All @@ -88,6 +90,30 @@ const routes: Routes = [
},
],
},
{
path: 'plugin',
data: { breadcrumb: 'Plugins', redirect: '/plugins' },
children: [
{
path: ':plugin',
data: {
breadcrumb: (data: Data) => data.plugin?.content.metadata.displayName,
redirect: (data: Data) => `/plugin/${data.plugin?.id}`,
},
component: PluginWrapperComponent,
children: [
{
path: '',
data: {
breadcrumb: 'details',
redirect: (data: Data) => `/plugin/${data.plugin?.id}`,
},
component: PluginDetailsComponent,
}
]
},
],
},
{
path: 'project',
data: { breadcrumb: 'projects', redirect: '/projects' },
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ import { SettingsComponent } from './settings/settings.component';
import { CreatePipelineComponent } from './projects/models/backup-settings/create-pipeline/create-pipeline.component';
import { PipelineGitInputComponent } from './projects/models/backup-settings/create-pipeline/pipeline-input/pipeline-git-input/pipeline-git-input.component';
import { PipelineT4CInputComponent } from './projects/models/backup-settings/create-pipeline/pipeline-input/pipeline-t4c-input/pipeline-t4c-input.component';
import { PluginWrapperComponent } from './plugins/store/plugin-wrapper/plugin-wrapper.component';
import { PluginDetailsComponent } from './plugins/store/plugin-detail/plugin-details.component';

@NgModule({
declarations: [
Expand Down Expand Up @@ -193,6 +195,8 @@ import { PipelineT4CInputComponent } from './projects/models/backup-settings/cre
PipelineWrapperComponent,
ProjectAuditLogComponent,
PluginStoreOverviewComponent,
PluginWrapperComponent,
PluginDetailsComponent,
ProjectDetailsComponent,
ProjectMetadataComponent,
ProjectOverviewComponent,
Expand Down
16 changes: 16 additions & 0 deletions frontend/src/app/interceptors/loader.interceptor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';

import { LoaderInterceptor } from './loader.interceptor';

describe('InterceptorsInterceptor', () => {
beforeEach(() => TestBed.configureTestingModule({
providers: [
LoaderInterceptor
]
}));

it('should be created', () => {
const interceptor: LoaderInterceptor = TestBed.inject(LoaderInterceptor);
expect(interceptor).toBeTruthy();
});
});
25 changes: 25 additions & 0 deletions frontend/src/app/interceptors/loader.interceptor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Injectable } from '@angular/core';
import {
HttpRequest,
HttpHandler,
HttpEvent,
HttpInterceptor,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { LoaderService } from '../services/loader/loader.service';
import { finalize } from 'rxjs/operators';

@Injectable()
export class LoaderInterceptor implements HttpInterceptor {

constructor(private loaderService: LoaderService) {
}

intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
this.loaderService.show();

return next.handle(request).pipe(
finalize(() => this.loaderService.hide()),
);
}
}
17 changes: 17 additions & 0 deletions frontend/src/app/loader/loader.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.overlay {
position: fixed;
display: block;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(74, 74, 74, .8);
z-index: 99999;
}

.spinner {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
3 changes: 3 additions & 0 deletions frontend/src/app/loader/loader.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<div *ngIf="isLoading | async" class="overlay">
<ngx-skeleton-loader appearance="line"></ngx-skeleton-loader>
</div>
25 changes: 25 additions & 0 deletions frontend/src/app/loader/loader.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { LoaderComponent } from './loader.component';

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

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

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

it('should create', () => {
expect(component).toBeTruthy();
});
});
17 changes: 17 additions & 0 deletions frontend/src/app/loader/loader.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Component } from '@angular/core';
import { Subject } from 'rxjs';
import { LoaderService } from '../services/loader/loader.service';

@Component({
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.css'],
})
export class LoaderComponent {
isLoading: Subject<boolean> = this.loaderService.isLoading;

constructor(private loaderService: LoaderService) {
}

ngOnInit(): void { }
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export class CreatePluginComponent {
constructor(
public pluginStoreService: PluginStoreService,
private router: Router
) {}
) { }

createPluginForm = new FormGroup({
remote: new FormControl('', Validators.required),
username: new FormControl(''),
Expand All @@ -38,7 +39,7 @@ export class CreatePluginComponent {
}
}

prettifyJSON(content: any) {
return JSON.stringify(content);
prettifyJSON(content: any, spaces: number = 2) {
return JSON.stringify(content, null, spaces);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
* SPDX-License-Identifier: Apache-2.0
*/

#title {
margin-left: 10px;
}

.metadata-item {
flex-basis: 50%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<!--
~ SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
~ SPDX-License-Identifier: Apache-2.0
-->

<h2 id="title">Plugin information</h2>
<mat-card>
<form [formGroup]="editPluginForm" (ngSubmit)="onSubmit()">
Direct URL to a raw `mbse-works-plugin.yml`:
<fieldset>
<mat-form-field appearance="outline">
<mat-label>Remote URL</mat-label>
<input matInput formControlName="remote" />
<mat-error *ngIf="editPluginForm.controls.remote.errors?.required">
The remote URL is required.
</mat-error>
</mat-form-field>
</fieldset>
Basic authentication to fetch template. <br />
<div class="flex-space-between">
<div>
<mat-form-field id="username" appearance="outline">
<mat-label>Username (optional)</mat-label>
<input matInput formControlName="username" />
</mat-form-field>
<mat-form-field id="password" appearance="outline">
<mat-label>Password (optional)</mat-label>
<input type="password" matInput formControlName="password" />
</mat-form-field>
</div>
<button type="submit" mat-raised-button color="primary">
Save plugin
</button>
</div>
</form>
</mat-card>
<mat-card>
<div class="flex-space-between">
<span> Currently used template: </span>
<button
mat-raised-button
color="primary"
id="reload"
(click)="refreshPluginContent()"
>
<mat-icon>refresh</mat-icon> Reload from remote
</button>
</div>
<div id="fetched-result">
{{
prettifyJSON(
this.peekContent || (pluginStoreService.plugin | async)?.content
)
}}
</div>
</mat-card>
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
* SPDX-License-Identifier: Apache-2.0
*/

import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { ToastService } from 'src/app/helpers/toast/toast.service';
import { filter } from 'rxjs';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Plugin, PluginStoreService } from '../service/plugin-store.service';

@UntilDestroy()
@Component({
selector: 'app-plugin-details',
templateUrl: './plugin-details.component.html',
styleUrls: ['./plugin-details.component.css'],
})
export class PluginDetailsComponent {
canDelete = false;
peekContent = '';
plugin?: Plugin;

constructor(
public pluginStoreService: PluginStoreService,
private toastService: ToastService,
private router: Router,
private route: ActivatedRoute
) {}

ngOnInit(): void {
this.pluginStoreService.plugin
.pipe(untilDestroyed(this), filter(Boolean))
.subscribe((plugin) => {
this.plugin = plugin;
this.editPluginForm.patchValue(plugin);
});
}

editPluginForm = new FormGroup({
remote: new FormControl('', Validators.required),
username: new FormControl(''),
password: new FormControl(''),
});

onSubmit() {
if (this.editPluginForm.valid) {
this.pluginStoreService
.updatePlugin(this.plugin!.id, this.editPluginForm.value as Plugin)
.subscribe(() => {
this.pluginStoreService.fetchPluginsFromStore();
this.router.navigate(['/plugins']);
});
}
}

refreshPluginContent() {
this.peekContent = this.pluginStoreService.fetchPluginContentFromRemote(
this.editPluginForm.value as Plugin
);
}

prettifyJSON(content: any, spaces: number = 2) {
return JSON.stringify(content, null, spaces);
}

deletePlugin(): void {
if (
!this.canDelete ||
!window.confirm(
`Do you really want to delete this project? All assigned users will lose access to it! The project cannot be restored!`
)
) {
return;
}

this.pluginStoreService.plugin.subscribe((plugin) => {
const pluginId: number = plugin!.id;
this.pluginStoreService.deletePlugin(pluginId).subscribe({
next: () => {
this.toastService.showSuccess(
'Project deleted',
`${pluginId} has been deleted`
);
this.router.navigate(['../../plugins'], { relativeTo: this.route });
},
error: () => {
this.toastService.showError(
'Plugin deletion failed',
`${pluginId} has not been deleted`
);
},
});
})

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/*
* SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
* SPDX-License-Identifier: Apache-2.0
*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<!--
~ SPDX-FileCopyrightText: Copyright DB Netz AG and the capella-collab-manager contributors
~ SPDX-License-Identifier: Apache-2.0
-->

<router-outlet></router-outlet>
Loading

0 comments on commit dea2e67

Please sign in to comment.