Change response representation to cards instead of table

This commit is contained in:
Chen Asraf
2018-01-21 02:02:44 +02:00
parent 8012e8ac01
commit 47c56ad42a
15 changed files with 205 additions and 30 deletions

View File

@@ -1,5 +1,5 @@
export interface IProps {
// props
className?: string
}
export interface IState {

View File

@@ -5,14 +5,13 @@ import * as I from './{{Name}}.module'
class {{Name}} extends React.Component<I.IProps, I.IState> {
constructor(props: I.IProps) {
super(props)
this.state = {
//
}
this.state = {}
}
render() {
const classNames = [
css.{{Name}},
this.props.className
].join(' ')
return (

View File

@@ -1,3 +1,5 @@
$font-family: "Helvetica Neue", "Calibri", "Segoe UI", "Arial", sans-serif;
$highlight: #05a;
$text-main: #222;
$text-light: #555;
$drop-shadow: drop-shadow(1.5px 1.5px 1px #0003);

View File

@@ -18,20 +18,23 @@ const StoreKeys = {
RequestType: 'REQ_TYPE'
}
export interface Action<T = any> {
name: string,
export type TActionName =
'UPDATE_RESPONSE' | 'UPDATE_TABLE' | 'UPDATE_COLUMNS' | 'UPDATE_VIEWKEY' | 'UPDATE_REQ_TYPE'
export interface IAction<T = any> {
name: TActionName | string,
payload?: T
}
export const AppDispatcher = new Dispatcher<Action>()
export const AppDispatcher = new Dispatcher<IAction>()
function innerObjFromKey<T = any>(obj: T, k: string): Immutable.OrderedMap<string, T> {
return Immutable.OrderedMap<string, any>(obj || {}).get(k, {})
}
type TState = Immutable.OrderedMap<string, any>
export type IState = Immutable.OrderedMap<string, any>
class AppStore extends ReduceStore<TState, Action> {
class AppStore extends ReduceStore<IState, IAction> {
constructor() {
super(AppDispatcher)
}
@@ -40,7 +43,7 @@ class AppStore extends ReduceStore<TState, Action> {
return Immutable.OrderedMap<string, any>()
}
reduce(state: TState, action: Action) {
reduce(state: IState, action: IAction) {
switch (action.name) {
case ActionTypes.UPDATE_COLUMNS:
return state.set(StoreKeys.Columns, action.payload)
@@ -56,14 +59,14 @@ class AppStore extends ReduceStore<TState, Action> {
}
}
export function dispatch(name: string, payload: any) {
export function dispatch(name: TActionName | string, payload: any) {
AppDispatcher.dispatch({
name, payload
})
}
export function register(name: string, callback: (payload: any) => void): string {
return AppDispatcher.register((payload: Action) => {
function register(name: TActionName | string, callback: (payload: any) => void): string {
return AppDispatcher.register((payload: IAction) => {
if (payload.name === name) {
console.debug('Dispatching:', payload.name, payload.payload)
callback(payload.payload)
@@ -73,4 +76,4 @@ export function register(name: string, callback: (payload: any) => void): string
const Store = new AppStore()
export default AppDispatcher
export { Store, ActionTypes, StoreKeys }
export { Store, ActionTypes, StoreKeys, AppDispatcher as Dispatcher, register }

View File

@@ -84,23 +84,23 @@ class Header extends React.Component<I.IProps, I.IState> {
axios.request({ method, url, data: this.requestPayload, headers: this.requestHeaders })
.then((response: AxiosResponse) => {
const { data } = response
let viewKey = this.props.store.get(StoreKeys.ViewKey, null)
let tableData
// let viewKey = this.props.store.get(StoreKeys.ViewKey, null)
// let tableData
if (viewKey && data.hasOwnProperty(viewKey)) {
tableData = data[viewKey]
} else {
viewKey = ''
}
// if (viewKey && data.hasOwnProperty(viewKey)) {
// tableData = data[viewKey]
// } else {
// viewKey = ''
// }
if (viewKey === '' || !tableData) {
tableData = [data]
}
// if (viewKey === '' || !tableData) {
// tableData = [data]
// }
dispatch(ActionTypes.UPDATE_RESPONSE, data)
dispatch(ActionTypes.UPDATE_VIEWKEY, viewKey)
dispatch(ActionTypes.UPDATE_TABLE, tableData)
dispatch(ActionTypes.UPDATE_COLUMNS, this.getDataColumns(tableData))
// dispatch(ActionTypes.UPDATE_VIEWKEY, viewKey)
// dispatch(ActionTypes.UPDATE_TABLE, tableData)
// dispatch(ActionTypes.UPDATE_COLUMNS, this.getDataColumns(tableData))
})
}

View File

@@ -0,0 +1,29 @@
@import "../../_variables.css";
.RObject {
display: inline-block;
background: #fff;
filter: $drop-shadow;
// max-width: 20vw;
padding: 7px;
margin: 7px 5px;
vertical-align: top;
border: 1px solid #ccc;
border-radius: 4px;
& > h3 {
font-size: 0.8rem;
font-weight: bold;
text-transform: uppercase;
color: $text-light;
margin-bottom: 5px;
}
}
.simple {
display: inline-block;
max-width: 16vw;
overflow: hidden;
white-space: pre;
text-overflow: ellipsis;
}

View File

@@ -0,0 +1,3 @@
export const RObject: string;
export const rObject: string;
export const simple: string;

View File

@@ -0,0 +1,8 @@
export interface IProps {
className?: string
data: any
}
export interface IState {
// state
}

View File

@@ -0,0 +1,50 @@
import * as React from 'react'
import * as css from './RObject.css'
import * as I from './RObject.module'
class RObject extends React.Component<I.IProps, I.IState> {
constructor(props: I.IProps) {
super(props)
this.state = {}
}
private getCorrectRepr(obj: any, cls?: string) {
try {
switch (typeof obj) {
case 'number':
case 'string':
return <span className={css.simple}>{obj}</span>
default:
const keys = obj ? Object.keys(obj) : []
const isArray = obj && obj.constructor === Array
if (!keys.length) {
return <span>{JSON.stringify(obj)}</span>
}
return keys.map((k: string) => {
return (
<div className={cls} key={'obj-' + k}>
<h3>{!isArray ? k : typeof obj}</h3>
<RObject data={obj[k]} />
</div>
)
})
}
} catch (e) {
return <span className={css.simple}>{typeof obj}</span>
}
}
render() {
const classNames = [
css.RObject,
this.props.className
].join(' ')
const repr = this.getCorrectRepr(this.props.data, classNames)
return repr
}
}
export default RObject

View File

@@ -0,0 +1,9 @@
@import "../../_variables.css";
.ResponseRepr {
/* */
}
.obj {
// max-width: 11vw;
}

View File

@@ -0,0 +1,3 @@
export const ResponseRepr: string;
export const responseRepr: string;
export const obj: string;

View File

@@ -0,0 +1,8 @@
export interface IProps {
className?: string
store: any
}
export interface IState {
response: any
}

View File

@@ -0,0 +1,61 @@
import * as React from 'react'
import * as css from './ResponseRepr.css'
import * as I from './ResponseRepr.module'
import * as D from 'common/Dispatcher'
import RObject from 'components/RObject/RObject'
class ResponseRepr extends React.Component<I.IProps, I.IState> {
private listeners: string[]
constructor(props: I.IProps) {
super(props)
this.state = {
response: props.store.get(D.ActionTypes.UPDATE_RESPONSE)
}
}
componentDidMount() {
this.listeners = [
D.register(D.ActionTypes.UPDATE_RESPONSE, (response) => {
this.setState({ response })
}),
D.register(D.ActionTypes.UPDATE_VIEWKEY, (viewKey) => {
this.setState({ response: this.state.response[viewKey] })
}),
]
}
componentWillUnmount() {
this.listeners.forEach(listener => D.AppDispatcher.unregister(listener))
}
private getRObjectList() {
const { response } = this.state
if (response && response.constructor === Array) {
return response.map((row, i) => {
return (<RObject key={`row-${i}`} className={css.obj} data={row} />)
})
}
return (
<RObject className={css.obj} data={response} />
)
}
render() {
const classNames = [
css.ResponseRepr,
this.props.className
].join(' ')
const repr = this.getRObjectList()
return (
<div className={classNames}>
{repr}
</div>
)
}
}
export default ResponseRepr

View File

@@ -2,7 +2,7 @@ import * as React from 'react'
import * as css from './App.css'
import Header from 'components/Header/Header'
import KeyList from 'components/KeyList/KeyList'
import DataTable from 'components/DataTable/DataTable'
import ResponseRepr from 'components/ResponseRepr/ResponseRepr'
import axios, { AxiosResponse } from 'axios'
import { Store } from 'common/Dispatcher'
@@ -42,7 +42,7 @@ class App extends React.Component<TProps> {
<div className={css.content}>
<KeyList className={[css.scrollable, css.keyList].join(' ')}
{...this.props} />
<DataTable className={[css.scrollable, css.table].join(' ')}
<ResponseRepr className={[css.scrollable, css.table].join(' ')}
{...this.props} />
</div>
</div>

View File

@@ -13,7 +13,7 @@
"eofline": false,
"forin": true,
"indent": [ true, "spaces" ],
"interface-name": [true, "never-prefix"],
"interface-name": [false], // true, "never-prefix"
"jsdoc-format": true,
"jsx-no-lambda": false,
"jsx-no-multiline-js": false,