forked from boos/BoosAPI
[codex] Add route cooldown controls (#365)
* Add route cooldown controls * Address route cooldown review comments
This commit is contained in:
@@ -41,6 +41,8 @@ describe('RouteCard', () => {
|
||||
onEdit={vi.fn()}
|
||||
onDelete={vi.fn()}
|
||||
onToggleEnabled={vi.fn()}
|
||||
onClearCooldown={vi.fn()}
|
||||
clearingCooldown={false}
|
||||
onRoutingStrategyChange={vi.fn()}
|
||||
updatingRoutingStrategy={false}
|
||||
channels={undefined}
|
||||
@@ -85,4 +87,53 @@ describe('RouteCard', () => {
|
||||
flexShrink: 1,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders a clear cooldown action on expanded cards', () => {
|
||||
const onClearCooldown = vi.fn();
|
||||
const root = create(
|
||||
<RouteCard
|
||||
route={buildRoute()}
|
||||
brand={null}
|
||||
expanded
|
||||
onToggleExpand={vi.fn()}
|
||||
onEdit={vi.fn()}
|
||||
onDelete={vi.fn()}
|
||||
onToggleEnabled={vi.fn()}
|
||||
onClearCooldown={onClearCooldown}
|
||||
clearingCooldown={false}
|
||||
onRoutingStrategyChange={vi.fn()}
|
||||
updatingRoutingStrategy={false}
|
||||
channels={[]}
|
||||
loadingChannels={false}
|
||||
routeDecision={null}
|
||||
loadingDecision={false}
|
||||
candidateView={{ routeCandidates: [], accountOptions: [], tokenOptionsByAccountId: {} }}
|
||||
channelTokenDraft={{}}
|
||||
updatingChannel={{}}
|
||||
savingPriority={false}
|
||||
onTokenDraftChange={vi.fn()}
|
||||
onSaveToken={vi.fn()}
|
||||
onDeleteChannel={vi.fn()}
|
||||
onToggleChannelEnabled={vi.fn()}
|
||||
onChannelDragEnd={vi.fn()}
|
||||
onSplitPriorityBucket={vi.fn()}
|
||||
missingTokenSiteItems={[]}
|
||||
missingTokenGroupItems={[]}
|
||||
onCreateTokenForMissing={vi.fn()}
|
||||
onAddChannel={vi.fn()}
|
||||
onSiteBlockModel={vi.fn()}
|
||||
expandedSourceGroupMap={{}}
|
||||
onToggleSourceGroup={vi.fn()}
|
||||
/>,
|
||||
);
|
||||
|
||||
const button = root.root.find((node) => (
|
||||
node.type === 'button'
|
||||
&& typeof node.props.onClick === 'function'
|
||||
&& collectText(node).trim() === '清除冷却'
|
||||
));
|
||||
|
||||
button.props.onClick();
|
||||
expect(onClearCooldown).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,6 +53,8 @@ type RouteCardProps = {
|
||||
onEdit: (route: RouteSummaryRow) => void;
|
||||
onDelete: (routeId: number) => void;
|
||||
onToggleEnabled: (route: RouteSummaryRow) => void;
|
||||
onClearCooldown: (routeId: number) => void;
|
||||
clearingCooldown: boolean;
|
||||
onRoutingStrategyChange: (route: RouteSummaryRow, strategy: RouteRoutingStrategy) => void;
|
||||
updatingRoutingStrategy: boolean;
|
||||
// Channel data (loaded on demand)
|
||||
@@ -106,6 +108,8 @@ function RouteCardInner({
|
||||
onEdit,
|
||||
onDelete,
|
||||
onToggleEnabled,
|
||||
onClearCooldown,
|
||||
clearingCooldown,
|
||||
onRoutingStrategyChange,
|
||||
updatingRoutingStrategy,
|
||||
channels,
|
||||
@@ -167,6 +171,14 @@ function RouteCardInner({
|
||||
|
||||
const priorityBuckets = buildPriorityBuckets(channels || []);
|
||||
const bucketEditorItems = buildPriorityBucketEditorItems(channels || []);
|
||||
const renderClearCooldownButton = () => {
|
||||
if (readOnlyRoute) return null;
|
||||
return (
|
||||
<button onClick={() => onClearCooldown(route.id)} className="btn btn-link btn-link-info" disabled={clearingCooldown}>
|
||||
{clearingCooldown ? tr('清除中...') : tr('清除冷却')}
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
// Collapsed card
|
||||
if (!expanded) {
|
||||
@@ -325,6 +337,7 @@ function RouteCardInner({
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
|
||||
{renderClearCooldownButton()}
|
||||
{!readOnlyRoute && (explicitGroupRoute || !exactRoute) && (
|
||||
<button onClick={() => onEdit(route)} className="btn btn-link">{tr('编辑群组')}</button>
|
||||
)}
|
||||
@@ -358,6 +371,7 @@ function RouteCardInner({
|
||||
</div>
|
||||
{!readOnlyRoute && (
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
|
||||
{renderClearCooldownButton()}
|
||||
{!exactRoute && (
|
||||
<button onClick={() => onEdit(route)} className="btn btn-link">{explicitGroupRoute ? tr('编辑群组') : tr('编辑路由')}</button>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user