mirror of
https://github.com/getredash/redash.git
synced 2025-12-25 01:03:20 -05:00
Remove Helper Classes from visualizations (#4788)
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,3 +38,7 @@
|
||||
.color-picker-trigger {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.color-picker-wrapper {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
8
client/app/components/visualizations/editor/Section.less
Normal file
8
client/app/components/visualizations/editor/Section.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.visualization-editor-section-title {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.visualization-editor-section {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
8
client/app/components/visualizations/editor/Switch.less
Normal file
8
client/app/components/visualizations/editor/Switch.less
Normal file
@@ -0,0 +1,8 @@
|
||||
.switch-with-label {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.switch-text {
|
||||
margin-left: 10px;
|
||||
}
|
||||
}
|
||||
12
client/app/components/visualizations/editor/TextArea.jsx
Normal file
12
client/app/components/visualizations/editor/TextArea.jsx
Normal 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);
|
||||
@@ -0,0 +1,3 @@
|
||||
.visualization-editor-text-area {
|
||||
resize: vertical;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,3 +5,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.visualization-editor-input {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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>
|
||||
))}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 })}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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`}
|
||||
|
||||
@@ -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 })}>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 })}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 }) => (
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 })}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 })}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) => (
|
||||
|
||||
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -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 => (
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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">×</span>
|
||||
<span className="image-dimension-selector-spacer">×</span>
|
||||
<Input
|
||||
data-test="Table.ColumnEditor.Image.Height"
|
||||
placeholder="Height"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import (reference, less) "~@/assets/less/ant.less";
|
||||
@import "../variables";
|
||||
|
||||
.table-visualization-container {
|
||||
.ant-pagination.ant-table-pagination {
|
||||
|
||||
35
client/app/visualizations/variables.less
Normal file
35
client/app/visualizations/variables.less
Normal 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;
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user