Most Nerdpacks in the Instant Observability catalog are open-source. This means you can clone or fork their repositories, customize them to suit your specific needs, and re-publish them to use with your account. In this guide, you customize a Nerdpack with visualizations and publish it to your account. However, to customize any Nerdpack, you follow the same steps.
Before you begin
If you haven't already:
- Sign up for a New Relic account
- Install Node.js
- Complete the first four steps in the
nr1
quick start to install and configure the CLI
View a Nerdpack
Subscribe to the Victory Charts Visualizations Nerdpack and open the Circular progress bar visualization in New Relic.
From your homepage at New Relic, navigate to Instant Observability:
Click the Victory Charts Visualizations Nerdpack in the catalog:
From Apps, open Custom visualizations:
From the list of visualizations in Custom visualizations click Circular progress bar, which you installed as part of the Victory Charts Visualizations Nerdpack.
Under Configure visualization properties, select your account and enter a NRQL query:
Now you see a circular chart that shows a percentage based on your query.
Tip
Read our documentation for instructions on how to configure the progress bar visualization.
Notice a few things about this visualization:
- You don't control the color of the chart
- The sections of the chart have rounded edges
For the sake of this tutorial, imagine this chart represents your data exactly how you want it to, except for two things. You'd like to use straight edges and control the chart's colors manually. In the real world you may come across Nerdpacks like this where you like what they offer, but you'd like them better if you could tweak them. Well, you can tweak them, and next, you'll learn how!
Because you're going to use a tweaked version of the Victory Charts Visualizations Nerdpack instead of the one you subscribed to, you can unsubscribe from our version now.
Clone a Nerdpack
Find the source code repository from the Nerdpack's catalog entry and clone it to your local machine.
From your homepage at New Relic, navigate to Instant Observability:
Click the Victory Charts Visualizations Nerdpack in the catalog:
Go to the Nerdpack's source code repository:
All open-source Nerdpacks in the catalog have links to their source code in their catalog information.
Clone the repository:
$nr1 nerdpack:clone -r https://github.com/newrelic/nr1-victory-visualizations.git
Now you have a local version of the Victory Charts Visualizations Nerdpack! Notice that you used nr1 nerdpack:clone
instead of git clone
to copy the repo. nr1 nerdpack:clone
offers built-in functionality to help keep your local copy distinct from the original Nerdpack in the Instant Observability public catalog. Specifically, it generates a new Nerdpack UUID so you don't have to do this yourself:
Re-generating UUID...Committing new UUID...
If you change to the nr1-victory-visualizations directory, and look at the git log, you'll see the new commit:
$git log -1 -pcommit e356bb5b10c3ecc8f93bae66d5739e1676ee21ef (HEAD -> main)Author: New Relic CLI <nr1@newrelic.com>Date: Tue May 25 14:29:37 2021 -0400 "chore: Auto-generated UUID"diff --git a/nr1.json b/nr1.jsonindex 054de52..7a107b5 100644--- a/nr1.json+++ b/nr1.json@@ -1,6 +1,6 @@ { "schemaType": "NERDPACK",- "id": "cf5f13d9-815f-4907-a21d-83d02fa2a4fb",+ "id": "ab123c45-678d-9012-efg3-45hi6jkl7890", "displayName": "Victory charts visualizations", "description": "Visualizations built on top of Victory charts" }
In nr1-victory-visualizations/nr1.json, change your Nerdpack's displayName
:
{ "schemaType": "NERDPACK", "id": "269055dd-67e8-4713-8da3-bff01c6a8687", "displayName": "My custom Victory Charts visualizations", "description": "Visualizations built on top of Victory charts"}
Now when you serve or publish your custom Nerdpack, you can easily distinguish it from the original.
Customize a Nerdpack
Tweak the Circular progress bar visualization to use straight edges and customizable colors.
Circular progress bar renders a VictoryPie
with some predefined fields. The fields you'll tweak are:
In your local Nerdpack, open nr1-victory-visualizations/visualizations/circular-progress-bar/nr1.json.
nr1.json is the Circular progress bar visualization's metadata file. Use this file to add a configurable colorScale
option, which corresponds to the colorScale
field on VictoryPie
.
Add a collection
of string
fields for you to customize your chart's colors:
1{2 "schemaType": "VISUALIZATION",3 "id": "circular-progress-bar",4 "displayName": "Circular progress bar",5 "description": "",6 "configuration": [7 {8 "name": "nrqlQueries",9 "title": "NRQL Queries",10 "type": "collection",11 "items": [12 {13 "name": "accountId",14 "title": "Account ID",15 "description": "Account ID to be associated with the query",16 "type": "account-id"17 },18 {19 "name": "query",20 "title": "Query",21 "description": "NRQL query for visualization",22 "type": "nrql"23 }24 ]25 },26 {27 "name": "thresholds",28 "title": "Thresholds",29 "type": "namespace",30 "items": [31 {32 "name": "criticalThreshold",33 "title": "Critical threshold",34 "description": "Value at which progress is displayed as critical",35 "type": "number"36 },37 {38 "name": "highValuesAreSuccess",39 "title": "Above threshold is success",40 "description": "If toggled on, values above the threshold display as successful. Otherwise, values at or above the threshold display as critical.",41 "type": "boolean"42 }43 ]44 },45 {46 "name": "colors",47 "title": "Colors",48 "type": "collection",49 "items": [50 {51 "name": "segmentColor",52 "title": "Segment color",53 "description": "The color of a bar segment.",54 "type": "string"55 }56 ]57 }58 ]59}
1import React from 'react';2import PropTypes from 'prop-types';3import { VictoryPie, VictoryAnimation, VictoryLabel } from 'victory';4import {5 Card,6 CardBody,7 HeadingText,8 NrqlQuery,9 Spinner,10 AutoSizer,11} from 'nr1';12import NrqlQueryError from '../../src/nrql-query-error';13import { baseLabelStyles } from '../../src/theme';14import { getUniqueAggregatesAndFacets } from '../../src/utils/nrql-validation-helper';15import Colors from '../../src/colors';16
17const BOUNDS = {18 X: 400,19 Y: 400,20};21
22const LABEL_SIZE = 24;23const LABEL_PADDING = 10;24const CHART_WIDTH = BOUNDS.X;25const CHART_HEIGHT = BOUNDS.Y - LABEL_SIZE - LABEL_PADDING;26
27export default class CircularProgressBar extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // the nr1.json file for the visualization. See docs for more details.30 static propTypes = {31 /**32 * An array of objects consisting of a nrql `query` and `accountId`.33 * This should be a standard prop for any NRQL based visualizations.34 */35 nrqlQueries: PropTypes.arrayOf(36 PropTypes.shape({37 accountId: PropTypes.number,38 query: PropTypes.string,39 })40 ),41
42 /**43 * Configuration that determines what values to display as critical or44 * successful.45 */46 thresholds: PropTypes.shape({47 criticalThreshold: PropTypes.number,48 highValuesAreSuccess: PropTypes.bool,49 }),50 };51
52 /**53 * Restructure the data for a aggregate NRQL query with no TIMESERIES and no54 * FACET into a for our visualization works well with.55 */56 transformData = (data) => {57 const {58 data: [series],59 metadata: { color: colorFromData, name: label },60 } = data[0];61
62 const percent = series.y * 100;63 const color = this.getColor(percent, colorFromData);64
65 return {66 percent,67 label,68 series: [69 { x: 'progress', y: percent, color },70 { x: 'remainder', y: 100 - percent, color: 'transparent' },71 ],72 };73 };74
75 nrqlInputIsValid = (data) => {76 const { data: seriesEntries } = data[0];77 const { uniqueAggregates, uniqueFacets } = getUniqueAggregatesAndFacets(78 data79 );80 const isNonTimeseries = seriesEntries.length === 1;81
82 return (83 uniqueAggregates.size === 1 && uniqueFacets.size === 0 && isNonTimeseries84 );85 };86
87 getColor = (value, colorFromData) => {88 const { red6: red, green6: green } = Colors.base;89 const {90 thresholds: { criticalThreshold, highValuesAreSuccess },91 } = this.props;92
93 const threshold = parseFloat(criticalThreshold);94
95 if (isNaN(threshold)) {96 return colorFromData;97 }98
99 if (highValuesAreSuccess) {100 return value > threshold ? green : red;101 }102
103 return value < threshold ? green : red;104 };105
106 render() {107 const { nrqlQueries } = this.props;108
109 const nrqlQueryPropsAvailable =110 nrqlQueries &&111 nrqlQueries[0] &&112 nrqlQueries[0].accountId &&113 nrqlQueries[0].query;114
115 if (!nrqlQueryPropsAvailable) {116 return <EmptyState />;117 }118
119 return (120 <AutoSizer>121 {({ width, height }) => (122 <NrqlQuery123 query={nrqlQueries[0].query}124 accountId={parseInt(nrqlQueries[0].accountId)}125 pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}126 >127 {({ data, loading, error }) => {128 if (loading) {129 return <Spinner />;130 }131
132 if (error) {133 return (134 <NrqlQueryError135 title="NRQL Syntax Error"136 description={error.message}137 />138 );139 }140
141 if (!this.nrqlInputIsValid(data)) {142 return (143 <NrqlQueryError144 title="Unsupported NRQL query"145 description="The provided NRQL query is not supported by this visualization. Please make sure to have exactly 1 aggregate function in the SELECT clause and no FACET or TIMESERIES clauses."146 />147 );148 }149
150 const { percent, label, series } = this.transformData(data);151
152 return (153 <svg154 viewBox={`0 0 ${BOUNDS.X} ${BOUNDS.Y}`}155 width={width}156 height={height}157 className="CircularProgressBar"158 >159 <VictoryPie160 standalone={false}161 animate={{ duration: 1000 }}162 data={series}163 width={CHART_WIDTH}164 height={CHART_HEIGHT}165 padding={10}166 innerRadius={135}167 cornerRadius={25}168 labels={() => null}169 style={{ data: { fill: ({ datum }) => datum.color } }}170 />171 <VictoryAnimation duration={1000} data={percent}>172 {(percent) => (173 <VictoryLabel174 textAnchor="middle"175 verticalAnchor="middle"176 x={CHART_WIDTH / 2}177 y={CHART_HEIGHT / 2}178 text={`${Math.round(percent)}%`}179 style={{ ...baseLabelStyles, fontSize: 45 }}180 />181 )}182 </VictoryAnimation>183 <VictoryLabel184 text={label}185 lineHeight={1}186 x={CHART_WIDTH / 2}187 y={BOUNDS.Y - LABEL_SIZE}188 textAnchor="middle"189 style={{ ...baseLabelStyles, fontSize: LABEL_SIZE }}190 />191 </svg>192 );193 }}194 </NrqlQuery>195 )}196 </AutoSizer>197 );198 }199}200
201const EmptyState = () => (202 <Card className="EmptyState">203 <CardBody className="EmptyState-cardBody">204 <HeadingText205 spacingType={[HeadingText.SPACING_TYPE.LARGE]}206 type={HeadingText.TYPE.HEADING_3}207 >208 Please provide a NRQL query & account ID pair209 </HeadingText>210 <HeadingText211 spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}212 type={HeadingText.TYPE.HEADING_4}213 >214 This Visualization supports NRQL queries with a single SELECT clause215 returning a percentage value (0 to 100 rather than 0 to 1). For example:216 </HeadingText>217 <code>218 {'FROM Transaction SELECT percentage(count(*), WHERE duration < 0.1)'}219 </code>220 </CardBody>221 </Card>222);
The VictoryPie
field that you'll use with this update is called colorScale
. It accepts an array of colors and applies each color to a segment of the progress bar. So, in your visualization's configuration options, you've specified a collection of strings that you use to pass colors to your chart.
In the same visualization directory, open index.js.
In render()
, set the VictoryPie
component's colorScale
prop:
1{2 "schemaType": "VISUALIZATION",3 "id": "circular-progress-bar",4 "displayName": "Circular progress bar",5 "description": "",6 "configuration": [7 {8 "name": "nrqlQueries",9 "title": "NRQL Queries",10 "type": "collection",11 "items": [12 {13 "name": "accountId",14 "title": "Account ID",15 "description": "Account ID to be associated with the query",16 "type": "account-id"17 },18 {19 "name": "query",20 "title": "Query",21 "description": "NRQL query for visualization",22 "type": "nrql"23 }24 ]25 },26 {27 "name": "thresholds",28 "title": "Thresholds",29 "type": "namespace",30 "items": [31 {32 "name": "criticalThreshold",33 "title": "Critical threshold",34 "description": "Value at which progress is displayed as critical",35 "type": "number"36 },37 {38 "name": "highValuesAreSuccess",39 "title": "Above threshold is success",40 "description": "If toggled on, values above the threshold display as successful. Otherwise, values at or above the threshold display as critical.",41 "type": "boolean"42 }43 ]44 },45 {46 "name": "colors",47 "title": "Colors",48 "type": "collection",49 "items": [50 {51 "name": "segmentColor",52 "title": "Segment color",53 "description": "The color of a bar segment.",54 "type": "string"55 }56 ]57 }58 ]59}
1import React from 'react';2import PropTypes from 'prop-types';3import { VictoryPie, VictoryAnimation, VictoryLabel } from 'victory';4import {5 Card,6 CardBody,7 HeadingText,8 NrqlQuery,9 Spinner,10 AutoSizer,11} from 'nr1';12import NrqlQueryError from '../../src/nrql-query-error';13import { baseLabelStyles } from '../../src/theme';14import { getUniqueAggregatesAndFacets } from '../../src/utils/nrql-validation-helper';15import Colors from '../../src/colors';16
17const BOUNDS = {18 X: 400,19 Y: 400,20};21
22const LABEL_SIZE = 24;23const LABEL_PADDING = 10;24const CHART_WIDTH = BOUNDS.X;25const CHART_HEIGHT = BOUNDS.Y - LABEL_SIZE - LABEL_PADDING;26
27export default class CircularProgressBar extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // the nr1.json file for the visualization. See docs for more details.30 static propTypes = {31 /**32 * An array of objects consisting of a nrql `query` and `accountId`.33 * This should be a standard prop for any NRQL based visualizations.34 */35 nrqlQueries: PropTypes.arrayOf(36 PropTypes.shape({37 accountId: PropTypes.number,38 query: PropTypes.string,39 })40 ),41
42 /**43 * Configuration that determines what values to display as critical or44 * successful.45 */46 thresholds: PropTypes.shape({47 criticalThreshold: PropTypes.number,48 highValuesAreSuccess: PropTypes.bool,49 }),50 };51
52 /**53 * Restructure the data for a aggregate NRQL query with no TIMESERIES and no54 * FACET into a for our visualization works well with.55 */56 transformData = (data) => {57 const {58 data: [series],59 metadata: { color: colorFromData, name: label },60 } = data[0];61
62 const percent = series.y * 100;63 const color = this.getColor(percent, colorFromData);64
65 return {66 percent,67 label,68 series: [69 { x: 'progress', y: percent, color },70 { x: 'remainder', y: 100 - percent, color: 'transparent' },71 ],72 };73 };74
75 nrqlInputIsValid = (data) => {76 const { data: seriesEntries } = data[0];77 const { uniqueAggregates, uniqueFacets } = getUniqueAggregatesAndFacets(78 data79 );80 const isNonTimeseries = seriesEntries.length === 1;81
82 return (83 uniqueAggregates.size === 1 && uniqueFacets.size === 0 && isNonTimeseries84 );85 };86
87 getColor = (value, colorFromData) => {88 const { red6: red, green6: green } = Colors.base;89 const {90 thresholds: { criticalThreshold, highValuesAreSuccess },91 } = this.props;92
93 const threshold = parseFloat(criticalThreshold);94
95 if (isNaN(threshold)) {96 return colorFromData;97 }98
99 if (highValuesAreSuccess) {100 return value > threshold ? green : red;101 }102
103 return value < threshold ? green : red;104 };105
106 render() {107 const { nrqlQueries, colors } = this.props;108 const colorScale = Array.from(colors, (x) => x.segmentColor);109
110 const nrqlQueryPropsAvailable =111 nrqlQueries &&112 nrqlQueries[0] &&113 nrqlQueries[0].accountId &&114 nrqlQueries[0].query;115
116 if (!nrqlQueryPropsAvailable) {117 return <EmptyState />;118 }119
120 return (121 <AutoSizer>122 {({ width, height }) => (123 <NrqlQuery124 query={nrqlQueries[0].query}125 accountId={parseInt(nrqlQueries[0].accountId)}126 pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}127 >128 {({ data, loading, error }) => {129 if (loading) {130 return <Spinner />;131 }132
133 if (error) {134 return (135 <NrqlQueryError136 title="NRQL Syntax Error"137 description={error.message}138 />139 );140 }141
142 if (!this.nrqlInputIsValid(data)) {143 return (144 <NrqlQueryError145 title="Unsupported NRQL query"146 description="The provided NRQL query is not supported by this visualization. Please make sure to have exactly 1 aggregate function in the SELECT clause and no FACET or TIMESERIES clauses."147 />148 );149 }150
151 const { percent, label, series } = this.transformData(data);152
153 return (154 <svg155 viewBox={`0 0 ${BOUNDS.X} ${BOUNDS.Y}`}156 width={width}157 height={height}158 className="CircularProgressBar"159 >160 <VictoryPie161 standalone={false}162 animate={{ duration: 1000 }}163 data={series}164 width={CHART_WIDTH}165 height={CHART_HEIGHT}166 padding={10}167 innerRadius={135}168 cornerRadius={25}169 labels={() => null}170 colorScale={colorScale}171 />172 <VictoryAnimation duration={1000} data={percent}>173 {(percent) => (174 <VictoryLabel175 textAnchor="middle"176 verticalAnchor="middle"177 x={CHART_WIDTH / 2}178 y={CHART_HEIGHT / 2}179 text={`${Math.round(percent)}%`}180 style={{ ...baseLabelStyles, fontSize: 45 }}181 />182 )}183 </VictoryAnimation>184 <VictoryLabel185 text={label}186 lineHeight={1}187 x={CHART_WIDTH / 2}188 y={BOUNDS.Y - LABEL_SIZE}189 textAnchor="middle"190 style={{ ...baseLabelStyles, fontSize: LABEL_SIZE }}191 />192 </svg>193 );194 }}195 </NrqlQuery>196 )}197 </AutoSizer>198 );199 }200}201
202const EmptyState = () => (203 <Card className="EmptyState">204 <CardBody className="EmptyState-cardBody">205 <HeadingText206 spacingType={[HeadingText.SPACING_TYPE.LARGE]}207 type={HeadingText.TYPE.HEADING_3}208 >209 Please provide a NRQL query & account ID pair210 </HeadingText>211 <HeadingText212 spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}213 type={HeadingText.TYPE.HEADING_4}214 >215 This Visualization supports NRQL queries with a single SELECT clause216 returning a percentage value (0 to 100 rather than 0 to 1). For example:217 </HeadingText>218 <code>219 {'FROM Transaction SELECT percentage(count(*), WHERE duration < 0.1)'}220 </code>221 </CardBody>222 </Card>223);
First, you created a new constant, called colorScale
, which is an array of the segmentColor
values from this.props.colors
. Then, you set the VictoryPie
component's colorScale
prop. Finally, you removed VictoryPie.style
because the colors are now controlled by colorScale
.
From your Nerdpack's root directory, run a local server:
$nr1 nerdpack:serve
Once the server is running, find the url for your local circular-progress-bar
:
Visualizations: ⁎ circular-progress-bar https://one.nr/04ERPALBYjW ⁎ range-chart https://one.nr/0oqQaxezJj1 ⁎ stacked-bar-chart https://one.nr/0PLRElq3bwa
Open your locally served visualization and configure your chart with your account, data query, and segment colors:
Tip
To add a second color, click the + in the top right of the Colors property.
Because there are two segments, you add two colors. The first color is for the progress section. The second color is for the remaining percentage.
In index.js, remove the VictoryPie
component's cornerRadius
prop:
1{2 "schemaType": "VISUALIZATION",3 "id": "circular-progress-bar",4 "displayName": "Circular progress bar",5 "description": "",6 "configuration": [7 {8 "name": "nrqlQueries",9 "title": "NRQL Queries",10 "type": "collection",11 "items": [12 {13 "name": "accountId",14 "title": "Account ID",15 "description": "Account ID to be associated with the query",16 "type": "account-id"17 },18 {19 "name": "query",20 "title": "Query",21 "description": "NRQL query for visualization",22 "type": "nrql"23 }24 ]25 },26 {27 "name": "thresholds",28 "title": "Thresholds",29 "type": "namespace",30 "items": [31 {32 "name": "criticalThreshold",33 "title": "Critical threshold",34 "description": "Value at which progress is displayed as critical",35 "type": "number"36 },37 {38 "name": "highValuesAreSuccess",39 "title": "Above threshold is success",40 "description": "If toggled on, values above the threshold display as successful. Otherwise, values at or above the threshold display as critical.",41 "type": "boolean"42 }43 ]44 },45 {46 "name": "colors",47 "title": "Colors",48 "type": "collection",49 "items": [50 {51 "name": "segmentColor",52 "title": "Segment color",53 "description": "The color of a bar segment.",54 "type": "string"55 }56 ]57 }58 ]59}
1import React from 'react';2import PropTypes from 'prop-types';3import { VictoryPie, VictoryAnimation, VictoryLabel } from 'victory';4import {5 Card,6 CardBody,7 HeadingText,8 NrqlQuery,9 Spinner,10 AutoSizer,11} from 'nr1';12import NrqlQueryError from '../../src/nrql-query-error';13import { baseLabelStyles } from '../../src/theme';14import { getUniqueAggregatesAndFacets } from '../../src/utils/nrql-validation-helper';15import Colors from '../../src/colors';16
17const BOUNDS = {18 X: 400,19 Y: 400,20};21
22const LABEL_SIZE = 24;23const LABEL_PADDING = 10;24const CHART_WIDTH = BOUNDS.X;25const CHART_HEIGHT = BOUNDS.Y - LABEL_SIZE - LABEL_PADDING;26
27export default class CircularProgressBar extends React.Component {28 // Custom props you wish to be configurable in the UI must also be defined in29 // the nr1.json file for the visualization. See docs for more details.30 static propTypes = {31 /**32 * An array of objects consisting of a nrql `query` and `accountId`.33 * This should be a standard prop for any NRQL based visualizations.34 */35 nrqlQueries: PropTypes.arrayOf(36 PropTypes.shape({37 accountId: PropTypes.number,38 query: PropTypes.string,39 })40 ),41
42 /**43 * Configuration that determines what values to display as critical or44 * successful.45 */46 thresholds: PropTypes.shape({47 criticalThreshold: PropTypes.number,48 highValuesAreSuccess: PropTypes.bool,49 }),50 };51
52 /**53 * Restructure the data for a aggregate NRQL query with no TIMESERIES and no54 * FACET into a for our visualization works well with.55 */56 transformData = (data) => {57 const {58 data: [series],59 metadata: { color: colorFromData, name: label },60 } = data[0];61
62 const percent = series.y * 100;63 const color = this.getColor(percent, colorFromData);64
65 return {66 percent,67 label,68 series: [69 { x: 'progress', y: percent, color },70 { x: 'remainder', y: 100 - percent, color: 'transparent' },71 ],72 };73 };74
75 nrqlInputIsValid = (data) => {76 const { data: seriesEntries } = data[0];77 const { uniqueAggregates, uniqueFacets } = getUniqueAggregatesAndFacets(78 data79 );80 const isNonTimeseries = seriesEntries.length === 1;81
82 return (83 uniqueAggregates.size === 1 && uniqueFacets.size === 0 && isNonTimeseries84 );85 };86
87 getColor = (value, colorFromData) => {88 const { red6: red, green6: green } = Colors.base;89 const {90 thresholds: { criticalThreshold, highValuesAreSuccess },91 } = this.props;92
93 const threshold = parseFloat(criticalThreshold);94
95 if (isNaN(threshold)) {96 return colorFromData;97 }98
99 if (highValuesAreSuccess) {100 return value > threshold ? green : red;101 }102
103 return value < threshold ? green : red;104 };105
106 render() {107 const { nrqlQueries, colors } = this.props;108 const colorScale = Array.from(colors, (x) => x.segmentColor);109
110 const nrqlQueryPropsAvailable =111 nrqlQueries &&112 nrqlQueries[0] &&113 nrqlQueries[0].accountId &&114 nrqlQueries[0].query;115
116 if (!nrqlQueryPropsAvailable) {117 return <EmptyState />;118 }119
120 return (121 <AutoSizer>122 {({ width, height }) => (123 <NrqlQuery124 query={nrqlQueries[0].query}125 accountId={parseInt(nrqlQueries[0].accountId)}126 pollInterval={NrqlQuery.AUTO_POLL_INTERVAL}127 >128 {({ data, loading, error }) => {129 if (loading) {130 return <Spinner />;131 }132
133 if (error) {134 return (135 <NrqlQueryError136 title="NRQL Syntax Error"137 description={error.message}138 />139 );140 }141
142 if (!this.nrqlInputIsValid(data)) {143 return (144 <NrqlQueryError145 title="Unsupported NRQL query"146 description="The provided NRQL query is not supported by this visualization. Please make sure to have exactly 1 aggregate function in the SELECT clause and no FACET or TIMESERIES clauses."147 />148 );149 }150
151 const { percent, label, series } = this.transformData(data);152
153 return (154 <svg155 viewBox={`0 0 ${BOUNDS.X} ${BOUNDS.Y}`}156 width={width}157 height={height}158 className="CircularProgressBar"159 >160 <VictoryPie161 standalone={false}162 animate={{ duration: 1000 }}163 data={series}164 width={CHART_WIDTH}165 height={CHART_HEIGHT}166 padding={10}167 innerRadius={135}168 labels={() => null}169 colorScale={colorScale}170 />171 <VictoryAnimation duration={1000} data={percent}>172 {(percent) => (173 <VictoryLabel174 textAnchor="middle"175 verticalAnchor="middle"176 x={CHART_WIDTH / 2}177 y={CHART_HEIGHT / 2}178 text={`${Math.round(percent)}%`}179 style={{ ...baseLabelStyles, fontSize: 45 }}180 />181 )}182 </VictoryAnimation>183 <VictoryLabel184 text={label}185 lineHeight={1}186 x={CHART_WIDTH / 2}187 y={BOUNDS.Y - LABEL_SIZE}188 textAnchor="middle"189 style={{ ...baseLabelStyles, fontSize: LABEL_SIZE }}190 />191 </svg>192 );193 }}194 </NrqlQuery>195 )}196 </AutoSizer>197 );198 }199}200
201const EmptyState = () => (202 <Card className="EmptyState">203 <CardBody className="EmptyState-cardBody">204 <HeadingText205 spacingType={[HeadingText.SPACING_TYPE.LARGE]}206 type={HeadingText.TYPE.HEADING_3}207 >208 Please provide a NRQL query & account ID pair209 </HeadingText>210 <HeadingText211 spacingType={[HeadingText.SPACING_TYPE.MEDIUM]}212 type={HeadingText.TYPE.HEADING_4}213 >214 This Visualization supports NRQL queries with a single SELECT clause215 returning a percentage value (0 to 100 rather than 0 to 1). For example:216 </HeadingText>217 <code>218 {'FROM Transaction SELECT percentage(count(*), WHERE duration < 0.1)'}219 </code>220 </CardBody>221 </Card>222);
This will revert the bar corners to the default 90-degrees instead of being rounded. While your local server is running, it automatically recognizes changes to index.js. So, view your visualization in your browser to see the update:
Perfect! You cloned and updated the open-source Circular progress bar visualization from the Instant Observability catalog. The only thing left to do is publish your version to the catalog so your accounts can subscribe to it.
Now that you're ready to publish your Nerdpack, stop your local server with CTRL+C
.
Add a custom visualization to a dashboard
Publish your version of the Victory charts Nerdpack to the catalog. Then subscribe to it and use your visualization in a dashboard.
Tip
Because you used nr1 clone
to clone the Nerdpack's repository, your local copy already has its own UUID. This is a prerequisite for publishing your version to the Instant Observability catalog. If you used git clone
to copy, you need to update the Nerdpack's UUID manually:
$nr1 nerdpack:uuid -gfThe new generated id is ab123c45-678d-9012-efg3-45hi6jkl7890
From its root directory, publish your Nerdpack:
$nr1 nerdpack:publish
Subscribe to your Nerdpack:
$nr1 nerdpack:subscribe
Here, you subscribed to your Nerdpack with the CLI. This is effectively the same action you performed earlier in this guide within the web UI, but from your terminal.
Go to the Apps view in New Relic:
From Apps, open Custom visualizations:
From here, click the Circular progress bar visualization. Update your visualization's configuration options like you did when you were serving your Nerdpack locally.
Click Add to dashboard:
Go to your dashboard and see your new, customized circular progress bar:
Summary
In this guide, you:
- Subscribed to a Nerdpack from the Instant Observability catalog
- Cloned an open-source Nerdpack
- Edited an existing visualization to meet your needs
- Published and subscribed to your own custom Nerdpack
- Added a visualization from your custom Nerdpack to a dashboard
Now you know how to build off the foundation of open-source Nerdpacks, you can use the work of the New Relic developer community to fast-track the creation of apps and visualizations.
Tip
If you want to maintain your own version in a remote repository, consider forking the original repo.