Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/commands/add-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ USER-SPECIFIED ADDRESS CONTRACTS:
- Address format validation is skipped for these contracts (the reference addresses are informational)
- At build time, `buildConfigFieldsFromAction()` automatically inserts a `contractAddress` template-input field at the top of the action config
- At runtime, `protocol-read.ts` and `protocol-write.ts` read `input.contractAddress` instead of looking up from the fixed addresses map
- Reference: `keeperhub/protocols/safe-wallet.ts` (canonical example)
- Reference: `keeperhub/protocols/safe.ts` (canonical example)

ICON HANDLING:
- Icon is fully optional -- if omitted, a default square protocol icon (`ProtocolIcon`) is displayed everywhere (Hub, workflow builder, etc.)
Expand Down
38 changes: 33 additions & 5 deletions components/workflow/config/action-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -580,10 +580,23 @@ function useCategoryData() {
};

for (const [category, actions] of Object.entries(pluginCategories)) {
allCategories[category] = actions.map((a) => ({
id: a.id,
label: a.label,
}));
// start custom keeperhub code //
// Deduplicate by slug within each category. When the same action is
// registered under two integrations, keep the first occurrence.
const seen = new Set<string>();
allCategories[category] = actions
.filter((a) => {
if (seen.has(a.slug)) {
return false;
}
seen.add(a.slug);
return true;
})
.map((a) => ({
id: a.id,
label: a.label,
}));
// end keeperhub code //
}

return allCategories;
Expand Down Expand Up @@ -634,7 +647,22 @@ export function ActionConfig({
}: ActionConfigProps) {
const actionType = (config?.actionType as string) || "";
const categories = useCategoryData();
const integrations = useMemo(() => getAllIntegrations(), []);
// start custom keeperhub code //
// Deduplicate integrations by label for the Service dropdown.
// When two integrations share a label, keep the one with more actions
// to avoid Radix Select duplicate-value collisions.
const integrations = useMemo(() => {
const all = getAllIntegrations();
const byLabel = new Map<string, (typeof all)[number]>();
for (const i of all) {
const existing = byLabel.get(i.label);
if (!existing || i.actions.length > existing.actions.length) {
byLabel.set(i.label, i);
}
}
return Array.from(byLabel.values());
}, []);
// end keeperhub code //

const selectedCategory = actionType ? getCategoryForAction(actionType) : null;
const [category, setCategory] = useState<string>(selectedCategory || "");
Expand Down
1 change: 0 additions & 1 deletion docs/plugins/_meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ export default {
code: "Code",
math: "Math",
safe: "Safe",
"safe-wallet": "Safe Wallet",
ajna: "Ajna",
sky: "Sky",
discord: "Discord",
Expand Down
3 changes: 1 addition & 2 deletions docs/plugins/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ Plugins provide the actions available in your workflows. Each plugin adds one or
| [Web3](/plugins/web3) | Blockchain | Balance checks, contract reads/writes, transfers, calldata decoding, risk assessment | Wallet (for writes) |
| [Code](/plugins/code) | Code | Execute custom JavaScript in a sandboxed VM | None |
| [Math](/plugins/math) | Math | Aggregation operations (sum, count, average, median, min, max, product) | None |
| [Safe](/plugins/safe) | Security | Monitor pending Safe multisig transactions | API key |
| [Safe Wallet](/plugins/safe-wallet) | Protocol | Safe multisig owners, threshold, nonce, module status | None |
| [Safe](/plugins/safe) | Protocol | Safe multisig owners, threshold, nonce, module status, pending transactions | API key (for pending txs) |
| [Ajna](/plugins/ajna) | Protocol | Liquidation keeper operations, vault rebalancing, buffer management | Wallet (for writes) |
| [Sky](/plugins/sky) | Protocol | USDS savings, token balances, approvals, DAI/MKR converters | Wallet (for writes) |
| [Discord](/plugins/discord) | Notifications | Send messages to channels | Webhook URL |
Expand Down
165 changes: 0 additions & 165 deletions docs/plugins/safe-wallet.md

This file was deleted.

Loading