Skip to content

Commit 6085b92

Browse files
authored
feat(site): add annotation to display values of type clibase.Duration correctly (#10667)
* Adds an annotation format_duration_ns to all deployment values of type clibase.Duration * Adds a unit test that complains if you forget to add the above annotation to a clibase.Duration * Modifies optionValue() to check for the presence of format_duration_ns when displaying an option.
1 parent 34c9661 commit 6085b92

File tree

4 files changed

+85
-14
lines changed

4 files changed

+85
-14
lines changed

codersdk/deployment.go

+19-6
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ type HealthcheckConfig struct {
403403
}
404404

405405
const (
406-
annotationEnterpriseKey = "enterprise"
407-
annotationSecretKey = "secret"
406+
annotationFormatDuration = "format_duration"
407+
annotationEnterpriseKey = "enterprise"
408+
annotationSecretKey = "secret"
408409
// annotationExternalProxies is used to mark options that are used by workspace
409410
// proxies. This is used to filter out options that are not relevant.
410411
annotationExternalProxies = "external_workspace_proxies"
@@ -630,6 +631,7 @@ when required by your organization's security policy.`,
630631
Default: time.Minute.String(),
631632
Value: &c.AutobuildPollInterval,
632633
YAML: "autobuildPollInterval",
634+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
633635
},
634636
{
635637
Name: "Job Hang Detector Interval",
@@ -640,6 +642,7 @@ when required by your organization's security policy.`,
640642
Default: time.Minute.String(),
641643
Value: &c.JobHangDetectorInterval,
642644
YAML: "jobHangDetectorInterval",
645+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
643646
},
644647
httpAddress,
645648
tlsBindAddress,
@@ -1333,6 +1336,7 @@ when required by your organization's security policy.`,
13331336
Value: &c.Provisioner.DaemonPollInterval,
13341337
Group: &deploymentGroupProvisioning,
13351338
YAML: "daemonPollInterval",
1339+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
13361340
},
13371341
{
13381342
Name: "Poll Jitter",
@@ -1343,6 +1347,7 @@ when required by your organization's security policy.`,
13431347
Value: &c.Provisioner.DaemonPollJitter,
13441348
Group: &deploymentGroupProvisioning,
13451349
YAML: "daemonPollJitter",
1350+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
13461351
},
13471352
{
13481353
Name: "Force Cancel Interval",
@@ -1353,6 +1358,7 @@ when required by your organization's security policy.`,
13531358
Value: &c.Provisioner.ForceCancelInterval,
13541359
Group: &deploymentGroupProvisioning,
13551360
YAML: "forceCancelInterval",
1361+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
13561362
},
13571363
{
13581364
Name: "Provisioner Daemon Pre-shared Key (PSK)",
@@ -1502,10 +1508,11 @@ when required by your organization's security policy.`,
15021508
// The default value is essentially "forever", so just use 100 years.
15031509
// We have to add in the 25 leap days for the frontend to show the
15041510
// "100 years" correctly.
1505-
Default: ((100 * 365 * time.Hour * 24) + (25 * time.Hour * 24)).String(),
1506-
Value: &c.MaxTokenLifetime,
1507-
Group: &deploymentGroupNetworkingHTTP,
1508-
YAML: "maxTokenLifetime",
1511+
Default: ((100 * 365 * time.Hour * 24) + (25 * time.Hour * 24)).String(),
1512+
Value: &c.MaxTokenLifetime,
1513+
Group: &deploymentGroupNetworkingHTTP,
1514+
YAML: "maxTokenLifetime",
1515+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
15091516
},
15101517
{
15111518
Name: "Enable swagger endpoint",
@@ -1613,6 +1620,7 @@ when required by your organization's security policy.`,
16131620
Hidden: true,
16141621
Default: time.Hour.String(),
16151622
Value: &c.MetricsCacheRefreshInterval,
1623+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
16161624
},
16171625
{
16181626
Name: "Agent Stat Refresh Interval",
@@ -1622,6 +1630,7 @@ when required by your organization's security policy.`,
16221630
Hidden: true,
16231631
Default: (30 * time.Second).String(),
16241632
Value: &c.AgentStatRefreshInterval,
1633+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
16251634
},
16261635
{
16271636
Name: "Agent Fallback Troubleshooting URL",
@@ -1688,6 +1697,7 @@ when required by your organization's security policy.`,
16881697
Value: &c.SessionDuration,
16891698
Group: &deploymentGroupNetworkingHTTP,
16901699
YAML: "sessionDuration",
1700+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
16911701
},
16921702
{
16931703
Name: "Disable Session Expiry Refresh",
@@ -1790,6 +1800,7 @@ Write out the current server config as YAML to stdout.`,
17901800
Value: &c.ProxyHealthStatusInterval,
17911801
Group: &deploymentGroupNetworkingHTTP,
17921802
YAML: "proxyHealthInterval",
1803+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
17931804
},
17941805
{
17951806
Name: "Default Quiet Hours Schedule",
@@ -1821,6 +1832,7 @@ Write out the current server config as YAML to stdout.`,
18211832
Value: &c.Healthcheck.Refresh,
18221833
Group: &deploymentGroupIntrospectionHealthcheck,
18231834
YAML: "refresh",
1835+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
18241836
},
18251837
{
18261838
Name: "Health Check Threshold: Database",
@@ -1831,6 +1843,7 @@ Write out the current server config as YAML to stdout.`,
18311843
Value: &c.Healthcheck.ThresholdDatabase,
18321844
Group: &deploymentGroupIntrospectionHealthcheck,
18331845
YAML: "thresholdDatabase",
1846+
Annotations: clibase.Annotations{}.Mark(annotationFormatDuration, "true"),
18341847
},
18351848
}
18361849

codersdk/deployment_test.go

+21
Original file line numberDiff line numberDiff line change
@@ -256,3 +256,24 @@ func must[T any](value T, err error) T {
256256
}
257257
return value
258258
}
259+
260+
func TestDeploymentValues_DurationFormatNanoseconds(t *testing.T) {
261+
t.Parallel()
262+
263+
set := (&codersdk.DeploymentValues{}).Options()
264+
for _, s := range set {
265+
if s.Value.Type() != "duration" {
266+
continue
267+
}
268+
// Just make sure the annotation is set.
269+
// If someone wants to not format a duration, they can
270+
// explicitly set the annotation to false.
271+
if s.Annotations.IsSet("format_duration") {
272+
continue
273+
}
274+
t.Logf("Option %q is a duration but does not have the format_duration annotation.", s.Name)
275+
t.Logf("To fix this, add the following to the option declaration:")
276+
t.Logf(`Annotations: clibase.Annotations{}.Mark(annotationFormatDurationNS, "true"),`)
277+
t.FailNow()
278+
}
279+
}

site/src/components/DeploySettingsLayout/optionValue.test.ts

+24-2
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,16 @@ describe("optionValue", () => {
2121
...defaultOption,
2222
name: "Max Token Lifetime",
2323
value: 3600 * 1e9,
24+
annotations: { format_duration: "false" },
2425
},
25-
expected: "1 hour",
26+
expected: 3600000000000,
2627
},
2728
{
2829
option: {
2930
...defaultOption,
3031
name: "Max Token Lifetime",
3132
value: 24 * 3600 * 1e9,
33+
annotations: { format_duration: "true" },
3234
},
3335
expected: "1 day",
3436
},
@@ -37,14 +39,16 @@ describe("optionValue", () => {
3739
...defaultOption,
3840
name: "Session Duration",
3941
value: 3600 * 1e9,
42+
annotations: { format_duration: "some non-truthful value" },
4043
},
41-
expected: "1 hour",
44+
expected: 3600000000000,
4245
},
4346
{
4447
option: {
4548
...defaultOption,
4649
name: "Session Duration",
4750
value: 24 * 3600 * 1e9,
51+
annotations: { format_duration: "true" },
4852
},
4953
expected: "1 day",
5054
},
@@ -104,6 +108,24 @@ describe("optionValue", () => {
104108
additionalValues: ["single_tailnet", "deployment_health_page"],
105109
expected: { single_tailnet: true, deployment_health_page: true },
106110
},
111+
{
112+
option: {
113+
...defaultOption,
114+
name: "Some Go Duration We Want To Show As A String",
115+
value: 30 * 1e9,
116+
annotations: { format_duration: "true" },
117+
},
118+
expected: "30 seconds",
119+
},
120+
{
121+
option: {
122+
...defaultOption,
123+
name: "Some Other Go Duration We Want To Just Display As A Number",
124+
value: 30 * 1e9,
125+
annotations: { format_duration: "false" },
126+
},
127+
expected: 30000000000,
128+
},
107129
])(
108130
`[$option.name]optionValue($option.value)`,
109131
({ option, expected, additionalValues }) => {

site/src/components/DeploySettingsLayout/optionValue.ts

+21-6
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,28 @@ export function optionValue(
66
option: ClibaseOption,
77
additionalValues?: string[],
88
) {
9+
// If option annotations are present, use them to format the value.
10+
if (option.annotations) {
11+
for (const [k, v] of Object.entries(option.annotations)) {
12+
if (v !== "true") {
13+
continue; // skip if not explicitly true
14+
}
15+
switch (k) {
16+
case "format_duration":
17+
return formatDuration(
18+
// intervalToDuration takes ms, so convert nanoseconds to ms
19+
intervalToDuration({
20+
start: 0,
21+
end: (option.value as number) / 1e6,
22+
}),
23+
);
24+
// Add additional cases here as needed.
25+
}
26+
}
27+
}
28+
29+
// If no format annotations are present, use the option name to format the value.
930
switch (option.name) {
10-
case "Max Token Lifetime":
11-
case "Session Duration":
12-
// intervalToDuration takes ms, so convert nanoseconds to ms
13-
return formatDuration(
14-
intervalToDuration({ start: 0, end: (option.value as number) / 1e6 }),
15-
);
1631
case "Strict-Transport-Security":
1732
if (option.value === 0) {
1833
return "Disabled";

0 commit comments

Comments
 (0)