Better example data
This commit is contained in:
@@ -36,6 +36,7 @@
|
||||
"@roadiehq/backstage-plugin-github-pull-requests": "0.3.0",
|
||||
"@roadiehq/backstage-plugin-travis-ci": "^0.2.3",
|
||||
"history": "^5.0.0",
|
||||
"moment": "^2.27.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
@@ -43,6 +44,7 @@
|
||||
"react-router": "6.0.0-beta.0",
|
||||
"react-router-dom": "6.0.0-beta.0",
|
||||
"react-use": "^15.3.3",
|
||||
"regression": "^2.0.1",
|
||||
"zen-observable": "^0.8.15"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -54,6 +56,7 @@
|
||||
"@types/jquery": "^3.3.34",
|
||||
"@types/node": "^12.0.0",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/regression": "^2.0.0",
|
||||
"@types/zen-observable": "^0.8.0",
|
||||
"cross-env": "^7.0.0",
|
||||
"cypress": "^4.2.0",
|
||||
|
||||
@@ -15,16 +15,72 @@
|
||||
*/
|
||||
/* eslint-disable no-restricted-imports */
|
||||
|
||||
import moment from 'moment';
|
||||
import regression from 'regression';
|
||||
import {
|
||||
CostInsightsApi,
|
||||
Alert,
|
||||
ChangeStatistic,
|
||||
Cost,
|
||||
CostInsightsApi,
|
||||
DateAggregation,
|
||||
Duration,
|
||||
Project,
|
||||
ProductCost,
|
||||
Group,
|
||||
ProductCost,
|
||||
Project,
|
||||
Trendline,
|
||||
} from '@backstage/plugin-cost-insights';
|
||||
|
||||
function durationOf(intervals: string): Duration {
|
||||
const match = intervals.match(/\/(?<duration>P\d+[DM])\//);
|
||||
const { duration } = match!.groups!;
|
||||
return duration as Duration;
|
||||
}
|
||||
|
||||
function aggregationFor(
|
||||
duration: Duration,
|
||||
baseline: number,
|
||||
): DateAggregation[] {
|
||||
const days = moment.duration(duration).asDays() * 2;
|
||||
|
||||
return [...Array(days).keys()].reduce(
|
||||
(values: DateAggregation[], i: number): DateAggregation[] => {
|
||||
const last = values.length ? values[values.length - 1].amount : baseline;
|
||||
values.push({
|
||||
date: moment()
|
||||
.subtract(days, 'days')
|
||||
.add(i, 'days')
|
||||
.format('YYYY-MM-DD'),
|
||||
amount: last + (baseline / 20) * (Math.random() * 2 - 1),
|
||||
});
|
||||
return values;
|
||||
},
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
function trendlineOf(aggregation: DateAggregation[]): Trendline {
|
||||
const data = [...aggregation.map(a => [Date.parse(a.date) / 1000, a.amount])];
|
||||
const result = regression.linear(data, { precision: 5 });
|
||||
return {
|
||||
slope: result.equation[0],
|
||||
intercept: result.equation[1],
|
||||
};
|
||||
}
|
||||
|
||||
function changeOf(aggregation: DateAggregation[]): ChangeStatistic {
|
||||
const half = Math.ceil(aggregation.length / 2);
|
||||
const before = aggregation
|
||||
.slice(0, half)
|
||||
.reduce((sum, a) => sum + a.amount, 0);
|
||||
const after = aggregation
|
||||
.slice(half, aggregation.length)
|
||||
.reduce((sum, a) => sum + a.amount, 0);
|
||||
return {
|
||||
ratio: (after - before) / before,
|
||||
amount: after - before,
|
||||
};
|
||||
}
|
||||
|
||||
export class ExampleCostInsightsClient implements CostInsightsApi {
|
||||
private request(_: any, res: any): Promise<any> {
|
||||
return new Promise(resolve => setTimeout(resolve, 0, res));
|
||||
@@ -53,30 +109,17 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
|
||||
metric: string | null,
|
||||
intervals: string,
|
||||
): Promise<Cost> {
|
||||
const aggregation = aggregationFor(
|
||||
durationOf(intervals),
|
||||
metric ? 0.3 : 8_000,
|
||||
);
|
||||
const groupDailyCost: Cost = await this.request(
|
||||
{ group, metric, intervals },
|
||||
{
|
||||
id: metric, // costs with null ids will appear as "All Projects" in Cost Overview panel
|
||||
aggregation: [
|
||||
{ date: '2020-08-01', amount: 75_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-02', amount: 120_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-03', amount: 110_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-04', amount: 90_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-05', amount: 80_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-06', amount: 85_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-07', amount: 82_500 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-08', amount: 100_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-09', amount: 130_000 / (metric ? 200_000 : 1) },
|
||||
{ date: '2020-08-10', amount: 140_000 / (metric ? 200_000 : 1) },
|
||||
],
|
||||
change: {
|
||||
ratio: 0.86,
|
||||
amount: 65_000,
|
||||
},
|
||||
trendline: {
|
||||
slope: 0,
|
||||
intercept: 90_000,
|
||||
},
|
||||
aggregation: aggregation,
|
||||
change: changeOf(aggregation),
|
||||
trendline: trendlineOf(aggregation),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -88,30 +131,17 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
|
||||
metric: string | null,
|
||||
intervals: string,
|
||||
): Promise<Cost> {
|
||||
const aggregation = aggregationFor(
|
||||
durationOf(intervals),
|
||||
metric ? 0.1 : 1_500,
|
||||
);
|
||||
const projectDailyCost: Cost = await this.request(
|
||||
{ project, metric, intervals },
|
||||
{
|
||||
id: 'project-a',
|
||||
aggregation: [
|
||||
{ date: '2020-08-01', amount: 1000 },
|
||||
{ date: '2020-08-02', amount: 2000 },
|
||||
{ date: '2020-08-03', amount: 3000 },
|
||||
{ date: '2020-08-04', amount: 4000 },
|
||||
{ date: '2020-08-05', amount: 5000 },
|
||||
{ date: '2020-08-06', amount: 6000 },
|
||||
{ date: '2020-08-07', amount: 7000 },
|
||||
{ date: '2020-08-08', amount: 8000 },
|
||||
{ date: '2020-08-09', amount: 9000 },
|
||||
{ date: '2020-08-10', amount: 10_000 },
|
||||
],
|
||||
change: {
|
||||
ratio: 0.5,
|
||||
amount: 10000,
|
||||
},
|
||||
trendline: {
|
||||
slope: 0,
|
||||
intercept: 0,
|
||||
},
|
||||
aggregation: aggregation,
|
||||
change: changeOf(aggregation),
|
||||
trendline: trendlineOf(aggregation),
|
||||
},
|
||||
);
|
||||
|
||||
@@ -134,7 +164,7 @@ export class ExampleCostInsightsClient implements CostInsightsApi {
|
||||
entities: [
|
||||
{
|
||||
id: null, // entities with null ids will be appear as "Unlabeled" in product panels
|
||||
aggregation: [45_000, 50_000],
|
||||
aggregation: [15_000, 30_000],
|
||||
},
|
||||
{
|
||||
id: 'entity-a',
|
||||
|
||||
@@ -64,7 +64,7 @@ const CostOverviewCard = ({
|
||||
</CostOverviewHeader>
|
||||
<Divider />
|
||||
<Box marginY={1} display="flex" flexDirection="column">
|
||||
<CostOverviewChartLegend change={change} title={name} />
|
||||
<CostOverviewChartLegend change={change} title={`${name} Trend`} />
|
||||
<CostOverviewChart
|
||||
responsive
|
||||
metric={metric}
|
||||
|
||||
@@ -5457,6 +5457,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/regression@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/@types/regression/-/regression-2.0.0.tgz#0677ea78d7bdb37039c02ebbccf062042f756ae3"
|
||||
integrity sha512-Ch2FD53M1HpFLL6zSTc/sfuyqQcIPy+/PV3xFT6QYtk9EOiMI29XOYmLNxBb1Y0lfMOR/NNa86J1gRc/1jGLyw==
|
||||
|
||||
"@types/relateurl@*":
|
||||
version "0.2.28"
|
||||
resolved "https://registry.npmjs.org/@types/relateurl/-/relateurl-0.2.28.tgz#6bda7db8653fa62643f5ee69e9f69c11a392e3a6"
|
||||
@@ -19842,6 +19847,11 @@ regjsparser@^0.6.4:
|
||||
dependencies:
|
||||
jsesc "~0.5.0"
|
||||
|
||||
regression@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://artifactory.spotify.net/artifactory/api/npm/virtual-npm/regression/-/regression-2.0.1.tgz#8d29c3e8224a10850c35e337e85a8b2fac3b0c87"
|
||||
integrity sha1-jSnD6CJKEIUMNeM36FqLL6w7DIc=
|
||||
|
||||
relateurl@^0.2.7:
|
||||
version "0.2.7"
|
||||
resolved "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
|
||||
|
||||
Reference in New Issue
Block a user