@@ -17,6 +17,7 @@ import { TagDto } from "types/Tag";
1717import { useActionWithPath , useTags } from "utils/query" ;
1818import { getErrorMessage } from "utils/utils" ;
1919import ReplaceTagsInput from "components/features/tags/ReplaceTagsInput" ;
20+ import { isValidTag } from "components/features/tags/tagUtils" ;
2021
2122export type TagDialogProps = {
2223 open : boolean ;
@@ -56,6 +57,7 @@ export default function AddTagDialog({
5657 const [ newTags , setNewTags ] = useState < string [ ] > (
5758 tags . map ( ( tag : TagDto ) => tag && `${ tag . key } :${ tag . value } ` ) ,
5859 ) ;
60+ const [ pendingInput , setPendingInput ] = useState ( "" ) ;
5961 // Only fetch all tags when the dialog is open (avoids slow /metadata/tags on every page that mounts this dialog).
6062 const { data : existingTags } = useTags < TagDto [ ] > ( { enabled : open } ) ;
6163
@@ -78,6 +80,9 @@ export default function AddTagDialog({
7880 const hasNoChanges =
7981 _differenceWith ( tags , parsedTags ( newTags ) , isTagEqual ) . length === 0 &&
8082 newTags . length === tags . length ;
83+ const hasInvalidTags = newTags . some ( ( tag ) => ! isValidTag ( tag ) ) ;
84+ const isSaveDisabled =
85+ hasNoChanges || pendingInput . trim ( ) . length > 0 || hasInvalidTags ;
8186
8287 function replaceTags ( newTags : any ) {
8388 for ( const tag of newTags ) {
@@ -137,6 +142,9 @@ export default function AddTagDialog({
137142 onChange = { ( tags ) => {
138143 setNewTags ( _uniq ( tags ) ) ;
139144 } }
145+ onInputChange = { ( value ) => {
146+ setPendingInput ( value ) ;
147+ } }
140148 />
141149 </ Box >
142150 </ DialogContent >
@@ -155,7 +163,7 @@ export default function AddTagDialog({
155163 variant = "contained"
156164 color = "primary"
157165 progress = { loading }
158- disabled = { hasNoChanges }
166+ disabled = { isSaveDisabled }
159167 onClick = { ( ) => replaceTags ( newTags ) }
160168 startIcon = { < SaveIcon /> }
161169 >
0 commit comments