This is an automated email from the ASF dual-hosted git repository.

shuai pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git


The following commit(s) were added to refs/heads/dev by this push:
     new 9249dd06 Added isInvalid styles for forms (#935)
9249dd06 is described below

commit 9249dd0679a5818d76b324c7c68a81db8a8f6974
Author: Nayan Thulkar <[email protected]>
AuthorDate: Tue May 28 08:59:08 2024 +0530

    Added isInvalid styles for forms (#935)
    
    ## This PR includes, fixing css style for some of the forms when clicked
    is invalid.
    Issue:- #927
    
    ### Question/ask page
    ![Screenshot 2024-05-01
    
163450](https://github.com/apache/incubator-answer/assets/43349097/90b5337b-85ea-459d-9d59-967968217ada)
    
    
    ### Question/details page
    ![Screenshot 2024-05-01
    
163532](https://github.com/apache/incubator-answer/assets/43349097/8012a67e-9508-4cb9-ab48-e4eb639dacd1)
    
    ---------
    
    Co-authored-by: Nayan <[email protected]>
---
 cmd/wire_gen.go                                    |   5 +-
 ui/pnpm-lock.yaml                                  | 650 ---------------------
 .../components/Comment/components/Form/index.tsx   |   1 +
 .../components/Comment/components/Reply/index.tsx  | 195 ++++---
 ui/src/components/TagSelector/index.tsx            |   6 +
 ui/src/components/TextArea/index.tsx               | 121 ++--
 ui/src/pages/Questions/Ask/index.tsx               |  20 +-
 .../Detail/components/WriteAnswer/index.tsx        |   1 +
 8 files changed, 181 insertions(+), 818 deletions(-)

diff --git a/cmd/wire_gen.go b/cmd/wire_gen.go
index 07b7a324..1fa655d8 100644
--- a/cmd/wire_gen.go
+++ b/cmd/wire_gen.go
@@ -1,6 +1,3 @@
-//go:build !wireinject
-// +build !wireinject
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -23,6 +20,8 @@
 // Code generated by Wire. DO NOT EDIT.
 
 //go:generate go run github.com/google/wire/cmd/wire
+//go:build !wireinject
+// +build !wireinject
 
 package answercmd
 
diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml
index 638da37d..66974ab7 100644
--- a/ui/pnpm-lock.yaml
+++ b/ui/pnpm-lock.yaml
@@ -1,20 +1,3 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements.  See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership.  The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License.  You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied.  See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
 lockfileVersion: '6.0'
 
 settings:
@@ -243,64 +226,6 @@ importers:
         specifier: ^0.8.0
         version: 0.8.0
 
-  src/plugins/captcha-basic:
-    devDependencies:
-      '@typescript-eslint/eslint-plugin':
-        specifier: ^6.0.0
-        version: 
6.11.0(@typescript-eslint/[email protected])([email protected])([email protected])
-      '@typescript-eslint/parser':
-        specifier: ^6.0.0
-        version: 6.11.0([email protected])([email protected])
-      '@vitejs/plugin-react-swc':
-        specifier: ^3.3.2
-        version: 3.5.0([email protected])
-      eslint:
-        specifier: ^8.45.0
-        version: 8.53.0
-      eslint-plugin-react-hooks:
-        specifier: ^4.6.0
-        version: 4.6.0([email protected])
-      eslint-plugin-react-refresh:
-        specifier: ^0.4.3
-        version: 0.4.5([email protected])
-      typescript:
-        specifier: ^5.0.2
-        version: 5.3.2
-      vite:
-        specifier: ^4.4.5
-        version: 4.5.0(@types/[email protected])([email protected])
-
-  src/plugins/captcha-google-v2:
-    dependencies:
-      react-google-recaptcha:
-        specifier: ^3.1.0
-        version: 3.1.0([email protected])
-    devDependencies:
-      '@typescript-eslint/eslint-plugin':
-        specifier: ^6.0.0
-        version: 
6.11.0(@typescript-eslint/[email protected])([email protected])([email protected])
-      '@typescript-eslint/parser':
-        specifier: ^6.0.0
-        version: 6.11.0([email protected])([email protected])
-      '@vitejs/plugin-react-swc':
-        specifier: ^3.3.2
-        version: 3.5.0([email protected])
-      eslint:
-        specifier: ^8.45.0
-        version: 8.53.0
-      eslint-plugin-react-hooks:
-        specifier: ^4.6.0
-        version: 4.6.0([email protected])
-      eslint-plugin-react-refresh:
-        specifier: ^0.4.3
-        version: 0.4.5([email protected])
-      typescript:
-        specifier: ^5.0.2
-        version: 5.3.2
-      vite:
-        specifier: ^4.4.5
-        version: 4.5.0(@types/[email protected])([email protected])
-
 packages:
 
   /@aashutoshrathi/[email protected]:
@@ -2263,204 +2188,6 @@ packages:
       postcss: 8.4.16
       postcss-selector-parser: 6.0.10
 
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [android]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [freebsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==}
-    engines: {node: '>=12'}
-    cpu: [arm]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==}
-    engines: {node: '>=12'}
-    cpu: [loong64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==}
-    engines: {node: '>=12'}
-    cpu: [mips64el]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==}
-    engines: {node: '>=12'}
-    cpu: [ppc64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==}
-    engines: {node: '>=12'}
-    cpu: [riscv64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==}
-    engines: {node: '>=12'}
-    cpu: [s390x]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [linux]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [netbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [openbsd]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [sunos]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==}
-    engines: {node: '>=12'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==}
-    engines: {node: '>=12'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@esbuild/[email protected]:
-    resolution: {integrity: 
sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==}
-    engines: {node: '>=12'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
   /@eslint-community/[email protected]([email protected]):
     resolution: {integrity: 
sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3262,129 +2989,12 @@ packages:
     transitivePeerDependencies:
       - supports-color
 
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-XVWFsKe6ei+SsDbwmsuRkYck1SXRpO60Hioa4hoLwR8fxbA9eVp6enZtMxzVVMBi8ej5seZ4HZQeAWepbukiBw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-KF/MXrnH1nakm1wbt4XV8FS7kvqD9TGmVxeJ0U4bbvxXMvzeYUurzg3AJUTXYmXDhH/VXOYJE5N5RkwZZPs5iA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [darwin]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-p8hikNnAEJrw5vHCtKiFT4hdlQxk1V7vqPmvUDgL/qe2menQDK/i12tbz7/3BEQ4UqUPnvwpmVn2d19RdEMNxw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    libc: [glibc]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-BWx/0EeY89WC4q3AaIaBSGfQxkYxIlS3mX19dwy2FWJs/O+fMvF9oLk/CyJPOZzbp+1DjGeeoGFuDYpiNO91JA==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [linux]
-    libc: [musl]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-XUdGu3dxAkjsahLYnm8WijPfKebo+jHgHphDxaW0ovI6sTdmEGFDew7QzKZRlbYL2jRkUuuKuDGvD6lO5frmhA==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    libc: [glibc]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-PhoXKf+f0OaNW/GCuXjJ0/KfK9EJX7z2gko+7nVnEA0p3aaPtbP6cq1Ubbl6CMoPL+Ci3gZ7nYumDqXNc3CtLQ==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [linux]
-    libc: [musl]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-PwLADZN6F9cXn4Jw52FeP/MCLVHm8vwouZZSOoOScDtihjY495SSjdPnlosMaRSR4wJQssGwiD/4MbpgQPqbAw==}
-    engines: {node: '>=10'}
-    cpu: [arm64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-0f6nicKSLlDKlyPRl2JEmkpBV4aeDfRQg6n8mPqgL7bliZIcDahG0ej+HxgNjZfS3e0yjDxsNRa6sAqWU2Z60A==}
-    engines: {node: '>=10'}
-    cpu: [ia32]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-b7J0rPoMkRTa3XyUGt8PwCaIBuYWsL2DqbirrQKRESzgCvif5iNpqaM6kjIjI/5y5q1Ycv564CB51YDpiS8EtQ==}
-    engines: {node: '>=10'}
-    cpu: [x64]
-    os: [win32]
-    requiresBuild: true
-    dev: true
-    optional: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-7dKgTyxJjlrMwFZYb1auj3Xq0D8ZBe+5oeIgfMlRU05doXZypYJe0LAk0yjj3WdbwYzpF+T1PLxwTWizI0pckw==}
-    engines: {node: '>=10'}
-    requiresBuild: true
-    peerDependencies:
-      '@swc/helpers': ^0.5.0
-    peerDependenciesMeta:
-      '@swc/helpers':
-        optional: true
-    dependencies:
-      '@swc/counter': 0.1.2
-      '@swc/types': 0.1.5
-    optionalDependencies:
-      '@swc/core-darwin-arm64': 1.3.100
-      '@swc/core-darwin-x64': 1.3.100
-      '@swc/core-linux-arm64-gnu': 1.3.100
-      '@swc/core-linux-arm64-musl': 1.3.100
-      '@swc/core-linux-x64-gnu': 1.3.100
-      '@swc/core-linux-x64-musl': 1.3.100
-      '@swc/core-win32-arm64-msvc': 1.3.100
-      '@swc/core-win32-ia32-msvc': 1.3.100
-      '@swc/core-win32-x64-msvc': 1.3.100
-    dev: true
-
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-9F4ys4C74eSTEUNndnER3VJ15oru2NumfQxS8geE+f3eB5xvfxpWyqE5XlVnxb/R14uoXi6SLbBwwiDSkv+XEw==}
-    dev: true
-
   /@swc/[email protected]:
     resolution: {integrity: 
sha512-FaruWX6KdudYloq1AHD/4nU+UsMTdNE8CKyrseXWEcgjDAbvkwJg2QGPAnfIJLIWsjZOSPLOAykK6fuYp4vp4A==}
     dependencies:
       tslib: 2.6.2
     dev: false
 
-  /@swc/[email protected]:
-    resolution: {integrity: 
sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw==}
-    dev: true
-
   /@testing-library/[email protected]:
     resolution: {integrity: 
sha512-oEvsm2B/WtcHKE+IcEeeCqNU/ltFGaVyGbpcm4g/2ytuT49jrlH9x5qRKL/H3A6yfM4YAbSbC0ceT5+9CEXnLg==}
     engines: {node: '>=12'}
@@ -3813,35 +3423,6 @@ packages:
       - supports-color
     dev: true
 
-  
/@typescript-eslint/[email protected](@typescript-eslint/[email protected])([email protected])([email protected]):
-    resolution: {integrity: 
sha512-uXnpZDc4VRjY4iuypDBKzW1rz9T5YBBK0snMn8MaTSNd2kMlj50LnLBABELjJiOL5YHk7ZD8hbSpI9ubzqYI0w==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@eslint-community/regexpp': 4.10.0
-      '@typescript-eslint/parser': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/type-utils': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      eslint: 8.53.0
-      graphemer: 1.4.0
-      ignore: 5.2.4
-      natural-compare: 1.4.0
-      semver: 7.5.4
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.3.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   
/@typescript-eslint/[email protected]([email protected])([email protected]):
     resolution: {integrity: 
sha512-kzXBRfvGlicgGk4CYuRUqKvwc2s3wHXNssUWWJU18bhMRxriFm3BZWyQ6vEHBRpEIMKB6b7MIQHO+9lYlts19w==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3894,27 +3475,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-+whEdjk+d5do5nxfxx73oanLL9ghKO3EwM9kBCkUtWMRwWuPaFv9ScuqlYfQ6pAD6ZiJhky7TZ2ZYhrMsfMxVQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      eslint: 8.53.0
-      typescript: 5.3.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -3969,26 +3529,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-nA4IOXwZtqBjIoYrJcYxLRO+F9ri+leVGoJcMW1uqr4r1Hq7vW5cyWrA43lFbpRvQ9XgNrnfLpIkO3i1emDBIA==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      '@typescript-eslint/utils': 6.11.0([email protected])([email protected])
-      debug: 4.3.4
-      eslint: 8.53.0
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.3.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4039,27 +3579,6 @@ packages:
       - supports-color
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-Aezzv1o2tWJwvZhedzvD5Yv7+Lpu1by/U1LZ5gLc4tCx8jUmuSCMioPFRjliN/6SJIvY6HpTtJIWubKuYYYesQ==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      typescript: '*'
-    peerDependenciesMeta:
-      typescript:
-        optional: true
-    dependencies:
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/visitor-keys': 6.11.0
-      debug: 4.3.4
-      globby: 11.1.0
-      is-glob: 4.0.3
-      semver: 7.5.4
-      ts-api-utils: 1.0.3([email protected])
-      typescript: 5.3.2
-    transitivePeerDependencies:
-      - supports-color
-    dev: true
-
   /@typescript-eslint/[email protected]([email protected])([email protected]):
     resolution: {integrity: 
sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4096,25 +3615,6 @@ packages:
       - typescript
     dev: true
 
-  /@typescript-eslint/[email protected]([email protected])([email protected]):
-    resolution: {integrity: 
sha512-p23ibf68fxoZy605dc0dQAEoUsoiNoP3MD9WQGiHLDuTSOuqoTsa4oAy+h3KDkTcxbbfOtUjb9h3Ta0gT4ug2g==}
-    engines: {node: ^16.0.0 || >=18.0.0}
-    peerDependencies:
-      eslint: ^7.0.0 || ^8.0.0
-    dependencies:
-      '@eslint-community/eslint-utils': 4.4.0([email protected])
-      '@types/json-schema': 7.0.15
-      '@types/semver': 7.5.5
-      '@typescript-eslint/scope-manager': 6.11.0
-      '@typescript-eslint/types': 6.11.0
-      '@typescript-eslint/typescript-estree': 6.11.0([email protected])
-      eslint: 8.53.0
-      semver: 7.5.4
-    transitivePeerDependencies:
-      - supports-color
-      - typescript
-    dev: true
-
   /@typescript-eslint/[email protected]:
     resolution: {integrity: 
sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
@@ -4133,17 +3633,6 @@ packages:
   /@ungap/[email protected]:
     resolution: {integrity: 
sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
 
-  /@vitejs/[email protected]([email protected]):
-    resolution: {integrity: 
sha512-1PrOvAaDpqlCV+Up8RkAh9qaiUjoDUcjtttyhXDKw53XA6Ve16SOp6cCOpRs8Dj8DqUQs6eTW5YkLcLJjrXAig==}
-    peerDependencies:
-      vite: ^4 || ^5
-    dependencies:
-      '@swc/core': 1.3.100
-      vite: 4.5.0(@types/[email protected])([email protected])
-    transitivePeerDependencies:
-      - '@swc/helpers'
-    dev: true
-
   /@webassemblyjs/[email protected]:
     resolution: {integrity: 
sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==}
     dependencies:
@@ -6243,36 +5732,6 @@ packages:
       is-date-object: 1.0.5
       is-symbol: 1.0.4
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==}
-    engines: {node: '>=12'}
-    hasBin: true
-    requiresBuild: true
-    optionalDependencies:
-      '@esbuild/android-arm': 0.18.20
-      '@esbuild/android-arm64': 0.18.20
-      '@esbuild/android-x64': 0.18.20
-      '@esbuild/darwin-arm64': 0.18.20
-      '@esbuild/darwin-x64': 0.18.20
-      '@esbuild/freebsd-arm64': 0.18.20
-      '@esbuild/freebsd-x64': 0.18.20
-      '@esbuild/linux-arm': 0.18.20
-      '@esbuild/linux-arm64': 0.18.20
-      '@esbuild/linux-ia32': 0.18.20
-      '@esbuild/linux-loong64': 0.18.20
-      '@esbuild/linux-mips64el': 0.18.20
-      '@esbuild/linux-ppc64': 0.18.20
-      '@esbuild/linux-riscv64': 0.18.20
-      '@esbuild/linux-s390x': 0.18.20
-      '@esbuild/linux-x64': 0.18.20
-      '@esbuild/netbsd-x64': 0.18.20
-      '@esbuild/openbsd-x64': 0.18.20
-      '@esbuild/sunos-x64': 0.18.20
-      '@esbuild/win32-arm64': 0.18.20
-      '@esbuild/win32-ia32': 0.18.20
-      '@esbuild/win32-x64': 0.18.20
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
     engines: {node: '>=6'}
@@ -6685,14 +6144,6 @@ packages:
     dependencies:
       eslint: 8.53.0
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-D53FYKJa+fDmZMtriODxvhwrO+IOqrxoEo21gMA0sjHdU6dPVH4OhyFip9ypl8HOF5RV5KdTo+rBQLvnY2cO8w==}
-    peerDependencies:
-      eslint: '>=7'
-    dependencies:
-      eslint: 8.53.0
-    dev: true
-
   /[email protected]([email protected]):
     resolution: {integrity: 
sha512-73QQMKALArI8/7xGLNI/3LylrEYrlKZSb5C9+q3OtOewTnMQi5cT+aE9E41sLCmli3I9PGGmD1yiZydyo4FEPw==}
     engines: {node: '>=4'}
@@ -7433,12 +6884,6 @@ packages:
     resolution: {integrity: 
sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
-    dependencies:
-      react-is: 16.13.1
-    dev: false
-
   /[email protected]:
     resolution: {integrity: 
sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==}
     engines: {node: '>= 6.0.0'}
@@ -9070,12 +8515,6 @@ packages:
     engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
-    engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
-    hasBin: true
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
 
@@ -10193,15 +9632,6 @@ packages:
       picocolors: 1.0.0
       source-map-js: 1.0.2
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==}
-    engines: {node: ^10 || ^12 || >=14}
-    dependencies:
-      nanoid: 3.3.7
-      picocolors: 1.0.0
-      source-map-js: 1.0.2
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
     engines: {node: '>= 0.8.0'}
@@ -10417,16 +9847,6 @@ packages:
       semver: 5.7.1
     dev: true
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-bCpkbm9JiAuMGhkqoAiC0lLkb40DJ0HOEJIku+9JDjxX3Rcs+ztEOG13wbrOskt3n2DTrjshhaQ/iay+SnGg5Q==}
-    peerDependencies:
-      react: '>=16.4.1'
-    dependencies:
-      hoist-non-react-statics: 3.3.2
-      prop-types: 15.8.1
-      react: 18.2.0
-    dev: false
-
   
/[email protected](@types/[email protected])([email protected])([email protected]):
     resolution: {integrity: 
sha512-87gRP69VAfeU2yKgp8RI3HvzhPNrnYIV2QNranYXataz3ef+k7OhvKGGdxQLQfUsQ2RTmlY66tn4pdFrZ94hNg==}
     peerDependencies:
@@ -10511,16 +9931,6 @@ packages:
     resolution: {integrity: 
sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==}
     dev: false
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-cYW2/DWas8nEKZGD7SCu9BSuVz8iOcOLHChHyi7upUuVhkpkhYG/6N3KDiTQ3XAiZ2UAZkfvYKMfAHOzBOcGEg==}
-    peerDependencies:
-      react: '>=16.4.1'
-    dependencies:
-      prop-types: 15.8.1
-      react: 18.2.0
-      react-async-script: 1.2.0([email protected])
-    dev: false
-
   /[email protected]([email protected])([email protected]):
     resolution: {integrity: 
sha512-9jZ57/dAn9t3q6hneQS0wukqC2ENOBgMNVEhb/ZG9ZSxUetzVIw4iAmEU38IaVg3QGYauQPhSeUTuIUtFglWpg==}
     peerDependencies:
@@ -10995,14 +10405,6 @@ packages:
     optionalDependencies:
       fsevents: 2.3.3
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==}
-    engines: {node: '>=14.18.0', npm: '>=8.0.0'}
-    hasBin: true
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==}
     engines: {node: '>=12'}
