Per guide ch.7 page split pattern (skeleton orchestrates, private components live in features/<domain>/): - InstancePage 1716->328, UsersPage 1309->240, TicketsPage 1076->195, TicketDetailPage 911->287, QueriesPage 883->479, LdapConfigPage 860->393, WorkflowPage 852->194 - new feature modules: datasource/ rbac/ ticket/ query/ system/ldap/ governance/workflow/ (components + hooks + types + utils) - stable keys replace index keys in dynamic lists; polling intervals and toast call sites preserved 1:1 (verified by agents) - filter/pagination state moved to URL query via new useQueryState hook (Instance/Users/Tickets/AuditLogs pages): refresh/share/back-button restore state; composite updates applied atomically - permission pure functions extracted to lib/permissions.ts (used by useAuth + useLogin); page-size audit: 0 pages over 700-line budget
49 lines
1.7 KiB
TypeScript
49 lines
1.7 KiB
TypeScript
/**
|
|
* 批量操作条:选中计数、全选/取消全选切换、批量删除按钮。
|
|
* 必需 props:selectedCount/total 计数、canDelete 权限、onSelectAll/onBatchDelete 回调;deleting 可选(默认 false)。
|
|
* 已知限制:仅应在 selectedCount > 0 时由父级渲染,空态展示逻辑不在组件内。
|
|
*/
|
|
import { Trash2, Loader2 } from 'lucide-react';
|
|
|
|
interface InstanceBatchBarProps {
|
|
selectedCount: number;
|
|
total: number;
|
|
canDelete: boolean;
|
|
deleting: boolean;
|
|
onSelectAll: () => void;
|
|
onBatchDelete: () => void;
|
|
}
|
|
|
|
export function InstanceBatchBar({
|
|
selectedCount,
|
|
total,
|
|
canDelete,
|
|
deleting,
|
|
onSelectAll,
|
|
onBatchDelete,
|
|
}: InstanceBatchBarProps) {
|
|
return (
|
|
<div className="flex items-center justify-between p-3 bg-blue-500/5 border border-blue-500/20 rounded-lg">
|
|
<div className="flex items-center gap-3">
|
|
<span className="text-sm text-blue-400 font-medium">已选择 {selectedCount} 个实例</span>
|
|
<button
|
|
onClick={onSelectAll}
|
|
className="text-xs text-[var(--dg-text-muted)] hover:text-blue-400 transition-colors"
|
|
>
|
|
{selectedCount === total ? '取消全选' : '全选'}
|
|
</button>
|
|
</div>
|
|
{canDelete && (
|
|
<button
|
|
onClick={onBatchDelete}
|
|
disabled={deleting}
|
|
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium bg-red-500/15 text-red-400 border border-red-500/30 rounded-md hover:bg-red-500/25 transition-all disabled:opacity-50"
|
|
>
|
|
{deleting ? <Loader2 className="w-3 h-3 animate-spin" /> : <Trash2 className="w-3 h-3" />}
|
|
{deleting ? '删除中...' : '批量删除'}
|
|
</button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|