Files
lobe-chat/src/routes/(main)/home/features/Recents/useDropdownMenu.tsx
T
Innei b4b1205ee9 ♻️ refactor(modal): migrate confirm modals to @lobehub/ui/base-ui (Phase 1) (#15259)
* ♻️ refactor(modal): migrate confirm modals to @lobehub/ui/base-ui

Replace all `App.useApp().modal.confirm`, `Modal.confirm` and `AntModal.confirm`
call sites with the headless `confirmModal` from `@lobehub/ui/base-ui`, dropping
antd-only props (`centered`, `type`, `width`, `okButtonProps.type='primary'`,
`okButtonProps.loading`, `classNames.root`) that the base-ui imperative API does
not accept.

- 82 files touched; `modal.confirm`/`Modal.confirm` call sites now zero
- `PageEditor/store/action.ts`: drop `modal` arg from `handleDelete`
- `ResourceManager/useUploadFolder`: replace dynamic `import('antd').Modal`
- `Eval/DatasetsTab`: migrate `modal.success` to `confirmModal`

Part of LOBE-9645 Phase 1.

* ♻️ refactor(ui): migrate select/modal call sites to @lobehub/ui/base-ui

- Convert imperative-modal factories (createXxxModal + Content split) for apikey,
  creds (Create/Edit/View), provider (CreateNewProvider), and messenger LinkModal.
- Switch Select usages to base-ui Select (Messenger AgentSelect, provider sdkType).
- Restructure CreateNewProvider form to vertical layout with manual section titles
  for tighter spacing; drop FormModal/Form group nesting.
- Standardize small ActionIcon sizing via DESKTOP_HEADER_ICON_SMALL_SIZE
  (WideScreenButton, ToggleRightPanelButton, ContextDropdown, AddNewProvider).
- Fix missing title on ResourceManager delete confirm modal so the header
  (title + close X) renders.
- Update react skill and AGENTS.md to require base-ui priority over root @lobehub/ui
  / antd; expand component table and Common Mistakes with explicit base-ui rules.

* ♻️ refactor(ui): swap antd Select to base-ui Select and migrate createStyles to createStaticStyles

*  test: update test mocks for base-ui confirmModal migration

*  test(e2e): switch delete confirm selector to base-ui dialog role
2026-05-28 02:46:27 +08:00

104 lines
3.0 KiB
TypeScript

import { type MenuProps } from '@lobehub/ui';
import { Icon } from '@lobehub/ui';
import { confirmModal } from '@lobehub/ui/base-ui';
import { PencilLineIcon, Trash } from 'lucide-react';
import { useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { type RecentItem } from '@/server/routers/lambda/recent';
import { documentService } from '@/services/document';
import { taskService } from '@/services/task';
import { topicService } from '@/services/topic';
import { useHomeStore } from '@/store/home';
export const useRecentItemDropdownMenu = (
item: RecentItem,
toggleEditing: (visible?: boolean) => void,
) => {
const { t } = useTranslation(['common', 'topic', 'components']);
const [updateRecentTitle, refreshRecents] = useHomeStore((s) => [
s.updateRecentTitle,
s.refreshRecents,
]);
const handleRename = useCallback(
async (newTitle: string) => {
// Optimistic update
updateRecentTitle(item.id, newTitle);
// Persist to server
switch (item.type) {
case 'document': {
await documentService.updateDocument({ id: item.id, title: newTitle });
break;
}
case 'task': {
await taskService.update(item.id, { name: newTitle });
break;
}
case 'topic': {
await topicService.updateTopic(item.id, { title: newTitle });
break;
}
}
},
[item, updateRecentTitle],
);
const handleDelete = useCallback(() => {
const confirmMessages: Record<string, string> = {
document: t('FileManager.actions.confirmDelete', { ns: 'components' }),
topic: t('actions.confirmRemoveTopic', { ns: 'topic' }),
};
confirmModal({
okButtonProps: { danger: true },
onOk: async () => {
switch (item.type) {
case 'topic': {
// Home has no active agent/group, so chatStore.removeTopic early-returns; call the service directly
await topicService.removeTopic(item.id);
break;
}
case 'document': {
await documentService.deleteDocument(item.id);
break;
}
case 'task': {
await taskService.delete(item.id);
break;
}
}
await refreshRecents();
},
title: confirmMessages[item.type] || t('delete', { ns: 'common' }),
});
}, [item, t, refreshRecents]);
const dropdownMenu = useCallback((): MenuProps['items'] => {
const canRename = true;
return [
...(canRename
? [
{
icon: <Icon icon={PencilLineIcon} />,
key: 'rename',
label: t('rename'),
onClick: () => toggleEditing(true),
},
]
: []),
{
danger: true,
icon: <Icon icon={Trash} />,
key: 'delete',
label: t('delete'),
onClick: handleDelete,
},
];
}, [item.type, t, toggleEditing, handleDelete]);
return { dropdownMenu, handleRename };
};