Skip to content

Commit

Permalink
Merge pull request #93 from avdev4j/83_add_health_check_endpoint
Browse files Browse the repository at this point in the history
83 add health check endpoint
  • Loading branch information
joewhite101 authored Sep 22, 2020
2 parents 3ac82f8 + e73dc3a commit 5b3681b
Show file tree
Hide file tree
Showing 13 changed files with 527 additions and 52 deletions.
39 changes: 39 additions & 0 deletions generators/client/files-angular.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2013-2020 the original author or authors from the JHipster project.
*
* This file is part of the JHipster project, see https://www.jhipster.tech/
* for more information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const constants = require('generator-jhipster/generators/generator-constants');

const { ANGULAR_DIR } = constants;

const filesAngular = {
angularAdminModule: [
{
path: ANGULAR_DIR,
templates: [{ file: 'admin/health/health.component.html', method: 'processHtml' }, 'admin/health/health.service.ts']
}
]
};

function writeFiles() {
this.writeFilesToDisk(filesAngular, this, false, 'angular');
}

module.exports = {
writeFiles,
files: filesAngular
};
39 changes: 39 additions & 0 deletions generators/client/files-react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2013-2020 the original author or authors from the JHipster project.
*
* This file is part of the JHipster project, see https://www.jhipster.tech/
* for more information.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const constants = require('generator-jhipster/generators/generator-constants');

const { REACT_DIR } = constants;

const filesReact = {
adminModule: [
{
path: REACT_DIR,
templates: [{ file: 'modules/administration/health/health.tsx', method: 'processJsx' }]
}
]
};

function writeFiles() {
this.writeFilesToDisk(filesReact, this, false, 'react');
}

module.exports = {
writeFiles,
files: filesReact
};
68 changes: 68 additions & 0 deletions generators/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* eslint-disable consistent-return */
const chalk = require('chalk');
const ClientGenerator = require('generator-jhipster/generators/client');
const constants = require('generator-jhipster/generators/generator-constants');
const writeAngularFiles = require('./files-angular').writeFiles;
const writeReactFiles = require('./files-react').writeFiles;

const { ANGULAR, REACT } = constants.SUPPORTED_CLIENT_FRAMEWORKS;