@@ -11970,15 +11372,6 @@ packages:
       typescript: 4.9.5
     dev: true
 
-  /[email protected]([email protected]):
-    resolution: {integrity: 
sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==}
-    engines: {node: '>=16.13.0'}
-    peerDependencies:
-      typescript: '>=4.2.0'
-    dependencies:
-      typescript: 5.3.2
-    dev: true
-
   /[email protected](@types/[email protected])([email protected]):
     resolution: {integrity: 
sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==}
     hasBin: true
@@ -12131,12 +11524,6 @@ packages:
     engines: {node: '>=4.2.0'}
     hasBin: true
 
-  /[email protected]:
-    resolution: {integrity: 
sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==}
-    engines: {node: '>=14.17'}
-    hasBin: true
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==}
     dependencies:
@@ -12303,43 +11690,6 @@ packages:
     resolution: {integrity: 
sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
     engines: {node: '>= 0.8'}
 
-  /[email protected](@types/[email protected])([email protected]):
-    resolution: {integrity: 
sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==}
-    engines: {node: ^14.18.0 || >=16.0.0}
-    hasBin: true
-    peerDependencies:
-      '@types/node': '>= 14'
-      less: '*'
-      lightningcss: ^1.21.0
-      sass: '*'
-      stylus: '*'
-      sugarss: '*'
-      terser: ^5.4.0
-    peerDependenciesMeta:
-      '@types/node':
-        optional: true
-      less:
-        optional: true
-      lightningcss:
-        optional: true
-      sass:
-        optional: true
-      stylus:
-        optional: true
-      sugarss:
-        optional: true
-      terser:
-        optional: true
-    dependencies:
-      '@types/node': 16.11.59
-      esbuild: 0.18.20
-      postcss: 8.4.32
-      rollup: 3.29.4
-      sass: 1.54.9
-    optionalDependencies:
-      fsevents: 2.3.3
-    dev: true
-
   /[email protected]:
     resolution: {integrity: 
sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==}
     engines: {node: '>=0.10.0'}
diff --git a/ui/src/components/Comment/components/Form/index.tsx 
b/ui/src/components/Comment/components/Form/index.tsx
index 12368193..ea1835eb 100644
--- a/ui/src/components/Comment/components/Form/index.tsx
+++ b/ui/src/components/Comment/components/Form/index.tsx
@@ -84,6 +84,7 @@ const Index = ({
               size="sm"
               value={type === 'edit' ? parseEditMentionUser(value) : value}
               onChange={handleChange}
+              isInvalid={validationErrorMsg !== ''}
             />
           </Mentions>
           <div className="form-text">{t(`tip_${mode}`)}</div>
diff --git a/ui/src/components/Comment/components/Reply/index.tsx 
b/ui/src/components/Comment/components/Reply/index.tsx
index 2bd722f2..fcf9532b 100644
--- a/ui/src/components/Comment/components/Reply/index.tsx
+++ b/ui/src/components/Comment/components/Reply/index.tsx
@@ -1,95 +1,100 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { useState, memo } from 'react';
-import { Button, Form } from 'react-bootstrap';
-import { useTranslation } from 'react-i18next';
-
-import classNames from 'classnames';
-
-import { TextArea, Mentions } from '@/components';
-import { usePageUsers, usePromptWithUnload } from '@/hooks';
-
-const Index = ({ userName, onSendReply, onCancel, mode }) => {
-  const [value, setValue] = useState('');
-  const pageUsers = usePageUsers();
-  const { t } = useTranslation('translation', { keyPrefix: 'comment' });
-  const [validationErrorMsg, setValidationErrorMsg] = useState('');
-
-  usePromptWithUnload({
-    when: Boolean(value),
-  });
-
-  const handleChange = (e) => {
-    setValue(e.target.value);
-  };
-  const handleSelected = (val) => {
-    setValue(val);
-  };
-  const handleSendReply = () => {
-    onSendReply(value).catch((ex) => {
-      if (ex.isError) {
-        setValidationErrorMsg(ex.msg);
-      }
-    });
-  };
-
-  return (
-    <div className="mb-2">
-      <div className="small mb-2">
-        {t('reply_to')} {userName}
-      </div>
-      <div className="d-flex mb-1 align-items-start flex-column flex-md-row">
-        <div className="w-100">
-          <div
-            className={classNames('custom-form-control', {
-              'is-invalid': validationErrorMsg,
-            })}>
-            <Mentions
-              pageUsers={pageUsers.getUsers()}
-              onSelected={handleSelected}>
-              <TextArea size="sm" value={value} onChange={handleChange} />
-            </Mentions>
-            <div className="form-text">{t(`tip_${mode}`)}</div>
-          </div>
-          <Form.Control.Feedback type="invalid">
-            {validationErrorMsg}
-          </Form.Control.Feedback>
-        </div>
-        <div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 
mt-md-0">
-          <Button
-            size="sm"
-            className="text-nowrap"
-            onClick={() => handleSendReply()}>
-            {t('btn_add_comment')}
-          </Button>
-          <Button
-            variant="link"
-            size="sm"
-            className="text-nowrap btn-no-border ms-2 ms-md-0"
-            onClick={onCancel}>
-            {t('btn_cancel')}
-          </Button>
-        </div>
-      </div>
-    </div>
-  );
-};
-
-export default memo(Index);
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { useState, memo } from 'react';
+import { Button, Form } from 'react-bootstrap';
+import { useTranslation } from 'react-i18next';
+
+import classNames from 'classnames';
+
+import { TextArea, Mentions } from '@/components';
+import { usePageUsers, usePromptWithUnload } from '@/hooks';
+
+const Index = ({ userName, onSendReply, onCancel, mode }) => {
+  const [value, setValue] = useState('');
+  const pageUsers = usePageUsers();
+  const { t } = useTranslation('translation', { keyPrefix: 'comment' });
+  const [validationErrorMsg, setValidationErrorMsg] = useState('');
+
+  usePromptWithUnload({
+    when: Boolean(value),
+  });
+
+  const handleChange = (e) => {
+    setValue(e.target.value);
+  };
+  const handleSelected = (val) => {
+    setValue(val);
+  };
+  const handleSendReply = () => {
+    onSendReply(value).catch((ex) => {
+      if (ex.isError) {
+        setValidationErrorMsg(ex.msg);
+      }
+    });
+  };
+
+  return (
+    <div className="mb-2">
+      <div className="small mb-2">
+        {t('reply_to')} {userName}
+      </div>
+      <div className="d-flex mb-1 align-items-start flex-column flex-md-row">
+        <div className="w-100">
+          <div
+            className={classNames('custom-form-control', {
+              'is-invalid': validationErrorMsg,
+            })}>
+            <Mentions
+              pageUsers={pageUsers.getUsers()}
+              onSelected={handleSelected}>
+              <TextArea
+                size="sm"
+                value={value}
+                onChange={handleChange}
+                isInvalid={validationErrorMsg !== ''}
+              />
+            </Mentions>
+            <div className="form-text">{t(`tip_${mode}`)}</div>
+          </div>
+          <Form.Control.Feedback type="invalid">
+            {validationErrorMsg}
+          </Form.Control.Feedback>
+        </div>
+        <div className="d-flex flex-row flex-md-column ms-0 ms-md-2 mt-2 
mt-md-0">
+          <Button
+            size="sm"
+            className="text-nowrap"
+            onClick={() => handleSendReply()}>
+            {t('btn_add_comment')}
+          </Button>
+          <Button
+            variant="link"
+            size="sm"
+            className="text-nowrap btn-no-border ms-2 ms-md-0"
+            onClick={onCancel}>
+            {t('btn_cancel')}
+          </Button>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default memo(Index);
diff --git a/ui/src/components/TagSelector/index.tsx 
b/ui/src/components/TagSelector/index.tsx
index de82599e..25ec293d 100644
--- a/ui/src/components/TagSelector/index.tsx
+++ b/ui/src/components/TagSelector/index.tsx
@@ -40,6 +40,8 @@ interface IProps {
   maxTagLength?: number;
   showRequiredTag?: boolean;
   autoFocus?: boolean;
+  isInvalid?: boolean;
+  errMsg?: string;
 }
 
 let timer;
@@ -52,6 +54,8 @@ const TagSelector: FC<IProps> = ({
   maxTagLength = 0,
   showRequiredTag = false,
   autoFocus = false,
+  isInvalid = false,
+  errMsg = '',
 }) => {
   const containerRef = useRef<HTMLDivElement>(null);
   const inputRef = useRef<HTMLInputElement>(null);
@@ -341,6 +345,7 @@ const TagSelector: FC<IProps> = ({
         className={classNames(
           'tag-selector-wrap form-control position-relative p-0',
           focusState ? 'tag-selector-wrap--focus' : '',
+          isInvalid ? 'is-invalid' : '',
         )}
         onFocus={handleTagSelectorFocus}
         onKeyDown={handleKeyDown}>
@@ -423,6 +428,7 @@ const TagSelector: FC<IProps> = ({
         </Dropdown.Menu>
       </div>
       {!hiddenDescription && <Form.Text>{t('hint')}</Form.Text>}
+      <Form.Control.Feedback type="invalid">{errMsg}</Form.Control.Feedback>
     </div>
   );
 };
diff --git a/ui/src/components/TextArea/index.tsx 
b/ui/src/components/TextArea/index.tsx
index 5976d0d2..b0c6d9a1 100644
--- a/ui/src/components/TextArea/index.tsx
+++ b/ui/src/components/TextArea/index.tsx
@@ -1,56 +1,65 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-import { FC, useRef, useEffect, memo } from 'react';
-import { FormControl, FormControlProps } from 'react-bootstrap';
-
-const TextArea: FC<
-  FormControlProps & { rows?: number; autoFocus?: boolean }
-> = ({ value, onChange, size, rows = 1, autoFocus = true, ...rest }) => {
-  const ref = useRef<HTMLTextAreaElement>(null);
-
-  const autoGrow = () => {
-    if (ref.current) {
-      ref.current.style.height = 'auto';
-      ref.current.style.height = `${ref.current.scrollHeight}px`;
-    }
-  };
-
-  useEffect(() => {
-    if (ref.current && value) {
-      autoGrow();
-    }
-  }, [ref, value]);
-
-  return (
-    <FormControl
-      as="textarea"
-      className="resize-none font-monospace"
-      rows={rows}
-      size={size}
-      value={value}
-      onChange={onChange}
-      autoFocus={autoFocus}
-      ref={ref}
-      onInput={autoGrow}
-      {...rest}
-    />
-  );
-};
-export default memo(TextArea);
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { FC, useRef, useEffect, memo } from 'react';
+import { FormControl, FormControlProps } from 'react-bootstrap';
+
+const TextArea: FC<
+  FormControlProps & { rows?: number; autoFocus?: boolean }
+> = ({
+  value,
+  onChange,
+  size,
+  rows = 1,
+  autoFocus = true,
+  isInvalid,
+  ...rest
+}) => {
+  const ref = useRef<HTMLTextAreaElement>(null);
+
+  const autoGrow = () => {
+    if (ref.current) {
+      ref.current.style.height = 'auto';
+      ref.current.style.height = `${ref.current.scrollHeight}px`;
+    }
+  };
+
+  useEffect(() => {
+    if (ref.current && value) {
+      autoGrow();
+    }
+  }, [ref, value]);
+
+  return (
+    <FormControl
+      as="textarea"
+      className="resize-none font-monospace"
+      rows={rows}
+      size={size}
+      value={value}
+      onChange={onChange}
+      autoFocus={autoFocus}
+      ref={ref}
+      onInput={autoGrow}
+      isInvalid={isInvalid}
+      {...rest}
+    />
+  );
+};
+export default memo(TextArea);
diff --git a/ui/src/pages/Questions/Ask/index.tsx 
b/ui/src/pages/Questions/Ask/index.tsx
index 1bc92cc7..bf06d1a3 100644
--- a/ui/src/pages/Questions/Ask/index.tsx
+++ b/ui/src/pages/Questions/Ask/index.tsx
@@ -446,25 +446,21 @@ const Ask = () => {
                 autoFocus
                 contentEditable
               />
-
               <Form.Control.Feedback type="invalid">
                 {formData.title.errorMsg}
               </Form.Control.Feedback>
               {bool && <SearchQuestion similarQuestions={similarQuestions} />}
             </Form.Group>
+
             <Form.Group controlId="content">
               <Form.Label>{t('form.fields.body.label')}</Form.Label>
-              <Form.Control
-                defaultValue={formData.content.value}
-                isInvalid={formData.content.isInvalid}
-                hidden
-              />
               <Editor
                 value={formData.content.value}
                 onChange={handleContentChange}
                 className={classNames(
                   'form-control p-0',
                   focusType === 'content' && 'focus',
+                  formData.content.isInvalid && 'is-invalid',
                 )}
                 onFocus={() => {
                   setForceType('content');
@@ -478,23 +474,19 @@ const Ask = () => {
                 {formData.content.errorMsg}
               </Form.Control.Feedback>
             </Form.Group>
+
             <Form.Group controlId="tags" className="my-3">
               <Form.Label>{t('form.fields.tags.label')}</Form.Label>
-              <Form.Control
-                defaultValue={JSON.stringify(formData.tags.value)}
-                isInvalid={formData.tags.isInvalid}
-                hidden
-              />
               <TagSelector
                 value={formData.tags.value}
                 onChange={handleTagsChange}
                 showRequiredTag
                 maxTagLength={5}
+                isInvalid={formData.tags.isInvalid}
+                errMsg={formData.tags.errorMsg}
               />
-              <Form.Control.Feedback type="invalid">
-                {formData.tags.errorMsg}
-              </Form.Control.Feedback>
             </Form.Group>
+
             {isEdit && (
               <Form.Group controlId="edit_summary" className="my-3">
                 <Form.Label>{t('form.fields.edit_summary.label')}</Form.Label>
diff --git a/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx 
b/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
index 456fbe37..5627231d 100644
--- a/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
+++ b/ui/src/pages/Questions/Detail/components/WriteAnswer/index.tsx
@@ -266,6 +266,7 @@ const Index: FC<Props> = ({ visible = false, data, callback 
}) => {
                 className={classNames(
                   'form-control p-0',
                   focusType === 'answer' && 'focus',
+                  formData.content.isInvalid && 'is-invalid',
                 )}
                 value={formData.content.value}
                 autoFocus={editorFocusState}


Reply via email to