diff --git a/ui/src/clockface/components/label/LabelSelector.scss b/ui/src/clockface/components/label/LabelSelector.scss index 2eb6ac2a824..e8d64d8cb3f 100644 --- a/ui/src/clockface/components/label/LabelSelector.scss +++ b/ui/src/clockface/components/label/LabelSelector.scss @@ -27,31 +27,14 @@ .label-selector--menu { width: 100%; - display: flex; - flex-direction: column; - align-items: stretch; + min-height: 50px; + margin: $ix-marg-b; } .label-selector--menu-item { - display: flex; - align-items: center; - padding: $ix-marg-a $ix-marg-b; - color: $g13-mist; - transition: color 0.25s ease, background-color 0.25s ease; - - &.active, - &.active:hover { - cursor: pointer; - color: $g18-cloud; - background-color: $g6-smoke; - } + margin: 1px; } -.label-selector--label { - flex: 4 0 0 -} - -.label-selector--description, .label-selector--empty { font-size: 13px; font-weight: 500; @@ -69,15 +52,10 @@ line-height: 30px; } -.label-selector--description { - margin-left: 6px; - color: $g13-mist; - flex: 2 0 50%; -} - -.label-selector--bottom { +.label-selector--selection { display: flex; flex-wrap: nowrap; + margin-bottom: $ix-marg-c; } .label-selector--remove-all { diff --git a/ui/src/clockface/components/label/LabelSelector.tsx b/ui/src/clockface/components/label/LabelSelector.tsx index fb6d670b088..eb18452793e 100644 --- a/ui/src/clockface/components/label/LabelSelector.tsx +++ b/ui/src/clockface/components/label/LabelSelector.tsx @@ -2,6 +2,9 @@ import React, {Component, ChangeEvent, KeyboardEvent} from 'react' import _ from 'lodash' +// APIs +import {client} from 'src/utils/api' + // Components import {Button} from '@influxdata/clockface' import Input from 'src/clockface/components/inputs/Input' @@ -12,7 +15,7 @@ import {ClickOutside} from 'src/shared/components/ClickOutside' // Types import {ComponentSize} from 'src/clockface/types' -import {Label as LabelAPI} from '@influxdata/influx' +import {Label as APILabel} from 'src/types/v2/labels' // Styles import './LabelSelector.scss' @@ -25,18 +28,19 @@ enum ArrowDirection { } interface Props { - selectedLabels: LabelAPI[] - allLabels: LabelAPI[] - onAddLabel: (label: LabelAPI) => void - onRemoveLabel: (label: LabelAPI) => void + selectedLabels: APILabel[] + allLabels: APILabel[] + onAddLabel: (label: APILabel) => void + onRemoveLabel: (label: APILabel) => void onRemoveAllLabels: () => void + onCreateLabel: (label: APILabel) => void resourceType: string inputSize?: ComponentSize } interface State { filterValue: string - filteredLabels: LabelAPI[] + filteredLabels: APILabel[] isSuggesting: boolean highlightedID: string } @@ -64,31 +68,21 @@ class LabelSelector extends Component { } } - public render() { - const {resourceType, inputSize} = this.props - const {filterValue} = this.state + public componentDidMount() { + this.handleStartSuggesting() + } + public render() { return ( -
- -
- - {this.suggestionMenu} + +
+
+ {this.selectedLabels} + {this.clearSelectedButton}
- -
- {this.selectedLabels} - {this.clearSelectedButton} + {this.input}
-
+
) } @@ -121,23 +115,45 @@ class LabelSelector extends Component { private get suggestionMenu(): JSX.Element { const {allLabels, selectedLabels} = this.props - const {isSuggesting, highlightedID} = this.state + const {isSuggesting, highlightedID, filterValue} = this.state const allLabelsUsed = allLabels.length === selectedLabels.length if (isSuggesting) { return ( ) } } + private get input(): JSX.Element { + const {resourceType, inputSize} = this.props + const {filterValue} = this.state + + return ( +
+ + {this.suggestionMenu} +
+ ) + } + private handleAddLabel = (labelID: string): void => { const {onAddLabel, allLabels} = this.props @@ -184,20 +200,7 @@ class LabelSelector extends Component { ) const filteredLabels = availableLabels.filter(label => { - const filterChars = _.lowerCase(filterValue) - .replace(/\s/g, '') - .split('') - const labelChars = _.lowerCase(label.name) - .replace(/\s/g, '') - .split('') - - const overlap = _.difference(filterChars, labelChars) - - if (overlap.length) { - return false - } - - return true + return label.name.includes(filterValue) }) const highlightedIDAvailable = filteredLabels.find( @@ -208,10 +211,19 @@ class LabelSelector extends Component { highlightedID = filteredLabels[0].name } + if (filterValue.length === 0) { + return this.setState({ + isSuggesting: true, + filteredLabels: this.props.allLabels, + highlightedID: null, + filterValue: '', + }) + } + this.setState({filterValue, filteredLabels, highlightedID}) } - private get availableLabels(): LabelAPI[] { + private get availableLabels(): APILabel[] { const {selectedLabels} = this.props const {filteredLabels} = this.state @@ -288,6 +300,12 @@ class LabelSelector extends Component { /> ) } + + private handleCreateLabel = async (label: APILabel) => { + const newLabel = await client.labels.create(label.name, label.properties) + this.props.onAddLabel(newLabel) + this.handleStopSuggesting() + } } export default LabelSelector diff --git a/ui/src/clockface/components/label/LabelSelectorMenu.tsx b/ui/src/clockface/components/label/LabelSelectorMenu.tsx index df601647b8b..79ec100c390 100644 --- a/ui/src/clockface/components/label/LabelSelectorMenu.tsx +++ b/ui/src/clockface/components/label/LabelSelectorMenu.tsx @@ -5,19 +5,22 @@ import _ from 'lodash' // Components import FancyScrollbar from 'src/shared/components/fancy_scrollbar/FancyScrollbar' import LabelSelectorMenuItem from 'src/clockface/components/label/LabelSelectorMenuItem' +import ResourceLabelForm from 'src/shared/components/ResourceLabelForm' // Decorators import {ErrorHandling} from 'src/shared/decorators/errors' // Types -import {Label} from '@influxdata/influx' +import {Label} from 'src/types/v2/labels' interface Props { + filterValue: string highlightItemID: string filteredLabels: Label[] onItemClick: (labelID: string) => void onItemHighlight: (labelID: string) => void allLabelsUsed: boolean + onCreateLabel: (label: Label) => Promise } @ErrorHandling @@ -26,7 +29,10 @@ class LabelSelectorMenu extends Component { return (
-
{this.menuItems}
+
+ {this.resourceLabelForm} + {this.menuItems} +
) @@ -67,6 +73,18 @@ class LabelSelectorMenu extends Component { return 'No labels match your query' } + + private get resourceLabelForm(): JSX.Element { + const {filterValue, onCreateLabel, filteredLabels} = this.props + + if (!filterValue || filteredLabels.find(l => l.name === filterValue)) { + return + } + + return ( + + ) + } } export default LabelSelectorMenu diff --git a/ui/src/clockface/components/label/LabelSelectorMenuItem.tsx b/ui/src/clockface/components/label/LabelSelectorMenuItem.tsx index af07ea7dae8..5e6e6d7720c 100644 --- a/ui/src/clockface/components/label/LabelSelectorMenuItem.tsx +++ b/ui/src/clockface/components/label/LabelSelectorMenuItem.tsx @@ -1,6 +1,5 @@ // Libraries import React, {Component} from 'react' -import classnames from 'classnames' import _ from 'lodash' // Components @@ -24,30 +23,21 @@ class LabelSelectorMenuItem extends Component { const {name, colorHex, description, id} = this.props return ( -
-
-
-
{description}
-
+