feat: notification and spinning display step 1 (#1345)

* feat: notification and loading display step 1

* chore: linter with husky and prettier, specifying rules needed
This commit is contained in:
Lightwing
2025-04-28 10:35:39 +08:00
committed by Junyan Qin
parent 5562148327
commit 8d37447146
8 changed files with 81 additions and 8 deletions

2
web_ui/.gitignore vendored
View File

@@ -39,3 +39,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
pnpm-lock.yaml

3
web_ui/.husky/pre-commit Normal file
View File

@@ -0,0 +1,3 @@
cd web_ui
pnpm lint-staged
pnpm test

View File

@@ -0,0 +1,3 @@
{
"*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix", "eslint"]
}

9
web_ui/.prettierrc.mjs Normal file
View File

@@ -0,0 +1,9 @@
/**
* @see https://prettier.io/docs/configuration
* @type {import("prettier").Config}
*/
const config = {
trailingComma: "none",
};
export default config;

View File

@@ -6,7 +6,9 @@
"dev": "next dev --turbopack",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"prepare": "cd .. && husky web_ui/.husky",
"lint-staged": "lint-staged"
},
"dependencies": {
"@ant-design/v5-patch-for-react-19": "^1.0.3",
@@ -26,6 +28,9 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.2.4",
"husky": "^9.1.7",
"lint-staged": "^15.5.1",
"prettier": "^3.5.3",
"typescript": "^5"
}
}

View File

@@ -11,6 +11,8 @@ import {UUID} from 'uuidjs'
import DynamicFormComponent from "@/app/home/components/dynamic-form/DynamicFormComponent";
import {httpClient} from "@/app/infra/http/HttpClient";
import { Bot } from "@/app/infra/api/api-types";
import { notification } from "antd";
export default function BotForm({
initBotId,
@@ -27,6 +29,7 @@ export default function BotForm({
const [dynamicForm] = Form.useForm();
const [adapterNameList, setAdapterNameList] = useState<IChooseAdapterEntity[]>([])
const [dynamicFormConfigList, setDynamicFormConfigList] = useState<IDynamicFormItemConfig[]>([])
const [isLoading, setIsLoading] = useState<boolean>(false)
useEffect(() => {
initBotFormComponent()
@@ -121,6 +124,8 @@ export default function BotForm({
// 只有通过外层固定表单验证才会走到这里,真正的提交逻辑在这里
function onDynamicFormSubmit(value: object) {
setIsLoading(true)
console.log('setloading', true)
if (initBotId) {
// 编辑提交
console.log('submit edit', form.getFieldsValue() ,value)
@@ -135,9 +140,20 @@ export default function BotForm({
// TODO success toast
console.log("update bot success", res)
onFormSubmit(form.getFieldsValue())
notification.success({
message: "更新成功",
description: "机器人更新成功"
})
}).catch(err => {
// TODO error toast
console.log("update bot error", err)
notification.error({
message: "更新失败",
description: "机器人更新失败"
})
}).finally(() => {
setIsLoading(false)
form.resetFields()
dynamicForm.resetFields()
})
} else {
// 创建提交
@@ -150,16 +166,28 @@ export default function BotForm({
}
httpClient.createBot(newBot).then(res => {
// TODO success toast
notification.success({
message: "创建成功",
description: "机器人创建成功"
})
console.log(res)
onFormSubmit(form.getFieldsValue())
}).catch(err => {
// TODO error toast
console.log(err)
notification.error({
message: "创建失败",
description: "机器人创建失败"
})
}).finally(() => {
setIsLoading(false)
form.resetFields()
dynamicForm.resetFields()
})
}
setShowDynamicForm(false)
form.resetFields()
dynamicForm.resetFields()
console.log('setloading', false)
// TODO 刷新bot列表
// TODO 关闭当前弹窗 Already closed @setShowDynamicForm(false)?
}
function handleSaveButton() {
@@ -174,6 +202,7 @@ export default function BotForm({
wrapperCol={{span: 18}}
layout='vertical'
onFinish={handleFormFinish}
disabled={isLoading}
>
<Form.Item<IBotFormEntity>
label={"机器人名称"}
@@ -225,6 +254,7 @@ export default function BotForm({
type="primary"
htmlType="button"
onClick={handleSubmitButton}
loading={isLoading}
>
</Button>
@@ -235,13 +265,14 @@ export default function BotForm({
type="primary"
htmlType="submit"
onClick={handleSaveButton}
loading={isLoading}
>
</Button>
}
<Button htmlType="button" onClick={() => {
onFormCancel(form.getFieldsValue())
}}>
}} disabled={isLoading}>
</Button>
</Space>

View File

@@ -5,7 +5,7 @@ import styles from "./botConfig.module.css";
import EmptyAndCreateComponent from "@/app/home/components/empty-and-create-component/EmptyAndCreateComponent";
import {useRouter} from "next/navigation";
import {BotCardVO} from "@/app/home/bots/components/bot-card/BotCardVO";
import {Modal} from "antd";
import {Modal, notification, Spin} from "antd";
import BotForm from "@/app/home/bots/components/bot-form/BotForm";
import BotCard from "@/app/home/bots/components/bot-card/BotCard";
import CreateCardComponent from "@/app/infra/basic-component/create-card-component/CreateCardComponent"
@@ -19,14 +19,18 @@ export default function BotConfigPage() {
const [botList, setBotList] = useState<BotCardVO[]>([])
const [isEditForm, setIsEditForm] = useState(false)
const [nowSelectedBotCard, setNowSelectedBotCard] = useState<BotCardVO>()
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
// TODO补齐加载转圈逻辑
setIsLoading(true)
checkHasLLM().then((hasLLM) => {
if (hasLLM) {
getBotList()
} else {
setPageShowRule(BotConfigPageShowRule.NO_LLM)
setIsLoading(false)
}
})
}, [])
@@ -55,8 +59,15 @@ export default function BotConfigPage() {
}
setBotList(botList)
}).catch((err) => {
// TODO error toast
console.error("get bot list error", err)
// TODO HACK: need refactor to hook mode Notification, but it's not working under render
notification.error({
message: "获取机器人列表失败",
description: err.message,
placement: "bottomRight",
})
}).finally(() => {
setIsLoading(false)
})
}
@@ -78,6 +89,7 @@ export default function BotConfigPage() {
}
return (
<Spin spinning={isLoading}>
<div className={styles.configPageContainer}>
<Modal
title={isEditForm ? "编辑机器人" : "创建机器人"}
@@ -139,6 +151,7 @@ export default function BotConfigPage() {
</div>
}
</div>
</Spin>
)
}

View File

@@ -6,6 +6,7 @@ import {
ApiRespPluginConfig, PluginReorderElement, AsyncTaskCreatedResp, ApiRespSystemInfo, ApiRespAsyncTasks, AsyncTask,
ApiRespAsyncTask, ApiRespUserToken
} from '../api/api-types'
import { notification } from 'antd'
type JSONValue = string | number | boolean | JSONObject | JSONArray | null
interface JSONObject { [key: string]: JSONValue }
@@ -111,6 +112,12 @@ class HttpClient {
break
case 500:
// TODO 弹Toast窗
// NOTE: move to component layer for customized message?
notification.error({
message: "服务器错误",
description: errMessage,
placement: "bottomRight",
})
console.error('Server error:', errMessage)
break
}