diff --git a/src/browser/modules/DatabaseInfo/DatabaseKernelInfo.jsx b/src/browser/modules/DatabaseInfo/DatabaseKernelInfo.jsx index d4e5caa6af2..62a602b5daa 100644 --- a/src/browser/modules/DatabaseInfo/DatabaseKernelInfo.jsx +++ b/src/browser/modules/DatabaseInfo/DatabaseKernelInfo.jsx @@ -20,20 +20,26 @@ import { connect } from 'preact-redux' import { withBus } from 'preact-suber' -import { getVersion, getEdition } from 'shared/modules/dbMeta/dbMetaDuck' +import { getVersion, getEdition, getDbName, getStoreSize, getClusterRole } from 'shared/modules/dbMeta/dbMetaDuck' import { executeCommand } from 'shared/modules/commands/commandsDuck' +import { toHumanReadableBytes } from 'services/utils' import Render from 'browser-components/Render' import {DrawerSection, DrawerSectionBody, DrawerSubHeader} from 'browser-components/drawer' import {StyledTable, StyledKey, StyledValue, StyledValueUCFirst, Link} from './styled' -export const DatabaseKernelInfo = ({version, edition, onItemClick}) => { +export const DatabaseKernelInfo = ({role, version, edition, dbName, storeSize, onItemClick}) => { return ( Database + + + Cluster role: {role} + + Version: {version} @@ -44,6 +50,16 @@ export const DatabaseKernelInfo = ({version, edition, onItemClick}) => { Edition: {edition} + + + Name: {dbName} + + + + + Size: {toHumanReadableBytes(storeSize)} + + Information: onItemClick(':sysinfo')}>:sysinfo @@ -60,7 +76,10 @@ export const DatabaseKernelInfo = ({version, edition, onItemClick}) => { const mapStateToProps = (store) => { return { version: getVersion(store), - edition: getEdition(store) + edition: getEdition(store), + dbName: getDbName(store), + storeSize: getStoreSize(store), + role: getClusterRole(store) } } const mapDispatchToProps = (dispatch, ownProps) => { diff --git a/src/shared/modules/dbMeta/__snapshots__/dbMetaDuck.test.js.snap b/src/shared/modules/dbMeta/__snapshots__/dbMetaDuck.test.js.snap index 963d93d693e..d1e770bb54e 100644 --- a/src/shared/modules/dbMeta/__snapshots__/dbMetaDuck.test.js.snap +++ b/src/shared/modules/dbMeta/__snapshots__/dbMetaDuck.test.js.snap @@ -7,9 +7,38 @@ Object { "procedures": Array [], "properties": Array [], "relationshipTypes": Array [], + "role": null, "server": Object { + "dbName": null, "edition": null, "storeId": null, + "storeSize": null, + "version": null, + }, + "settings": Object { + "browser.allow_outgoing_connections": false, + "browser.remote_content_hostname_whitelist": "guides.neo4j.com, localhost", + }, +} +`; + +exports[`updating metadata can update meta values with UPDATE 1`] = ` +Object { + "functions": Array [], + "hydrated": true, + "labels": Array [], + "myKey": "yo", + "noKey": true, + "procedures": Array [], + "properties": Array [], + "relationshipTypes": Array [], + "role": null, + "secondKey": true, + "server": Object { + "dbName": null, + "edition": null, + "storeId": null, + "storeSize": null, "version": null, }, "settings": Object { @@ -27,9 +56,12 @@ Object { "procedures": Array [], "properties": Array [], "relationshipTypes": Array [], + "role": null, "server": Object { + "dbName": undefined, "edition": "enterprise", "storeId": "xxxx", + "storeSize": undefined, "version": "3.2.0-RC2", }, "settings": Object { @@ -48,9 +80,12 @@ Object { "procedures": Array [], "properties": Array [], "relationshipTypes": Array [], + "role": null, "server": Object { + "dbName": null, "edition": null, "storeId": null, + "storeSize": null, "version": null, }, "settings": Object { diff --git a/src/shared/modules/dbMeta/dbMetaDuck.js b/src/shared/modules/dbMeta/dbMetaDuck.js index 0208f1371b5..df5f9830460 100644 --- a/src/shared/modules/dbMeta/dbMetaDuck.js +++ b/src/shared/modules/dbMeta/dbMetaDuck.js @@ -34,6 +34,7 @@ import { } from 'shared/modules/connections/connectionsDuck' export const NAME = 'meta' +export const UPDATE = 'meta/UPDATE' export const UPDATE_META = 'meta/UPDATE_META' export const UPDATE_SERVER = 'meta/UPDATE_SERVER' export const UPDATE_SETTINGS = 'meta/UPDATE_SETTINGS' @@ -63,6 +64,9 @@ export function getMetaInContext (state, context) { export const getVersion = (state) => state[NAME].server.version export const getEdition = (state) => state[NAME].server.edition +export const getDbName = (state) => state[NAME].server.dbName +export const getStoreSize = (state) => state[NAME].server.storeSize +export const getClusterRole = (state) => state[NAME].role export const isEnterprise = (state) => state[NAME].server.edition === 'enterprise' export const isBeta = (state) => /-/.test(state[NAME].server.version) export const getStoreId = (state) => state[NAME].server.storeId @@ -133,10 +137,13 @@ const initialState = { properties: [], functions: [], procedures: [], + role: null, server: { version: null, edition: null, - storeId: null + storeId: null, + dbName: null, + storeSize: null }, settings: { 'browser.allow_outgoing_connections': false, @@ -151,10 +158,14 @@ export default function meta (state = initialState, action) { state = hydrate(initialState, state) switch (action.type) { + case UPDATE: + const { type, ...rest } = action // eslint-disable-line + return { ...state, ...rest } case UPDATE_META: return {...state, ...updateMetaForContext(state, action.meta, action.context)} case UPDATE_SERVER: - return {...state, server: { version: action.version, edition: action.edition, storeId: action.storeId }} + const { version, edition, storeId, dbName, storeSize } = action + return {...state, server: { version, edition, storeId, dbName, storeSize }} case UPDATE_SETTINGS: return {...state, settings: { ...action.settings }} case CLEAR: @@ -178,6 +189,13 @@ export function fetchMetaData () { } } +export const update = (obj) => { + return { + type: UPDATE, + ...obj + } +} + export const updateSettings = (settings) => { return { type: UPDATE_SETTINGS, @@ -228,22 +246,28 @@ export const dbMetaEpic = (some$, store) => .fromPromise(getJmxValues([ ['Kernel', 'KernelVersion'], ['Kernel', 'StoreId'], - ['Configuration', 'unsupported.dbms.edition'] + ['Kernel', 'DatabaseName'], + ['Configuration', 'unsupported.dbms.edition'], + ['Store file sizes', 'TotalStoreSize'] ])) .catch((e) => Rx.Observable.of(null)) }) .do((res) => { if (!res) return - const [ kvObj, storeObj, edObj ] = res + const [ kvObj, storeObj, nameObj, edObj, sizeObj ] = res const versionMatch = kvObj.KernelVersion.match(/version:\s([^,$]+)/) const version = (versionMatch !== null && versionMatch.length > 1) ? versionMatch[1] : null const edition = edObj['unsupported.dbms.edition'] const storeId = storeObj['StoreId'] + const dbName = nameObj['DatabaseName'] + const storeSize = sizeObj['TotalStoreSize'] store.dispatch({ type: UPDATE_SERVER, version, edition, - storeId + storeId, + dbName, + storeSize }) }) // Server config for browser @@ -262,7 +286,6 @@ export const dbMetaEpic = (some$, store) => store.dispatch(updateSettings(settings)) }) }) - .takeUntil(some$.ofType(LOST_CONNECTION).filter(connectionLossFilter)) // Server security settings .mergeMap(() => { return getServerConfig(['dbms.security']) @@ -276,6 +299,19 @@ export const dbMetaEpic = (some$, store) => store.dispatch(setAuthEnabled(authEnabled)) }) }) + // Cluster role + .mergeMap(() => + Rx.Observable + .fromPromise(bolt.directTransaction('CALL dbms.cluster.role() YIELD role')) + .catch((e) => Rx.Observable.of(null)) + .do((res) => { + if (!res) return Rx.Observable.of(null) + const role = res.records[0].get(0) + store.dispatch(update({ role })) + return Rx.Observable.of(null) + }) + ) + .takeUntil(some$.ofType(LOST_CONNECTION).filter(connectionLossFilter)) .mapTo({ type: 'NOOP' }) }) diff --git a/src/shared/modules/dbMeta/dbMetaDuck.test.js b/src/shared/modules/dbMeta/dbMetaDuck.test.js index 5eb0200b9fc..efc58184f60 100644 --- a/src/shared/modules/dbMeta/dbMetaDuck.test.js +++ b/src/shared/modules/dbMeta/dbMetaDuck.test.js @@ -186,4 +186,19 @@ describe('updating metadata', () => { // Then expect(nextState).toMatchSnapshot() }) + + test('can update meta values with UPDATE', () => { + // Given + const initState = { + myKey: 'val', + noKey: true + } + const action = { type: meta.UPDATE, myKey: 'yo', secondKey: true } + + // When + const nextState = reducer(initState, action) + + // Then + expect(nextState).toMatchSnapshot() + }) })