Update diff view
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import * as React from 'react'
|
||||
import CodeDiff from './components/CodeDiff'
|
||||
import ConnectionSetup from './components/ConnectionSetup/ConnectionSetup'
|
||||
import CssBaseline from '@material-ui/core/CssBaseline'
|
||||
import ErrorBoundary from './ErrorBoundary'
|
||||
|
||||
77
app/src/components/CodeDiff.tsx
Normal file
77
app/src/components/CodeDiff.tsx
Normal file
@@ -0,0 +1,77 @@
|
||||
import * as diff from 'diff'
|
||||
import * as React from 'react'
|
||||
import * as Prism from 'prismjs'
|
||||
import { Theme, withStyles } from '@material-ui/core'
|
||||
require('prismjs/components/prism-json')
|
||||
import 'prismjs/themes/prism-tomorrow.css'
|
||||
|
||||
interface Props {
|
||||
previous: string
|
||||
current: string
|
||||
classes: any
|
||||
}
|
||||
|
||||
interface State {
|
||||
}
|
||||
|
||||
class CodeDiff extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const changes = diff.diffLines(this.props.previous, this.props.current)
|
||||
const styledLines = Prism.highlight(this.props.current, Prism.languages.json).split('\n')
|
||||
|
||||
let lineNumber = 0
|
||||
const code = changes.map((change, key) => {
|
||||
const hasStyledCode = change.removed !== true
|
||||
const changedLines = change.count || 0
|
||||
if (hasStyledCode) {
|
||||
const html = styledLines.slice(lineNumber, lineNumber + changedLines).join('\n')
|
||||
lineNumber += changedLines
|
||||
|
||||
return <div key={key}><span className={this.cssClassForChange(change)} dangerouslySetInnerHTML={{ __html: html }} /></div>
|
||||
}
|
||||
|
||||
return <div key={key}><span className={this.cssClassForChange(change)}>{change.value}</span></div>
|
||||
})
|
||||
|
||||
return <pre style={{ maxHeight: '200px' }} className="language-json">{code}</pre>
|
||||
}
|
||||
|
||||
private cssClassForChange(change: diff.Change) {
|
||||
if (change.added === true) {
|
||||
return this.props.classes.addition
|
||||
}
|
||||
|
||||
if (change.removed === true) {
|
||||
return this.props.classes.deletion
|
||||
}
|
||||
|
||||
return this.props.classes.code
|
||||
}
|
||||
}
|
||||
|
||||
const style = (theme: Theme) => {
|
||||
const baseStyle = {
|
||||
width: '100%',
|
||||
}
|
||||
return {
|
||||
code: {
|
||||
...baseStyle,
|
||||
// backgroundColor: theme.palette.background.paper,
|
||||
// color: theme.palette.text.primary,
|
||||
},
|
||||
deletion: {
|
||||
...baseStyle,
|
||||
backgroundColor: 'rgba(255, 10, 10, 0.3)',
|
||||
},
|
||||
addition: {
|
||||
...baseStyle,
|
||||
backgroundColor: 'rgba(10, 255, 10, 0.3)',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export default withStyles(style)(CodeDiff)
|
||||
@@ -1,9 +1,11 @@
|
||||
import * as diff from 'diff'
|
||||
import * as q from '../../../../backend/src/Model'
|
||||
import * as React from 'react'
|
||||
import { MonacoDiffEditor } from 'react-monaco-editor'
|
||||
import { default as ReactResizeDetector } from 'react-resize-detector'
|
||||
import { Theme, withTheme } from '@material-ui/core/styles'
|
||||
import * as diff from 'diff'
|
||||
import CodeDiff from '../CodeDiff';
|
||||
|
||||
const sha1 = require('sha1')
|
||||
|
||||
interface Props {
|
||||
node?: q.TreeNode<any>,
|
||||
@@ -13,7 +15,6 @@ interface Props {
|
||||
|
||||
interface State {
|
||||
width: number
|
||||
modifiedValue?: string
|
||||
node?: q.TreeNode<any>
|
||||
currentMessage?: q.Message
|
||||
}
|
||||
@@ -25,13 +26,22 @@ class ValueRenderer extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
public render() {
|
||||
return <div style={{ padding: '8px 0px 8px 8px' }}>{this.renderValue()}</div>
|
||||
if (!this.props.node) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '8px 0px 8px 8px' }}>
|
||||
<ReactResizeDetector handleWidth={true} onResize={this.updateWidth} />
|
||||
{this.renderValue()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public renderValue() {
|
||||
const { node } = this.props
|
||||
if (!node || !node.message) {
|
||||
return null
|
||||
return <span key="empty" />
|
||||
}
|
||||
|
||||
const message = node.message
|
||||
@@ -53,8 +63,8 @@ class ValueRenderer extends React.Component<Props, State> {
|
||||
} else if (typeof json === 'boolean') {
|
||||
return this.renderRawValue(message.value, compareMessage.value)
|
||||
} else {
|
||||
const current = this.messageToPrettyJson(message)
|
||||
const compare = this.messageToPrettyJson(compareMessage)
|
||||
const current = this.messageToPrettyJson(message) || message.value
|
||||
const compare = this.messageToPrettyJson(compareMessage) || compareMessage.value
|
||||
const language = current && compare ? 'json' : undefined
|
||||
|
||||
return this.renderDiff(current, compare, language)
|
||||
@@ -67,66 +77,19 @@ class ValueRenderer extends React.Component<Props, State> {
|
||||
...state,
|
||||
node: props.node,
|
||||
currentMessage: props.node && props.node.message,
|
||||
modifiedValue: discardEdit ? undefined : state.modifiedValue,
|
||||
}
|
||||
}
|
||||
|
||||
private heightForLines(lines: number) {
|
||||
return 0 + (lines * 18)
|
||||
}
|
||||
|
||||
private editorOptions = {
|
||||
lineHeigh: 16,
|
||||
lineNumbers: 'off' as 'off',
|
||||
scrollBeyondLastLine: false,
|
||||
minimap: { enabled: false },
|
||||
theme: 'vs-dark',
|
||||
}
|
||||
|
||||
private renderDiff(current: string = '', previous: string = '', language: 'json' | undefined) {
|
||||
const theme = (this.props.theme.palette.type === 'dark') ? 'monokai' : 'bright:inverted'
|
||||
|
||||
const value = this.state.modifiedValue !== undefined ? this.state.modifiedValue : current
|
||||
const lines = this.expectedLineCountFor(value, previous)
|
||||
const height = this.heightForLines(lines)
|
||||
private renderDiff(current: string = '', previous: string = '') {
|
||||
return (
|
||||
<div>
|
||||
<ReactResizeDetector handleWidth={true} onResize={this.updateWidth} />
|
||||
<MonacoDiffEditor
|
||||
key="editor"
|
||||
language={language}
|
||||
height={Math.min(height, 200)}
|
||||
options={{ ...this.editorOptions, renderSideBySide: false }}
|
||||
onChange={value => this.setState({ modifiedValue: value })}
|
||||
original={previous}
|
||||
width={this.state.width}
|
||||
value={value}
|
||||
/>
|
||||
</div>
|
||||
<CodeDiff
|
||||
key={sha1(current + previous)}
|
||||
previous={previous}
|
||||
current={current}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private expectedLineCountFor(current?: string, original?: string): number {
|
||||
if (current === undefined) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const originalStr = original || ''
|
||||
const changes = diff.diffLines(originalStr, current)
|
||||
|
||||
const added = changes
|
||||
.map((change) => {
|
||||
const added = (change.added && change.count) || 0
|
||||
|
||||
return Math.abs(added)
|
||||
})
|
||||
.reduce((a: number, b: number) => a + b, 0)
|
||||
|
||||
const originalLines = originalStr.split('\n').length
|
||||
|
||||
return originalLines + added
|
||||
}
|
||||
|
||||
private messageToPrettyJson(message?: q.Message): string | undefined {
|
||||
if (!message || !message.value) {
|
||||
return undefined
|
||||
@@ -141,11 +104,13 @@ class ValueRenderer extends React.Component<Props, State> {
|
||||
}
|
||||
|
||||
private updateWidth = (width: number) => {
|
||||
this.setState({ width })
|
||||
if (width !== this.state.width) {
|
||||
this.setState({ width })
|
||||
}
|
||||
}
|
||||
|
||||
private renderRawValue(value: string, compare?: string) {
|
||||
return this.renderDiff(value, compare, undefined)
|
||||
private renderRawValue(value: string, compare: string) {
|
||||
return this.renderDiff(value, compare)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user