diff --git a/app/portainer/react/components/index.ts b/app/portainer/react/components/index.ts
index 3433f10ef..793ff68ce 100644
--- a/app/portainer/react/components/index.ts
+++ b/app/portainer/react/components/index.ts
@@ -34,6 +34,7 @@ import { BadgeIcon } from '@@/BadgeIcon';
import { TeamsSelector } from '@@/TeamsSelector';
import { PortainerSelect } from '@@/form-components/PortainerSelect';
import { Slider } from '@@/form-components/Slider';
+import { TagButton } from '@@/TagButton';
import { fileUploadField } from './file-upload-field';
import { switchField } from './switch-field';
@@ -45,6 +46,10 @@ export const componentsModule = angular
'tagSelector',
r2a(withReactQuery(TagSelector), ['allowCreate', 'onChange', 'value'])
)
+ .component(
+ 'tagButton',
+ r2a(TagButton, ['value', 'label', 'title', 'onRemove'])
+ )
.component(
'portainerTooltip',
r2a(Tooltip, ['message', 'position', 'className'])
diff --git a/app/react/components/TagSelector/TagSelector.module.css b/app/react/components/TagButton/TagButton.module.css
similarity index 100%
rename from app/react/components/TagSelector/TagSelector.module.css
rename to app/react/components/TagButton/TagButton.module.css
diff --git a/app/react/components/TagButton/TagButton.tsx b/app/react/components/TagButton/TagButton.tsx
new file mode 100644
index 000000000..e649e98c7
--- /dev/null
+++ b/app/react/components/TagButton/TagButton.tsx
@@ -0,0 +1,33 @@
+import clsx from 'clsx';
+import { Trash2 } from 'lucide-react';
+
+import { Icon } from '@/react/components/Icon';
+
+import styles from './TagButton.module.css';
+
+interface Props {
+ value: number;
+ label: string;
+ title: string;
+ onRemove(): void;
+}
+
+export function TagButton({ value, label, title, onRemove }: Props) {
+ return (
+
+ );
+}
diff --git a/app/react/components/TagButton/index.ts b/app/react/components/TagButton/index.ts
new file mode 100644
index 000000000..ed32cb1ec
--- /dev/null
+++ b/app/react/components/TagButton/index.ts
@@ -0,0 +1 @@
+export { TagButton } from './TagButton';
diff --git a/app/react/components/TagSelector/TagSelector.tsx b/app/react/components/TagSelector/TagSelector.tsx
index 2dafeaffc..d50b44a1c 100644
--- a/app/react/components/TagSelector/TagSelector.tsx
+++ b/app/react/components/TagSelector/TagSelector.tsx
@@ -1,16 +1,13 @@
-import clsx from 'clsx';
import _ from 'lodash';
-import { Trash2 } from 'lucide-react';
import { TagId } from '@/portainer/tags/types';
-import { Icon } from '@/react/components/Icon';
import { useCreateTagMutation, useTags } from '@/portainer/tags/queries';
import { Creatable, Select } from '@@/form-components/ReactSelect';
import { FormControl } from '@@/form-components/FormControl';
import { Link } from '@@/Link';
-import styles from './TagSelector.module.css';
+import { TagButton } from '../TagButton';
interface Props {
value: TagId[];
@@ -62,21 +59,12 @@ export function TagSelector({ value, allowCreate = false, onChange }: Props) {
{value.length > 0 && (
{selectedTags.map((tag) => (
-
+ value={tag.value}
+ label={tag.label}
+ onRemove={() => handleRemove(tag.value)}
+ />
))}
)}
@@ -112,6 +100,12 @@ export function TagSelector({ value, allowCreate = false, onChange }: Props) {
if (!allowCreate) {
return;
}
+
+ // Prevent the new tag composed of space from being added
+ if (!inputValue.replace(/\s/g, '').length) {
+ return;
+ }
+
createTagMutation.mutate(inputValue, {
onSuccess(tag) {
handleAdd({ label: tag.Name, value: tag.ID });