module.exports = class extends ClientGenerator {
constructor(args, opts) {
super(args, { fromBlueprint: true, ...opts }); // fromBlueprint variable is important

const jhContext = (this.jhipsterContext = this.options.jhipsterContext);

if (!jhContext) {
this.error(`This is a JHipster blueprint and should be used only like ${chalk.yellow('jhipster --blueprint quarkus')}`);
}

this.configOptions = jhContext.configOptions || {};

// This sets up options for this sub generator and is being reused from JHipster
jhContext.setupClientOptions(this, jhContext);
}

get initializing() {
return super._initializing();
}

get prompting() {
return super._prompting();
}

get configuring() {
// Here we are not overriding this phase and hence its being handled by JHipster
return super._configuring();
}

get default() {
// Here we are not overriding this phase and hence its being handled by JHipster
return super._default();
}

get writing() {
const phaseFromJHipster = super._writing();
const phaseFromQuarkus = {
writeQuarkusFiles() {
if (this.skipClient) return;
if (this.clientFramework === ANGULAR) {
return writeAngularFiles.call(this);
}
if (this.clientFramework === REACT) {
return writeReactFiles.call(this);
}
}
};
return { ...phaseFromJHipster, ...phaseFromQuarkus };
}

get install() {
// Here we are not overriding this phase and hence its being handled by JHipster
return super._install();
}

get end() {
return super._end();
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<%#
Copyright 2013-2020 the original author or authors from the JHipster project.
This file is part of the JHipster project, see https://www.jhipster.tech/
for more information.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-%>
<div>
<h2>
<span id="health-page-heading" jhiTranslate="health.title" data-cy="healthPageHeading">Health Checks</span>

<button class="btn btn-primary float-right" (click)="refresh()">
<fa-icon icon="sync"></fa-icon> <span jhiTranslate="health.refresh.button">Refresh</span>
</button>
</h2>

<div class="table-responsive">
<table id="healthCheck" class="table table-striped" aria-describedby="health-page-heading">
<thead>
<tr>
<th scope="col" jhiTranslate="health.table.service">Service Name</th>
<th scope="col" class="text-center" jhiTranslate="health.table.status">Status</th>
<th scope="col" class="text-center" jhiTranslate="health.details.details">Details</th>
</tr>
</thead>
<tbody *ngIf="health">
<tr *ngFor="let componentHealth of health.checks | keys">
<td>
<span class="text-capitalize">{{ componentHealth.value.name }}</span>
</td>
<td class="text-center">
<span class="badge" [ngClass]="getBadgeClass(componentHealth.value.status)" jhiTranslate="{{ 'health.status.' + componentHealth.value.status }}">
{{ componentHealth.value.status }}
</span>
</td>
<td class="text-center">
<a class="hand" (click)="showHealth(componentHealth)" *ngIf="componentHealth.value.details">
<fa-icon icon="eye"></fa-icon>
</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<%#
Copyright 2013-2020 the original author or authors from the JHipster project.
This file is part of the JHipster project, see https://www.jhipster.tech/
for more information.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-%>
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

import { SERVER_API_URL } from 'app/app.constants';

export type HealthStatus = 'UP' | 'DOWN' | 'UNKNOWN' | 'OUT_OF_SERVICE';

export type HealthKey =
<%_ if (messageBroker === 'kafka') { _%>
| 'binders'
<%_ } _%>
<%_ if (applicationType === 'gateway' || serviceDiscoveryType) { _%>
| 'discoveryComposite'
| 'refreshScope'
| 'clientConfigServer'
| 'hystrix'
<%_ } _%>
<%_ if (serviceDiscoveryType === 'consul') { _%>
| 'consul'
<%_ } _%>
| 'diskSpace'
| 'mail'
| 'ping'
<%_ if (searchEngine === 'elasticsearch') { _%>
| 'elasticsearch'
<%_ } _%>
<%_ if (databaseType === 'sql') { _%>
| 'db'
<%_ } else if (databaseType === 'mongodb') { _%>
| 'mongo'
<%_ } else if (databaseType === 'cassandra') { _%>
| 'cassandra'
<%_ } else if (databaseType === 'couchbase') { _%>
| 'couchbase'
<%_ } _%>
;

export interface Health {
status: HealthStatus;
checks: {
[key in HealthKey]?: HealthDetails;
};
}

export interface HealthDetails {
status: HealthStatus;
details: any;
}

@Injectable({ providedIn: 'root' })
export class HealthService {
constructor(private http: HttpClient) {}

checkHealth(): Observable<Health> {
return this.http.get<Health>(SERVER_API_URL + 'management/health');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
<%#
Copyright 2013-2020 the original author or authors from the JHipster project.
This file is part of the JHipster project, see https://www.jhipster.tech/
for more information.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-%>
import React, { useState, useEffect } from 'react';
import { connect } from 'react-redux';
import { Translate } from 'react-jhipster';
import { Table, Badge, Col, Row, Button } from 'reactstrap';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

import { IRootState } from 'app/shared/reducers';
import { systemHealth } from '../administration.reducer';
import HealthModal from './health-modal';

export interface IHealthPageProps extends StateProps, DispatchProps {}

export const HealthPage = (props: IHealthPageProps) => {
const [healthObject, setHealthObject] = useState({});
const [showModal, setShowModal] = useState(false);

useEffect(() => {
props.systemHealth();
}, []);

const getSystemHealth = () => {
if (!props.isFetching) {
props.systemHealth();
}
};

const getSystemHealthInfo = (name, healthObj) => () => {
setShowModal(true);
setHealthObject({ ...healthObj, name });
};

const handleClose = () => setShowModal(false);

const renderModal = () => <HealthModal healthObject={healthObject} handleClose={handleClose} showModal={showModal} />;

const { health, isFetching } = props;
const data = (health || {}).checks || {};

return (
<div>
<h2 id="health-page-heading" data-cy="healthPageHeading">Health Checks</h2>
<p>
<Button onClick={getSystemHealth} color={isFetching ? 'btn btn-danger' : 'btn btn-primary'} disabled={isFetching}>
<FontAwesomeIcon icon="sync" />
&nbsp;
<Translate component="span" contentKey="health.refresh.button">
Refresh
</Translate>
</Button>
</p>
<Row>
<Col md="12">
<Table bordered aria-describedby="health-page-heading">
<thead>
<tr>
<th>Service Name</th>
<th>Status</th>
<th>Details</th>
</tr>
</thead>
<tbody>
{Object.keys(data).map((configPropKey, configPropIndex) =>
configPropKey !== 'status' ? (
<tr key={configPropIndex}>
<td>{data[configPropKey].name</td>
<td>
<Badge color={data[configPropKey].status !== 'UP' ? 'danger' : 'success'}>{data[configPropKey].status}</Badge>
</td>
<td>
{data[configPropKey].details ? (
<a onClick={getSystemHealthInfo(configPropKey, data[configPropKey])}>
<FontAwesomeIcon icon="eye" />
</a>
) : null}
</td>
</tr>
) : null
)}
</tbody>
</Table>
</Col>
</Row>
{renderModal()}
</div>
);
};

const mapStateToProps = (storeState: IRootState) => ({
health: storeState.administration.health,
isFetching: storeState.administration.loading
});

const mapDispatchToProps = { systemHealth };

type StateProps = ReturnType<typeof mapStateToProps>;
type DispatchProps = typeof mapDispatchToProps;

export default connect(mapStateToProps, mapDispatchToProps)(HealthPage);
Loading

0 comments on commit 5b3681b

Please sign in to comment.