Remove Helper Classes from visualizations (#4788)

This commit is contained in:
Gabriel Dutra
2020-04-25 15:51:21 -03:00
committed by GitHub
parent 60bc1f8e35
commit bb767f3747
54 changed files with 228 additions and 153 deletions

View File

@@ -6,9 +6,13 @@ import Tooltip from "antd/lib/tooltip";
import "./swatch.less";
export default function Swatch({ className, color, title, size, ...props }) {
export default function Swatch({ className, color, title, size, style, ...props }) {
const result = (
<span className={cx("color-swatch", className)} style={{ backgroundColor: color, width: size }} {...props} />
<span
className={cx("color-swatch", className)}
style={{ backgroundColor: color, width: size, ...style }}
{...props}
/>
);
if (isString(title) && title !== "") {
@@ -23,6 +27,7 @@ export default function Swatch({ className, color, title, size, ...props }) {
Swatch.propTypes = {
className: PropTypes.string,
style: PropTypes.object,
title: PropTypes.string,
color: PropTypes.string,
size: PropTypes.number,
@@ -30,6 +35,7 @@ Swatch.propTypes = {
Swatch.defaultProps = {
className: null,
style: null,
title: null,
color: "transparent",
size: 12,

View File

@@ -70,7 +70,7 @@ export default function ColorPicker({
}, [validatedColor, visible]);
return (
<React.Fragment>
<span className="color-picker-wrapper">
{addonBefore}
<Popover
arrowPointAtCenter
@@ -110,7 +110,7 @@ export default function ColorPicker({
)}
</Popover>
{addonAfter}
</React.Fragment>
</span>
);
}

View File

@@ -38,3 +38,7 @@
.color-picker-trigger {
cursor: pointer;
}
.color-picker-wrapper {
white-space: nowrap;
}

View File

@@ -1,5 +1,4 @@
@import (reference, less) "~bootstrap/less/variables.less";
@import (reference, less) "~@/assets/less/main.less";
@import "../../visualizations/variables";
@jvi-gutter: 20px;
@jvi-spacing: 2px;
@@ -60,7 +59,7 @@
color: @text-color;
&.jvi-string {
color: @state-success-text;
color: @green;
}
&.jvi-braces {
@@ -82,10 +81,10 @@
}
.jvi-value {
color: @state-success-text;
color: @green;
&.jvi-primitive {
color: @brand-warning;
color: @orange;
}
&.jvi-string {
@@ -94,14 +93,15 @@
}
.jvi-object-key {
.jvi-value, .jvi-punctuation {
color: @brand-primary;
.jvi-value,
.jvi-punctuation {
color: @blue;
}
}
.jvi-comment {
color: @text-muted;
font-family: @redash-font;
font-family: @visualizations-font;
font-style: italic;
margin: 0 0 0 2 * @jvi-spacing;
opacity: 0.5;

View File

@@ -24,7 +24,7 @@ ContextHelp.defaultProps = {
children: null,
};
ContextHelp.defaultIcon = <Icon className="m-l-5 m-r-5" type="question-circle" theme="filled" />;
ContextHelp.defaultIcon = <Icon className="context-help-default-icon" type="question-circle" theme="filled" />;
function NumberFormatSpecs() {
const { HelpTriggerComponent } = visualizationsSettings;

View File

@@ -2,13 +2,15 @@ import React from "react";
import PropTypes from "prop-types";
import cx from "classnames";
import "./Section.less";
function SectionTitle({ className, children, ...props }) {
if (!children) {
return null;
}
return (
<h4 className={cx("m-t-0", "m-b-15", className)} {...props}>
<h4 className={cx("visualization-editor-section-title", className)} {...props}>
{children}
</h4>
);
@@ -26,7 +28,7 @@ SectionTitle.defaultProps = {
export default function Section({ className, children, ...props }) {
return (
<div className={cx("m-b-15", className)} {...props}>
<div className={cx("visualization-editor-section", className)} {...props}>
{children}
</div>
);

View File

@@ -0,0 +1,8 @@
.visualization-editor-section-title {
margin-top: 0px;
margin-bottom: 15px;
}
.visualization-editor-section {
margin-bottom: 15px;
}

View File

@@ -3,6 +3,8 @@ import PropTypes from "prop-types";
import AntSwitch from "antd/lib/switch";
import Typography from "antd/lib/typography";
import "./Switch.less";
export default function Switch({ id, children, disabled, ...props }) {
const fallbackId = useMemo(
() =>
@@ -15,9 +17,9 @@ export default function Switch({ id, children, disabled, ...props }) {
if (children) {
return (
<label htmlFor={id} className="d-flex align-items-center">
<label htmlFor={id} className="switch-with-label">
<AntSwitch id={id} disabled={disabled} {...props} />
<Typography.Text className="m-l-10" disabled={disabled}>
<Typography.Text className="switch-text" disabled={disabled}>
{children}
</Typography.Text>
</label>

View File

@@ -0,0 +1,8 @@
.switch-with-label {
display: flex;
align-items: center;
.switch-text {
margin-left: 10px;
}
}

View File

@@ -0,0 +1,12 @@
import React from "react";
import cx from "classnames";
import AntInput from "antd/lib/input";
import withControlLabel from "./withControlLabel";
import "./TextArea.less";
function TextArea({ className, ...otherProps }) {
return <AntInput.TextArea className={cx("visualization-editor-text-area", className)} {...otherProps} />;
}
export default withControlLabel(TextArea);

View File

@@ -0,0 +1,3 @@
.visualization-editor-text-area {
resize: vertical;
}

View File

@@ -1,12 +1,17 @@
@import (reference, less) '~@/assets/less/main.less';
a.visualization-editor-context-help {
&, .ant-typography & {
&,
.ant-typography & {
font: inherit;
color: inherit;
&:hover, &:active {
color: @link-hover-color;
&:hover,
&:active {
color: #0a6ebd;
}
}
}
.context-help-default-icon {
margin-left: 5px;
margin-right: 5px;
}

View File

@@ -5,3 +5,7 @@
}
}
}
.visualization-editor-input {
width: 100% !important;
}

View File

@@ -10,12 +10,12 @@ import withControlLabel, { ControlLabel } from "./withControlLabel";
import createTabbedEditor from "./createTabbedEditor";
import Section from "./Section";
import Switch from "./Switch";
import TextArea from "./TextArea";
import ContextHelp from "./ContextHelp";
export { Section, ControlLabel, Checkbox, Switch, ContextHelp, withControlLabel, createTabbedEditor };
export { Section, ControlLabel, Checkbox, Switch, TextArea, ContextHelp, withControlLabel, createTabbedEditor };
export const Select = withControlLabel(AntSelect);
export const Input = withControlLabel(AntInput);
export const TextArea = withControlLabel(AntInput.TextArea);
export const InputNumber = withControlLabel(AntInputNumber);
export const ColorPicker = withControlLabel(RedashColorPicker);
export const TextAlignmentSelect = withControlLabel(RedashTextAlignmentSelect);

View File

@@ -1,4 +1,5 @@
import React, { useMemo } from "react";
import cx from "classnames";
import PropTypes from "prop-types";
import hoistNonReactStatics from "hoist-non-react-statics";
import * as Grid from "antd/lib/grid";
@@ -55,7 +56,7 @@ ControlLabel.defaultProps = {
export default function withControlLabel(WrappedControl) {
// eslint-disable-next-line react/prop-types
function ControlWrapper({ id, layout, label, labelProps, disabled, ...props }) {
function ControlWrapper({ className, id, layout, label, labelProps, disabled, ...props }) {
const fallbackId = useMemo(
() =>
`visualization-editor-control-${Math.random()
@@ -70,7 +71,12 @@ export default function withControlLabel(WrappedControl) {
return (
<ControlLabel layout={layout} label={label} labelProps={labelProps} disabled={disabled}>
<WrappedControl id={labelProps.htmlFor} disabled={disabled} {...props} />
<WrappedControl
className={cx("visualization-editor-input", className)}
id={labelProps.htmlFor}
disabled={disabled}
{...props}
/>
</ControlLabel>
);
}

View File

@@ -27,7 +27,6 @@ export default function AxisSettings({ id, options, features, onChange }) {
<Section>
<Select
label="Scale"
className="w-100"
data-test={`Chart.${id}.Type`}
defaultValue={options.type}
onChange={type => optionsChanged({ type })}>
@@ -66,7 +65,6 @@ export default function AxisSettings({ id, options, features, onChange }) {
<Grid.Col span={12}>
<InputNumber
label="Min Value"
className="w-100"
placeholder="Auto"
data-test={`Chart.${id}.RangeMin`}
defaultValue={toNumber(options.rangeMin)}
@@ -76,7 +74,6 @@ export default function AxisSettings({ id, options, features, onChange }) {
<Grid.Col span={12}>
<InputNumber
label="Max Value"
className="w-100"
placeholder="Auto"
data-test={`Chart.${id}.RangeMax`}
defaultValue={toNumber(options.rangeMax)}

View File

@@ -27,7 +27,7 @@ export default function ChartTypeSelect(props) {
<Select {...props}>
{map(chartTypes, ({ type, name, icon }) => (
<Select.Option key={type} value={type} data-test={`Chart.ChartType.${type}`}>
<i className={`m-r-5 fa fa-${icon}`} />
<i className={`fa fa-${icon}`} style={{ marginRight: 5 }} />
{name}
</Select.Option>
))}

View File

@@ -20,7 +20,6 @@ export default function ColumnMappingSelect({ value, availableColumns, type, onC
<Section>
<Select
label={label}
className="w-100"
data-test={`Chart.ColumnMapping.${type}`}
mode={multiple ? "multiple" : "default"}
allowClear

View File

@@ -17,7 +17,6 @@ export default function CustomChartSettings({ options, onOptionsChange }) {
<TextArea
label="Custom code"
data-test="Chart.Custom.Code"
className="form-control v-resizable"
rows="10"
defaultValue={isNil(options.customCode) ? defaultCustomCode : options.customCode}
onChange={event => onOptionsChange({ customCode: event.target.value })}

View File

@@ -73,7 +73,7 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
<React.Fragment>
Data Labels
<ContextHelp placement="topRight" arrowPointAtCenter>
<div className="p-b-5">Use special names to access additional properties:</div>
<div style={{ paddingBottom: 5 }}>Use special names to access additional properties:</div>
<div>
<code>{"{{ @@name }}"}</code> series name;
</div>
@@ -92,11 +92,11 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
<div>
<code>{"{{ @@size }}"}</code> bubble size;
</div>
<div className="p-t-5">
<div style={{ paddingTop: 5 }}>
Also, all query result columns can be referenced
<br />
using
<code className="text-nowrap">{"{{ column_name }}"}</code> syntax.
<code style={{ whiteSpace: "nowrap" }}>{"{{ column_name }}"}</code> syntax.
</div>
</ContextHelp>
</React.Fragment>

View File

@@ -46,7 +46,6 @@ export default function DefaultColorsSettings({ options, data, onOptionsChange }
title: "Color",
dataIndex: "color",
width: "1%",
className: "text-nowrap",
render: (unused, item) => (
<ColorPicker
data-test={`Chart.Series.${item.key}.Color`}

View File

@@ -103,7 +103,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<ChartTypeSelect
label="Chart Type"
className="w-100"
data-test="Chart.GlobalSeriesType"
defaultValue={options.globalSeriesType}
onChange={handleGlobalSeriesTypeChange}
@@ -125,7 +124,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<InputNumber
label="Bubble Size Coefficient"
className="w-100"
data-test="Chart.BubbleCoefficient"
defaultValue={options.coefficient}
onChange={value => onOptionsChange({ coefficient: toNumber(value) })}
@@ -135,7 +133,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Bubble Size Proportional To"
className="w-100"
data-test="Chart.SizeMode"
defaultValue={options.sizemode}
onChange={mode => onOptionsChange({ sizemode: mode })}>
@@ -154,7 +151,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Direction"
className="w-100"
data-test="Chart.PieDirection"
defaultValue={options.direction.type}
onChange={type => onOptionsChange({ direction: { type } })}>
@@ -194,7 +190,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Stacking"
className="w-100"
data-test="Chart.Stacking"
defaultValue={options.series.stacking}
disabled={!includes(["line", "area", "column"], options.globalSeriesType)}
@@ -224,7 +219,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Missing and NULL values"
className="w-100"
data-test="Chart.MissingValues"
defaultValue={options.missingValuesAsZero ? 1 : 0}
onChange={value => onOptionsChange({ missingValuesAsZero: !!value })}>

View File

@@ -31,7 +31,6 @@ export default function HeatmapColorsSettings({ options, onOptionsChange }) {
<Section>
<Select
label="Color Scheme"
className="w-100"
data-test="Chart.Colors.Heatmap.ColorScheme"
placeholder="Choose Color Scheme..."
allowClear

View File

@@ -56,7 +56,6 @@ export default function PieColorsSettings({ options, data, onOptionsChange }) {
title: "Color",
dataIndex: "color",
width: "1%",
className: "text-nowrap",
render: (unused, item) => (
<ColorPicker
data-test={`Chart.Series.${item.key}.Color`}

View File

@@ -17,9 +17,8 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
{
title: "Order",
dataIndex: "zIndex",
className: "text-nowrap",
render: (unused, item) => (
<span className="d-flex align-items-center">
<span className="series-settings-order">
<DragHandle />
{item.zIndex + 1}
</span>
@@ -28,7 +27,6 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
{
title: "Label",
dataIndex: "name",
className: "text-nowrap",
render: (unused, item) => (
<Input
data-test={`Chart.Series.${item.key}.Label`}
@@ -44,10 +42,9 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
result.push({
title: "Y Axis",
dataIndex: "yAxis",
className: "text-nowrap",
render: (unused, item) => (
<Radio.Group
className="text-nowrap"
className="series-settings-y-axis"
value={item.yAxis === 1 ? 1 : 0}
onChange={event => updateSeriesOption(item.key, "yAxis", event.target.value)}>
<Radio value={0} data-test={`Chart.Series.${item.key}.UseLeftAxis`}>
@@ -62,10 +59,8 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
result.push({
title: "Type",
dataIndex: "type",
className: "text-nowrap",
render: (unused, item) => (
<ChartTypeSelect
className="w-100"
data-test={`Chart.Series.${item.key}.Type`}
dropdownMatchSelectWidth={false}
value={item.type}

View File

@@ -1,4 +1,14 @@
.chart-editor-series {
.series-settings-order {
display: flex;
align-items: center;
white-space: nowrap;
}
.series-settings-y-axis {
white-space: nowrap;
}
.drag-handle {
height: 28px;
padding: 0 5px;
@@ -13,7 +23,7 @@
thead th {
// TODO: replace with @table-header-bg
// Cannot do it not because of conflict between Antd and Bootstrap variables
background: mix(#ffffff, rgb(102, 136, 153), 97%) !important;
background: mix(#ffffff, rgb(102, 136, 153), 97%) !important;
}
&.sortable-container-dragging tbody {

View File

@@ -39,10 +39,10 @@ export default function BoundsSettings({ options, onOptionsChange }) {
<ControlLabel label="North-East latitude and longitude">
<Grid.Row gutter={15}>
<Grid.Col span={12}>
<InputNumber className="w-100" value={bounds[1][0]} onChange={value => updateBounds(1, 0, value)} />
<InputNumber value={bounds[1][0]} onChange={value => updateBounds(1, 0, value)} />
</Grid.Col>
<Grid.Col span={12}>
<InputNumber className="w-100" value={bounds[1][1]} onChange={value => updateBounds(1, 1, value)} />
<InputNumber value={bounds[1][1]} onChange={value => updateBounds(1, 1, value)} />
</Grid.Col>
</Grid.Row>
</ControlLabel>
@@ -52,10 +52,10 @@ export default function BoundsSettings({ options, onOptionsChange }) {
<ControlLabel label="South-West latitude and longitude">
<Grid.Row gutter={15}>
<Grid.Col span={12}>
<InputNumber className="w-100" value={bounds[0][0]} onChange={value => updateBounds(0, 0, value)} />
<InputNumber value={bounds[0][0]} onChange={value => updateBounds(0, 0, value)} />
</Grid.Col>
<Grid.Col span={12}>
<InputNumber className="w-100" value={bounds[0][1]} onChange={value => updateBounds(0, 1, value)} />
<InputNumber value={bounds[0][1]} onChange={value => updateBounds(0, 1, value)} />
</Grid.Col>
</Grid.Row>
</ControlLabel>

View File

@@ -13,7 +13,6 @@ export default function ColorsSettings({ options, onOptionsChange }) {
<Select
layout="horizontal"
label="Clustering mode"
className="w-100"
data-test="Choropleth.Editor.ClusteringMode"
defaultValue={options.clusteringMode}
onChange={clusteringMode => onOptionsChange({ clusteringMode })}>
@@ -33,7 +32,6 @@ export default function ColorsSettings({ options, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Steps"
className="w-100"
data-test="Choropleth.Editor.ColorSteps"
min={3}
max={11}

View File

@@ -16,10 +16,10 @@ function TemplateFormatHint({ mapType }) {
// eslint-disable-line react/prop-types
return (
<ContextHelp placement="topLeft" arrowPointAtCenter>
<div className="p-b-5">
<div style={{ paddingBottom: 5 }}>
All query result columns can be referenced using <code>{"{{ column_name }}"}</code> syntax.
</div>
<div className="p-b-5">Use special names to access additional properties:</div>
<div style={{ paddingBottom: 5 }}>Use special names to access additional properties:</div>
<div>
<code>{"{{ @@value }}"}</code> formatted value;
</div>
@@ -79,7 +79,6 @@ export default function GeneralSettings({ options, onOptionsChange }) {
<ContextHelp.NumberFormatSpecs />
</React.Fragment>
}
className="w-100"
data-test="Choropleth.Editor.ValueFormat"
defaultValue={options.valueFormat}
onChange={event => onOptionsChangeDebounced({ valueFormat: event.target.value })}
@@ -88,7 +87,6 @@ export default function GeneralSettings({ options, onOptionsChange }) {
<Grid.Col span={12}>
<Input
label="Value placeholder"
className="w-100"
data-test="Choropleth.Editor.ValuePlaceholder"
defaultValue={options.noValuePlaceholder}
onChange={event => onOptionsChangeDebounced({ noValuePlaceholder: event.target.value })}
@@ -111,7 +109,6 @@ export default function GeneralSettings({ options, onOptionsChange }) {
<Grid.Col span={12}>
<Select
label="Legend position"
className="w-100"
data-test="Choropleth.Editor.LegendPosition"
disabled={!options.legend.visible}
defaultValue={options.legend.position}
@@ -154,7 +151,6 @@ export default function GeneralSettings({ options, onOptionsChange }) {
<Section>
<Input
label={<React.Fragment>Tooltip template {templateFormatHint}</React.Fragment>}
className="w-100"
data-test="Choropleth.Editor.TooltipTemplate"
disabled={!options.tooltip.enabled}
defaultValue={options.tooltip.template}
@@ -174,7 +170,6 @@ export default function GeneralSettings({ options, onOptionsChange }) {
<Section>
<TextArea
label={<React.Fragment>Popup template {templateFormatHint}</React.Fragment>}
className="w-100"
data-test="Choropleth.Editor.PopupTemplate"
disabled={!options.popup.enabled}
rows={4}

View File

@@ -42,7 +42,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Map type"
className="w-100"
data-test="Choropleth.Editor.MapType"
defaultValue={options.mapType}
onChange={mapType => handleChangeAndInferType({ mapType })}>
@@ -58,7 +57,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Key column"
className="w-100"
data-test="Choropleth.Editor.KeyColumn"
defaultValue={options.countryCodeColumn}
onChange={countryCodeColumn => handleChangeAndInferType({ countryCodeColumn })}>
@@ -73,7 +71,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Key type"
className="w-100"
data-test="Choropleth.Editor.KeyType"
value={options.countryCodeType}
onChange={countryCodeType => onOptionsChange({ countryCodeType })}>
@@ -88,7 +85,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Section>
<Select
label="Value column"
className="w-100"
data-test="Choropleth.Editor.ValueColumn"
defaultValue={options.valueColumn}
onChange={valueColumn => onOptionsChange({ valueColumn })}>

View File

@@ -7,9 +7,9 @@ export default function Legend({ items, alignText }) {
return (
<div className="choropleth-visualization-legend">
{map(items, (item, index) => (
<div key={`legend${index}`} className="d-flex align-items-center">
<ColorPicker.Swatch color={item.color} className="m-r-5" />
<div className={`flex-fill text-${alignText}`}>{item.text}</div>
<div key={`legend${index}`} className="legend-item">
<ColorPicker.Swatch color={item.color} />
<div className={`legend-item-text text-${alignText}`}>{item.text}</div>
</div>
))}
</div>

View File

@@ -6,4 +6,27 @@
line-height: 1;
margin: 5px;
}
.legend-item {
display: flex;
align-items: center;
.color-swatch {
margin-right: 5px;
}
.legend-item-text {
flex: 1 1 auto;
&.text-left {
text-align: left;
}
&.text-center {
text-align: center;
}
&.text-right {
text-align: right;
}
}
}
}

View File

@@ -47,7 +47,6 @@ export default function ColorsSettings({ options, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Steps"
className="w-100"
min={minSteps}
max={maxSteps}
value={options.colors.steps}

View File

@@ -11,7 +11,6 @@ export default function ColumnsSettings({ options, data, onOptionsChange }) {
layout="horizontal"
label="Date (Bucket)"
data-test="Cohort.DateColumn"
className="w-100"
value={options.dateColumn}
onChange={dateColumn => onOptionsChange({ dateColumn })}>
{map(data.columns, ({ name }) => (
@@ -27,7 +26,6 @@ export default function ColumnsSettings({ options, data, onOptionsChange }) {
layout="horizontal"
label="Stage"
data-test="Cohort.StageColumn"
className="w-100"
value={options.stageColumn}
onChange={stageColumn => onOptionsChange({ stageColumn })}>
{map(data.columns, ({ name }) => (
@@ -43,7 +41,6 @@ export default function ColumnsSettings({ options, data, onOptionsChange }) {
layout="horizontal"
label="Bucket Population Size"
data-test="Cohort.TotalColumn"
className="w-100"
value={options.totalColumn}
onChange={totalColumn => onOptionsChange({ totalColumn })}>
{map(data.columns, ({ name }) => (
@@ -59,7 +56,6 @@ export default function ColumnsSettings({ options, data, onOptionsChange }) {
layout="horizontal"
label="Stage Value"
data-test="Cohort.ValueColumn"
className="w-100"
value={options.valueColumn}
onChange={valueColumn => onOptionsChange({ valueColumn })}>
{map(data.columns, ({ name }) => (

View File

@@ -22,7 +22,6 @@ export default function OptionsSettings({ options, onOptionsChange }) {
layout="horizontal"
label="Time Interval"
data-test="Cohort.TimeInterval"
className="w-100"
value={options.timeInterval}
onChange={timeInterval => onOptionsChange({ timeInterval })}>
{map(CohortTimeIntervals, (name, value) => (
@@ -38,7 +37,6 @@ export default function OptionsSettings({ options, onOptionsChange }) {
layout="horizontal"
label="Mode"
data-test="Cohort.Mode"
className="w-100"
value={options.mode}
onChange={mode => onOptionsChange({ mode })}>
{map(CohortModes, (name, value) => (

View File

@@ -1,7 +1,6 @@
.cornelius-container {
// replace with variable from `ant-variables.less` after Bootstrap removed
@table-header-color: #333;
@import "../variables";
.cornelius-container {
.cornelius-title {
text-align: center;
padding-bottom: 10px;
@@ -14,13 +13,14 @@
.cornelius-table {
font-size: 9pt;
border-spacing: 0;
border: 1px solid #E4E4E4;
border: 1px solid #e4e4e4;
border-collapse: collapse;
th, td {
th,
td {
text-align: center;
padding: 10px;
border: 1px solid #E4E4E4;
border: 1px solid #e4e4e4;
color: @table-header-color;
font-weight: bold;
}

View File

@@ -1,18 +1,21 @@
@import (reference, less) '~@/assets/less/inc/variables';
@import "../variables";
.cohort-visualization-container {
.cornelius-table {
width: 100%;
&, tr, th, td {
border-color: @table-border-color;
&,
tr,
th,
td {
border-color: #f0f0f0;
}
.cornelius-time,
.cornelius-label,
.cornelius-stage,
.cornelius-people {
background-color: fade(@redash-gray, 3%);
background-color: fade(@visualizations-gray, 3%);
}
}
}

View File

@@ -12,7 +12,6 @@ export default function FormatSettings({ options, data, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Formatting Decimal Place"
className="w-100"
data-test="Counter.Formatting.DecimalPlace"
defaultValue={options.stringDecimal}
disabled={!inputsEnabled}
@@ -24,7 +23,6 @@ export default function FormatSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Formatting Decimal Character"
className="w-100"
data-test="Counter.Formatting.DecimalCharacter"
defaultValue={options.stringDecChar}
disabled={!inputsEnabled}
@@ -36,7 +34,6 @@ export default function FormatSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Formatting Thousands Separator"
className="w-100"
data-test="Counter.Formatting.ThousandsSeparator"
defaultValue={options.stringThouSep}
disabled={!inputsEnabled}
@@ -48,7 +45,6 @@ export default function FormatSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Formatting String Prefix"
className="w-100"
data-test="Counter.Formatting.StringPrefix"
defaultValue={options.stringPrefix}
disabled={!inputsEnabled}
@@ -60,7 +56,6 @@ export default function FormatSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Formatting String Suffix"
className="w-100"
data-test="Counter.Formatting.StringSuffix"
defaultValue={options.stringSuffix}
disabled={!inputsEnabled}

View File

@@ -10,7 +10,6 @@ export default function GeneralSettings({ options, data, visualizationName, onOp
<Input
layout="horizontal"
label="Counter Label"
className="w-100"
data-test="Counter.General.Label"
defaultValue={options.counterLabel}
placeholder={visualizationName}
@@ -22,7 +21,6 @@ export default function GeneralSettings({ options, data, visualizationName, onOp
<Select
layout="horizontal"
label="Counter Value Column Name"
className="w-100"
data-test="Counter.General.ValueColumn"
defaultValue={options.counterColName}
disabled={options.countRow}
@@ -39,7 +37,6 @@ export default function GeneralSettings({ options, data, visualizationName, onOp
<InputNumber
layout="horizontal"
label="Counter Value Row Number"
className="w-100"
data-test="Counter.General.ValueRowNumber"
defaultValue={options.rowNumber}
disabled={options.countRow}
@@ -51,7 +48,6 @@ export default function GeneralSettings({ options, data, visualizationName, onOp
<Select
layout="horizontal"
label="Target Value Column Name"
className="w-100"
data-test="Counter.General.TargetValueColumn"
defaultValue={options.targetColName}
onChange={targetColName => onOptionsChange({ targetColName })}>
@@ -68,7 +64,6 @@ export default function GeneralSettings({ options, data, visualizationName, onOp
<InputNumber
layout="horizontal"
label="Target Value Row Number"
className="w-100"
data-test="Counter.General.TargetValueRowNumber"
defaultValue={options.targetRowNumber}
onChange={targetRowNumber => onOptionsChange({ targetRowNumber })}

View File

@@ -17,7 +17,6 @@ export default function AppearanceSettings({ options, onOptionsChange }) {
<ContextHelp.NumberFormatSpecs />
</React.Fragment>
}
className="w-100"
data-test="Funnel.NumberFormat"
defaultValue={options.numberFormat}
onChange={event => onOptionsChangeDebounced({ numberFormat: event.target.value })}
@@ -33,7 +32,6 @@ export default function AppearanceSettings({ options, onOptionsChange }) {
<ContextHelp.NumberFormatSpecs />
</React.Fragment>
}
className="w-100"
data-test="Funnel.PercentFormat"
defaultValue={options.percentFormat}
onChange={event => onOptionsChangeDebounced({ percentFormat: event.target.value })}
@@ -44,7 +42,6 @@ export default function AppearanceSettings({ options, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Items Count Limit"
className="w-100"
data-test="Funnel.ItemsLimit"
min={2}
defaultValue={options.itemsLimit}
@@ -56,7 +53,6 @@ export default function AppearanceSettings({ options, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Min Percent Value"
className="w-100"
data-test="Funnel.PercentRangeMin"
min={0}
defaultValue={options.percentValuesRange.min}
@@ -68,7 +64,6 @@ export default function AppearanceSettings({ options, onOptionsChange }) {
<InputNumber
layout="horizontal"
label="Max Percent Value"
className="w-100"
data-test="Funnel.PercentRangeMax"
min={0}
defaultValue={options.percentValuesRange.max}

View File

@@ -15,7 +15,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
layout="horizontal"
label="Step Column"
className="w-100"
data-test="Funnel.StepColumn"
placeholder="Choose column..."
defaultValue={options.stepCol.colName || undefined}
@@ -32,7 +31,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Step Column Title"
className="w-100"
data-test="Funnel.StepColumnTitle"
defaultValue={options.stepCol.displayAs}
onChange={event => onOptionsChangeDebounced({ stepCol: { displayAs: event.target.value } })}
@@ -43,7 +41,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
layout="horizontal"
label="Value Column"
className="w-100"
data-test="Funnel.ValueColumn"
placeholder="Choose column..."
defaultValue={options.valueCol.colName || undefined}
@@ -60,7 +57,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Input
layout="horizontal"
label="Value Column Title"
className="w-100"
data-test="Funnel.ValueColumnTitle"
defaultValue={options.valueCol.displayAs}
onChange={event => onOptionsChangeDebounced({ valueCol: { displayAs: event.target.value } })}
@@ -82,7 +78,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
layout="horizontal"
label="Sort Column"
className="w-100"
data-test="Funnel.SortColumn"
allowClear
placeholder="Choose column..."
@@ -100,7 +95,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
layout="horizontal"
label="Sort Order"
className="w-100"
data-test="Funnel.SortDirection"
disabled={!options.sortKeyCol.colName}
defaultValue={options.sortKeyCol.reverse ? "desc" : "asc"}

View File

@@ -7,10 +7,10 @@ function TemplateFormatHint() {
// eslint-disable-line react/prop-types
return (
<ContextHelp placement="topLeft" arrowPointAtCenter>
<div className="p-b-5">
<div style={{ paddingBottom: 5 }}>
All query result columns can be referenced using <code>{"{{ column_name }}"}</code> syntax.
</div>
<div className="p-b-5">Leave this field empty to use default template.</div>
<div style={{ paddingBottom: 5 }}>Leave this field empty to use default template.</div>
</ContextHelp>
);
}
@@ -34,7 +34,6 @@ export default function FormatSettings({ options, onOptionsChange }) {
<Section>
<Input
label={<React.Fragment>Tooltip template {templateFormatHint}</React.Fragment>}
className="w-100"
data-test="Map.Editor.TooltipTemplate"
disabled={!options.tooltip.enabled}
placeholder="Default template"
@@ -55,7 +54,6 @@ export default function FormatSettings({ options, onOptionsChange }) {
<Section>
<TextArea
label={<React.Fragment>Popup template {templateFormatHint}</React.Fragment>}
className="w-100"
data-test="Map.Editor.PopupTemplate"
disabled={!options.popup.enabled}
rows={4}

View File

@@ -23,7 +23,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
label="Latitude Column Name"
data-test="Map.Editor.LatitudeColumnName"
className="w-100"
value={options.latColName}
onChange={latColName => onOptionsChange({ latColName })}>
{map(getColumns(options.latColName, unusedColumns), col => (
@@ -38,7 +37,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
label="Longitude Column Name"
data-test="Map.Editor.LongitudeColumnName"
className="w-100"
value={options.lonColName}
onChange={lonColName => onOptionsChange({ lonColName })}>
{map(getColumns(options.lonColName, unusedColumns), col => (
@@ -53,7 +51,6 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
<Select
label="Group By"
data-test="Map.Editor.GroupBy"
className="w-100"
allowClear
placeholder="none"
value={options.classify || undefined}

View File

@@ -43,7 +43,6 @@ export default function GroupsSettings({ options, data, onOptionsChange }) {
title: "Color",
dataIndex: "color",
width: "1%",
className: "text-nowrap",
render: (unused, item) => (
<ColorPicker
interactive

View File

@@ -89,7 +89,6 @@ export default function StyleSettings({ options, onOptionsChange }) {
<Select
label="Map Tiles"
data-test="Map.Editor.Tiles"
className="w-100"
value={options.mapTileUrl}
onChange={mapTileUrl => onOptionsChange({ mapTileUrl })}>
{map(mapTiles, ({ name, url }) => (
@@ -134,7 +133,6 @@ export default function StyleSettings({ options, onOptionsChange }) {
<Select
layout="horizontal"
label="Shape"
className="w-100"
data-test="Map.Editor.MarkerShape"
value={options.iconShape}
onChange={iconShape => onOptionsChange({ iconShape })}>
@@ -167,20 +165,19 @@ export default function StyleSettings({ options, onOptionsChange }) {
<React.Fragment>
Icon
<ContextHelp placement="topLeft" arrowPointAtCenter>
<div className="m-b-5">
<div style={{ marginBottom: 5 }}>
Enter an icon name from{" "}
<a href="https://fontawesome.com/v4.7.0/icons/" target="_blank" rel="noopener noreferrer">
Font-Awesome 4.7
</a>
</div>
<div className="m-b-5">
<div style={{ marginBottom: 5 }}>
Examples: <code>check</code>, <code>times-circle</code>, <code>flag</code>
</div>
<div>Leave blank to remove.</div>
</ContextHelp>
</React.Fragment>
}
className="w-100"
data-test="Map.Editor.MarkerIcon"
defaultValue={options.iconFont}
onChange={event => debouncedOnOptionsChange({ iconFont: event.target.value })}

View File

@@ -1,15 +1,20 @@
@redash-gray: rgba(102, 136, 153, 1);
@import "../variables.less";
.pivot-table-visualization-container {
&[data-hide-controls] {
.pvtAxisContainer, .pvtRenderers, .pvtVals {
.pvtAxisContainer,
.pvtRenderers,
.pvtVals {
display: none;
}
}
&[data-hide-row-totals] {
td:last-child, th:last-child {
&.pvtTotalLabel:not(:empty), &.pvtTotal, &.pvtGrandTotal {
td:last-child,
th:last-child {
&.pvtTotalLabel:not(:empty),
&.pvtTotal,
&.pvtGrandTotal {
display: none;
}
}
@@ -17,27 +22,30 @@
&[data-hide-column-totals] {
tbody > tr:last-child {
& > .pvtTotalLabel, & > .pvtTotal, & > .pvtGrandTotal {
& > .pvtTotalLabel,
& > .pvtTotal,
& > .pvtGrandTotal {
display: none;
}
}
}
}
.pvtAxisContainer, .pvtVals {
border: 1px solid fade(@redash-gray, 15%);
.pvtAxisContainer,
.pvtVals {
border: 1px solid fade(@visualizations-gray, 15%);
background: #fff;
}
.pvtAxisContainer li span.pvtAttr {
background: fade(@redash-gray, 10%);
border: 1px solid fade(@redash-gray, 15%);
background: fade(@visualizations-gray, 10%);
border: 1px solid fade(@visualizations-gray, 15%);
border-radius: 3px;
}
.pvtCheckContainer {
border-top: 1px solid fade(@redash-gray, 15%);
border-bottom: 1px solid fade(@redash-gray, 15%);
border-top: 1px solid fade(@visualizations-gray, 15%);
border-bottom: 1px solid fade(@visualizations-gray, 15%);
}
.pvtCheckContainer p {
@@ -46,11 +54,12 @@
}
.pvtTriangle {
color: fade(@redash-gray, 90%);
color: fade(@visualizations-gray, 90%);
}
table.pvtTable thead tr th, table.pvtTable tbody tr th {
background-color: fade(@redash-gray, 10%);
table.pvtTable thead tr th,
table.pvtTable tbody tr th {
background-color: fade(@visualizations-gray, 10%);
border: 1px solid #ced8dc;
}
@@ -59,9 +68,9 @@ table.pvtTable tbody tr td {
}
.pvtFilterBox {
border: 1px solid fade(@redash-gray, 15%);
border: 1px solid fade(@visualizations-gray, 15%);
border-radius: 3px;
box-shadow: fade(@redash-gray, 15%) 0px 4px 9px -3px;
box-shadow: fade(@visualizations-gray, 15%) 0px 4px 9px -3px;
button {
background-color: rgba(102, 136, 153, 0.15);
@@ -77,7 +86,7 @@ table.pvtTable tbody tr td {
}
}
input[type='text'] {
input[type="text"] {
width: 90%;
margin: 0 auto 10px;
height: 35px;

View File

@@ -58,7 +58,6 @@ export default function ColumnEditor({ column, onChange }) {
<Select
label="Display as:"
data-test={`Table.Column.${column.name}.DisplayAs`}
className="w-100"
defaultValue={column.displayAs}
onChange={displayAs => handleChange({ displayAs })}>
{map(ColumnTypes, ({ friendlyName }, key) => (

View File

@@ -51,7 +51,7 @@ export default function ColumnsSettings({ options, onOptionsChange }) {
<span data-test={`Table.Column.${column.name}.Name`}>
{column.name}
{column.title !== "" && column.title !== column.name && (
<Text type="secondary" className="m-l-5">
<Text type="secondary" style={{ marginLeft: 5 }}>
<i>({column.title})</i>
</Text>
)}

View File

@@ -11,7 +11,6 @@ export default function GridSettings({ options, onOptionsChange }) {
<Select
label="Items per page"
data-test="Table.ItemsPerPage"
className="w-100"
defaultValue={options.itemsPerPage}
onChange={itemsPerPage => onOptionsChange({ itemsPerPage })}>
{map(ALLOWED_ITEM_PER_PAGE, value => (

View File

@@ -20,4 +20,14 @@
.table-visualization-editor-column {
padding-left: 6px;
.image-dimension-selector {
display: flex;
align-items: center;
.image-dimension-selector-spacer {
padding-left: 5px;
padding-right: 5px;
}
}
}

View File

@@ -25,19 +25,19 @@ function Editor({ column, onChange }) {
<React.Fragment>
Size
<ContextHelp placement="topLeft" arrowPointAtCenter>
<div className="m-b-5">Any positive integer value that specifies size in pixels.</div>
<div style={{ marginBottom: 5 }}>Any positive integer value that specifies size in pixels.</div>
<div>Leave empty to use default value.</div>
</ContextHelp>
</React.Fragment>
}>
<div className="d-flex align-items-center">
<div className="image-dimension-selector">
<Input
data-test="Table.ColumnEditor.Image.Width"
placeholder="Width"
defaultValue={column.imageWidth}
onChange={event => onChangeDebounced({ imageWidth: event.target.value })}
/>
<span className="p-l-5 p-r-5">&times;</span>
<span className="image-dimension-selector-spacer">&times;</span>
<Input
data-test="Table.ColumnEditor.Image.Height"
placeholder="Height"

View File

@@ -1,4 +1,4 @@
@import (reference, less) "~@/assets/less/ant.less";
@import "../variables";
.table-visualization-container {
.ant-pagination.ant-table-pagination {

View File

@@ -0,0 +1,35 @@
/* --------------------------------------------------------
Colors
-----------------------------------------------------------*/
@black: #000;
@blue: #2196f3;
@green: #4caf50;
@orange: #ff9800;
@visualizations-gray: rgba(102, 136, 153, 1);
/* --------------------------------------------------------
Font
-----------------------------------------------------------*/
@font-family-monospace: Menlo, Monaco, Consolas, "Courier New", monospace;
@visualizations-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell,
"Helvetica Neue", sans-serif;
/* --------------------------------------------------------
Borders
-----------------------------------------------------------*/
@border-width-base: 1px;
@border-style-base: solid;
@border-color-split: hsv(0, 0, 91%);
/* --------------------------------------------------------
Typography
-----------------------------------------------------------*/
@text-color: #595959;
@text-muted: #828282;
@text-color-secondary: fade(@black, 45%);
/* --------------------------------------------------------
Table
-----------------------------------------------------------*/
@table-border-color: #f0f0f0;
@table-header-color: #333;

View File

@@ -15,7 +15,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Select
label="Words Column"
data-test="WordCloud.WordsColumn"
className="w-100"
value={options.column}
onChange={column => optionsChanged({ column })}>
{map(data.columns, ({ name }) => (
@@ -29,7 +28,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Select
label="Frequencies Column"
data-test="WordCloud.FrequenciesColumn"
className="w-100"
value={options.frequenciesColumn}
onChange={frequenciesColumn => optionsChanged({ frequenciesColumn })}>
<Select.Option key="none" value="">
@@ -48,7 +46,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Grid.Col span={12}>
<InputNumber
data-test="WordCloud.WordLengthLimit.Min"
className="w-100"
placeholder="Min"
min={0}
value={options.wordLengthLimit.min}
@@ -58,7 +55,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Grid.Col span={12}>
<InputNumber
data-test="WordCloud.WordLengthLimit.Max"
className="w-100"
placeholder="Max"
min={0}
value={options.wordLengthLimit.max}
@@ -74,7 +70,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Grid.Col span={12}>
<InputNumber
data-test="WordCloud.WordCountLimit.Min"
className="w-100"
placeholder="Min"
min={0}
value={options.wordCountLimit.min}
@@ -84,7 +79,6 @@ export default function Editor({ options, data, onOptionsChange }) {
<Grid.Col span={12}>
<InputNumber
data-test="WordCloud.WordCountLimit.Max"
className="w-100"
placeholder="Max"
min={0}
value={options.wordCountLimit.max}