refactor(frontend): split 7 oversized pages into feature co-location

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
This commit is contained in:
Logan.Li committed 2026-10-26 17:54:15 +08:00
1 parent ac563d1c5e
commit ac498c7ba2
92 files changed
+8224 -6146

No files matched your search

@@ -0,0 +1,48 @@
/**
* 批量操作条:选中计数、全选/取消全选切换、批量删除按钮。
* 必需 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>
);
}