diff --git a/e2e_tests/integration/auto-prefix.spec.ts b/e2e_tests/integration/auto-prefix.spec.ts
index 91ae45027be..bf7af8403cb 100644
--- a/e2e_tests/integration/auto-prefix.spec.ts
+++ b/e2e_tests/integration/auto-prefix.spec.ts
@@ -47,7 +47,7 @@ describe(':auto prefix in browser', () => {
if (Cypress.config('serverVersion') >= 4.4) {
it('shows help link when running CALL IN TRANSACTIONS without :auto', () => {
cy.executeCommand(
- `MATCH (n) WITH n CALL {{} CALL db.ping() YIELD SUCCESS {}} IN TRANSACTIONS`
+ `MATCH (n) WITH n CALL {{} CALL db.ping() YIELD success {}} IN TRANSACTIONS`
)
cy.getFrames().contains('ERROR')
cy.getFrames().contains(':auto')
@@ -55,7 +55,7 @@ describe(':auto prefix in browser', () => {
it('adding :auto enables running CALL IN TRANSACTIONS', () => {
cy.executeCommand(
- `:auto MATCH (n) WITH n CALL {{} CALL db.ping() YIELD SUCCESS {}} IN TRANSACTIONS`
+ `:auto MATCH (n) WITH n CALL {{} CALL db.ping() YIELD success {}} IN TRANSACTIONS`
)
cy.getFrames().should('not.contain', 'ERROR')
cy.getFrames().contains('(no changes, no records)')
diff --git a/e2e_tests/integration/loadcsv.spec.ts b/e2e_tests/integration/loadcsv.spec.ts
index fbd5b16e6b4..643503cc7e7 100644
--- a/e2e_tests/integration/loadcsv.spec.ts
+++ b/e2e_tests/integration/loadcsv.spec.ts
@@ -30,48 +30,46 @@ describe('LOAD CSV', () => {
cy.connect('neo4j', password)
})
it('imports without periodic commit', () => {
- if (!Cypress.config('includeImportTests')) {
- return
- }
- cy.executeCommand(':clear')
- cy.executeCommand('MATCH (n) DETACH DELETE n')
- cy.executeCommand(`LOAD CSV WITH HEADERS FROM 'file:///import.csv' AS row{shift}{enter}
+ if (Cypress.config('includeImportTests')) {
+ cy.executeCommand(':clear')
+ cy.executeCommand('MATCH (n) DETACH DELETE n')
+ cy.executeCommand(`LOAD CSV WITH HEADERS FROM 'file:///import.csv' AS row{shift}{enter}
CREATE (p:Person {{}name: row.name, born: toInteger(row.born), city: row.city, comment:row.comment});`)
- cy.resultContains('Added 3 labels, created 3 nodes, set 11 properties,')
+ cy.resultContains('Added 3 labels, created 3 nodes, set 11 properties,')
- cy.executeCommand(
- 'MATCH (n:Person {{}born: 2012}) RETURN n.city, n.comment'
- )
- cy.resultContains('"Borås"')
- cy.resultContains('"I like unicorns, and "flying unicorns""')
+ cy.executeCommand(
+ 'MATCH (n:Person {{}born: 2012}) RETURN n.city, n.comment'
+ )
+ cy.resultContains('"Borås"')
+ cy.resultContains('"I like unicorns, and "flying unicorns""')
+ }
})
it('imports with periodic commit', () => {
if (
- !Cypress.config('includeImportTests') &&
+ Cypress.config('includeImportTests') &&
Cypress.config('serverVersion') < 5
) {
- return
- }
- const periodicQuery = `USING PERIODIC COMMIT 1{shift}{enter}
+ const periodicQuery = `USING PERIODIC COMMIT 1{shift}{enter}
LOAD CSV WITH HEADERS FROM 'file:///import.csv' AS row
CREATE (p:Person {{}name: row.name, born: toInteger(row.born), city: row.city, comment:row.comment});`
- // Let's see it fail when not using auto-committed tx's first
- cy.executeCommand(':clear')
- cy.executeCommand(periodicQuery)
- cy.resultContains('Neo.ClientError.Statement.SemanticError')
+ // Let's see it fail when not using auto-committed tx's first
+ cy.executeCommand(':clear')
+ cy.executeCommand(periodicQuery)
+ cy.resultContains('Neo.ClientError.Statement.SemanticError')
- cy.executeCommand(':clear')
- cy.executeCommand('MATCH (n) DETACH DELETE n')
- cy.executeCommand(`:auto ${periodicQuery}`)
+ cy.executeCommand(':clear')
+ cy.executeCommand('MATCH (n) DETACH DELETE n')
+ cy.executeCommand(`:auto ${periodicQuery}`)
- cy.resultContains('Added 3 labels, created 3 nodes, set 11 properties,')
+ cy.resultContains('Added 3 labels, created 3 nodes, set 11 properties,')
- cy.executeCommand(
- 'MATCH (n:Person {{}born: 2012}) RETURN n.city, n.comment'
- )
- cy.resultContains('"Borås"')
- cy.resultContains('"I like unicorns, and "flying unicorns""')
+ cy.executeCommand(
+ 'MATCH (n:Person {{}born: 2012}) RETURN n.city, n.comment'
+ )
+ cy.resultContains('"Borås"')
+ cy.resultContains('"I like unicorns, and "flying unicorns""')
+ }
})
})
diff --git a/src/browser/modules/Stream/Queries/QueriesFrame.test.tsx b/src/browser/modules/Stream/Queries/LegacyQueriesFrame.test.tsx
similarity index 90%
rename from src/browser/modules/Stream/Queries/QueriesFrame.test.tsx
rename to src/browser/modules/Stream/Queries/LegacyQueriesFrame.test.tsx
index 2cc7f34eddf..e54b4911641 100644
--- a/src/browser/modules/Stream/Queries/QueriesFrame.test.tsx
+++ b/src/browser/modules/Stream/Queries/LegacyQueriesFrame.test.tsx
@@ -21,7 +21,7 @@ import { fireEvent, render } from '@testing-library/react'
import React from 'react'
import { createBus } from 'suber'
-import { QueriesFrame } from './QueriesFrame'
+import { LegacyQueriesFrame } from './LegacyQueriesFrame'
import {
CONNECTED_STATE,
DISCONNECTED_STATE
@@ -41,7 +41,7 @@ it('shows error message in statusBar when not connected', () => {
const props = {
connectionState: DISCONNECTED_STATE
} as any
- const { getByText } = render()
+ const { getByText } = render()
expect(getByText(/Unable to connect to bolt server/i)).not.toBeNull()
})
@@ -82,10 +82,12 @@ it('can list and kill queries', () => {
isFullscreen: false,
isCollapsed: false,
isOnCausalCluster: false,
- canListQueries: true
+ hasListQueriesProcedure: true,
+ versionOverFive: false,
+ frame: null
}
- const { getByText, getByTestId } = render()
+ const { getByText, getByTestId } = render()
// Check that it's listed
expect(getByText('neo4j://testhost.test')).not.toBeNull()
diff --git a/src/browser/modules/Stream/Queries/LegacyQueriesFrame.tsx b/src/browser/modules/Stream/Queries/LegacyQueriesFrame.tsx
new file mode 100644
index 00000000000..a347b0134fb
--- /dev/null
+++ b/src/browser/modules/Stream/Queries/LegacyQueriesFrame.tsx
@@ -0,0 +1,379 @@
+/*
+ * Copyright (c) "Neo4j"
+ * Neo4j Sweden AB [http://neo4j.com]
+ *
+ * This file is part of Neo4j.
+ *
+ * Neo4j is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+import React, { Component } from 'react'
+import { Bus } from 'suber'
+
+import FrameAside from '../../Frame/FrameAside'
+import FrameBodyTemplate from '../../Frame/FrameBodyTemplate'
+import FrameError from '../../Frame/FrameError'
+import {
+ AutoRefreshSpan,
+ AutoRefreshToggle,
+ StatusbarWrapper,
+ StyledStatusBar
+} from '../AutoRefresh/styled'
+import {
+ Code,
+ StyledHeaderRow,
+ StyledTable,
+ StyledTableWrapper,
+ StyledTd,
+ StyledTh
+} from './styled'
+import { EnterpriseOnlyFrame } from 'browser-components/EditionView'
+import { ConfirmationButton } from 'browser-components/buttons/ConfirmationButton'
+import bolt from 'services/bolt/bolt'
+import { NEO4J_BROWSER_USER_ACTION_QUERY } from 'services/bolt/txMetadata'
+import { CONNECTED_STATE } from 'shared/modules/connections/connectionsDuck'
+import {
+ AD_HOC_CYPHER_REQUEST,
+ CLUSTER_CYPHER_REQUEST,
+ CYPHER_REQUEST
+} from 'shared/modules/cypher/cypherDuck'
+import {
+ killQueriesProcedure,
+ listQueriesProcedure
+} from 'shared/modules/cypher/queriesProcedureHelper'
+
+import { getDefaultBoltScheme } from 'shared/modules/features/versionedFeatures'
+
+type LegacyQueriesFrameState = {
+ queries: any[]
+ autoRefresh: boolean
+ autoRefreshInterval: number
+ success: null | boolean | string
+ errors: any[]
+}
+
+export type LegacyQueriesFrameProps = {
+ frame: any
+ bus: Bus
+ hasListQueriesProcedure: boolean
+ connectionState: number
+ neo4jVersion: string | null
+ isFullscreen: boolean
+ versionOverFive: boolean
+ isCollapsed: boolean
+ isOnCausalCluster: boolean
+}
+export class LegacyQueriesFrame extends Component<
+ LegacyQueriesFrameProps,
+ LegacyQueriesFrameState
+> {
+ timer: any
+ state = {
+ queries: [],
+ autoRefresh: false,
+ autoRefreshInterval: 20, // seconds
+ success: null,
+ errors: []
+ }
+
+ componentDidMount() {
+ if (this.props.connectionState === CONNECTED_STATE) {
+ this.getRunningQueries()
+ } else {
+ this.setState({ errors: [new Error('Unable to connect to bolt server')] })
+ }
+ }
+
+ componentDidUpdate(prevProps: any, prevState: LegacyQueriesFrameState) {
+ if (prevState.autoRefresh !== this.state.autoRefresh) {
+ if (this.state.autoRefresh) {
+ this.timer = setInterval(
+ this.getRunningQueries.bind(this),
+ this.state.autoRefreshInterval * 1000
+ )
+ } else {
+ clearInterval(this.timer)
+ }
+ }
+ if (
+ (this.props.frame &&
+ this.props.frame.ts !== prevProps.frame.ts &&
+ this.props.frame.isRerun) ||
+ this.props.isOnCausalCluster !== prevProps.isOnCausalCluster
+ ) {
+ this.getRunningQueries()
+ }
+ }
+
+ getRunningQueries(suppressQuerySuccessMessage = false) {
+ this.props.bus.self(
+ this.props.isOnCausalCluster ? CLUSTER_CYPHER_REQUEST : CYPHER_REQUEST,
+ {
+ query: listQueriesProcedure(),
+ queryType: NEO4J_BROWSER_USER_ACTION_QUERY
+ },
+ (response: any) => {
+ if (response.success) {
+ const queries = this.extractQueriesFromBoltResult(response.result)
+ const errors = queries
+ .filter((_: any) => _.error)
+ .map((e: any) => ({
+ ...e.error
+ }))
+ const validQueries = queries.filter((_: any) => !_.error)
+ const resultMessage = this.constructOverviewMessage(
+ validQueries,
+ errors
+ )
+
+ this.setState((prevState: any) => {
+ return {
+ queries: validQueries,
+ errors,
+ success: suppressQuerySuccessMessage
+ ? prevState.success
+ : resultMessage
+ }
+ })
+ } else {
+ const errors: any[] = this.state.errors || []
+ this.setState({
+ errors: errors.concat([response.error]),
+ success: false
+ })
+ }
+ }
+ )
+ }
+
+ killQueries(host: any, queryIdList: any) {
+ this.props.bus.self(
+ this.props.isOnCausalCluster ? AD_HOC_CYPHER_REQUEST : CYPHER_REQUEST,
+ { host, query: killQueriesProcedure(queryIdList) },
+ (response: any) => {
+ if (response.success) {
+ this.setState({
+ success: 'Query successfully cancelled',
+ errors: []
+ })
+ this.getRunningQueries(true)
+ } else {
+ const errors: any[] = this.state.errors || []
+ this.setState({
+ errors: errors.concat([response.error]),
+ success: false
+ })
+ }
+ }
+ )
+ }
+
+ extractQueriesFromBoltResult(result: any) {
+ return result.records.map(({ keys, _fields, host, error }: any) => {
+ if (error) {
+ return { error }
+ }
+ const queryInfo: any = {}
+ keys.forEach((key: any, idx: any) => {
+ queryInfo[key] = bolt.itemIntToNumber(_fields[idx])
+ })
+ if (host) {
+ queryInfo.host = getDefaultBoltScheme(this.props.neo4jVersion) + host
+ } else {
+ queryInfo.host =
+ getDefaultBoltScheme(this.props.neo4jVersion) +
+ result.summary.server.address
+ }
+ return queryInfo
+ })
+ }
+
+ onCancelQuery(host: any, queryId: any) {
+ this.killQueries(host, [queryId])
+ }
+
+ constructOverviewMessage(queries: any, errors: any) {
+ const clusterCount = new Set(queries.map((query: any) => query.host)).size
+
+ const numMachinesMsg =
+ clusterCount > 1
+ ? `running on ${clusterCount} cluster servers`
+ : 'running on one server'
+
+ const numQueriesMsg = queries.length > 1 ? 'queries' : 'query'
+
+ const successMessage = `Found ${queries.length} ${numQueriesMsg} ${numMachinesMsg}`
+
+ return errors.length > 0 ? (
+
+ {successMessage} ({errors.length} unsuccessful)
+
+ ) : (
+ successMessage
+ )
+ }
+
+ constructViewFromQueryList(queries: any, errors: any) {
+ if (queries.length === 0) {
+ return null
+ }
+ const tableHeaderSizes = [
+ ['Database URI', '20%'],
+ ['User', '8%'],
+ ['Query', 'auto'],
+ ['Params', '7%'],
+ ['Meta', 'auto'],
+ ['Elapsed time', '95px'],
+ ['Kill', '95px']
+ ]
+ const tableRows = queries.map((query: any, i: any) => {
+ return (
+
+
+ {query.host}
+
+
+ {query.username}
+
+
+ {query.query}
+
+
+ {JSON.stringify(query.parameters, null, 2)}
+
+
+ {JSON.stringify(query.metaData, null, 2)}
+
+
+ {query.elapsedTimeMillis} ms
+
+
+
+
+
+ )
+ })
+
+ const errorRows = errors.map((error: any, i: any) => (
+
+
+ Error connecting to: {error.host}
+
+
+ ))
+
+ const tableHeaders = tableHeaderSizes.map(heading => {
+ return (
+
+ {heading[0]}
+
+ )
+ })
+ return (
+
+
+
+ {tableHeaders}
+
+
+ {tableRows}
+ {errorRows}
+
+
+
+ )
+ }
+
+ setAutoRefresh(autoRefresh: any) {
+ this.setState({ autoRefresh: autoRefresh })
+
+ if (autoRefresh) {
+ this.getRunningQueries()
+ }
+ }
+
+ render() {
+ let frameContents
+ let aside
+ let statusBar
+
+ if (
+ this.props.hasListQueriesProcedure ||
+ this.props.connectionState !== CONNECTED_STATE
+ ) {
+ frameContents = this.constructViewFromQueryList(
+ this.state.queries,
+ this.state.errors
+ )
+ statusBar = (
+
+ {this.state.errors && !this.state.success && (
+ `${e.host}: ${e.message}`)
+ .join(', ')}
+ />
+ )}
+ {this.state.success && (
+
+ {this.state.success}
+
+ this.setAutoRefresh(e.target.checked)}
+ />
+
+
+ )}
+
+ )
+ } else {
+ aside = (
+
+ )
+ frameContents =
+ }
+ return (
+
+ )
+ }
+}
+
+export default LegacyQueriesFrame
diff --git a/src/browser/modules/Stream/Queries/QueriesFrame.tsx b/src/browser/modules/Stream/Queries/QueriesFrame.tsx
index 2401242d498..9389079989f 100644
--- a/src/browser/modules/Stream/Queries/QueriesFrame.tsx
+++ b/src/browser/modules/Stream/Queries/QueriesFrame.tsx
@@ -22,7 +22,6 @@ import { connect } from 'react-redux'
import { withBus } from 'react-suber'
import { Bus } from 'suber'
-import FrameAside from '../../Frame/FrameAside'
import FrameBodyTemplate from '../../Frame/FrameBodyTemplate'
import FrameError from '../../Frame/FrameError'
import {
@@ -39,75 +38,83 @@ import {
StyledTd,
StyledTh
} from './styled'
-import { EnterpriseOnlyFrame } from 'browser-components/EditionView'
import { ConfirmationButton } from 'browser-components/buttons/ConfirmationButton'
import { GlobalState } from 'project-root/src/shared/globalState'
-import bolt from 'services/bolt/bolt'
import { NEO4J_BROWSER_USER_ACTION_QUERY } from 'services/bolt/txMetadata'
import {
CONNECTED_STATE,
getConnectionState
} from 'shared/modules/connections/connectionsDuck'
-import {
- AD_HOC_CYPHER_REQUEST,
- CLUSTER_CYPHER_REQUEST,
- CYPHER_REQUEST
-} from 'shared/modules/cypher/cypherDuck'
-import {
- killQueriesProcedure,
- listQueriesProcedure
-} from 'shared/modules/cypher/queriesProcedureHelper'
+import { CYPHER_REQUEST } from 'shared/modules/cypher/cypherDuck'
+import { durationFormat } from 'services/bolt/cypherTypesFormatting'
+import { Frame } from 'shared/modules/frames/framesDuck'
+import LegacyQueriesFrame, {
+ LegacyQueriesFrameProps
+} from './LegacyQueriesFrame'
import {
getRawVersion,
+ getSemanticVersion,
hasProcedure,
isOnCausalCluster
} from 'shared/modules/dbMeta/dbMetaDuck'
-import { getDefaultBoltScheme } from 'shared/modules/features/versionedFeatures'
+import { gte } from 'semver'
type QueriesFrameState = {
queries: any[]
autoRefresh: boolean
autoRefreshInterval: number
- success: null | boolean | string
- errors: any[]
+ successMessage: null | string
+ errorMessages: string[]
}
type QueriesFrameProps = {
- frame?: any
+ frame?: Frame
bus: Bus
- canListQueries: boolean
connectionState: number
- neo4jVersion: string | null
isFullscreen: boolean
isCollapsed: boolean
- isOnCausalCluster: boolean
}
+
+function constructOverviewMessage(queries: any, errors: string[]) {
+ const numQueriesMsg = queries.length > 1 ? 'queries' : 'query'
+ const successMessage = `Found ${queries.length} ${numQueriesMsg} on one server (neo4j 5.0 clusters not yet supported).`
+
+ return errors.length > 0
+ ? `${successMessage} (${errors.length} unsuccessful)`
+ : successMessage
+}
+
export class QueriesFrame extends Component<
QueriesFrameProps,
QueriesFrameState
> {
- timer: any
- state = {
+ timer: number | undefined
+ state: QueriesFrameState = {
queries: [],
autoRefresh: false,
autoRefreshInterval: 20, // seconds
- success: null,
- errors: []
+ successMessage: null,
+ errorMessages: []
}
- componentDidMount() {
+ componentDidMount(): void {
if (this.props.connectionState === CONNECTED_STATE) {
this.getRunningQueries()
} else {
- this.setState({ errors: [new Error('Unable to connect to bolt server')] })
+ this.setState({
+ errorMessages: ['Unable to connect to neo4j']
+ })
}
}
- componentDidUpdate(prevProps: any, prevState: QueriesFrameState) {
+ componentDidUpdate(
+ prevProps: QueriesFrameProps,
+ prevState: QueriesFrameState
+ ): void {
if (prevState.autoRefresh !== this.state.autoRefresh) {
if (this.state.autoRefresh) {
this.timer = setInterval(
- this.getRunningQueries.bind(this),
+ this.getRunningQueries,
this.state.autoRefreshInterval * 1000
)
} else {
@@ -115,129 +122,100 @@ export class QueriesFrame extends Component<
}
}
if (
- (this.props.frame &&
- this.props.frame.ts !== prevProps.frame.ts &&
- this.props.frame.isRerun) ||
- this.props.isOnCausalCluster !== prevProps.isOnCausalCluster
+ this.props.frame &&
+ this.props.frame.ts !== prevProps.frame?.ts &&
+ this.props.frame.isRerun
) {
this.getRunningQueries()
}
}
- getRunningQueries(suppressQuerySuccessMessage = false) {
+ getRunningQueries = (suppressQuerySuccessMessage = false): void => {
this.props.bus.self(
- this.props.isOnCausalCluster ? CLUSTER_CYPHER_REQUEST : CYPHER_REQUEST,
+ CYPHER_REQUEST,
{
- query: listQueriesProcedure(),
+ query:
+ 'SHOW TRANSACTIONS YIELD currentQuery, username, metaData, parameters, status, elapsedTime, database, transactionId',
queryType: NEO4J_BROWSER_USER_ACTION_QUERY
},
- (response: any) => {
- if (response.success) {
- const queries = this.extractQueriesFromBoltResult(response.result)
+ resp => {
+ if (resp.success) {
+ const queries = resp.result.records.map(
+ ({ host, keys, _fields, error }: any) => {
+ if (error) return { error }
+ const nonNullHost = host ?? resp.result.summary.server.address
+ const data: any = {}
+ keys.forEach((key: string, idx: number) => {
+ data[key] = _fields[idx]
+ })
+
+ return {
+ ...data,
+ host: `neo4j://${nonNullHost}`,
+ query: data.currentQuery,
+ elapsedTimeMillis: durationFormat(data.elapsedTime),
+ queryId: data.transactionId
+ }
+ }
+ )
+
const errors = queries
.filter((_: any) => _.error)
.map((e: any) => ({
...e.error
}))
const validQueries = queries.filter((_: any) => !_.error)
- const resultMessage = this.constructOverviewMessage(
- validQueries,
- errors
- )
+ const resultMessage = constructOverviewMessage(validQueries, errors)
- this.setState((prevState: any) => {
- return {
- queries: validQueries,
- errors,
- success: suppressQuerySuccessMessage
- ? prevState.success
- : resultMessage
- }
- })
- } else {
- const errors: any[] = this.state.errors || []
- this.setState({
- errors: errors.concat([response.error]),
- success: false
- })
+ this.setState((prevState: QueriesFrameState) => ({
+ queries: validQueries,
+ errorMessages: errors,
+ successMessage: suppressQuerySuccessMessage
+ ? prevState.successMessage
+ : resultMessage
+ }))
}
}
)
}
- killQueries(host: any, queryIdList: any) {
+ killQueries(queryIdList: string[]): void {
this.props.bus.self(
- this.props.isOnCausalCluster ? AD_HOC_CYPHER_REQUEST : CYPHER_REQUEST,
- { host, query: killQueriesProcedure(queryIdList) },
+ CYPHER_REQUEST,
+ {
+ query: `TERMINATE TRANSACTIONS ${queryIdList
+ .map(q => `"${q}"`)
+ .join(',')}`,
+ queryType: NEO4J_BROWSER_USER_ACTION_QUERY
+ },
(response: any) => {
if (response.success) {
this.setState({
- success: 'Query successfully cancelled',
- errors: []
+ successMessage: 'Query successfully cancelled',
+ errorMessages: []
})
this.getRunningQueries(true)
} else {
- const errors: any[] = this.state.errors || []
- this.setState({
- errors: errors.concat([response.error]),
- success: false
- })
+ this.setState(state => ({
+ errorMessages: state.errorMessages.concat([response.error.message]),
+ successMessage: null
+ }))
}
}
)
}
- extractQueriesFromBoltResult(result: any) {
- return result.records.map(({ keys, _fields, host, error }: any) => {
- if (error) {
- return { error }
- }
- const queryInfo: any = {}
- keys.forEach((key: any, idx: any) => {
- queryInfo[key] = bolt.itemIntToNumber(_fields[idx])
- })
- if (host) {
- queryInfo.host = getDefaultBoltScheme(this.props.neo4jVersion) + host
- } else {
- queryInfo.host =
- getDefaultBoltScheme(this.props.neo4jVersion) +
- result.summary.server.address
- }
- return queryInfo
- })
- }
-
- onCancelQuery(host: any, queryId: any) {
- this.killQueries(host, [queryId])
- }
-
- constructOverviewMessage(queries: any, errors: any) {
- const clusterCount = new Set(queries.map((query: any) => query.host)).size
-
- const numMachinesMsg =
- clusterCount > 1
- ? `running on ${clusterCount} cluster servers`
- : 'running on one server'
-
- const numQueriesMsg = queries.length > 1 ? 'queries' : 'query'
-
- const successMessage = `Found ${queries.length} ${numQueriesMsg} ${numMachinesMsg}`
-
- return errors.length > 0 ? (
-
- {successMessage} ({errors.length} unsuccessful)
-
- ) : (
- successMessage
- )
+ killQuery(queryId: string): void {
+ this.killQueries([queryId])
}
- constructViewFromQueryList(queries: any, errors: any) {
+ constructViewFromQueryList = (): JSX.Element | null => {
+ const { queries, errorMessages: errors } = this.state
if (queries.length === 0) {
return null
}
const tableHeaderSizes = [
- ['Database URI', '20%'],
+ ['Database', '8%'],
['User', '8%'],
['Query', 'auto'],
['Params', '7%'],
@@ -245,151 +223,133 @@ export class QueriesFrame extends Component<
['Elapsed time', '95px'],
['Kill', '95px']
]
- const tableRows = queries.map((query: any, i: any) => {
- return (
-
-
- {query.host}
-
-
- {query.username}
-
-
- {query.query}
-
-
- {JSON.stringify(query.parameters, null, 2)}
-
-
- {JSON.stringify(query.metaData, null, 2)}
-
-
- {query.elapsedTimeMillis} ms
-
-
-
-
-
- )
- })
- const errorRows = errors.map((error: any, i: any) => (
-
-
- Error connecting to: {error.host}
-
-
- ))
-
- const tableHeaders = tableHeaderSizes.map(heading => {
- return (
-
- {heading[0]}
-
- )
- })
return (
- {tableHeaders}
+
+ {tableHeaderSizes.map(heading => (
+
+ {heading[0]}
+
+ ))}
+
- {tableRows}
- {errorRows}
+ {queries.map((query: any, i: number) => (
+
+
+ {query.database}
+
+
+ {query.username}
+
+
+ {query.query}
+
+
+ {JSON.stringify(query.parameters, null, 2)}
+
+
+ {JSON.stringify(query.metaData, null, 2)}
+
+
+ {query.elapsedTimeMillis} ms
+
+
+ this.killQuery(query.queryId)}
+ />
+
+
+ ))}
+
+ {errors.map((error: any, i: number) => (
+
+
+ Error connecting to: {error.host}
+
+
+ ))}
)
}
- setAutoRefresh(autoRefresh: any) {
- this.setState({ autoRefresh: autoRefresh })
+ setAutoRefresh(autoRefresh: boolean): void {
+ this.setState({ autoRefresh })
if (autoRefresh) {
this.getRunningQueries()
}
}
- render() {
- let frameContents
- let aside
- let statusBar
+ render(): JSX.Element {
+ const { isCollapsed, isFullscreen } = this.props
+ const { errorMessages, successMessage, autoRefresh } = this.state
- if (
- this.props.canListQueries ||
- this.props.connectionState !== CONNECTED_STATE
- ) {
- frameContents = this.constructViewFromQueryList(
- this.state.queries,
- this.state.errors
- )
- statusBar = (
-
- {this.state.errors && !this.state.success && (
- `${e.host}: ${e.message}`)
- .join(', ')}
- />
- )}
- {this.state.success && (
-
- {this.state.success}
-
- this.setAutoRefresh(e.target.checked)}
- />
-
-
- )}
-
- )
- } else {
- aside = (
-
- )
- frameContents =
- }
return (
+ {successMessage ? (
+
+ {successMessage}
+
+ this.setAutoRefresh(e.target.checked)}
+ />
+
+
+ ) : (
+ errorMessages &&
+ )}
+
+ }
/>
)
}
}
-const mapStateToProps = (state: GlobalState) => ({
- canListQueries: hasProcedure(state, 'dbms.listQueries'),
- connectionState: getConnectionState(state),
- neo4jVersion: getRawVersion(state),
- isOnCausalCluster: isOnCausalCluster(state)
-})
+const mapStateToProps = (state: GlobalState) => {
+ const version = getSemanticVersion(state)
+ const versionOverFive = version
+ ? gte(version, '5.0.0')
+ : true /* assume we're 5.0 */
+
+ return {
+ hasListQueriesProcedure: hasProcedure(state, 'dbms.listQueries'),
+ versionOverFive,
+ connectionState: getConnectionState(state),
+ neo4jVersion: getRawVersion(state),
+ isOnCausalCluster: isOnCausalCluster(state)
+ }
+}
-export default withBus(connect(mapStateToProps, null)(QueriesFrame))
+export default withBus(
+ connect(mapStateToProps)((props: LegacyQueriesFrameProps) => {
+ return props.versionOverFive ? (
+
+ ) : (
+
+ )
+ })
+)