Commit 83de8d32 authored by Andrii Vorobiov's avatar Andrii Vorobiov

ui: CSS modules for PlanView component

- refactor fonts imports to correctly resolve paths
when module is required from different locations;
- move all files related to PlanView component under
`planView` directory
- Added story for PlanView component

Release note: None
parent cf566561
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
export * from "./planView";
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
import {cockroach} from "src/js/protos";
import IExplainTreePlanNode = cockroach.sql.IExplainTreePlanNode;
export const logicalPlan: IExplainTreePlanNode = {
"name": "root",
"attrs": [],
"children": [
{
"name": "count",
"attrs": [],
"children": [
{
"name": "upsert",
"attrs": [
{
"key": "into",
"value": "vehicle_location_histories(city, ride_id, timestamp, lat, long)",
},
{
"key": "strategy",
"value": "opt upserter",
},
],
"children": [
{
"name": "buffer node",
"attrs": [
{
"key": "label",
"value": "buffer 1",
},
],
"children": [
{
"name": "row source to plan node",
"attrs": [],
"children": [
{
"name": "render",
"attrs": [
{
"key": "render",
"value": "column1",
},
{
"key": "render",
"value": "column2",
},
{
"key": "render",
"value": "column3",
},
{
"key": "render",
"value": "column4",
},
{
"key": "render",
"value": "column5",
},
{
"key": "render",
"value": "column4",
},
{
"key": "render",
"value": "column5",
},
],
"children": [
{
"name": "values",
"attrs": [
{
"key": "size",
"value": "5 columns, 1 row",
},
{
"key": "row 0, expr",
"value": "_",
},
{
"key": "row 0, expr",
"value": "_",
},
{
"key": "row 0, expr",
"value": "now()",
},
{
"key": "row 0, expr",
"value": "_",
},
{
"key": "row 0, expr",
"value": "_",
},
],
"children": [],
},
],
},
],
},
],
},
],
},
],
},
{
"name": "postquery",
"attrs": [],
"children": [
{
"name": "error if rows",
"attrs": [],
"children": [
{
"name": "row source to plan node",
"attrs": [],
"children": [
{
"name": "lookup-join",
"attrs": [
{
"key": "table",
"value": "[email protected]",
},
{
"key": "type",
"value": "anti",
},
{
"key": "equality",
"value": "(column1, column2) = (city, id)",
},
{
"key": "equality cols are key",
"value": "",
},
{
"key": "parallel",
"value": "",
},
],
"children": [
{
"name": "render",
"attrs": [
{
"key": "render",
"value": "column1",
},
{
"key": "render",
"value": "column2",
},
],
"children": [
{
"name": "scan buffer node",
"children": [],
"attrs": [
{
"key": "label",
"value": "buffer 1",
},
],
},
],
},
],
},
],
},
],
},
],
},
],
};
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
@require '~styl/base/palette.styl'
@require '~src/views/shared/util/table.styl'
@require '~src/components/core/index'
.base-heading
composes base-heading from '~styl/base/typography.styl'
.plan-view-table
@extend $table-base
.plan-view-table__cell
padding 0
.summary--card__title
font-family SourceSansPro-Regular
line-height 1.6
letter-spacing -0.2px
color $popover-color
font-size 16px
display inline-block
margin-bottom 10px
padding 0
text-transform none
&__row
&--body
border-top none
&:hover
background-color $adminui-white
&__tooltip
.hover-tooltip__text
width 520px
margin-left 15px
.plan-view-table
&__tooltip
width 36px // Reserve space for 10px padding around centered 16px icon
height 16px
display inline-block
// Overrides to let the tooltip sit inside a table header.
text-transform none
font-weight normal
white-space normal
letter-spacing normal
font-size 14px
&__tooltip-hover-area
width 100%
padding 0px 10px
&__info-icon
width 16px
height 16px
border-radius 50%
border 1px solid $tooltip-color
font-size 12px
line-height 14px // Visual tweak to vertically center the "i"
text-align center
color $tooltip-color
.hover-tooltip--hovered &__info-icon
border-color $body-color
color $body-color
.plan-view
color $body-color
position relative
.plan-view-container
height 100%
max-height 100%
overflow hidden
.plan-view-container-scroll
max-height 400px
overflow-y scroll
.plan-view-container-directions
text-align center
cursor pointer
text-transform uppercase
color $main-blue-color
font-size smaller
.node-icon
margin 0 10px 0 0
color $grey-light
.warning-icon
margin 0 4px 0 4px
position relative
top 3px
path
fill $colors--functional-orange-4
.warn
position relative
left -5px
color $colors--functional-orange-4
background-color $plan-node-warning-background-color
border-radius 2px
padding 2px
.nodeDetails
position relative
padding 6px 0
border 1px solid transparent
b
font-family SourceSansPro-SemiBold
font-size 12px
font-weight 600
line-height 1.67
letter-spacing 0.3px
color $text-color
.nodeAttributes
color $adminui-grey-2
padding 7px 16px 0px 18px
margin-left 3px
border-left 1px solid $grey-light
font-family RobotoMono-Medium
font-size 12px
font-weight 500
line-height 1.83
.nodeAttributeKey
color $colors--primary-green-3
ul
padding 0
margin 0
li
padding 0
margin 0
position relative
list-style-type none
// vertical line, to previous node (above)
&:not(:first-child):after
content ''
width 1px
height 19px
background-color $grey-light
position absolute
top -10px
left 4px
ul
padding-left 27px
position relative
&:last-child
&:before
content ''
width 28px
height 29px
position absolute
border-left 1px solid $grey-light
border-bottom 1px solid $grey-light
top -10px
left 4px
border-bottom-left-radius 10px
li
&:before
content none
&:first-child:after
content none
li
// first node: horizontal line, to parent
.nodeDetails
margin-left 12px
&:not(:first-child):after
left 16px
&:last-child
.nodeAttributes
border-color transparent
&:first-child
&:after
content ''
height 1px
width 27px
background-color $grey-light
position absolute
top 18px
left -22px
&:before
content ''
width 1px
height 100%
background-color $grey-light
position absolute
top -10px
left -23px
......@@ -11,7 +11,12 @@
import { assert } from "chai";
import { cockroach } from "src/js/protos";
import { FlatPlanNode, FlatPlanNodeAttribute, flattenTree, flattenAttributes } from "src/views/statements/planView";
import {
FlatPlanNode,
FlatPlanNodeAttribute,
flattenTree,
flattenAttributes,
} from "src/views/statements/planView";
import IAttr = cockroach.sql.ExplainTreePlanNode.IAttr;
import IExplainTreePlanNode = cockroach.sql.IExplainTreePlanNode;
......
// Copyright 2020 The Cockroach Authors.
//
// Use of this software is governed by the Business Source License
// included in the file licenses/BSL.txt.
//
// As of the Change Date specified in that file, in accordance with
// the Business Source License, use of this software will be governed
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
import React from "react";
import { storiesOf } from "@storybook/react";
import { PlanView } from "./planView";
import {logicalPlan} from "./planView.fixtures";
storiesOf("PlanView", module)
.add("default", () => (
<PlanView
title="Logical Plan"
plan={logicalPlan}
/>),
);
......@@ -12,17 +12,18 @@ import _ from "lodash";
import React, { Fragment } from "react";
import { cockroach } from "src/js/protos";
import { ToolTipWrapper } from "src/views/shared/components/toolTip";
import styles from "./planView.module.styl";
import IAttr = cockroach.sql.ExplainTreePlanNode.IAttr;
import IExplainTreePlanNode = cockroach.sql.IExplainTreePlanNode;
const WARNING_ICON = (
<svg className="warning-icon" width="17" height="17" viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg">
<svg className={styles["warning-icon"]} width="17" height="17" viewBox="0 0 24 22" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.7798 2.18656L23.4186 15.5005C25.0821 18.4005 22.9761 21.9972 19.6387 21.9972H4.3619C1.02395 21.9972 -1.08272 18.4009 0.582041 15.5005M0.582041 15.5005L8.21987 2.18656C9.89189 -0.728869 14.1077 -0.728837 15.7798 2.18656M13.4002 7.07075C13.4002 6.47901 12.863 5.99932 12.2002 5.99932C11.5375 5.99932 11.0002 6.47901 11.0002 7.07075V13.4993C11.0002 14.0911 11.5375 14.5707 12.2002 14.5707C12.863 14.5707 13.4002 14.0911 13.4002 13.4993V7.07075ZM13.5717 17.2774C13.5717 16.5709 12.996 15.9981 12.286 15.9981C11.5759 15.9981 11.0002 16.5709 11.0002 17.2774V17.2902C11.0002 17.9967 11.5759 18.5695 12.286 18.5695C12.996 18.5695 13.5717 17.9967 13.5717 17.2902V17.2774Z"/>
</svg>
);
const NODE_ICON = (
<span className="node-icon">&#x26AC;</span>
<span className={styles["node-icon"]}>&#x26AC;</span>
);
// FlatPlanNodeAttribute contains a flattened representation of IAttr[].
......@@ -203,9 +204,9 @@ class PlanNodeDetails extends React.Component<PlanNodeDetailProps> {
keyClassName = "";
}
return (
<div key={attr.key} className={attrClassName}>
<div key={attr.key} className={styles[attrClassName]}>
{attr.warn && WARNING_ICON}
<span className={keyClassName}>{attr.key}</span>
<span className={styles[keyClassName]}>{attr.key}</span>
{this.renderAttributeValues(attr.values)}
</div>
);
......@@ -215,7 +216,7 @@ class PlanNodeDetails extends React.Component<PlanNodeDetailProps> {
const node = this.props.node;
if (node.attrs && node.attrs.length > 0) {
return (
<div className="nodeAttributes">
<div className={styles[`nodeAttributes`]}>
{node.attrs.map( (attr) => this.renderAttribute(attr))}
</div>
);
......@@ -225,7 +226,7 @@ class PlanNodeDetails extends React.Component<PlanNodeDetailProps> {
render() {
const node = this.props.node;
return (
<div className="nodeDetails">
<div className={styles[`nodeDetails`]}>
{NODE_ICON} <b>{_.capitalize(node.name)}</b>
{this.renderNodeDetails()}
</div>
......@@ -326,16 +327,16 @@ export class PlanView extends React.Component<PlanViewProps, PlanViewState> {
);
return (
<table className="plan-view-table">
<table className={styles["plan-view-table"]}>
<thead>
<tr className="plan-view-table__row--header">
<th className="plan-view-table__cell">
<h2 className="base-heading summary--card__title">{this.props.title}</h2>
<div className="plan-view-table__tooltip">
<tr className={styles["plan-view-table__row--header"]}>
<th className={styles["plan-view-table__cell"]}>
<h2 className={`${styles["base-heading"]} ${styles["summary--card__title"]}`}>{this.props.title}</h2>
<div className={styles["plan-view-table__tooltip"]}>
<ToolTipWrapper
text={lastSampledHelpText}>
<div className="plan-view-table__tooltip-hover-area">
<div className="plan-view-table__info-icon">i</div>
<div className={styles["plan-view-table__tooltip-hover-area"]}>
<div className={styles["plan-view-table__info-icon"]}>i</div>
</div>
</ToolTipWrapper>
</div>
......@@ -343,9 +344,9 @@ export class PlanView extends React.Component<PlanViewProps, PlanViewState> {
</tr>
</thead>
<tbody>
<tr className="plan-view-table__row--body">
<td className="plan-view plan-view-table__cell" style={{ textAlign: "left" }}>
<div className="plan-view-container">
<tr className={styles["plan-view-table__row--body"]}>
<td className={`${styles["plan-view"]} ${styles["plan-view-table__cell"]}`} style={{ textAlign: "left" }}>
<div className={styles["plan-view-container"]}>
<div
id="plan-view-inner-container"
ref={this.innerContainer}
......
......@@ -13,6 +13,7 @@
@require 'base/layout-vars.styl'
@require 'base/palette.styl'
@require 'base/typography.styl'
@require 'utils/fonts.styl'
@require 'base/reset.styl'
@require 'pages/reports.styl'
......
......@@ -8,7 +8,6 @@
// by the Apache License, Version 2.0, included in the file
// licenses/APL.txt.
@require 'utils/fonts.styl'
@require "~src/components/core/index.styl"
// Using the same strategy as sassline: establish the root size (rems) as 1/2
......@@ -34,16 +33,3 @@ h2.base-heading
code
font-family $font-family--monospace
font-face('Lato-Light')
font-face('Lato-Bold')
font-face('Lato-Regular')
font-face('Lato-Medium')
font-face('RobotoMono-Bold')
font-face('RobotoMono-Regular')
font-face('RobotoMono-Medium')
font-face('Inconsolata-Regular')
font-face('SourceSansPro-Bold')
font-face('SourceSansPro-Regular')
font-face('SourceSansPro-SemiBold')
font-face('SFMono-Semibold')
......@@ -21,3 +21,16 @@ font-face($family, $style='normal')
font-weight normal
font-style $style
text-rendering optimizeLegibility
font-face('Lato-Light')
font-face('Lato-Bold')
font-face('Lato-Regular')
font-face('Lato-Medium')
font-face('RobotoMono-Bold')
font-face('RobotoMono-Regular')
font-face('RobotoMono-Medium')
font-face('Inconsolata-Regular')
font-face('SourceSansPro-Bold')
font-face('SourceSansPro-Regular')
font-face('SourceSansPro-SemiBold')
font-face('SFMono-Semibold')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment