Example plugins
Copy-paste-able starting points. Drop into ~/Library/Application Support/com.buoy.app/plugins/ as .tsx files. Each example assumes /// <reference path="./buoy-sdk.d.ts" /> is in scope (the scaffold writes it).
ConfigMap data viewer
Shows entry count + a table of keys with byte counts.
export default (buoy: Buoy) => {
buoy.meta({ name: "configmap-data", version: "0.1.0" });
buoy.addDetailTab({
match: { group: "", kind: "ConfigMap" },
id: "data",
label: "Data",
render: ({ obj }) => {
const entries = Object.entries(obj?.data ?? {});
return (
<>
<KeyValue title="Summary">
<Row label="Entries" value={entries.length} />
<Row label="Binary" value={Object.keys(obj?.binaryData ?? {}).length} />
</KeyValue>
<Table
rows={entries}
columns={[
{ header: "KEY", cell: ([k]) => k },
{ header: "BYTES", cell: ([, v]) => (v as string).length },
]}
/>
</>
);
},
});
};
Argo Rollout: pause / resume action
Pauses or resumes a rollout via spec.paused. The when predicates make the two items mutually exclusive in the menu.
export default (buoy: Buoy) => {
buoy.meta({ name: "rollout-pause" });
buoy.addAction({
match: { group: "argoproj.io", kind: "Rollout" },
id: "pause",
label: "Pause Rollout",
when: (obj) => !obj.spec?.paused,
confirm: { phrase: (obj) => obj.metadata.name },
run: async (ctx) => {
await ctx.mergePatch({ spec: { paused: true } });
},
});
buoy.addAction({
match: { group: "argoproj.io", kind: "Rollout" },
id: "resume",
label: "Resume Rollout",
when: (obj) => obj.spec?.paused === true,
confirm: { phrase: (obj) => obj.metadata.name },
run: async (ctx) => {
await ctx.mergePatch({ spec: { paused: false } });
},
});
};
Deployment: owner + peers + rollout history
A custom tab that combines useObject (the owning ReplicaSet) with useList (sibling Pods) and a small replica-set history table.
export default (buoy: Buoy) => {
buoy.meta({ name: "deployment-overview" });
buoy.addDetailTab({
match: { group: "apps", kind: "Deployment" },
id: "overview",
label: "Overview+",
render: ({ obj }) => {
const peers = useList("pods", {
labelSelector: obj.spec.selector?.matchLabels,
});
const replicaSets = useList("replicasets", {
labelSelector: obj.spec.selector?.matchLabels,
});
const ready = peers.rows.filter((r) => {
const ready = r.object.status?.containerStatuses ?? [];
return ready.every((c: any) => c.ready);
}).length;
return (
<>
<KeyValue title="At a glance">
<Row label="Image" value={obj.spec.template.spec.containers[0]?.image} mono />
<Row label="Replicas" value={`${ready}/${obj.spec.replicas}`} />
<Row label="Strategy" value={obj.spec.strategy?.type ?? "RollingUpdate"} />
</KeyValue>
<Table
title="ReplicaSets"
rows={replicaSets.rows}
columns={[
{ header: "NAME", cell: (r) => (
<CellValue
value={r.name}
link={{ kind: "ReplicaSet", resource: "replicasets", name: r.name, namespace: r.namespace }}
/>
) },
{ header: "DESIRED", cell: (r) => r.object.spec?.replicas ?? 0 },
{ header: "READY", cell: (r) => r.object.status?.readyReplicas ?? 0 },
]}
/>
</>
);
},
});
};
Promoted list columns for a CRD
Tell Buoy that whenever you get rollouts, the STRATEGY and STEP columns from the apiserver Table response should always show (instead of being hidden as wide).
export default (buoy: Buoy) => {
buoy.meta({ name: "rollout-columns" });
buoy.addListColumns({
match: { group: "argoproj.io", kind: "Rollout" },
promotedWide: ["STRATEGY", "STEP"],
defaults: [
{ kind: "label", key: "app.kubernetes.io/instance", header: "INSTANCE" },
],
});
};