Web-console: add loader to show-json, add status-dialog (#8172)

* add loader to show json, add status-dialog

* fix ordered import

* fix changes

* order inputs

* update snapshots

* fix bad merge conflicts
This commit is contained in:
mcbrewster 2019-07-30 08:08:36 -07:00 committed by Fangjin Yang
parent a0270512a2
commit f7abc300a8
12 changed files with 559 additions and 56 deletions

View File

@ -11,7 +11,9 @@ exports[`rule editor matches snapshot 1`] = `
class="bp3-button-group right-buttons"
>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -21,7 +23,9 @@ exports[`rule editor matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -31,7 +35,9 @@ exports[`rule editor matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -45,10 +51,40 @@ exports[`rule editor matches snapshot 1`] = `
<div
class="main-area"
>
<textarea
class="bp3-input"
readonly=""
/>
<div
class="loader"
>
<div
class="loader-logo"
>
<svg
viewBox="0 0 100 100"
>
<path
class="one"
d="M54.2,69.8h-2.7c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h2.7c11.5,0,23.8-7.4,23.8-23.7
c0-9.1-6.9-15.8-16.4-15.8H38c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3c3.5,3.4,5.4,8,5.4,13.1
c0,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
/>
<path
class="two"
d="M55.7,59.5h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5
c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8
C63.5,58,59.9,59.5,55.7,59.5z"
/>
<path
class="three"
d="M27.2,38h-6.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3S27.9,38,27.2,38z"
/>
<path
class="four"
d="M45.1,69.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3
C46.4,69.2,45.8,69.8,45.1,69.8z"
/>
</svg>
</div>
</div>
</div>
</div>
`;

View File

@ -37,5 +37,9 @@
width: 100%;
resize: none;
}
.loader {
position: relative;
}
}
}

View File

@ -24,6 +24,7 @@ import React from 'react';
import { AppToaster } from '../../singletons/toaster';
import { UrlBaser } from '../../singletons/url-baser';
import { downloadFile } from '../../utils';
import { Loader } from '../loader/loader';
import './show-json.scss';
@ -74,6 +75,7 @@ export class ShowJson extends React.PureComponent<ShowJsonProps, ShowJsonState>
<ButtonGroup className="right-buttons">
{downloadFilename && (
<Button
disabled={!jsonValue}
text="Save"
minimal
onClick={() => downloadFile(jsonValue, 'json', downloadFilename)}
@ -81,6 +83,7 @@ export class ShowJson extends React.PureComponent<ShowJsonProps, ShowJsonState>
)}
<Button
text="Copy"
disabled={!jsonValue}
minimal
onClick={() => {
copy(jsonValue, { format: 'text/plain' });
@ -92,13 +95,15 @@ export class ShowJson extends React.PureComponent<ShowJsonProps, ShowJsonState>
/>
<Button
text="View raw"
disabled={!jsonValue}
minimal
onClick={() => window.open(UrlBaser.base(endpoint), '_blank')}
/>
</ButtonGroup>
</div>
<div className="main-area">
<TextArea readOnly value={jsonValue} />
{!jsonValue && <Loader loadingText="" loading />}
{jsonValue && <TextArea readOnly value={jsonValue} />}
</div>
</div>
);

View File

@ -101,7 +101,9 @@ exports[`task table action dialog matches snapshot 1`] = `
class="bp3-button-group right-buttons"
>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -111,7 +113,9 @@ exports[`task table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -121,7 +125,9 @@ exports[`task table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -135,10 +141,40 @@ exports[`task table action dialog matches snapshot 1`] = `
<div
class="main-area"
>
<textarea
class="bp3-input"
readonly=""
/>
<div
class="loader"
>
<div
class="loader-logo"
>
<svg
viewBox="0 0 100 100"
>
<path
class="one"
d="M54.2,69.8h-2.7c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h2.7c11.5,0,23.8-7.4,23.8-23.7
c0-9.1-6.9-15.8-16.4-15.8H38c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3c3.5,3.4,5.4,8,5.4,13.1
c0,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
/>
<path
class="two"
d="M55.7,59.5h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5
c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8
C63.5,58,59.9,59.5,55.7,59.5z"
/>
<path
class="three"
d="M27.2,38h-6.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3S27.9,38,27.2,38z"
/>
<path
class="four"
d="M45.1,69.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3
C46.4,69.2,45.8,69.8,45.1,69.8z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,174 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`table action dialog matches snapshot 1`] = `
<div
class="bp3-portal"
>
<div
class="bp3-overlay bp3-overlay-open bp3-overlay-scroll-container"
>
<div
class="bp3-overlay-backdrop bp3-overlay-appear bp3-overlay-appear-active"
/>
<div
class="bp3-dialog-container bp3-overlay-content bp3-overlay-appear bp3-overlay-appear-active"
tabindex="0"
>
<div
class="bp3-dialog spec-dialog"
>
<div
class="bp3-dialog-header"
>
<h4
class="bp3-heading"
>
spec-dialog
</h4>
<button
aria-label="Close"
class="bp3-button bp3-minimal bp3-dialog-close-button"
type="button"
>
<span
class="bp3-icon bp3-icon-small-cross"
icon="small-cross"
>
<svg
data-icon="small-cross"
height="20"
viewBox="0 0 20 20"
width="20"
>
<desc>
small-cross
</desc>
<path
d="M11.41 10l3.29-3.29c.19-.18.3-.43.3-.71a1.003 1.003 0 0 0-1.71-.71L10 8.59l-3.29-3.3a1.003 1.003 0 0 0-1.42 1.42L8.59 10 5.3 13.29c-.19.18-.3.43-.3.71a1.003 1.003 0 0 0 1.71.71l3.29-3.3 3.29 3.29c.18.19.43.3.71.3a1.003 1.003 0 0 0 .71-1.71L11.41 10z"
fill-rule="evenodd"
/>
</svg>
</span>
</button>
</div>
<div
class=" ace_editor ace-tm spec-dialog-textarea"
id="brace-editor"
style="width: 100%; height: 500px;"
>
<textarea
autocapitalize="off"
autocorrect="off"
class="ace_text-input"
spellcheck="false"
style="opacity: 0;"
wrap="off"
/>
<div
aria-hidden="true"
class="ace_gutter"
>
<div
class="ace_layer ace_gutter-layer ace_folding-enabled"
/>
<div
class="ace_gutter-active-line"
/>
</div>
<div
class="ace_scroller"
>
<div
class="ace_content"
>
<div
class="ace_layer ace_print-margin-layer"
>
<div
class="ace_print-margin"
style="left: 4px; visibility: hidden;"
/>
</div>
<div
class="ace_layer ace_marker-layer"
/>
<div
class="ace_layer ace_text-layer"
style="padding: 0px 4px;"
/>
<div
class="ace_layer ace_marker-layer"
/>
<div
class="ace_layer ace_cursor-layer ace_hidden-cursors"
>
<div
class="ace_cursor"
/>
</div>
</div>
</div>
<div
class="ace_scrollbar ace_scrollbar-v"
style="display: none; width: 20px;"
>
<div
class="ace_scrollbar-inner"
style="width: 20px;"
/>
</div>
<div
class="ace_scrollbar ace_scrollbar-h"
style="display: none; height: 20px;"
>
<div
class="ace_scrollbar-inner"
style="height: 20px;"
/>
</div>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: hidden;"
>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
/>
<div
style="height: auto; width: auto; top: 0px; left: 0px; visibility: hidden; position: absolute; white-space: pre; overflow: visible;"
>
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
</div>
</div>
</div>
<div
class="bp3-dialog-footer"
>
<div
class="bp3-dialog-footer-actions"
>
<button
class="bp3-button"
type="button"
>
<span
class="bp3-button-text"
>
Close
</span>
</button>
<button
class="bp3-button bp3-intent-primary"
type="button"
>
<span
class="bp3-button-text"
>
Submit
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,45 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/
$side-bar-width: 120px;
.status-dialog {
&.bp3-dialog {
margin-top: 5vh;
top: 5%;
width: 60vw;
.status-dialog-main-area {
height: 60vh;
padding: 10px;
}
.bp3-dialog-footer {
position: relative;
padding-top: 5px;
.footer-actions-left {
position: absolute;
left: $side-bar-width;
& > * {
margin-right: 10px;
}
}
}
}
}

View File

@ -0,0 +1,32 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { render } from '@testing-library/react';
import React from 'react';
import { SpecDialog } from '..';
describe('table action dialog', () => {
it('matches snapshot', () => {
const tableActionDialog = (
<SpecDialog onClose={() => null} title={'spec-dialog'} onSubmit={() => null} />
);
render(tableActionDialog);
expect(document.body.lastChild).toMatchSnapshot();
});
});

View File

@ -0,0 +1,53 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 { Button, Classes, Dialog, IDialogProps, Intent } from '@blueprintjs/core';
import React from 'react';
import { ShowJson } from '../../components';
import './status-dialog.scss';
interface StatusDialogProps extends IDialogProps {
onClose: () => void;
title: string;
}
export class StatusDialog extends React.PureComponent<StatusDialogProps> {
constructor(props: StatusDialogProps) {
super(props);
this.state = {};
}
render() {
const { onClose, title, isOpen } = this.props;
return (
<Dialog className={'status-dialog'} onClose={onClose} isOpen={isOpen} title={title}>
<div className={'status-dialog-main-area'}>
<ShowJson endpoint={`/status`} downloadFilename={'status'} />
</div>
<div className={Classes.DIALOG_FOOTER}>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button text="Close" intent={Intent.PRIMARY} onClick={onClose} />
</div>
</div>
</Dialog>
);
}
}

View File

@ -188,7 +188,9 @@ exports[`supervisor table action dialog matches snapshot 1`] = `
class="bp3-button-group right-buttons"
>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -198,7 +200,9 @@ exports[`supervisor table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -208,7 +212,9 @@ exports[`supervisor table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -222,10 +228,40 @@ exports[`supervisor table action dialog matches snapshot 1`] = `
<div
class="main-area"
>
<textarea
class="bp3-input"
readonly=""
/>
<div
class="loader"
>
<div
class="loader-logo"
>
<svg
viewBox="0 0 100 100"
>
<path
class="one"
d="M54.2,69.8h-2.7c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h2.7c11.5,0,23.8-7.4,23.8-23.7
c0-9.1-6.9-15.8-16.4-15.8H38c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3c3.5,3.4,5.4,8,5.4,13.1
c0,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
/>
<path
class="two"
d="M55.7,59.5h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5
c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8
C63.5,58,59.9,59.5,55.7,59.5z"
/>
<path
class="three"
d="M27.2,38h-6.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3S27.9,38,27.2,38z"
/>
<path
class="four"
d="M45.1,69.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3
C46.4,69.2,45.8,69.8,45.1,69.8z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>

View File

@ -188,7 +188,9 @@ exports[`task table action dialog matches snapshot 1`] = `
class="bp3-button-group right-buttons"
>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -198,7 +200,9 @@ exports[`task table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -208,7 +212,9 @@ exports[`task table action dialog matches snapshot 1`] = `
</span>
</button>
<button
class="bp3-button bp3-minimal"
class="bp3-button bp3-disabled bp3-minimal"
disabled=""
tabindex="-1"
type="button"
>
<span
@ -222,10 +228,40 @@ exports[`task table action dialog matches snapshot 1`] = `
<div
class="main-area"
>
<textarea
class="bp3-input"
readonly=""
/>
<div
class="loader"
>
<div
class="loader-logo"
>
<svg
viewBox="0 0 100 100"
>
<path
class="one"
d="M54.2,69.8h-2.7c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h2.7c11.5,0,23.8-7.4,23.8-23.7
c0-9.1-6.9-15.8-16.4-15.8H38c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h23.6c5.3,0,10.1,1.9,13.6,5.3c3.5,3.4,5.4,8,5.4,13.1
c0,6.6-2.3,13-6.3,17.7C69.5,66.8,62.5,69.8,54.2,69.8z"
/>
<path
class="two"
d="M55.7,59.5h-26c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h26c7.5,0,11.5-5.8,11.5-11.5
c0-4.2-3.2-7.3-7.7-7.3h-26c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h26c5.9,0,10.3,4.3,10.3,9.9c0,3.7-1.3,7.2-3.7,9.8
C63.5,58,59.9,59.5,55.7,59.5z"
/>
<path
class="three"
d="M27.2,38h-6.3c-0.7,0-1.3-0.6-1.3-1.3s0.6-1.3,1.3-1.3h6.3c0.7,0,1.3,0.6,1.3,1.3S27.9,38,27.2,38z"
/>
<path
class="four"
d="M45.1,69.8h-5.8c-0.7,0-1.3-0.6-1.3-1.3c0-0.7,0.6-1.3,1.3-1.3h5.8c0.7,0,1.3,0.6,1.3,1.3
C46.4,69.2,45.8,69.8,45.1,69.8z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>

View File

@ -4,28 +4,24 @@ exports[`home view matches snapshot 1`] = `
<div
className="home-view app-view"
>
<a
href="/status"
target="_blank"
<Blueprint3.Card
className="status-card"
elevation={0}
interactive={true}
onClick={[Function]}
>
<Blueprint3.Card
className="home-view-card"
elevation={0}
interactive={true}
>
<Component>
<Blueprint3.Icon
color="#bfccd5"
icon="graph"
/>
 
Status
</Component>
<p>
Loading...
</p>
</Blueprint3.Card>
</a>
<Component>
<Blueprint3.Icon
color="#bfccd5"
icon="graph"
/>
 
Status
</Component>
<p>
Loading...
</p>
</Blueprint3.Card>
<a
href="#datasources"
>

View File

@ -22,13 +22,13 @@ import axios from 'axios';
import { sum } from 'd3-array';
import React from 'react';
import { UrlBaser } from '../../singletons/url-baser';
import { StatusDialog } from '../../dialogs/status-dialog/status-dialog';
import { lookupBy, pluralIfNeeded, queryDruidSql, QueryManager } from '../../utils';
import { deepGet } from '../../utils/object-change';
import './home-view.scss';
export interface CardOptions {
export interface CardLinkOptions {
href: string;
icon: IconName;
title: string;
@ -37,6 +37,15 @@ export interface CardOptions {
error?: string;
}
export interface CardModalOptions {
onClick: () => void;
icon: IconName;
title: string;
loading?: boolean;
content: JSX.Element | string;
error?: string;
}
export interface HomeViewProps {
noSqlMode: boolean;
}
@ -78,6 +87,8 @@ export interface HomeViewState {
peonCount: number;
serverCountError?: string;
showStatusDialog: boolean;
lookupsCountLoading: boolean;
lookupsCount: number;
lookupsUninitialized: boolean;
@ -126,6 +137,8 @@ export class HomeView extends React.PureComponent<HomeViewProps, HomeViewState>
middleManagerCount: 0,
peonCount: 0,
showStatusDialog: false,
lookupsCountLoading: false,
lookupsCount: 0,
lookupsUninitialized: false,
@ -339,7 +352,21 @@ GROUP BY 1`,
this.serverQueryManager.terminate();
}
renderCard(cardOptions: CardOptions): JSX.Element {
renderStatusDialog() {
const { showStatusDialog } = this.state;
if (!showStatusDialog) {
return null;
}
return (
<StatusDialog
onClose={() => this.setState({ showStatusDialog: false })}
title={'Status'}
isOpen
/>
);
}
renderCard(cardOptions: CardLinkOptions): JSX.Element {
return (
<a href={cardOptions.href} target={cardOptions.href[0] === '/' ? '_blank' : undefined}>
<Card className="home-view-card" interactive>
@ -359,13 +386,35 @@ GROUP BY 1`,
);
}
renderModalCard(cardOptions: CardModalOptions): JSX.Element {
return (
<Card
className="status-card"
interactive
onClick={() => this.setState({ showStatusDialog: true })}
>
<H5>
<Icon color="#bfccd5" icon={cardOptions.icon} />
&nbsp;{cardOptions.title}
</H5>
{cardOptions.loading ? (
<p>Loading...</p>
) : cardOptions.error ? (
`Error: ${cardOptions.error}`
) : (
cardOptions.content
)}
</Card>
);
}
render(): JSX.Element {
const state = this.state;
return (
<div className="home-view app-view">
{this.renderCard({
href: UrlBaser.base('/status'),
{this.renderModalCard({
onClick: () => this.setState({ showStatusDialog: true }),
icon: IconNames.GRAPH,
title: 'Status',
loading: state.versionLoading,
@ -470,7 +519,7 @@ GROUP BY 1`,
{Boolean(state.peonCount) && <p>{pluralIfNeeded(state.peonCount, 'peon')}</p>}
</>
),
error: state.serverCountError,
error: state.serverCountError ? state.serverCountError : undefined,
})}
{this.renderCard({
href: '#lookups',
@ -488,6 +537,7 @@ GROUP BY 1`,
),
error: !state.lookupsUninitialized ? state.lookupsCountError : undefined,
})}
{!state.versionLoading && this.renderStatusDialog()}
</div>
);
}