mirror of
https://github.com/mattermost/focalboard.git
synced 2024-12-27 13:48:52 +02:00
[GH-1013] Fix visibility of clear button for select option (#1160)
* Show clear button for (multi)select property only when it is being edited. * Files for multi-select property moved to separate folder. * Extracted component for select property. * Minor tweaks for Label style. * Redundant code for clear button removed. * Unit test for select property component added. * Jest snapshots updated. * Fix stylelint error. * Jest snapshot updated. Co-authored-by: Scott Bishel <scott.bishel@mattermost.com>
This commit is contained in:
parent
826e717af8
commit
ca2116c04b
@ -56,6 +56,7 @@ exports[`components/propertyValueElement should match snapshot, select 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -66,16 +67,6 @@ exports[`components/propertyValueElement should match snapshot, select 1`] = `
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,6 +76,7 @@ exports[`components/propertyValueElement should match snapshot, select, read-onl
|
||||
<div>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
@ -28,6 +28,7 @@ exports[`components/cardDetail/CardDetailProperties should match snapshot 1`] =
|
||||
</div>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -38,16 +39,6 @@ exports[`components/cardDetail/CardDetailProperties should match snapshot 1`] =
|
||||
>
|
||||
Jean-Luc Picard
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -35,7 +35,7 @@
|
||||
right: 0;
|
||||
}
|
||||
|
||||
> .octo-propertyvalue {
|
||||
.octo-propertyvalue {
|
||||
margin: 4px 0 0;
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
|
@ -6,7 +6,7 @@ import userEvent from '@testing-library/user-event'
|
||||
import '@testing-library/jest-dom'
|
||||
import {IntlProvider} from 'react-intl'
|
||||
|
||||
import {IPropertyOption, IPropertyTemplate} from '../../blocks/board'
|
||||
import {IPropertyOption, IPropertyTemplate} from '../../../blocks/board'
|
||||
|
||||
import MultiSelect from './multiSelect'
|
||||
|
@ -3,11 +3,11 @@
|
||||
|
||||
import React, {useState} from 'react'
|
||||
|
||||
import {IPropertyOption, IPropertyTemplate} from '../../blocks/board'
|
||||
import {IPropertyOption, IPropertyTemplate} from '../../../blocks/board'
|
||||
|
||||
import Label from '../../widgets/label'
|
||||
import Label from '../../../widgets/label'
|
||||
|
||||
import ValueSelector from '../../widgets/valueSelector'
|
||||
import ValueSelector from '../../../widgets/valueSelector'
|
||||
|
||||
type Props = {
|
||||
emptyValue: string;
|
||||
@ -44,7 +44,9 @@ const MultiSelectProperty = (props: Props): JSX.Element => {
|
||||
</Label>
|
||||
))}
|
||||
{values.length === 0 && (
|
||||
<Label color='empty'>{''}</Label>
|
||||
<Label
|
||||
color='empty'
|
||||
>{''}</Label>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
@ -61,6 +63,7 @@ const MultiSelectProperty = (props: Props): JSX.Element => {
|
||||
onDeleteOption={onDeleteOption}
|
||||
onDeleteValue={(valueToRemove) => onDeleteValue(valueToRemove, values)}
|
||||
onCreate={(newValue) => onCreate(newValue, values)}
|
||||
onBlur={() => setOpen(false)}
|
||||
/>
|
||||
)
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`components/properties/select shows empty placeholder 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="Label empty "
|
||||
>
|
||||
<span
|
||||
class="Label-text"
|
||||
>
|
||||
Empty
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`components/properties/select shows the selected option 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
class="Label propColorDefault "
|
||||
>
|
||||
<span
|
||||
class="Label-text"
|
||||
>
|
||||
one
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
193
webapp/src/components/properties/select/select.test.tsx
Normal file
193
webapp/src/components/properties/select/select.test.tsx
Normal file
@ -0,0 +1,193 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
import {render, screen} from '@testing-library/react'
|
||||
import '@testing-library/jest-dom'
|
||||
|
||||
import userEvent from '@testing-library/user-event'
|
||||
|
||||
import {IPropertyTemplate} from '../../../blocks/board'
|
||||
|
||||
import {wrapIntl} from '../../../testUtils'
|
||||
|
||||
import Select from './select'
|
||||
|
||||
function selectPropertyTemplate(): IPropertyTemplate {
|
||||
return {
|
||||
id: 'select-template',
|
||||
name: 'select',
|
||||
type: 'select',
|
||||
options: [
|
||||
{
|
||||
id: 'option-1',
|
||||
value: 'one',
|
||||
color: 'propColorDefault',
|
||||
},
|
||||
{
|
||||
id: 'option-2',
|
||||
value: 'two',
|
||||
color: 'propColorGreen',
|
||||
},
|
||||
{
|
||||
id: 'option-3',
|
||||
value: 'three',
|
||||
color: 'propColorRed',
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
function selectCallbacks() {
|
||||
return {
|
||||
onCreate: jest.fn(),
|
||||
onChange: jest.fn(),
|
||||
onChangeColor: jest.fn(),
|
||||
onDeleteOption: jest.fn(),
|
||||
onDeleteValue: jest.fn(),
|
||||
}
|
||||
}
|
||||
|
||||
describe('components/properties/select', () => {
|
||||
const nonEditableSelectTestId = 'select-non-editable'
|
||||
|
||||
const clearButton = () => screen.queryByRole('button', {name: /clear/i})
|
||||
|
||||
it('shows the selected option', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const option = propertyTemplate.options[0]
|
||||
|
||||
const {container} = render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={''}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={option.id}
|
||||
isEditable={false}
|
||||
{...selectCallbacks()}
|
||||
/>,
|
||||
))
|
||||
|
||||
expect(screen.getByText(option.value)).toBeInTheDocument()
|
||||
expect(clearButton()).not.toBeInTheDocument()
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('shows empty placeholder', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const emptyValue = 'Empty'
|
||||
|
||||
const {container} = render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={emptyValue}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={''}
|
||||
isEditable={false}
|
||||
{...selectCallbacks()}
|
||||
/>,
|
||||
))
|
||||
|
||||
expect(screen.getByText(emptyValue)).toBeInTheDocument()
|
||||
expect(clearButton()).not.toBeInTheDocument()
|
||||
|
||||
expect(container).toMatchSnapshot()
|
||||
})
|
||||
|
||||
it('shows the menu with options when preview is clicked', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const selected = propertyTemplate.options[1]
|
||||
|
||||
render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={''}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={selected.id}
|
||||
isEditable={true}
|
||||
{...selectCallbacks()}
|
||||
/>,
|
||||
))
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableSelectTestId))
|
||||
|
||||
// check that all options are visible
|
||||
for (const option of propertyTemplate.options) {
|
||||
const elements = screen.getAllByText(option.value)
|
||||
|
||||
// selected option is rendered twice: in the input and inside the menu
|
||||
const expected = option.id === selected.id ? 2 : 1
|
||||
expect(elements.length).toBe(expected)
|
||||
}
|
||||
|
||||
expect(clearButton()).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('can select the option from menu', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const optionToSelect = propertyTemplate.options[2]
|
||||
const onChange = jest.fn()
|
||||
|
||||
render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={'Empty'}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={''}
|
||||
isEditable={true}
|
||||
{...selectCallbacks()}
|
||||
onChange={onChange}
|
||||
/>,
|
||||
))
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableSelectTestId))
|
||||
userEvent.click(screen.getByText(optionToSelect.value))
|
||||
|
||||
expect(clearButton()).not.toBeInTheDocument()
|
||||
expect(onChange).toHaveBeenCalledWith(optionToSelect.id)
|
||||
})
|
||||
|
||||
it('can clear the selected option', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const selected = propertyTemplate.options[1]
|
||||
const onDeleteValue = jest.fn()
|
||||
|
||||
render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={'Empty'}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={selected.id}
|
||||
isEditable={true}
|
||||
{...selectCallbacks()}
|
||||
onDeleteValue={onDeleteValue}
|
||||
/>,
|
||||
))
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableSelectTestId))
|
||||
|
||||
const clear = clearButton()
|
||||
expect(clear).toBeInTheDocument()
|
||||
userEvent.click(clear!)
|
||||
|
||||
expect(onDeleteValue).toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('can create new option', () => {
|
||||
const propertyTemplate = selectPropertyTemplate()
|
||||
const initialOption = propertyTemplate.options[0]
|
||||
const newOption = 'new-option'
|
||||
const onCreate = jest.fn()
|
||||
|
||||
render(wrapIntl(
|
||||
<Select
|
||||
emptyValue={'Empty'}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={initialOption.id}
|
||||
isEditable={true}
|
||||
{...selectCallbacks()}
|
||||
onCreate={onCreate}
|
||||
/>,
|
||||
))
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableSelectTestId))
|
||||
userEvent.type(screen.getByRole('textbox', {name: /value selector/i}), `${newOption}{enter}`)
|
||||
|
||||
expect(onCreate).toHaveBeenCalledWith(newOption)
|
||||
})
|
||||
})
|
61
webapp/src/components/properties/select/select.tsx
Normal file
61
webapp/src/components/properties/select/select.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import React, {useState} from 'react'
|
||||
|
||||
import {IPropertyOption, IPropertyTemplate} from '../../../blocks/board'
|
||||
|
||||
import Label from '../../../widgets/label'
|
||||
import ValueSelector from '../../../widgets/valueSelector'
|
||||
|
||||
type Props = {
|
||||
emptyValue: string
|
||||
propertyValue: string
|
||||
propertyTemplate: IPropertyTemplate
|
||||
onCreate: (value: string) => void
|
||||
onChange: (value: string) => void
|
||||
onChangeColor: (option: IPropertyOption, color: string) => void
|
||||
onDeleteOption: (option: IPropertyOption) => void
|
||||
onDeleteValue: () => void;
|
||||
isEditable: boolean
|
||||
}
|
||||
|
||||
const SelectProperty = React.memo((props: Props) => {
|
||||
const {emptyValue, propertyValue, propertyTemplate, isEditable} = props
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const option = propertyTemplate.options.find((o) => o.id === propertyValue)
|
||||
const propertyColorCssClassName = option?.color || ''
|
||||
const displayValue = option?.value
|
||||
const finalDisplayValue = displayValue || emptyValue
|
||||
|
||||
if (!isEditable || !open) {
|
||||
return (
|
||||
<div
|
||||
className='octo-propertyvalue'
|
||||
data-testid='select-non-editable'
|
||||
tabIndex={0}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<Label color={displayValue ? propertyColorCssClassName : 'empty'}>
|
||||
<span className='Label-text'>{finalDisplayValue}</span>
|
||||
</Label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ValueSelector
|
||||
emptyValue={emptyValue}
|
||||
options={propertyTemplate.options}
|
||||
value={propertyTemplate.options.find((p) => p.id === propertyValue)}
|
||||
onCreate={props.onCreate}
|
||||
onChange={(value) => props.onChange(value as string)}
|
||||
onChangeColor={props.onChangeColor}
|
||||
onDeleteOption={props.onDeleteOption}
|
||||
onDeleteValue={props.onDeleteValue}
|
||||
onBlur={() => setOpen(false)}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
export default SelectProperty
|
@ -12,22 +12,17 @@ import mutator from '../mutator'
|
||||
import {OctoUtils} from '../octoUtils'
|
||||
import {Utils} from '../utils'
|
||||
import Editable from '../widgets/editable'
|
||||
import ValueSelector from '../widgets/valueSelector'
|
||||
|
||||
import Label from '../widgets/label'
|
||||
|
||||
import Switch from '../widgets/switch'
|
||||
import IconButton from '../widgets/buttons/iconButton'
|
||||
import CloseIcon from '../widgets/icons/close'
|
||||
|
||||
import UserProperty from './properties/user/user'
|
||||
import MultiSelectProperty from './properties/multiSelect'
|
||||
import MultiSelectProperty from './properties/multiSelect/multiSelect'
|
||||
import URLProperty from './properties/link/link'
|
||||
import LastModifiedBy from './properties/lastModifiedBy/lastModifiedBy'
|
||||
import LastModifiedAt from './properties/lastModifiedAt/lastModifiedAt'
|
||||
import CreatedAt from './properties/createdAt/createdAt'
|
||||
import CreatedBy from './properties/createdBy/createdBy'
|
||||
import DateRange from './properties/dateRange/dateRange'
|
||||
import SelectProperty from './properties/select/select'
|
||||
|
||||
type Props = {
|
||||
board: Board
|
||||
@ -48,7 +43,6 @@ const PropertyValueElement = (props:Props): JSX.Element => {
|
||||
const propertyValue = card.fields.properties[propertyTemplate.id]
|
||||
const displayValue = OctoUtils.propertyDisplayValue(card, propertyValue, propertyTemplate, intl)
|
||||
const finalDisplayValue = displayValue || emptyDisplayValue
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
const editableFields: Array<PropertyType> = ['text', 'number', 'email', 'url', 'phone']
|
||||
|
||||
@ -130,47 +124,12 @@ const PropertyValueElement = (props:Props): JSX.Element => {
|
||||
}
|
||||
|
||||
if (propertyTemplate.type === 'select') {
|
||||
let propertyColorCssClassName = ''
|
||||
const cardPropertyValue = propertyTemplate.options.find((o) => o.id === propertyValue)
|
||||
if (cardPropertyValue) {
|
||||
propertyColorCssClassName = cardPropertyValue.color
|
||||
}
|
||||
|
||||
if (readOnly || !board || !open) {
|
||||
return (
|
||||
<div
|
||||
className='octo-propertyvalue'
|
||||
tabIndex={0}
|
||||
onClick={() => setOpen(true)}
|
||||
>
|
||||
<Label color={displayValue ? propertyColorCssClassName : 'empty'}>
|
||||
<span className='Label-text'>{finalDisplayValue}</span>
|
||||
{displayValue && !props.readOnly &&
|
||||
<IconButton
|
||||
onClick={onDeleteValue}
|
||||
onMouseDown={(e: React.MouseEvent) => e.stopPropagation()}
|
||||
icon={<CloseIcon/>}
|
||||
title='Clear'
|
||||
className='margin-left delete-value'
|
||||
/>}
|
||||
</Label>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<ValueSelector
|
||||
<SelectProperty
|
||||
isEditable={!readOnly && Boolean(board)}
|
||||
emptyValue={emptyDisplayValue}
|
||||
options={propertyTemplate.options}
|
||||
value={propertyTemplate.options.find((p) => p.id === propertyValue)}
|
||||
onChange={(newValue) => {
|
||||
mutator.changePropertyValue(card, propertyTemplate.id, newValue)
|
||||
}}
|
||||
onChangeColor={(option: IPropertyOption, colorId: string): void => {
|
||||
mutator.changePropertyOptionColor(board, propertyTemplate, option, colorId)
|
||||
}}
|
||||
onDeleteOption={(option: IPropertyOption): void => {
|
||||
mutator.deletePropertyOption(board, propertyTemplate, option)
|
||||
}}
|
||||
propertyValue={propertyValue as string}
|
||||
propertyTemplate={propertyTemplate}
|
||||
onCreate={
|
||||
async (newValue) => {
|
||||
const option: IPropertyOption = {
|
||||
@ -182,6 +141,15 @@ const PropertyValueElement = (props:Props): JSX.Element => {
|
||||
mutator.changePropertyValue(card, propertyTemplate.id, option.id)
|
||||
}
|
||||
}
|
||||
onChange={(newValue) => {
|
||||
mutator.changePropertyValue(card, propertyTemplate.id, newValue)
|
||||
}}
|
||||
onChangeColor={(option: IPropertyOption, colorId: string): void => {
|
||||
mutator.changePropertyOptionColor(board, propertyTemplate, option, colorId)
|
||||
}}
|
||||
onDeleteOption={(option: IPropertyOption): void => {
|
||||
mutator.deletePropertyOption(board, propertyTemplate, option)
|
||||
}}
|
||||
onDeleteValue={onDeleteValue}
|
||||
/>
|
||||
)
|
||||
|
@ -180,6 +180,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -190,16 +191,6 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -209,6 +200,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -276,6 +268,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -286,16 +279,6 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -305,6 +288,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -584,6 +568,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -594,16 +579,6 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -613,6 +588,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -680,6 +656,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -690,16 +667,6 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -709,6 +676,7 @@ exports[`components/table/Table extended should match snapshot with CreatedBy 2`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -988,6 +956,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -998,16 +967,6 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1017,6 +976,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1084,6 +1044,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1094,16 +1055,6 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1113,6 +1064,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedAt 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1392,6 +1344,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1402,16 +1355,6 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1421,6 +1364,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1488,6 +1432,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1498,16 +1443,6 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1517,6 +1452,7 @@ exports[`components/table/Table extended should match snapshot with UpdatedBy 1`
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1772,6 +1708,7 @@ exports[`components/table/Table should match snapshot 1`] = `
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -1782,16 +1719,6 @@ exports[`components/table/Table should match snapshot 1`] = `
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1801,6 +1728,7 @@ exports[`components/table/Table should match snapshot 1`] = `
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -2255,6 +2183,7 @@ exports[`components/table/Table should match snapshot, read-only 1`] = `
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -2274,6 +2203,7 @@ exports[`components/table/Table should match snapshot, read-only 1`] = `
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
@ -137,6 +137,7 @@ exports[`components/table/TableRow should match snapshot, display properties 1`]
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -147,16 +148,6 @@ exports[`components/table/TableRow should match snapshot, display properties 1`]
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -166,6 +157,7 @@ exports[`components/table/TableRow should match snapshot, display properties 1`]
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -319,6 +311,7 @@ exports[`components/table/TableRow should match snapshot, resizing column 1`] =
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
@ -329,16 +322,6 @@ exports[`components/table/TableRow should match snapshot, resizing column 1`] =
|
||||
>
|
||||
value 1
|
||||
</span>
|
||||
<div
|
||||
aria-label="Clear"
|
||||
class="Button IconButton margin-left delete-value"
|
||||
role="button"
|
||||
title="Clear"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-close CloseIcon"
|
||||
/>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -348,6 +331,7 @@ exports[`components/table/TableRow should match snapshot, resizing column 1`] =
|
||||
>
|
||||
<div
|
||||
class="octo-propertyvalue"
|
||||
data-testid="select-non-editable"
|
||||
tabindex="0"
|
||||
>
|
||||
<span
|
||||
|
@ -3,7 +3,7 @@
|
||||
import {IntlProvider} from 'react-intl'
|
||||
import React from 'react'
|
||||
|
||||
export const wrapIntl = (children: any) => <IntlProvider locale='en'>{children}</IntlProvider>
|
||||
export const wrapIntl = (children?: React.ReactNode): JSX.Element => <IntlProvider locale='en'>{children}</IntlProvider>
|
||||
|
||||
export function mockDOM(): void {
|
||||
window.focus = jest.fn()
|
||||
|
@ -2,6 +2,8 @@
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
border-radius: 3px;
|
||||
line-height: 20px;
|
||||
color: rgba(var(--center-channel-color-rgb), 0.8);
|
||||
@ -9,8 +11,6 @@
|
||||
text-transform: uppercase;
|
||||
font-weight: 600;
|
||||
font-size: 13px;
|
||||
margin-right: 5px;
|
||||
margin-bottom: 5px;
|
||||
|
||||
input {
|
||||
line-height: 20px;
|
||||
|
@ -10,7 +10,7 @@ type Props = {
|
||||
color?: string
|
||||
title?: string
|
||||
children: React.ReactNode
|
||||
classNames?: string
|
||||
className?: string
|
||||
}
|
||||
|
||||
// Switch is an on-off style switch / checkbox
|
||||
@ -21,7 +21,7 @@ function Label(props: Props): JSX.Element {
|
||||
}
|
||||
return (
|
||||
<span
|
||||
className={`Label ${color} ${props.classNames ? props.classNames : ''}`}
|
||||
className={`Label ${color} ${props.className ? props.className : ''}`}
|
||||
title={props.title}
|
||||
>
|
||||
{props.children}
|
||||
|
@ -36,6 +36,10 @@
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.Label-no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.Label-single-select {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ type Props = {
|
||||
onDeleteOption: (option: IPropertyOption) => void
|
||||
isMulti?: boolean
|
||||
onDeleteValue?: (value: IPropertyOption) => void
|
||||
onBlur?: () => void
|
||||
}
|
||||
|
||||
type LabelProps = {
|
||||
@ -40,22 +41,26 @@ type LabelProps = {
|
||||
onChangeColor: (option: IPropertyOption, color: string) => void
|
||||
onDeleteOption: (option: IPropertyOption) => void
|
||||
onDeleteValue?: (value: IPropertyOption) => void
|
||||
isMulti?: boolean
|
||||
}
|
||||
|
||||
const ValueSelectorLabel = React.memo((props: LabelProps): JSX.Element => {
|
||||
const {option, onDeleteValue, meta} = props
|
||||
const {option, onDeleteValue, meta, isMulti} = props
|
||||
const intl = useIntl()
|
||||
if (meta.context === 'value') {
|
||||
let className = onDeleteValue ? 'Label-no-padding' : 'Label-single-select'
|
||||
if (!isMulti) {
|
||||
className += ' Label-no-margin'
|
||||
}
|
||||
return (
|
||||
<Label
|
||||
color={option.color}
|
||||
classNames={`${onDeleteValue ? 'Label-no-padding' : 'Label-single-select'}`}
|
||||
className={className}
|
||||
>
|
||||
<span className='Label-text'>{option.value}</span>
|
||||
{onDeleteValue &&
|
||||
<IconButton
|
||||
onClick={() => onDeleteValue(option)}
|
||||
onMouseDown={(e) => e.stopPropagation()}
|
||||
icon={<CloseIcon/>}
|
||||
title='Clear'
|
||||
className='margin-left delete-value'
|
||||
@ -114,6 +119,12 @@ const valueSelectorStyle = {
|
||||
padding: '0 8px',
|
||||
overflow: 'unset',
|
||||
}),
|
||||
singleValue: (provided: CSSObject): CSSObject => ({
|
||||
...provided,
|
||||
position: 'static',
|
||||
top: 'unset',
|
||||
transform: 'unset',
|
||||
}),
|
||||
multiValue: (provided: CSSObject): CSSObject => ({
|
||||
...provided,
|
||||
margin: 0,
|
||||
@ -151,6 +162,7 @@ function ValueSelector(props: Props): JSX.Element {
|
||||
<ValueSelectorLabel
|
||||
option={option}
|
||||
meta={meta}
|
||||
isMulti={props.isMulti}
|
||||
onChangeColor={props.onChangeColor}
|
||||
onDeleteOption={props.onDeleteOption}
|
||||
onDeleteValue={props.onDeleteValue}
|
||||
@ -171,6 +183,7 @@ function ValueSelector(props: Props): JSX.Element {
|
||||
props.onChange('')
|
||||
}
|
||||
}}
|
||||
onBlur={props.onBlur}
|
||||
onCreateOption={props.onCreate}
|
||||
autoFocus={true}
|
||||
value={props.value}
|
||||
|
Loading…
Reference in New Issue
Block a user