Skip to content
Snippets Groups Projects
Commit 21d9f4b6 authored by Kyle Doherty's avatar Kyle Doherty
Browse files

initial wip on data reference

parent 9aea7615
No related branches found
No related tags found
No related merge requests found
Showing
with 11307 additions and 3372 deletions
......@@ -11,6 +11,11 @@ import EntityBrowser from "metabase/questions/containers/EntityBrowser.jsx";
import EntityList from "metabase/questions/containers/EntityList.jsx";
import EditLabels from "metabase/questions/containers/EditLabels.jsx";
import ReferenceApp from "metabase/reference/ReferenceApp.jsx";
import ReferenceEntityList from "metabase/reference/containers/ReferenceEntityList.jsx";
import ReferenceEntity from "metabase/reference/containers/ReferenceEntity.jsx";
import ReferenceEntityEditor from "metabase/reference/containers/ReferenceEntityEditor.jsx";
export default class Routes extends Component {
render() {
return (
......@@ -26,6 +31,13 @@ export default class Routes extends Component {
<Route path=":entity/:id/revisions" component={RevisionHistoryApp} />
</Route>
</Route>
<Route path="/reference" component={ReferenceApp}>
<Route path=":entity" component={ReferenceEntityList} />
<Route path=":entity/:id" component={ReferenceEntity} />
<Route path=":entity/:id/edit" component={ReferenceEntityEditor} />
</Route>
<Route path="/questions" component={EntityBrowser}>
<Route path="edit/labels" component={EditLabels} />
<Route path=":section" component={EntityList} />
......
......@@ -120,6 +120,12 @@ Metabase.config(['$routeProvider', '$locationProvider', function($routeProvider,
}]
}
};
$routeProvider.when('/reference', route);
$routeProvider.when('/reference/metrics', route);
$routeProvider.when('/reference/metrics/:id', route);
$routeProvider.when('/reference/lists', route);
$routeProvider.when('/reference/lists/:id', route);
$routeProvider.when('/reference/:entity/:id/edit', route);
$routeProvider.when('/questions', route);
$routeProvider.when('/questions/edit/:section', route);
......@@ -134,6 +140,7 @@ Metabase.config(['$routeProvider', '$locationProvider', function($routeProvider,
$routeProvider.when('/admin/datamodel/:objectType/:objectId/revisions', route);
$routeProvider.when('/unauthorized/', {
templateUrl: '/app/unauthorized.html',
controller: 'Unauthorized'
......
......@@ -118,6 +118,9 @@ export default class Navbar extends Component {
<li className="pl1">
<a data-metabase-event={"Navbar;Pulses"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background", {"NavItem--selected": this.isActive("/pulse") })} href="/pulse/">Pulses</a>
</li>
<li className="pl1">
<a data-metabase-event={"Navbar;DataReference"} style={this.styles.navButton} className={cx("NavItem cursor-pointer text-white text-bold no-decoration flex align-center px2 transition-background", {"NavItem--selected": this.isActive("/reference") })} href="/reference/">Data Reference</a>
</li>
<li className="pl3">
<a data-metabase-event={"Navbar;New Question"} style={this.styles.newQuestion} className="NavNewQuestion rounded inline-block bg-white text-brand text-bold cursor-pointer px2 no-decoration transition-all" href="/q">New <span className="hide sm-show">Question</span></a>
</li>
......
/* eslint "react/prop-types": "warn" */
import React, { Component, PropTypes } from "react";
import cx from "classnames"
const SidebarLayout = ({ className, style, sidebar, children }) =>
<div className={className} style={{ ...style, display: "flex", flexDirection: "row"}}>
<div className={cx('spread', className)} style={{ ...style, display: "flex", flexDirection: "row"}}>
{ React.cloneElement(
sidebar,
{ style: { flexShrink: 0 },
......
......@@ -158,3 +158,10 @@
.text-white-hover:hover { color: #fff; }
.bg-white, :local(.bg-white) { background-color: #fff; }
.bg-light-blue { background-color: #F5FAFC; }
.text-light-blue,
.text-light-blue-hover:hover {
color: #CFE4F5
}
......@@ -199,3 +199,5 @@
line-height: 1;
text-transform: uppercase;
}
.circle { border-radius: 99px; }
......@@ -4,9 +4,7 @@ import ReactDOM from "react-dom";
import { connect } from "react-redux";
import Sidebar from "../components/Sidebar.jsx";
import SidebarLayout from "../components/SidebarLayout.jsx";
import cx from "classnames";
import SidebarLayout from "metabase/components/SidebarLayout.jsx";
import * as questionsActions from "../questions";
import * as labelsActions from "../labels";
......@@ -54,7 +52,6 @@ export default class EntityBrowser extends Component {
render() {
return (
<SidebarLayout
className={cx("spread")}
sidebar={<Sidebar {...this.props} children={undefined}/>}
>
{this.props.children}
......
import React, { Component } from "react";
import { Link } from "react-router"
import { Flex } from "react-manhattan";
import SidebarLayout from "metabase/components/SidebarLayout.jsx";
import Icon from "metabase/components/Icon.jsx";
import { Block } from "react-manhattan";
import { singularize } from "metabase/lib/formatting";
import { SIDEBAR_ITEMS } from "./fixture_data.delete.js";
export const Text = ({children}) =>
<Measure><p>{children}</p></Measure>
export const Measure = ({children}) =>
<Block maxWidth="32rem">{children}</Block>
const Bold = ({children}) => <b>{children}</b>
export const ReferenceEntitySideBarItem = ({href, icon, name}) =>
<li>
<Link to={href} className="block text-brand link px4 py2 bg-brand-hover text-white-hover">
<ItemWithIcon icon={icon}>
<Bold>{name}</Bold>
</ItemWithIcon>
</Link>
</li>
export const ReferenceEntitySidebar = ({items}) =>
<ul className="bg-light-blue border-right pt4">
{ items.map((item, index) =>
<ReferenceEntitySideBarItem {...item} key={index} />)
}
</ul>
export const ItemWithIcon = ({children, icon}) =>
<Flex alignItems="center">
<Icon name={icon.name} className="text-light-blue mr1"/>
{children}
</Flex>
class ReferenceApp extends Component {
renderSidebar () {
const { entity, id } = this.props.params
if (id) {
return (
<ul>
<li>
<ReferenceEntitySideBarItem
name='Details'
icon={{
name: 'chevrondown'
}}
href={`/reference/${entity}/${id}/details`}
/>
</li>
{ singularize(entity) === 'list' ?
<li>
<ReferenceEntitySideBarItem
name={`Fields in this ${singularize(entity)}`}
icon={{
name: 'chevrondown'
}}
href={`/reference/${entity}/${id}/fields`}
/>
</li>
: null}
<li>
<ReferenceEntitySideBarItem
name={`Questions based on this ${singularize(entity)}`}
icon={{
name: 'chevrondown'
}}
href={`/reference/${entity}/${id}/questions`}
/>
</li>
<li>
<ReferenceEntitySideBarItem
name='Revision history'
icon={{
name: 'history'
}}
href={`/reference/${entity}/${id}/revisions`}
/>
</li>
</ul>
)
} else {
return <ReferenceEntitySidebar items={SIDEBAR_ITEMS}/>
}
}
render () {
const { children } = this.props
return (
<SidebarLayout sidebar={this.renderSidebar()}>
<div className="wrapper">{children}</div>
</SidebarLayout>
)
}
}
export default ReferenceApp
import React, { Component } from "react";
import { Link } from "react-router";
import { Flex, Block } from "react-manhattan";
import { singularize } from "metabase/lib/formatting";
import Icon from "metabase/components/Icon.jsx";
import IconBorder from "metabase/components/IconBorder.jsx";
import { ItemWithIcon, Text, Measure } from "../ReferenceApp.jsx";
import { INSIGHTS } from "../fixture_data.delete.js";
const AdditionalInfoItem = ({children, icon, href}) =>
<Link to={href} className="block link mb1 border-bottom py2">
<ItemWithIcon
icon={{
name: icon.name
}}
>
{children}
<IconBorder className="ml-auto">
<Icon name="chevronright"/>
</IconBorder>
</ItemWithIcon>
</Link>
const AdditionalMetricInfo = () =>
<Block>
<Block className="mb2">
<h3>Most useful fields to group this metric by</h3>
<MetricFields fields={INSIGHTS} />
</Block>
<Block>
<h3>Other fields you can group this metric by</h3>
<MetricFields fields={INSIGHTS} />
</Block>
</Block>
const MetricField = ({name, icon, href}) =>
<Measure>
<AdditionalInfoItem icon={icon} href={'/'}>{name}</AdditionalInfoItem>
</Measure>
const MetricFields = ({fields}) =>
<Block>
{ fields.map((f, i) => <MetricField {...f} key={i} />) }
</Block>
const ReferenceEntityDetail = ({title, detail}) =>
<Block>
<h3>{title}</h3>
<Measure>
<p>{detail}</p>
</Measure>
</Block>
const MetricCalculation = () =>
<ReferenceEntityDetail
title="How is this metric calculated?"
detail="Second base bat curve relay world series, rhubarb cubs plunked second baseman. Robbed starter skipper center fielder pennant stance relay. Forkball rookie curve pitchout mound passed ball cardinals."
/>
const ReferenceEntityDescription = () =>
<ReferenceEntityDetail
title="Description"
detail="Second base bat curve relay world series, rhubarb cubs plunked second baseman. Robbed starter skipper center fielder pennant stance relay. Forkball rookie curve pitchout mound passed ball cardinals."
/>
const ReferenceEntityImportance = ({entity}) =>
<ReferenceEntityDetail
title={`Why is this ${entity} important?`}
detail="Second base bat curve relay world series, rhubarb cubs plunked second baseman. Robbed starter skipper center fielder pennant stance relay. Forkball rookie curve pitchout mound passed ball cardinals."
/>
const ReferenceEntityTitle = ({title}) => <h1>{title}</h1>
const ReferenceEntityHeader = ({children}) =>
<Flex className="border-bottom py2 mb4" alignItems="center">{children}</Flex>
const ReferenceEntityActions = ({children}) =>
<Block className="ml-auto">
{children}
</Block>
const EditEntityAction = ({href}) =>
<Flex alignItems="center">
<Link to={href}>
<Icon name="pencil" />
Edit
</Link>
</Flex>
const ReferenceEntityDetails = ({entity}) =>
<div>
<ReferenceEntityDescription />
<ReferenceEntityImportance entity={entity} />
{ entity === 'metric' ? <MetricCalculation /> : null }
</div>
class ReferenceEntity extends Component {
componentWillMount() {
}
renderEntityIcon () {
// should be able to juse use the singularized entity name here
switch(singularize(this.props.params.entity)) {
case 'metric':
return <Icon name="check" />
case 'list':
return <Icon name="close" />
case 'database':
return <Icon name="database" />
default:
return <Icon name="chevronDown" />
}
}
renderAdditionalInfo () {
switch(singularize(this.props.params.entity)) {
case 'metric':
return <AdditionalMetricInfo />
case 'list':
return <Icon name="close" />
case 'database':
return <Icon name="clock" />
default:
return <Icon name="chevronDown" />
}
}
render () {
const { entity, id } = this.props.params
return (
<Flex>
<Block width="40" height="40" className="mt4 mr4">
<div className="flex align-center justify-center bg-light-blue circle text-brand p4">
{ this.renderEntityIcon() }
</div>
</Block>
<div className="flex-full">
<ReferenceEntityHeader>
<ReferenceEntityTitle title="Lifetime value" />
<ReferenceEntityActions>
<EditEntityAction href={`/reference/${entity}/${id}/edit`} />
</ReferenceEntityActions>
</ReferenceEntityHeader>
<ReferenceEntityDetails entity={singularize(entity)} />
<Block className="mt4">
{ this.renderAdditionalInfo() }
</Block>
</div>
</Flex>
)
}
}
export default ReferenceEntity
import React from "react";
const ReferenceEntityEditor = ({params}) =>
<div>EDIT ME</div>
import React from "react";
import { Link } from "react-router"
import { Text } from "../ReferenceApp.jsx"
import { INSIGHTS } from "../fixture_data.delete.js";
const EntityTitle=({children}) => <h2>{children}</h2>
const ReferenceEntityListItem = ({name, href, description}) =>
<Link to={href} className="py2 block border-bottom link">
<EntityTitle>{name}</EntityTitle>
<Text className="text-normal text-grey-1">{description}</Text>
</Link>
const ReferenceEntityList = ({entities, params}) => {
const href = `${params.entity}/1`
return (
<ul className="wrapper">
{
entities.map((insight, index) =>
<li key={index}>
<ReferenceEntityListItem {...insight} href={href} />
</li>
)
}
</ul>
)
}
ReferenceEntityList.defaultProps = {
entities: INSIGHTS
}
export default ReferenceEntityList
import insight from "insightful"
export const SIDEBAR_ITEMS = [
{
name: 'Understanding our data',
href: '/reference',
icon: {
name: 'reference'
}
},
{
name: 'Metrics',
href: '/reference/metrics',
icon: {
name: 'chevrondown'
}
},
{
name: 'Lists',
href: '/reference/lists',
icon: {
name: 'chevrondown'
}
},
{
name: 'Databases and tables',
href: '/reference/data',
icon: {
name: 'database'
}
},
]
export let INSIGHTS = []
const rando = () => Math.floor(Math.random() * 20 + 10)
for(let i = 0; i < rando(); i ++) {
INSIGHTS.push({
name: insight(),
description: 'Derp lerp merp werp',
icon: {
name: 'reference'
}
})
}
This diff is collapsed.
......@@ -8,7 +8,7 @@ var CommonsChunkPlugin = webpack.optimize.CommonsChunkPlugin;
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var UnusedFilesWebpackPlugin = require("unused-files-webpack-plugin").default;
var FlowStatusWebpackPlugin = require('flow-status-webpack-plugin');
// var FlowStatusWebpackPlugin = require('flow-status-webpack-plugin');
var _ = require('underscore');
var glob = require('glob');
......@@ -236,7 +236,7 @@ if (NODE_ENV === "development" || NODE_ENV === "hot") {
}
}
config.plugins.push(new FlowStatusWebpackPlugin())
// config.plugins.push(new FlowStatusWebpackPlugin())
}
if (NODE_ENV === "hot" || isWatching) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment