diff options
| -rw-r--r-- | cli/app/controllers/graph_controller.py | 6 | ||||
| -rw-r--r-- | cli/app/controllers/page_controller.py | 30 | ||||
| -rw-r--r-- | frontend/types.js | 6 | ||||
| -rw-r--r-- | frontend/util/index.js | 1 | ||||
| -rw-r--r-- | frontend/views/graph/components/graph.editor.js | 35 | ||||
| -rw-r--r-- | frontend/views/graph/components/page.edit.js | 2 | ||||
| -rw-r--r-- | frontend/views/graph/graph.css | 7 | ||||
| -rw-r--r-- | frontend/views/graph/graph.reducer.js | 6 | ||||
| -rw-r--r-- | frontend/views/page/components/page.header.js | 3 | ||||
| -rw-r--r-- | frontend/views/page/components/tile.edit.js | 1 | ||||
| -rw-r--r-- | frontend/views/page/components/tile.form.js | 4 | ||||
| -rw-r--r-- | frontend/views/page/components/tile.new.js | 1 | ||||
| -rw-r--r-- | frontend/views/page/page.actions.js | 32 | ||||
| -rw-r--r-- | frontend/views/page/page.container.js | 13 | ||||
| -rw-r--r-- | frontend/views/page/page.reducer.js | 6 |
15 files changed, 121 insertions, 32 deletions
diff --git a/cli/app/controllers/graph_controller.py b/cli/app/controllers/graph_controller.py index 3fa4cce..7efda73 100644 --- a/cli/app/controllers/graph_controller.py +++ b/cli/app/controllers/graph_controller.py @@ -17,13 +17,13 @@ class GraphView(CrudView): session.query(Tile).filter(Tile.page_id == item.id).delete(synchronize_session=False) session.query(Page).filter(Page.graph_id == item.id).delete(synchronize_session=False) - @route('/name/<path>', methods=['GET']) - def get_name(self, path: str): + @route('/name/<graph_path>', methods=['GET']) + def get_name(self, graph_path: str): """ Fetch a single {model}. """ session = Session() - item = session.query(self.model).filter(self.model.path == path).first() + item = session.query(self.model).filter(self.model.path == graph_path).first() if not item: session.close() return jsonify({ diff --git a/cli/app/controllers/page_controller.py b/cli/app/controllers/page_controller.py index 41d30f3..b6bfaa8 100644 --- a/cli/app/controllers/page_controller.py +++ b/cli/app/controllers/page_controller.py @@ -3,6 +3,7 @@ from flask_classful import route from werkzeug.datastructures import MultiDict from app.sql.common import db, Session +from app.sql.models.graph import Graph from app.sql.models.page import Page, PageForm from app.sql.models.tile import Tile from app.controllers.crud_controller import CrudView @@ -26,3 +27,32 @@ class PageView(CrudView): def on_destroy(self, session, item): session.query(Tile).filter(Tile.page_id == item.id).delete(synchronize_session=False) + + @route('/name/<graph_path>/<page_path>', methods=['GET']) + def get_name(self, graph_path: str, page_path: str): + """ + Fetch a single {model}. + """ + session = Session() + graph = session.query(Graph).filter(Graph.path == graph_path).first() + if not graph: + session.close() + return jsonify({ + 'status': 'error', + 'error': 'graph not found' + }) + + page = session.query(Page).filter(Page.graph_id == graph.id, Page.path == page_path).first() + if not page: + session.close() + return jsonify({ + 'status': 'error', + 'error': 'page not found' + }) + + result = { + 'status': 'ok', + 'res': page.toFullJSON() if hasattr(page, 'toFullJSON') else page.toJSON(), + } + session.close() + return jsonify(result) diff --git a/frontend/types.js b/frontend/types.js index 1c0de90..4a1b39d 100644 --- a/frontend/types.js +++ b/frontend/types.js @@ -6,7 +6,11 @@ export const graph = crud_type('graph', [ 'show_edit_page_form', 'hide_edit_page_form', 'update_graph_page', ]) -export const page = crud_type('page', []) +export const page = crud_type('page', [ + 'show_add_tile_form', 'hide_add_tile_form', + 'show_edit_tile_form', 'hide_edit_tile_form', + 'update_page_tile', +]) export const tile = crud_type('tile', []) export const upload = crud_type('upload', []) diff --git a/frontend/util/index.js b/frontend/util/index.js index b1b103c..02a7a4d 100644 --- a/frontend/util/index.js +++ b/frontend/util/index.js @@ -67,6 +67,7 @@ export const percent = n => (n * 100).toFixed(1) + '%' export const px = (n, w) => Math.round(n * w) + 'px' export const clamp = (n, a=0, b=1) => n < a ? a : n < b ? n : b +export const dist = (x1, y1, x2, y2) => Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)) /* URLs */ diff --git a/frontend/views/graph/components/graph.editor.js b/frontend/views/graph/components/graph.editor.js index 1b2d446..5093327 100644 --- a/frontend/views/graph/components/graph.editor.js +++ b/frontend/views/graph/components/graph.editor.js @@ -1,14 +1,15 @@ import React, { Component } from 'react' -import { Route } from 'react-router-dom' +import { Route, Link } from 'react-router-dom' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' +import { history } from '../../../store' import { session } from '../../../session' import actions from '../../../actions' import * as graphActions from '../graph.actions' import { Loader } from '../../../common' -import { clamp } from '../../../util' +import { clamp, dist } from '../../../util' const defaultState = { dragging: false, @@ -80,7 +81,7 @@ class GraphEditor extends Component { y = clamp(y, 0, 1) this.setState({ page, - draggingBox: true, + dragging: true, bounds, mouseX, mouseY, @@ -97,10 +98,10 @@ class GraphEditor extends Component { handleMouseMove(e) { const { - dragging, draggingBox, + dragging, bounds, mouseX, mouseY, initialBox, box } = this.state - if (draggingBox) { + if (dragging) { e.preventDefault() let { x, y, w, h } = initialBox let dx = (e.pageX - mouseX) / bounds.width @@ -117,9 +118,10 @@ class GraphEditor extends Component { handleMouseUp(e) { // const { actions } = this.props - const { dragging, draggingBox, bounds, box, page } = this.state - if (!dragging && !draggingBox) return + const { dragging, bounds, initialBox, box, page } = this.state + if (!dragging) return e.preventDefault() + const { width, height } = bounds const { x, y, w, h } = box let url = window.location.pathname this.setState({ @@ -127,9 +129,8 @@ class GraphEditor extends Component { box: null, initialBox: null, dragging: false, - draggingBox: false, }) - // console.log(page) + if (dist(width * x, height * y, width * initialBox.x, height * initialBox.y) < 3) return const updatedPage = { ...page, settings: { @@ -145,13 +146,14 @@ class GraphEditor extends Component { // console.log(this.props.graph.show.res) const currentPage = this.state.page const currentBox = this.state.box - const { res } = this.props.graph.show + const { res: graph } = this.props.graph.show // console.log(res.pages) return ( <div className='graph' ref={this.graphRef}> - {this.state.bounds && res.pages.map(page => ( + {this.state.bounds && graph.pages.map(page => ( <PageHandle key={page.id} + graph={graph} page={page} bounds={this.state.bounds} box={currentPage && page.id === currentPage.id && currentBox} @@ -163,7 +165,7 @@ class GraphEditor extends Component { } } -const PageHandle = ({ page, bounds, box, onMouseDown }) => { +const PageHandle = ({ graph, page, bounds, box, onMouseDown }) => { let style; if (box) { style = { @@ -176,10 +178,17 @@ const PageHandle = ({ page, bounds, box, onMouseDown }) => { left: (bounds.width) * Math.min(page.settings.x, 0.95), } } + const url = '/' + graph.path + '/' + page.path // console.log(style) return ( - <div className='handle' onMouseDown={onMouseDown} style={style}> + <div + className='handle' + onMouseDown={onMouseDown} + onDoubleClick={() => history.push(url)} + style={style} + > {page.title} + <Link to={url}>{'>'}</Link> </div> ) } diff --git a/frontend/views/graph/components/page.edit.js b/frontend/views/graph/components/page.edit.js index f4f351b..1e59647 100644 --- a/frontend/views/graph/components/page.edit.js +++ b/frontend/views/graph/components/page.edit.js @@ -20,7 +20,7 @@ class PageEdit extends Component { .then(response => { // response console.log(response) - history.push('/' + data.path) + // history.push('/' + data.path) }) } diff --git a/frontend/views/graph/graph.css b/frontend/views/graph/graph.css index a2ab8a4..73ac103 100644 --- a/frontend/views/graph/graph.css +++ b/frontend/views/graph/graph.css @@ -66,4 +66,9 @@ user-select: none; cursor: arrow; } - +.handle a { + margin-left: 0.25rem; + color: #fff; + font-weight: bold; + text-decoration: none; +} diff --git a/frontend/views/graph/graph.reducer.js b/frontend/views/graph/graph.reducer.js index 9e682e4..3dcea1d 100644 --- a/frontend/views/graph/graph.reducer.js +++ b/frontend/views/graph/graph.reducer.js @@ -42,6 +42,7 @@ export default function graphReducer(state = initialState, action) { editor: { ...state.editor, addingPage: true, + editingPage: false, } } @@ -59,7 +60,8 @@ export default function graphReducer(state = initialState, action) { ...state, editor: { ...state.editor, - addingPage: true, + addingPage: false, + editingPage: true, } } @@ -68,7 +70,7 @@ export default function graphReducer(state = initialState, action) { ...state, editor: { ...state.editor, - addingPage: false, + editingPage: false, } } diff --git a/frontend/views/page/components/page.header.js b/frontend/views/page/components/page.header.js index a6c47ee..3eff339 100644 --- a/frontend/views/page/components/page.header.js +++ b/frontend/views/page/components/page.header.js @@ -9,7 +9,7 @@ function PageHeader(props) { return ( <header> <div> - <Link to="/" className="logo"><b>{props.site.siteTitle}</b></Link> + <Link to={props.graph.show.res ? "/" + props.graph.show.res.path : "/"} className="logo"><b>{props.site.siteTitle}</b></Link> </div> <div> <button onClick={() => props.pageActions.showAddTileForm()}>+ Add tile</button> @@ -21,6 +21,7 @@ function PageHeader(props) { const mapStateToProps = (state) => ({ // auth: state.auth, site: state.site, + graph: state.graph, // isAuthenticated: state.auth.isAuthenticated, }) diff --git a/frontend/views/page/components/tile.edit.js b/frontend/views/page/components/tile.edit.js index 3420505..6d8d835 100644 --- a/frontend/views/page/components/tile.edit.js +++ b/frontend/views/page/components/tile.edit.js @@ -36,6 +36,7 @@ class TileEdit extends Component { <TileForm data={show.res} graph={this.props.graph.show.res} + page={this.props.page.show.res} onSubmit={this.handleSubmit.bind(this)} /> ) diff --git a/frontend/views/page/components/tile.form.js b/frontend/views/page/components/tile.form.js index 1e75cd8..6b9d0a7 100644 --- a/frontend/views/page/components/tile.form.js +++ b/frontend/views/page/components/tile.form.js @@ -25,7 +25,7 @@ export default class TileForm extends Component { } componentDidMount() { - const { graph, data, isNew } = this.props + const { graph, page, data, isNew } = this.props const title = isNew ? 'new tile' : 'editing ' + data.title const submitTitle = isNew ? "Create Tile" : "Save Changes" this.setState({ @@ -33,7 +33,7 @@ export default class TileForm extends Component { submitTitle, errorFields: new Set([]), data: { - ...newTile({ graph_id: graph.id }), + ...newTile({ graph_id: graph.id, page_id: page.id }), ...data, }, }) diff --git a/frontend/views/page/components/tile.new.js b/frontend/views/page/components/tile.new.js index 7445f27..cb5eaa8 100644 --- a/frontend/views/page/components/tile.new.js +++ b/frontend/views/page/components/tile.new.js @@ -28,6 +28,7 @@ class TileNew extends Component { <TileForm isNew graph={this.props.graph.show.res} + page={this.props.page.show.res} data={{}} onSubmit={this.handleSubmit.bind(this)} /> diff --git a/frontend/views/page/page.actions.js b/frontend/views/page/page.actions.js index cfd0f98..941bd9b 100644 --- a/frontend/views/page/page.actions.js +++ b/frontend/views/page/page.actions.js @@ -1,13 +1,39 @@ import * as types from '../../types' +import { store } from '../../store' +import actions from '../../actions' export const showAddTileForm = () => dispatch => { - dispatch({ type: types.graph.show_add_tile_form }) + dispatch({ type: types.page.show_add_tile_form }) } export const hideAddTileForm = () => dispatch => { - dispatch({ type: types.graph.hide_add_tile_form }) + dispatch({ type: types.page.hide_add_tile_form }) } export const updatePageTile = tile => dispatch => { - dispatch({ type: types.graph.update_graph_tile, tile }) + dispatch({ type: types.page.update_graph_tile, tile }) } + +export const showGraphAndPageIfUnloaded = ({ graph_name, page_name }) => dispatch => ( + new Promise((resolve, reject) => { + showGraphIfUnloaded({ graph_name })(dispatch) + .then(graph => ( + actions.page.show('name/' + graph_name + '/' + page_name) + .then(resolve) + .catch(reject) + )) + .catch(reject) + }) +) + +export const showGraphIfUnloaded = ({ graph_name }) => dispatch => ( + new Promise((resolve, reject) => { + const { res: graph } = store.getState().graph.show + if (graph && graph.path === graph_name) { + return resolve(graph) + } + actions.graph.show('name/' + graph_name) + .then(resolve) + .catch(reject) + }) +)
\ No newline at end of file diff --git a/frontend/views/page/page.container.js b/frontend/views/page/page.container.js index 2de56bb..bbb1f3a 100644 --- a/frontend/views/page/page.container.js +++ b/frontend/views/page/page.container.js @@ -8,8 +8,10 @@ import './page.css' import actions from '../../actions' import { Loader } from '../../common' -// import * as uploadActions from './upload.actions' +import * as graphActions from '../graph/graph.actions' +import * as pageActions from './page.actions' +import PageEdit from '../graph/components/page.edit' import TileNew from './components/tile.new' import TileEdit from './components/tile.edit' @@ -37,9 +39,12 @@ class PageContainer extends Component { } load() { actions.site.setSiteTitle("loading " + this.props.match.params.page_name + "...") - actions.page.show('name/' + this.props.match.params.graph_name + '/' + this.props.match.params.page_name) + this.props.pageActions.showGraphAndPageIfUnloaded(this.props.match.params) .then(data => { actions.site.setSiteTitle(data.res.title) + if (!data.res.tiles.length) { + this.props.pageActions.showAddTileForm() + } }) } render() { @@ -61,6 +66,7 @@ class PageContainer extends Component { <PageHeader /> <div className='body'> <PageEditor /> + {this.props.graph.editor.editingPage && <PageEdit />} {this.props.page.editor.addingTile && <TileNew />} {this.props.page.editor.editingTile && <TileEdit />} </div> @@ -75,7 +81,8 @@ const mapStateToProps = state => ({ }) const mapDispatchToProps = dispatch => ({ - // uploadActions: bindActionCreators({ ...uploadActions }, dispatch), + graphActions: bindActionCreators({ ...graphActions }, dispatch), + pageActions: bindActionCreators({ ...pageActions }, dispatch), }) export default connect(mapStateToProps, mapDispatchToProps)(PageContainer) diff --git a/frontend/views/page/page.reducer.js b/frontend/views/page/page.reducer.js index d1d6510..1494bc2 100644 --- a/frontend/views/page/page.reducer.js +++ b/frontend/views/page/page.reducer.js @@ -42,6 +42,7 @@ export default function pageReducer(state = initialState, action) { editor: { ...state.editor, addingTile: true, + editingTile: false, } } @@ -59,7 +60,8 @@ export default function pageReducer(state = initialState, action) { ...state, editor: { ...state.editor, - addingTile: true, + addingTile: false, + editingTile: true, } } @@ -68,7 +70,7 @@ export default function pageReducer(state = initialState, action) { ...state, editor: { ...state.editor, - addingTile: false, + editingTile: false, } } |
