diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-05-07 13:01:01 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-05-09 20:21:09 +0200 |
commit | 2f02c40ef393c1cd20adc69d53409d31fc739ef8 (patch) | |
tree | 0c8852c557db9a29ebfb2e2e7177ab22ca05eaa6 /server/sonar-web/src/main/js/apps/system | |
parent | 3831ff61b755d3e419d46d2491afd8b037bc5089 (diff) | |
download | sonarqube-2f02c40ef393c1cd20adc69d53409d31fc739ef8.tar.gz sonarqube-2f02c40ef393c1cd20adc69d53409d31fc739ef8.zip |
SONAR-11938 Remove Server ID and Version from system information
Diffstat (limited to 'server/sonar-web/src/main/js/apps/system')
25 files changed, 622 insertions, 308 deletions
diff --git a/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts index d94d51599ec..22247758f54 100644 --- a/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts +++ b/server/sonar-web/src/main/js/apps/system/__tests__/utils-test.ts @@ -17,8 +17,9 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +/* eslint-disable sonarjs/no-duplicate-string */ import * as u from '../utils'; -import { ClusterSysInfo, SysInfo, SystemUpgrade } from '../../../api/system'; +import { mockClusterSysInfo, mockStandaloneSysInfo } from '../../../helpers/testMocks'; describe('parseQuery', () => { it('should correctly parse the expand array', () => { @@ -44,44 +45,30 @@ describe('groupSections', () => { }); describe('getSystemLogsLevel', () => { - it('should correctly return log level for standalone mode', () => { - expect(u.getSystemLogsLevel({ System: { 'Logs Level': 'FOO' } } as SysInfo)).toBe('FOO'); - expect(u.getSystemLogsLevel({} as SysInfo)).toBe('INFO'); - expect(u.getSystemLogsLevel()).toBe('INFO'); + it('should correctly return the worst log level for standalone mode', () => { + expect(u.getSystemLogsLevel(mockStandaloneSysInfo())).toBe('DEBUG'); }); it('should return the worst log level for cluster mode', () => { - expect( - u.getSystemLogsLevel({ - System: { 'High Availability': true }, - 'Application Nodes': [ - { - 'Compute Engine Logging': { 'Logs Level': 'DEBUG' }, - 'Web Logging': { 'Logs Level': 'INFO' } - }, - { - 'Compute Engine Logging': { 'Logs Level': 'INFO' }, - 'Web Logging': { 'Logs Level': 'INFO' } - } - ] - } as ClusterSysInfo) - ).toBe('DEBUG'); + expect(u.getSystemLogsLevel(mockClusterSysInfo())).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) + u.getSystemLogsLevel( + mockClusterSysInfo({ + 'Application Nodes': [{ Name: 'App 1' }, { Name: 'App 2' }] + }) + ) ).toBe('INFO'); expect( - u.getSystemLogsLevel({ - System: { 'High Availability': true }, - 'Application Nodes': [{ 'Compute Engine Logging': {} }, { Name: 'App 2' }] - } as any) + u.getSystemLogsLevel( + mockClusterSysInfo({ + 'Application Nodes': [{ 'Compute Engine Logging': {} }, { Name: 'App 2' }] + }) + ) ).toBe('INFO'); - expect(u.getSystemLogsLevel({ System: {} } as SysInfo)).toBe('INFO'); + expect(u.getSystemLogsLevel({} as T.SysInfoStandalone)).toBe('INFO'); }); }); @@ -93,7 +80,7 @@ describe('sortUpgrades', () => { { version: '5.10' }, { version: '5.1' }, { version: '5.4' } - ] as SystemUpgrade[]) + ] as T.SystemUpgrade[]) ).toEqual([{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }]); expect( u.sortUpgrades([ @@ -101,7 +88,7 @@ describe('sortUpgrades', () => { { version: '5.1.2' }, { version: '6.0' }, { version: '6.9' } - ] as SystemUpgrade[]) + ] as T.SystemUpgrade[]) ).toEqual([{ version: '6.9' }, { version: '6.0' }, { version: '5.10' }, { version: '5.1.2' }]); }); }); @@ -114,7 +101,7 @@ describe('groupUpgrades', () => { { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' } - ] as SystemUpgrade[]) + ] as T.SystemUpgrade[]) ).toEqual([ [{ version: '5.10' }, { version: '5.4.2' }, { version: '5.4' }, { version: '5.1' }] ]); @@ -125,10 +112,186 @@ describe('groupUpgrades', () => { { version: '6.0' }, { version: '5.10' }, { version: '5.4.2' } - ] as SystemUpgrade[]) + ] as T.SystemUpgrade[]) ).toEqual([ [{ version: '6.9' }, { version: '6.7' }, { version: '6.0' }], [{ version: '5.10' }, { version: '5.4.2' }] ]); }); }); + +describe('isCluster', () => { + it('should return the correct information', () => { + expect(u.isCluster(mockClusterSysInfo())).toBe(true); + expect(u.isCluster(mockStandaloneSysInfo())).toBe(false); + }); +}); + +describe('isLogInfoBlock', () => { + it('should return the correct information', () => { + expect(u.isLogInfoBlock(mockStandaloneSysInfo().System)).toBe(false); + expect(u.isLogInfoBlock(mockStandaloneSysInfo()['Web Logging'])).toBe(true); + }); +}); + +describe('hasLoggingInfo', () => { + it('should return the correct information', () => { + expect(u.hasLoggingInfo(mockStandaloneSysInfo())).toBe(true); + expect(u.hasLoggingInfo(mockClusterSysInfo()['Application Nodes'][0])).toBe(true); + expect(u.hasLoggingInfo(mockClusterSysInfo())).toBe(false); + }); +}); + +describe('getStandaloneSecondarySections', () => { + it('should return the correct information', () => { + expect(Object.keys(u.getStandaloneSecondarySections(mockStandaloneSysInfo()))).toEqual( + expect.arrayContaining(['Compute Engine', 'Search Engine', 'Web']) + ); + expect(Object.keys(u.getStandaloneSecondarySections(mockClusterSysInfo()))).toEqual( + expect.arrayContaining(['Compute Engine', 'Search Engine', 'Web']) + ); + }); +}); + +describe('getStandaloneMainSections', () => { + it('should return the correct information', () => { + expect(Object.keys(u.getStandaloneMainSections(mockStandaloneSysInfo()))).toEqual( + expect.arrayContaining([ + 'Server ID', + 'High Availability', + 'Health', + 'Health Causes', + 'Database' + ]) + ); + }); +}); + +describe('getClusterMainCardSection', () => { + it('should return the correct information', () => { + expect(Object.keys(u.getClusterMainCardSection(mockClusterSysInfo()))).toEqual( + expect.arrayContaining([ + 'Server ID', + 'High Availability', + 'Lines of Code', + 'Health', + 'Health Causes', + 'Database', + 'Compute Engine Tasks', + 'Search State', + 'Search Indexes' + ]) + ); + }); +}); + +describe('getSearchNodes', () => { + it('should return the correct information', () => { + expect( + u.getSearchNodes( + mockClusterSysInfo({ + 'Search Nodes': [{ Name: 'searchnode1' }] + }) + ) + ).toEqual([{ Name: 'searchnode1' }]); + }); +}); + +describe('getAppNodes', () => { + it('should return the correct information', () => { + expect( + u.getAppNodes( + mockClusterSysInfo({ + 'Application Nodes': [{ Name: 'appnode1' }] + }) + ) + ).toEqual([{ Name: 'appnode1' }]); + }); +}); + +describe('getNodeName', () => { + it('should return the correct information', () => { + expect(u.getNodeName({ Name: 'Foo' })).toEqual('Foo'); + }); +}); + +describe('getHealthCauses', () => { + it('should return the correct information', () => { + expect(u.getHealthCauses({ 'Health Causes': ['Foo'] } as T.SysInfoBase)).toEqual(['Foo']); + }); +}); + +describe('getHealth', () => { + it('should return the correct information', () => { + expect(u.getHealth({ Health: 'GREEN' } as T.SysInfoBase)).toEqual('GREEN'); + }); +}); + +describe('getLogsLevel', () => { + it('should return the correct information, if available', () => { + expect(u.getLogsLevel({ 'Compute Engine Logging': { 'Logs Level': 'TRACE' } })).toEqual( + 'TRACE' + ); + }); + + it('should return the worst level', () => { + expect( + u.getLogsLevel({ + 'Web Logging': { 'Logs Level': 'DEBUG' }, + 'Compute Engine Logging': { 'Logs Level': 'TRACE' } + }) + ).toEqual('TRACE'); + }); + + it('should return the default level if no information is provided', () => { + expect(u.getLogsLevel()).toEqual('INFO'); + }); +}); + +describe('getServerId', () => { + it('should return the correct information, if available', () => { + expect(u.getServerId(mockStandaloneSysInfo({ System: { 'Server ID': 'foo-bar' } }))).toEqual( + 'foo-bar' + ); + }); + + it('should return undefined if no information is available', () => { + expect(u.getServerId(mockStandaloneSysInfo({ System: {} }))).toBeUndefined(); + }); +}); + +describe('getVersion', () => { + it('should return the correct information, if available', () => { + expect(u.getVersion(mockStandaloneSysInfo({ System: { Version: '1.0' } }))).toEqual('1.0'); + }); + + it('should return undefined if no information is available', () => { + expect(u.getVersion(mockStandaloneSysInfo({ System: {} }))).toBeUndefined(); + }); +}); + +describe('getClusterVersion', () => { + it('should return the correct information, if available', () => { + expect( + u.getClusterVersion( + mockClusterSysInfo({ + 'Application Nodes': [{ System: { Version: '1.0' } }] + }) + ) + ).toEqual('1.0'); + }); + + it('should return undefined if no information is available', () => { + expect( + u.getClusterVersion(mockClusterSysInfo({ 'Application Nodes': [{ System: {} }] })) + ).toBeUndefined(); + expect( + u.getClusterVersion( + mockClusterSysInfo({ + 'Application Nodes': [], + System: { Version: '1.0' } + }) + ) + ).toBeUndefined(); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/system/components/App.tsx b/server/sonar-web/src/main/js/apps/system/components/App.tsx index b90b28493f3..07cec002e46 100644 --- a/server/sonar-web/src/main/js/apps/system/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/App.tsx @@ -26,14 +26,16 @@ import StandaloneSysInfos from './StandaloneSysInfos'; import SystemUpgradeNotif from './system-upgrade/SystemUpgradeNotif'; import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import { translate } from '../../../helpers/l10n'; -import { ClusterSysInfo, getSystemInfo, SysInfo } from '../../../api/system'; +import { getSystemInfo } from '../../../api/system'; import { getServerId, getSystemLogsLevel, isCluster, parseQuery, Query, - serializeQuery + serializeQuery, + getVersion, + getClusterVersion } from '../utils'; import '../styles.css'; @@ -41,7 +43,7 @@ type Props = WithRouterProps; interface State { loading: boolean; - sysInfoData?: SysInfo; + sysInfoData?: T.SysInfoCluster | T.SysInfoStandalone; } class App extends React.PureComponent<Props, State> { @@ -60,7 +62,7 @@ class App extends React.PureComponent<Props, State> { fetchSysInfo = () => { this.setState({ loading: true }); getSystemInfo().then( - (sysInfoData: SysInfo) => { + sysInfoData => { if (this.mounted) { this.setState({ loading: false, sysInfoData }); } @@ -100,7 +102,7 @@ class App extends React.PureComponent<Props, State> { return ( <ClusterSysInfos expandedCards={query.expandedCards} - sysInfoData={sysInfoData as ClusterSysInfo} + sysInfoData={sysInfoData} toggleCard={this.toggleSysInfoCards} /> ); @@ -121,14 +123,19 @@ class App extends React.PureComponent<Props, State> { <Suggestions suggestions="system_info" /> <Helmet title={translate('system_info.page')} /> <SystemUpgradeNotif /> - <PageHeader - isCluster={isCluster(sysInfoData)} - loading={loading} - logLevel={getSystemLogsLevel(sysInfoData)} - onLogLevelChange={this.fetchSysInfo} - serverId={getServerId(sysInfoData)} - showActions={sysInfoData !== undefined} - /> + {sysInfoData && ( + <PageHeader + isCluster={isCluster(sysInfoData)} + loading={loading} + logLevel={getSystemLogsLevel(sysInfoData)} + onLogLevelChange={this.fetchSysInfo} + serverId={getServerId(sysInfoData)} + showActions={sysInfoData !== undefined} + version={ + isCluster(sysInfoData) ? getClusterVersion(sysInfoData) : getVersion(sysInfoData) + } + /> + )} {this.renderSysInfo()} </div> ); diff --git a/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx b/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx index 7231c753b25..2a86c77b1c3 100644 --- a/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/ClusterSysInfos.tsx @@ -21,7 +21,6 @@ import * as React from 'react'; import { sortBy } from 'lodash'; import HealthCard from './info-items/HealthCard'; import { translate } from '../../../helpers/l10n'; -import { ClusterSysInfo } from '../../../api/system'; import { getAppNodes, getHealth, @@ -34,7 +33,7 @@ import { interface Props { expandedCards: string[]; - sysInfoData: ClusterSysInfo; + sysInfoData: T.SysInfoCluster; toggleCard: (toggledCard: string) => void; } @@ -54,7 +53,7 @@ export default function ClusterSysInfos({ expandedCards, sysInfoData, toggleCard <li className="note system-info-health-title"> {translate('system.application_nodes_title')} </li> - {sortBy(getAppNodes(sysInfoData), getNodeName).map(node => ( + {sortBy(getAppNodes(sysInfoData), getNodeName).map((node: T.SysInfoAppNode) => ( <HealthCard health={getHealth(node)} healthCauses={getHealthCauses(node)} @@ -66,10 +65,8 @@ export default function ClusterSysInfos({ expandedCards, sysInfoData, toggleCard /> ))} <li className="note system-info-health-title">{translate('system.search_nodes_title')}</li> - {sortBy(getSearchNodes(sysInfoData), getNodeName).map(node => ( + {sortBy(getSearchNodes(sysInfoData), getNodeName).map((node: T.SysInfoSearchNode) => ( <HealthCard - health={getHealth(node)} - healthCauses={getHealthCauses(node)} key={getNodeName(node)} name={getNodeName(node)} onClick={toggleCard} diff --git a/server/sonar-web/src/main/js/apps/system/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/system/components/PageHeader.tsx index bc55969fc2a..3816eb2cb02 100644 --- a/server/sonar-web/src/main/js/apps/system/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/PageHeader.tsx @@ -19,36 +19,71 @@ */ import * as React from 'react'; import PageActions from './PageActions'; +import ClipboardButton from '../../../components/controls/ClipboardButton'; import { translate } from '../../../helpers/l10n'; +import { toShortNotSoISOString } from '../../../helpers/dates'; -interface Props { +export interface Props { isCluster: boolean; loading: boolean; logLevel: string; onLogLevelChange: () => void; serverId?: string; showActions: boolean; + version?: string; } export default function PageHeader(props: Props) { + const { isCluster, loading, logLevel, serverId, showActions, version } = props; return ( <header className="page-header"> <h1 className="page-title">{translate('system_info.page')}</h1> - {props.showActions && ( + {showActions && ( <PageActions - canDownloadLogs={!props.isCluster} - canRestart={!props.isCluster} - cluster={props.isCluster} - logLevel={props.logLevel} + canDownloadLogs={!isCluster} + canRestart={!isCluster} + cluster={isCluster} + logLevel={logLevel} onLogLevelChange={props.onLogLevelChange} - serverId={props.serverId} + serverId={serverId} /> )} - {props.loading && ( + {loading && ( <div className="page-actions"> <i className="spinner" /> </div> )} + {serverId && version && ( + <div className="system-info-copy-paste-id-info boxed-group display-flex-center"> + <div className="flex-1"> + <table className="width-100"> + <tbody> + <tr> + <th> + <strong>{translate('system.server_id')}</strong> + </th> + <td>{serverId}</td> + </tr> + <tr> + <th> + <strong>{translate('system.version')}</strong> + </th> + <td>{version}</td> + </tr> + </tbody> + </table> + </div> + <ClipboardButton + className="flex-0" + copyValue={`SonarQube ID information +Server ID: ${serverId} +Version: ${version} +Date: ${toShortNotSoISOString(Date.now())} +`} + label={translate('system.copy_id_info')} + /> + </div> + )} </header> ); } diff --git a/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx b/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx index e0ba16fe754..adb9db52ec5 100644 --- a/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/StandaloneSysInfos.tsx @@ -20,7 +20,6 @@ import * as React from 'react'; import { map } from 'lodash'; import HealthCard from './info-items/HealthCard'; -import { SysInfo } from '../../../api/system'; import { getHealth, getHealthCauses, @@ -31,7 +30,7 @@ import { interface Props { expandedCards: string[]; - sysInfoData: SysInfo; + sysInfoData: T.SysInfoStandalone; toggleCard: (toggledCard: string) => void; } diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx index ed0b62b7dc3..395f5bf30ac 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/ClusterSysInfos-test.tsx @@ -20,78 +20,74 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import ClusterSysInfos from '../ClusterSysInfos'; -import { ClusterSysInfo, HealthType } from '../../../../api/system'; - -const sysInfoData: ClusterSysInfo = { - Health: HealthType.RED, - 'Health Causes': ['Database down'], - 'Application Nodes': [ - { - Name: 'Bar', - Health: HealthType.GREEN, - 'Health Causes': [], - 'Compute Engine Logging': { 'Logs Level': 'INFO' }, - 'Web Logging': { 'Logs Level': 'INFO' } - } - ], - 'Search Nodes': [ - { - Name: 'Baz', - Health: HealthType.YELLOW, - 'Health Causes': [], - 'Compute Engine Logging': { 'Logs Level': 'INFO' }, - 'Web Logging': { 'Logs Level': 'INFO' } - } - ], - System: { - 'High Availability': true, - 'Logs Level': 'INFO', - 'Server ID': 'MyServerId' - } -}; +import { mockClusterSysInfo } from '../../../../helpers/testMocks'; it('should render correctly', () => { expect( - getWrapper({ - sysInfoData: { - ...sysInfoData, + shallowRender( + mockClusterSysInfo({ + sysInfoData: { + Health: 'RED', + 'Health Causes': ['Database down'], + 'Application Nodes': [ + { + Name: 'Foo', + Health: 'GREEN', + 'Health Causes': [], + 'Compute Engine Logging': { 'Logs Level': 'INFO' }, + 'Web Logging': { 'Logs Level': 'INFO' } + }, + { + Name: 'Bar', + Health: 'RED', + 'Health Causes': [], + 'Compute Engine Logging': { 'Logs Level': 'INFO' }, + 'Web Logging': { 'Logs Level': 'DEBUG' } + }, + { + Name: 'Baz', + Health: 'YELLOW', + 'Health Causes': [], + 'Compute Engine Logging': { 'Logs Level': 'TRACE' }, + 'Web Logging': { 'Logs Level': 'DEBUG' } + } + ] + } + }) + ).find('HealthCard') + ).toHaveLength(4); +}); + +it('should support more than two nodes', () => { + expect(shallowRender()).toMatchSnapshot(); +}); + +function shallowRender(props = {}) { + return shallow( + <ClusterSysInfos + expandedCards={['System', 'Foo']} + sysInfoData={mockClusterSysInfo({ + Health: 'RED', + 'Health Causes': ['Database down'], 'Application Nodes': [ { - Name: 'Foo', - Health: HealthType.GREEN, - 'Health Causes': [], - 'Compute Engine Logging': { 'Logs Level': 'INFO' }, - 'Web Logging': { 'Logs Level': 'INFO' } - }, - { Name: 'Bar', - Health: HealthType.RED, + Health: 'GREEN', 'Health Causes': [], 'Compute Engine Logging': { 'Logs Level': 'INFO' }, - 'Web Logging': { 'Logs Level': 'DEBUG' } - }, + 'Web Logging': { 'Logs Level': 'INFO' } + } + ], + 'Search Nodes': [ { Name: 'Baz', - Health: HealthType.YELLOW, + Health: 'YELLOW', 'Health Causes': [], - 'Compute Engine Logging': { 'Logs Level': 'TRACE' }, - 'Web Logging': { 'Logs Level': 'DEBUG' } + 'Compute Engine Logging': { 'Logs Level': 'INFO' }, + 'Web Logging': { 'Logs Level': 'INFO' } } ] - } - }).find('HealthCard') - ).toHaveLength(5); -}); - -it('should support more than two nodes', () => { - expect(getWrapper()).toMatchSnapshot(); -}); - -function getWrapper(props = {}) { - return shallow( - <ClusterSysInfos - expandedCards={['System', 'Foo']} - sysInfoData={sysInfoData} + })} toggleCard={() => {}} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/PageHeader-test.tsx index 0164cc044eb..382169ee3b9 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/PageHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/PageHeader-test.tsx @@ -19,32 +19,27 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import PageHeader from '../PageHeader'; +import PageHeader, { Props } from '../PageHeader'; + +jest.mock('../../../../helpers/dates', () => ({ + toShortNotSoISOString: () => '2019-01-01' +})); it('should render correctly', () => { - expect( - shallow( - <PageHeader - isCluster={true} - loading={false} - logLevel="INFO" - onLogLevelChange={() => {}} - showActions={true} - /> - ) - ).toMatchSnapshot(); + expect(shallowRender()).toMatchSnapshot(); + expect(shallowRender({ loading: true, showActions: false })).toMatchSnapshot(); + expect(shallowRender({ serverId: 'foo-bar', version: '7.7.0.1234' })).toMatchSnapshot(); }); -it('should show a loading spinner and no actions', () => { - expect( - shallow( - <PageHeader - isCluster={true} - loading={true} - logLevel="INFO" - onLogLevelChange={() => {}} - showActions={false} - /> - ) - ).toMatchSnapshot(); -}); +function shallowRender(props: Partial<Props> = {}) { + return shallow( + <PageHeader + isCluster={true} + loading={false} + logLevel="INFO" + onLogLevelChange={jest.fn()} + showActions={true} + {...props} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx b/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx index 69a40917cb5..e7bec64929e 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/StandaloneSysInfos-test.tsx @@ -20,20 +20,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import StandaloneSysInfos from '../StandaloneSysInfos'; -import { HealthType, SysInfo } from '../../../../api/system'; - -const sysInfoData: SysInfo = { - Health: HealthType.RED, - 'Health Causes': ['Database down'], - 'Web JVM': { 'Max Memory': '2Gb' }, - 'Compute Engine': { Pending: 4 }, - Search: { 'Number of Nodes': 1 }, - System: { - 'High Availability': true, - 'Logs Level': 'DEBUG', - 'Server ID': 'MyServerId' - } -}; +import { mockStandaloneSysInfo } from '../../../../helpers/testMocks'; it('should render correctly', () => { expect(getWrapper()).toMatchSnapshot(); @@ -43,7 +30,7 @@ function getWrapper(props = {}) { return shallow( <StandaloneSysInfos expandedCards={['Compute Engine', 'Foo']} - sysInfoData={sysInfoData} + sysInfoData={mockStandaloneSysInfo({ Health: 'RED', 'Health Causes': ['Database down'] })} toggleCard={() => {}} {...props} /> diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap index 580f6979534..a186f4110d3 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/ClusterSysInfos-test.tsx.snap @@ -15,9 +15,28 @@ exports[`should support more than two nodes 1`] = ` open={true} sysInfoData={ Object { + "Compute Engine Tasks": Object { + "Total In Progress": 0, + "Total Pending": 0, + }, + "Database": Object { + "Database": "PostgreSQL", + "Database Version": "10.3", + "Driver": "PostgreSQL JDBC Driver", + "Driver Version": "42.2.5", + "URL": "jdbc:postgresql://localhost/sonar", + "Username": "sonar", + }, "High Availability": true, - "Logs Level": "INFO", - "Server ID": "MyServerId", + "Lines of Code": "989,880", + "Search Indexes": Object { + "Index components - Docs": 30445, + "Index components - Shards": 10, + }, + "Search State": Object { + "Nodes": 3, + "State": "GREEN", + }, } } /> @@ -50,8 +69,6 @@ exports[`should support more than two nodes 1`] = ` system.search_nodes_title </li> <HealthCard - health="YELLOW" - healthCauses={Array []} key="Baz" name="Baz" onClick={[Function]} diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageHeader-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageHeader-test.tsx.snap index 39f93da4322..84f459faba7 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/PageHeader-test.tsx.snap @@ -14,12 +14,12 @@ exports[`should render correctly 1`] = ` canRestart={false} cluster={true} logLevel="INFO" - onLogLevelChange={[Function]} + onLogLevelChange={[MockFunction]} /> </header> `; -exports[`should show a loading spinner and no actions 1`] = ` +exports[`should render correctly 2`] = ` <header className="page-header" > @@ -37,3 +37,66 @@ exports[`should show a loading spinner and no actions 1`] = ` </div> </header> `; + +exports[`should render correctly 3`] = ` +<header + className="page-header" +> + <h1 + className="page-title" + > + system_info.page + </h1> + <PageActions + canDownloadLogs={false} + canRestart={false} + cluster={true} + logLevel="INFO" + onLogLevelChange={[MockFunction]} + serverId="foo-bar" + /> + <div + className="system-info-copy-paste-id-info boxed-group display-flex-center" + > + <div + className="flex-1" + > + <table + className="width-100" + > + <tbody> + <tr> + <th> + <strong> + system.server_id + </strong> + </th> + <td> + foo-bar + </td> + </tr> + <tr> + <th> + <strong> + system.version + </strong> + </th> + <td> + 7.7.0.1234 + </td> + </tr> + </tbody> + </table> + </div> + <ClipboardButton + className="flex-0" + copyValue="SonarQube ID information +Server ID: foo-bar +Version: 7.7.0.1234 +Date: 2019-01-01 +" + label="system.copy_id_info" + /> + </div> +</header> +`; diff --git a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap index b71406e8fba..0d5a69d87e1 100644 --- a/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/system/components/__tests__/__snapshots__/StandaloneSysInfos-test.tsx.snap @@ -15,9 +15,15 @@ exports[`should render correctly 1`] = ` open={false} sysInfoData={ Object { - "High Availability": true, - "Logs Level": "DEBUG", - "Server ID": "MyServerId", + "Database": Object { + "Database": "PostgreSQL", + "Database Version": "10.3", + "Driver": "PostgreSQL JDBC Driver", + "Driver Version": "42.2.5", + "URL": "jdbc:postgresql://localhost/sonar", + "Username": "sonar", + }, + "High Availability": false, } } /> @@ -28,8 +34,21 @@ exports[`should render correctly 1`] = ` open={false} sysInfoData={ Object { - "Web JVM": Object { - "Max Memory": "2Gb", + "Web Database Connection": Object { + "Pool Active Connections": 0, + "Pool Max Connections": 60, + }, + "Web JVM Properties": Object { + "file.encoding": "UTF-8", + "file.separator": "/", + }, + "Web JVM State": Object { + "Free Memory (MB)": 111, + "Max Memory (MB)": 1024, + }, + "Web Logging": Object { + "Logs Dir": "/logs", + "Logs Level": "INFO", }, } } @@ -41,8 +60,25 @@ exports[`should render correctly 1`] = ` open={true} sysInfoData={ Object { - "Compute Engine": Object { - "Pending": 4, + "Compute Engine Database Connection": Object { + "Pool Active Connections": 0, + "Pool Initial Size": 0, + }, + "Compute Engine JVM Properties": Object { + "file.encoding": "UTF-8", + "file.separator": "/", + }, + "Compute Engine JVM State": Object { + "Free Memory (MB)": 89, + "Max Memory (MB)": 1024, + }, + "Compute Engine Logging": Object { + "Logs Dir": "/logs", + "Logs Level": "DEBUG", + }, + "Compute Engine Tasks": Object { + "In Progress": 0, + "Pending": 0, }, } } @@ -54,8 +90,13 @@ exports[`should render correctly 1`] = ` open={false} sysInfoData={ Object { - "Search": Object { - "Number of Nodes": 1, + "Search Indexes": Object { + "Index components - Docs": 30445, + "Index components - Shards": 10, + }, + "Search State": Object { + "Nodes": 3, + "State": "GREEN", }, } } diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx index f6e21f1b189..95e3d72aef6 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCard.tsx @@ -21,20 +21,19 @@ import * as React from 'react'; import { map } from 'lodash'; import HealthItem from './HealthItem'; import Section from './Section'; +import { Alert } from '../../../../components/ui/Alert'; import BoxedGroupAccordion from '../../../../components/controls/BoxedGroupAccordion'; -import { HealthType, SysValueObject } from '../../../../api/system'; import { LOGS_LEVELS, groupSections, getLogsLevel } from '../../utils'; import { translate } from '../../../../helpers/l10n'; -import { Alert } from '../../../../components/ui/Alert'; interface Props { biggerHealth?: boolean; - health?: HealthType; + health?: T.HealthType; healthCauses?: string[]; onClick: (toggledCard: string) => void; open: boolean; name: string; - sysInfoData: SysValueObject; + sysInfoData: T.SysInfoValueObject; } export default function HealthCard({ diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx index 04c416e1338..79ebc2e1ca4 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthCauseItem.tsx @@ -19,12 +19,11 @@ */ import * as React from 'react'; import * as classNames from 'classnames'; -import { HealthType } from '../../../../api/system'; import { Alert } from '../../../../components/ui/Alert'; interface Props { className?: string; - health: HealthType; + health: T.HealthType; healthCause: string; } @@ -33,7 +32,7 @@ export default function HealthCauseItem({ className, health, healthCause }: Prop <Alert className={classNames('boxed-group-accordion-alert', className)} display="inline" - variant={health === HealthType.RED ? 'error' : 'warning'}> + variant={health === 'RED' ? 'error' : 'warning'}> {healthCause} </Alert> ); diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx index 1b71f37fce3..e5291e8c1be 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/HealthItem.tsx @@ -22,19 +22,18 @@ 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; + health: T.HealthType; healthCauses?: string[]; } export default function HealthItem({ biggerHealth, className, name, health, healthCauses }: Props) { - const hasHealthCauses = healthCauses && healthCauses.length > 0 && health !== HealthType.GREEN; + const hasHealthCauses = healthCauses && healthCauses.length > 0 && health !== 'GREEN'; const statusIndicator = ( <StatusIndicator color={health.toLowerCase()} size={biggerHealth ? 'big' : undefined} /> ); diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/Section.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/Section.tsx index a40845a12a3..b548e94afa9 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/Section.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/Section.tsx @@ -20,11 +20,10 @@ import * as React from 'react'; import { map } from 'lodash'; import SysInfoItem from './SysInfoItem'; -import { SysValueObject } from '../../../../api/system'; interface Props { name?: string; - items: SysValueObject; + items: T.SysInfoValueObject; } export default function Section({ name, items }: Props) { diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/SysInfoItem.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/SysInfoItem.tsx index 3389df8bb61..fc004f88d99 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/SysInfoItem.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/SysInfoItem.tsx @@ -22,17 +22,16 @@ import { map } from 'lodash'; import HealthItem from './HealthItem'; import AlertErrorIcon from '../../../../components/icons-components/AlertErrorIcon'; import AlertSuccessIcon from '../../../../components/icons-components/AlertSuccessIcon'; -import { HealthType, SysValue, SysValueObject } from '../../../../api/system'; -import { HEALTH_FIELD } from '../../utils'; +import { HEALTH_FIELD, STATE_FIELD } from '../../utils'; export interface Props { name: string; - value: SysValue; + value: T.SysInfoValue; } export default function SysInfoItem({ name, value }: Props): JSX.Element { - if (name === HEALTH_FIELD || name === 'State') { - return <HealthItem className="no-margin" health={value as HealthType} />; + if (name === HEALTH_FIELD || name === STATE_FIELD) { + return <HealthItem className="no-margin" health={value as T.HealthType} />; } if (value instanceof Array) { return <code>{JSON.stringify(value)}</code>; @@ -55,7 +54,7 @@ function BooleanItem({ value }: { value: boolean }) { } } -function ObjectItem({ value }: { value: SysValueObject }) { +function ObjectItem({ value }: { value: T.SysInfoValueObject }) { return ( <table className="data"> <tbody> diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx index c8eaa8d45ef..f96d0245c37 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCard-test.tsx @@ -20,7 +20,6 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import HealthCard from '../HealthCard'; -import { HealthType } from '../../../../../api/system'; it('should render correctly', () => { expect(getWrapper()).toMatchSnapshot(); @@ -48,7 +47,7 @@ function getWrapper(props = {}) { return shallow( <HealthCard biggerHealth={false} - health={HealthType.RED} + health="RED" healthCauses={['foo']} name="Foobar" onClick={() => {}} diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx index 1c415360938..52ca0760f4c 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthCauseItem-test.tsx @@ -20,11 +20,8 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import HealthCauseItem from '../HealthCauseItem'; -import { HealthType } from '../../../../../api/system'; it('should render correctly', () => { - expect(shallow(<HealthCauseItem health={HealthType.RED} healthCause="foo" />)).toMatchSnapshot(); - expect( - shallow(<HealthCauseItem health={HealthType.YELLOW} healthCause="foo" />) - ).toMatchSnapshot(); + expect(shallow(<HealthCauseItem health="RED" healthCause="foo" />)).toMatchSnapshot(); + expect(shallow(<HealthCauseItem health="YELLOW" healthCause="foo" />)).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx index 9857ee9b8f9..a17f1140b98 100644 --- a/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/info-items/__tests__/HealthItem-test.tsx @@ -20,25 +20,18 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import HealthItem from '../HealthItem'; -import { HealthType } from '../../../../../api/system'; it('should render correctly', () => { expect( - shallow( - <HealthItem biggerHealth={true} health={HealthType.RED} healthCauses={['foo']} name="Foo" /> - ) + shallow(<HealthItem biggerHealth={true} health="RED" healthCauses={['foo']} name="Foo" />) ).toMatchSnapshot(); }); it('should not render health causes', () => { - expect( - shallow(<HealthItem health={HealthType.GREEN} healthCauses={['foo']} />) - ).toMatchSnapshot(); - expect(shallow(<HealthItem health={HealthType.YELLOW} healthCauses={[]} />)).toMatchSnapshot(); + expect(shallow(<HealthItem health="GREEN" healthCauses={['foo']} />)).toMatchSnapshot(); + expect(shallow(<HealthItem health="YELLOW" healthCauses={[]} />)).toMatchSnapshot(); }); it('should render multiple health causes', () => { - expect( - shallow(<HealthItem health={HealthType.YELLOW} healthCauses={['foo', 'bar']} />) - ).toMatchSnapshot(); + expect(shallow(<HealthItem health="YELLOW" healthCauses={['foo', 'bar']} />)).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeForm.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeForm.tsx index 65712b193e7..9bc6c42f038 100644 --- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeForm.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeForm.tsx @@ -19,13 +19,12 @@ */ import * as React from 'react'; import SystemUpgradeItem from './SystemUpgradeItem'; -import { SystemUpgrade } from '../../../../api/system'; import Modal from '../../../../components/controls/Modal'; import { translate } from '../../../../helpers/l10n'; import { ResetButtonLink } from '../../../../components/ui/buttons'; interface Props { - systemUpgrades: SystemUpgrade[][]; + systemUpgrades: T.SystemUpgrade[][]; onClose: () => void; } diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeIntermediate.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeIntermediate.tsx index cd49bba50d1..14c65114dbd 100644 --- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeIntermediate.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeIntermediate.tsx @@ -21,12 +21,11 @@ import * as React from 'react'; import DateFormatter from '../../../../components/intl/DateFormatter'; import DropdownIcon from '../../../../components/icons-components/DropdownIcon'; import { ButtonLink } from '../../../../components/ui/buttons'; -import { SystemUpgrade } from '../../../../api/system'; import { translate } from '../../../../helpers/l10n'; interface Props { className?: string; - upgrades: SystemUpgrade[]; + upgrades: T.SystemUpgrade[]; } interface State { diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeItem.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeItem.tsx index 93e9e7b48e6..5881085f99d 100644 --- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeItem.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeItem.tsx @@ -21,12 +21,11 @@ import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import SystemUpgradeIntermediate from './SystemUpgradeIntermediate'; import DateFormatter from '../../../../components/intl/DateFormatter'; -import { SystemUpgrade } from '../../../../api/system'; import { translate, translateWithParameters } from '../../../../helpers/l10n'; interface Props { type?: string; - systemUpgrades: SystemUpgrade[]; + systemUpgrades: T.SystemUpgrade[]; } export default function SystemUpgradeItem({ type, systemUpgrades }: Props) { diff --git a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx index 87677c1b39a..c4800cccafa 100644 --- a/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx +++ b/server/sonar-web/src/main/js/apps/system/components/system-upgrade/SystemUpgradeNotif.tsx @@ -20,13 +20,13 @@ import * as React from 'react'; import SystemUpgradeForm from './SystemUpgradeForm'; import { sortUpgrades, groupUpgrades } from '../../utils'; -import { getSystemUpgrades, SystemUpgrade } from '../../../../api/system'; +import { getSystemUpgrades } from '../../../../api/system'; import { Button } from '../../../../components/ui/buttons'; import { translate } from '../../../../helpers/l10n'; import { Alert } from '../../../../components/ui/Alert'; interface State { - systemUpgrades: SystemUpgrade[][]; + systemUpgrades: T.SystemUpgrade[][]; openSystemUpgradeForm: boolean; } diff --git a/server/sonar-web/src/main/js/apps/system/styles.css b/server/sonar-web/src/main/js/apps/system/styles.css index ec695d0194f..33f60e68f48 100644 --- a/server/sonar-web/src/main/js/apps/system/styles.css +++ b/server/sonar-web/src/main/js/apps/system/styles.css @@ -26,6 +26,13 @@ margin-top: -12px; } +.system-info-copy-paste-id-info { + max-width: 550px; + padding: var(--gridSize) calc(2 * var(--gridSize)); + clear: both; + line-height: 1.8; +} + .system-info-health-info .status-indicator { position: relative; top: 8px; diff --git a/server/sonar-web/src/main/js/apps/system/utils.ts b/server/sonar-web/src/main/js/apps/system/utils.ts index e2d26559342..85f34adb82b 100644 --- a/server/sonar-web/src/main/js/apps/system/utils.ts +++ b/server/sonar-web/src/main/js/apps/system/utils.ts @@ -25,15 +25,6 @@ import { RawQuery, serializeStringArray } from '../../helpers/query'; -import { - ClusterSysInfo, - HealthType, - NodeInfo, - SysInfo, - SysInfoSection, - SysValueObject, - SystemUpgrade -} from '../../api/system'; import { formatMeasure } from '../../helpers/measures'; export interface Query { @@ -41,132 +32,167 @@ export interface Query { } export const LOGS_LEVELS = ['INFO', 'DEBUG', 'TRACE']; +const DEFAULT_LOG_LEVEL = LOGS_LEVELS[0]; + +export const APP_NODES_FIELD = 'Application Nodes'; +export const CE_FIELD_PREFIX = 'Compute Engine'; +export const CE_LOGGING_FIELD = 'Compute Engine Logging'; export const HA_FIELD = 'High Availability'; +export const HEALTH_CAUSES_FIELD = 'Health Causes'; export const HEALTH_FIELD = 'Health'; -export const HEALTHCAUSES_FIELD = 'Health Causes'; +export const LOGS_LEVEL_FIELD = 'Logs Level'; +export const NAME_FIELD = 'Name'; +export const NCLOC_FIELD = 'ncloc'; export const PLUGINS_FIELD = 'Plugins'; +export const SEARCH_NODES_FIELD = 'Search Nodes'; +export const SEARCH_PREFIX = 'Search'; +export const SERVER_ID_FIELD = 'Server ID'; export const SETTINGS_FIELD = 'Settings'; - -export function ignoreInfoFields(sysInfoObject: SysValueObject): SysValueObject { +export const STATE_FIELD = 'State'; +export const STATS_FIELD = 'Statistics'; +export const SYSTEM_FIELD = 'System'; +export const VERSION_FIELD = 'Version'; +export const WEB_LOGGING_FIELD = 'Web Logging'; +export const WEB_PREFIX = 'Web'; + +export function ignoreInfoFields(sysInfoObject: T.SysInfoValueObject) { return omit(sysInfoObject, [ HEALTH_FIELD, - HEALTHCAUSES_FIELD, - 'Name', + HEALTH_CAUSES_FIELD, + NAME_FIELD, PLUGINS_FIELD, - SETTINGS_FIELD - ]) as SysValueObject; + SETTINGS_FIELD, + SERVER_ID_FIELD, + VERSION_FIELD + ]); } -export function getHealth(sysInfoObject: SysValueObject): HealthType { - return sysInfoObject[HEALTH_FIELD] as HealthType; +export function getHealth(sysInfoObject: T.SysInfoBase) { + return sysInfoObject[HEALTH_FIELD]; } -export function getHealthCauses(sysInfoObject: SysValueObject): string[] { - return sysInfoObject[HEALTHCAUSES_FIELD] as string[]; +export function getHealthCauses(sysInfoObject: T.SysInfoBase) { + return sysInfoObject[HEALTH_CAUSES_FIELD]; } -export function getLogsLevel(sysInfoObject?: SysValueObject): string { - if (!sysInfoObject) { - return LOGS_LEVELS[0]; - } - if (sysInfoObject['Web Logging'] || sysInfoObject['Compute Engine Logging']) { - return sortBy( - [ - getLogsLevel((sysInfoObject as NodeInfo)['Web Logging']), - getLogsLevel((sysInfoObject as NodeInfo)['Compute Engine Logging']) - ], - logLevel => LOGS_LEVELS.indexOf(logLevel) - )[1]; - } - if (sysInfoObject['System']) { - return getLogsLevel((sysInfoObject as SysInfo)['System']); +export function getLogsLevel(sysInfoObject?: T.SysInfoValueObject): string { + if (sysInfoObject !== undefined) { + if (isLogInfoBlock(sysInfoObject)) { + return sysInfoObject[LOGS_LEVEL_FIELD]; + } else if (hasLoggingInfo(sysInfoObject)) { + return sortBy( + [ + getLogsLevel(sysInfoObject[WEB_LOGGING_FIELD]), + getLogsLevel(sysInfoObject[CE_LOGGING_FIELD]) + ], + logLevel => LOGS_LEVELS.indexOf(logLevel) + )[1]; + } } - return (sysInfoObject['Logs Level'] || LOGS_LEVELS[0]) as string; + return DEFAULT_LOG_LEVEL; } -export function getAppNodes(sysInfoData: ClusterSysInfo): NodeInfo[] { - return sysInfoData['Application Nodes']; +export function getAppNodes(sysInfoData: T.SysInfoCluster): T.SysInfoAppNode[] { + return sysInfoData[APP_NODES_FIELD]; } -export function getSearchNodes(sysInfoData: ClusterSysInfo): NodeInfo[] { - return sysInfoData['Search Nodes']; +export function getSearchNodes(sysInfoData: T.SysInfoCluster): T.SysInfoSearchNode[] { + return sysInfoData[SEARCH_NODES_FIELD]; } -export function isCluster(sysInfoData?: SysInfo): boolean { - return ( - sysInfoData !== undefined && sysInfoData['System'] && sysInfoData['System'][HA_FIELD] === true - ); +export function isCluster( + sysInfoData: T.SysInfoCluster | T.SysInfoStandalone +): sysInfoData is T.SysInfoCluster { + return sysInfoData[SYSTEM_FIELD] && sysInfoData[SYSTEM_FIELD][HA_FIELD] === true; } -export function getServerId(sysInfoData?: SysInfo): string | undefined { - return sysInfoData && sysInfoData['System']['Server ID']; +export function isLogInfoBlock( + sysInfoObject: T.SysInfoValueObject +): sysInfoObject is T.SysInfoLogging { + return sysInfoObject[LOGS_LEVEL_FIELD] !== undefined; } -export function getSystemLogsLevel(sysInfoData?: SysInfo): string { - const defaultLevel = LOGS_LEVELS[0]; - if (!sysInfoData) { - return defaultLevel; - } +export function hasLoggingInfo( + sysInfoObject: T.SysInfoValueObject +): sysInfoObject is T.SysInfoStandalone | T.SysInfoAppNode { + return Boolean(sysInfoObject[WEB_LOGGING_FIELD] || sysInfoObject[CE_LOGGING_FIELD]); +} + +export function getServerId(sysInfoData: T.SysInfoCluster | T.SysInfoStandalone): string { + return sysInfoData && sysInfoData[SYSTEM_FIELD][SERVER_ID_FIELD]; +} + +export function getVersion(sysInfoData: T.SysInfoStandalone): string | undefined { + return sysInfoData && sysInfoData[SYSTEM_FIELD][VERSION_FIELD]; +} + +export function getClusterVersion(sysInfoData: T.SysInfoCluster): string | undefined { + const appNodes = getAppNodes(sysInfoData); + return appNodes.length > 0 ? appNodes[0][SYSTEM_FIELD][VERSION_FIELD] : undefined; +} + +export function getSystemLogsLevel(sysInfoData: T.SysInfoCluster | T.SysInfoStandalone): string { if (isCluster(sysInfoData)) { - const logLevels = sortBy( - getAppNodes(sysInfoData as ClusterSysInfo).map(getLogsLevel), - logLevel => LOGS_LEVELS.indexOf(logLevel) + const logLevels = sortBy(getAppNodes(sysInfoData).map(getLogsLevel), logLevel => + LOGS_LEVELS.indexOf(logLevel) ); - return logLevels.length > 0 ? logLevels[logLevels.length - 1] : defaultLevel; + return logLevels.length > 0 ? logLevels[logLevels.length - 1] : DEFAULT_LOG_LEVEL; } else { return getLogsLevel(sysInfoData); } } -export function getNodeName(nodeInfo: NodeInfo): string { - return nodeInfo['Name']; +export function getNodeName(nodeInfo: T.SysInfoAppNode | T.SysInfoSearchNode): string { + return nodeInfo[NAME_FIELD]; } -function getSystemData(sysInfoData: SysInfo): SysValueObject { - const statData: SysValueObject = {}; - const statistics = sysInfoData['Statistics'] as SysValueObject; +function getSystemData(sysInfoData: T.SysInfoBase): T.SysInfoValueObject { + const statData: T.SysInfoValueObject = {}; + const statistics = sysInfoData[STATS_FIELD] as T.SysInfoValueObject; // TODO if (statistics) { - statData['Lines of Code'] = formatMeasure(statistics['ncloc'] as number, 'INT'); + statData['Lines of Code'] = formatMeasure(statistics[NCLOC_FIELD] as number, 'INT'); } - return { ...sysInfoData['System'], ...statData }; + return { ...sysInfoData[SYSTEM_FIELD], ...statData }; } -export function getClusterMainCardSection(sysInfoData: ClusterSysInfo): SysValueObject { +export function getClusterMainCardSection(sysInfoData: T.SysInfoCluster): T.SysInfoValueObject { return { ...getSystemData(sysInfoData), - ...(omit(sysInfoData, [ - 'Application Nodes', + ...omit(sysInfoData, [ + APP_NODES_FIELD, PLUGINS_FIELD, - 'Search Nodes', + SEARCH_NODES_FIELD, SETTINGS_FIELD, - 'Statistics', - 'System' - ]) as SysValueObject) + STATS_FIELD, + SYSTEM_FIELD + ]) }; } -export function getStandaloneMainSections(sysInfoData: SysInfo): SysValueObject { +export function getStandaloneMainSections(sysInfoData: T.SysInfoBase): T.SysInfoValueObject { return { ...getSystemData(sysInfoData), ...(omitBy( sysInfoData, (value, key) => value == null || - [PLUGINS_FIELD, SETTINGS_FIELD, 'Statistics', 'System'].includes(key) || - key.startsWith('Compute Engine') || - key.startsWith('Search') || - key.startsWith('Web') - ) as SysValueObject) + [PLUGINS_FIELD, SETTINGS_FIELD, STATS_FIELD, SYSTEM_FIELD].includes(key) || + key.startsWith(CE_FIELD_PREFIX) || + key.startsWith(SEARCH_PREFIX) || + key.startsWith(WEB_PREFIX) + ) as T.SysInfoValueObject) }; } -export function getStandaloneSecondarySections(sysInfoData: SysInfo): SysInfoSection { +export function getStandaloneSecondarySections(sysInfoData: T.SysInfoBase): T.SysInfoSection { return { - Web: pickBy(sysInfoData, (_, key) => key.startsWith('Web')) as SysValueObject, + Web: pickBy(sysInfoData, (_, key) => key.startsWith(WEB_PREFIX)) as T.SysInfoValueObject, 'Compute Engine': pickBy(sysInfoData, (_, key) => - key.startsWith('Compute Engine') - ) as SysValueObject, - 'Search Engine': pickBy(sysInfoData, (_, key) => key.startsWith('Search')) as SysValueObject + key.startsWith(CE_FIELD_PREFIX) + ) as T.SysInfoValueObject, + 'Search Engine': pickBy(sysInfoData, (_, key) => + key.startsWith(SEARCH_PREFIX) + ) as T.SysInfoValueObject }; } @@ -179,9 +205,9 @@ export function getFileNameSuffix(suffix?: string) { ); } -export function groupSections(sysInfoData: SysValueObject) { - const mainSection: SysValueObject = {}; - const sections: SysInfoSection = {}; +export function groupSections(sysInfoData: T.SysInfoValueObject) { + const mainSection: T.SysInfoValueObject = {}; + const sections: T.SysInfoSection = {}; each(sysInfoData, (item, key) => { if (typeof item !== 'object' || item instanceof Array) { mainSection[key] = item; @@ -205,15 +231,15 @@ export const serializeQuery = memoize( }) ); -export function sortUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[] { +export function sortUpgrades(upgrades: T.SystemUpgrade[]): T.SystemUpgrade[] { return sortBy(upgrades, [ - (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[0]), - (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[1] || 0), - (upgrade: SystemUpgrade) => -Number(upgrade.version.split('.')[2] || 0) + (upgrade: T.SystemUpgrade) => -Number(upgrade.version.split('.')[0]), + (upgrade: T.SystemUpgrade) => -Number(upgrade.version.split('.')[1] || 0), + (upgrade: T.SystemUpgrade) => -Number(upgrade.version.split('.')[2] || 0) ]); } -export function groupUpgrades(upgrades: SystemUpgrade[]): SystemUpgrade[][] { +export function groupUpgrades(upgrades: T.SystemUpgrade[]): T.SystemUpgrade[][] { const groupedVersions = groupBy(upgrades, upgrade => upgrade.version.split('.')[0]); const sortedMajor = sortBy(Object.keys(groupedVersions), key => -Number(key)); return sortedMajor.map(key => groupedVersions[key]); |