/* eslint-disable react/no-multi-comp */ import { isString, extend, each, has, map, includes, findIndex, find, fromPairs, clone, isEmpty } from "lodash"; import React, { Fragment } from "react"; import PropTypes from "prop-types"; import classNames from "classnames"; import Select from "antd/lib/select"; import Table from "antd/lib/table"; import Popover from "antd/lib/popover"; import Button from "antd/lib/button"; import Tag from "antd/lib/tag"; import Input from "antd/lib/input"; import Radio from "antd/lib/radio"; import Form from "antd/lib/form"; import Tooltip from "@/components/Tooltip"; import ParameterValueInput from "@/components/ParameterValueInput"; import { ParameterMappingType } from "@/services/widget"; import { Parameter, cloneParameter } from "@/services/parameters"; import HelpTrigger from "@/components/HelpTrigger"; import QuestionCircleFilledIcon from "@ant-design/icons/QuestionCircleFilled"; import EditOutlinedIcon from "@ant-design/icons/EditOutlined"; import CloseOutlinedIcon from "@ant-design/icons/CloseOutlined"; import CheckOutlinedIcon from "@ant-design/icons/CheckOutlined"; import "./ParameterMappingInput.less"; export const MappingType = { DashboardAddNew: "dashboard-add-new", DashboardMapToExisting: "dashboard-map-to-existing", WidgetLevel: "widget-level", StaticValue: "static-value", }; export function parameterMappingsToEditableMappings(mappings, parameters, existingParameterNames = []) { return map(mappings, (mapping) => { const result = extend({}, mapping); const alreadyExists = includes(existingParameterNames, mapping.mapTo); result.param = find(parameters, (p) => p.name === mapping.name); switch (mapping.type) { case ParameterMappingType.DashboardLevel: result.type = alreadyExists ? MappingType.DashboardMapToExisting : MappingType.DashboardAddNew; result.value = null; break; case ParameterMappingType.StaticValue: result.type = MappingType.StaticValue; result.param = cloneParameter(result.param); result.param.setValue(result.value); break; case ParameterMappingType.WidgetLevel: result.type = MappingType.WidgetLevel; result.value = null; break; // no default } return result; }); } export function editableMappingsToParameterMappings(mappings) { return fromPairs( map( // convert to map mappings, (mapping) => { const result = extend({}, mapping); switch (mapping.type) { case MappingType.DashboardAddNew: result.type = ParameterMappingType.DashboardLevel; result.value = null; break; case MappingType.DashboardMapToExisting: result.type = ParameterMappingType.DashboardLevel; result.value = null; break; case MappingType.StaticValue: result.type = ParameterMappingType.StaticValue; result.param = cloneParameter(mapping.param); result.param.setValue(result.value); result.value = result.param.value; break; case MappingType.WidgetLevel: result.type = ParameterMappingType.WidgetLevel; result.value = null; break; // no default } delete result.param; return [result.name, result]; } ) ); } export function synchronizeWidgetTitles(sourceMappings, widgets) { const affectedWidgets = []; each(sourceMappings, (sourceMapping) => { if (sourceMapping.type === ParameterMappingType.DashboardLevel) { each(widgets, (widget) => { const widgetMappings = widget.options.parameterMappings; each(widgetMappings, (widgetMapping) => { // check if mapped to the same dashboard-level parameter if ( widgetMapping.type === ParameterMappingType.DashboardLevel && widgetMapping.mapTo === sourceMapping.mapTo ) { // dirty check - update only when needed if (widgetMapping.title !== sourceMapping.title) { widgetMapping.title = sourceMapping.title; affectedWidgets.push(widget); } } }); }); } }); return affectedWidgets; } export class ParameterMappingInput extends React.Component { static propTypes = { mapping: PropTypes.object, // eslint-disable-line react/forbid-prop-types existingParamNames: PropTypes.arrayOf(PropTypes.string), onChange: PropTypes.func, inputError: PropTypes.string, }; static defaultProps = { mapping: {}, existingParamNames: [], onChange: () => {}, inputError: null, }; formItemProps = { labelCol: { span: 5 }, wrapperCol: { span: 16 }, className: "form-item", }; updateSourceType = (type) => { let { mapping: { mapTo }, } = this.props; const { existingParamNames } = this.props; // if mapped name doesn't already exists // default to first select option if (type === MappingType.DashboardMapToExisting && !includes(existingParamNames, mapTo)) { mapTo = existingParamNames[0]; } this.updateParamMapping({ type, mapTo }); }; updateParamMapping = (update) => { const { onChange, mapping } = this.props; const newMapping = extend({}, mapping, update); if (newMapping.value !== mapping.value) { newMapping.param = cloneParameter(newMapping.param); newMapping.param.setValue(newMapping.value); } if (has(update, "type")) { if (update.type === MappingType.StaticValue) { newMapping.value = newMapping.param.value; } else { newMapping.value = null; } } onChange(newMapping); }; renderMappingTypeSelector() { const noExisting = isEmpty(this.props.existingParamNames); return ( this.updateSourceType(e.target.value)}> New dashboard parameter Existing dashboard parameter{" "} {noExisting ? ( ) : null} Widget parameter Static value ); } renderDashboardAddNew() { const { mapping: { mapTo }, } = this.props; return ( this.updateParamMapping({ mapTo: e.target.value })} /> ); } renderDashboardMapToExisting() { const { mapping, existingParamNames } = this.props; const options = map(existingParamNames, (paramName) => ({ label: paramName, value: paramName })); return ); } renderEditButton() { const { mapping } = this.props; if (mapping.type === MappingType.StaticValue) { return ( {/* eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex */}