@@ -19,8 +19,7 @@ | |||
*/ | |||
import { map } from 'lodash'; | |||
import * as React from 'react'; | |||
import AlertErrorIcon from 'sonar-ui-common/components/icons/AlertErrorIcon'; | |||
import AlertSuccessIcon from 'sonar-ui-common/components/icons/AlertSuccessIcon'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { HEALTH_FIELD, STATE_FIELD } from '../../utils'; | |||
import HealthItem from './HealthItem'; | |||
@@ -29,7 +28,7 @@ export interface Props { | |||
value: T.SysInfoValue; | |||
} | |||
export default function SysInfoItem({ name, value }: Props): JSX.Element { | |||
export default function SysInfoItem({ name, value }: Props) { | |||
if (name === HEALTH_FIELD || name === STATE_FIELD) { | |||
return <HealthItem className="no-margin" health={value as T.HealthType} />; | |||
} | |||
@@ -38,35 +37,23 @@ export default function SysInfoItem({ name, value }: Props): JSX.Element { | |||
} | |||
switch (typeof value) { | |||
case 'boolean': | |||
return <BooleanItem value={value} />; | |||
return <>{translate(value ? 'yes' : 'no')}</>; | |||
case 'object': | |||
return <ObjectItem value={value} />; | |||
return ( | |||
<table className="data"> | |||
<tbody> | |||
{map(value, (v, n) => ( | |||
<tr key={n}> | |||
<td className="thin nowrap">{n}</td> | |||
<td> | |||
<SysInfoItem name={n} value={v} /> | |||
</td> | |||
</tr> | |||
))} | |||
</tbody> | |||
</table> | |||
); | |||
default: | |||
return <code>{value}</code>; | |||
} | |||
} | |||
function BooleanItem({ value }: { value: boolean }) { | |||
if (value) { | |||
return <AlertSuccessIcon />; | |||
} else { | |||
return <AlertErrorIcon />; | |||
} | |||
} | |||
function ObjectItem({ value }: { value: T.SysInfoValueObject }) { | |||
return ( | |||
<table className="data"> | |||
<tbody> | |||
{map(value, (value, name) => ( | |||
<tr key={name}> | |||
<td className="thin nowrap">{name}</td> | |||
<td> | |||
<SysInfoItem name={name} value={value} /> | |||
</td> | |||
</tr> | |||
))} | |||
</tbody> | |||
</table> | |||
); | |||
} |
@@ -19,60 +19,24 @@ | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import HealthItem from '../HealthItem'; | |||
import SysInfoItem, { Props } from '../SysInfoItem'; | |||
it('should render string', () => { | |||
expect( | |||
shallowRender('/some/path/as/an/example') | |||
.find('code') | |||
.text() | |||
).toBe('/some/path/as/an/example'); | |||
}); | |||
it('should render object', () => { | |||
expect( | |||
shallowRender({ bar: 'baz' }) | |||
.find('ObjectItem') | |||
.prop('value') | |||
).toEqual({ bar: 'baz' }); | |||
}); | |||
it('should render boolean', () => { | |||
expect( | |||
shallowRender(true) | |||
.find('BooleanItem') | |||
.prop('value') | |||
).toBe(true); | |||
it('should render correctly', () => { | |||
expect(shallowRender('/some/path/as/an/example')).toMatchSnapshot('string'); | |||
expect(shallowRender({ foo: 'Far', bar: { a: 1, b: 'b' }, baz: true })).toMatchSnapshot('object'); | |||
expect(shallowRender(true)).toMatchSnapshot('true'); | |||
expect(shallowRender(false)).toMatchSnapshot('false'); | |||
}); | |||
it('should render health item', () => { | |||
expect( | |||
shallowRender('GREEN', 'Health') | |||
.find('HealthItem') | |||
.find(HealthItem) | |||
.prop('health') | |||
).toBe('GREEN'); | |||
}); | |||
it('should render `true`', () => { | |||
const wrapper = shallowRender(true); | |||
expect(wrapper.find('BooleanItem').exists()).toBe(true); | |||
expect(wrapper.dive()).toMatchSnapshot(); | |||
}); | |||
it('should render `false`', () => { | |||
const wrapper = shallowRender(false); | |||
expect(wrapper.find('BooleanItem').exists()).toBe(true); | |||
expect(wrapper.dive()).toMatchSnapshot(); | |||
}); | |||
it('should render object correctly', () => { | |||
expect( | |||
shallowRender({ foo: 'Far', bar: { a: 1, b: 'b' }, baz: true }) | |||
.find('ObjectItem') | |||
.dive() | |||
).toMatchSnapshot(); | |||
}); | |||
function shallowRender(value: Props['value'], name: Props['name'] = 'foo') { | |||
return shallow(<SysInfoItem name={name} value={value} />); | |||
} |
@@ -1,10 +1,12 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render \`false\` 1`] = `<AlertErrorIcon />`; | |||
exports[`should render \`true\` 1`] = `<AlertSuccessIcon />`; | |||
exports[`should render correctly: false 1`] = ` | |||
<Fragment> | |||
no | |||
</Fragment> | |||
`; | |||
exports[`should render object correctly 1`] = ` | |||
exports[`should render correctly: object 1`] = ` | |||
<table | |||
className="data" | |||
> | |||
@@ -62,3 +64,15 @@ exports[`should render object correctly 1`] = ` | |||
</tbody> | |||
</table> | |||
`; | |||
exports[`should render correctly: string 1`] = ` | |||
<code> | |||
/some/path/as/an/example | |||
</code> | |||
`; | |||
exports[`should render correctly: true 1`] = ` | |||
<Fragment> | |||
yes | |||
</Fragment> | |||
`; |
@@ -46,18 +46,6 @@ | |||
background-color: var(--red); | |||
} | |||
.status-indicator.red::after { | |||
position: absolute; | |||
z-index: 3; | |||
display: block; | |||
width: 6px; | |||
height: 2px; | |||
top: 3px; | |||
left: 1px; | |||
background-color: #fff; | |||
content: ''; | |||
} | |||
.status-indicator.yellow { | |||
background-color: var(--yellow); | |||
} |
@@ -19,26 +19,31 @@ | |||
*/ | |||
import * as classNames from 'classnames'; | |||
import * as React from 'react'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import './StatusIndicator.css'; | |||
interface Props { | |||
export interface StatusIndicatorProps { | |||
className?: string; | |||
color?: string; | |||
size?: string; | |||
} | |||
export default function StatusIndicator({ className, color, size }: Props) { | |||
export default function StatusIndicator({ className, color, size }: StatusIndicatorProps) { | |||
return ( | |||
<i | |||
className={classNames( | |||
'status-indicator', | |||
color, | |||
{ | |||
'small-status-indicator': size === 'small', | |||
'big-status-indicator': size === 'big' | |||
}, | |||
className | |||
)} | |||
/> | |||
<> | |||
{color ? translate('system.current_health', color) : undefined} | |||
<i | |||
className={classNames( | |||
'spacer-left', | |||
'status-indicator', | |||
color, | |||
{ | |||
'small-status-indicator': size === 'small', | |||
'big-status-indicator': size === 'big' | |||
}, | |||
className | |||
)} | |||
/> | |||
</> | |||
); | |||
} |
@@ -0,0 +1,34 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2021 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import StatusIndicator, { StatusIndicatorProps } from '../StatusIndicator'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot('default'); | |||
expect(shallowRender({ color: 'green' })).toMatchSnapshot('green'); | |||
expect(shallowRender({ size: 'small' })).toMatchSnapshot('small'); | |||
expect(shallowRender({ size: 'big' })).toMatchSnapshot('big'); | |||
}); | |||
function shallowRender(props: Partial<StatusIndicatorProps> = {}) { | |||
return shallow<StatusIndicatorProps>(<StatusIndicator className="my-class" {...props} />); | |||
} |
@@ -0,0 +1,34 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly: big 1`] = ` | |||
<Fragment> | |||
<i | |||
className="spacer-left status-indicator big-status-indicator my-class" | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly: default 1`] = ` | |||
<Fragment> | |||
<i | |||
className="spacer-left status-indicator my-class" | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly: green 1`] = ` | |||
<Fragment> | |||
system.current_health.green | |||
<i | |||
className="spacer-left status-indicator green my-class" | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly: small 1`] = ` | |||
<Fragment> | |||
<i | |||
className="spacer-left status-indicator small-status-indicator my-class" | |||
/> | |||
</Fragment> | |||
`; |
@@ -2924,6 +2924,9 @@ system.are_you_sure_to_restart=Are you sure you want to restart the server? The | |||
system.cluster_log_level.info=Your selection affect all Application nodes but not the Search nodes. | |||
system.copy_id_info=Copy ID information | |||
system.current_health_of_x=Current health status of {0} | |||
system.current_health.green=Status is up | |||
system.current_health.yellow=Status is starting | |||
system.current_health.red=Status is down | |||
system.download_logs=Download Logs | |||
system.download_system_info=Download System Info | |||
system.download_x=Download {0} |