From cf5d115aaba1bf62239817d4ced78316a9e50490 Mon Sep 17 00:00:00 2001 From: Peter Wahlberg Date: Mon, 22 Aug 2022 15:29:20 +0200 Subject: [PATCH] feat(aws-cloudwatch): add support for sparkline graphs in SingleValueWidget (#21684) Adds configuration option for enabling sparkline in SingleValueWidget. Fixes #21683 --- packages/@aws-cdk/aws-cloudwatch/README.md | 13 +++ packages/@aws-cdk/aws-cloudwatch/lib/graph.ts | 13 +++ packages/@aws-cdk/aws-cloudwatch/package.json | 1 + .../aws-cloudwatch/test/graphs.test.ts | 47 ++++++++ ...arkline-singlevaluewidget-and-dashboard.ts | 28 +++++ ...evaluewidget-sparkline-integ.template.json | 21 ++++ .../cdk.out | 1 + .../integ.json | 11 ++ .../manifest.json | 37 +++++++ ...aultTestDeployAssert6B085881.template.json | 1 + .../tree.json | 102 ++++++++++++++++++ 11 files changed, 275 insertions(+) create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/integ.sparkline-singlevaluewidget-and-dashboard.ts create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ.template.json create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/cdk.out create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/integ.json create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/manifest.json create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881.template.json create mode 100644 packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/tree.json diff --git a/packages/@aws-cdk/aws-cloudwatch/README.md b/packages/@aws-cdk/aws-cloudwatch/README.md index 069c11e89904d..e92e0f09356c7 100644 --- a/packages/@aws-cdk/aws-cloudwatch/README.md +++ b/packages/@aws-cdk/aws-cloudwatch/README.md @@ -430,6 +430,7 @@ dashboard.addWidgets(new cloudwatch.SingleValueWidget({ Show as many digits as can fit, before rounding. + ```ts declare const dashboard: cloudwatch.Dashboard; @@ -440,6 +441,18 @@ dashboard.addWidgets(new cloudwatch.SingleValueWidget({ })); ``` +Sparkline allows you to glance the trend of a metric by displaying a simplified linegraph below the value. You can't use `sparkline: true` together with `setPeriodToTimeRange: true` + +```ts +declare const dashboard: cloudwatch.Dashboard; + +dashboard.addWidgets(new cloudwatch.SingleValueWidget({ + metrics: [ /* ... */ ], + + sparkline: true, +})); +``` + ### Text widget A text widget shows an arbitrary piece of MarkDown. Use this to add explanations diff --git a/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts b/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts index 956ab3661e347..16bce048a7132 100644 --- a/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts +++ b/packages/@aws-cdk/aws-cloudwatch/lib/graph.ts @@ -335,6 +335,14 @@ export interface SingleValueWidgetProps extends MetricWidgetProps { * @default false */ readonly fullPrecision?: boolean; + + /** + * Whether to show a graph below the value illustrating the value for the whole time range. + * Cannot be used in combination with `setPeriodToTimeRange` + * + * @default false + */ + readonly sparkline?: boolean; } /** @@ -347,6 +355,10 @@ export class SingleValueWidget extends ConcreteWidget { super(props.width || 6, props.height || 3); this.props = props; this.copyMetricWarnings(...props.metrics); + + if (props.setPeriodToTimeRange && props.sparkline) { + throw new Error('You cannot use setPeriodToTimeRange with sparkline'); + } } public toJson(): any[] { @@ -360,6 +372,7 @@ export class SingleValueWidget extends ConcreteWidget { view: 'singleValue', title: this.props.title, region: this.props.region || cdk.Aws.REGION, + sparkline: this.props.sparkline, metrics: allMetricsGraphJson(this.props.metrics, []), setPeriodToTimeRange: this.props.setPeriodToTimeRange, singleValueFullPrecision: this.props.fullPrecision, diff --git a/packages/@aws-cdk/aws-cloudwatch/package.json b/packages/@aws-cdk/aws-cloudwatch/package.json index 81efaf0e3bcd7..4fecd4700ef15 100644 --- a/packages/@aws-cdk/aws-cloudwatch/package.json +++ b/packages/@aws-cdk/aws-cloudwatch/package.json @@ -83,6 +83,7 @@ "@aws-cdk/assertions": "0.0.0", "@aws-cdk/cdk-build-tools": "0.0.0", "@aws-cdk/integ-runner": "0.0.0", + "@aws-cdk/integ-tests": "0.0.0", "@aws-cdk/cfn2ts": "0.0.0", "@aws-cdk/pkglint": "0.0.0", "@types/jest": "^27.5.2", diff --git a/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts b/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts index ec5be311ecbb9..e459063e5936d 100644 --- a/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts +++ b/packages/@aws-cdk/aws-cloudwatch/test/graphs.test.ts @@ -621,6 +621,53 @@ describe('Graphs', () => { }); + test('add sparkline to singleValueWidget', () => { + // GIVEN + const stack = new Stack(); + const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); + + // WHEN + const widget = new SingleValueWidget({ + metrics: [metric], + sparkline: true, + }); + + // THEN + expect(stack.resolve(widget.toJson())).toEqual([{ + type: 'metric', + width: 6, + height: 3, + properties: { + view: 'singleValue', + region: { Ref: 'AWS::Region' }, + metrics: [ + ['CDK', 'Test'], + ], + sparkline: true, + }, + }]); + + + }); + + test('throws if setPeriodToTimeRange and sparkline is set on singleValueWidget', () => { + // GIVEN + new Stack(); + const metric = new Metric({ namespace: 'CDK', metricName: 'Test' }); + + // WHEN + const toThrow = () => { + new SingleValueWidget({ + metrics: [metric], + setPeriodToTimeRange: true, + sparkline: true, + }); + }; + + // THEN + expect(() => toThrow()).toThrow(/You cannot use setPeriodToTimeRange with sparkline/); + }); + test('add singleValueFullPrecision to singleValueWidget', () => { // GIVEN const stack = new Stack(); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/integ.sparkline-singlevaluewidget-and-dashboard.ts b/packages/@aws-cdk/aws-cloudwatch/test/integ.sparkline-singlevaluewidget-and-dashboard.ts new file mode 100644 index 0000000000000..01cd4e3dd664b --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/integ.sparkline-singlevaluewidget-and-dashboard.ts @@ -0,0 +1,28 @@ +import { App, Stack, StackProps } from '@aws-cdk/core'; +import { IntegTest } from '@aws-cdk/integ-tests'; +import { Dashboard, SingleValueWidget, Metric } from '../lib'; + +class TestStack extends Stack { + constructor(scope: App, id: string, props?: StackProps) { + super(scope, id, props); + + const dashboard = new Dashboard(this, 'Dashboard'); + + const testMetric = new Metric({ + namespace: 'CDK/Test', + metricName: 'Metric', + }); + + const widget = new SingleValueWidget({ + metrics: [testMetric], + sparkline: true, + }); + + dashboard.addWidgets(widget); + } +} +const app = new App(); +const testCase = new TestStack(app, 'aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ'); +new IntegTest(app, 'singlevaluewidget-with-sparkline', { + testCases: [testCase], +}); diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ.template.json b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ.template.json new file mode 100644 index 0000000000000..faff4f3ee0949 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ.template.json @@ -0,0 +1,21 @@ +{ + "Resources": { + "Dashboard9E4231ED": { + "Type": "AWS::CloudWatch::Dashboard", + "Properties": { + "DashboardBody": { + "Fn::Join": [ + "", + [ + "{\"widgets\":[{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":0,\"properties\":{\"view\":\"singleValue\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"sparkline\":true,\"metrics\":[[\"CDK/Test\",\"Metric\"]]}}]}" + ] + ] + } + } + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/cdk.out b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/cdk.out new file mode 100644 index 0000000000000..588d7b269d34f --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/cdk.out @@ -0,0 +1 @@ +{"version":"20.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/integ.json b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/integ.json new file mode 100644 index 0000000000000..153f43dc454b7 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/integ.json @@ -0,0 +1,11 @@ +{ + "version": "20.0.0", + "testCases": { + "singlevaluewidget-with-sparkline/DefaultTest": { + "stacks": [ + "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ" + ], + "assertionStack": "singlevaluewidget-with-sparkline/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/manifest.json b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/manifest.json new file mode 100644 index 0000000000000..d9ad7246d0f02 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/manifest.json @@ -0,0 +1,37 @@ +{ + "version": "20.0.0", + "artifacts": { + "Tree": { + "type": "cdk:tree", + "properties": { + "file": "tree.json" + } + }, + "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ.template.json", + "validateOnSynth": false + }, + "metadata": { + "/aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ/Dashboard/Resource": [ + { + "type": "aws:cdk:logicalId", + "data": "Dashboard9E4231ED" + } + ] + }, + "displayName": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ" + }, + "singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881": { + "type": "aws:cloudformation:stack", + "environment": "aws://unknown-account/unknown-region", + "properties": { + "templateFile": "singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881.template.json", + "validateOnSynth": false + }, + "displayName": "singlevaluewidget-with-sparkline/DefaultTest/DeployAssert" + } + } +} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881.template.json b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881.template.json new file mode 100644 index 0000000000000..9e26dfeeb6e64 --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/singlevaluewidgetwithsparklineDefaultTestDeployAssert6B085881.template.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/tree.json b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/tree.json new file mode 100644 index 0000000000000..7a1304b42d81a --- /dev/null +++ b/packages/@aws-cdk/aws-cloudwatch/test/sparkline-singlevaluewidget-and-dashboard.integ.snapshot/tree.json @@ -0,0 +1,102 @@ +{ + "version": "tree-0.1", + "tree": { + "id": "App", + "path": "", + "children": { + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.78" + } + }, + "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ": { + "id": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ", + "path": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ", + "children": { + "Dashboard": { + "id": "Dashboard", + "path": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ/Dashboard", + "children": { + "Resource": { + "id": "Resource", + "path": "aws-cdk-cloudwatch-singlevaluewidget-sparkline-integ/Dashboard/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::CloudWatch::Dashboard", + "aws:cdk:cloudformation:props": { + "dashboardBody": { + "Fn::Join": [ + "", + [ + "{\"widgets\":[{\"type\":\"metric\",\"width\":6,\"height\":3,\"x\":0,\"y\":0,\"properties\":{\"view\":\"singleValue\",\"region\":\"", + { + "Ref": "AWS::Region" + }, + "\",\"sparkline\":true,\"metrics\":[[\"CDK/Test\",\"Metric\"]]}}]}" + ] + ] + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudwatch.CfnDashboard", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/aws-cloudwatch.Dashboard", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + }, + "singlevaluewidget-with-sparkline": { + "id": "singlevaluewidget-with-sparkline", + "path": "singlevaluewidget-with-sparkline", + "children": { + "DefaultTest": { + "id": "DefaultTest", + "path": "singlevaluewidget-with-sparkline/DefaultTest", + "children": { + "Default": { + "id": "Default", + "path": "singlevaluewidget-with-sparkline/DefaultTest/Default", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.1.78" + } + }, + "DeployAssert": { + "id": "DeployAssert", + "path": "singlevaluewidget-with-sparkline/DefaultTest/DeployAssert", + "constructInfo": { + "fqn": "@aws-cdk/core.Stack", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTestCase", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/integ-tests.IntegTest", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "@aws-cdk/core.App", + "version": "0.0.0" + } + } +} \ No newline at end of file