Skip to content
Snippets Groups Projects
Commit 06b9071d authored by Florent Poittevin's avatar Florent Poittevin
Browse files

feat: 912 preservation monitoring

parent ce796463
No related branches found
No related tags found
No related merge requests found
Showing
with 457 additions and 26 deletions
......@@ -7,6 +7,14 @@ module.exports = {
"^/api": ""
}
},
"/api/preservation-planning": {
"target": "https://test.dlcm.ch/administration",
"logLevel": "info",
"changeOrigin": true,
"pathRewrite": {
"^/api": ""
}
},
"/api/ingest": {
"target": "https://test.dlcm.ch/ingestion",
"logLevel": "info",
......
......@@ -3,7 +3,13 @@ module.exports = {
"target": "http://localhost:16115/dlcm",
"pathRewrite": {
"^/api": ""
}
}
},
"/api/preservation-planning": {
"target": "http://localhost:16115/dlcm",
"pathRewrite": {
"^/api": ""
}
},
"/api/ingest": {
"target": "http://localhost:16116/dlcm",
......@@ -26,9 +32,9 @@ module.exports = {
"/api/rss": {
"target": "https://www.unige.ch/feed",
"pathRewrite":
{
"^/api": ""
},
{
"^/api": ""
},
"changeOrigin": true
},
"/dlcm/oauth": {
......@@ -40,13 +46,13 @@ module.exports = {
"/dlcm/shiblogin": {
"target": "http://localhost:16110",
"onProxyReq": (proxyReq, req, res) => {
proxyReq.setHeader('mail', 'Marty.McFly@unige.ch');
proxyReq.setHeader('persistent-id', '999999@unige.ch');
proxyReq.setHeader('uniqueid', '999999@unige.ch');
proxyReq.setHeader('givenname', 'Marty');
proxyReq.setHeader('surname', 'McFly');
proxyReq.setHeader('homeorganization', 'unige.ch');
proxyReq.setHeader('preferredlanguage', 'fr-ch');
proxyReq.setHeader('mail', 'Marty.McFly@unige.ch');
proxyReq.setHeader('persistent-id', '999999@unige.ch');
proxyReq.setHeader('uniqueid', '999999@unige.ch');
proxyReq.setHeader('givenname', 'Marty');
proxyReq.setHeader('surname', 'McFly');
proxyReq.setHeader('homeorganization', 'unige.ch');
proxyReq.setHeader('preferredlanguage', 'fr-ch');
},
"onProxyRes": (proxyRes, req, res) => {
proxyRes.headers['Access-Control-Allow-Origin'] = 'http://localhost:4200';
......
......@@ -3,7 +3,13 @@ module.exports = {
"target": "http://localhost:16105/dlcm",
"pathRewrite": {
"^/api": ""
}
}
},
"/api/preservation-planning": {
"target": "http://localhost:16105/dlcm",
"pathRewrite": {
"^/api": ""
}
},
"/api/ingest": {
"target": "http://localhost:16106/dlcm",
......@@ -26,9 +32,9 @@ module.exports = {
"/api/rss": {
"target": "https://www.unige.ch/feed",
"pathRewrite":
{
"^/api": ""
},
{
"^/api": ""
},
"changeOrigin": true
},
"/dlcm/oauth": {
......@@ -40,13 +46,13 @@ module.exports = {
"/dlcm/shiblogin": {
"target": "http://localhost:16100",
"onProxyReq": (proxyReq, req, res) => {
proxyReq.setHeader('mail', 'Marty.McFly@unige.ch');
proxyReq.setHeader('persistent-id', '999999@unige.ch');
proxyReq.setHeader('uniqueid', '999999@unige.ch');
proxyReq.setHeader('givenname', 'Marty');
proxyReq.setHeader('surname', 'McFly');
proxyReq.setHeader('homeorganization', 'unige.ch');
proxyReq.setHeader('preferredlanguage', 'fr-ch');
proxyReq.setHeader('mail', 'Marty.McFly@unige.ch');
proxyReq.setHeader('persistent-id', '999999@unige.ch');
proxyReq.setHeader('uniqueid', '999999@unige.ch');
proxyReq.setHeader('givenname', 'Marty');
proxyReq.setHeader('surname', 'McFly');
proxyReq.setHeader('homeorganization', 'unige.ch');
proxyReq.setHeader('preferredlanguage', 'fr-ch');
},
"onProxyRes": (proxyRes, req, res) => {
proxyRes.headers['Access-Control-Allow-Origin'] = 'http://localhost:4200';
......
......@@ -48,7 +48,7 @@ export class PreservationHomeRoutable extends SharedAbstractPresentational {
avatarIcon: "user-md",
titleToTranslate: TRANSLATE("preservation.monitoring.home.title"),
subtitleToTranslate: TRANSLATE("preservation.monitoring.home.subtitle"),
path: RoutesEnum.preservationPreservationPlanning,
path: RoutesEnum.preservationMonitoring,
isVisible: () => PermissionUtil.isUserHavePermission(true, ApplicationRolePermissionEnum.rootPermission, this.userRolesObs),
},
{
......
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
<a [href]="service._links.self.href">
{{service.name}}
<ng-template [ngIf]="!(index | isNullOrUndefined)">{{index + 1}}</ng-template>
</a>
</mat-panel-title>
<span class="status"
[class.is-up]="service.status === 'UP'"
[class.is-down]="service.status === 'DOWN'"
>{{service.status}}</span>
</mat-expansion-panel-header>
<ul class="resource">
<li *ngFor="let resource of getResources()">
<a [href]="resource.href">{{getResourceName(resource.href)}}</a>
</li>
</ul>
</mat-expansion-panel>
@import "../sass/abstracts/variables";
@import "../sass/abstracts/mixins";
:host {
.status {
border-radius: 4px;
padding: 0 5px;
color: $white;
width: 60px;
display: inline-block;
text-align: center;
margin-right: 20px;
font-weight: bold;
&.is-up {
background-color: $success;
}
&.is-down {
background-color: $error;
}
}
li {
padding: 2px 5px;
&:nth-child(even) {
background-color: $extra-ultra-light-grey;
}
}
}
import {
ChangeDetectionStrategy,
Component,
Input,
} from "@angular/core";
import {SharedAbstractPresentational} from "@app/shared/components/presentationals/shared-abstract/shared-abstract.presentational";
import {PreservationPlanningMonitorService} from "@shared/models/business/preservation-planning-monitor.model";
import {
HateOASLink,
isArray,
urlSeparator,
} from "solidify-frontend";
@Component({
selector: "dlcm-monitoring-service",
templateUrl: "./monitoring-service.presentational.html",
styleUrls: ["./monitoring-service.presentational.scss"],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class MonitoringServicePresentational extends SharedAbstractPresentational {
@Input()
service: PreservationPlanningMonitorService;
@Input()
index: number | undefined;
getResourceName(url: string): string {
return url.substring(url.lastIndexOf(urlSeparator) + 1, url.length);
}
getResources(): HateOASLink[] {
const resources = this.service._links.resources;
if (isArray(resources)) {
return resources;
}
return [resources];
}
}
<h1>{{'preservation.monitoring.home.title' | translate}}</h1>
<div class="wrapper"
[dlcmSpinner]="isLoading | async"
>
<mat-accordion *ngIf="(preservationPlanningMonitor | async) as preservationPlanningState">
<ng-container *ngFor="let service of getListOfServices(preservationPlanningState); trackBy: trackByFn">
<ng-template [ngIf]="service | isArray"
[ngIfElse]="displayService"
>
<ng-container *ngFor="let serviceBis of service; let i = index; trackBy: trackByFn">
<dlcm-monitoring-service [service]="serviceBis"
[index]="i"
></dlcm-monitoring-service>
</ng-container>
</ng-template>
<ng-template #displayService>
<dlcm-monitoring-service [service]="service"></dlcm-monitoring-service>
</ng-template>
</ng-container>
</mat-accordion>
</div>
@import "../sass/abstracts/variables";
@import "../sass/abstracts/mixins";
@include content();
@include spinner-wrapper();
import {
Component,
OnInit,
} from "@angular/core";
import {PreservationMonitoringAction} from "@app/features/preservation/monitoring/stores/preservation-monitoring.action";
import {PreservationMonitoringState} from "@app/features/preservation/monitoring/stores/preservation-monitoring.state";
import {SharedAbstractPresentational} from "@app/shared/components/presentationals/shared-abstract/shared-abstract.presentational";
import {Store} from "@ngxs/store";
import {
PreservationPlanningMonitor,
PreservationPlanningMonitorService,
} from "@shared/models/business/preservation-planning-monitor.model";
import {
Observable,
timer,
} from "rxjs";
import {
isNullOrUndefined,
MemoizedUtil,
ObjectUtil,
StringUtil,
} from "solidify-frontend";
@Component({
selector: "dlcm-preservation-home-routable",
templateUrl: "./monitoring-home.routable.html",
styleUrls: ["./monitoring-home.routable.scss"],
})
export class MonitoringHomeRoutable extends SharedAbstractPresentational implements OnInit {
preservationPlanningMonitor: Observable<PreservationPlanningMonitor> = MemoizedUtil.select(this._store, PreservationMonitoringState, state => state.preservationPlanningMonitor, true);
isLoading: Observable<boolean> = MemoizedUtil.isLoading(this._store, PreservationMonitoringState);
private readonly INTERVAL_REFRESH_IN_SECOND: number = 10;
constructor(private readonly _store: Store) {
super();
}
ngOnInit(): void {
super.ngOnInit();
this._store.dispatch(new PreservationMonitoringAction.Get(true));
const intervalInMillisecond = this.INTERVAL_REFRESH_IN_SECOND * 1000;
this.subscribe(timer(intervalInMillisecond, intervalInMillisecond),
() => {
this._store.dispatch(new PreservationMonitoringAction.Get(true));
});
}
getListOfServices(preservationPlanningMonitor: PreservationPlanningMonitor): PreservationPlanningMonitorService[] | PreservationPlanningMonitor[] {
return ObjectUtil.values(preservationPlanningMonitor);
}
trackByFn(index: number, item: PreservationPlanningMonitorService | PreservationPlanningMonitor): string {
if (isNullOrUndefined(item.name)) {
item = item as PreservationPlanningMonitor;
return StringUtil.stringEmpty;
}
item = item as PreservationPlanningMonitorService;
return item.name + " " + item.status;
}
}
import {NgModule} from "@angular/core";
import {RouterModule} from "@angular/router";
import {MonitoringHomeRoutable} from "@app/features/preservation/monitoring/components/routables/monitoring-home/monitoring-home.routable";
import {DlcmRoutes} from "@app/shared/models/dlcm-route.model";
const routes: DlcmRoutes = [
{
path: "",
component: MonitoringHomeRoutable,
data: {},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class PreservationMonitoringRoutingModule {
}
import {NgModule} from "@angular/core";
import {MonitoringServicePresentational} from "@app/features/preservation/monitoring/components/presentationals/monitoring-service/monitoring-service.presentational";
import {MonitoringHomeRoutable} from "@app/features/preservation/monitoring/components/routables/monitoring-home/monitoring-home.routable";
import {PreservationMonitoringRoutingModule} from "@app/features/preservation/monitoring/preservation-monitoring-routing.module";
import {PreservationMonitoringState} from "@app/features/preservation/monitoring/stores/preservation-monitoring.state";
import {SharedModule} from "@app/shared/shared.module";
import {TranslateModule} from "@ngx-translate/core";
import {NgxsModule} from "@ngxs/store";
const routables = [
MonitoringHomeRoutable,
];
const containers = [];
const dialogs = [];
const presentationals = [
MonitoringServicePresentational,
];
@NgModule({
declarations: [
...routables,
...containers,
...dialogs,
...presentationals,
],
imports: [
SharedModule,
PreservationMonitoringRoutingModule,
TranslateModule.forChild({}),
NgxsModule.forFeature([
PreservationMonitoringState,
]),
],
entryComponents: [
...dialogs,
],
exports: [
...routables,
],
providers: [],
})
export class PreservationMonitoringModule {
}
import {LocalStateEnum} from "@shared/enums/local-state.enum";
import {PreservationPlanningMonitor} from "@shared/models/business/preservation-planning-monitor.model";
import {
BaseAction,
BaseSubAction,
} from "solidify-frontend";
const state = LocalStateEnum.preservation_monitoring;
export namespace PreservationMonitoringAction {
export class Get extends BaseAction {
static readonly type: string = `[${state}] Get`;
constructor(public keepCurrentContext: boolean = false) {
super();
}
}
export class GetSuccess extends BaseSubAction<Get> {
static readonly type: string = `[${state}] Get Success`;
constructor(public parent: Get, public preservationPlanningMonitor: PreservationPlanningMonitor) {
super(parent);
}
}
export class GetFail extends BaseSubAction<Get> {
static readonly type: string = `[${state}] Get Fail`;
constructor(public parent: Get) {
super(parent);
}
}
}
export const preservationMonitorActionNameSpace = PreservationMonitoringAction;
import {
preservationMonitorActionNameSpace,
PreservationMonitoringAction,
} from "@app/features/preservation/monitoring/stores/preservation-monitoring.action";
import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
import {Navigate} from "@ngxs/router-plugin";
import {
Action,
Actions,
State,
StateContext,
Store,
} from "@ngxs/store";
import {PreservationPlanningResourceApiEnum} from "@shared/enums/api.enum";
import {PreservationPlanningMonitor} from "@shared/models/business/preservation-planning-monitor.model";
import {Observable} from "rxjs";
import {
catchError,
tap,
} from "rxjs/operators";
import {
ApiService,
BaseState,
BaseStateModel,
defaultBaseStateInitValue,
NotificationService,
SolidifyStateError,
StoreUtil,
} from "solidify-frontend";
export interface PreservationMonitoringStateModel extends BaseStateModel {
preservationPlanningMonitor: PreservationPlanningMonitor | undefined;
}
@State<PreservationMonitoringStateModel>({
name: LocalStateEnum.preservation_monitoring,
defaults: {
...defaultBaseStateInitValue(),
preservationPlanningMonitor: undefined,
},
children: [],
})
export class PreservationMonitoringState extends BaseState<PreservationMonitoringStateModel> {
constructor(protected apiService: ApiService,
protected store: Store,
protected notificationService: NotificationService,
protected actions$: Actions) {
super(apiService, store, notificationService, actions$, {
nameSpace: preservationMonitorActionNameSpace,
}, PreservationMonitoringState);
}
protected get _urlResource(): string {
return PreservationPlanningResourceApiEnum.monitor;
}
@Action(PreservationMonitoringAction.Get)
get(ctx: StateContext<PreservationMonitoringStateModel>, action: PreservationMonitoringAction.Get): Observable<PreservationPlanningMonitor> {
let reset = {};
if (!action.keepCurrentContext) {
reset = {
preservationPlanningMonitor: undefined,
};
}
ctx.patchState({
isLoadingCounter: ctx.getState().isLoadingCounter + 1,
...reset,
});
return this.apiService.get<PreservationPlanningMonitor>(this._urlResource, null)
.pipe(
StoreUtil.cancelUncompleted(ctx, this.actions$, [PreservationMonitoringAction.Get, Navigate]),
tap((preservationPlanningMonitor: PreservationPlanningMonitor) => {
ctx.dispatch(new PreservationMonitoringAction.GetSuccess(action, preservationPlanningMonitor));
}),
catchError(error => {
ctx.dispatch(new PreservationMonitoringAction.GetFail(action));
throw new SolidifyStateError(this, error);
}),
);
}
@Action(PreservationMonitoringAction.GetSuccess)
getAllSuccess(ctx: StateContext<PreservationMonitoringStateModel>, action: PreservationMonitoringAction.GetSuccess): void {
ctx.patchState({
preservationPlanningMonitor: action.preservationPlanningMonitor,
isLoadingCounter: ctx.getState().isLoadingCounter - 1,
});
}
@Action(PreservationMonitoringAction.GetFail)
getAllFail(ctx: StateContext<PreservationMonitoringStateModel>, action: PreservationMonitoringAction.GetFail): void {
ctx.patchState({
isLoadingCounter: ctx.getState().isLoadingCounter - 1,
});
}
}
......@@ -4,7 +4,12 @@ import {
Routes,
} from "@angular/router";
import {PreservationHomeRoutable} from "@app/features/preservation/components/routables/admin-home/preservation-home.routable";
import {AppRoutesEnum} from "@app/shared/enums/routes.enum";
import {
AppRoutesEnum,
PreservationPlanningRoutesEnum,
} from "@app/shared/enums/routes.enum";
import {ApplicationRoleGuardService} from "@shared/guards/application-role-guard.service";
import {TRANSLATE} from "solidify-frontend";
const routes: Routes = [
{
......@@ -12,6 +17,15 @@ const routes: Routes = [
component: PreservationHomeRoutable,
data: {},
},
{
path: PreservationPlanningRoutesEnum.monitoring,
// @ts-ignore Dynamic import
loadChildren: () => import("./monitoring/preservation-monitoring.module").then(m => m.PreservationMonitoringModule),
data: {
breadcrumb: TRANSLATE("breadcrumb.preservation.monitoring.root"),
},
canActivate: [ApplicationRoleGuardService],
},
];
@NgModule({
......@@ -19,4 +33,5 @@ const routes: Routes = [
exports: [RouterModule],
})
export class PreservationRoutingModule {
}
import {NgModule} from "@angular/core";
import {PreservationHomeRoutable} from "@app/features/preservation/components/routables/admin-home/preservation-home.routable";
import {PreservationMonitoringState} from "@app/features/preservation/monitoring/stores/preservation-monitoring.state";
import {PreservationRoutingModule} from "@app/features/preservation/preservation-routing.module";
import {PreservationState} from "@app/features/preservation/stores/preservation.state";
import {SharedModule} from "@app/shared/shared.module";
......@@ -26,6 +27,7 @@ const presentationals = [];
TranslateModule.forChild({}),
NgxsModule.forFeature([
PreservationState,
PreservationMonitoringState,
]),
],
entryComponents: [
......
import {
PreservationMonitoringState,
PreservationMonitoringStateModel,
} from "@app/features/preservation/monitoring/stores/preservation-monitoring.state";
import {LocalStateEnum} from "@app/shared/enums/local-state.enum";
import {
State,
......@@ -6,14 +10,18 @@ import {
import {BaseStateModel} from "solidify-frontend";
export interface PreservationStateModel extends BaseStateModel {
preservation_monitoring: PreservationMonitoringStateModel | undefined;
}
@State<PreservationStateModel>({
name: LocalStateEnum.preservation,
defaults: {
isLoadingCounter: 0,
preservation_monitoring: undefined,
},
children: [],
children: [
PreservationMonitoringState,
],
})
export class PreservationState {
constructor(protected store: Store) {
......
......@@ -141,7 +141,7 @@ export class SharedDataTablePresentational<T> extends SharedAbstractPresentation
getData(row: T, column: DataTableColumns): any {
const field = column.field;
if (field.includes(this._SEPARATOR)) {
return ObjectUtil.getNestedValue(row, column.field);
return ObjectUtil.getNestedValue(row as any, column.field);
}
return row[field];
}
......
......@@ -236,6 +236,14 @@ export class PreservationPlanningResourceApiEnum implements ResourceApiEnum {
static get preservationJobs(): string {
return BaseResourceApiEnum.preservationPlanning + SEPARATOR + ApiResourceNameEnum.PRES_JOB;
}
static get monitor(): string {
return BaseResourceApiEnum.preservationPlanning + SEPARATOR + ApiResourceNameEnum.MONITOR;
}
static get preservationAip(): string {
return BaseResourceApiEnum.preservationPlanning + SEPARATOR + ApiResourceNameEnum.AIP;
}
}
export class ResourceSrvResourceApiEnum implements ResourceApiEnum {
......
......@@ -58,4 +58,5 @@ export enum LocalStateEnum {
admin_fundingAgencies = "admin_fundingAgencies",
preservation = "preservation",
preservation_monitoring = "preservation_monitoring",
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment