Skip to content

Commit 18786c4

Browse files
authored
fix(dashboards)!: handle dynamic dashboards in SingleWidgetDashboardSegment (#373)
This change fixes a couple things with the dynamic dashboard functionality that was introduced in d118a6e 1. `SingleWidgetDashboardSegment` was accepting ctor params to control dashboard visibility which conflicted with the overrideProps uses elsewhere to control the same. This change removes those params in favor of having consumers control this using overrideProps. 2. Fixes some issues in the `StaticSegmentDynamicAdapter` logic which were impacting backwards compatibility. 3. Introduces a new test to provide better coverage for the above two issues. --- _By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license_
1 parent 5d906f4 commit 18786c4

File tree

7 files changed

+139
-46
lines changed

7 files changed

+139
-46
lines changed

.projen/tasks.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.projenrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const project = new awscdk.AwsCdkConstructLibrary({
1111
keywords: ["cloudwatch", "monitoring"],
1212

1313
defaultReleaseBranch: "main",
14-
majorVersion: 4,
14+
majorVersion: 5,
1515
stability: "experimental",
1616

1717
cdkVersion: CDK_VERSION,

API.md

Lines changed: 31 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/dashboard/DynamicDashboardSegment.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,26 @@ export class StaticSegmentDynamicAdapter implements IDynamicDashboardSegment {
1717
this.props = props;
1818
}
1919

20+
/**
21+
* Adapts an IDashboardSegment to the IDynamicDashboardSegment interface by using
22+
* overrideProps to determine if a segment should be shown on a specific dashboard.
23+
* The default values are true, so consumers must set these to false if they would
24+
* like to hide these items from dashboards
25+
*/
2026
widgetsForDashboard(name: string): IWidget[] {
21-
if (
22-
this.props.overrideProps?.addToDetailDashboard ||
23-
name === DefaultDashboards.DETAIL
24-
) {
27+
const overrideProps = this.props.overrideProps;
28+
const addToDetailDashboard = overrideProps?.addToDetailDashboard ?? true;
29+
const addToSummaryDashboard = overrideProps?.addToSummaryDashboard ?? true;
30+
const addToAlarmsDashboard = overrideProps?.addToAlarmDashboard ?? true;
31+
if (addToDetailDashboard && name === DefaultDashboards.DETAIL) {
2532
return this.props.segment.widgets();
2633
}
27-
if (
28-
this.props.overrideProps?.addToSummaryDashboard ||
29-
name === DefaultDashboards.SUMMARY
30-
) {
34+
if (addToSummaryDashboard && name === DefaultDashboards.SUMMARY) {
3135
return this.props.segment.summaryWidgets();
3236
}
33-
if (
34-
this.props.overrideProps?.addToAlarmDashboard ||
35-
name === DefaultDashboards.ALARMS
36-
) {
37+
if (addToAlarmsDashboard && name === DefaultDashboards.ALARMS) {
3738
return this.props.segment.alarmWidgets();
3839
}
39-
4040
return [];
4141
}
4242
}
Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,57 @@
11
import { IWidget } from "aws-cdk-lib/aws-cloudwatch";
2-
32
import { IDashboardSegment } from "./DashboardSegment";
3+
import { DefaultDashboards } from "./DefaultDashboardFactory";
4+
import { IDynamicDashboardSegment } from "./DynamicDashboardSegment";
45

5-
export class SingleWidgetDashboardSegment implements IDashboardSegment {
6+
export class SingleWidgetDashboardSegment
7+
implements IDashboardSegment, IDynamicDashboardSegment
8+
{
69
protected readonly widget: IWidget;
7-
protected readonly addToSummary: boolean;
8-
protected readonly addToAlarm: boolean;
10+
protected readonly dashboardsToInclude: string[];
911

10-
constructor(widget: IWidget, addToSummary?: boolean, addToAlarm?: boolean) {
12+
/**
13+
* Create a dashboard segment representing a single widget.
14+
* @param widget widget to add
15+
* @param dashboardsToInclude list of dashboard names which to show this widget on. Defaults to the default dashboards.
16+
*/
17+
constructor(widget: IWidget, dashboardsToInclude?: string[]) {
1118
this.widget = widget;
12-
this.addToSummary = addToSummary ?? true;
13-
this.addToAlarm = addToAlarm ?? true;
19+
this.dashboardsToInclude = dashboardsToInclude ?? [
20+
DefaultDashboards.ALARMS,
21+
DefaultDashboards.DETAIL,
22+
DefaultDashboards.SUMMARY,
23+
];
24+
}
25+
26+
widgetsForDashboard(name: string): IWidget[] {
27+
if (this.dashboardsToInclude.includes(name)) {
28+
return [this.widget];
29+
} else {
30+
return [];
31+
}
1432
}
1533

1634
alarmWidgets(): IWidget[] {
17-
if (this.addToAlarm) {
35+
if (this.dashboardsToInclude.includes(DefaultDashboards.ALARMS)) {
1836
return [this.widget];
37+
} else {
38+
return [];
1939
}
20-
return [];
2140
}
2241

2342
summaryWidgets(): IWidget[] {
24-
if (this.addToSummary) {
43+
if (this.dashboardsToInclude.includes(DefaultDashboards.SUMMARY)) {
2544
return [this.widget];
45+
} else {
46+
return [];
2647
}
27-
return [];
2848
}
2949

3050
widgets(): IWidget[] {
31-
return [this.widget];
51+
if (this.dashboardsToInclude.includes(DefaultDashboards.DETAIL)) {
52+
return [this.widget];
53+
} else {
54+
return [];
55+
}
3256
}
3357
}

lib/facade/MonitoringFacade.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,9 +371,11 @@ export class MonitoringFacade extends MonitoringScope {
371371
}
372372

373373
addWidget(widget: IWidget, addToSummary?: boolean, addToAlarm?: boolean) {
374-
this.addSegment(
375-
new SingleWidgetDashboardSegment(widget, addToSummary, addToAlarm)
376-
);
374+
this.addSegment(new SingleWidgetDashboardSegment(widget), {
375+
addToAlarmDashboard: addToAlarm ?? true,
376+
addToSummaryDashboard: addToSummary ?? true,
377+
addToDetailDashboard: true,
378+
});
377379
return this;
378380
}
379381

test/facade/MonitoringFacade.test.ts

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { Stack } from "aws-cdk-lib";
2-
import { Template } from "aws-cdk-lib/assertions";
3-
import { DynamicDashboardFactory, MonitoringFacade } from "../../lib";
2+
import { Capture, Template } from "aws-cdk-lib/assertions";
3+
import { TextWidget } from "aws-cdk-lib/aws-cloudwatch";
4+
import {
5+
DefaultDashboardFactory,
6+
DynamicDashboardFactory,
7+
MonitoringFacade,
8+
SingleWidgetDashboardSegment,
9+
} from "../../lib";
410

511
describe("test of defaults", () => {
612
test("only default dashboard gets created by default", () => {
@@ -57,4 +63,48 @@ describe("test of defaults", () => {
5763
DashboardName: "testPrefix-Dynamic2",
5864
});
5965
});
66+
67+
test("SingleWidgetDashboardSegment is not displayed if addSegment overrides set to false", () => {
68+
// configure monitoring facade with dashboard factory which populates all three default dashboards
69+
const stack = new Stack();
70+
const dashboardFactory = new DefaultDashboardFactory(
71+
stack,
72+
"TestDashboardFactory",
73+
{
74+
dashboardNamePrefix: "testPrefix",
75+
createDashboard: true,
76+
createAlarmDashboard: true,
77+
createSummaryDashboard: true,
78+
}
79+
);
80+
const facade = new MonitoringFacade(stack, "Test", {
81+
dashboardFactory: dashboardFactory,
82+
});
83+
84+
// add SingleWidgetDashboardSegment with default ctor args but use overrides to
85+
// direct exclusion from default dashboards
86+
facade.addSegment(
87+
new SingleWidgetDashboardSegment(
88+
new TextWidget({ markdown: "Simple Dashboard Segment" })
89+
),
90+
{
91+
addToAlarmDashboard: false,
92+
addToDetailDashboard: false,
93+
addToSummaryDashboard: false,
94+
}
95+
);
96+
97+
// verify that the generated dashboards do not include the SingleWidgetDashboardSegment
98+
// due to override exclusion directives
99+
const result = Template.fromStack(stack);
100+
const dashboardCapture = new Capture();
101+
result.hasResourceProperties("AWS::CloudWatch::Dashboard", {
102+
DashboardBody: dashboardCapture,
103+
});
104+
105+
do {
106+
const dashboardBody = JSON.parse(dashboardCapture.asString());
107+
expect(dashboardBody.widgets).toHaveLength(0);
108+
} while (dashboardCapture.next());
109+
});
60110
});

0 commit comments

Comments
 (0)