mirror of
https://github.com/getredash/redash.git
synced 2025-12-19 09:27:23 -05:00
@@ -1,5 +1,4 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
// @ts-expect-error (Must be removed after adding @redash/viz typing)
|
||||
import ErrorBoundary, { ErrorBoundaryContext } from "@redash/viz/lib/components/ErrorBoundary";
|
||||
import { Auth } from "@/services/auth";
|
||||
import { policy } from "@/services/policy";
|
||||
@@ -62,9 +61,10 @@ export function UserSessionWrapper<P>({ bodyClass, currentRoute, render }: UserS
|
||||
return (
|
||||
<ApplicationLayout>
|
||||
<React.Fragment key={currentRoute.key}>
|
||||
{/* @ts-expect-error FIXME */}
|
||||
<ErrorBoundary renderError={(error: Error) => <ErrorMessage error={error} />}>
|
||||
<ErrorBoundaryContext.Consumer>
|
||||
{({ handleError }: { handleError: UserSessionWrapperRenderChildrenProps<P>["onError"] }) =>
|
||||
{({ handleError } /* : { handleError: UserSessionWrapperRenderChildrenProps<P>["onError"] } FIXME bring back type */) =>
|
||||
render({ ...currentRoute.routeParams, pageTitle: currentRoute.title, onError: handleError })
|
||||
}
|
||||
</ErrorBoundaryContext.Consumer>
|
||||
|
||||
@@ -15,21 +15,14 @@
|
||||
"jsx": "react",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"noUnusedLocals": true,
|
||||
"lib": [
|
||||
"dom",
|
||||
"dom.iterable",
|
||||
"esnext"
|
||||
],
|
||||
"lib": ["dom", "dom.iterable", "esnext"],
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["./app/*"]
|
||||
}
|
||||
},
|
||||
"skipLibCheck": true
|
||||
},
|
||||
"include": [
|
||||
"app/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"dist"
|
||||
]
|
||||
"include": ["app/**/*"],
|
||||
"exclude": ["dist"]
|
||||
}
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@@ -5384,22 +5384,22 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "16.9.41",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.41.tgz",
|
||||
"integrity": "sha512-6cFei7F7L4wwuM+IND/Q2cV1koQUvJ8iSV+Gwn0c3kvABZ691g7sp3hfEQHOUBJtccl1gPi+EyNjMIl9nGA0ug==",
|
||||
"version": "16.14.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.2.tgz",
|
||||
"integrity": "sha512-BzzcAlyDxXl2nANlabtT4thtvbbnhee8hMmH/CcJrISDBVcJS1iOsP1f0OAgSdGE0MsY9tqcrb9YoZcOFv9dbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
"csstype": "^2.2.0"
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"version": "16.9.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.8.tgz",
|
||||
"integrity": "sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==",
|
||||
"version": "16.9.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-16.9.10.tgz",
|
||||
"integrity": "sha512-ItatOrnXDMAYpv6G8UCk2VhbYVTjZT9aorLtA/OzDN9XJ2GKcfam68jutoAcILdRjsRUO8qb7AmyObF77Q8QFw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
"@types/react": "^16"
|
||||
}
|
||||
},
|
||||
"@types/sinonjs__fake-timers": {
|
||||
@@ -9448,9 +9448,9 @@
|
||||
}
|
||||
},
|
||||
"csstype": {
|
||||
"version": "2.6.11",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.11.tgz",
|
||||
"integrity": "sha512-l8YyEC9NBkSm783PFTvh0FmJy7s5pFKrDp49ZL7zBGX3fWkO+N4EEyan1qqp8cwPLDcD0OSdyY6hAMoxp34JFw==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.5.tgz",
|
||||
"integrity": "sha512-uVDi8LpBUKQj6sdxNaTetL6FpeCqTjOvAQuQUa/qAqq8oOd4ivkbhgnqayl0dnPal8Tb/yB1tF+gOvCBiicaiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"cubic-hermite": {
|
||||
@@ -25447,9 +25447,9 @@
|
||||
}
|
||||
},
|
||||
"typescript": {
|
||||
"version": "3.9.6",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.6.tgz",
|
||||
"integrity": "sha512-Pspx3oKAPJtjNwE92YS05HQoY7z2SFyOpHo9MqJor3BXAGNaPUs83CuVp9VISFkSjyRfiTpmKuAYGJB7S7hOxw==",
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.2.tgz",
|
||||
"integrity": "sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
|
||||
@@ -95,8 +95,8 @@
|
||||
"@types/hoist-non-react-statics": "^3.3.1",
|
||||
"@types/lodash": "^4.14.157",
|
||||
"@types/prop-types": "^15.7.3",
|
||||
"@types/react": "^16.9.41",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react": "^16.14.2",
|
||||
"@types/react-dom": "^16.9.10",
|
||||
"@types/sql-formatter": "^2.3.0",
|
||||
"@typescript-eslint/eslint-plugin": "^2.10.0",
|
||||
"@typescript-eslint/parser": "^2.10.0",
|
||||
@@ -144,7 +144,7 @@
|
||||
"request": "^2.88.0",
|
||||
"request-cookies": "^1.1.0",
|
||||
"style-loader": "^2.0.0",
|
||||
"typescript": "^3.9.6",
|
||||
"typescript": "^4.1.2",
|
||||
"url-loader": "^1.1.2",
|
||||
"webpack": "^4.44.2",
|
||||
"webpack-build-notifier": "^0.1.30",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"],
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"],
|
||||
"plugins": [
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
[
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["dist", "lib"]
|
||||
}
|
||||
2149
viz-lib/package-lock.json
generated
2149
viz-lib/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -5,10 +5,13 @@
|
||||
"main": "dist/redash-visualizations.js",
|
||||
"scripts": {
|
||||
"clean": "rm -rf lib dist",
|
||||
"build:babel": "babel src --out-dir lib --source-maps --ignore 'src/**/*.test.js' --copy-files --no-copy-ignored",
|
||||
"type-check": "tsc --noEmit",
|
||||
"type-gen": "tsc --emitDeclarationOnly",
|
||||
"build:babel:base": "babel src --out-dir lib --source-maps --ignore 'src/**/*.test.js' --copy-files --no-copy-ignored --extensions .ts,.tsx,.js,.jsx",
|
||||
"build:babel": "npm run type-gen && npm run build:babel:base",
|
||||
"build:webpack": "webpack",
|
||||
"build": " NODE_ENV=production npm-run-all clean build:babel build:webpack",
|
||||
"watch:babel": "babel src --watch --out-dir lib --source-maps --ignore 'src/**/*.test.js' --copy-files --no-copy-ignored",
|
||||
"watch:babel": "npm run build:babel:base -- --watch",
|
||||
"watch:webpack": "webpack --watch",
|
||||
"watch": "npm-run-all --parallel watch:*",
|
||||
"version": "npm run build",
|
||||
@@ -34,6 +37,20 @@
|
||||
"@babel/plugin-proposal-class-properties": "^7.8.3",
|
||||
"@babel/preset-env": "^7.9.0",
|
||||
"@babel/preset-react": "^7.9.4",
|
||||
"@babel/preset-typescript": "^7.12.7",
|
||||
"@types/chroma-js": "^2.1.2",
|
||||
"@types/d3": "^6.2.0",
|
||||
"@types/d3-cloud": "^1.2.3",
|
||||
"@types/debug": "^4.1.5",
|
||||
"@types/dompurify": "^2.0.4",
|
||||
"@types/enzyme": "^3.10.8",
|
||||
"@types/jest": "^26.0.18",
|
||||
"@types/leaflet": "^1.5.19",
|
||||
"@types/numeral": "0.0.28",
|
||||
"@types/plotly.js": "^1.54.4",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/tinycolor2": "^1.4.2",
|
||||
"babel-loader": "^8.1.0",
|
||||
"babel-plugin-istanbul": "^6.0.0",
|
||||
"babel-plugin-module-resolver": "^4.0.0",
|
||||
@@ -50,6 +67,8 @@
|
||||
"prettier": "^1.19.1",
|
||||
"prop-types": "^15.7.2",
|
||||
"style-loader": "^1.1.4",
|
||||
"ts-migrate": "^0.1.10",
|
||||
"typescript": "^4.1.2",
|
||||
"webpack": "^4.42.1",
|
||||
"webpack-cli": "^3.3.11"
|
||||
},
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isNil, isArray, chunk, map, filter, toPairs } from "lodash";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import tinycolor from "tinycolor2";
|
||||
import TextInput from "antd/lib/input";
|
||||
import Typography from "antd/lib/typography";
|
||||
@@ -8,7 +7,7 @@ import Swatch from "./Swatch";
|
||||
|
||||
import "./input.less";
|
||||
|
||||
function preparePresets(presetColors, presetColumns) {
|
||||
function preparePresets(presetColors: any, presetColumns: any) {
|
||||
presetColors = isArray(presetColors) ? map(presetColors, v => [null, v]) : toPairs(presetColors);
|
||||
presetColors = map(presetColors, ([title, value]) => {
|
||||
if (isNil(value)) {
|
||||
@@ -23,7 +22,7 @@ function preparePresets(presetColors, presetColumns) {
|
||||
return chunk(filter(presetColors), presetColumns);
|
||||
}
|
||||
|
||||
function validateColor(value, callback, prefix = "#") {
|
||||
function validateColor(value: any, callback: any, prefix = "#") {
|
||||
if (isNil(value)) {
|
||||
callback(null);
|
||||
}
|
||||
@@ -33,13 +32,25 @@ function validateColor(value, callback, prefix = "#") {
|
||||
}
|
||||
}
|
||||
|
||||
export default function Input({ color, presetColors, presetColumns, onChange, onPressEnter }) {
|
||||
type OwnProps = {
|
||||
color?: string;
|
||||
presetColors?: string[] | {
|
||||
[key: string]: string;
|
||||
};
|
||||
presetColumns?: number;
|
||||
onChange?: (...args: any[]) => any;
|
||||
onPressEnter?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Input.defaultProps;
|
||||
|
||||
export default function Input({ color, presetColors, presetColumns, onChange, onPressEnter }: Props) {
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [isInputFocused, setIsInputFocused] = useState(false);
|
||||
|
||||
const presets = preparePresets(presetColors, presetColumns);
|
||||
|
||||
function handleInputChange(value) {
|
||||
function handleInputChange(value: any) {
|
||||
setInputValue(value);
|
||||
validateColor(value, onChange);
|
||||
}
|
||||
@@ -55,6 +66,7 @@ export default function Input({ color, presetColors, presetColumns, onChange, on
|
||||
{map(presets, (group, index) => (
|
||||
<div className="color-picker-input-swatches" key={`preset-row-${index}`}>
|
||||
{map(group, ([title, value]) => (
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
<Swatch key={value} color={value} title={title} size={30} onClick={() => validateColor(value, onChange)} />
|
||||
))}
|
||||
</div>
|
||||
@@ -74,17 +86,6 @@ export default function Input({ color, presetColors, presetColumns, onChange, on
|
||||
);
|
||||
}
|
||||
|
||||
Input.propTypes = {
|
||||
color: PropTypes.string,
|
||||
presetColors: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.string), // array of colors (no tooltips)
|
||||
PropTypes.objectOf(PropTypes.string), // color name => color value
|
||||
]),
|
||||
presetColumns: PropTypes.number,
|
||||
onChange: PropTypes.func,
|
||||
onPressEnter: PropTypes.func,
|
||||
};
|
||||
|
||||
Input.defaultProps = {
|
||||
color: "#FFFFFF",
|
||||
presetColors: null,
|
||||
@@ -1,11 +1,21 @@
|
||||
import React, { useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
|
||||
import { validateColor, getColorName } from "./utils";
|
||||
import "./label.less";
|
||||
|
||||
export default function Label({ className, color, presetColors, ...props }) {
|
||||
type OwnProps = {
|
||||
className?: string;
|
||||
color?: string;
|
||||
presetColors?: string[] | {
|
||||
[key: string]: string;
|
||||
};
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Label.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
export default function Label({ className, color, presetColors, ...props }: Props) {
|
||||
const name = useMemo(() => getColorName(validateColor(color), presetColors), [color, presetColors]);
|
||||
|
||||
return (
|
||||
@@ -15,15 +25,6 @@ export default function Label({ className, color, presetColors, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
Label.propTypes = {
|
||||
className: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
presetColors: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.string), // array of colors (no tooltips)
|
||||
PropTypes.objectOf(PropTypes.string), // color name => color value
|
||||
]),
|
||||
};
|
||||
|
||||
Label.defaultProps = {
|
||||
className: null,
|
||||
color: "#FFFFFF",
|
||||
@@ -1,15 +1,26 @@
|
||||
import { isString } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
|
||||
import "./swatch.less";
|
||||
|
||||
export default function Swatch({ className, color, title, size, style, ...props }) {
|
||||
type OwnProps = {
|
||||
className?: string;
|
||||
style?: any;
|
||||
title?: string;
|
||||
color?: string;
|
||||
size?: number;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Swatch.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
export default function Swatch({ className, color, title, size, style, ...props }: Props) {
|
||||
const result = (
|
||||
<span
|
||||
className={cx("color-swatch", className)}
|
||||
// @ts-expect-error ts-migrate(2698) FIXME: Spread types may only be created from object types... Remove this comment to see the full error message
|
||||
style={{ backgroundColor: color, width: size, ...style }}
|
||||
{...props}
|
||||
/>
|
||||
@@ -25,14 +36,6 @@ export default function Swatch({ className, color, title, size, style, ...props
|
||||
return result;
|
||||
}
|
||||
|
||||
Swatch.propTypes = {
|
||||
className: PropTypes.string,
|
||||
style: PropTypes.object,
|
||||
title: PropTypes.string,
|
||||
color: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
};
|
||||
|
||||
Swatch.defaultProps = {
|
||||
className: null,
|
||||
style: null,
|
||||
@@ -1,6 +1,5 @@
|
||||
import { toString } from "lodash";
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import Popover from "antd/lib/popover";
|
||||
import Card from "antd/lib/card";
|
||||
@@ -17,18 +16,24 @@ import { validateColor } from "./utils";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
export default function ColorPicker({
|
||||
color,
|
||||
placement,
|
||||
presetColors,
|
||||
presetColumns,
|
||||
interactive,
|
||||
children,
|
||||
onChange,
|
||||
triggerProps,
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
}) {
|
||||
type OwnProps = {
|
||||
color?: string;
|
||||
placement?: "top" | "left" | "right" | "bottom" | "topLeft" | "topRight" | "bottomLeft" | "bottomRight" | "leftTop" | "leftBottom" | "rightTop" | "rightBottom";
|
||||
presetColors?: string[] | {
|
||||
[key: string]: string;
|
||||
};
|
||||
presetColumns?: number;
|
||||
interactive?: boolean;
|
||||
triggerProps?: any;
|
||||
children?: React.ReactNode;
|
||||
addonBefore?: React.ReactNode;
|
||||
addonAfter?: React.ReactNode;
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ColorPicker.defaultProps;
|
||||
|
||||
export default function ColorPicker({ color, placement, presetColors, presetColumns, interactive, children, onChange, triggerProps, addonBefore, addonAfter, }: Props) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const validatedColor = useMemo(() => validateColor(color), [color]);
|
||||
const [currentColor, setCurrentColor] = useState("");
|
||||
@@ -36,6 +41,7 @@ export default function ColorPicker({
|
||||
function handleApply() {
|
||||
setVisible(false);
|
||||
if (!interactive) {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
onChange(currentColor);
|
||||
}
|
||||
}
|
||||
@@ -58,15 +64,17 @@ export default function ColorPicker({
|
||||
);
|
||||
}
|
||||
|
||||
function handleInputChange(newColor) {
|
||||
function handleInputChange(newColor: any) {
|
||||
setCurrentColor(newColor);
|
||||
if (interactive) {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
onChange(newColor);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string | null' is not assignable... Remove this comment to see the full error message
|
||||
setCurrentColor(validatedColor);
|
||||
}
|
||||
}, [validatedColor, visible]);
|
||||
@@ -77,6 +85,7 @@ export default function ColorPicker({
|
||||
<Popover
|
||||
arrowPointAtCenter
|
||||
overlayClassName={`color-picker ${interactive ? "color-picker-interactive" : "color-picker-with-actions"}`}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ "--color-picker-selected-color": string; }... Remove this comment to see the full error message
|
||||
overlayStyle={{ "--color-picker-selected-color": currentColor }}
|
||||
content={
|
||||
<Card
|
||||
@@ -86,14 +95,18 @@ export default function ColorPicker({
|
||||
title={toString(currentColor).toUpperCase()}
|
||||
headStyle={{
|
||||
backgroundColor: currentColor,
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string | null | undefined' is not assignable... Remove this comment to see the full error message
|
||||
color: chooseTextColorForBackground(currentColor),
|
||||
}}
|
||||
actions={actions}>
|
||||
<ColorInput
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
color={currentColor}
|
||||
presetColors={presetColors}
|
||||
presetColumns={presetColumns}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(newColor: any) => void' is not assignable t... Remove this comment to see the full error message
|
||||
onChange={handleInputChange}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '() => void' is not assignable to type 'never... Remove this comment to see the full error message
|
||||
onPressEnter={handleApply}
|
||||
/>
|
||||
</Card>
|
||||
@@ -107,6 +120,7 @@ export default function ColorPicker({
|
||||
color={validatedColor}
|
||||
size={30}
|
||||
{...triggerProps}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'className' does not exist on type 'never... Remove this comment to see the full error message
|
||||
className={cx("color-picker-trigger", triggerProps.className)}
|
||||
/>
|
||||
)}
|
||||
@@ -116,35 +130,6 @@ export default function ColorPicker({
|
||||
);
|
||||
}
|
||||
|
||||
ColorPicker.propTypes = {
|
||||
color: PropTypes.string,
|
||||
placement: PropTypes.oneOf([
|
||||
"top",
|
||||
"left",
|
||||
"right",
|
||||
"bottom",
|
||||
"topLeft",
|
||||
"topRight",
|
||||
"bottomLeft",
|
||||
"bottomRight",
|
||||
"leftTop",
|
||||
"leftBottom",
|
||||
"rightTop",
|
||||
"rightBottom",
|
||||
]),
|
||||
presetColors: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.string), // array of colors (no tooltips)
|
||||
PropTypes.objectOf(PropTypes.string), // color name => color value
|
||||
]),
|
||||
presetColumns: PropTypes.number,
|
||||
interactive: PropTypes.bool,
|
||||
triggerProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
children: PropTypes.node,
|
||||
addonBefore: PropTypes.node,
|
||||
addonAfter: PropTypes.node,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
ColorPicker.defaultProps = {
|
||||
color: "#FFFFFF",
|
||||
placement: "top",
|
||||
@@ -1,12 +1,12 @@
|
||||
import { isArray, findKey } from "lodash";
|
||||
import tinycolor from "tinycolor2";
|
||||
|
||||
export function validateColor(value, fallback = null) {
|
||||
export function validateColor(value: any, fallback = null) {
|
||||
value = tinycolor(value);
|
||||
return value.isValid() ? "#" + value.toHex().toUpperCase() : fallback;
|
||||
}
|
||||
|
||||
export function getColorName(color, presetColors) {
|
||||
export function getColorName(color: any, presetColors: any) {
|
||||
if (isArray(presetColors)) {
|
||||
return color;
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import { isFunction } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import debug from "debug";
|
||||
import Alert from "antd/lib/alert";
|
||||
|
||||
const logger = debug("redash:errors");
|
||||
|
||||
export const ErrorBoundaryContext = React.createContext({
|
||||
handleError: error => {
|
||||
handleError: (error: any) => {
|
||||
// Allow calling chain to roll up, and then throw the error in global context
|
||||
setTimeout(() => {
|
||||
throw error;
|
||||
@@ -16,23 +15,29 @@ export const ErrorBoundaryContext = React.createContext({
|
||||
reset: () => {},
|
||||
});
|
||||
|
||||
export function ErrorMessage({ children }) {
|
||||
type OwnErrorMessageProps = {
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type ErrorMessageProps = OwnErrorMessageProps & typeof ErrorMessage.defaultProps;
|
||||
|
||||
export function ErrorMessage({ children }: ErrorMessageProps) {
|
||||
return <Alert message={children} type="error" showIcon />;
|
||||
}
|
||||
|
||||
ErrorMessage.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
ErrorMessage.defaultProps = {
|
||||
children: "Something went wrong.",
|
||||
};
|
||||
|
||||
export default class ErrorBoundary extends React.Component {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
renderError: PropTypes.func, // error => ReactNode
|
||||
};
|
||||
type OwnErrorBoundaryProps = {
|
||||
renderError?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type ErrorBoundaryState = any;
|
||||
|
||||
type ErrorBoundaryProps = OwnErrorBoundaryProps & typeof ErrorBoundary.defaultProps;
|
||||
|
||||
export default class ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {
|
||||
|
||||
static defaultProps = {
|
||||
children: null,
|
||||
@@ -41,10 +46,13 @@ export default class ErrorBoundary extends React.Component {
|
||||
|
||||
state = { error: null };
|
||||
|
||||
handleError = error => {
|
||||
handleError = (error: any) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'getDerivedStateFromError' does not exist... Remove this comment to see the full error message
|
||||
this.setState(this.constructor.getDerivedStateFromError(error));
|
||||
this.componentDidCatch(error, null);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleException' does not exist on type ... Remove this comment to see the full error message
|
||||
if (isFunction(window.handleException)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'handleException' does not exist on type ... Remove this comment to see the full error message
|
||||
window.handleException(error);
|
||||
}
|
||||
};
|
||||
@@ -53,11 +61,11 @@ export default class ErrorBoundary extends React.Component {
|
||||
this.setState({ error: null });
|
||||
};
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
static getDerivedStateFromError(error: any) {
|
||||
return { error };
|
||||
}
|
||||
|
||||
componentDidCatch(error, errorInfo) {
|
||||
componentDidCatch(error: any, errorInfo: any) {
|
||||
logger(error, errorInfo);
|
||||
}
|
||||
|
||||
@@ -67,6 +75,7 @@ export default class ErrorBoundary extends React.Component {
|
||||
|
||||
if (error) {
|
||||
if (isFunction(renderError)) {
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
return renderError(error);
|
||||
}
|
||||
return <ErrorMessage />;
|
||||
@@ -6,15 +6,18 @@ const HtmlContent = React.memo(function HtmlContent({ children, ...props }) {
|
||||
return (
|
||||
<div
|
||||
{...props}
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'ReactNode' is not assignable to ... Remove this comment to see the full error message
|
||||
dangerouslySetInnerHTML={{ __html: sanitize(children) }} // eslint-disable-line react/no-danger
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'propTypes' does not exist on type 'Named... Remove this comment to see the full error message
|
||||
HtmlContent.propTypes = {
|
||||
children: PropTypes.string,
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'defaultProps' does not exist on type 'Na... Remove this comment to see the full error message
|
||||
HtmlContent.defaultProps = {
|
||||
children: "",
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import { pickBy, startsWith } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
import Radio from "antd/lib/radio";
|
||||
import Tooltip from "antd/lib/tooltip";
|
||||
@@ -11,7 +10,14 @@ import AlignRightOutlinedIcon from "@ant-design/icons/AlignRightOutlined";
|
||||
|
||||
import "./index.less";
|
||||
|
||||
export default function TextAlignmentSelect({ className, ...props }) {
|
||||
type OwnProps = {
|
||||
className?: string;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof TextAlignmentSelect.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
export default function TextAlignmentSelect({ className, ...props }: Props) {
|
||||
return (
|
||||
// Antd RadioGroup does not use any custom attributes
|
||||
<div {...pickBy(props, (v, k) => startsWith(k, "data-"))}>
|
||||
@@ -36,10 +42,6 @@ export default function TextAlignmentSelect({ className, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
TextAlignmentSelect.propTypes = {
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
TextAlignmentSelect.defaultProps = {
|
||||
className: null,
|
||||
};
|
||||
@@ -3,11 +3,16 @@
|
||||
import { isFinite, isString, isArray, isObject, keys, map } from "lodash";
|
||||
import React, { useState } from "react";
|
||||
import cx from "classnames";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import "./json-view-interactive.less";
|
||||
|
||||
function JsonBlock({ value, children, openingBrace, closingBrace, withKeys }) {
|
||||
function JsonBlock({
|
||||
value,
|
||||
children,
|
||||
openingBrace,
|
||||
closingBrace,
|
||||
withKeys
|
||||
}: any) {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
const objectKeys = keys(value);
|
||||
@@ -56,7 +61,10 @@ function JsonBlock({ value, children, openingBrace, closingBrace, withKeys }) {
|
||||
);
|
||||
}
|
||||
|
||||
function JsonValue({ value, children }) {
|
||||
function JsonValue({
|
||||
value,
|
||||
children
|
||||
}: any) {
|
||||
if (value === null || value === false || value === true || isFinite(value)) {
|
||||
return (
|
||||
<span className="jvi-value jvi-primitive">
|
||||
@@ -92,7 +100,13 @@ function JsonValue({ value, children }) {
|
||||
return null;
|
||||
}
|
||||
|
||||
export default function JsonViewInteractive({ value }) {
|
||||
type OwnJsonViewInteractiveProps = {
|
||||
value?: any;
|
||||
};
|
||||
|
||||
type JsonViewInteractiveProps = OwnJsonViewInteractiveProps & typeof JsonViewInteractive.defaultProps;
|
||||
|
||||
export default function JsonViewInteractive({ value }: JsonViewInteractiveProps) {
|
||||
return (
|
||||
<span className="jvi-item jvi-root">
|
||||
<JsonValue value={value} />
|
||||
@@ -100,10 +114,6 @@ export default function JsonViewInteractive({ value }) {
|
||||
);
|
||||
}
|
||||
|
||||
JsonViewInteractive.propTypes = {
|
||||
value: PropTypes.any, // eslint-disable-line react/forbid-prop-types
|
||||
};
|
||||
|
||||
JsonViewInteractive.defaultProps = {
|
||||
// `null` will be rendered as "null" because it is a valid JSON value, so use `undefined` for no value
|
||||
value: undefined,
|
||||
@@ -1,20 +1,36 @@
|
||||
import { isFunction, wrap } from "lodash";
|
||||
import React, { useRef, useState } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
// @ts-expect-error ts-migrate(2724) FIXME: Module '"../../../node_modules/react-sortable-hoc/... Remove this comment to see the full error message
|
||||
import { sortableContainer, sortableElement, sortableHandle } from "react-sortable-hoc";
|
||||
|
||||
import "./style.less";
|
||||
|
||||
export const DragHandle = sortableHandle(({ className, ...restProps }) => (
|
||||
export const DragHandle = sortableHandle(({
|
||||
className,
|
||||
...restProps
|
||||
}: any) => (
|
||||
<div className={cx("drag-handle", className)} {...restProps} />
|
||||
));
|
||||
|
||||
export const SortableContainerWrapper = sortableContainer(({ children }) => children);
|
||||
export const SortableContainerWrapper = sortableContainer(({
|
||||
children
|
||||
}: any) => children);
|
||||
|
||||
export const SortableElement = sortableElement(({ children }) => children);
|
||||
export const SortableElement = sortableElement(({
|
||||
children
|
||||
}: any) => children);
|
||||
|
||||
export function SortableContainer({ disabled, containerComponent, containerProps, children, ...wrapperProps }) {
|
||||
type OwnProps = {
|
||||
disabled?: boolean;
|
||||
containerComponent?: React.ReactElement;
|
||||
containerProps?: any;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof SortableContainer.defaultProps;
|
||||
|
||||
export function SortableContainer({ disabled, containerComponent, containerProps, children, ...wrapperProps }: Props) {
|
||||
const containerRef = useRef();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
||||
@@ -25,22 +41,26 @@ export function SortableContainer({ disabled, containerComponent, containerProps
|
||||
// Disabled state:
|
||||
// - forbid drag'n'drop (and therefore no need to hook events
|
||||
// - don't override anything on container element
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'shouldCancelStart' does not exist on typ... Remove this comment to see the full error message
|
||||
wrapperProps.shouldCancelStart = () => true;
|
||||
} else {
|
||||
// Enabled state:
|
||||
|
||||
// - use container element as a default helper element
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'helperContainer' does not exist on type ... Remove this comment to see the full error message
|
||||
wrapperProps.helperContainer = wrap(wrapperProps.helperContainer, helperContainer =>
|
||||
isFunction(helperContainer) ? helperContainer(containerRef.current) : containerRef.current
|
||||
);
|
||||
|
||||
// - hook drag start/end events
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'updateBeforeSortStart' does not exist on... Remove this comment to see the full error message
|
||||
wrapperProps.updateBeforeSortStart = wrap(wrapperProps.updateBeforeSortStart, (updateBeforeSortStart, ...args) => {
|
||||
setIsDragging(true);
|
||||
if (isFunction(updateBeforeSortStart)) {
|
||||
updateBeforeSortStart(...args);
|
||||
}
|
||||
});
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'onSortEnd' does not exist on type '{}'.
|
||||
wrapperProps.onSortEnd = wrap(wrapperProps.onSortEnd, (onSortEnd, ...args) => {
|
||||
setIsDragging(false);
|
||||
if (isFunction(onSortEnd)) {
|
||||
@@ -60,18 +80,12 @@ export function SortableContainer({ disabled, containerComponent, containerProps
|
||||
const ContainerComponent = containerComponent;
|
||||
return (
|
||||
<SortableContainerWrapper {...wrapperProps}>
|
||||
{/* @ts-expect-error ts-migrate(2604) FIXME: JSX element type 'ContainerComponent' does not hav... Remove this comment to see the full error message */}
|
||||
<ContainerComponent {...containerProps}>{children}</ContainerComponent>
|
||||
</SortableContainerWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
SortableContainer.propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
containerComponent: PropTypes.elementType,
|
||||
containerProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
SortableContainer.defaultProps = {
|
||||
disabled: false,
|
||||
containerComponent: "div",
|
||||
@@ -1,12 +1,18 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Popover from "antd/lib/popover";
|
||||
import QuestionCircleFilledIcon from "@ant-design/icons/QuestionCircleFilled";
|
||||
import { visualizationsSettings } from "@/visualizations/visualizationsSettings";
|
||||
|
||||
import "./context-help.less";
|
||||
|
||||
export default function ContextHelp({ icon, children, ...props }) {
|
||||
type OwnContextHelpProps = {
|
||||
icon?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type ContextHelpProps = OwnContextHelpProps & typeof ContextHelp.defaultProps;
|
||||
|
||||
export default function ContextHelp({ icon, children, ...props }: ContextHelpProps) {
|
||||
return (
|
||||
<Popover {...props} content={children}>
|
||||
{icon || ContextHelp.defaultIcon}
|
||||
@@ -14,11 +20,6 @@ export default function ContextHelp({ icon, children, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
ContextHelp.propTypes = {
|
||||
icon: PropTypes.node,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
ContextHelp.defaultProps = {
|
||||
icon: null,
|
||||
children: null,
|
||||
@@ -30,6 +31,7 @@ function NumberFormatSpecs() {
|
||||
const { HelpTriggerComponent } = visualizationsSettings;
|
||||
return (
|
||||
<HelpTriggerComponent
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element; type: string; title: st... Remove this comment to see the full error message
|
||||
type="NUMBER_FORMAT_SPECS"
|
||||
title="Formatting Numbers"
|
||||
href="https://redash.io/help/user-guide/visualizations/formatting-numbers"
|
||||
@@ -1,10 +1,17 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import cx from "classnames";
|
||||
|
||||
import "./Section.less";
|
||||
|
||||
function SectionTitle({ className, children, ...props }) {
|
||||
type OwnSectionTitleProps = {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type SectionTitleProps = OwnSectionTitleProps & typeof SectionTitle.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
function SectionTitle({ className, children, ...props }: SectionTitleProps) {
|
||||
if (!children) {
|
||||
return null;
|
||||
}
|
||||
@@ -16,17 +23,20 @@ function SectionTitle({ className, children, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
SectionTitle.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
SectionTitle.defaultProps = {
|
||||
className: null,
|
||||
children: null,
|
||||
};
|
||||
|
||||
export default function Section({ className, children, ...props }) {
|
||||
type OwnSectionProps = {
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type SectionProps = OwnSectionProps & typeof Section.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
export default function Section({ className, children, ...props }: SectionProps) {
|
||||
return (
|
||||
<div className={cx("visualization-editor-section", className)} {...props}>
|
||||
{children}
|
||||
@@ -34,11 +44,6 @@ export default function Section({ className, children, ...props }) {
|
||||
);
|
||||
}
|
||||
|
||||
Section.propTypes = {
|
||||
className: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
Section.defaultProps = {
|
||||
className: null,
|
||||
children: null,
|
||||
@@ -1,11 +1,19 @@
|
||||
import React, { useMemo } from "react";
|
||||
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 }) {
|
||||
type OwnProps = {
|
||||
id?: string;
|
||||
disabled?: boolean;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof Switch.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2700) FIXME: Rest types may only be created from object types.
|
||||
export default function Switch({ id, children, disabled, ...props }: Props) {
|
||||
const fallbackId = useMemo(
|
||||
() =>
|
||||
`visualization-editor-control-${Math.random()
|
||||
@@ -29,12 +37,6 @@ export default function Switch({ id, children, disabled, ...props }) {
|
||||
return <AntSwitch {...props} />;
|
||||
}
|
||||
|
||||
Switch.propTypes = {
|
||||
id: PropTypes.string,
|
||||
disabled: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
Switch.defaultProps = {
|
||||
id: null,
|
||||
disabled: false,
|
||||
@@ -5,7 +5,10 @@ import withControlLabel from "./withControlLabel";
|
||||
|
||||
import "./TextArea.less";
|
||||
|
||||
function TextArea({ className, ...otherProps }) {
|
||||
function TextArea({
|
||||
className,
|
||||
...otherProps
|
||||
}: any) {
|
||||
return <AntInput.TextArea className={cx("visualization-editor-text-area", className)} {...otherProps} />;
|
||||
}
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
import { isFunction, map, filter, extend, merge } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import Tabs from "antd/lib/tabs";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
export const UpdateOptionsStrategy = {
|
||||
replace: (existingOptions, newOptions) => merge({}, newOptions),
|
||||
shallowMerge: (existingOptions, newOptions) => extend({}, existingOptions, newOptions),
|
||||
deepMerge: (existingOptions, newOptions) => merge({}, existingOptions, newOptions),
|
||||
};
|
||||
|
||||
export function TabbedEditor({ tabs, options, data, onOptionsChange, ...restProps }) {
|
||||
const optionsChanged = (newOptions, updateStrategy = UpdateOptionsStrategy.deepMerge) => {
|
||||
onOptionsChange(updateStrategy(options, newOptions));
|
||||
};
|
||||
|
||||
tabs = filter(tabs, tab => (isFunction(tab.isAvailable) ? tab.isAvailable(options, data) : true));
|
||||
|
||||
return (
|
||||
<Tabs animated={false} tabBarGutter={20}>
|
||||
{map(tabs, ({ key, title, component: Component }) => (
|
||||
<Tabs.TabPane
|
||||
key={key}
|
||||
tab={<span data-test={`VisualizationEditor.Tabs.${key}`}>{isFunction(title) ? title(options) : title}</span>}>
|
||||
<Component options={options} data={data} onOptionsChange={optionsChanged} {...restProps} />
|
||||
</Tabs.TabPane>
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
TabbedEditor.propTypes = {
|
||||
...EditorPropTypes,
|
||||
tabs: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
key: PropTypes.string.isRequired,
|
||||
title: PropTypes.oneOfType([
|
||||
PropTypes.string,
|
||||
PropTypes.func, // (options) => string
|
||||
]).isRequired,
|
||||
isAvailable: PropTypes.func, // (options) => boolean
|
||||
component: PropTypes.func.isRequired,
|
||||
})
|
||||
),
|
||||
};
|
||||
|
||||
TabbedEditor.defaultProps = {
|
||||
tabs: [],
|
||||
};
|
||||
|
||||
export default function createTabbedEditor(tabs) {
|
||||
return function TabbedEditorWrapper(props) {
|
||||
return <TabbedEditor {...props} tabs={tabs} />;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import { isFunction, map, filter, extend, merge } from "lodash";
|
||||
import React from "react";
|
||||
import Tabs from "antd/lib/tabs";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
export const UpdateOptionsStrategy = {
|
||||
replace: (existingOptions: any, newOptions: any) => merge({}, newOptions),
|
||||
shallowMerge: (existingOptions: any, newOptions: any) => extend({}, existingOptions, newOptions),
|
||||
deepMerge: (existingOptions: any, newOptions: any) => merge({}, existingOptions, newOptions),
|
||||
};
|
||||
|
||||
/*
|
||||
(ts-migrate) TODO: Migrate the remaining prop types
|
||||
...EditorPropTypes
|
||||
*/
|
||||
type OwnProps = {
|
||||
tabs?: {
|
||||
key: string;
|
||||
title: string | ((...args: any[]) => any);
|
||||
isAvailable?: (...args: any[]) => any;
|
||||
component: (...args: any[]) => any;
|
||||
}[];
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof TabbedEditor.defaultProps;
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'options' does not exist on type 'Props'.
|
||||
export function TabbedEditor({ tabs, options, data, onOptionsChange, ...restProps }: Props) {
|
||||
const optionsChanged = (newOptions: any, updateStrategy = UpdateOptionsStrategy.deepMerge) => {
|
||||
onOptionsChange(updateStrategy(options, newOptions));
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(number | ((() => string) & (() => string)) ... Remove this comment to see the full error message
|
||||
tabs = filter(tabs, tab => (isFunction(tab.isAvailable) ? tab.isAvailable(options, data) : true));
|
||||
|
||||
return (
|
||||
<Tabs animated={false} tabBarGutter={20}>
|
||||
{map(tabs, ({ key, title, component: Component }) => (
|
||||
<Tabs.TabPane
|
||||
key={key}
|
||||
tab={<span data-test={`VisualizationEditor.Tabs.${key}`}>{isFunction(title) ? title(options) : title}</span>}>
|
||||
<Component options={options} data={data} onOptionsChange={optionsChanged} {...restProps} />
|
||||
</Tabs.TabPane>
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
}
|
||||
|
||||
TabbedEditor.defaultProps = {
|
||||
tabs: [],
|
||||
};
|
||||
|
||||
export default function createTabbedEditor(tabs: any) {
|
||||
return function TabbedEditorWrapper(props: any) {
|
||||
return <TabbedEditor {...props} tabs={tabs} />;
|
||||
};
|
||||
}
|
||||
@@ -1,13 +1,22 @@
|
||||
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";
|
||||
import Typography from "antd/lib/typography";
|
||||
|
||||
import "./control-label.less";
|
||||
|
||||
export function ControlLabel({ layout, label, labelProps, disabled, children }) {
|
||||
type OwnProps = {
|
||||
layout?: "vertical" | "horizontal";
|
||||
label?: React.ReactNode;
|
||||
labelProps?: any;
|
||||
disabled?: boolean;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ControlLabel.defaultProps;
|
||||
|
||||
export function ControlLabel({ layout, label, labelProps, disabled, children }: Props) {
|
||||
if (layout === "vertical" && label) {
|
||||
return (
|
||||
<div className="visualization-editor-control-label visualization-editor-control-label-vertical">
|
||||
@@ -23,6 +32,7 @@ export function ControlLabel({ layout, label, labelProps, disabled, children })
|
||||
return (
|
||||
<Grid.Row
|
||||
className="visualization-editor-control-label visualization-editor-control-label-horizontal"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element[]; className: string; ty... Remove this comment to see the full error message
|
||||
type="flex"
|
||||
align="middle"
|
||||
gutter={15}>
|
||||
@@ -39,14 +49,6 @@ export function ControlLabel({ layout, label, labelProps, disabled, children })
|
||||
return children;
|
||||
}
|
||||
|
||||
ControlLabel.propTypes = {
|
||||
layout: PropTypes.oneOf(["vertical", "horizontal"]),
|
||||
label: PropTypes.node,
|
||||
labelProps: PropTypes.object, // eslint-disable-line react/forbid-prop-types
|
||||
disabled: PropTypes.bool,
|
||||
children: PropTypes.node,
|
||||
};
|
||||
|
||||
ControlLabel.defaultProps = {
|
||||
layout: "vertical",
|
||||
label: null,
|
||||
@@ -54,9 +56,17 @@ ControlLabel.defaultProps = {
|
||||
children: null,
|
||||
};
|
||||
|
||||
export default function withControlLabel(WrappedControl) {
|
||||
export default function withControlLabel(WrappedControl: any) {
|
||||
// eslint-disable-next-line react/prop-types
|
||||
function ControlWrapper({ className, id, layout, label, labelProps, disabled, ...props }) {
|
||||
function ControlWrapper({
|
||||
className,
|
||||
id,
|
||||
layout,
|
||||
label,
|
||||
labelProps,
|
||||
disabled,
|
||||
...props
|
||||
}: any) {
|
||||
const fallbackId = useMemo(
|
||||
() =>
|
||||
`visualization-editor-control-${Math.random()
|
||||
@@ -71,6 +81,7 @@ export default function withControlLabel(WrappedControl) {
|
||||
|
||||
return (
|
||||
<ControlLabel layout={layout} label={label} labelProps={labelProps} disabled={disabled}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<WrappedControl
|
||||
className={cx("visualization-editor-input", className)}
|
||||
id={labelProps.htmlFor}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { maxBy } from "lodash";
|
||||
import chroma from "chroma-js";
|
||||
|
||||
export default function chooseTextColorForBackground(backgroundColor, textColors = ["#ffffff", "#333333"]) {
|
||||
export default function chooseTextColorForBackground(backgroundColor: any, textColors = ["#ffffff", "#333333"]) {
|
||||
try {
|
||||
backgroundColor = chroma(backgroundColor);
|
||||
return maxBy(textColors, color => chroma.contrast(backgroundColor, color));
|
||||
@@ -1,10 +1,11 @@
|
||||
import { isEqual } from "lodash";
|
||||
import { useMemo, useRef } from "react";
|
||||
|
||||
export default function useMemoWithDeepCompare(create, inputs) {
|
||||
export default function useMemoWithDeepCompare(create: any, inputs: any) {
|
||||
const valueRef = useRef();
|
||||
const value = useMemo(create, inputs);
|
||||
if (!isEqual(value, valueRef.current)) {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'unknown' is not assignable to type 'undefine... Remove this comment to see the full error message
|
||||
valueRef.current = value;
|
||||
}
|
||||
return valueRef.current;
|
||||
@@ -1,39 +0,0 @@
|
||||
import { each, debounce } from "lodash";
|
||||
|
||||
export default function createReferenceCountingCache({ cleanupDelay = 2000 } = {}) {
|
||||
const items = {};
|
||||
|
||||
const cleanup = debounce(() => {
|
||||
each(items, (item, key) => {
|
||||
if (item.refCount <= 0) {
|
||||
delete items[key];
|
||||
}
|
||||
});
|
||||
}, cleanupDelay);
|
||||
|
||||
function get(key, getter) {
|
||||
if (!items[key]) {
|
||||
items[key] = {
|
||||
value: getter(),
|
||||
refCount: 0,
|
||||
};
|
||||
}
|
||||
const item = items[key];
|
||||
item.refCount += 1;
|
||||
return item.value;
|
||||
}
|
||||
|
||||
function release(key) {
|
||||
if (items[key]) {
|
||||
const item = items[key];
|
||||
if (item.refCount > 0) {
|
||||
item.refCount -= 1;
|
||||
if (item.refCount <= 0) {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { get, release };
|
||||
}
|
||||
46
viz-lib/src/lib/referenceCountingCache.ts
Normal file
46
viz-lib/src/lib/referenceCountingCache.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { each, debounce } from "lodash";
|
||||
|
||||
export default function createReferenceCountingCache({ cleanupDelay = 2000 } = {}) {
|
||||
const items = {};
|
||||
|
||||
const cleanup = debounce(() => {
|
||||
each(items, (item, key) => {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'refCount' does not exist on type 'never'... Remove this comment to see the full error message
|
||||
if (item.refCount <= 0) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
delete items[key];
|
||||
}
|
||||
});
|
||||
}, cleanupDelay);
|
||||
|
||||
function get(key: any, getter: any) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
if (!items[key]) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
items[key] = {
|
||||
value: getter(),
|
||||
refCount: 0,
|
||||
};
|
||||
}
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const item = items[key];
|
||||
item.refCount += 1;
|
||||
return item.value;
|
||||
}
|
||||
|
||||
function release(key: any) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
if (items[key]) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const item = items[key];
|
||||
if (item.refCount > 0) {
|
||||
item.refCount -= 1;
|
||||
if (item.refCount <= 0) {
|
||||
cleanup();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { get, release };
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import moment from "moment";
|
||||
import { visualizationsSettings } from "@/visualizations/visualizationsSettings";
|
||||
|
||||
function formatDateTime(value) {
|
||||
function formatDateTime(value: any) {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
@@ -14,7 +14,7 @@ function formatDateTime(value) {
|
||||
return parsed.format(visualizationsSettings.dateTimeFormat);
|
||||
}
|
||||
|
||||
function formatDate(value) {
|
||||
function formatDate(value: any) {
|
||||
if (!value) {
|
||||
return "";
|
||||
}
|
||||
@@ -27,7 +27,7 @@ function formatDate(value) {
|
||||
return parsed.format(visualizationsSettings.dateFormat);
|
||||
}
|
||||
|
||||
export function formatColumnValue(value, columnType = null) {
|
||||
export function formatColumnValue(value: any, columnType = null) {
|
||||
if (moment.isMoment(value)) {
|
||||
if (columnType === "date") {
|
||||
return formatDate(value);
|
||||
@@ -12,9 +12,9 @@ const urlPattern = /(^|[\s\n]|<br\/?>)((?:https?|ftp):\/\/[\-A-Z0-9+\u0026\u2019
|
||||
|
||||
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
|
||||
export function createTextFormatter(highlightLinks) {
|
||||
export function createTextFormatter(highlightLinks: any) {
|
||||
if (highlightLinks) {
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
if (isString(value)) {
|
||||
const Link = visualizationsSettings.LinkComponent;
|
||||
value = value.replace(urlPattern, (unused, prefix, href) => {
|
||||
@@ -29,10 +29,10 @@ export function createTextFormatter(highlightLinks) {
|
||||
return toString(value);
|
||||
};
|
||||
}
|
||||
return value => toString(value);
|
||||
return (value: any) => toString(value);
|
||||
}
|
||||
|
||||
function toMoment(value) {
|
||||
function toMoment(value: any) {
|
||||
if (moment.isMoment(value)) {
|
||||
return value;
|
||||
}
|
||||
@@ -43,21 +43,21 @@ function toMoment(value) {
|
||||
return moment(toString(value), [moment.ISO_8601, moment.RFC_2822]);
|
||||
}
|
||||
|
||||
export function createDateTimeFormatter(format) {
|
||||
export function createDateTimeFormatter(format: any) {
|
||||
if (isString(format) && format !== "") {
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
const wrapped = toMoment(value);
|
||||
return wrapped.isValid() ? wrapped.format(format) : toString(value);
|
||||
};
|
||||
}
|
||||
return value => toString(value);
|
||||
return (value: any) => toString(value);
|
||||
}
|
||||
|
||||
export function createBooleanFormatter(values) {
|
||||
export function createBooleanFormatter(values: any) {
|
||||
if (isArray(values)) {
|
||||
if (values.length >= 2) {
|
||||
// Both `true` and `false` specified
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
if (isNil(value)) {
|
||||
return "";
|
||||
}
|
||||
@@ -65,10 +65,10 @@ export function createBooleanFormatter(values) {
|
||||
};
|
||||
} else if (values.length === 1) {
|
||||
// Only `true`
|
||||
return value => (value ? values[0] : "");
|
||||
return (value: any) => value ? values[0] : "";
|
||||
}
|
||||
}
|
||||
return value => {
|
||||
return (value: any) => {
|
||||
if (isNil(value)) {
|
||||
return "";
|
||||
}
|
||||
@@ -76,15 +76,15 @@ export function createBooleanFormatter(values) {
|
||||
};
|
||||
}
|
||||
|
||||
export function createNumberFormatter(format) {
|
||||
export function createNumberFormatter(format: any) {
|
||||
if (isString(format) && format !== "") {
|
||||
const n = numeral(0); // cache `numeral` instance
|
||||
return value => (value === null || value === "" ? "" : n.set(value).format(format));
|
||||
return (value: any) => value === null || value === "" ? "" : n.set(value).format(format);
|
||||
}
|
||||
return value => toString(value);
|
||||
return (value: any) => toString(value);
|
||||
}
|
||||
|
||||
export function formatSimpleTemplate(str, data) {
|
||||
export function formatSimpleTemplate(str: any, data: any) {
|
||||
if (!isString(str)) {
|
||||
return "";
|
||||
}
|
||||
@@ -19,7 +19,7 @@ function checkItems() {
|
||||
}
|
||||
}
|
||||
|
||||
export default function observe(node, callback) {
|
||||
export default function observe(node: any, callback: any) {
|
||||
if (node && !items.has(node)) {
|
||||
const shouldTrigger = items.size === 0;
|
||||
items.set(node, { callback });
|
||||
@@ -1,16 +1,19 @@
|
||||
import React, { useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import registeredVisualizations from "@/visualizations/registeredVisualizations";
|
||||
|
||||
export default function Editor({ type, options: optionsProp, data, ...otherProps }) {
|
||||
/*
|
||||
(ts-migrate) TODO: Migrate the remaining prop types
|
||||
...EditorPropTypes
|
||||
*/
|
||||
type Props = {
|
||||
type: string;
|
||||
} & typeof EditorPropTypes;
|
||||
|
||||
export default function Editor({ type, options: optionsProp, data, ...otherProps }: Props) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const { Editor, getOptions } = registeredVisualizations[type];
|
||||
const options = useMemo(() => getOptions(optionsProp, data), [optionsProp, data]);
|
||||
|
||||
return <Editor options={options} data={data} {...otherProps} />;
|
||||
}
|
||||
|
||||
Editor.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
...EditorPropTypes,
|
||||
};
|
||||
@@ -1,22 +1,24 @@
|
||||
import { isEqual } from "lodash";
|
||||
import React, { useEffect, useRef } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import ErrorBoundary, { ErrorMessage } from "@/components/ErrorBoundary";
|
||||
import { RendererPropTypes } from "@/visualizations/prop-types";
|
||||
import registeredVisualizations from "@/visualizations/registeredVisualizations";
|
||||
|
||||
export default function Renderer({
|
||||
type,
|
||||
data,
|
||||
options: optionsProp,
|
||||
visualizationName,
|
||||
addonBefore,
|
||||
addonAfter,
|
||||
...otherProps
|
||||
}) {
|
||||
/*
|
||||
(ts-migrate) TODO: Migrate the remaining prop types
|
||||
...RendererPropTypes
|
||||
*/
|
||||
type Props = {
|
||||
type: string;
|
||||
addonBefore?: React.ReactNode;
|
||||
addonAfter?: React.ReactNode;
|
||||
} & typeof RendererPropTypes;
|
||||
|
||||
export default function Renderer({ type, data, options: optionsProp, visualizationName, addonBefore, addonAfter, ...otherProps }: Props) {
|
||||
const lastOptions = useRef();
|
||||
const errorHandlerRef = useRef();
|
||||
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const { Renderer, getOptions } = registeredVisualizations[type];
|
||||
|
||||
// Avoid unnecessary updates (which may be expensive or cause issues with
|
||||
@@ -31,6 +33,7 @@ export default function Renderer({
|
||||
|
||||
useEffect(() => {
|
||||
if (errorHandlerRef.current) {
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
errorHandlerRef.current.reset();
|
||||
}
|
||||
}, [optionsProp, data]);
|
||||
@@ -38,6 +41,7 @@ export default function Renderer({
|
||||
return (
|
||||
<div className="visualization-renderer">
|
||||
{addonBefore}
|
||||
{/* @ts-expect-error ts-migrate(2769) FIXME: No overload matches this call. */}
|
||||
<ErrorBoundary
|
||||
ref={errorHandlerRef}
|
||||
renderError={() => <ErrorMessage>Error while rendering visualization.</ErrorMessage>}>
|
||||
@@ -49,10 +53,3 @@ export default function Renderer({
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Renderer.propTypes = {
|
||||
type: PropTypes.string.isRequired,
|
||||
addonBefore: PropTypes.node,
|
||||
addonAfter: PropTypes.node,
|
||||
...RendererPropTypes,
|
||||
};
|
||||
@@ -2,34 +2,39 @@ import React from "react";
|
||||
import { Section, Input } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
export default function Editor({ options, onOptionsChange }) {
|
||||
const onXAxisLabelChanged = xAxisLabel => {
|
||||
export default function Editor({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const onXAxisLabelChanged = (xAxisLabel: any) => {
|
||||
const newOptions = { ...options, xAxisLabel };
|
||||
onOptionsChange(newOptions);
|
||||
};
|
||||
|
||||
const onYAxisLabelChanged = yAxisLabel => {
|
||||
const onYAxisLabelChanged = (yAxisLabel: any) => {
|
||||
const newOptions = { ...options, yAxisLabel };
|
||||
onOptionsChange(newOptions);
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label="X Axis Label"
|
||||
data-test="BoxPlot.XAxisLabel"
|
||||
value={options.xAxisLabel}
|
||||
onChange={event => onXAxisLabelChanged(event.target.value)}
|
||||
onChange={(event: any) => onXAxisLabelChanged(event.target.value)}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label="Y Axis Label"
|
||||
data-test="BoxPlot.YAxisLabel"
|
||||
value={options.yAxisLabel}
|
||||
onChange={event => onYAxisLabelChanged(event.target.value)}
|
||||
onChange={(event: any) => onYAxisLabelChanged(event.target.value)}
|
||||
/>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
@@ -6,8 +6,8 @@ import { RendererPropTypes } from "@/visualizations/prop-types";
|
||||
import box from "./d3box";
|
||||
import "./renderer.less";
|
||||
|
||||
function calcIqr(k) {
|
||||
return d => {
|
||||
function calcIqr(k: any) {
|
||||
return (d: any) => {
|
||||
const q1 = d.quartiles[0];
|
||||
const q3 = d.quartiles[2];
|
||||
const iqr = (q3 - q1) * k;
|
||||
@@ -29,7 +29,10 @@ function calcIqr(k) {
|
||||
};
|
||||
}
|
||||
|
||||
function render(container, data, { xAxisLabel, yAxisLabel }) {
|
||||
function render(container: any, data: any, {
|
||||
xAxisLabel,
|
||||
yAxisLabel
|
||||
}: any) {
|
||||
container = d3.select(container);
|
||||
|
||||
const containerBounds = container.node().getBoundingClientRect();
|
||||
@@ -48,11 +51,12 @@ function render(container, data, { xAxisLabel, yAxisLabel }) {
|
||||
|
||||
let min = Infinity;
|
||||
let max = -Infinity;
|
||||
const mydata = [];
|
||||
const mydata: any = [];
|
||||
let value = 0;
|
||||
let d = [];
|
||||
|
||||
const columns = map(data.columns, col => col.name);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'scale' does not exist on type 'typeof im... Remove this comment to see the full error message
|
||||
const xscale = d3.scale
|
||||
.ordinal()
|
||||
.domain(columns)
|
||||
@@ -76,6 +80,7 @@ function render(container, data, { xAxisLabel, yAxisLabel }) {
|
||||
});
|
||||
});
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'scale' does not exist on type 'typeof im... Remove this comment to see the full error message
|
||||
const yscale = d3.scale
|
||||
.linear()
|
||||
.domain([min * 0.99, max * 1.01])
|
||||
@@ -83,32 +88,37 @@ function render(container, data, { xAxisLabel, yAxisLabel }) {
|
||||
|
||||
const chart = box()
|
||||
.whiskers(calcIqr(1.5))
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'width' does not exist on type '{ (g: any... Remove this comment to see the full error message
|
||||
.width(boxWidth - 2 * margin.inner)
|
||||
.height(height)
|
||||
.domain([min * 0.99, max * 1.01]);
|
||||
const xAxis = d3.svg
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'axis' does not exist on type '(url: stri... Remove this comment to see the full error message
|
||||
.axis()
|
||||
.scale(xscale)
|
||||
.orient("bottom");
|
||||
|
||||
const yAxis = d3.svg
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'axis' does not exist on type '(url: stri... Remove this comment to see the full error message
|
||||
.axis()
|
||||
.scale(yscale)
|
||||
.orient("left");
|
||||
|
||||
const xLines = d3.svg
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'axis' does not exist on type '(url: stri... Remove this comment to see the full error message
|
||||
.axis()
|
||||
.scale(xscale)
|
||||
.tickSize(height)
|
||||
.orient("bottom");
|
||||
|
||||
const yLines = d3.svg
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'axis' does not exist on type '(url: stri... Remove this comment to see the full error message
|
||||
.axis()
|
||||
.scale(yscale)
|
||||
.tickSize(width)
|
||||
.orient("right");
|
||||
|
||||
function barOffset(i) {
|
||||
function barOffset(i: any) {
|
||||
return xscale(columns[i]) + (xscale(columns[1]) - margin.inner) / 2.0;
|
||||
}
|
||||
|
||||
@@ -174,11 +184,14 @@ function render(container, data, { xAxisLabel, yAxisLabel }) {
|
||||
.attr("class", "box")
|
||||
.attr("width", boxWidth)
|
||||
.attr("height", height)
|
||||
.attr("transform", (_, i) => `translate(${barOffset(i)},${0})`)
|
||||
.attr("transform", (_: any, i: any) => `translate(${barOffset(i)},${0})`)
|
||||
.call(chart);
|
||||
}
|
||||
|
||||
export default function Renderer({ data, options }) {
|
||||
export default function Renderer({
|
||||
data,
|
||||
options
|
||||
}: any) {
|
||||
const [container, setContainer] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -191,6 +204,7 @@ export default function Renderer({ data, options }) {
|
||||
}
|
||||
}, [container, data, options]);
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Dispatch<SetStateAction<null>>' is not assig... Remove this comment to see the full error message
|
||||
return <div className="box-plot-deprecated-visualization-container" ref={setContainer} />;
|
||||
}
|
||||
|
||||
@@ -4,16 +4,17 @@ function box() {
|
||||
let width = 1,
|
||||
height = 1,
|
||||
duration = 0,
|
||||
domain = null,
|
||||
domain: any = null,
|
||||
value = Number,
|
||||
whiskers = boxWhiskers,
|
||||
quartiles = boxQuartiles,
|
||||
tickFormat = null;
|
||||
tickFormat: any = null;
|
||||
|
||||
// For each small multiple…
|
||||
function box(g) {
|
||||
g.each(function(d, i) {
|
||||
function box(g: any) {
|
||||
g.each(function(d: any, i: any) {
|
||||
d = d.map(value).sort(d3.ascending);
|
||||
// @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message
|
||||
let g = d3.select(this),
|
||||
n = d.length,
|
||||
min = d[0],
|
||||
@@ -23,6 +24,7 @@ function box() {
|
||||
const quartileData = (d.quartiles = quartiles(d));
|
||||
|
||||
// Compute whiskers. Must return exactly 2 elements, or null.
|
||||
// @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message
|
||||
let whiskerIndices = whiskers && whiskers.call(this, d, i),
|
||||
whiskerData = whiskerIndices && whiskerIndices.map(i => d[i]);
|
||||
|
||||
@@ -33,20 +35,25 @@ function box() {
|
||||
: d3.range(n);
|
||||
|
||||
// Compute the new x-scale.
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'scale' does not exist on type 'typeof im... Remove this comment to see the full error message
|
||||
const x1 = d3.scale
|
||||
.linear()
|
||||
// @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message
|
||||
.domain((domain && domain.call(this, d, i)) || [min, max])
|
||||
.range([height, 0]);
|
||||
|
||||
// Retrieve the old x-scale, if this is an update.
|
||||
const x0 =
|
||||
// @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message
|
||||
this.__chart__ ||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'scale' does not exist on type 'typeof im... Remove this comment to see the full error message
|
||||
d3.scale
|
||||
.linear()
|
||||
.domain([0, Infinity])
|
||||
.range(x1.range());
|
||||
|
||||
// Stash the new scale.
|
||||
// @ts-expect-error ts-migrate(2683) FIXME: 'this' implicitly has type 'any' because it does n... Remove this comment to see the full error message
|
||||
this.__chart__ = x1;
|
||||
|
||||
// Note: the box, median, and box tick elements are fixed in number,
|
||||
@@ -84,7 +91,9 @@ function box() {
|
||||
.transition()
|
||||
.duration(duration)
|
||||
.style("opacity", 1e-6)
|
||||
// @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
|
||||
.attr("y1", d => x1(d[0]))
|
||||
// @ts-expect-error ts-migrate(2571) FIXME: Object is of type 'unknown'.
|
||||
.attr("y2", d => x1(d[1]))
|
||||
.remove();
|
||||
|
||||
@@ -196,6 +205,7 @@ function box() {
|
||||
.exit()
|
||||
.transition()
|
||||
.duration(duration)
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
.attr("cy", i => x1(d[i]))
|
||||
.style("opacity", 1e-6)
|
||||
.remove();
|
||||
@@ -263,52 +273,54 @@ function box() {
|
||||
.style("opacity", 1e-6)
|
||||
.remove();
|
||||
});
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'flush' does not exist on type '(callback... Remove this comment to see the full error message
|
||||
d3.timer.flush();
|
||||
}
|
||||
|
||||
box.width = function(x) {
|
||||
box.width = function(x: any) {
|
||||
if (!arguments.length) return width;
|
||||
width = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.height = function(x) {
|
||||
box.height = function(x: any) {
|
||||
if (!arguments.length) return height;
|
||||
height = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.tickFormat = function(x) {
|
||||
box.tickFormat = function(x: any) {
|
||||
if (!arguments.length) return tickFormat;
|
||||
tickFormat = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.duration = function(x) {
|
||||
box.duration = function(x: any) {
|
||||
if (!arguments.length) return duration;
|
||||
duration = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.domain = function(x) {
|
||||
box.domain = function(x: any) {
|
||||
if (!arguments.length) return domain;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'functor' does not exist on type 'typeof ... Remove this comment to see the full error message
|
||||
domain = x == null ? x : d3.functor(x);
|
||||
return box;
|
||||
};
|
||||
|
||||
box.value = function(x) {
|
||||
box.value = function(x: any) {
|
||||
if (!arguments.length) return value;
|
||||
value = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.whiskers = function(x) {
|
||||
box.whiskers = function(x: any) {
|
||||
if (!arguments.length) return whiskers;
|
||||
whiskers = x;
|
||||
return box;
|
||||
};
|
||||
|
||||
box.quartiles = function(x) {
|
||||
box.quartiles = function(x: any) {
|
||||
if (!arguments.length) return quartiles;
|
||||
quartiles = x;
|
||||
return box;
|
||||
@@ -317,11 +329,11 @@ function box() {
|
||||
return box;
|
||||
}
|
||||
|
||||
function boxWhiskers(d) {
|
||||
function boxWhiskers(d: any) {
|
||||
return [0, d.length - 1];
|
||||
}
|
||||
|
||||
function boxQuartiles(d) {
|
||||
function boxQuartiles(d: any) {
|
||||
return [d3.quantile(d, 0.25), d3.quantile(d, 0.5), d3.quantile(d, 0.75)];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ export default {
|
||||
type: "BOXPLOT",
|
||||
name: "Boxplot (Deprecated)",
|
||||
isDeprecated: true,
|
||||
getOptions: options => ({ ...options }),
|
||||
getOptions: (options: any) => ({
|
||||
...options
|
||||
}),
|
||||
Renderer,
|
||||
Editor,
|
||||
|
||||
@@ -1,110 +0,0 @@
|
||||
import { isString, isObject, isFinite, isNumber, merge } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import * as Grid from "antd/lib/grid";
|
||||
import { Section, Select, Input, InputNumber } from "@/components/visualizations/editor";
|
||||
|
||||
function toNumber(value) {
|
||||
value = isNumber(value) ? value : parseFloat(value);
|
||||
return isFinite(value) ? value : null;
|
||||
}
|
||||
|
||||
export default function AxisSettings({ id, options, features, onChange }) {
|
||||
function optionsChanged(newOptions) {
|
||||
onChange(merge({}, options, newOptions));
|
||||
}
|
||||
|
||||
const [handleNameChange] = useDebouncedCallback(text => {
|
||||
const title = isString(text) && text !== "" ? { text } : null;
|
||||
optionsChanged({ title });
|
||||
}, 200);
|
||||
|
||||
const [handleMinMaxChange] = useDebouncedCallback(opts => optionsChanged(opts), 200);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Section>
|
||||
<Select
|
||||
label="Scale"
|
||||
data-test={`Chart.${id}.Type`}
|
||||
defaultValue={options.type}
|
||||
onChange={type => optionsChanged({ type })}>
|
||||
{features.autoDetectType && (
|
||||
<Select.Option value="-" data-test={`Chart.${id}.Type.Auto`}>
|
||||
Auto Detect
|
||||
</Select.Option>
|
||||
)}
|
||||
<Select.Option value="datetime" data-test={`Chart.${id}.Type.DateTime`}>
|
||||
Datetime
|
||||
</Select.Option>
|
||||
<Select.Option value="linear" data-test={`Chart.${id}.Type.Linear`}>
|
||||
Linear
|
||||
</Select.Option>
|
||||
<Select.Option value="logarithmic" data-test={`Chart.${id}.Type.Logarithmic`}>
|
||||
Logarithmic
|
||||
</Select.Option>
|
||||
<Select.Option value="category" data-test={`Chart.${id}.Type.Category`}>
|
||||
Category
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Input
|
||||
label="Name"
|
||||
data-test={`Chart.${id}.Name`}
|
||||
defaultValue={isObject(options.title) ? options.title.text : null}
|
||||
onChange={event => handleNameChange(event.target.value)}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{features.range && (
|
||||
<Section>
|
||||
<Grid.Row gutter={15} type="flex" align="middle">
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
label="Min Value"
|
||||
placeholder="Auto"
|
||||
data-test={`Chart.${id}.RangeMin`}
|
||||
defaultValue={toNumber(options.rangeMin)}
|
||||
onChange={value => handleMinMaxChange({ rangeMin: toNumber(value) })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
label="Max Value"
|
||||
placeholder="Auto"
|
||||
data-test={`Chart.${id}.RangeMax`}
|
||||
defaultValue={toNumber(options.rangeMax)}
|
||||
onChange={value => handleMinMaxChange({ rangeMax: toNumber(value) })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</Section>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
AxisSettings.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
options: PropTypes.shape({
|
||||
type: PropTypes.string.isRequired,
|
||||
title: PropTypes.shape({
|
||||
text: PropTypes.string,
|
||||
}),
|
||||
rangeMin: PropTypes.number,
|
||||
rangeMax: PropTypes.number,
|
||||
}).isRequired,
|
||||
features: PropTypes.shape({
|
||||
autoDetectType: PropTypes.bool,
|
||||
range: PropTypes.bool,
|
||||
}),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
AxisSettings.defaultProps = {
|
||||
features: {},
|
||||
onChange: () => {},
|
||||
};
|
||||
125
viz-lib/src/visualizations/chart/Editor/AxisSettings.tsx
Normal file
125
viz-lib/src/visualizations/chart/Editor/AxisSettings.tsx
Normal file
@@ -0,0 +1,125 @@
|
||||
import { isString, isObject, isFinite, isNumber, merge } from "lodash";
|
||||
import React from "react";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import * as Grid from "antd/lib/grid";
|
||||
import { Section, Select, Input, InputNumber } from "@/components/visualizations/editor";
|
||||
|
||||
function toNumber(value: any) {
|
||||
value = isNumber(value) ? value : parseFloat(value);
|
||||
return isFinite(value) ? value : null;
|
||||
}
|
||||
|
||||
type OwnProps = {
|
||||
id: string;
|
||||
options: {
|
||||
type: string;
|
||||
title?: {
|
||||
text?: string;
|
||||
};
|
||||
rangeMin?: number;
|
||||
rangeMax?: number;
|
||||
};
|
||||
features?: {
|
||||
autoDetectType?: boolean;
|
||||
range?: boolean;
|
||||
};
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof AxisSettings.defaultProps;
|
||||
|
||||
export default function AxisSettings({ id, options, features, onChange }: Props) {
|
||||
function optionsChanged(newOptions: any) {
|
||||
onChange(merge({}, options, newOptions));
|
||||
}
|
||||
|
||||
const [handleNameChange] = useDebouncedCallback(text => {
|
||||
const title = isString(text) && text !== "" ? { text } : null;
|
||||
optionsChanged({ title });
|
||||
}, 200);
|
||||
|
||||
const [handleMinMaxChange] = useDebouncedCallback(opts => optionsChanged(opts), 200);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Select
|
||||
label="Scale"
|
||||
data-test={`Chart.${id}.Type`}
|
||||
defaultValue={options.type}
|
||||
onChange={(type: any) => optionsChanged({ type })}>
|
||||
{features.autoDetectType && (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message
|
||||
<Select.Option value="-" data-test={`Chart.${id}.Type.Auto`}>
|
||||
Auto Detect
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
)}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="datetime" data-test={`Chart.${id}.Type.DateTime`}>
|
||||
Datetime
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="linear" data-test={`Chart.${id}.Type.Linear`}>
|
||||
Linear
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="logarithmic" data-test={`Chart.${id}.Type.Logarithmic`}>
|
||||
Logarithmic
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="category" data-test={`Chart.${id}.Type.Category`}>
|
||||
Category
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label="Name"
|
||||
data-test={`Chart.${id}.Name`}
|
||||
defaultValue={isObject(options.title) ? options.title.text : null}
|
||||
onChange={(event: any) => handleNameChange(event.target.value)}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{features.range && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type '{ children: Element[]; gutter: number; type:... Remove this comment to see the full error message */}
|
||||
<Grid.Row gutter={15} type="flex" align="middle">
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
label="Min Value"
|
||||
placeholder="Auto"
|
||||
data-test={`Chart.${id}.RangeMin`}
|
||||
defaultValue={toNumber(options.rangeMin)}
|
||||
onChange={(value: any) => handleMinMaxChange({ rangeMin: toNumber(value) })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
label="Max Value"
|
||||
placeholder="Auto"
|
||||
data-test={`Chart.${id}.RangeMax`}
|
||||
defaultValue={toNumber(options.rangeMax)}
|
||||
onChange={(value: any) => handleMinMaxChange({ rangeMax: toNumber(value) })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</Section>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
AxisSettings.defaultProps = {
|
||||
features: {},
|
||||
onChange: () => {},
|
||||
};
|
||||
@@ -1,6 +1,5 @@
|
||||
import { filter, includes, map } from "lodash";
|
||||
import React, { useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Select } from "@/components/visualizations/editor";
|
||||
import { visualizationsSettings } from "@/visualizations/visualizationsSettings";
|
||||
|
||||
@@ -15,7 +14,13 @@ const allChartTypes = [
|
||||
{ type: "box", name: "Box", icon: "square-o" },
|
||||
];
|
||||
|
||||
export default function ChartTypeSelect({ hiddenChartTypes, ...props }) {
|
||||
type OwnProps = {
|
||||
hiddenChartTypes?: any[]; // TODO: PropTypes.oneOf(map(allChartTypes, "type"))
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ChartTypeSelect.defaultProps;
|
||||
|
||||
export default function ChartTypeSelect({ hiddenChartTypes, ...props }: Props) {
|
||||
const chartTypes = useMemo(() => {
|
||||
const result = [...allChartTypes];
|
||||
|
||||
@@ -33,19 +38,17 @@ export default function ChartTypeSelect({ hiddenChartTypes, ...props }) {
|
||||
return (
|
||||
<Select {...props}>
|
||||
{map(chartTypes, ({ type, name, icon }) => (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message
|
||||
<Select.Option key={type} value={type} data-test={`Chart.ChartType.${type}`}>
|
||||
<i className={`fa fa-${icon}`} style={{ marginRight: 5 }} />
|
||||
{name}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
|
||||
ChartTypeSelect.propTypes = {
|
||||
hiddenChartTypes: PropTypes.arrayOf(PropTypes.oneOf(map(allChartTypes, "type"))),
|
||||
};
|
||||
|
||||
ChartTypeSelect.defaultProps = {
|
||||
hiddenChartTypes: [],
|
||||
};
|
||||
@@ -5,11 +5,11 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import ColorsSettings from "./ColorsSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<ColorsSettings
|
||||
@@ -22,7 +22,7 @@ function mount(options, done) {
|
||||
rows: [{ a: "v", b: 3.14 }],
|
||||
}}
|
||||
options={options}
|
||||
onOptionsChange={changedOptions => {
|
||||
onOptionsChange={(changedOptions: any) => {
|
||||
expect(changedOptions).toMatchSnapshot();
|
||||
done();
|
||||
}}
|
||||
@@ -10,7 +10,11 @@ const components = {
|
||||
heatmap: HeatmapColorsSettings,
|
||||
};
|
||||
|
||||
export default function ColorsSettings({ options, ...props }) {
|
||||
export default function ColorsSettings({
|
||||
options,
|
||||
...props
|
||||
}: any) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const Component = components[options.globalSeriesType] || DefaultColorsSettings;
|
||||
return <Component options={options} {...props} />;
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import { isString, map, uniq, flatten, filter, sortBy, keys } from "lodash";
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { Section, Select } from "@/components/visualizations/editor";
|
||||
|
||||
const MappingTypes = {
|
||||
@@ -18,13 +17,23 @@ const SwappedMappingTypes = {
|
||||
y: { label: "X Columns", multiple: true },
|
||||
};
|
||||
|
||||
export default function ColumnMappingSelect({ value, availableColumns, type, onChange, areAxesSwapped }) {
|
||||
type OwnProps = {
|
||||
value?: string | string[];
|
||||
availableColumns?: string[];
|
||||
type?: any; // TODO: PropTypes.oneOf(keys(MappingTypes))
|
||||
onChange?: (...args: any[]) => any;
|
||||
};
|
||||
|
||||
type Props = OwnProps & typeof ColumnMappingSelect.defaultProps;
|
||||
|
||||
export default function ColumnMappingSelect({ value, availableColumns, type, onChange, areAxesSwapped }: Props) {
|
||||
const options = sortBy(filter(uniq(flatten([availableColumns, value])), v => isString(v) && v !== ""));
|
||||
|
||||
// this swaps the ui, as the data will be swapped on render
|
||||
const { label, multiple } = !areAxesSwapped ? MappingTypes[type] : SwappedMappingTypes[type];
|
||||
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Select
|
||||
label={label}
|
||||
@@ -34,10 +43,13 @@ export default function ColumnMappingSelect({ value, availableColumns, type, onC
|
||||
showSearch
|
||||
placeholder={multiple ? "Choose columns..." : "Choose column..."}
|
||||
value={value || undefined}
|
||||
onChange={column => onChange(column || null, type)}>
|
||||
// @ts-expect-error ts-migrate(2349) FIXME: This expression is not callable.
|
||||
onChange={(column: any) => onChange(column || null, type)}>
|
||||
{map(options, c => (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message
|
||||
<Select.Option key={c} value={c} data-test={`Chart.ColumnMapping.${type}.${c}`}>
|
||||
{c}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
@@ -45,13 +57,6 @@ export default function ColumnMappingSelect({ value, availableColumns, type, onC
|
||||
);
|
||||
}
|
||||
|
||||
ColumnMappingSelect.propTypes = {
|
||||
value: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
|
||||
availableColumns: PropTypes.arrayOf(PropTypes.string),
|
||||
type: PropTypes.oneOf(keys(MappingTypes)),
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
ColumnMappingSelect.defaultProps = {
|
||||
value: null,
|
||||
availableColumns: [],
|
||||
@@ -1,48 +0,0 @@
|
||||
import { isNil, trimStart } from "lodash";
|
||||
import React from "react";
|
||||
import { Section, Switch, TextArea } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
const defaultCustomCode = trimStart(`
|
||||
// Available variables are x, ys, element, and Plotly
|
||||
// Type console.log(x, ys); for more info about x and ys
|
||||
// To plot your graph call Plotly.plot(element, ...)
|
||||
// Plotly examples and docs: https://plot.ly/javascript/
|
||||
`);
|
||||
|
||||
export default function CustomChartSettings({ options, onOptionsChange }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Section>
|
||||
<TextArea
|
||||
label="Custom code"
|
||||
data-test="Chart.Custom.Code"
|
||||
rows="10"
|
||||
defaultValue={isNil(options.customCode) ? defaultCustomCode : options.customCode}
|
||||
onChange={event => onOptionsChange({ customCode: event.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
data-test="Chart.Custom.EnableConsoleLogs"
|
||||
defaultChecked={options.enableConsoleLogs}
|
||||
onChange={enableConsoleLogs => onOptionsChange({ enableConsoleLogs })}>
|
||||
Show errors in the console
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
id="chart-editor-auto-update-custom-chart"
|
||||
data-test="Chart.Custom.AutoUpdate"
|
||||
defaultChecked={options.autoRedraw}
|
||||
onChange={autoRedraw => onOptionsChange({ autoRedraw })}>
|
||||
Auto update graph
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
CustomChartSettings.propTypes = EditorPropTypes;
|
||||
@@ -0,0 +1,63 @@
|
||||
import { isNil, trimStart } from "lodash";
|
||||
import React from "react";
|
||||
import { Section, Switch, TextArea } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
const defaultCustomCode = trimStart(`
|
||||
// Available variables are x, ys, element, and Plotly
|
||||
// Type console.log(x, ys); for more info about x and ys
|
||||
// To plot your graph call Plotly.plot(element, ...)
|
||||
// Plotly examples and docs: https://plot.ly/javascript/
|
||||
`);
|
||||
|
||||
export default function CustomChartSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<TextArea
|
||||
label="Custom code"
|
||||
data-test="Chart.Custom.Code"
|
||||
rows="10"
|
||||
defaultValue={isNil(options.customCode) ? defaultCustomCode : options.customCode}
|
||||
onChange={(event: any) => onOptionsChange({ customCode: event.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.Custom.EnableConsoleLogs"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.enableConsoleLogs}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(enableConsoleLogs: any) => any' is not assi... Remove this comment to see the full error message
|
||||
onChange={(enableConsoleLogs: any) => onOptionsChange({ enableConsoleLogs })}>
|
||||
Show errors in the console
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
id="chart-editor-auto-update-custom-chart"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.Custom.AutoUpdate"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.autoRedraw}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(autoRedraw: any) => any' is not assignable ... Remove this comment to see the full error message
|
||||
onChange={(autoRedraw: any) => onOptionsChange({ autoRedraw })}>
|
||||
Auto update graph
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
CustomChartSettings.propTypes = EditorPropTypes;
|
||||
@@ -4,11 +4,11 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import DataLabelsSettings from "./DataLabelsSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<DataLabelsSettings
|
||||
@@ -4,7 +4,10 @@ import { useDebouncedCallback } from "use-debounce";
|
||||
import { Section, Input, Checkbox, ContextHelp } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
export default function DataLabelsSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const isShowDataLabelsAvailable = includes(
|
||||
["line", "area", "column", "scatter", "pie", "heatmap"],
|
||||
options.globalSeriesType
|
||||
@@ -15,6 +18,7 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{isShowDataLabelsAvailable && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Chart.DataLabels.ShowDataLabels"
|
||||
@@ -25,6 +29,7 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label={
|
||||
@@ -35,10 +40,11 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
}
|
||||
data-test="Chart.DataLabels.NumberFormat"
|
||||
defaultValue={options.numberFormat}
|
||||
onChange={e => debouncedOnOptionsChange({ numberFormat: e.target.value })}
|
||||
onChange={(e: any) => debouncedOnOptionsChange({ numberFormat: e.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label={
|
||||
@@ -49,10 +55,11 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
}
|
||||
data-test="Chart.DataLabels.PercentFormat"
|
||||
defaultValue={options.percentFormat}
|
||||
onChange={e => debouncedOnOptionsChange({ percentFormat: e.target.value })}
|
||||
onChange={(e: any) => debouncedOnOptionsChange({ percentFormat: e.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label={
|
||||
@@ -63,15 +70,17 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
}
|
||||
data-test="Chart.DataLabels.DateTimeFormat"
|
||||
defaultValue={options.dateTimeFormat}
|
||||
onChange={e => debouncedOnOptionsChange({ dateTimeFormat: e.target.value })}
|
||||
onChange={(e: any) => debouncedOnOptionsChange({ dateTimeFormat: e.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label={
|
||||
<React.Fragment>
|
||||
Data Labels
|
||||
{/* @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message */}
|
||||
<ContextHelp placement="topRight" arrowPointAtCenter>
|
||||
<div style={{ paddingBottom: 5 }}>Use special names to access additional properties:</div>
|
||||
<div>
|
||||
@@ -104,7 +113,7 @@ export default function DataLabelsSettings({ options, onOptionsChange }) {
|
||||
data-test="Chart.DataLabels.TextFormat"
|
||||
placeholder="(auto)"
|
||||
defaultValue={options.textFormat}
|
||||
onChange={e => debouncedOnOptionsChange({ textFormat: e.target.value })}
|
||||
onChange={(e: any) => debouncedOnOptionsChange({ textFormat: e.target.value })}
|
||||
/>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
@@ -6,7 +6,11 @@ import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import ColorPalette from "@/visualizations/ColorPalette";
|
||||
import getChartData from "../getChartData";
|
||||
|
||||
export default function DefaultColorsSettings({ options, data, onOptionsChange }) {
|
||||
export default function DefaultColorsSettings({
|
||||
options,
|
||||
data,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const colors = useMemo(
|
||||
() => ({
|
||||
Automatic: null,
|
||||
@@ -46,20 +50,28 @@ export default function DefaultColorsSettings({ options, data, onOptionsChange }
|
||||
title: "Color",
|
||||
dataIndex: "color",
|
||||
width: "1%",
|
||||
render: (unused, item) => (
|
||||
render: (unused: any, item: any) => (
|
||||
<ColorPicker
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test={`Chart.Series.${item.key}.Color`}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
interactive
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ "Indian Red": string; "Green 2": string; "... Remove this comment to see the full error message
|
||||
presetColors={colors}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
placement="topRight"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
color={item.color}
|
||||
onChange={value => updateSeriesOption(item.key, "color", value)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onChange={(value: any) => updateSeriesOption(item.key, "color", value)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'never'.
|
||||
addonAfter={<ColorPicker.Label color={item.color} presetColors={colors} />}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean[]' is not assignable to type 'object... Remove this comment to see the full error message
|
||||
return <Table showHeader={false} dataSource={series} columns={columns} pagination={false} />;
|
||||
}
|
||||
|
||||
@@ -4,15 +4,15 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import GeneralSettings from "./GeneralSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function elementExists(wrapper, testId) {
|
||||
function elementExists(wrapper: any, testId: any) {
|
||||
return findByTestID(wrapper, testId).length > 0;
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<GeneralSettings
|
||||
@@ -149,6 +149,7 @@ describe("Visualizations -> Chart -> Editor -> General Settings", () => {
|
||||
|
||||
describe("Column mappings should be available", () => {
|
||||
test("for bubble", () => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const el = mount({
|
||||
globalSeriesType: "column",
|
||||
seriesOptions: {
|
||||
@@ -164,6 +165,7 @@ describe("Visualizations -> Chart -> Editor -> General Settings", () => {
|
||||
});
|
||||
|
||||
test("for heatmap", () => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const el = mount({
|
||||
globalSeriesType: "heatmap",
|
||||
seriesOptions: {
|
||||
@@ -179,6 +181,7 @@ describe("Visualizations -> Chart -> Editor -> General Settings", () => {
|
||||
});
|
||||
|
||||
test("for all types except of bubble, heatmap and custom", () => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const el = mount({
|
||||
globalSeriesType: "column",
|
||||
seriesOptions: {
|
||||
@@ -7,7 +7,7 @@ import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import ChartTypeSelect from "./ChartTypeSelect";
|
||||
import ColumnMappingSelect from "./ColumnMappingSelect";
|
||||
|
||||
function getAvailableColumnMappingTypes(options) {
|
||||
function getAvailableColumnMappingTypes(options: any) {
|
||||
const result = ["x", "y"];
|
||||
|
||||
if (!includes(["custom", "heatmap"], options.globalSeriesType)) {
|
||||
@@ -29,22 +29,26 @@ function getAvailableColumnMappingTypes(options) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function getMappedColumns(options, availableColumns) {
|
||||
function getMappedColumns(options: any, availableColumns: any) {
|
||||
const mappedColumns = {};
|
||||
const availableTypes = getAvailableColumnMappingTypes(options);
|
||||
each(availableTypes, type => {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
mappedColumns[type] = ColumnMappingSelect.MappingTypes[type].multiple ? [] : null;
|
||||
});
|
||||
|
||||
availableColumns = map(availableColumns, c => c.name);
|
||||
const usedColumns = [];
|
||||
const usedColumns: any = [];
|
||||
|
||||
each(options.columnMapping, (type, column) => {
|
||||
if (includes(availableColumns, column) && includes(availableTypes, type)) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const { multiple } = ColumnMappingSelect.MappingTypes[type];
|
||||
if (multiple) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
mappedColumns[type].push(column);
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
mappedColumns[type] = column;
|
||||
}
|
||||
usedColumns.push(column);
|
||||
@@ -57,15 +61,17 @@ function getMappedColumns(options, availableColumns) {
|
||||
};
|
||||
}
|
||||
|
||||
function mappedColumnsToColumnMappings(mappedColumns) {
|
||||
function mappedColumnsToColumnMappings(mappedColumns: any) {
|
||||
const result = {};
|
||||
each(mappedColumns, (value, type) => {
|
||||
if (isArray(value)) {
|
||||
each(value, v => {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
result[v] = type;
|
||||
});
|
||||
} else {
|
||||
if (value) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
result[value] = type;
|
||||
}
|
||||
}
|
||||
@@ -73,13 +79,17 @@ function mappedColumnsToColumnMappings(mappedColumns) {
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
export default function GeneralSettings({
|
||||
options,
|
||||
data,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const { mappedColumns, unusedColumns } = useMemo(() => getMappedColumns(options, data.columns), [
|
||||
options,
|
||||
data.columns,
|
||||
]);
|
||||
|
||||
function handleGlobalSeriesTypeChange(globalSeriesType) {
|
||||
function handleGlobalSeriesTypeChange(globalSeriesType: any) {
|
||||
onOptionsChange({
|
||||
globalSeriesType,
|
||||
showDataLabels: globalSeriesType === "pie",
|
||||
@@ -91,7 +101,7 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
});
|
||||
}
|
||||
|
||||
function handleColumnMappingChange(column, type) {
|
||||
function handleColumnMappingChange(column: any, type: any) {
|
||||
const columnMapping = mappedColumnsToColumnMappings({
|
||||
...mappedColumns,
|
||||
[type]: column,
|
||||
@@ -99,7 +109,7 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
onOptionsChange({ columnMapping }, UpdateOptionsStrategy.shallowMerge);
|
||||
}
|
||||
|
||||
function handleLegendPlacementChange(value) {
|
||||
function handleLegendPlacementChange(value: any) {
|
||||
if (value === "hidden") {
|
||||
onOptionsChange({ legend: { enabled: false } });
|
||||
} else {
|
||||
@@ -118,8 +128,10 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ChartTypeSelect
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ label: string; "data-test": string; defaul... Remove this comment to see the full error message
|
||||
label="Chart Type"
|
||||
data-test="Chart.GlobalSeriesType"
|
||||
defaultValue={options.globalSeriesType}
|
||||
@@ -128,6 +140,7 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
</Section>
|
||||
|
||||
{includes(["column", "line", "box"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Chart.SwappedAxes"
|
||||
@@ -141,37 +154,48 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
|
||||
{map(mappedColumns, (value, type) => (
|
||||
<ColumnMappingSelect
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
key={type}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
type={type}
|
||||
value={value}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
areAxesSwapped={options.swappedAxes}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'unknown[]' is not assignable to type 'never'... Remove this comment to see the full error message
|
||||
availableColumns={unusedColumns}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(column: any, type: any) => void' is not ass... Remove this comment to see the full error message
|
||||
onChange={handleColumnMappingChange}
|
||||
/>
|
||||
))}
|
||||
|
||||
{includes(["bubble"], options.globalSeriesType) && (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<InputNumber
|
||||
label="Bubble Size Coefficient"
|
||||
data-test="Chart.BubbleCoefficient"
|
||||
defaultValue={options.coefficient}
|
||||
onChange={value => onOptionsChange({ coefficient: toNumber(value) })}
|
||||
onChange={(value: any) => onOptionsChange({ coefficient: toNumber(value) })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Select
|
||||
label="Bubble Size Proportional To"
|
||||
data-test="Chart.SizeMode"
|
||||
defaultValue={options.sizemode}
|
||||
onChange={mode => onOptionsChange({ sizemode: mode })}>
|
||||
onChange={(mode: any) => onOptionsChange({ sizemode: mode })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="area" data-test="Chart.SizeMode.Area">
|
||||
Area
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="diameter" data-test="Chart.SizeMode.Diameter">
|
||||
Diameter
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
@@ -179,17 +203,22 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
)}
|
||||
|
||||
{includes(["pie"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Select
|
||||
label="Direction"
|
||||
data-test="Chart.PieDirection"
|
||||
defaultValue={options.direction.type}
|
||||
onChange={type => onOptionsChange({ direction: { type } })}>
|
||||
onChange={(type: any) => onOptionsChange({ direction: { type } })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="counterclockwise" data-test="Chart.PieDirection.Counterclockwise">
|
||||
Counterclockwise
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="clockwise" data-test="Chart.PieDirection.Clockwise">
|
||||
Clockwise
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
@@ -197,36 +226,48 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
|
||||
{!includes(["custom", "heatmap"], options.globalSeriesType) && (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Select
|
||||
label="Legend Placement"
|
||||
data-test="Chart.LegendPlacement"
|
||||
value={options.legend.enabled ? options.legend.placement : "hidden"}
|
||||
onChange={handleLegendPlacementChange}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="hidden" data-test="Chart.LegendPlacement.HideLegend">
|
||||
Hide legend
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="auto" data-test="Chart.LegendPlacement.Auto">
|
||||
Right
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="below" data-test="Chart.LegendPlacement.Below">
|
||||
Bottom
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
|
||||
{options.legend.enabled && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Select
|
||||
label="Legend Items Order"
|
||||
data-test="Chart.LegendItemsOrder"
|
||||
value={options.legend.traceorder}
|
||||
onChange={traceorder => onOptionsChange({ legend: { traceorder } })}>
|
||||
onChange={(traceorder: any) => onOptionsChange({ legend: { traceorder } })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="normal" data-test="Chart.LegendItemsOrder.Normal">
|
||||
Normal
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="reversed" data-test="Chart.LegendItemsOrder.Reversed">
|
||||
Reversed
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
@@ -235,6 +276,7 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
)}
|
||||
|
||||
{includes(["box"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Chart.ShowPoints"
|
||||
@@ -246,24 +288,30 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
)}
|
||||
|
||||
{!includes(["custom", "heatmap"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Select
|
||||
label="Stacking"
|
||||
data-test="Chart.Stacking"
|
||||
defaultValue={options.series.stacking}
|
||||
disabled={!includes(["line", "area", "column"], options.globalSeriesType)}
|
||||
onChange={stacking => onOptionsChange({ series: { stacking } })}>
|
||||
onChange={(stacking: any) => onOptionsChange({ series: { stacking } })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value={null} data-test="Chart.Stacking.Disabled">
|
||||
Disabled
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="stack" data-test="Chart.Stacking.Stack">
|
||||
Stack
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
)}
|
||||
|
||||
{includes(["line", "area", "column"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Chart.NormalizeValues"
|
||||
@@ -275,17 +323,22 @@ export default function GeneralSettings({ options, data, onOptionsChange }) {
|
||||
)}
|
||||
|
||||
{!includes(["custom", "heatmap", "bubble", "scatter"], options.globalSeriesType) && (
|
||||
// @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message
|
||||
<Section>
|
||||
<Select
|
||||
label="Missing and NULL values"
|
||||
data-test="Chart.MissingValues"
|
||||
defaultValue={options.missingValuesAsZero ? 1 : 0}
|
||||
onChange={value => onOptionsChange({ missingValuesAsZero: !!value })}>
|
||||
onChange={(value: any) => onOptionsChange({ missingValuesAsZero: !!value })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value={0} data-test="Chart.MissingValues.Keep">
|
||||
Do not display in chart
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value={1} data-test="Chart.MissingValues.Zero">
|
||||
Convert to 0 and display in chart
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
@@ -25,9 +25,13 @@ const ColorSchemes = [
|
||||
"Custom...",
|
||||
];
|
||||
|
||||
export default function HeatmapColorsSettings({ options, onOptionsChange }) {
|
||||
export default function HeatmapColorsSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Select
|
||||
label="Color Scheme"
|
||||
@@ -35,10 +39,12 @@ export default function HeatmapColorsSettings({ options, onOptionsChange }) {
|
||||
placeholder="Choose Color Scheme..."
|
||||
allowClear
|
||||
value={options.colorScheme || undefined}
|
||||
onChange={value => onOptionsChange({ colorScheme: value || null })}>
|
||||
onChange={(value: any) => onOptionsChange({ colorScheme: value || null })}>
|
||||
{map(ColorSchemes, scheme => (
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message
|
||||
<Select.Option key={scheme} value={scheme} data-test={`Chart.Colors.Heatmap.ColorScheme.${scheme}`}>
|
||||
{scheme}
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
@@ -46,6 +52,7 @@ export default function HeatmapColorsSettings({ options, onOptionsChange }) {
|
||||
|
||||
{options.colorScheme === "Custom..." && (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -55,10 +62,12 @@ export default function HeatmapColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topLeft"
|
||||
presetColors={ColorPalette}
|
||||
color={options.heatMinColor}
|
||||
onChange={heatMinColor => onOptionsChange({ heatMinColor })}
|
||||
onChange={(heatMinColor: any) => onOptionsChange({ heatMinColor })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.heatMinColor} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -68,7 +77,8 @@ export default function HeatmapColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
presetColors={ColorPalette}
|
||||
color={options.heatMaxColor}
|
||||
onChange={heatMaxColor => onOptionsChange({ heatMaxColor })}
|
||||
onChange={(heatMaxColor: any) => onOptionsChange({ heatMaxColor })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.heatMaxColor} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
@@ -6,7 +6,7 @@ import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import ColorPalette from "@/visualizations/ColorPalette";
|
||||
import getChartData from "../getChartData";
|
||||
|
||||
function getUniqueValues(chartData) {
|
||||
function getUniqueValues(chartData: any) {
|
||||
const uniqueValuesNames = new Set();
|
||||
each(chartData, series => {
|
||||
each(series.data, row => {
|
||||
@@ -16,7 +16,11 @@ function getUniqueValues(chartData) {
|
||||
return [...uniqueValuesNames];
|
||||
}
|
||||
|
||||
export default function PieColorsSettings({ options, data, onOptionsChange }) {
|
||||
export default function PieColorsSettings({
|
||||
options,
|
||||
data,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const colors = useMemo(
|
||||
() => ({
|
||||
Automatic: null,
|
||||
@@ -29,6 +33,7 @@ export default function PieColorsSettings({ options, data, onOptionsChange }) {
|
||||
() =>
|
||||
map(getUniqueValues(getChartData(data.rows, options)), value => ({
|
||||
key: value,
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'unknown' cannot be used as an index type.
|
||||
color: (options.valuesOptions[value] || {}).color || null,
|
||||
})),
|
||||
[options, data]
|
||||
@@ -56,14 +61,21 @@ export default function PieColorsSettings({ options, data, onOptionsChange }) {
|
||||
title: "Color",
|
||||
dataIndex: "color",
|
||||
width: "1%",
|
||||
render: (unused, item) => (
|
||||
render: (unused: any, item: any) => (
|
||||
<ColorPicker
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test={`Chart.Series.${item.key}.Color`}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'never'.
|
||||
interactive
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ "Indian Red": string; "Green 2": string; "... Remove this comment to see the full error message
|
||||
presetColors={colors}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
placement="topRight"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
color={item.color}
|
||||
onChange={value => updateValuesOption(item.key, "color", value)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(value: any) => void' is not assignable to t... Remove this comment to see the full error message
|
||||
onChange={(value: any) => updateValuesOption(item.key, "color", value)}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'never'.
|
||||
addonAfter={<ColorPicker.Label color={item.color} presetColors={colors} />}
|
||||
/>
|
||||
),
|
||||
@@ -4,11 +4,11 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import SeriesSettings from "./SeriesSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<SeriesSettings
|
||||
@@ -4,20 +4,21 @@ import { useDebouncedCallback } from "use-debounce";
|
||||
import Table from "antd/lib/table";
|
||||
import Input from "antd/lib/input";
|
||||
import Radio from "antd/lib/radio";
|
||||
// @ts-expect-error ts-migrate(2724) FIXME: Module '"../../../../node_modules/react-sortable-h... Remove this comment to see the full error message
|
||||
import { sortableElement } from "react-sortable-hoc";
|
||||
import { SortableContainer, DragHandle } from "@/components/sortable";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import ChartTypeSelect from "./ChartTypeSelect";
|
||||
import getChartData from "../getChartData";
|
||||
|
||||
const SortableBodyRow = sortableElement(props => <tr {...props} />);
|
||||
const SortableBodyRow = sortableElement((props: any) => <tr {...props} />);
|
||||
|
||||
function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOption) {
|
||||
function getTableColumns(options: any, updateSeriesOption: any, debouncedUpdateSeriesOption: any) {
|
||||
const result = [
|
||||
{
|
||||
title: "Order",
|
||||
dataIndex: "zIndex",
|
||||
render: (unused, item) => (
|
||||
render: (unused: any, item: any) => (
|
||||
<span className="series-settings-order">
|
||||
<DragHandle />
|
||||
{item.zIndex + 1}
|
||||
@@ -27,7 +28,7 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
|
||||
{
|
||||
title: "Label",
|
||||
dataIndex: "name",
|
||||
render: (unused, item) => (
|
||||
render: (unused: any, item: any) => (
|
||||
<Input
|
||||
data-test={`Chart.Series.${item.key}.Label`}
|
||||
placeholder={item.key}
|
||||
@@ -67,8 +68,9 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
|
||||
data-test={`Chart.Series.${item.key}.Type`}
|
||||
dropdownMatchSelectWidth={false}
|
||||
value={item.type}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
hiddenChartTypes={["pie", "heatmap", "bubble", "box"]}
|
||||
onChange={value => updateSeriesOption(item.key, "type", value)}
|
||||
onChange={(value: any) => updateSeriesOption(item.key, "type", value)}
|
||||
/>
|
||||
),
|
||||
});
|
||||
@@ -77,7 +79,11 @@ function getTableColumns(options, updateSeriesOption, debouncedUpdateSeriesOptio
|
||||
return result;
|
||||
}
|
||||
|
||||
export default function SeriesSettings({ options, data, onOptionsChange }) {
|
||||
export default function SeriesSettings({
|
||||
options,
|
||||
data,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const series = useMemo(
|
||||
() =>
|
||||
map(
|
||||
@@ -92,6 +98,7 @@ export default function SeriesSettings({ options, data, onOptionsChange }) {
|
||||
({ oldIndex, newIndex }) => {
|
||||
const seriesOptions = [...series];
|
||||
seriesOptions.splice(newIndex, 0, ...seriesOptions.splice(oldIndex, 1));
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'key' does not exist on type 'Boolean'.
|
||||
onOptionsChange({ seriesOptions: fromPairs(map(seriesOptions, ({ key }, zIndex) => [key, { zIndex }])) });
|
||||
},
|
||||
[onOptionsChange, series]
|
||||
@@ -124,12 +131,14 @@ export default function SeriesSettings({ options, data, onOptionsChange }) {
|
||||
lockToContainerEdges
|
||||
useDragHandle
|
||||
helperClass="chart-editor-series-dragged-item"
|
||||
helperContainer={container => container.querySelector("tbody")}
|
||||
helperContainer={(container: any) => container.querySelector("tbody")}
|
||||
onSortEnd={handleSortEnd}
|
||||
containerProps={{
|
||||
className: "chart-editor-series",
|
||||
}}>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<Table
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean[]' is not assignable to type 'object... Remove this comment to see the full error message
|
||||
dataSource={series}
|
||||
columns={columns}
|
||||
components={{
|
||||
@@ -137,6 +146,7 @@ export default function SeriesSettings({ options, data, onOptionsChange }) {
|
||||
row: SortableBodyRow,
|
||||
},
|
||||
}}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(item: object) => { index: any; }' is not as... Remove this comment to see the full error message
|
||||
onRow={item => ({ index: item.zIndex })}
|
||||
pagination={false}
|
||||
/>
|
||||
@@ -1,47 +0,0 @@
|
||||
import React from "react";
|
||||
import { Section, Switch } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
import AxisSettings from "./AxisSettings";
|
||||
|
||||
export default function XAxisSettings({ options, onOptionsChange }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AxisSettings
|
||||
id="XAxis"
|
||||
features={{ autoDetectType: true }}
|
||||
options={options.xAxis}
|
||||
onChange={xAxis => onOptionsChange({ xAxis })}
|
||||
/>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
data-test="Chart.XAxis.Sort"
|
||||
defaultChecked={options.sortX}
|
||||
onChange={sortX => onOptionsChange({ sortX })}>
|
||||
Sort Values
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
data-test="Chart.XAxis.Reverse"
|
||||
defaultChecked={options.reverseX}
|
||||
onChange={reverseX => onOptionsChange({ reverseX })}>
|
||||
Reverse Order
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
data-test="Chart.XAxis.ShowLabels"
|
||||
defaultChecked={options.xAxis.labels.enabled}
|
||||
onChange={enabled => onOptionsChange({ xAxis: { labels: { enabled } } })}>
|
||||
Show Labels
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
XAxisSettings.propTypes = EditorPropTypes;
|
||||
@@ -4,11 +4,11 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import XAxisSettings from "./XAxisSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<XAxisSettings
|
||||
66
viz-lib/src/visualizations/chart/Editor/XAxisSettings.tsx
Normal file
66
viz-lib/src/visualizations/chart/Editor/XAxisSettings.tsx
Normal file
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { Section, Switch } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
import AxisSettings from "./AxisSettings";
|
||||
|
||||
export default function XAxisSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<AxisSettings
|
||||
id="XAxis"
|
||||
features={{ autoDetectType: true }}
|
||||
options={options.xAxis}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(xAxis: any) => any' is not assignable to ty... Remove this comment to see the full error message
|
||||
onChange={(xAxis: any) => onOptionsChange({ xAxis })}
|
||||
/>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.XAxis.Sort"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.sortX}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(sortX: any) => any' is not assignable to ty... Remove this comment to see the full error message
|
||||
onChange={(sortX: any) => onOptionsChange({ sortX })}>
|
||||
Sort Values
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.XAxis.Reverse"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.reverseX}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(reverseX: any) => any' is not assignable to... Remove this comment to see the full error message
|
||||
onChange={(reverseX: any) => onOptionsChange({ reverseX })}>
|
||||
Reverse Order
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.XAxis.ShowLabels"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.xAxis.labels.enabled}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(enabled: any) => any' is not assignable to ... Remove this comment to see the full error message
|
||||
onChange={(enabled: any) => onOptionsChange({ xAxis: { labels: { enabled } } })}>
|
||||
Show Labels
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
XAxisSettings.propTypes = EditorPropTypes;
|
||||
@@ -1,75 +0,0 @@
|
||||
import React from "react";
|
||||
import { Section, Switch } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
import AxisSettings from "./AxisSettings";
|
||||
|
||||
export default function YAxisSettings({ options, onOptionsChange }) {
|
||||
const [leftYAxis, rightYAxis] = options.yAxis;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Section.Title>{!options.swappedAxes ? "Left Y Axis" : "X Axis"}</Section.Title>
|
||||
|
||||
<Section>
|
||||
<AxisSettings
|
||||
id="LeftYAxis"
|
||||
features={{ range: true }}
|
||||
options={leftYAxis}
|
||||
onChange={axis => onOptionsChange({ yAxis: [axis, rightYAxis] })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{options.globalSeriesType !== "heatmap" && !options.swappedAxes && (
|
||||
<React.Fragment>
|
||||
<Section.Title>Right Y Axis</Section.Title>
|
||||
|
||||
<Section>
|
||||
<AxisSettings
|
||||
id="RightYAxis"
|
||||
features={{ range: true }}
|
||||
options={rightYAxis}
|
||||
onChange={axis => onOptionsChange({ yAxis: [leftYAxis, axis] })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
id="chart-editor-y-axis-align-at-zero"
|
||||
data-test="Chart.YAxis.AlignAtZero"
|
||||
defaultChecked={options.alignYAxesAtZero}
|
||||
onChange={alignYAxesAtZero => onOptionsChange({ alignYAxesAtZero })}>
|
||||
Align Y Axes at Zero
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{options.globalSeriesType === "heatmap" && (
|
||||
<React.Fragment>
|
||||
<Section>
|
||||
<Switch
|
||||
id="chart-editor-y-axis-sort"
|
||||
data-test="Chart.LeftYAxis.Sort"
|
||||
defaultChecked={options.sortY}
|
||||
onChange={sortY => onOptionsChange({ sortY })}>
|
||||
Sort Values
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
<Section>
|
||||
<Switch
|
||||
id="chart-editor-y-axis-reverse"
|
||||
data-test="Chart.LeftYAxis.Reverse"
|
||||
defaultChecked={options.reverseY}
|
||||
onChange={reverseY => onOptionsChange({ reverseY })}>
|
||||
Reverse Order
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
YAxisSettings.propTypes = EditorPropTypes;
|
||||
@@ -4,15 +4,15 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import YAxisSettings from "./YAxisSettings";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function elementExists(wrapper, testId) {
|
||||
function elementExists(wrapper: any, testId: any) {
|
||||
return findByTestID(wrapper, testId).length > 0;
|
||||
}
|
||||
|
||||
function mount(options, done) {
|
||||
function mount(options: any, done: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(
|
||||
<YAxisSettings
|
||||
@@ -91,6 +91,7 @@ describe("Visualizations -> Chart -> Editor -> Y-Axis Settings", () => {
|
||||
|
||||
describe("for non-heatmap", () => {
|
||||
test("Right Y Axis should be available", () => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const el = mount({
|
||||
globalSeriesType: "column",
|
||||
yAxis: [{ type: "linear" }, { type: "linear", opposite: true }],
|
||||
@@ -102,6 +103,7 @@ describe("Visualizations -> Chart -> Editor -> Y-Axis Settings", () => {
|
||||
|
||||
describe("for heatmap", () => {
|
||||
test("Right Y Axis should not be available", () => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
const el = mount({
|
||||
globalSeriesType: "heatmap",
|
||||
yAxis: [{ type: "linear" }, { type: "linear", opposite: true }],
|
||||
102
viz-lib/src/visualizations/chart/Editor/YAxisSettings.tsx
Normal file
102
viz-lib/src/visualizations/chart/Editor/YAxisSettings.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from "react";
|
||||
import { Section, Switch } from "@/components/visualizations/editor";
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
|
||||
import AxisSettings from "./AxisSettings";
|
||||
|
||||
export default function YAxisSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const [leftYAxis, rightYAxis] = options.yAxis;
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section.Title>{!options.swappedAxes ? "Left Y Axis" : "X Axis"}</Section.Title>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<AxisSettings
|
||||
id="LeftYAxis"
|
||||
features={{ range: true }}
|
||||
options={leftYAxis}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(axis: any) => any' is not assignable to typ... Remove this comment to see the full error message
|
||||
onChange={(axis: any) => onOptionsChange({ yAxis: [axis, rightYAxis] })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{options.globalSeriesType !== "heatmap" && !options.swappedAxes && (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section.Title>Right Y Axis</Section.Title>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<AxisSettings
|
||||
id="RightYAxis"
|
||||
features={{ range: true }}
|
||||
options={rightYAxis}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(axis: any) => any' is not assignable to typ... Remove this comment to see the full error message
|
||||
onChange={(axis: any) => onOptionsChange({ yAxis: [leftYAxis, axis] })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
id="chart-editor-y-axis-align-at-zero"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.YAxis.AlignAtZero"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.alignYAxesAtZero}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(alignYAxesAtZero: any) => any' is not assig... Remove this comment to see the full error message
|
||||
onChange={(alignYAxesAtZero: any) => onOptionsChange({ alignYAxesAtZero })}>
|
||||
Align Y Axes at Zero
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{options.globalSeriesType === "heatmap" && (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
id="chart-editor-y-axis-sort"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.LeftYAxis.Sort"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.sortY}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(sortY: any) => any' is not assignable to ty... Remove this comment to see the full error message
|
||||
onChange={(sortY: any) => onOptionsChange({ sortY })}>
|
||||
Sort Values
|
||||
</Switch>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Switch
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
id="chart-editor-y-axis-reverse"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'never'.
|
||||
data-test="Chart.LeftYAxis.Reverse"
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any' is not assignable to type 'never'.
|
||||
defaultChecked={options.reverseY}
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '(reverseY: any) => any' is not assignable to... Remove this comment to see the full error message
|
||||
onChange={(reverseY: any) => onOptionsChange({ reverseY })}>
|
||||
Reverse Order
|
||||
</Switch>
|
||||
</Section>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
YAxisSettings.propTypes = EditorPropTypes;
|
||||
@@ -4,15 +4,15 @@ import enzyme from "enzyme";
|
||||
import getOptions from "../getOptions";
|
||||
import Editor from "./index";
|
||||
|
||||
function findByTestID(wrapper, testId) {
|
||||
function findByTestID(wrapper: any, testId: any) {
|
||||
return wrapper.find(`[data-test="${testId}"]`);
|
||||
}
|
||||
|
||||
function elementExists(wrapper, testId) {
|
||||
function elementExists(wrapper: any, testId: any) {
|
||||
return findByTestID(wrapper, testId).length > 0;
|
||||
}
|
||||
|
||||
function mount(options, data) {
|
||||
function mount(options: any, data: any) {
|
||||
options = getOptions(options);
|
||||
return enzyme.mount(<Editor visualizationName="Test" data={data} options={options} onOptionsChange={() => {}} />);
|
||||
}
|
||||
@@ -12,48 +12,50 @@ import CustomChartSettings from "./CustomChartSettings";
|
||||
|
||||
import "./editor.less";
|
||||
|
||||
const isCustomChart = options => options.globalSeriesType === "custom";
|
||||
const isPieChart = options => options.globalSeriesType === "pie";
|
||||
const isCustomChart = (options: any) => options.globalSeriesType === "custom";
|
||||
const isPieChart = (options: any) => options.globalSeriesType === "pie";
|
||||
|
||||
export default createTabbedEditor([
|
||||
{
|
||||
key: "General",
|
||||
title: "General",
|
||||
component: props => (
|
||||
<React.Fragment>
|
||||
<GeneralSettings {...props} />
|
||||
{isCustomChart(props.options) && <CustomChartSettings {...props} />}
|
||||
</React.Fragment>
|
||||
),
|
||||
component: (props: any) => <React.Fragment>
|
||||
<GeneralSettings {...props} />
|
||||
{isCustomChart(props.options) && <CustomChartSettings {...props} />}
|
||||
</React.Fragment>,
|
||||
},
|
||||
{
|
||||
key: "XAxis",
|
||||
title: ({ swappedAxes }) => (!swappedAxes ? "X Axis" : "Y Axis"),
|
||||
title: ({
|
||||
swappedAxes
|
||||
}: any) => (!swappedAxes ? "X Axis" : "Y Axis"),
|
||||
component: XAxisSettings,
|
||||
isAvailable: options => !isCustomChart(options) && !isPieChart(options),
|
||||
isAvailable: (options: any) => !isCustomChart(options) && !isPieChart(options),
|
||||
},
|
||||
{
|
||||
key: "YAxis",
|
||||
title: ({ swappedAxes }) => (!swappedAxes ? "Y Axis" : "X Axis"),
|
||||
title: ({
|
||||
swappedAxes
|
||||
}: any) => (!swappedAxes ? "Y Axis" : "X Axis"),
|
||||
component: YAxisSettings,
|
||||
isAvailable: options => !isCustomChart(options) && !isPieChart(options),
|
||||
isAvailable: (options: any) => !isCustomChart(options) && !isPieChart(options),
|
||||
},
|
||||
{
|
||||
key: "Series",
|
||||
title: "Series",
|
||||
component: SeriesSettings,
|
||||
isAvailable: options => !isCustomChart(options),
|
||||
isAvailable: (options: any) => !isCustomChart(options),
|
||||
},
|
||||
{
|
||||
key: "Colors",
|
||||
title: "Colors",
|
||||
component: ColorsSettings,
|
||||
isAvailable: options => !isCustomChart(options),
|
||||
isAvailable: (options: any) => !isCustomChart(options),
|
||||
},
|
||||
{
|
||||
key: "DataLabels",
|
||||
title: "Data Labels",
|
||||
component: DataLabelsSettings,
|
||||
isAvailable: options => !isCustomChart(options),
|
||||
isAvailable: (options: any) => !isCustomChart(options),
|
||||
},
|
||||
]);
|
||||
@@ -6,7 +6,10 @@ import resizeObserver from "@/services/resizeObserver";
|
||||
import getChartData from "../getChartData";
|
||||
import { Plotly, prepareCustomChartData, createCustomChartRenderer } from "../plotly";
|
||||
|
||||
export default function CustomPlotlyChart({ options, data }) {
|
||||
export default function CustomPlotlyChart({
|
||||
options,
|
||||
data
|
||||
}: any) {
|
||||
const [container, setContainer] = useState(null);
|
||||
|
||||
const renderCustomChart = useMemo(() => createCustomChartRenderer(options.customCode, options.enableConsoleLogs), [
|
||||
@@ -20,6 +23,7 @@ export default function CustomPlotlyChart({ options, data }) {
|
||||
if (container) {
|
||||
const unwatch = resizeObserver(container, () => {
|
||||
// Clear existing data with blank data for succeeding codeCall adds data to existing plot.
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message
|
||||
Plotly.purge(container);
|
||||
renderCustomChart(plotlyData.x, plotlyData.ys, container, Plotly);
|
||||
});
|
||||
@@ -30,10 +34,12 @@ export default function CustomPlotlyChart({ options, data }) {
|
||||
// Cleanup when component destroyed
|
||||
useEffect(() => {
|
||||
if (container) {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'null' is not assignable to param... Remove this comment to see the full error message
|
||||
return () => Plotly.purge(container);
|
||||
}
|
||||
}, [container]);
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Dispatch<SetStateAction<null>>' is not assig... Remove this comment to see the full error message
|
||||
return <div className="chart-visualization-container" ref={setContainer} />;
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
import React from "react";
|
||||
export interface PlotlyChartProps {
|
||||
data: {
|
||||
rows: any[];
|
||||
columns: any[];
|
||||
}
|
||||
options: object;
|
||||
}
|
||||
declare const PlotlyChart: React.FC<PlotlyChartProps>;
|
||||
export default PlotlyChart;
|
||||
@@ -6,16 +6,29 @@ import { visualizationsSettings } from "@/visualizations/visualizationsSettings"
|
||||
import getChartData from "../getChartData";
|
||||
import initChart from "./initChart";
|
||||
|
||||
export default function PlotlyChart({ options, data }) {
|
||||
export interface PlotlyChartProps {
|
||||
data: {
|
||||
rows: any[];
|
||||
columns: any[];
|
||||
}
|
||||
options: object;
|
||||
}
|
||||
|
||||
export default function PlotlyChart({
|
||||
options,
|
||||
data
|
||||
}: PlotlyChartProps) {
|
||||
const [container, setContainer] = useState(null);
|
||||
const [chart, setChart] = useState(null);
|
||||
|
||||
const errorHandler = useContext(ErrorBoundaryContext);
|
||||
const errorHandlerRef = useRef();
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ handleError: (error: any) => void; reset: ... Remove this comment to see the full error message
|
||||
errorHandlerRef.current = errorHandler;
|
||||
|
||||
const isMobile = useMedia({ maxWidth: 768 });
|
||||
const isMobileRef = useRef();
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'boolean' is not assignable to type 'undefine... Remove this comment to see the full error message
|
||||
isMobileRef.current = isMobile;
|
||||
|
||||
useEffect(() => {
|
||||
@@ -23,7 +36,8 @@ export default function PlotlyChart({ options, data }) {
|
||||
let isDestroyed = false;
|
||||
|
||||
const chartData = getChartData(data.rows, options);
|
||||
const _chart = initChart(container, options, chartData, visualizationsSettings, error => {
|
||||
const _chart = initChart(container, options, chartData, visualizationsSettings, (error: any) => {
|
||||
// @ts-expect-error ts-migrate(2532) FIXME: Object is possibly 'undefined'.
|
||||
errorHandlerRef.current.handleError(error);
|
||||
});
|
||||
_chart.initialized.then(() => {
|
||||
@@ -40,10 +54,12 @@ export default function PlotlyChart({ options, data }) {
|
||||
|
||||
useEffect(() => {
|
||||
if (chart) {
|
||||
// @ts-expect-error ts-migrate(2531) FIXME: Object is possibly 'null'.
|
||||
chart.setZoomEnabled(!isMobile);
|
||||
}
|
||||
}, [chart, isMobile]);
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Dispatch<SetStateAction<null>>' is not assig... Remove this comment to see the full error message
|
||||
return <div className="chart-visualization-container" ref={setContainer} />;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ import { visualizationsSettings } from "@/visualizations/visualizationsSettings"
|
||||
|
||||
import "./renderer.less";
|
||||
|
||||
export default function Renderer({ options, ...props }) {
|
||||
export default function Renderer({
|
||||
options,
|
||||
...props
|
||||
}: any) {
|
||||
if (options.globalSeriesType === "custom" && visualizationsSettings.allowCustomJSVisualizations) {
|
||||
return <CustomPlotlyChart options={options} {...props} />;
|
||||
}
|
||||
@@ -2,8 +2,8 @@ import { isArray, isObject, isString, isFunction, startsWith, reduce, merge, map
|
||||
import resizeObserver from "@/services/resizeObserver";
|
||||
import { Plotly, prepareData, prepareLayout, updateData, updateAxes, updateChartSize } from "../plotly";
|
||||
|
||||
function createErrorHandler(errorHandler) {
|
||||
return error => {
|
||||
function createErrorHandler(errorHandler: any) {
|
||||
return (error: any) => {
|
||||
// This error happens only when chart width is 20px and looks that
|
||||
// it's safe to just ignore it: 1px less or more and chart will get fixed.
|
||||
if (isString(error) && startsWith(error, "ax.dtick error")) {
|
||||
@@ -21,16 +21,17 @@ function createErrorHandler(errorHandler) {
|
||||
// `.process()` merges all updates into a single object and calls `Plotly.relayout()`. After that
|
||||
// it calls all callbacks, collects their return values and does another loop if needed.
|
||||
function initPlotUpdater() {
|
||||
let actions = [];
|
||||
let actions: any = [];
|
||||
|
||||
const updater = {
|
||||
append(action) {
|
||||
append(action: any) {
|
||||
if (isArray(action) && isObject(action[0])) {
|
||||
actions.push(action);
|
||||
}
|
||||
return updater;
|
||||
},
|
||||
process(plotlyElement) {
|
||||
// @ts-expect-error ts-migrate(7023) FIXME: 'process' implicitly has return type 'any' because... Remove this comment to see the full error message
|
||||
process(plotlyElement: any) {
|
||||
if (actions.length > 0) {
|
||||
const updates = reduce(actions, (updates, action) => merge(updates, action[0]), {});
|
||||
const handlers = map(actions, action => (isFunction(action[1]) ? action[1] : () => null));
|
||||
@@ -48,7 +49,7 @@ function initPlotUpdater() {
|
||||
return updater;
|
||||
}
|
||||
|
||||
export default function initChart(container, options, data, additionalOptions, onError) {
|
||||
export default function initChart(container: any, options: any, data: any, additionalOptions: any, onError: any) {
|
||||
const handleError = createErrorHandler(onError);
|
||||
|
||||
const plotlyOptions = {
|
||||
@@ -57,6 +58,7 @@ export default function initChart(container, options, data, additionalOptions, o
|
||||
};
|
||||
|
||||
if (additionalOptions.hidePlotlyModeBar) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'displayModeBar' does not exist on type '... Remove this comment to see the full error message
|
||||
plotlyOptions.displayModeBar = false;
|
||||
}
|
||||
|
||||
@@ -67,7 +69,8 @@ export default function initChart(container, options, data, additionalOptions, o
|
||||
|
||||
let updater = initPlotUpdater();
|
||||
|
||||
function createSafeFunction(fn) {
|
||||
function createSafeFunction(fn: any) {
|
||||
// @ts-expect-error ts-migrate(7019) FIXME: Rest parameter 'args' implicitly has an 'any[]' ty... Remove this comment to see the full error message
|
||||
return (...args) => {
|
||||
if (!isDestroyed) {
|
||||
try {
|
||||
@@ -95,9 +98,10 @@ export default function initChart(container, options, data, additionalOptions, o
|
||||
createSafeFunction(() => {
|
||||
container.on(
|
||||
"plotly_restyle",
|
||||
createSafeFunction(updates => {
|
||||
createSafeFunction((updates: any) => {
|
||||
// This event is triggered if some plotly data/layout has changed.
|
||||
// We need to catch only changes of traces visibility to update stacking
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'visible' does not exist on type 'object'... Remove this comment to see the full error message
|
||||
if (isArray(updates) && isObject(updates[0]) && updates[0].visible) {
|
||||
updateData(plotlyData, options);
|
||||
updater.append(updateAxes(container, plotlyData, plotlyLayout, options)).process(container);
|
||||
@@ -117,10 +121,12 @@ export default function initChart(container, options, data, additionalOptions, o
|
||||
)
|
||||
.catch(handleError);
|
||||
|
||||
// @ts-expect-error ts-migrate(7022) FIXME: 'result' implicitly has type 'any' because it does... Remove this comment to see the full error message
|
||||
const result = {
|
||||
initialized: promise.then(() => result),
|
||||
setZoomEnabled: createSafeFunction(allowZoom => {
|
||||
setZoomEnabled: createSafeFunction((allowZoom: any) => {
|
||||
const layoutUpdates = { dragmode: allowZoom ? "zoom" : false };
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type '{ dragmode: string | boolean; }'... Remove this comment to see the full error message
|
||||
return Plotly.relayout(container, layoutUpdates);
|
||||
}),
|
||||
destroy: createSafeFunction(() => {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { isNil, isObject, each, forOwn, sortBy, values } from "lodash";
|
||||
|
||||
function addPointToSeries(point, seriesCollection, seriesName) {
|
||||
function addPointToSeries(point: any, seriesCollection: any, seriesName: any) {
|
||||
if (seriesCollection[seriesName] === undefined) {
|
||||
seriesCollection[seriesName] = {
|
||||
name: seriesName,
|
||||
@@ -12,7 +12,7 @@ function addPointToSeries(point, seriesCollection, seriesName) {
|
||||
seriesCollection[seriesName].data.push(point);
|
||||
}
|
||||
|
||||
export default function getChartData(data, options) {
|
||||
export default function getChartData(data: any, options: any) {
|
||||
const series = {};
|
||||
|
||||
const mappings = options.columnMapping;
|
||||
@@ -22,9 +22,9 @@ export default function getChartData(data, options) {
|
||||
let seriesName = null;
|
||||
let xValue = 0;
|
||||
const yValues = {};
|
||||
let eValue = null;
|
||||
let sizeValue = null;
|
||||
let zValue = null;
|
||||
let eValue: any = null;
|
||||
let sizeValue: any = null;
|
||||
let zValue: any = null;
|
||||
|
||||
forOwn(row, (value, definition) => {
|
||||
definition = "" + definition;
|
||||
@@ -38,14 +38,18 @@ export default function getChartData(data, options) {
|
||||
|
||||
if (type === "x") {
|
||||
xValue = value;
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
point[type] = value;
|
||||
}
|
||||
if (type === "y") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
yValues[name] = value;
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
point[type] = value;
|
||||
}
|
||||
if (type === "yError") {
|
||||
eValue = value;
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
point[type] = value;
|
||||
}
|
||||
|
||||
@@ -54,11 +58,13 @@ export default function getChartData(data, options) {
|
||||
}
|
||||
|
||||
if (type === "size") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
point[type] = value;
|
||||
sizeValue = value;
|
||||
}
|
||||
|
||||
if (type === "zVal") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
point[type] = value;
|
||||
zValue = value;
|
||||
}
|
||||
@@ -70,16 +76,20 @@ export default function getChartData(data, options) {
|
||||
|
||||
if (isNil(seriesName)) {
|
||||
each(yValues, (yValue, ySeriesName) => {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type '{ x: number; y: never; $raw: any; }' is not ... Remove this comment to see the full error message
|
||||
point = { x: xValue, y: yValue, $raw: point.$raw };
|
||||
if (eValue !== null) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yError' does not exist on type '{ $raw: ... Remove this comment to see the full error message
|
||||
point.yError = eValue;
|
||||
}
|
||||
|
||||
if (sizeValue !== null) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'size' does not exist on type '{ $raw: an... Remove this comment to see the full error message
|
||||
point.size = sizeValue;
|
||||
}
|
||||
|
||||
if (zValue !== null) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'zVal' does not exist on type '{ $raw: an... Remove this comment to see the full error message
|
||||
point.zVal = zValue;
|
||||
}
|
||||
addPointToSeries(point, series, ySeriesName);
|
||||
@@ -26,7 +26,7 @@ const DEFAULT_OPTIONS = {
|
||||
missingValuesAsZero: true,
|
||||
};
|
||||
|
||||
export default function getOptions(options) {
|
||||
export default function getOptions(options: any) {
|
||||
const result = merge(
|
||||
{},
|
||||
DEFAULT_OPTIONS,
|
||||
@@ -1,14 +1,17 @@
|
||||
import { each } from "lodash";
|
||||
import { normalizeValue } from "./utils";
|
||||
|
||||
export function prepareCustomChartData(series) {
|
||||
const x = [];
|
||||
export function prepareCustomChartData(series: any) {
|
||||
const x: any = [];
|
||||
const ys = {};
|
||||
|
||||
each(series, ({ name, data }) => {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
ys[name] = [];
|
||||
each(data, point => {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2-3 arguments, but got 1.
|
||||
x.push(normalizeValue(point.x));
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
ys[name].push(normalizeValue(point.y));
|
||||
});
|
||||
});
|
||||
@@ -16,10 +19,11 @@ export function prepareCustomChartData(series) {
|
||||
return { x, ys };
|
||||
}
|
||||
|
||||
export function createCustomChartRenderer(code, logErrorsToConsole = false) {
|
||||
export function createCustomChartRenderer(code: any, logErrorsToConsole = false) {
|
||||
// Create a function from custom code; catch syntax errors
|
||||
let render = () => {};
|
||||
try {
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'Function' is not assignable to type '() => v... Remove this comment to see the full error message
|
||||
render = new Function("x, ys, element, Plotly", code); // eslint-disable-line no-new-func
|
||||
} catch (err) {
|
||||
if (logErrorsToConsole) {
|
||||
@@ -28,8 +32,9 @@ export function createCustomChartRenderer(code, logErrorsToConsole = false) {
|
||||
}
|
||||
|
||||
// Return function that will invoke custom code; catch runtime errors
|
||||
return (x, ys, element, Plotly) => {
|
||||
return (x: any, ys: any, element: any, Plotly: any) => {
|
||||
try {
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 0 arguments, but got 4.
|
||||
render(x, ys, element, Plotly);
|
||||
} catch (err) {
|
||||
if (logErrorsToConsole) {
|
||||
@@ -1,29 +0,0 @@
|
||||
import Plotly from "plotly.js/lib/core";
|
||||
import bar from "plotly.js/lib/bar";
|
||||
import pie from "plotly.js/lib/pie";
|
||||
import histogram from "plotly.js/lib/histogram";
|
||||
import box from "plotly.js/lib/box";
|
||||
import heatmap from "plotly.js/lib/heatmap";
|
||||
|
||||
import prepareData from "./prepareData";
|
||||
import prepareLayout from "./prepareLayout";
|
||||
import updateData from "./updateData";
|
||||
import updateAxes from "./updateAxes";
|
||||
import updateChartSize from "./updateChartSize";
|
||||
import { prepareCustomChartData, createCustomChartRenderer } from "./customChartUtils";
|
||||
|
||||
Plotly.register([bar, pie, histogram, box, heatmap]);
|
||||
Plotly.setPlotConfig({
|
||||
modeBarButtonsToRemove: ["sendDataToCloud"],
|
||||
});
|
||||
|
||||
export {
|
||||
Plotly,
|
||||
prepareData,
|
||||
prepareLayout,
|
||||
updateData,
|
||||
updateAxes,
|
||||
updateChartSize,
|
||||
prepareCustomChartData,
|
||||
createCustomChartRenderer,
|
||||
};
|
||||
36
viz-lib/src/visualizations/chart/plotly/index.ts
Normal file
36
viz-lib/src/visualizations/chart/plotly/index.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import Plotly from "plotly.js/lib/core";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import bar from "plotly.js/lib/bar";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import pie from "plotly.js/lib/pie";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import histogram from "plotly.js/lib/histogram";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import box from "plotly.js/lib/box";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import heatmap from "plotly.js/lib/heatmap";
|
||||
|
||||
import prepareData from "./prepareData";
|
||||
import prepareLayout from "./prepareLayout";
|
||||
import updateData from "./updateData";
|
||||
import updateAxes from "./updateAxes";
|
||||
import updateChartSize from "./updateChartSize";
|
||||
import { prepareCustomChartData, createCustomChartRenderer } from "./customChartUtils";
|
||||
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'register' does not exist on type 'typeof... Remove this comment to see the full error message
|
||||
Plotly.register([bar, pie, histogram, box, heatmap]);
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'setPlotConfig' does not exist on type 't... Remove this comment to see the full error message
|
||||
Plotly.setPlotConfig({
|
||||
modeBarButtonsToRemove: ["sendDataToCloud"],
|
||||
});
|
||||
|
||||
export {
|
||||
Plotly,
|
||||
prepareData,
|
||||
prepareLayout,
|
||||
updateData,
|
||||
updateAxes,
|
||||
updateChartSize,
|
||||
prepareCustomChartData,
|
||||
createCustomChartRenderer,
|
||||
};
|
||||
@@ -1,8 +1,11 @@
|
||||
/* eslint-disable global-require, import/no-unresolved */
|
||||
import prepareData from "./prepareData";
|
||||
|
||||
function cleanSeries(series) {
|
||||
return series.map(({ sourceData, ...rest }) => rest);
|
||||
function cleanSeries(series: any) {
|
||||
return series.map(({
|
||||
sourceData,
|
||||
...rest
|
||||
}: any) => rest);
|
||||
}
|
||||
|
||||
describe("Visualizations", () => {
|
||||
@@ -3,11 +3,12 @@ import prepareHeatmapData from "./prepareHeatmapData";
|
||||
import prepareDefaultData from "./prepareDefaultData";
|
||||
import updateData from "./updateData";
|
||||
|
||||
export default function prepareData(seriesList, options) {
|
||||
export default function prepareData(seriesList: any, options: any) {
|
||||
switch (options.globalSeriesType) {
|
||||
case "pie":
|
||||
return updateData(preparePieData(seriesList, options), options);
|
||||
case "heatmap":
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 1.
|
||||
return updateData(prepareHeatmapData(seriesList, options, options));
|
||||
default:
|
||||
return updateData(prepareDefaultData(seriesList, options), options);
|
||||
@@ -3,11 +3,11 @@ import chooseTextColorForBackground from "@/lib/chooseTextColorForBackground";
|
||||
import { ColorPaletteArray } from "@/visualizations/ColorPalette";
|
||||
import { cleanNumber, normalizeValue, getSeriesAxis } from "./utils";
|
||||
|
||||
function getSeriesColor(seriesOptions, seriesIndex) {
|
||||
function getSeriesColor(seriesOptions: any, seriesIndex: any) {
|
||||
return seriesOptions.color || ColorPaletteArray[seriesIndex % ColorPaletteArray.length];
|
||||
}
|
||||
|
||||
function getHoverInfoPattern(options) {
|
||||
function getHoverInfoPattern(options: any) {
|
||||
const hasX = /{{\s*@@x\s*}}/.test(options.textFormat);
|
||||
const hasName = /{{\s*@@name\s*}}/.test(options.textFormat);
|
||||
let result = "text";
|
||||
@@ -16,7 +16,7 @@ function getHoverInfoPattern(options) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function prepareBarSeries(series, options, additionalOptions) {
|
||||
function prepareBarSeries(series: any, options: any, additionalOptions: any) {
|
||||
series.type = "bar";
|
||||
series.offsetgroup = toString(additionalOptions.index);
|
||||
if (options.showDataLabels) {
|
||||
@@ -25,24 +25,27 @@ function prepareBarSeries(series, options, additionalOptions) {
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareLineSeries(series, options) {
|
||||
function prepareLineSeries(series: any, options: any) {
|
||||
series.mode = "lines" + (options.showDataLabels ? "+text" : "");
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareAreaSeries(series, options) {
|
||||
function prepareAreaSeries(series: any, options: any) {
|
||||
series.mode = "lines" + (options.showDataLabels ? "+text" : "");
|
||||
series.fill = options.series.stacking ? "tonexty" : "tozeroy";
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareScatterSeries(series, options) {
|
||||
function prepareScatterSeries(series: any, options: any) {
|
||||
series.type = "scatter";
|
||||
series.mode = "markers" + (options.showDataLabels ? "+text" : "");
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareBubbleSeries(series, options, { seriesColor, data }) {
|
||||
function prepareBubbleSeries(series: any, options: any, {
|
||||
seriesColor,
|
||||
data
|
||||
}: any) {
|
||||
const coefficient = options.coefficient || 1;
|
||||
series.mode = "markers";
|
||||
series.marker = {
|
||||
@@ -53,7 +56,9 @@ function prepareBubbleSeries(series, options, { seriesColor, data }) {
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareBoxSeries(series, options, { seriesColor }) {
|
||||
function prepareBoxSeries(series: any, options: any, {
|
||||
seriesColor
|
||||
}: any) {
|
||||
series.type = "box";
|
||||
series.mode = "markers";
|
||||
|
||||
@@ -71,7 +76,7 @@ function prepareBoxSeries(series, options, { seriesColor }) {
|
||||
return series;
|
||||
}
|
||||
|
||||
function prepareSeries(series, options, additionalOptions) {
|
||||
function prepareSeries(series: any, options: any, additionalOptions: any) {
|
||||
const { hoverInfoPattern, index } = additionalOptions;
|
||||
|
||||
const seriesOptions = extend({ type: options.globalSeriesType, yAxis: 0 }, options.seriesOptions[series.name]);
|
||||
@@ -85,15 +90,15 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
// for other types `y` is always number
|
||||
const cleanYValue = includes(["bubble", "scatter"], seriesOptions.type)
|
||||
? normalizeValue
|
||||
: v => {
|
||||
: (v: any) => {
|
||||
v = cleanNumber(v);
|
||||
return options.missingValuesAsZero && isNil(v) ? 0.0 : v;
|
||||
};
|
||||
|
||||
const sourceData = new Map();
|
||||
const xValues = [];
|
||||
const yValues = [];
|
||||
const yErrorValues = [];
|
||||
const xValues: any = [];
|
||||
const yValues: any = [];
|
||||
const yErrorValues: any = [];
|
||||
each(data, row => {
|
||||
const x = normalizeValue(row.x, options.xAxis.type); // number/datetime/category
|
||||
const y = cleanYValue(row.y, seriesYAxis === "y2" ? options.yAxis[1].type : options.yAxis[0].type); // depends on series type!
|
||||
@@ -136,10 +141,13 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
case "column":
|
||||
return prepareBarSeries(plotlySeries, options, additionalOptions);
|
||||
case "line":
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 3.
|
||||
return prepareLineSeries(plotlySeries, options, additionalOptions);
|
||||
case "area":
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 3.
|
||||
return prepareAreaSeries(plotlySeries, options, additionalOptions);
|
||||
case "scatter":
|
||||
// @ts-expect-error ts-migrate(2554) FIXME: Expected 2 arguments, but got 3.
|
||||
return prepareScatterSeries(plotlySeries, options, additionalOptions);
|
||||
case "bubble":
|
||||
return prepareBubbleSeries(plotlySeries, options, additionalOptions);
|
||||
@@ -150,7 +158,7 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function prepareDefaultData(seriesList, options) {
|
||||
export default function prepareDefaultData(seriesList: any, options: any) {
|
||||
const additionalOptions = {
|
||||
hoverInfoPattern: getHoverInfoPattern(options),
|
||||
};
|
||||
@@ -12,7 +12,7 @@ const defaultColorScheme = [
|
||||
[1, "#e92827"],
|
||||
];
|
||||
|
||||
function prepareSeries(series, options, additionalOptions) {
|
||||
function prepareSeries(series: any, options: any, additionalOptions: any) {
|
||||
const { colorScheme, formatNumber } = additionalOptions;
|
||||
|
||||
const plotlySeries = {
|
||||
@@ -24,7 +24,9 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
colorscale: colorScheme,
|
||||
};
|
||||
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any[]' is not assignable to type 'never[]'.
|
||||
plotlySeries.x = uniq(map(series.data, v => v.x));
|
||||
// @ts-expect-error ts-migrate(2322) FIXME: Type 'any[]' is not assignable to type 'never[]'.
|
||||
plotlySeries.y = uniq(map(series.data, v => v.y));
|
||||
|
||||
if (options.sortX) {
|
||||
@@ -69,14 +71,18 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
if (isFinite(zMax) && options.showDataLabels) {
|
||||
dataLabels.x.push(plotlySeries.x[j]);
|
||||
dataLabels.y.push(plotlySeries.y[i]);
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any' is not assignable to parame... Remove this comment to see the full error message
|
||||
dataLabels.text.push(formatNumber(zValue));
|
||||
if (options.colorScheme && options.colorScheme === "Custom...") {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
dataLabels.textfont.color.push("white");
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'string' is not assignable to par... Remove this comment to see the full error message
|
||||
dataLabels.textfont.color.push(zValue / zMax < 0.25 ? "white" : "black");
|
||||
}
|
||||
}
|
||||
}
|
||||
// @ts-expect-error ts-migrate(2345) FIXME: Argument of type 'any[]' is not assignable to para... Remove this comment to see the full error message
|
||||
plotlySeries.z.push(item);
|
||||
}
|
||||
|
||||
@@ -86,7 +92,7 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
return [plotlySeries];
|
||||
}
|
||||
|
||||
export default function prepareHeatmapData(seriesList, options) {
|
||||
export default function prepareHeatmapData(seriesList: any, options: any) {
|
||||
let colorScheme = [];
|
||||
|
||||
if (!options.colorScheme) {
|
||||
@@ -1,11 +1,11 @@
|
||||
import { isObject, isUndefined, filter, map } from "lodash";
|
||||
import { getPieDimensions } from "./preparePieData";
|
||||
|
||||
function getAxisTitle(axis) {
|
||||
function getAxisTitle(axis: any) {
|
||||
return isObject(axis.title) ? axis.title.text : null;
|
||||
}
|
||||
|
||||
function getAxisScaleType(axis) {
|
||||
function getAxisScaleType(axis: any) {
|
||||
switch (axis.type) {
|
||||
case "datetime":
|
||||
return "date";
|
||||
@@ -16,7 +16,7 @@ function getAxisScaleType(axis) {
|
||||
}
|
||||
}
|
||||
|
||||
function prepareXAxis(axisOptions, additionalOptions) {
|
||||
function prepareXAxis(axisOptions: any, additionalOptions: any) {
|
||||
const axis = {
|
||||
title: getAxisTitle(axisOptions),
|
||||
type: getAxisScaleType(axisOptions),
|
||||
@@ -25,20 +25,23 @@ function prepareXAxis(axisOptions, additionalOptions) {
|
||||
|
||||
if (additionalOptions.sortX && axis.type === "category") {
|
||||
if (additionalOptions.reverseX) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryorder' does not exist on type '{... Remove this comment to see the full error message
|
||||
axis.categoryorder = "category descending";
|
||||
} else {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'categoryorder' does not exist on type '{... Remove this comment to see the full error message
|
||||
axis.categoryorder = "category ascending";
|
||||
}
|
||||
}
|
||||
|
||||
if (!isUndefined(axisOptions.labels)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'showticklabels' does not exist on type '... Remove this comment to see the full error message
|
||||
axis.showticklabels = axisOptions.labels.enabled;
|
||||
}
|
||||
|
||||
return axis;
|
||||
}
|
||||
|
||||
function prepareYAxis(axisOptions) {
|
||||
function prepareYAxis(axisOptions: any) {
|
||||
return {
|
||||
title: getAxisTitle(axisOptions),
|
||||
type: getAxisScaleType(axisOptions),
|
||||
@@ -48,7 +51,7 @@ function prepareYAxis(axisOptions) {
|
||||
};
|
||||
}
|
||||
|
||||
function preparePieLayout(layout, options, data) {
|
||||
function preparePieLayout(layout: any, options: any, data: any) {
|
||||
const hasName = /{{\s*@@name\s*}}/.test(options.textFormat);
|
||||
|
||||
const { cellsInRow, cellWidth, cellHeight, xPadding } = getPieDimensions(data);
|
||||
@@ -58,7 +61,9 @@ function preparePieLayout(layout, options, data) {
|
||||
} else {
|
||||
layout.annotations = filter(
|
||||
map(data, (series, index) => {
|
||||
// @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message
|
||||
const xPosition = (index % cellsInRow) * cellWidth;
|
||||
// @ts-expect-error ts-migrate(2362) FIXME: The left-hand side of an arithmetic operation must... Remove this comment to see the full error message
|
||||
const yPosition = Math.floor(index / cellsInRow) * cellHeight;
|
||||
return {
|
||||
x: xPosition + (cellWidth - xPadding) / 2,
|
||||
@@ -75,8 +80,8 @@ function preparePieLayout(layout, options, data) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
function prepareDefaultLayout(layout, options, data) {
|
||||
const y2Series = data.filter(s => s.yaxis === "y2");
|
||||
function prepareDefaultLayout(layout: any, options: any, data: any) {
|
||||
const y2Series = data.filter((s: any) => s.yaxis === "y2");
|
||||
|
||||
layout.xaxis = prepareXAxis(options.xAxis, options);
|
||||
|
||||
@@ -94,14 +99,14 @@ function prepareDefaultLayout(layout, options, data) {
|
||||
return layout;
|
||||
}
|
||||
|
||||
function prepareBoxLayout(layout, options, data) {
|
||||
function prepareBoxLayout(layout: any, options: any, data: any) {
|
||||
layout = prepareDefaultLayout(layout, options, data);
|
||||
layout.boxmode = "group";
|
||||
layout.boxgroupgap = 0.5;
|
||||
return layout;
|
||||
}
|
||||
|
||||
export default function prepareLayout(element, options, data) {
|
||||
export default function prepareLayout(element: any, options: any, data: any) {
|
||||
const layout = {
|
||||
margin: { l: 10, r: 10, b: 5, t: 20, pad: 4 },
|
||||
// plot size should be at least 5x5px
|
||||
@@ -5,7 +5,7 @@ import { ColorPaletteArray } from "@/visualizations/ColorPalette";
|
||||
|
||||
import { cleanNumber, normalizeValue } from "./utils";
|
||||
|
||||
export function getPieDimensions(series) {
|
||||
export function getPieDimensions(series: any) {
|
||||
const rows = series.length > 2 ? 2 : 1;
|
||||
const cellsInRow = Math.ceil(series.length / rows);
|
||||
const cellWidth = 1 / cellsInRow;
|
||||
@@ -16,14 +16,14 @@ export function getPieDimensions(series) {
|
||||
return { rows, cellsInRow, cellWidth, cellHeight, xPadding, yPadding };
|
||||
}
|
||||
|
||||
function getPieHoverInfoPattern(options) {
|
||||
function getPieHoverInfoPattern(options: any) {
|
||||
const hasX = /{{\s*@@x\s*}}/.test(options.textFormat);
|
||||
let result = "text";
|
||||
if (!hasX) result += "+label";
|
||||
return result;
|
||||
}
|
||||
|
||||
function prepareSeries(series, options, additionalOptions) {
|
||||
function prepareSeries(series: any, options: any, additionalOptions: any) {
|
||||
const {
|
||||
cellWidth,
|
||||
cellHeight,
|
||||
@@ -41,8 +41,8 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
const xPosition = (index % cellsInRow) * cellWidth;
|
||||
const yPosition = Math.floor(index / cellsInRow) * cellHeight;
|
||||
|
||||
const labels = [];
|
||||
const values = [];
|
||||
const labels: any = [];
|
||||
const values: any = [];
|
||||
const sourceData = new Map();
|
||||
const seriesTotal = reduce(
|
||||
series.data,
|
||||
@@ -94,8 +94,9 @@ function prepareSeries(series, options, additionalOptions) {
|
||||
};
|
||||
}
|
||||
|
||||
export default function preparePieData(seriesList, options) {
|
||||
export default function preparePieData(seriesList: any, options: any) {
|
||||
// we will use this to assign colors for values that have no explicitly set color
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'scale' does not exist on type 'typeof im... Remove this comment to see the full error message
|
||||
const getDefaultColor = d3.scale
|
||||
.ordinal()
|
||||
.domain([])
|
||||
@@ -103,6 +104,7 @@ export default function preparePieData(seriesList, options) {
|
||||
const valuesColors = {};
|
||||
each(options.valuesOptions, (item, key) => {
|
||||
if (isString(item.color) && item.color !== "") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
valuesColors[key] = item.color;
|
||||
}
|
||||
});
|
||||
@@ -111,7 +113,8 @@ export default function preparePieData(seriesList, options) {
|
||||
...getPieDimensions(seriesList),
|
||||
hasX: includes(options.columnMapping, "x"),
|
||||
hoverInfoPattern: getPieHoverInfoPattern(options),
|
||||
getValueColor: v => valuesColors[v] || getDefaultColor(v),
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
getValueColor: (v: any) => valuesColors[v] || getDefaultColor(v),
|
||||
};
|
||||
|
||||
return map(seriesList, (series, index) => prepareSeries(series, options, { ...additionalOptions, index }));
|
||||
@@ -1,14 +1,14 @@
|
||||
import { isObject, isNumber, each } from "lodash";
|
||||
|
||||
function calculateAxisRange(range, min, max) {
|
||||
function calculateAxisRange(range: any, min: any, max: any) {
|
||||
return [isNumber(min) ? min : range[0], isNumber(max) ? max : range[1]];
|
||||
}
|
||||
|
||||
function calculateAbsoluteDiff(value, totalRange, percentageDiff) {
|
||||
function calculateAbsoluteDiff(value: any, totalRange: any, percentageDiff: any) {
|
||||
return (percentageDiff * totalRange) / (1 - Math.abs(value) / totalRange - percentageDiff);
|
||||
}
|
||||
|
||||
function alignYAxesAtZero(axisA, axisB) {
|
||||
function alignYAxesAtZero(axisA: any, axisB: any) {
|
||||
// Make sure the origin is included in both axes
|
||||
axisA.range[1] = Math.max(0, axisA.range[1]);
|
||||
axisB.range[1] = Math.max(0, axisB.range[1]);
|
||||
@@ -40,9 +40,10 @@ function alignYAxesAtZero(axisA, axisB) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function updateAxes(plotlyElement, seriesList, layout, options) {
|
||||
export default function updateAxes(plotlyElement: any, seriesList: any, layout: any, options: any) {
|
||||
const updates = {};
|
||||
if (isObject(layout.yaxis)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
updates.yaxis = {
|
||||
...layout.yaxis,
|
||||
autorange: true,
|
||||
@@ -50,6 +51,7 @@ export default function updateAxes(plotlyElement, seriesList, layout, options) {
|
||||
};
|
||||
}
|
||||
if (isObject(layout.yaxis2)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis2' does not exist on type '{}'.
|
||||
updates.yaxis2 = {
|
||||
...layout.yaxis2,
|
||||
autorange: true,
|
||||
@@ -64,14 +66,18 @@ export default function updateAxes(plotlyElement, seriesList, layout, options) {
|
||||
if (isObject(layout.yaxis)) {
|
||||
const axisOptions = options.yAxis[0];
|
||||
const defaultRange = plotlyElement.layout.yaxis.range;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
updates.yaxis.autorange = false;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
updates.yaxis.range = calculateAxisRange(defaultRange, axisOptions.rangeMin, axisOptions.rangeMax);
|
||||
}
|
||||
|
||||
if (isObject(layout.yaxis2)) {
|
||||
const axisOptions = options.yAxis[1];
|
||||
const defaultRange = plotlyElement.layout.yaxis2.range;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis2' does not exist on type '{}'.
|
||||
updates.yaxis2.autorange = false;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis2' does not exist on type '{}'.
|
||||
updates.yaxis2.range = calculateAxisRange(defaultRange, axisOptions.rangeMin, axisOptions.rangeMax);
|
||||
}
|
||||
|
||||
@@ -85,19 +91,24 @@ export default function updateAxes(plotlyElement, seriesList, layout, options) {
|
||||
});
|
||||
|
||||
const { xaxis } = layout;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
const { yaxis, yaxis2 } = updates;
|
||||
|
||||
if (isObject(xaxis) && isObject(yaxis)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'xaxis' does not exist on type '{}'.
|
||||
updates.xaxis = yaxis;
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
updates.yaxis = xaxis;
|
||||
}
|
||||
if (isObject(yaxis2)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis2' does not exist on type '{}'.
|
||||
updates.yaxis2 = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Align Y axes
|
||||
if (options.alignYAxesAtZero && isObject(layout.yaxis) && isObject(layout.yaxis2)) {
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'yaxis' does not exist on type '{}'.
|
||||
alignYAxesAtZero(updates.yaxis, updates.yaxis2);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { find, pick, extend } from "lodash";
|
||||
|
||||
function fixLegendContainer(plotlyElement) {
|
||||
function fixLegendContainer(plotlyElement: any) {
|
||||
const legend = plotlyElement.querySelector(".legend");
|
||||
if (legend) {
|
||||
let node = legend.parentNode;
|
||||
@@ -14,7 +14,7 @@ function fixLegendContainer(plotlyElement) {
|
||||
}
|
||||
}
|
||||
|
||||
function placeLegendNextToPlot(plotlyElement, layout) {
|
||||
function placeLegendNextToPlot(plotlyElement: any, layout: any) {
|
||||
const transformName = find(
|
||||
["transform", "WebkitTransform", "MozTransform", "MsTransform", "OTransform"],
|
||||
prop => prop in plotlyElement.style
|
||||
@@ -32,13 +32,14 @@ function placeLegendNextToPlot(plotlyElement, layout) {
|
||||
|
||||
const legend = plotlyElement.querySelector(".legend");
|
||||
if (legend) {
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'undefined' cannot be used as an index type.
|
||||
legend.style[transformName] = null;
|
||||
}
|
||||
|
||||
return [pick(layout, ["width", "height", "legend"]), null]; // no further updates
|
||||
}
|
||||
|
||||
function placeLegendBelowPlot(plotlyElement, layout) {
|
||||
function placeLegendBelowPlot(plotlyElement: any, layout: any) {
|
||||
const transformName = find(
|
||||
["transform", "WebkitTransform", "MozTransform", "MsTransform", "OTransform"],
|
||||
prop => prop in plotlyElement.style
|
||||
@@ -89,6 +90,7 @@ function placeLegendBelowPlot(plotlyElement, layout) {
|
||||
// so we can split container's height half by half between them.
|
||||
layout.height = Math.floor(Math.max(layoutHeight / 2, layoutHeight - (bounds.bottom - bounds.top)));
|
||||
// offset the legend
|
||||
// @ts-expect-error ts-migrate(2538) FIXME: Type 'undefined' cannot be used as an index type.
|
||||
legend.style[transformName] = "translate(0, " + layout.height + "px)";
|
||||
return [pick(layout, ["height"]), null]; // no further updates
|
||||
}
|
||||
@@ -96,7 +98,7 @@ function placeLegendBelowPlot(plotlyElement, layout) {
|
||||
];
|
||||
}
|
||||
|
||||
function placeLegendAuto(plotlyElement, layout) {
|
||||
function placeLegendAuto(plotlyElement: any, layout: any) {
|
||||
if (layout.width <= 600) {
|
||||
return placeLegendBelowPlot(plotlyElement, layout);
|
||||
} else {
|
||||
@@ -104,7 +106,7 @@ function placeLegendAuto(plotlyElement, layout) {
|
||||
}
|
||||
}
|
||||
|
||||
export default function updateChartSize(plotlyElement, layout, options) {
|
||||
export default function updateChartSize(plotlyElement: any, layout: any, options: any) {
|
||||
// update layout size to plot container
|
||||
// plot size should be at least 5x5px
|
||||
layout.width = Math.max(5, Math.floor(plotlyElement.offsetWidth));
|
||||
@@ -2,11 +2,11 @@ import { isNil, each, extend, filter, identity, includes, map, sortBy } from "lo
|
||||
import { createNumberFormatter, formatSimpleTemplate } from "@/lib/value-format";
|
||||
import { normalizeValue } from "./utils";
|
||||
|
||||
function shouldUseUnifiedXAxis(options) {
|
||||
function shouldUseUnifiedXAxis(options: any) {
|
||||
return options.sortX && options.xAxis.type === "category" && options.globalSeriesType !== "box";
|
||||
}
|
||||
|
||||
function defaultFormatSeriesText(item) {
|
||||
function defaultFormatSeriesText(item: any) {
|
||||
let result = item["@@y"];
|
||||
if (item["@@yError"] !== undefined) {
|
||||
result = `${result} \u00B1 ${item["@@yError"]}`;
|
||||
@@ -20,18 +20,18 @@ function defaultFormatSeriesText(item) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function defaultFormatSeriesTextForPie(item) {
|
||||
function defaultFormatSeriesTextForPie(item: any) {
|
||||
return item["@@yPercent"] + " (" + item["@@y"] + ")";
|
||||
}
|
||||
|
||||
function createTextFormatter(options) {
|
||||
function createTextFormatter(options: any) {
|
||||
if (options.textFormat === "") {
|
||||
return options.globalSeriesType === "pie" ? defaultFormatSeriesTextForPie : defaultFormatSeriesText;
|
||||
}
|
||||
return item => formatSimpleTemplate(options.textFormat, item);
|
||||
return (item: any) => formatSimpleTemplate(options.textFormat, item);
|
||||
}
|
||||
|
||||
function formatValue(value, axis, options) {
|
||||
function formatValue(value: any, axis: any, options: any) {
|
||||
let axisType = null;
|
||||
switch (axis) {
|
||||
case "x":
|
||||
@@ -48,7 +48,7 @@ function formatValue(value, axis, options) {
|
||||
return normalizeValue(value, axisType, options.dateTimeFormat);
|
||||
}
|
||||
|
||||
function updateSeriesText(seriesList, options) {
|
||||
function updateSeriesText(seriesList: any, options: any) {
|
||||
const formatNumber = createNumberFormatter(options.numberFormat);
|
||||
const formatPercent = createNumberFormatter(options.percentFormat);
|
||||
const formatText = createTextFormatter(options);
|
||||
@@ -61,7 +61,7 @@ function updateSeriesText(seriesList, options) {
|
||||
series.text = [];
|
||||
series.hover = [];
|
||||
const xValues = options.globalSeriesType === "pie" ? series.labels : series.x;
|
||||
xValues.forEach(x => {
|
||||
xValues.forEach((x: any) => {
|
||||
const text = {
|
||||
"@@name": series.name,
|
||||
};
|
||||
@@ -74,16 +74,21 @@ function updateSeriesText(seriesList, options) {
|
||||
// using default (ISO) date/time format. Here we need to use custom date/time format, so we pass original value
|
||||
// to `formatValue` which will call `normalizeValue` again, but this time with different date/time format
|
||||
// (if needed)
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
text["@@x"] = formatValue(item.row.x, "x", options);
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
text["@@y"] = yValueIsAny ? formatValue(item.row.y, series.yaxis, options) : formatNumber(item.y);
|
||||
if (item.yError !== undefined) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
text["@@yError"] = formatNumber(item.yError);
|
||||
}
|
||||
if (item.size !== undefined) {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
text["@@size"] = formatNumber(item.size);
|
||||
}
|
||||
|
||||
if (options.series.percentValues || options.globalSeriesType === "pie") {
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
text["@@yPercent"] = formatPercent(Math.abs(item.yPercent));
|
||||
}
|
||||
|
||||
@@ -94,22 +99,22 @@ function updateSeriesText(seriesList, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function updatePercentValues(seriesList, options) {
|
||||
function updatePercentValues(seriesList: any, options: any) {
|
||||
if (options.series.percentValues) {
|
||||
// Some series may not have corresponding x-values;
|
||||
// do calculations for each x only for series that do have that x
|
||||
const sumOfCorrespondingPoints = new Map();
|
||||
each(seriesList, series => {
|
||||
series.sourceData.forEach(item => {
|
||||
series.sourceData.forEach((item: any) => {
|
||||
const sum = sumOfCorrespondingPoints.get(item.x) || 0;
|
||||
sumOfCorrespondingPoints.set(item.x, sum + Math.abs(item.y || 0.0));
|
||||
});
|
||||
});
|
||||
|
||||
each(seriesList, series => {
|
||||
const yValues = [];
|
||||
const yValues: any = [];
|
||||
|
||||
series.sourceData.forEach(item => {
|
||||
series.sourceData.forEach((item: any) => {
|
||||
if (isNil(item.y) && !options.missingValuesAsZero) {
|
||||
item.yPercent = null;
|
||||
} else {
|
||||
@@ -124,11 +129,11 @@ function updatePercentValues(seriesList, options) {
|
||||
}
|
||||
}
|
||||
|
||||
function getUnifiedXAxisValues(seriesList, sorted) {
|
||||
function getUnifiedXAxisValues(seriesList: any, sorted: any) {
|
||||
const set = new Set();
|
||||
each(seriesList, series => {
|
||||
// `Map.forEach` will walk items in insertion order
|
||||
series.sourceData.forEach(item => {
|
||||
series.sourceData.forEach((item: any) => {
|
||||
set.add(item.x);
|
||||
});
|
||||
});
|
||||
@@ -137,7 +142,7 @@ function getUnifiedXAxisValues(seriesList, sorted) {
|
||||
return sorted ? sortBy(result, identity) : result;
|
||||
}
|
||||
|
||||
function updateUnifiedXAxisValues(seriesList, options) {
|
||||
function updateUnifiedXAxisValues(seriesList: any, options: any) {
|
||||
const unifiedX = getUnifiedXAxisValues(seriesList, options.sortX);
|
||||
const defaultY = options.missingValuesAsZero ? 0.0 : null;
|
||||
each(seriesList, series => {
|
||||
@@ -158,11 +163,11 @@ function updateUnifiedXAxisValues(seriesList, options) {
|
||||
});
|
||||
}
|
||||
|
||||
function updatePieData(seriesList, options) {
|
||||
function updatePieData(seriesList: any, options: any) {
|
||||
updateSeriesText(seriesList, options);
|
||||
}
|
||||
|
||||
function updateLineAreaData(seriesList, options) {
|
||||
function updateLineAreaData(seriesList: any, options: any) {
|
||||
// Apply "percent values" modification
|
||||
updatePercentValues(seriesList, options);
|
||||
if (options.series.stacking) {
|
||||
@@ -176,7 +181,9 @@ function updateLineAreaData(seriesList, options) {
|
||||
return null;
|
||||
}
|
||||
const x = series.x[i];
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
const stackedY = y + (cumulativeValues[x] || 0.0);
|
||||
// @ts-expect-error ts-migrate(7053) FIXME: Element implicitly has an 'any' type because expre... Remove this comment to see the full error message
|
||||
cumulativeValues[x] = stackedY;
|
||||
return stackedY;
|
||||
});
|
||||
@@ -191,7 +198,7 @@ function updateLineAreaData(seriesList, options) {
|
||||
updateSeriesText(seriesList, options);
|
||||
}
|
||||
|
||||
function updateDefaultData(seriesList, options) {
|
||||
function updateDefaultData(seriesList: any, options: any) {
|
||||
// Apply "percent values" modification
|
||||
updatePercentValues(seriesList, options);
|
||||
|
||||
@@ -205,7 +212,7 @@ function updateDefaultData(seriesList, options) {
|
||||
updateSeriesText(seriesList, options);
|
||||
}
|
||||
|
||||
export default function updateData(seriesList, options) {
|
||||
export default function updateData(seriesList: any, options: any) {
|
||||
// Use only visible series
|
||||
const visibleSeriesList = filter(seriesList, s => s.visible === true);
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { isUndefined } from "lodash";
|
||||
import moment from "moment";
|
||||
// @ts-expect-error ts-migrate(7016) FIXME: Could not find a declaration file for module 'plot... Remove this comment to see the full error message
|
||||
import plotlyCleanNumber from "plotly.js/src/lib/clean_number";
|
||||
|
||||
export function cleanNumber(value) {
|
||||
export function cleanNumber(value: any) {
|
||||
return isUndefined(value) ? value : plotlyCleanNumber(value);
|
||||
}
|
||||
|
||||
export function getSeriesAxis(series, options) {
|
||||
export function getSeriesAxis(series: any, options: any) {
|
||||
const seriesOptions = options.seriesOptions[series.name] || { type: options.globalSeriesType };
|
||||
if (seriesOptions.yAxis === 1 && (!options.series.stacking || seriesOptions.type === "line")) {
|
||||
return "y2";
|
||||
@@ -14,7 +15,7 @@ export function getSeriesAxis(series, options) {
|
||||
return "y";
|
||||
}
|
||||
|
||||
export function normalizeValue(value, axisType, dateTimeFormat = "YYYY-MM-DD HH:mm:ss") {
|
||||
export function normalizeValue(value: any, axisType: any, dateTimeFormat = "YYYY-MM-DD HH:mm:ss") {
|
||||
if (axisType === "datetime" && moment.utc(value).isValid()) {
|
||||
value = moment.utc(value);
|
||||
}
|
||||
@@ -8,7 +8,10 @@ import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import useLoadGeoJson from "../hooks/useLoadGeoJson";
|
||||
import { getGeoJsonBounds } from "./utils";
|
||||
|
||||
export default function BoundsSettings({ options, onOptionsChange }) {
|
||||
export default function BoundsSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
// Bounds may be changed in editor or on preview (by drag/zoom map).
|
||||
// Changes from preview does not come frequently (only when user release mouse button),
|
||||
// but changes from editor should be debounced.
|
||||
@@ -51,42 +54,48 @@ export default function BoundsSettings({ options, onOptionsChange }) {
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'null | un... Remove this comment to see the full error message */}
|
||||
<ControlLabel label="North-East Latitude and Longitude">
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<Grid.Row gutter={15}>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
disabled={!boundsAvailable}
|
||||
value={boundsAvailable ? bounds[1][0] : undefined}
|
||||
onChange={value => updateBounds(1, 0, value)}
|
||||
onChange={(value: any) => updateBounds(1, 0, value)}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
disabled={!boundsAvailable}
|
||||
value={boundsAvailable ? bounds[1][1] : undefined}
|
||||
onChange={value => updateBounds(1, 1, value)}
|
||||
onChange={(value: any) => updateBounds(1, 1, value)}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</ControlLabel>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'string' is not assignable to type 'null | un... Remove this comment to see the full error message */}
|
||||
<ControlLabel label="South-West Latitude and Longitude">
|
||||
{/* @ts-expect-error ts-migrate(2322) FIXME: Type 'Element' is not assignable to type 'null | u... Remove this comment to see the full error message */}
|
||||
<Grid.Row gutter={15}>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
disabled={!boundsAvailable}
|
||||
value={boundsAvailable ? bounds[0][0] : undefined}
|
||||
onChange={value => updateBounds(0, 0, value)}
|
||||
onChange={(value: any) => updateBounds(0, 0, value)}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
<InputNumber
|
||||
disabled={!boundsAvailable}
|
||||
value={boundsAvailable ? bounds[0][1] : undefined}
|
||||
onChange={value => updateBounds(0, 1, value)}
|
||||
onChange={(value: any) => updateBounds(0, 1, value)}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
@@ -4,30 +4,41 @@ import { Section, Select, InputNumber, ColorPicker } from "@/components/visualiz
|
||||
import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import ColorPalette from "../ColorPalette";
|
||||
|
||||
export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
export default function ColorsSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const [onOptionsChangeDebounced] = useDebouncedCallback(onOptionsChange, 200);
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Select
|
||||
layout="horizontal"
|
||||
label="Clustering Mode"
|
||||
data-test="Choropleth.Editor.ClusteringMode"
|
||||
defaultValue={options.clusteringMode}
|
||||
onChange={clusteringMode => onOptionsChange({ clusteringMode })}>
|
||||
onChange={(clusteringMode: any) => onOptionsChange({ clusteringMode })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="q" data-test="Choropleth.Editor.ClusteringMode.q">
|
||||
quantile
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="e" data-test="Choropleth.Editor.ClusteringMode.e">
|
||||
equidistant
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="k" data-test="Choropleth.Editor.ClusteringMode.k">
|
||||
k-means
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<InputNumber
|
||||
layout="horizontal"
|
||||
@@ -36,10 +47,11 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
min={3}
|
||||
max={11}
|
||||
defaultValue={options.steps}
|
||||
onChange={steps => onOptionsChangeDebounced({ steps })}
|
||||
onChange={(steps: any) => onOptionsChangeDebounced({ steps })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -49,11 +61,13 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
color={options.colors.min}
|
||||
triggerProps={{ "data-test": "Choropleth.Editor.Colors.Min" }}
|
||||
onChange={min => onOptionsChange({ colors: { min } })}
|
||||
onChange={(min: any) => onOptionsChange({ colors: { min } })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.colors.min} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -63,11 +77,13 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
color={options.colors.max}
|
||||
triggerProps={{ "data-test": "Choropleth.Editor.Colors.Max" }}
|
||||
onChange={max => onOptionsChange({ colors: { max } })}
|
||||
onChange={(max: any) => onOptionsChange({ colors: { max } })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.colors.max} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -77,11 +93,13 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
color={options.colors.noValue}
|
||||
triggerProps={{ "data-test": "Choropleth.Editor.Colors.NoValue" }}
|
||||
onChange={noValue => onOptionsChange({ colors: { noValue } })}
|
||||
onChange={(noValue: any) => onOptionsChange({ colors: { noValue } })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.colors.noValue} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -91,11 +109,13 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
color={options.colors.background}
|
||||
triggerProps={{ "data-test": "Choropleth.Editor.Colors.Background" }}
|
||||
onChange={background => onOptionsChange({ colors: { background } })}
|
||||
onChange={(background: any) => onOptionsChange({ colors: { background } })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.colors.background} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<ColorPicker
|
||||
layout="horizontal"
|
||||
@@ -105,7 +125,8 @@ export default function ColorsSettings({ options, onOptionsChange }) {
|
||||
placement="topRight"
|
||||
color={options.colors.borders}
|
||||
triggerProps={{ "data-test": "Choropleth.Editor.Colors.Borders" }}
|
||||
onChange={borders => onOptionsChange({ colors: { borders } })}
|
||||
onChange={(borders: any) => onOptionsChange({ colors: { borders } })}
|
||||
// @ts-expect-error ts-migrate(2339) FIXME: Property 'Label' does not exist on type '({ classN... Remove this comment to see the full error message
|
||||
addonAfter={<ColorPicker.Label color={options.colors.borders} presetColors={ColorPalette} />}
|
||||
/>
|
||||
</Section>
|
||||
@@ -1,6 +1,5 @@
|
||||
import { map } from "lodash";
|
||||
import React, { useMemo } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import * as Grid from "antd/lib/grid";
|
||||
import {
|
||||
@@ -17,8 +16,15 @@ import { EditorPropTypes } from "@/visualizations/prop-types";
|
||||
import useLoadGeoJson from "../hooks/useLoadGeoJson";
|
||||
import { getGeoJsonFields } from "./utils";
|
||||
|
||||
function TemplateFormatHint({ geoJsonProperties }) {
|
||||
type OwnTemplateFormatHintProps = {
|
||||
geoJsonProperties?: string[];
|
||||
};
|
||||
|
||||
type TemplateFormatHintProps = OwnTemplateFormatHintProps & typeof TemplateFormatHint.defaultProps;
|
||||
|
||||
function TemplateFormatHint({ geoJsonProperties }: TemplateFormatHintProps) {
|
||||
return (
|
||||
// @ts-expect-error ts-migrate(2746) FIXME: This JSX tag's 'children' prop expects a single ch... Remove this comment to see the full error message
|
||||
<ContextHelp placement="topLeft" arrowPointAtCenter>
|
||||
<div style={{ paddingBottom: 5 }}>
|
||||
<div>
|
||||
@@ -44,15 +50,14 @@ function TemplateFormatHint({ geoJsonProperties }) {
|
||||
);
|
||||
}
|
||||
|
||||
TemplateFormatHint.propTypes = {
|
||||
geoJsonProperties: PropTypes.arrayOf(PropTypes.string),
|
||||
};
|
||||
|
||||
TemplateFormatHint.defaultProps = {
|
||||
geoJsonProperties: [],
|
||||
};
|
||||
|
||||
export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
export default function GeneralSettings({
|
||||
options,
|
||||
onOptionsChange
|
||||
}: any) {
|
||||
const [onOptionsChangeDebounced] = useDebouncedCallback(onOptionsChange, 200);
|
||||
const [geoJson] = useLoadGeoJson(options.mapType);
|
||||
const geoJsonFields = useMemo(() => getGeoJsonFields(geoJson), [geoJson]);
|
||||
@@ -61,6 +66,7 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
|
||||
return (
|
||||
<div className="choropleth-visualization-editor-format-settings">
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Grid.Row gutter={15}>
|
||||
<Grid.Col span={12}>
|
||||
@@ -73,7 +79,7 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
}
|
||||
data-test="Choropleth.Editor.ValueFormat"
|
||||
defaultValue={options.valueFormat}
|
||||
onChange={event => onOptionsChangeDebounced({ valueFormat: event.target.value })}
|
||||
onChange={(event: any) => onOptionsChangeDebounced({ valueFormat: event.target.value })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
<Grid.Col span={12}>
|
||||
@@ -81,12 +87,13 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
label="Value Placeholder"
|
||||
data-test="Choropleth.Editor.ValuePlaceholder"
|
||||
defaultValue={options.noValuePlaceholder}
|
||||
onChange={event => onOptionsChangeDebounced({ noValuePlaceholder: event.target.value })}
|
||||
onChange={(event: any) => onOptionsChangeDebounced({ noValuePlaceholder: event.target.value })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Choropleth.Editor.LegendVisibility"
|
||||
@@ -96,6 +103,7 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
</Checkbox>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Grid.Row gutter={15}>
|
||||
<Grid.Col span={12}>
|
||||
@@ -104,18 +112,26 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
data-test="Choropleth.Editor.LegendPosition"
|
||||
disabled={!options.legend.visible}
|
||||
defaultValue={options.legend.position}
|
||||
onChange={position => onOptionsChange({ legend: { position } })}>
|
||||
onChange={(position: any) => onOptionsChange({ legend: { position } })}>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="top-left" data-test="Choropleth.Editor.LegendPosition.TopLeft">
|
||||
top / left
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="top-right" data-test="Choropleth.Editor.LegendPosition.TopRight">
|
||||
top / right
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="bottom-left" data-test="Choropleth.Editor.LegendPosition.BottomLeft">
|
||||
bottom / left
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
<Select.Option value="bottom-right" data-test="Choropleth.Editor.LegendPosition.BottomRight">
|
||||
bottom / right
|
||||
{/* @ts-expect-error ts-migrate(2339) FIXME: Property 'Option' does not exist on type '({ class... Remove this comment to see the full error message */}
|
||||
</Select.Option>
|
||||
</Select>
|
||||
</Grid.Col>
|
||||
@@ -125,12 +141,13 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
label="Legend Text Alignment"
|
||||
disabled={!options.legend.visible}
|
||||
defaultValue={options.legend.alignText}
|
||||
onChange={event => onOptionsChange({ legend: { alignText: event.target.value } })}
|
||||
onChange={(event: any) => onOptionsChange({ legend: { alignText: event.target.value } })}
|
||||
/>
|
||||
</Grid.Col>
|
||||
</Grid.Row>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Choropleth.Editor.TooltipEnabled"
|
||||
@@ -140,16 +157,18 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
</Checkbox>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Input
|
||||
label={<React.Fragment>Tooltip Template {templateFormatHint}</React.Fragment>}
|
||||
data-test="Choropleth.Editor.TooltipTemplate"
|
||||
disabled={!options.tooltip.enabled}
|
||||
defaultValue={options.tooltip.template}
|
||||
onChange={event => onOptionsChangeDebounced({ tooltip: { template: event.target.value } })}
|
||||
onChange={(event: any) => onOptionsChangeDebounced({ tooltip: { template: event.target.value } })}
|
||||
/>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<Checkbox
|
||||
data-test="Choropleth.Editor.PopupEnabled"
|
||||
@@ -159,6 +178,7 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
</Checkbox>
|
||||
</Section>
|
||||
|
||||
{/* @ts-expect-error ts-migrate(2745) FIXME: This JSX tag's 'children' prop expects type 'never... Remove this comment to see the full error message */}
|
||||
<Section>
|
||||
<TextArea
|
||||
label={<React.Fragment>Popup Template {templateFormatHint}</React.Fragment>}
|
||||
@@ -166,7 +186,7 @@ export default function GeneralSettings({ options, onOptionsChange }) {
|
||||
disabled={!options.popup.enabled}
|
||||
rows={4}
|
||||
defaultValue={options.popup.template}
|
||||
onChange={event => onOptionsChangeDebounced({ popup: { template: event.target.value } })}
|
||||
onChange={(event: any) => onOptionsChangeDebounced({ popup: { template: event.target.value } })}
|
||||
/>
|
||||
</Section>
|
||||
</div>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user