mirror of
https://github.com/chenasraf/redar-browser.git
synced 2026-05-17 17:58:04 +00:00
Recursive keylist
This commit is contained in:
8
src/components/KeyList/KeyList.module.d.ts
vendored
8
src/components/KeyList/KeyList.module.d.ts
vendored
@@ -4,6 +4,12 @@ export interface IProps {
|
||||
}
|
||||
|
||||
export interface IState {
|
||||
keyList: string[]
|
||||
keyList: KeyItem[]
|
||||
viewKey: string
|
||||
}
|
||||
|
||||
export interface KeyItem {
|
||||
label: string,
|
||||
path: string
|
||||
children?: KeyItem[]
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import SelectBox, { Option, styles as selectBoxStyle } from 'components/SelectBo
|
||||
import Button from 'components/Button/Button'
|
||||
import axios, { AxiosResponse } from 'axios'
|
||||
import Dispatcher, { register, dispatch, ActionTypes, StoreKeys } from 'common/Dispatcher'
|
||||
import * as classNames from 'classnames'
|
||||
|
||||
class KeyList extends React.Component<I.IProps, I.IState> {
|
||||
private listeners: string[]
|
||||
@@ -16,6 +17,15 @@ class KeyList extends React.Component<I.IProps, I.IState> {
|
||||
keyList: this.keyListFromObject(props.store.get(StoreKeys.Response, {})),
|
||||
viewKey: props.store.get(StoreKeys.ViewKey, '')
|
||||
}
|
||||
console.debug(this.keyListFromObject({
|
||||
one: {
|
||||
two: 2,
|
||||
three: {
|
||||
four: 4,
|
||||
five: 5
|
||||
}
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
public componentWillMount() {
|
||||
@@ -39,45 +49,66 @@ class KeyList extends React.Component<I.IProps, I.IState> {
|
||||
this.listeners.forEach(l => Dispatcher.unregister(l))
|
||||
}
|
||||
|
||||
private keyListFromObject(data: any) {
|
||||
return [''].concat(Object.keys(data))
|
||||
private keyListFromObject(data: any, relativePath: string = ''): I.KeyItem[] {
|
||||
const list: I.KeyItem[] = []
|
||||
|
||||
if (relativePath === '') {
|
||||
list.push({
|
||||
label: '[Response]',
|
||||
path: '',
|
||||
})
|
||||
}
|
||||
|
||||
Object.keys(data).forEach((key) => {
|
||||
const newPath = relativePath ? [relativePath, key].join('.') : key
|
||||
let children
|
||||
|
||||
if (typeof data[key] !== 'string' && typeof data[key] !== 'number' &&
|
||||
data[key].constructor !== Array && Object.keys(data[key]).length) {
|
||||
children = this.keyListFromObject(data[key], newPath)
|
||||
}
|
||||
|
||||
list.push({ label: key, path: newPath, children })
|
||||
})
|
||||
return list
|
||||
}
|
||||
|
||||
private selectItem(key: string) {
|
||||
this.setState({ viewKey: key }, () => {
|
||||
dispatch(ActionTypes.UPDATE_VIEWKEY, key)
|
||||
private selectItem(key: I.KeyItem) {
|
||||
this.setState({ viewKey: key.path }, () => {
|
||||
dispatch(ActionTypes.UPDATE_VIEWKEY, key.path)
|
||||
})
|
||||
}
|
||||
|
||||
private get keyListElements() {
|
||||
private keyListElements(keyList: I.KeyItem[], depth: number = 0) {
|
||||
const fullData = this.props.store.get(StoreKeys.Response, {})
|
||||
const viewKey = this.state.viewKey
|
||||
|
||||
return this.state.keyList.map((key: string) => {
|
||||
const className = [
|
||||
css.item,
|
||||
key === '' || (fullData[key] && fullData[key].constructor === Array) ? css.valid : '',
|
||||
viewKey === key ? css.selected : ''
|
||||
].join(' ')
|
||||
return keyList.map((key: I.KeyItem) => {
|
||||
const className = classNames(css.item, {
|
||||
[css.selected]: viewKey === key.path
|
||||
})
|
||||
|
||||
return (
|
||||
<div className={className}
|
||||
key={key}
|
||||
onClick={(e) => this.selectItem(key)}>
|
||||
{key === '' ? '[Response]' : key}
|
||||
<div key={key.path}>
|
||||
<div className={className}
|
||||
style={{marginLeft: depth * 20 + 'px'}}
|
||||
onClick={(e) => this.selectItem(key)}>
|
||||
{key.label}
|
||||
</div>
|
||||
{key.children && key.children.length ? (
|
||||
this.keyListElements(key.children, depth + 1)
|
||||
) : ''}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
const classNames = [
|
||||
css.KeyList,
|
||||
this.props.className || ''
|
||||
].join(' ')
|
||||
const className = classNames(css.KeyList, this.props.className)
|
||||
|
||||
return (
|
||||
<div className={classNames}>
|
||||
{this.keyListElements}
|
||||
<div className={className}>
|
||||
{this.keyListElements(this.state.keyList)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -24,16 +24,16 @@ class ResponseRepr extends React.Component<I.IProps, I.IState> {
|
||||
this.listeners = [
|
||||
D.register(D.ActionTypes.UPDATE_RESPONSE, (response) => {
|
||||
const viewKey = this.props.store.get(D.StoreKeys.ViewKey)
|
||||
if (viewKey && Object.keys(response).indexOf(viewKey) > -1) {
|
||||
response = response[viewKey]
|
||||
if (viewKey) {
|
||||
response = this.objectByPath(response, viewKey)
|
||||
}
|
||||
this.setState({ response })
|
||||
}),
|
||||
|
||||
D.register(D.ActionTypes.UPDATE_VIEWKEY, (viewKey) => {
|
||||
let resp = this.props.store.get(D.StoreKeys.Response, {})
|
||||
resp = resp && viewKey && resp.hasOwnProperty(viewKey) ? resp[viewKey] : resp
|
||||
this.setState({ response: resp })
|
||||
let response = this.props.store.get(D.StoreKeys.Response, {})
|
||||
response = response && viewKey ? this.objectByPath(response, viewKey) : response
|
||||
this.setState({ response: response })
|
||||
}),
|
||||
]
|
||||
}
|
||||
@@ -42,6 +42,16 @@ class ResponseRepr extends React.Component<I.IProps, I.IState> {
|
||||
this.listeners.forEach(listener => D.AppDispatcher.unregister(listener))
|
||||
}
|
||||
|
||||
private objectByPath(obj: any, key: string) {
|
||||
return key.split('.').reduce((acc, cur, i) => {
|
||||
if (acc.hasOwnProperty(cur)) {
|
||||
return acc[cur]
|
||||
} else {
|
||||
throw new Error('invalid key!')
|
||||
}
|
||||
}, obj)
|
||||
}
|
||||
|
||||
private sortBy(key: string) {
|
||||
this.setState((cur) => ({
|
||||
sortKey: key,
|
||||
@@ -81,8 +91,8 @@ class ResponseRepr extends React.Component<I.IProps, I.IState> {
|
||||
// numbers are matching
|
||||
if (typeof a[key] === 'number' && typeof b === 'number' ||
|
||||
isFinite(a[key]) && isFinite(b[key])) {
|
||||
const out = parseFloat(a[key]) - parseFloat(b[key])
|
||||
return desc ? -out : out
|
||||
const result = parseFloat(a[key]) - parseFloat(b[key])
|
||||
return desc ? -result : result
|
||||
}
|
||||
|
||||
if (a[key] > b[key]) {
|
||||
@@ -137,40 +147,55 @@ class ResponseRepr extends React.Component<I.IProps, I.IState> {
|
||||
return response
|
||||
}
|
||||
|
||||
private filterInput() {
|
||||
return (
|
||||
<input className={css.filterInput}
|
||||
type="text" value={this.state.filter}
|
||||
placeholder={`Filter data (e.g.: first_name="John" age>=32)`}
|
||||
onChange={(e) => this.setState({ filter: e.target.value })} />
|
||||
)
|
||||
}
|
||||
|
||||
private table() {
|
||||
const keys = Object.keys(this.state.response && this.state.response[0] || {})
|
||||
const colAmt = keys.length
|
||||
|
||||
return (
|
||||
<div className={css.table}
|
||||
style={{gridTemplateColumns: `repeat(${colAmt}, auto)`}}>
|
||||
{this.filterInput()}
|
||||
{this.columns()}
|
||||
{this.processedResponse().map((row, i) => {
|
||||
const cls = (j) => {
|
||||
return classNames(css.cell, {
|
||||
[css.rowStart]: j % colAmt === 0,
|
||||
[css.rowEnd]: j % colAmt === colAmt - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<RObject className={cls}
|
||||
key={`row-${i}`}
|
||||
data={row} />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private getRObjectList() {
|
||||
const { response } = this.state
|
||||
let colAmt
|
||||
|
||||
if (response && response.constructor === Array) {
|
||||
const keys = Object.keys(response[0] || {})
|
||||
colAmt = keys.length
|
||||
return (
|
||||
<div className={css.table}
|
||||
style={{gridTemplateColumns: `repeat(${colAmt}, auto)`}}>
|
||||
{this.columns()}
|
||||
{this.processedResponse().map((row, i) => {
|
||||
const cls = (j) => {
|
||||
return classNames(css.cell, {
|
||||
[css.rowStart]: j % colAmt === 0,
|
||||
[css.rowEnd]: j % colAmt === colAmt - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<RObject className={cls}
|
||||
key={`row-${i}`}
|
||||
data={row} />
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
return this.table()
|
||||
}
|
||||
|
||||
colAmt = Object.keys(response || {})
|
||||
|
||||
return (
|
||||
<div className={css.table}
|
||||
style={{gridTemplateRows: `repeat(${colAmt}, auto)`}}>
|
||||
style={{gridTemplateRows: `repeat(${colAmt}, min-content)`}}>
|
||||
<RObject data={response} />
|
||||
</div>
|
||||
)
|
||||
@@ -181,16 +206,10 @@ class ResponseRepr extends React.Component<I.IProps, I.IState> {
|
||||
css.ResponseRepr,
|
||||
this.props.className
|
||||
].join(' ')
|
||||
|
||||
const repr = this.getRObjectList()
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<input className={css.filterInput}
|
||||
type="text" value={this.state.filter}
|
||||
placeholder={`Filter data (e.g.: first_name="John" age>=32)`}
|
||||
onChange={(e) => this.setState({ filter: e.target.value })} />
|
||||
{repr}
|
||||
{this.getRObjectList()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user