-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(layout): add dataset view with draggable sidebar, datasets picke…
…r, etc
- Loading branch information
1 parent
1d4ccd6
commit 4707c46
Showing
29 changed files
with
1,666 additions
and
336 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"extends": [ | ||
"standard-with-typescript", | ||
"plugin:react/recommended" | ||
], | ||
"parser": "@typescript-eslint/parser", | ||
"parserOptions": { | ||
"sourceType": "module", | ||
"ecmaFeatures": { | ||
"jsx": true | ||
}, | ||
"project": "./tsconfig.json" | ||
}, | ||
"rules": { | ||
"@typescript-eslint/explicit-function-return-type": "off", | ||
"@typescript-eslint/explicit-member-accessibility": "off", | ||
"react/prop-types": "off" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015-present C. T. Lin | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
import { actionCreatorVoid } from './helpers' | ||
|
||
export const increment = actionCreatorVoid('INCREMENT_COUNTER') | ||
export const decrement = actionCreatorVoid('DECREMENT_COUNTER') | ||
|
||
export function incrementIfOdd () { | ||
return (dispatch: Function, getState: Function) => { | ||
const { counter } = getState() | ||
|
||
if (counter % 2 === 0) { | ||
return | ||
} | ||
|
||
dispatch(increment()) | ||
} | ||
} | ||
|
||
export function incrementAsync (delay: number = 1000) { | ||
return (dispatch: Function) => { | ||
setTimeout(() => { | ||
dispatch(increment()) | ||
}, delay) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Action } from 'redux' | ||
|
||
export interface IAction extends Action {} // eslint-disable-line | ||
export interface IActionWithPayload<T> extends Action { | ||
readonly payload: T | ||
} | ||
|
||
interface IActionCreator<T> { | ||
readonly type: string | ||
(payload: T): IActionWithPayload<T> | ||
|
||
test(action: IAction): action is IActionWithPayload<T> | ||
} | ||
|
||
interface IActionCreatorVoid { | ||
readonly type: string | ||
(): IAction | ||
|
||
test(action: IAction): action is IAction | ||
} | ||
|
||
export const actionCreator = <T>(type: string): IActionCreator<T> => | ||
Object.assign((payload: T): any => ({ type, payload }), { // eslint-disable-line | ||
type, | ||
test (action: IAction): action is IActionWithPayload<T> { | ||
return action.type === type | ||
} | ||
}) | ||
|
||
export const actionCreatorVoid = (type: string): IActionCreatorVoid => | ||
Object.assign((): any => ({ type }), { // eslint-disable-line | ||
type, | ||
test (action: IAction): action is IAction { | ||
return action.type === type | ||
} | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
@import "scss/style" | ||
@import "scss/style" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,14 @@ | ||
import * as React from 'react' | ||
import DatasetContainer from '../containers/DatasetContainer' | ||
|
||
// App is the main component and currently the only view | ||
// Everything must flow through here | ||
export default class App extends React.Component { | ||
render() { | ||
return ( | ||
<div>Hello World</div> | ||
) | ||
} | ||
} | ||
render () { | ||
return ( | ||
<div id='app'> | ||
<DatasetContainer /> | ||
</div> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import * as React from 'react' | ||
|
||
interface FileRowProps { | ||
name: string | ||
} | ||
|
||
const FileRow: React.SFC<FileRowProps> = (props) => { | ||
return ( | ||
<div className='file-row sidebar-row'> | ||
<div className='label'>{props.name}</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default class DatasetSidebar extends React.Component<{}, { activeTab: string }> { | ||
constructor (p: {}) { | ||
super(p) | ||
this.state = { | ||
activeTab: 'status' | ||
} | ||
} | ||
|
||
handleTabClick (activeTab: string) { | ||
this.setState({ activeTab }) | ||
} | ||
|
||
render () { | ||
const { activeTab } = this.state | ||
return ( | ||
<div id='dataset-sidebar'> | ||
<div id='tabs' className='sidebar-row'> | ||
<div className={'tab ' + (activeTab === 'status' ? 'active' : '')} onClick={() => this.handleTabClick('status')}>Status</div> | ||
<div className={'tab ' + (activeTab === 'status' ? '' : 'active')} onClick={() => this.handleTabClick('history')}>History</div> | ||
</div> | ||
<div id='content'> | ||
<div id='status-content' className='sidebar-content' hidden = {activeTab !== 'status'}> | ||
<div className='sidebar-row'> | ||
<div className='changes'> | ||
Changes | ||
</div> | ||
</div> | ||
<FileRow name='Meta' /> | ||
<FileRow name='Body' /> | ||
<FileRow name='Schema' /> | ||
</div> | ||
<div id='history-content' className='sidebar-content' hidden = {activeTab === 'status'}> | ||
<FileRow name='Last Commit' /> | ||
<FileRow name='Some other Commit' /> | ||
<FileRow name='First Commit' /> | ||
</div> | ||
</div> | ||
</div> | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import * as React from 'react' | ||
|
||
/** | ||
* Component abstracting a resizable panel. | ||
* Borrowed from https://github.com/desktop/desktop/blob/development/app/src/ui/resizable/resizable.tsx | ||
* | ||
* Note: this component is pure, consumers must subscribe to the | ||
* onResize and onReset event and update the width prop accordingly. | ||
*/ | ||
export class Resizable extends React.Component<IResizableProps, {}> { | ||
public static defaultProps: IResizableProps = { | ||
width: 250, | ||
maximumWidth: 350, | ||
minimumWidth: 200 | ||
} | ||
|
||
private startWidth: number | null = null | ||
private startX: number | null = null | ||
|
||
/** | ||
* Returns the current width as determined by props. | ||
* | ||
* This value will be constrained by the maximum and minimum | ||
* with props and might not be identical to that of props.width. | ||
*/ | ||
private getCurrentWidth () { | ||
return this.clampWidth(this.props.width) | ||
} | ||
|
||
/** | ||
* Constrains the provided width to lie within the minimum and | ||
* maximum widths as determined by props | ||
*/ | ||
private clampWidth (width: number) { | ||
return Math.max( | ||
this.props.minimumWidth!, // eslint-disable-line | ||
Math.min(this.props.maximumWidth!, width) // eslint-disable-line | ||
) | ||
} | ||
|
||
/** | ||
* Handler for when the user presses the mouse button over the resize | ||
* handle. | ||
*/ | ||
private handleDragStart = (e: React.MouseEvent<any>) => { | ||
this.startX = e.clientX | ||
this.startWidth = this.getCurrentWidth() || null | ||
|
||
document.addEventListener('mousemove', this.handleDragMove) | ||
document.addEventListener('mouseup', this.handleDragStop) | ||
|
||
e.preventDefault() | ||
} | ||
|
||
/** | ||
* Handler for when the user moves the mouse while dragging | ||
*/ | ||
private handleDragMove = (e: MouseEvent) => { | ||
if (this.startWidth == null || this.startX == null) { | ||
return | ||
} | ||
|
||
const deltaX = e.clientX - this.startX | ||
const newWidth = this.startWidth + deltaX | ||
const newWidthClamped = this.clampWidth(newWidth) | ||
|
||
if (this.props.onResize) { | ||
this.props.onResize(newWidthClamped) | ||
} | ||
|
||
e.preventDefault() | ||
} | ||
|
||
/** | ||
* Handler for when the user lets go of the mouse button during | ||
* a resize operation. | ||
*/ | ||
private handleDragStop = (e: MouseEvent) => { | ||
document.removeEventListener('mousemove', this.handleDragMove) | ||
document.removeEventListener('mouseup', this.handleDragStop) | ||
|
||
e.preventDefault() | ||
} | ||
|
||
/** | ||
* Handler for when the resize handle is double clicked. | ||
* | ||
* Resets the panel width to its default value and clears | ||
* any persisted value. | ||
*/ | ||
private handleDoubleClick = () => { | ||
if (this.props.onReset) { | ||
this.props.onReset() | ||
} | ||
} | ||
|
||
public render () { | ||
const style: React.CSSProperties = { | ||
width: this.getCurrentWidth(), | ||
maxWidth: this.props.maximumWidth, | ||
minWidth: this.props.minimumWidth | ||
} | ||
|
||
return ( | ||
<div id={this.props.id} className="resizable-component" style={style}> | ||
{this.props.children} | ||
<div | ||
onMouseDown={this.handleDragStart} | ||
onDoubleClick={this.handleDoubleClick} | ||
className="resize-handle" | ||
/> | ||
</div> | ||
) | ||
} | ||
} | ||
|
||
export interface IResizableProps { | ||
readonly width: number | ||
|
||
/** The maximum width the panel can be resized to. | ||
* | ||
* @default 350 | ||
*/ | ||
readonly maximumWidth?: number | ||
|
||
/** | ||
* The minimum width the panel can be resized to. | ||
* | ||
* @default 150 | ||
*/ | ||
readonly minimumWidth?: number | ||
|
||
/** The optional ID for the root element. */ | ||
readonly id?: string | ||
|
||
/** | ||
* Handler called when the width of the component has changed | ||
* through an explicit resize event (dragging the handle). | ||
*/ | ||
readonly onResize?: (newWidth: number) => void | ||
|
||
/** | ||
* Handler called when the resizable component has been | ||
* reset (ie restored to its original width by double clicking | ||
* on the resize handle). | ||
*/ | ||
readonly onReset?: () => void | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,9 @@ | ||
import * as React from 'react' | ||
|
||
export default class AppComponent extends React.Component { | ||
render() { | ||
render () { | ||
return ( | ||
<div>{this.props.children}</div> | ||
<div id="app-container">{this.props.children}</div> | ||
) | ||
} | ||
} | ||
} |
Oops, something went wrong.