mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-06-02 03:55:55 +00:00
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:
2
web_ui/.gitignore
vendored
2
web_ui/.gitignore
vendored
@@ -39,3 +39,5 @@ yarn-error.log*
|
||||
# typescript
|
||||
*.tsbuildinfo
|
||||
next-env.d.ts
|
||||
|
||||
pnpm-lock.yaml
|
||||
3
web_ui/.husky/pre-commit
Normal file
3
web_ui/.husky/pre-commit
Normal file
@@ -0,0 +1,3 @@
|
||||
cd web_ui
|
||||
pnpm lint-staged
|
||||
pnpm test
|
||||
3
web_ui/.lintstagedrc.json
Normal file
3
web_ui/.lintstagedrc.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"*.{js,jsx,ts,tsx}": ["prettier --write", "eslint --fix", "eslint"]
|
||||
}
|
||||
9
web_ui/.prettierrc.mjs
Normal file
9
web_ui/.prettierrc.mjs
Normal file
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* @see https://prettier.io/docs/configuration
|
||||
* @type {import("prettier").Config}
|
||||
*/
|
||||
const config = {
|
||||
trailingComma: "none",
|
||||
};
|
||||
|
||||
export default config;
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user