Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make accessing query result records in ascii view type safe #1281

Merged
merged 5 commits into from
Feb 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/browser/modules/D3Visualization/components/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import neoGraphStyle from '../graphStyle'
import { InspectorComponent } from './Inspector'
import { LegendComponent } from './Legend'
import { StyledFullSizeContainer } from './styled'
import { GlobalState } from 'shared/globalState'
import { getMaxFieldItems } from 'shared/modules/settings/settingsDuck'
import { connect } from 'react-redux'

Expand Down Expand Up @@ -247,6 +248,6 @@ export class ExplorerComponent extends Component<any, ExplorerComponentState> {
)
}
}
export const Explorer = connect(state => ({
export const Explorer = connect((state: GlobalState) => ({
maxFieldItems: getMaxFieldItems(state)
}))(ExplorerComponent)
2 changes: 1 addition & 1 deletion src/browser/modules/Frame/FrameTemplate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type FrameTemplateProps = {
contents: JSX.Element | null | string
header?: Frame
className?: string
onResize?: (fullscreen: boolean, collapsed: boolean, height?: number) => void
onResize?: (fullscreen: boolean, collapsed: boolean, height: number) => void
numRecords?: number
getRecords?: () => any
visElement?: any
Expand Down
8 changes: 4 additions & 4 deletions src/browser/modules/Frame/FrameTitlebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import * as editor from 'shared/modules/editor/editorDuck'
import {
cancel as cancelRequest,
getRequest,
Request,
BrowserRequest,
REQUEST_STATUS_PENDING
} from 'shared/modules/requests/requestsDuck'
import {
Expand Down Expand Up @@ -109,15 +109,15 @@ type FrameTitleBarBaseProps = {
}

type FrameTitleBarProps = FrameTitleBarBaseProps & {
request: Request | null
request: BrowserRequest | null
isRelateAvailable: boolean
newFavorite: (cmd: string) => void
newProjectFile: (cmd: string) => void
cancelQuery: (requestId: string) => void
onCloseClick: (
frameId: string,
requestId: string,
request: Request | null
request: BrowserRequest | null
) => void
onRunClick: () => void
reRun: (obj: Frame, cmd: string) => void
Expand Down Expand Up @@ -467,7 +467,7 @@ const mapDispatchToProps = (
onCloseClick: async (
id: string,
requestId: string,
request: Request | null
request: BrowserRequest | null
) => {
if (request && request.status === REQUEST_STATUS_PENDING) {
dispatch(cancelRequest(requestId))
Expand Down
35 changes: 25 additions & 10 deletions src/browser/modules/Stream/CypherFrame/AsciiView.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('AsciiViews', () => {
test('displays bodyMessage if no rows', () => {
// Given
const sps = jest.fn()
const result = {
const result: any = {
records: [],
summary: {
resultAvailableAfter: neo4j.int(5),
Expand All @@ -42,7 +42,12 @@ describe('AsciiViews', () => {

// When
const { container } = render(
<AsciiView setParentState={sps} result={result} maxRows={5} />
<AsciiView
setAsciiMaxColWidth={sps}
result={result}
maxRows={5}
maxFieldItems={5}
/>
)

// Then
Expand All @@ -51,7 +56,7 @@ describe('AsciiViews', () => {
test('does not display bodyMessage if rows', () => {
// Given
const sps = jest.fn()
const result = {
const result: any = {
records: [{ keys: ['x'], _fields: ['y'], get: () => 'y' }],
summary: {
resultAvailableAfter: neo4j.int(5),
Expand All @@ -61,7 +66,12 @@ describe('AsciiViews', () => {

// When
const { container } = render(
<AsciiView setParentState={sps} result={result} />
<AsciiView
setAsciiMaxColWidth={sps}
result={result}
maxRows={5}
maxFieldItems={5}
/>
)

// Then
Expand All @@ -72,7 +82,7 @@ describe('AsciiViews', () => {
test('displays statusBarMessage if no rows', () => {
// Given
const sps = jest.fn()
const result = {
const result: any = {
records: [],
summary: {
resultAvailableAfter: neo4j.int(5),
Expand All @@ -82,7 +92,12 @@ describe('AsciiViews', () => {

// When
const { container } = render(
<AsciiStatusbar setParentState={sps} result={result} />
<AsciiStatusbar
setAsciiSetColWidth={sps}
result={result}
maxRows={5}
maxFieldItems={5}
/>
)

// Then
Expand All @@ -91,21 +106,21 @@ describe('AsciiViews', () => {
test('displays statusBarMessage if no rows', () => {
// Given
const sps = jest.fn()
const result = {
const result: any = {
records: [{ keys: ['x'], _fields: ['y'], get: () => 'y' }],
summary: {
resultAvailableAfter: neo4j.int(5),
resultConsumedAfter: neo4j.int(5)
}
}
const serializedRows = [['x'], ['y']]

// When
const { container } = render(
<AsciiStatusbar
setParentState={sps}
setAsciiSetColWidth={sps}
result={result}
_asciiSerializedRows={serializedRows}
maxRows={5}
maxFieldItems={5}
/>
)

Expand Down
98 changes: 70 additions & 28 deletions src/browser/modules/Stream/CypherFrame/AsciiView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,29 +43,44 @@ import { stringModifier } from 'services/bolt/cypherTypesFormatting'
import { getMaxFieldItems } from 'shared/modules/settings/settingsDuck'
import { connect } from 'react-redux'
import { Icon } from 'semantic-ui-react'
import { GlobalState } from 'shared/globalState'
import { BrowserRequestResult } from 'shared/modules/requests/requestsDuck'

type AsciiViewComponentState = any
interface BaseAsciiViewComponentProps {
result: BrowserRequestResult
updated?: number
maxRows: unknown
_asciiSetColWidth?: string
setAsciiMaxColWidth: { (asciiMaxColWidth: number): void }
}
interface AsciiViewComponentProps extends BaseAsciiViewComponentProps {
maxFieldItems: number
}
interface AsciiViewComponentState {
serializedRows: string[]
bodyMessage: string | null
}

export class AsciiViewComponent extends Component<
any,
AsciiViewComponentProps,
AsciiViewComponentState
> {
state = {
serializedRows: [] as any[],
state: AsciiViewComponentState = {
serializedRows: [],
bodyMessage: ''
}

componentDidMount() {
componentDidMount(): void {
this.makeState(this.props)
}

componentDidUpdate(prevProps: {}) {
componentDidUpdate(prevProps: AsciiViewComponentProps): void {
if (!this.equalProps(prevProps)) {
this.makeState(this.props)
}
}

equalProps(props: any) {
equalProps(props: AsciiViewComponentProps): boolean {
if (
this.props !== undefined &&
this.props.result !== undefined &&
Expand All @@ -78,16 +93,22 @@ export class AsciiViewComponent extends Component<
return false
}

shouldComponentUpdate(props: {}, state: AsciiViewComponentState) {
shouldComponentUpdate(
props: AsciiViewComponentProps,
state: AsciiViewComponentState
): boolean {
return !this.equalProps(props) || !shallowEquals(state, this.state)
}

makeState(props: any) {
makeState(props: AsciiViewComponentProps): void {
const { result, maxRows, maxFieldItems } = props
const { bodyMessage = null } =
getBodyAndStatusBarMessages(result, maxRows) || {}
this.setState({ bodyMessage })
if (!result || !result.records || !result.records.length) return

const hasRecords = result && 'records' in result && result.records.length
if (!hasRecords) return

const records = getRecordsToDisplayInTable(props.result, props.maxRows)
const serializedRows =
stringifyResultArray(
Expand All @@ -98,11 +119,10 @@ export class AsciiViewComponent extends Component<
this.setState({ serializedRows })
const maxColWidth = asciitable.maxColumnWidth(serializedRows)

this.props.setParentState &&
this.props.setParentState({ _asciiMaxColWidth: maxColWidth })
this.props.setAsciiMaxColWidth(maxColWidth)
}

render() {
render(): JSX.Element {
const { _asciiSetColWidth: maxColWidth = 70 } = this.props
const { serializedRows, bodyMessage } = this.state
let contents = <StyledBodyMessage>{bodyMessage}</StyledBodyMessage>
Expand All @@ -121,29 +141,48 @@ export class AsciiViewComponent extends Component<
}
}

export const AsciiView = connect(state => ({
export const AsciiView = connect((state: GlobalState) => ({
maxFieldItems: getMaxFieldItems(state)
}))(AsciiViewComponent)

type AsciiStatusbarComponentState = any
interface BaseAsciiStatusbarComponentProps {
_asciiMaxColWidth?: number
_asciiSetColWidth?: string
maxRows: number
result: BrowserRequestResult
setAsciiSetColWidth: { (asciiSetColWidth: string): void }
updated?: number
}

interface AsciiStatusbarComponentProps
extends BaseAsciiStatusbarComponentProps {
maxFieldItems: number
}
interface AsciiStatusbarComponentState {
maxSliderWidth: number
minSliderWidth: number
maxColWidth: number | string
statusBarMessage: string | null
hasTruncatedFields: boolean
}

export class AsciiStatusbarComponent extends Component<
any,
AsciiStatusbarComponentProps,
AsciiStatusbarComponentState
> {
state = {
state: AsciiStatusbarComponentState = {
maxSliderWidth: 140,
minSliderWidth: 3,
maxColWidth: 70,
statusBarMessage: '',
hasTruncatedFields: false
}

componentDidUpdate() {
componentDidUpdate(): void {
this.makeState(this.props)
}

makeState(props: any) {
makeState(props: AsciiStatusbarComponentProps): void {
this.setMaxSliderWidth(props._asciiMaxColWidth)
const { statusBarMessage = null } =
getBodyAndStatusBarMessages(props.result, props.maxRows) || {}
Expand All @@ -154,7 +193,10 @@ export class AsciiStatusbarComponent extends Component<
this.setState({ statusBarMessage, hasTruncatedFields })
}

shouldComponentUpdate(props: any, state: AsciiStatusbarComponentState) {
shouldComponentUpdate(
props: AsciiStatusbarComponentProps,
state: AsciiStatusbarComponentState
): boolean {
return (
state.maxColWidth !== this.state.maxColWidth ||
state.maxSliderWidth !== this.state.maxSliderWidth ||
Expand All @@ -164,23 +206,23 @@ export class AsciiStatusbarComponent extends Component<
)
}

componentDidMount() {
componentDidMount(): void {
this.makeState(this.props)
}

setColWidthChanged = (w: any) => {
setColWidthChanged = (w: React.ChangeEvent<HTMLInputElement>): void => {
const value = w.target.value
this.setState({ maxColWidth: value })
this.props.setParentState({ _asciiSetColWidth: value })
this.props.setAsciiSetColWidth(value)
}

setMaxSliderWidth(w: any) {
setMaxSliderWidth(w?: number): void {
this.setState({ maxSliderWidth: w || this.state.minSliderWidth })
}

render() {
const hasRecords =
this.props.result.records && this.props.result.records.length
render(): JSX.Element {
const { result } = this.props
const hasRecords = result && 'records' in result && result.records.length
const { maxColWidth, maxSliderWidth, hasTruncatedFields } = this.state
return (
<StyledStatsBar>
Expand Down Expand Up @@ -212,6 +254,6 @@ export class AsciiStatusbarComponent extends Component<
}
}

export const AsciiStatusbar = connect(state => ({
export const AsciiStatusbar = connect((state: GlobalState) => ({
maxFieldItems: getMaxFieldItems(state)
}))(AsciiStatusbarComponent)
4 changes: 2 additions & 2 deletions src/browser/modules/Stream/CypherFrame/CancelView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import Centered from 'browser-components/Centered'
import { SpinnerContainer, StyledBodyMessage } from '../styled'
import { Spinner } from 'browser-components/icons/Icons'
import {
RequestStatus,
Status,
REQUEST_STATUS_CANCELED,
REQUEST_STATUS_CANCELING
} from 'shared/modules/requests/requestsDuck'

interface CancelViewProps {
requestStatus: RequestStatus
requestStatus: Status
}

export const CancelView = ({ requestStatus }: CancelViewProps): JSX.Element => (
Expand Down
3 changes: 2 additions & 1 deletion src/browser/modules/Stream/CypherFrame/CodeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
import { getMaxFieldItems } from 'shared/modules/settings/settingsDuck'
import { connect } from 'react-redux'
import { map, take } from 'lodash-es'
import { GlobalState } from 'shared/globalState'

type ExpandableContentState = any

Expand Down Expand Up @@ -122,7 +123,7 @@ export class CodeViewComponent extends Component<any> {
}
}

export const CodeView = connect(state => ({
export const CodeView = connect((state: GlobalState) => ({
maxFieldItems: getMaxFieldItems(state)
}))(CodeViewComponent)

Expand Down
2 changes: 1 addition & 1 deletion src/browser/modules/Stream/CypherFrame/WarningsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ export class WarningsView extends Component<any> {
}
}

export class WarningsStatusbar extends Component {
export class WarningsStatusbar extends Component<any> {
shouldComponentUpdate() {
return false
}
Expand Down
Loading