} as ClusterSysInfo)
).toBe('DEBUG');
});
+
+ it('should not fail if the log informations are not there yet', () => {
+ expect(
+ u.getSystemLogsLevel({
+ System: { 'High Availability': true },
+ 'Application Nodes': [{ Name: 'App 1' }, { Name: 'App 2' }]
+ } as ClusterSysInfo)
+ ).toBe('INFO');
+ expect(
+ u.getSystemLogsLevel({
+ System: { 'High Availability': true },
+ 'Application Nodes': [{ 'Compute Engine Logging': {} }, { Name: 'App 2' }]
+ } as ClusterSysInfo)
+ ).toBe('INFO');
+ expect(u.getSystemLogsLevel({ System: {} } as SysInfo)).toBe('INFO');
+ });
});
<OpenCloseIcon className="little-spacer-right" open={open} />
{this.props.name}
</span>
+ {showLogLevelWarning && (
+ <span className="alert alert-danger spacer-left">
+ {translate('system.log_level.warning.short')}
+ </span>
+ )}
{health && (
<HealthItem
biggerHealth={this.props.biggerHealth}
- className="pull-right spacer-left"
+ className="pull-right"
health={health}
healthCauses={this.props.healthCauses}
+ name={this.props.name}
/>
)}
- {showLogLevelWarning && (
- <span className="pull-right alert alert-danger">
- {translate('system.log_level.warning.short')}
- </span>
- )}
</div>
{open && (
<div
import * as classNames from 'classnames';
import HealthCauseItem from './HealthCauseItem';
import StatusIndicator from '../../../../components/common/StatusIndicator';
+import Tooltip from '../../../../components/controls/Tooltip';
import { HealthType } from '../../../../api/system';
+import { translateWithParameters } from '../../../../helpers/l10n';
interface Props {
biggerHealth?: boolean;
+ name?: string;
className?: string;
health: HealthType;
healthCauses?: string[];
}
-export default function HealthItem({ biggerHealth, className, health, healthCauses }: Props) {
+export default function HealthItem({ biggerHealth, className, name, health, healthCauses }: Props) {
const hasHealthCauses = healthCauses && healthCauses.length > 0 && health !== HealthType.GREEN;
+ const statusIndicator = (
+ <StatusIndicator color={health.toLowerCase()} size={biggerHealth ? 'big' : undefined} />
+ );
return (
<div className={classNames('system-info-health-info', className)}>
{hasHealthCauses &&
healthCauses!.map((cause, idx) => (
<HealthCauseItem key={idx} className="spacer-right" health={health} healthCause={cause} />
))}
- <StatusIndicator color={health.toLowerCase()} size={biggerHealth ? 'big' : undefined} />
+ {name ? (
+ <Tooltip
+ overlay={translateWithParameters('system.current_health_of_x', name)}
+ placement="left">
+ <span>{statusIndicator}</span>
+ </Tooltip>
+ ) : (
+ statusIndicator
+ )}
</div>
);
}
*/
import * as React from 'react';
import { map } from 'lodash';
+import CheckIcon from '../../../../components/icons-components/CheckIcon';
+import CloseIcon from '../../../../components/icons-components/CloseIcon';
import HealthItem from './HealthItem';
import { HealthType, SysValue, SysValueObject } from '../../../../api/system';
import { HEALTH_FIELD } from '../../utils';
}
export default function SysInfoItem({ name, value }: Props): JSX.Element {
- if (name === HEALTH_FIELD) {
+ if (name === HEALTH_FIELD || name === 'State') {
return <HealthItem className="no-margin" health={value as HealthType} />;
}
if (value instanceof Array) {
function BooleanItem({ value }: { value: boolean }) {
if (value) {
- return <i className="icon-check" />;
+ return <CheckIcon />;
} else {
- return <i className="icon-delete" />;
+ return <CloseIcon />;
}
}
it('should render correctly', () => {
expect(
- shallow(<HealthItem biggerHealth={true} health={HealthType.RED} healthCauses={['foo']} />)
+ shallow(
+ <HealthItem biggerHealth={true} name="Foo" health={HealthType.RED} healthCauses={['foo']} />
+ )
).toMatchSnapshot();
});
it('should render `true`', () => {
const wrapper = mount(<SysInfoItem name="test" value={true} />);
- expect(wrapper.find('.icon-check')).toHaveLength(1);
+ expect(wrapper.find('CheckIcon')).toHaveLength(1);
});
it('should render `false`', () => {
const wrapper = mount(<SysInfoItem name="test" value={false} />);
- expect(wrapper.find('.icon-delete')).toHaveLength(1);
+ expect(wrapper.find('CloseIcon')).toHaveLength(1);
});
exports[`should display the log level alert 1`] = `
<span
- className="pull-right alert alert-danger"
+ className="alert alert-danger spacer-left"
>
system.log_level.warning.short
</span>
</span>
<HealthItem
biggerHealth={true}
- className="pull-right spacer-left"
+ className="pull-right"
health="RED"
healthCauses={
Array [
"foo",
]
}
+ name="Foobar"
/>
</div>
<div
</span>
<HealthItem
biggerHealth={false}
- className="pull-right spacer-left"
+ className="pull-right"
health="RED"
healthCauses={
Array [
"foo",
]
}
+ name="Foobar"
/>
</div>
</li>
</span>
<HealthItem
biggerHealth={false}
- className="pull-right spacer-left"
+ className="pull-right"
health="RED"
healthCauses={
Array [
"foo",
]
}
+ name="Foobar"
/>
</div>
<div
health="RED"
healthCause="foo"
/>
- <StatusIndicator
- color="red"
- size="big"
- />
+ <Tooltip
+ overlay="system.current_health_of_x.Foo"
+ placement="left"
+ >
+ <span>
+ <StatusIndicator
+ color="red"
+ size="big"
+ />
+ </span>
+ </Tooltip>
</div>
`;
<BooleanItem
value={true}
>
- <i
- className="icon-check"
- />
+ <CheckIcon>
+ <svg
+ height={16}
+ viewBox="0 0 16 16"
+ width={16}
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d="M14.92 4.804q0 0.357-0.25 0.607l-7.679 7.679q-0.25 0.25-0.607 0.25t-0.607-0.25l-4.446-4.446q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.634 5.857-5.866q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607z"
+ style={
+ Object {
+ "fill": "currentColor",
+ }
+ }
+ />
+ ;
+ </svg>
+ </CheckIcon>
</BooleanItem>
</SysInfoItem>
</td>
}
.system-info-health-card .boxed-group-header > .alert {
- margin-top: -6px;
+ display: inline-block;
+ margin-bottom: -3px;
+ margin-top: -3px;
}
.system-info-health-card .boxed-group-inner {
export const HA_FIELD = 'High Availability';
export const HEALTH_FIELD = 'Health';
export const HEALTHCAUSES_FIELD = 'Health Causes';
+export const PLUGINS_FIELD = 'Plugins';
+export const SETTINGS_FIELD = 'Settings';
export function ignoreInfoFields(sysInfoObject: SysValueObject): SysValueObject {
- return omit(sysInfoObject, [HEALTH_FIELD, HEALTHCAUSES_FIELD, 'Name', 'Settings']);
+ return omit(sysInfoObject, [HEALTH_FIELD, HEALTHCAUSES_FIELD, 'Name', SETTINGS_FIELD]);
}
export function getHealth(sysInfoObject: SysValueObject): HealthType {
return sysInfoObject[HEALTHCAUSES_FIELD] as string[];
}
-export function getLogsLevel(sysInfoObject: SysValueObject): string {
- if (sysInfoObject['Web Logging']) {
+export function getLogsLevel(sysInfoObject?: SysValueObject): string {
+ if (!sysInfoObject) {
+ return LOGS_LEVELS[0];
+ }
+ if (sysInfoObject['Web Logging'] || sysInfoObject['Compute Engine Logging']) {
return sortBy(
[
- (sysInfoObject as NodeInfo)['Compute Engine Logging']['Logs Level'],
- (sysInfoObject as NodeInfo)['Web Logging']['Logs Level']
+ getLogsLevel((sysInfoObject as NodeInfo)['Web Logging']),
+ getLogsLevel((sysInfoObject as NodeInfo)['Compute Engine Logging'])
],
logLevel => LOGS_LEVELS.indexOf(logLevel)
)[1];
}
if (sysInfoObject['System']) {
- return (sysInfoObject as SysInfo)['System']['Logs Level'];
+ return getLogsLevel((sysInfoObject as SysInfo)['System']);
}
return (sysInfoObject['Logs Level'] || LOGS_LEVELS[0]) as string;
}
...sysInfoData['System'],
...omit(sysInfoData, [
'Application Nodes',
- 'Plugins',
+ PLUGINS_FIELD,
'Search Nodes',
- 'Settings',
+ SETTINGS_FIELD,
'Statistics',
'System'
])
sysInfoData,
(value, key) =>
value == null ||
- ['Plugins', 'Settings', 'Statistics', 'System'].includes(key) ||
+ [PLUGINS_FIELD, SETTINGS_FIELD, 'Statistics', 'System'].includes(key) ||
key.startsWith('Compute Engine') ||
key.startsWith('Search') ||
key.startsWith('Web')
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 * as React from 'react';
+
+interface Props {
+ className?: string;
+ size?: number;
+}
+
+export default function CheckIcon({ className, size = 16 }: Props) {
+ return (
+ <svg
+ className={className}
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 16 16"
+ width={size}
+ height={size}>
+ <path
+ style={{ fill: 'currentColor' }}
+ d="M14.92 4.804q0 0.357-0.25 0.607l-7.679 7.679q-0.25 0.25-0.607 0.25t-0.607-0.25l-4.446-4.446q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.634 5.857-5.866q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607z"
+ />;
+ </svg>
+ );
+}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2017 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.
- */
-// @flow
-import React from 'react';
-
-/*::
-type Props = { className?: string, size?: number };
-*/
-
-export default function CloseIcon({ className, size = 16 } /*: Props */) {
- /* eslint-disable max-len */
- return (
- <svg
- xmlns="http://www.w3.org/2000/svg"
- className={className}
- height={size}
- width={size}
- viewBox="0 0 16 16">
- <path
- fill="currentColor"
- d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
- />
- </svg>
- );
-}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2017 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 * as React from 'react';
+
+interface Props {
+ className?: string;
+ size?: number;
+}
+
+export default function CloseIcon({ className, size = 16 }: Props) {
+ return (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ className={className}
+ height={size}
+ width={size}
+ viewBox="0 0 16 16">
+ <path
+ fill="currentColor"
+ d="M12.843 11.232q0 0.357-0.25 0.607l-1.214 1.214q-0.25 0.25-0.607 0.25t-0.607-0.25l-2.625-2.625-2.625 2.625q-0.25 0.25-0.607 0.25t-0.607-0.25l-1.214-1.214q-0.25-0.25-0.25-0.607t0.25-0.607l2.625-2.625-2.625-2.625q-0.25-0.25-0.25-0.607t0.25-0.607l1.214-1.214q0.25-0.25 0.607-0.25t0.607 0.25l2.625 2.625 2.625-2.625q0.25-0.25 0.607-0.25t0.607 0.25l1.214 1.214q0.25 0.25 0.25 0.607t-0.25 0.607l-2.625 2.625 2.625 2.625q0.25 0.25 0.25 0.607z"
+ />
+ </svg>
+ );
+}
import _BugIcon from './BugIcon';
import _ChangeIcon from './ChangeIcon';
import _ChartLegendIcon from './ChartLegendIcon';
+import _CheckIcon from './CheckIcon';
import _CloseIcon from './CloseIcon';
import _CodeSmellIcon from './CodeSmellIcon';
import _DeleteIcon from './DeleteIcon';
export const BugIcon = _BugIcon;
export const ChangeIcon = _ChangeIcon;
export const ChartLegendIcon = _ChartLegendIcon;
+export const CheckIcon = _CheckIcon;
export const CloseIcon = _CloseIcon;
export const CodeSmellIcon = _CodeSmellIcon;
export const DeleteIcon = _DeleteIcon;
system.application_nodes_title=Application Nodes
system.are_you_sure_to_restart=Are you sure you want to restart the server?
system.cluster_log_level.info=Changes apply to all Application nodes but not to Search nodes.
+system.current_health_of_x=Current health status of {1}
system.download_logs=Download Logs
system.download_system_info=Download System Info
system.is_restarting=Server is restarting. This page will be automatically refreshed.