diff --git a/lib/static/components/controls/base-host-input.jsx b/lib/static/components/controls/base-host-input.jsx index dc3385bf1..3d3acb4f6 100644 --- a/lib/static/components/controls/base-host-input.jsx +++ b/lib/static/components/controls/base-host-input.jsx @@ -4,6 +4,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import {bindActionCreators} from 'redux'; import {connect} from 'react-redux'; +import {TextInput} from '@gravity-ui/uikit'; import * as actions from '../../modules/actions'; class BaseHostInput extends Component { @@ -19,12 +20,13 @@ class BaseHostInput extends Component { render() { return ( - ); } diff --git a/lib/static/components/controls/browser-list/index.jsx b/lib/static/components/controls/browser-list/index.jsx index e94322b88..a8ee3f6b0 100644 --- a/lib/static/components/controls/browser-list/index.jsx +++ b/lib/static/components/controls/browser-list/index.jsx @@ -5,224 +5,169 @@ import {flatten, isEmpty, get, chain, compact} from 'lodash'; import PropTypes from 'prop-types'; import CheckboxTree from 'react-checkbox-tree'; -import Label from './label'; import {mkBrowserIcon, buildComplexId} from './utils'; import Popup from '../../popup'; import ArrayContainer from '../../../containers/array'; import 'react-checkbox-tree/lib/react-checkbox-tree.css'; import './index.styl'; - -const BrowserList = (props) => { - const {available, onChange, selected: selectedProp} = props; - - const [expanded, setExpanded] = useState([]); - const [selected, setSelected] = useState(buidSelectedItems()); - const [elements, setElements] = useState([]); - const treeDataMap = useMemo(buildTreeDataMap, [available]); - const nodes = useMemo(prepareTreeData, [available]); - const selectAll = useCallback(_selectAll, [setExpanded, treeDataMap]); - - useEffect(() => { - updateLabels(); - onChange && onChange(formatSelectedData(selected)); - }, [selected]); - - function buildTreeDataMap() { - return available.reduce((acc, {id: browserId, versions}) => { - const hasChildren = !isEmpty(versions) && versions.length > 1; - - acc[buildComplexId(browserId)] = {browserId, isLeaf: !hasChildren}; - - if (hasChildren) { - versions.forEach(version => { - acc[buildComplexId(browserId, version)] = {browserId, version, isLeaf: true}; - }); +import { Button, Select, useSelectOptions } from '@gravity-ui/uikit'; + +const BrowserList = ({available, onChange, selected: selectedProp}) => { + const getOptions = () => { + const groups = {}; + const DEFAULT_GROUP = "other"; + let hasNestedOptions = false; + available.forEach(({id: browserId, versions}) => { + if (!versions || versions.length < 2) { + groups[DEFAULT_GROUP] = groups[DEFAULT_GROUP] || []; + groups[DEFAULT_GROUP].push({value: buildComplexId(browserId), + content:
{mkBrowserIcon(browserId)}{buildComplexId(browserId)}
}); + return; } + hasNestedOptions = true; + versions.forEach((version) => { + groups[browserId] = groups[browserId] || []; + groups[browserId].push({value: buildComplexId(browserId, version), + content:
{mkBrowserIcon(browserId)}{buildComplexId(browserId, version)}
}); + }) + }); + if (!hasNestedOptions) { + return groups[DEFAULT_GROUP]; + } + else { + const optionsList = []; + Object.keys(groups).forEach((name) => { + optionsList.push({ + label: name, + options: groups[name] + }) + }) + return optionsList; + } - return acc; - }, {}); } - - function buidSelectedItems() { + const getMapping = () => { + const mapping = {}; + available.forEach(({id: browserId, versions}) => { + if (!versions || !versions.length) { + mapping[buildComplexId(browserId)] = {id: browserId}; + return; + } + if (versions.length < 2) { + mapping[buildComplexId(browserId)] = {id: browserId, version: versions[0]}; + return; + } + versions.forEach((version) => { + mapping[buildComplexId(browserId, version)] = {id: browserId, version}; + }) + }); + return mapping; + } + const getSelected = () => { + const selectedOptions = []; if (!selectedProp || !selectedProp.length) { return []; } - - const selectedItems = selectedProp.map(({id, versions}) => { - if (!versions) { - return []; + selectedProp.forEach(({id: browserId, versions}) => { + if (!versions || versions.length < 2) { + selectedOptions.push(buildComplexId(browserId)); + return; } - - const availableNode = available.find((item) => item.id === id); - const shouldDrawOnlyRootNode = get(availableNode, 'versions.length', 1) === 1; - - if (shouldDrawOnlyRootNode) { - return buildComplexId(id); - } - - return versions.length - ? versions.map((version) => buildComplexId(id, version)) - : availableNode.versions.map(version => buildComplexId(id, version)); + versions.forEach((version) => { + selectedOptions.push(buildComplexId(browserId, version)); + }) }); - - return flatten(selectedItems); + return selectedOptions; } - - function prepareTreeData() { - const mkNode = ({browserId, version, icon}) => ({ - icon, - data: {browserId, version}, - value: buildComplexId(browserId, version), - label: mkLabel({browserId, version, elements}) - }); - - return available.map(({id: browserId, versions}) => { - const node = mkNode({browserId, icon: mkBrowserIcon(browserId)}); - - if (!isEmpty(versions) && versions.length > 1) { - node.children = versions.map(version => mkNode({browserId, version})); + const rawOptions = useMemo(getOptions, [available]); + const getOptionsFrom = (optionsData) => { + const allOptionsList = []; + optionsData.forEach((option) => { + if (option.label) { + getOptionsFrom(option.options).forEach((o) => allOptionsList.push(o)); } - - return node; - }); + else { + allOptionsList.push(option.value); + } + }) + return allOptionsList; + } + const allOptions = useMemo(() => getOptionsFrom(rawOptions), [rawOptions]); + const options = useSelectOptions({ + options: rawOptions + }); + const mapping = useMemo(getMapping, [available]); + const [selected, setSelected] = useState(getSelected()); + + const selectAll = () => { + setSelected(allOptions); } - function _selectAll() { - const leaves = Object.keys(treeDataMap).filter(key => treeDataMap[key].isLeaf); - const cb = selected => selected.length !== leaves.length - ? leaves - : selected; - - setSelected(cb); + const formatSelectedData = () => { + const selectedData = {} + selected.forEach((option) => { + if (!mapping[option] || !mapping[option].id) return; + const {id: browserId, version} = mapping[option]; + selectedData[browserId] = selectedData[browserId] || []; + selectedData[browserId].push(version); + }) + return Object.entries(selectedData).map(([id, versions]) => ({id, versions: compact(versions)})) } - function mkLabel({browserId, version, elements}) { + const renderFilter = () => { + const allSelected = selected.length == options.length; return ( -