Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,19 +126,10 @@ export const DashboardSettingsFlyout = ({ onClose, ariaLabelledBy }: DashboardSe
if (!savedObjectsTaggingApi) return;

return (
<EuiFormRow
label={
<FormattedMessage
id="dashboard.embeddableApi.showSettings.flyout.form.tagsFormRowLabel"
defaultMessage="Tags"
/>
}
>
<savedObjectsTaggingApi.ui.components.TagSelector
selected={localSettings.tags ?? []}
onTagsSelected={(selectedTags) => updateDashboardSetting({ tags: selectedTags })}
/>
</EuiFormRow>
<savedObjectsTaggingApi.ui.components.SavedObjectSaveModalTagSelector
initialSelection={localSettings.tags ?? []}
onTagsSelected={(selectedTags) => updateDashboardSetting({ tags: selectedTags })}
/>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1471,7 +1471,6 @@
"dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchLabel": "Farbpaletten zwischen den Bedienfeldern synchronisieren",
"dashboard.embeddableApi.showSettings.flyout.form.syncCursorBetweenPanelsSwitchLabel": "Cursor über alle Felder hinweg synchronisieren",
"dashboard.embeddableApi.showSettings.flyout.form.syncTooltipsBetweenPanelsSwitchLabel": "Synchrone Tooltips für alle Bedienfelder",
"dashboard.embeddableApi.showSettings.flyout.form.tagsFormRowLabel": "Tags",
"dashboard.embeddableApi.showSettings.flyout.form.useMarginsBetweenPanelsSwitchLabel": "Verwenden Sie Abstände zwischen den Panels",
"dashboard.embeddableApi.showSettings.flyout.formRow.syncAcrossPanelsLabel": "Über alle Felder hinweg synchronisieren",
"dashboard.embeddableApi.showSettings.flyout.title": "Dashboard-Einstellungen",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1488,7 +1488,6 @@
"dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchLabel": "Synchroniser les palettes de couleur de tous les panneaux",
"dashboard.embeddableApi.showSettings.flyout.form.syncCursorBetweenPanelsSwitchLabel": "Synchroniser le curseur de tous les panneaux",
"dashboard.embeddableApi.showSettings.flyout.form.syncTooltipsBetweenPanelsSwitchLabel": "Synchroniser les infobulles de tous les panneaux",
"dashboard.embeddableApi.showSettings.flyout.form.tagsFormRowLabel": "Balises",
"dashboard.embeddableApi.showSettings.flyout.form.useMarginsBetweenPanelsSwitchLabel": "Utiliser des marges entre les panneaux",
"dashboard.embeddableApi.showSettings.flyout.formRow.syncAcrossPanelsLabel": "Synchroniser sur tous les panneaux",
"dashboard.embeddableApi.showSettings.flyout.title": "Paramètres du tableau de bord",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1491,7 +1491,6 @@
"dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchLabel": "パネル全体でカラーパレットを同期",
"dashboard.embeddableApi.showSettings.flyout.form.syncCursorBetweenPanelsSwitchLabel": "パネル全体でカーソルを同期",
"dashboard.embeddableApi.showSettings.flyout.form.syncTooltipsBetweenPanelsSwitchLabel": "パネル間でツールチップを同期",
"dashboard.embeddableApi.showSettings.flyout.form.tagsFormRowLabel": "タグ",
"dashboard.embeddableApi.showSettings.flyout.form.useMarginsBetweenPanelsSwitchLabel": "パネルの間に余白を使用",
"dashboard.embeddableApi.showSettings.flyout.formRow.syncAcrossPanelsLabel": "パネル全体で同期",
"dashboard.embeddableApi.showSettings.flyout.title": "ダッシュボード設定",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1485,7 +1485,6 @@
"dashboard.embeddableApi.showSettings.flyout.form.syncColorsBetweenPanelsSwitchLabel": "在面板之间同步调色板",
"dashboard.embeddableApi.showSettings.flyout.form.syncCursorBetweenPanelsSwitchLabel": "在面板之间同步光标",
"dashboard.embeddableApi.showSettings.flyout.form.syncTooltipsBetweenPanelsSwitchLabel": "在面板之间同步工具提示",
"dashboard.embeddableApi.showSettings.flyout.form.tagsFormRowLabel": "标签",
"dashboard.embeddableApi.showSettings.flyout.form.useMarginsBetweenPanelsSwitchLabel": "在面板间使用边距",
"dashboard.embeddableApi.showSettings.flyout.formRow.syncAcrossPanelsLabel": "跨面板同步",
"dashboard.embeddableApi.showSettings.flyout.title": "仪表板设置",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export const TagSelector: FC<TagSelectorProps> = ({
allowCreate,
openCreateModal,
fullWidth = true,
...otherProps
...comboBoxProps
}) => {
const [currentSearch, setCurrentSearch] = useState('');

Expand Down Expand Up @@ -175,16 +175,26 @@ export const TagSelector: FC<TagSelectorProps> = ({
[selected, onTagsSelected, openCreateModal, currentSearch]
);

const { onSearchChange: onSearchChangeProp, ...restProps } = comboBoxProps;

const handleOnSearchChange = useCallback(
(searchValue: string) => {
setCurrentSearch(searchValue);
onSearchChangeProp?.(searchValue);
},
[onSearchChangeProp]
);

return (
<EuiComboBox<Tag | CreateOption>
placeholder={''}
options={options}
selectedOptions={selectedOptions}
onSearchChange={setCurrentSearch}
onSearchChange={handleOnSearchChange}
onChange={onChange}
renderOption={renderOption}
fullWidth={fullWidth}
{...otherProps}
{...restProps}
/>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import useObservable from 'react-use/lib/useObservable';
import { EuiFormRow, EuiText } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n-react';
import type { SavedObjectSaveModalTagSelectorComponentProps } from '@kbn/saved-objects-tagging-oss-plugin/public';
import { i18n } from '@kbn/i18n';
import type { TagsCapabilities } from '../../../common';
import { TagSelector } from '../base';
import type { ITagsCache } from '../../services';
Expand All @@ -35,6 +36,44 @@ export const getConnectedSavedObjectModalTagSelectorComponent = ({
}: SavedObjectSaveModalTagSelectorComponentProps) => {
const tags = useObservable(cache.getState$(), cache.getState());
const [selected, setSelected] = useState<string[]>(initialSelection);
const [searchValue, setSearchValue] = useState('');
const [touched, setTouched] = useState(false);

const normalizedSearchValue = searchValue.trim().toLowerCase();

const exactTagMatch = !!normalizedSearchValue
? tags.find((tag) => tag.name.toLowerCase() === normalizedSearchValue)
: undefined;

const isTagAlreadyCreated = !!exactTagMatch;
const isTagAlreadySelected = isTagAlreadyCreated && selected.includes(exactTagMatch.id);
const noMatchingTag = !!normalizedSearchValue && !isTagAlreadyCreated;
const isInvalid = touched && (noMatchingTag || isTagAlreadyCreated || isTagAlreadySelected);

const getErrorMessage = () => {
if (isTagAlreadySelected) {
return i18n.translate('xpack.savedObjectsTagging.uiApi.saveModal.alreadySelectedHint', {
defaultMessage: 'Tag "{searchValue}" is already selected.',
values: { searchValue },
});
}
if (isTagAlreadyCreated) {
return i18n.translate('xpack.savedObjectsTagging.uiApi.saveModal.exactTagMatchHint', {
defaultMessage: 'Tag "{searchValue}" already exists. Select it from the existing tags.',
values: { searchValue },
});
}
return capabilities.create
? i18n.translate('xpack.savedObjectsTagging.uiApi.saveModal.noMatchingTagCreateHint', {
defaultMessage:
'No tags match "{searchValue}". Select an existing tag or create a new one.',
values: { searchValue },
})
: i18n.translate('xpack.savedObjectsTagging.uiApi.saveModal.noMatchingTagHint', {
defaultMessage: 'No tags match "{searchValue}".',
values: { searchValue },
});
};

const setSelectedInternal = useCallback(
(newSelection: string[]) => {
Expand Down Expand Up @@ -63,6 +102,8 @@ export const getConnectedSavedObjectModalTagSelectorComponent = ({
</EuiText>
)
}
isInvalid={isInvalid}
error={isInvalid ? getErrorMessage() : undefined}
>
<TagSelector
selected={selected}
Expand All @@ -71,6 +112,9 @@ export const getConnectedSavedObjectModalTagSelectorComponent = ({
data-test-subj="savedObjectTagSelector"
allowCreate={capabilities.create}
openCreateModal={openCreateModal}
onSearchChange={setSearchValue}
onBlur={() => setTouched(true)}
isInvalid={isInvalid}
{...rest}
/>
</EuiFormRow>
Expand Down