Skip to content

Commit cc6495a

Browse files
committed
Add Terraform autoscaling snippet and chart to ROI tools
1 parent e92afd7 commit cc6495a

File tree

3 files changed

+60
-0
lines changed

3 files changed

+60
-0
lines changed

web/src/pages/ToolsPage.css

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,20 @@
168168
.tools__empty {
169169
color: rgba(148, 163, 184, 0.75);
170170
}
171+
172+
.tools__terraform-comment {
173+
color: rgba(148, 163, 184, 0.8);
174+
font-size: 0.85rem;
175+
margin: 0 0 0.75rem;
176+
}
177+
178+
.tools__terraform-snippet {
179+
background: rgba(15, 23, 42, 0.85);
180+
border: 1px solid rgba(148, 163, 184, 0.2);
181+
border-radius: 0.75rem;
182+
padding: 0.75rem 1rem;
183+
font-family: "JetBrains Mono", "Fira Code", monospace;
184+
font-size: 0.85rem;
185+
color: rgba(226, 232, 240, 0.95);
186+
white-space: pre-wrap;
187+
}

web/src/pages/ToolsPage.tsx

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@ interface CostPoint {
2626
nimbusMonthly: number;
2727
}
2828

29+
interface TerraformSuggestion {
30+
desiredCapacity: number;
31+
comment: string;
32+
snippet: string;
33+
}
34+
2935
const DEFAULT_INPUTS: RoiInputs = {
3036
runsPerDay: 180,
3137
avgRuntimeMins: 12,
@@ -109,6 +115,28 @@ export function ToolsPage() {
109115
URL.revokeObjectURL(url);
110116
};
111117

118+
const terraformSuggestion = useMemo<TerraformSuggestion>(() => {
119+
const totalMinutesPerDay = inputs.runsPerDay * inputs.avgRuntimeMins;
120+
const targetUtilisationMinutes = 8 * 60; // assume 8 productive hours per agent
121+
const desiredCapacity = Math.max(1, Math.ceil(totalMinutesPerDay / targetUtilisationMinutes));
122+
const snippet = [
123+
"# Suggested values generated by the ROI calculator",
124+
`agent_instance_type = "t3.large"`,
125+
`agent_desired_capacity = ${desiredCapacity}`,
126+
].join("\n");
127+
const comment =
128+
"Assuming ~8 productive hours per agent each day. Tweak the instance type or desired capacity to match your workload.";
129+
return {
130+
desiredCapacity,
131+
comment,
132+
snippet,
133+
};
134+
}, [inputs]);
135+
136+
const handleCopyTerraform = () => {
137+
void navigator.clipboard.writeText(terraformSuggestion.snippet);
138+
};
139+
112140
return (
113141
<div className="tools__container">
114142
<header className="tools__header">
@@ -187,6 +215,19 @@ export function ToolsPage() {
187215
</li>
188216
</ul>
189217
</section>
218+
219+
<section className="tools__section">
220+
<div className="tools__chart-header">
221+
<h2>Terraform autoscaling snippet</h2>
222+
<button type="button" onClick={handleCopyTerraform} className="tools__download">
223+
Copy snippet
224+
</button>
225+
</div>
226+
<p className="tools__terraform-comment">{terraformSuggestion.comment}</p>
227+
<pre className="tools__terraform-snippet">
228+
{terraformSuggestion.snippet}
229+
</pre>
230+
</section>
190231
</div>
191232
);
192233
}

web/src/pages/__tests__/ToolsPage.test.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ describe('ToolsPage', () => {
1818
expect(screen.getByText(/GitHub Actions monthly cost/i)).toBeInTheDocument();
1919
expect(screen.getByRole('img', { name: /Monthly cost comparison/i })).toBeInTheDocument();
2020
expect(screen.getByText(/Download CSV/i)).toBeInTheDocument();
21+
expect(screen.getByText(/terraform autoscaling snippet/i)).toBeInTheDocument();
22+
expect(screen.getByText(/agent_desired_capacity/)).toBeInTheDocument();
2123
});
2224

2325
it('updates calculations when inputs change', () => {

0 commit comments

Comments
 (0)