This is an automated email from the ASF dual-hosted git repository.
shuai pushed a commit to branch feat/1.3.6/ui
in repository https://gitbox.apache.org/repos/asf/incubator-answer.git
The following commit(s) were added to refs/heads/feat/1.3.6/ui by this push:
new a4960f09 fix: optimize admin/write page content #815
a4960f09 is described below
commit a4960f09be22bf37aa93d6601b4c215b2a41fd30
Author: shuai <[email protected]>
AuthorDate: Fri Jul 12 11:13:12 2024 +0800
fix: optimize admin/write page content #815
---
i18n/en_US.yaml | 14 +-
ui/src/common/interface.ts | 6 +-
ui/src/components/Editor/utils/index.ts | 3 +
ui/src/components/TagSelector/index.tsx | 14 +-
ui/src/pages/Admin/Write/index.tsx | 234 ++++++++++++++++++++++----------
ui/src/stores/writeSetting.ts | 2 +-
6 files changed, 187 insertions(+), 86 deletions(-)
diff --git a/i18n/en_US.yaml b/i18n/en_US.yaml
index 9be207f7..ef1b0bc9 100644
--- a/i18n/en_US.yaml
+++ b/i18n/en_US.yaml
@@ -1747,19 +1747,21 @@ ui:
write:
page_title: Write
restrict_answer:
- title: Restrict answer
+ title: Answer write
label: Each user can only write one answer for the same question
- text: "Turn off to allow users to write multiple answers to the same
question, which may cause answers to be unfocused."
+ text: "Turn off to allow users to write multiple answers to the same
question, which may cause answers to be unfocused."
recommend_tags:
label: Recommend tags
- text: "Please input tag slug above, one tag per line."
+ text: "Recommend tags will show in the dropdown list by default."
+ msg:
+ contain_reserved: "recommended tags cannot contain reserved tags"
required_tag:
- title: Required tag
- label: Set recommend tag as required
+ title: Set required tags
+ label: Set “Recommend tags” as required tags
text: "Every new question must have at least one recommend tag."
reserved_tags:
label: Reserved tags
- text: "Reserved tags can only be added to a post by moderator."
+ text: "Reserved tags can only be used by moderator."
seo:
page_title: SEO
permalink:
diff --git a/ui/src/common/interface.ts b/ui/src/common/interface.ts
index 0acd2f02..ff7c0902 100644
--- a/ui/src/common/interface.ts
+++ b/ui/src/common/interface.ts
@@ -425,9 +425,9 @@ export interface AdminSettingsLegal {
export interface AdminSettingsWrite {
restrict_answer?: boolean;
- recommend_tags?: string[];
- required_tag?: string;
- reserved_tags?: string[];
+ recommend_tags?: Tag[];
+ required_tag?: boolean;
+ reserved_tags?: Tag[];
}
export interface AdminSettingsSeo {
diff --git a/ui/src/components/Editor/utils/index.ts
b/ui/src/components/Editor/utils/index.ts
index 406acb8d..d49da78c 100644
--- a/ui/src/components/Editor/utils/index.ts
+++ b/ui/src/components/Editor/utils/index.ts
@@ -97,6 +97,9 @@ export const useEditor = ({
wordWrap: 'break-word',
wordBreak: 'break-all',
},
+ '.ͼ7, .ͼ6': {
+ textDecoration: 'none',
+ },
});
const startState = EditorState.create({
diff --git a/ui/src/components/TagSelector/index.tsx
b/ui/src/components/TagSelector/index.tsx
index 845ace24..1204a686 100644
--- a/ui/src/components/TagSelector/index.tsx
+++ b/ui/src/components/TagSelector/index.tsx
@@ -41,6 +41,8 @@ interface IProps {
showRequiredTag?: boolean;
autoFocus?: boolean;
isInvalid?: boolean;
+ tagStyleMode?: 'default' | 'simple';
+ formText?: string;
errMsg?: string;
}
@@ -55,6 +57,8 @@ const TagSelector: FC<IProps> = ({
showRequiredTag = false,
autoFocus = false,
isInvalid = false,
+ formText = '',
+ tagStyleMode = 'default',
errMsg = '',
}) => {
const containerRef = useRef<HTMLDivElement>(null);
@@ -366,8 +370,12 @@ const TagSelector: FC<IProps> = ({
key={item.slug_name}
className={classNames(
'badge-tag rounded-1 m-1 flex-shrink-0',
- item.reserved && 'badge-tag-reserved',
- item.recommend && 'badge-tag-required',
+ tagStyleMode === 'default' &&
+ item.reserved &&
+ 'badge-tag-reserved',
+ tagStyleMode === 'default' &&
+ item.recommend &&
+ 'badge-tag-required',
index === repeatIndex && 'bg-fade-out',
)}>
{item.display_name}
@@ -435,7 +443,7 @@ const TagSelector: FC<IProps> = ({
)}
</Dropdown.Menu>
</div>
- {!hiddenDescription && <Form.Text>{t('hint')}</Form.Text>}
+ {!hiddenDescription && <Form.Text>{formText || t('hint')}</Form.Text>}
<Form.Control.Feedback type="invalid">{errMsg}</Form.Control.Feedback>
</div>
);
diff --git a/ui/src/pages/Admin/Write/index.tsx
b/ui/src/pages/Admin/Write/index.tsx
index 42806111..442c58f6 100644
--- a/ui/src/pages/Admin/Write/index.tsx
+++ b/ui/src/pages/Admin/Write/index.tsx
@@ -19,8 +19,9 @@
import { FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
+import { Form, Button } from 'react-bootstrap';
-import { SchemaForm, JSONSchema, initFormData, UISchema } from '@/components';
+import { TagSelector } from '@/components';
import type * as Type from '@/common/interface';
import { useToast } from '@/hooks';
import {
@@ -30,80 +31,84 @@ import {
import { handleFormError, scrollToElementTop } from '@/utils';
import { writeSettingStore } from '@/stores';
+const initFormData = {
+ reserved_tags: {
+ value: [] as Type.Tag[], // Replace `Type.Tag` with the correct type for
`reserved_tags.value`
+ errorMsg: '',
+ isInvalid: false,
+ },
+ recommend_tags: {
+ value: [] as Type.Tag[],
+ errorMsg: '',
+ isInvalid: false,
+ },
+ required_tag: {
+ value: false,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ restrict_answer: {
+ value: false,
+ errorMsg: '',
+ isInvalid: false,
+ },
+};
+
const Index: FC = () => {
const { t } = useTranslation('translation', {
keyPrefix: 'admin.write',
});
const Toast = useToast();
- const schema: JSONSchema = {
- title: t('page_title'),
- properties: {
- restrict_answer: {
- type: 'boolean',
- title: t('restrict_answer.title'),
- description: t('restrict_answer.text'),
- default: true,
- },
- recommend_tags: {
- type: 'string',
- title: t('recommend_tags.label'),
- description: t('recommend_tags.text'),
- },
- required_tag: {
- type: 'boolean',
- title: t('required_tag.title'),
- description: t('required_tag.text'),
- },
- reserved_tags: {
- type: 'string',
- title: t('reserved_tags.label'),
- description: t('reserved_tags.text'),
- },
- },
+ const [formData, setFormData] = useState(initFormData);
+
+ const handleValueChange = (value) => {
+ setFormData({
+ ...formData,
+ ...value,
+ });
};
- const uiSchema: UISchema = {
- restrict_answer: {
- 'ui:widget': 'switch',
- 'ui:options': {
- label: t('restrict_answer.label'),
- },
- },
- recommend_tags: {
- 'ui:widget': 'textarea',
- 'ui:options': {
- rows: 10,
- },
- },
- required_tag: {
- 'ui:widget': 'switch',
- 'ui:options': {
- label: t('required_tag.label'),
- },
- },
- reserved_tags: {
- 'ui:widget': 'textarea',
- 'ui:options': {
- rows: 10,
- },
- },
+
+ const checkValidated = (): boolean => {
+ let bol = true;
+ const { recommend_tags, reserved_tags } = formData;
+ // 找出 recommend_tags 和 reserved_tags 中是否有重复的标签
+ // 通过标签中的 slug_name 来去重
+ const repeatTag = recommend_tags.value.filter((tag) =>
+ reserved_tags.value.some((rTag) => rTag?.slug_name === tag?.slug_name),
+ );
+ if (repeatTag.length > 0) {
+ handleValueChange({
+ recommend_tags: {
+ ...recommend_tags,
+ errorMsg: t('recommend_tags.msg.contain_reserved'),
+ isInvalid: true,
+ },
+ });
+ bol = false;
+ const ele = document.getElementById('recommend_tags');
+ scrollToElementTop(ele);
+ } else {
+ handleValueChange({
+ recommend_tags: {
+ ...recommend_tags,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ });
+ }
+ return bol;
};
- const [formData, setFormData] = useState(initFormData(schema));
const onSubmit = (evt) => {
evt.preventDefault();
evt.stopPropagation();
- let recommend_tags = [];
- if (formData.recommend_tags.value?.trim()) {
- recommend_tags = formData.recommend_tags.value.trim().split('\n');
- }
- let reserved_tags = [];
- if (formData.reserved_tags.value?.trim()) {
- reserved_tags = formData.reserved_tags.value.trim().split('\n');
+ if (!checkValidated()) {
+ return;
}
const reqParams: Type.AdminSettingsWrite = {
- recommend_tags,
- reserved_tags,
+ recommend_tags: formData.recommend_tags.value,
+ reserved_tags: formData.reserved_tags.value,
required_tag: formData.required_tag.value,
restrict_answer: formData.restrict_answer.value,
};
@@ -130,12 +135,12 @@ const Index: FC = () => {
const initData = () => {
getRequireAndReservedTag().then((res) => {
if (Array.isArray(res.recommend_tags)) {
- formData.recommend_tags.value = res.recommend_tags.join('\n');
+ formData.recommend_tags.value = res.recommend_tags;
}
formData.required_tag.value = res.required_tag;
formData.restrict_answer.value = res.restrict_answer;
if (Array.isArray(res.reserved_tags)) {
- formData.reserved_tags.value = res.reserved_tags.join('\n');
+ formData.reserved_tags.value = res.reserved_tags;
}
setFormData({ ...formData });
});
@@ -145,20 +150,103 @@ const Index: FC = () => {
initData();
}, []);
- const handleOnChange = (data) => {
- setFormData(data);
- };
+ // const handleOnChange = (data) => {
+ // setFormData(data);
+ // };
return (
<>
<h3 className="mb-4">{t('page_title')}</h3>
- <SchemaForm
- schema={schema}
- formData={formData}
- onSubmit={onSubmit}
- uiSchema={uiSchema}
- onChange={handleOnChange}
- />
+ <Form noValidate onSubmit={onSubmit}>
+ <Form.Group className="mb-3" controlId="reserved_tags">
+ <Form.Label>{t('reserved_tags.label')}</Form.Label>
+ <TagSelector
+ value={formData.reserved_tags.value}
+ onChange={(val) => {
+ handleValueChange({
+ reserved_tags: {
+ value: val,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ });
+ }}
+ showRequiredTag={false}
+ maxTagLength={0}
+ tagStyleMode="simple"
+ formText={t('reserved_tags.text')}
+ isInvalid={formData.reserved_tags.isInvalid}
+ errMsg={formData.reserved_tags.errorMsg}
+ />
+ </Form.Group>
+
+ <Form.Group className="mb-3" controlId="recommend_tags">
+ <Form.Label>{t('recommend_tags.label')}</Form.Label>
+ <TagSelector
+ value={formData.recommend_tags.value}
+ onChange={(val) => {
+ handleValueChange({
+ recommend_tags: {
+ value: val,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ });
+ }}
+ showRequiredTag={false}
+ tagStyleMode="simple"
+ formText={t('recommend_tags.text')}
+ isInvalid={formData.recommend_tags.isInvalid}
+ errMsg={formData.recommend_tags.errorMsg}
+ />
+ </Form.Group>
+
+ <Form.Group className="mb-3" controlId="required_tag">
+ <Form.Label>{t('required_tag.title')}</Form.Label>
+ <Form.Switch
+ label={t('required_tag.label')}
+ checked={formData.required_tag.value}
+ onChange={(evt) => {
+ handleValueChange({
+ required_tag: {
+ value: evt.target.checked,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ });
+ }}
+ />
+ <Form.Text>{t('required_tag.text')}</Form.Text>
+ <Form.Control.Feedback type="invalid">
+ {formData.required_tag.errorMsg}
+ </Form.Control.Feedback>
+ </Form.Group>
+
+ <Form.Group className="mb-3" controlId="restrict_answer">
+ <Form.Label>{t('restrict_answer.title')}</Form.Label>
+ <Form.Switch
+ label={t('restrict_answer.label')}
+ checked={formData.restrict_answer.value}
+ onChange={(evt) => {
+ handleValueChange({
+ restrict_answer: {
+ value: evt.target.checked,
+ errorMsg: '',
+ isInvalid: false,
+ },
+ });
+ }}
+ />
+ <Form.Text>{t('restrict_answer.text')}</Form.Text>
+ <Form.Control.Feedback type="invalid">
+ {formData.restrict_answer.errorMsg}
+ </Form.Control.Feedback>
+ </Form.Group>
+
+ <Form.Group className="mb-3">
+ <Button type="submit">{t('save', { keyPrefix: 'btns' })}</Button>
+ </Form.Group>
+ </Form>
</>
);
};
diff --git a/ui/src/stores/writeSetting.ts b/ui/src/stores/writeSetting.ts
index 0ea04962..8e7c1f52 100644
--- a/ui/src/stores/writeSetting.ts
+++ b/ui/src/stores/writeSetting.ts
@@ -30,7 +30,7 @@ const Index = create<IProps>((set) => ({
write: {
restrict_answer: true,
recommend_tags: [],
- required_tag: '',
+ required_tag: false,
reserved_tags: [],
},
update: (params) =>