Merge remote-tracking branch 'origin/master' into scaffolder-result-content

This commit is contained in:
bnechyporenko
2022-10-20 15:33:02 +02:00
40 changed files with 706 additions and 379 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Updated `@swc/core` to version 1.3.9 which fixes a `.tsx` parser bug
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/create-app': patch
---
Updated `@swc/core` to `v1.3.9` which fixes a `.tsx` parser bug. You may want to run `yarn backstage-cli versions:bump` to get on latest version including the CLI itself.
+9
View File
@@ -0,0 +1,9 @@
---
'@backstage/plugin-bitrise': patch
'@backstage/plugin-code-coverage': patch
'@backstage/plugin-cost-insights': minor
'@backstage/plugin-git-release-manager': patch
'@backstage/plugin-xcmetrics': patch
---
Updated recharts to v2.0.0 and fixed typing issues
+14
View File
@@ -0,0 +1,14 @@
---
'@backstage/plugin-catalog-backend-module-github': minor
---
Added the ability for the GitHub discovery provider to validate that catalog files exist before emitting them.
Users can now set the `validateLocationsExist` property to `true` in their GitHub discovery configuration to opt in to this feature.
This feature only works with `catalogPath`s that do not contain wildcards.
When `validateLocationsExist` is set to `true`, the GitHub discovery provider will retrieve the object from the
repository at the provided `catalogPath`.
If this file exists and is non-empty, then it will be emitted as a location for further processing.
If this file does not exist or is empty, then it will not be emitted.
Not emitting locations that do not exist allows for far fewer calls to the GitHub API to validate locations that do not exist.
+3 -3
View File
@@ -414,8 +414,8 @@ __metadata:
linkType: hard
"cypress@npm:^10.0.0":
version: 10.8.0
resolution: "cypress@npm:10.8.0"
version: 10.10.0
resolution: "cypress@npm:10.10.0"
dependencies:
"@cypress/request": ^2.88.10
"@cypress/xvfb": ^1.2.4
@@ -461,7 +461,7 @@ __metadata:
yauzl: ^2.10.0
bin:
cypress: bin/cypress
checksum: c052690049980e7721e6fca563b724fde839d87d83c1478dfe26ce7d230992717c2c4028e7157bfb39ec274473e51929f49e5aab6a23c2b25cde2a439b1c3cf9
checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2
languageName: node
linkType: hard
+15 -1
View File
@@ -104,6 +104,13 @@ catalog:
topic:
include: ['backstage-include'] # optional array of strings
exclude: ['experiments'] # optional array of strings
validateLocationsExist:
organization: 'backstage' # string
catalogPath: '/catalog-info.yaml' # string
filters:
branch: 'main' # string
repository: '.*' # Regex
validateLocationsExist: true # optional boolean
enterpriseProviderId:
host: ghe.example.net
organization: 'backstage' # string
@@ -118,7 +125,8 @@ This provider supports multiple organizations via unique provider IDs.
- **`catalogPath`** _(optional)_:
Default: `/catalog-info.yaml`.
Path where to look for `catalog-info.yaml` files.
You can use wildcards - `*` or `**` - to search the path and/or the filename
You can use wildcards - `*` or `**` - to search the path and/or the filename.
Wildcards cannot be used if the `validateLocationsExist` option is set to `true`.
- **`filters`** _(optional)_:
- **`branch`** _(optional)_:
String used to filter results based on the branch name.
@@ -139,6 +147,12 @@ This provider supports multiple organizations via unique provider IDs.
- **`organization`**:
Name of your organization account/workspace.
If you want to add multiple organizations, you need to add one provider config each.
- **`validateLocationsExist`** _(optional)_:
Whether to validate locations that exist before emitting them.
This option avoids generating locations for catalog info files that do not exist in the source repository.
Defaults to `false`.
Due to limitations in the GitHub API's ability to query for repository objects, this option cannot be used in
conjunction with wildcards in the `catalogPath`.
- **`schedule`** _(optional)_:
- **`frequency`**:
How often you want the task to run. The system does its best to avoid overlapping invocations.
+1 -1
View File
@@ -52,7 +52,7 @@
"@svgr/plugin-svgo": "6.5.x",
"@svgr/rollup": "6.5.x",
"@svgr/webpack": "6.5.x",
"@swc/core": "^1.2.239",
"@swc/core": "^1.3.9",
"@swc/helpers": "^0.4.7",
"@swc/jest": "^0.2.22",
"@types/jest": "^29.0.0",
+1 -1
View File
@@ -36,7 +36,7 @@
"luxon": "^3.0.0",
"qs": "^6.9.6",
"react-use": "^17.2.4",
"recharts": "^1.8.5"
"recharts": "^2.0.0"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0"
@@ -213,6 +213,7 @@ describe('github', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'demo',
@@ -222,6 +223,11 @@ describe('github', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'acb123',
text: 'some yaml',
},
},
],
pageInfo: {
@@ -243,6 +249,7 @@ describe('github', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'demo',
@@ -252,6 +259,11 @@ describe('github', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'acb123',
text: 'some yaml',
},
},
],
};
@@ -262,9 +274,9 @@ describe('github', () => {
),
);
await expect(getOrganizationRepositories(graphql, 'a')).resolves.toEqual(
output,
);
await expect(
getOrganizationRepositories(graphql, 'a', 'catalog-info.yaml'),
).resolves.toEqual(output);
});
});
});
@@ -65,6 +65,11 @@ export type Repository = {
defaultBranchRef: {
name: string;
} | null;
catalogInfoFile: {
__typename: string;
id: string;
text: string;
} | null;
};
type RepositoryTopics = {
@@ -266,14 +271,30 @@ export async function getOrganizationTeams(
export async function getOrganizationRepositories(
client: typeof graphql,
org: string,
catalogPath: string,
): Promise<{ repositories: Repository[] }> {
let relativeCatalogPathRef: string;
// We must strip the leading slash or the query for objects does not work
if (catalogPath.startsWith('/')) {
relativeCatalogPathRef = catalogPath.substring(1);
} else {
relativeCatalogPathRef = catalogPath;
}
const catalogPathRef = `HEAD:${relativeCatalogPathRef}`;
const query = `
query repositories($org: String!, $cursor: String) {
query repositories($org: String!, $catalogPathRef: String!, $cursor: String) {
repositoryOwner(login: $org) {
login
repositories(first: 100, after: $cursor) {
nodes {
name
catalogInfoFile: object(expression: $catalogPathRef) {
__typename
... on Blob {
id
text
}
}
url
isArchived
repositoryTopics(first: 100) {
@@ -302,7 +323,7 @@ export async function getOrganizationRepositories(
query,
r => r.repositoryOwner?.repositories,
x => x,
{ org },
{ org, catalogPathRef },
);
return { repositories };
@@ -153,6 +153,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'master',
},
catalogInfoFile: null,
},
{
name: 'demo',
@@ -162,6 +163,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
],
});
@@ -203,6 +205,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
],
});
@@ -234,6 +237,7 @@ describe('GithubDiscoveryProcessor', () => {
repositoryTopics: { nodes: [] },
isArchived: false,
defaultBranchRef: null,
catalogInfoFile: null,
},
],
});
@@ -259,6 +263,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'master',
},
catalogInfoFile: null,
},
],
});
@@ -293,6 +298,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'techdocs-cli',
@@ -302,6 +308,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'techdocs-container',
@@ -311,6 +318,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'techdocs-durp',
@@ -318,6 +326,7 @@ describe('GithubDiscoveryProcessor', () => {
repositoryTopics: { nodes: [] },
isArchived: false,
defaultBranchRef: null,
catalogInfoFile: null,
},
],
});
@@ -360,6 +369,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'test',
@@ -369,6 +379,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'test-archived',
@@ -378,6 +389,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'testxyz',
@@ -387,6 +399,7 @@ describe('GithubDiscoveryProcessor', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
],
});
@@ -121,7 +121,11 @@ export class GithubDiscoveryProcessor implements CatalogProcessor {
const startTimestamp = Date.now();
this.logger.info(`Reading GitHub repositories from ${location.target}`);
const { repositories } = await getOrganizationRepositories(client, org);
const { repositories } = await getOrganizationRepositories(
client,
org,
catalogPath,
);
const matching = repositories.filter(
r => !r.isArchived && repoSearchPath.test(r.name),
);
@@ -174,6 +174,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
],
}),
@@ -271,6 +276,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
],
}),
@@ -345,6 +355,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
],
}),
@@ -386,6 +401,110 @@ describe('GithubEntityProvider', () => {
});
});
it('should filter out invalid locations when validateLocationsExist is set to true', async () => {
const config = new ConfigReader({
catalog: {
providers: {
github: {
myProvider: {
organization: 'test-org',
catalogPath: 'catalog-custom.yaml',
filters: {
branch: 'main',
},
validateLocationsExist: true,
},
},
},
},
});
const schedule = new PersistingTaskRunner();
const entityProviderConnection: EntityProviderConnection = {
applyMutation: jest.fn(),
refresh: jest.fn(),
};
const provider = GithubEntityProvider.fromConfig(config, {
logger,
schedule,
})[0];
const mockGetOrganizationRepositories = jest.spyOn(
helpers,
'getOrganizationRepositories',
);
mockGetOrganizationRepositories.mockReturnValue(
Promise.resolve({
repositories: [
{
name: 'test-repo',
url: 'https://github.com/test-org/test-repo',
repositoryTopics: {
nodes: [],
},
isArchived: false,
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: null,
},
{
name: 'another-repo',
url: 'https://github.com/test-org/another-repo',
repositoryTopics: {
nodes: [],
},
isArchived: false,
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
],
}),
);
await provider.connect(entityProviderConnection);
const taskDef = schedule.getTasks()[0];
expect(taskDef.id).toEqual('github-provider:myProvider:refresh');
await (taskDef.fn as () => Promise<void>)();
const url = `https://github.com/test-org/another-repo/blob/main/catalog-custom.yaml`;
const expectedEntities = [
{
entity: {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Location',
metadata: {
annotations: {
'backstage.io/managed-by-location': `url:${url}`,
'backstage.io/managed-by-origin-location': `url:${url}`,
},
name: 'generated-934f500db2ba2e8ea3524567926f45a73bb0b532',
},
spec: {
presence: 'optional',
target: `${url}`,
type: 'url',
},
},
locationKey: 'github-provider:myProvider',
},
];
expect(entityProviderConnection.applyMutation).toHaveBeenCalledTimes(1);
expect(entityProviderConnection.applyMutation).toHaveBeenCalledWith({
type: 'full',
entities: expectedEntities,
});
});
it('apply full update on scheduled execution with topic exclusion taking priority over topic inclusion', async () => {
const config = new ConfigReader({
catalog: {
@@ -440,6 +559,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
{
name: 'test-repo-2',
@@ -458,6 +582,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
{
name: 'test-repo-3',
@@ -473,6 +602,11 @@ describe('GithubEntityProvider', () => {
defaultBranchRef: {
name: 'main',
},
catalogInfoFile: {
__typename: 'Blob',
id: 'abc123',
text: 'some yaml',
},
},
],
}),
@@ -178,6 +178,7 @@ export class GithubEntityProvider implements EntityProvider {
private async findCatalogFiles(): Promise<Repository[]> {
const organization = this.config.organization;
const host = this.integration.host;
const catalogPath = this.config.catalogPath;
const orgUrl = `https://${host}/${organization}`;
const { headers } = await this.githubCredentialsProvider.getCredentials({
@@ -192,8 +193,18 @@ export class GithubEntityProvider implements EntityProvider {
const { repositories } = await getOrganizationRepositories(
client,
organization,
catalogPath,
);
if (this.config.validateLocationsExist) {
return repositories.filter(repository => {
return (
repository.catalogInfoFile?.__typename === 'Blob' &&
repository.catalogInfoFile.text !== ''
);
});
}
return repositories;
}
@@ -112,6 +112,7 @@ describe('readProviderConfigs', () => {
},
},
schedule: undefined,
validateLocationsExist: false,
});
expect(providerConfigs[1]).toEqual({
id: 'providerCustomCatalogPath',
@@ -127,6 +128,7 @@ describe('readProviderConfigs', () => {
},
},
schedule: undefined,
validateLocationsExist: false,
});
expect(providerConfigs[2]).toEqual({
id: 'providerWithRepositoryFilter',
@@ -142,6 +144,7 @@ describe('readProviderConfigs', () => {
},
},
schedule: undefined,
validateLocationsExist: false,
});
expect(providerConfigs[3]).toEqual({
id: 'providerWithBranchFilter',
@@ -157,6 +160,7 @@ describe('readProviderConfigs', () => {
},
},
schedule: undefined,
validateLocationsExist: false,
});
expect(providerConfigs[4]).toEqual({
id: 'providerWithTopicFilter',
@@ -172,6 +176,7 @@ describe('readProviderConfigs', () => {
},
},
schedule: undefined,
validateLocationsExist: false,
});
expect(providerConfigs[5]).toEqual({
id: 'providerWithHost',
@@ -186,6 +191,7 @@ describe('readProviderConfigs', () => {
exclude: undefined,
},
},
validateLocationsExist: false,
schedule: undefined,
});
expect(providerConfigs[6]).toEqual({
@@ -207,6 +213,38 @@ describe('readProviderConfigs', () => {
minutes: 3,
},
},
validateLocationsExist: false,
});
});
it('defaults validateLocationsExist to false', () => {
const config = new ConfigReader({
catalog: {
providers: {
github: {
organization: 'test-org',
},
},
},
});
const providerConfigs = readProviderConfigs(config);
expect(providerConfigs[0].validateLocationsExist).toEqual(false);
});
it('throws an error when a wildcard catalog path is configured with validation of locations', () => {
const config = new ConfigReader({
catalog: {
providers: {
github: {
organization: 'test-org',
validateLocationsExist: true,
catalogPath: '/*/catalog-info.yaml',
},
},
},
});
expect(() => readProviderConfigs(config)).toThrow();
});
});
@@ -33,6 +33,7 @@ export type GithubEntityProviderConfig = {
branch?: string;
topic?: GithubTopicFilters;
};
validateLocationsExist: boolean;
schedule?: TaskScheduleDefinition;
};
@@ -77,6 +78,16 @@ function readProviderConfig(
const topicFilterExclude = config?.getOptionalStringArray(
'filters.topic.exclude',
);
const validateLocationsExist =
config?.getOptionalBoolean('validateLocationsExist') ?? false;
const catalogPathContainsWildcard = catalogPath.includes('*');
if (validateLocationsExist && catalogPathContainsWildcard) {
throw Error(
`Error while processing GitHub provider config. The catalog path ${catalogPath} contains a wildcard, which is incompatible with validation of locations existing before emitting them. Ensure that validateLocationsExist is set to false.`,
);
}
const schedule = config.has('schedule')
? readTaskScheduleDefinitionFromConfig(config.getConfig('schedule'))
@@ -98,6 +109,7 @@ function readProviderConfig(
},
},
schedule,
validateLocationsExist,
};
}
+1 -1
View File
@@ -37,7 +37,7 @@
"highlight.js": "^10.6.0",
"luxon": "^3.0.0",
"react-use": "^17.2.4",
"recharts": "^1.8.5"
"recharts": "^2.0.0"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0",
+11 -8
View File
@@ -11,14 +11,12 @@ import { BackstagePlugin } from '@backstage/core-plugin-api';
import { BackstageTheme } from '@backstage/theme';
import { ChangeStatistic as ChangeStatistic_2 } from '@backstage/plugin-cost-insights-common';
import * as common from '@backstage/plugin-cost-insights-common';
import { ContentRenderer } from 'recharts';
import { Dispatch } from 'react';
import { ForwardRefExoticComponent } from 'react';
import { Maybe as Maybe_2 } from '@backstage/plugin-cost-insights-common';
import { PaletteOptions } from '@material-ui/core/styles/createPalette';
import { PropsWithChildren } from 'react';
import { ReactNode } from 'react';
import { RechartsFunction } from 'recharts';
import { RefAttributes } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { SetStateAction } from 'react';
@@ -178,10 +176,10 @@ export type BarChartProps = {
resources: ResourceData[];
responsive?: boolean;
displayAmount?: number;
options?: Partial<BarChartData>;
tooltip?: ContentRenderer<TooltipProps>;
onClick?: RechartsFunction;
onMouseMove?: RechartsFunction;
options?: Partial<BarChartOptions>;
tooltip?: TooltipRenderer;
onClick?: (...args: any[]) => void;
onMouseMove?: (...args: any[]) => void;
};
// @public (undocumented)
@@ -586,10 +584,15 @@ export interface ResourceData {
// @public (undocumented)
export type TooltipItem = {
fill: string;
label: string;
value: string;
label?: string;
value?: string;
};
// @public (undocumented)
export type TooltipRenderer = (
props: TooltipProps<string, string>,
) => ReactNode;
// @public @deprecated (undocumented)
export type Trendline = common.Trendline;
+1 -1
View File
@@ -49,7 +49,7 @@
"pluralize": "^8.0.0",
"qs": "^6.9.4",
"react-use": "^17.2.4",
"recharts": "^1.8.5",
"recharts": "^2.0.0",
"regression": "^2.0.1",
"yup": "^0.32.9"
},
@@ -69,6 +69,23 @@ class CustomProjectGrowthAlert extends ProjectGrowthAlert {
}
describe('ProjectGrowthAlert', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
describe('constructor', () => {
it('should create a project growth alert', async () => {
const alert = new ProjectGrowthAlert(mockData);
@@ -66,6 +66,22 @@ class CustomUnlabeledDataflowAlert extends UnlabeledDataflowAlert {
}
describe('UnlabeledDataflowAlert', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
describe('constructor', () => {
it('should create an unlabeled dataflow alert', async () => {
const alert = new UnlabeledDataflowAlert(mockData);
@@ -55,6 +55,22 @@ const renderWithProps = ({
};
describe('<BarChart />', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('Renders without exploding', async () => {
const rendered = await renderWithProps({} as BarChartProps);
expect(rendered.getByText('test-id-10')).toBeInTheDocument();
@@ -19,11 +19,8 @@ import {
Bar,
BarChart as RechartsBarChart,
CartesianGrid,
ContentRenderer,
TooltipProps as RechartsTooltipProps,
RechartsFunction,
ResponsiveContainer,
Tooltip as RechartsTooltip,
ResponsiveContainer,
XAxis,
YAxis,
} from 'recharts';
@@ -34,20 +31,18 @@ import { BarChartTooltip } from './BarChartTooltip';
import { BarChartTooltipItem } from './BarChartTooltipItem';
import { currencyFormatter } from '../../utils/formatters';
import {
BarChartData,
ResourceData,
DataKey,
CostInsightsTheme,
BarChartOptions,
} from '../../types';
import { notEmpty } from '../../utils/assert';
import { useBarChartStyles } from '../../utils/styles';
import { resourceSort } from '../../utils/sort';
import { isInvalid, titleOf, tooltipItemOf } from '../../utils/graphs';
import { TooltipRenderer } from '../../types/Tooltip';
export const defaultTooltip: ContentRenderer<RechartsTooltipProps> = ({
label,
payload = [],
}) => {
export const defaultTooltip: TooltipRenderer = ({ label, payload = [] }) => {
if (isInvalid({ label, payload })) return null;
const title = titleOf(label);
@@ -66,10 +61,10 @@ export type BarChartProps = {
resources: ResourceData[];
responsive?: boolean;
displayAmount?: number;
options?: Partial<BarChartData>;
tooltip?: ContentRenderer<RechartsTooltipProps>;
onClick?: RechartsFunction;
onMouseMove?: RechartsFunction;
options?: Partial<BarChartOptions>;
tooltip?: TooltipRenderer;
onClick?: (...args: any[]) => void;
onMouseMove?: (...args: any[]) => void;
};
/** @public */
@@ -22,8 +22,8 @@ import { useTooltipStyles as useStyles } from '../../utils/styles';
/** @public */
export type TooltipItem = {
fill: string;
label: string;
value: string;
label?: string;
value?: string;
};
/** @public */
@@ -25,8 +25,6 @@ import {
import { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';
import {
AreaChart,
ContentRenderer,
TooltipProps,
XAxis,
YAxis,
Tooltip as RechartsTooltip,
@@ -52,6 +50,7 @@ import { getPreviousPeriodTotalCost } from '../../utils/change';
import { formatPeriod } from '../../utils/formatters';
import { aggregationSum } from '../../utils/sum';
import { BarChartLegendOptions } from '../BarChart/BarChartLegend';
import { TooltipRenderer } from '../../types/Tooltip';
export type CostOverviewBreakdownChartProps = {
costBreakdown: Cost[];
@@ -168,17 +167,15 @@ export const CostOverviewBreakdownChart = ({
fill={color}
onClick={() => setExpanded(true)}
style={{
cursor: breakdown === 'Other' && !isExpanded ? 'pointer' : null,
cursor:
breakdown === 'Other' && !isExpanded ? 'pointer' : undefined,
}}
/>
);
});
};
const tooltipRenderer: ContentRenderer<TooltipProps> = ({
label,
payload = [],
}) => {
const tooltipRenderer: TooltipRenderer = ({ label, payload = [] }) => {
if (isInvalid({ label, payload })) return null;
const date =
@@ -186,10 +183,10 @@ export const CostOverviewBreakdownChart = ({
? DateTime.fromMillis(label)
: DateTime.fromISO(label!);
const dateTitle = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
const items = payload.map(p => ({
const items = payload.map((p, i) => ({
label: p.dataKey as string,
value: formatGraphValue(p.value as number),
fill: p.fill!,
value: formatGraphValue(Number(p.value), i),
fill: p.color!,
}));
const expandText = (
<Box>
@@ -53,6 +53,22 @@ function renderInContext(children: JSX.Element) {
}
describe('<CostOverviewCard/>', () => {
beforeEach(() => {
// @ts-expect-error: Since we have strictNullChecks enabled, this will throw an error as window.ResizeObserver
// it's not an optional operand
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('Renders without exploding', async () => {
const { getByText } = await renderInContext(
<CostOverviewCard dailyCostData={mockGroupDailyCost} metricData={null} />,
@@ -18,8 +18,6 @@ import { DateTime } from 'luxon';
import { useTheme, Box } from '@material-ui/core';
import {
ComposedChart,
ContentRenderer,
TooltipProps,
XAxis,
YAxis,
Tooltip as RechartsTooltip,
@@ -50,6 +48,7 @@ import { useCostOverviewStyles as useStyles } from '../../utils/styles';
import { groupByDate, toDataMax, trendFrom } from '../../utils/charts';
import { aggregationSort } from '../../utils/sort';
import { CostOverviewLegend } from './CostOverviewLegend';
import { TooltipRenderer } from '../../types/Tooltip';
type CostOverviewChartProps = {
metric: Maybe<Metric>;
@@ -98,10 +97,7 @@ export const CostOverviewChart = ({
: {}),
}));
const tooltipRenderer: ContentRenderer<TooltipProps> = ({
label,
payload = [],
}) => {
const tooltipRenderer: TooltipRenderer = ({ label, payload = [] }) => {
if (isInvalid({ label, payload })) return null;
const dataKeys = [data.dailyCost.dataKey, data.metric.dataKey];
@@ -112,15 +108,15 @@ export const CostOverviewChart = ({
const title = date.toUTC().toFormat(DEFAULT_DATE_FORMAT);
const items = payload
.filter(p => dataKeys.includes(p.dataKey as string))
.map(p => ({
.map((p, i) => ({
label:
p.dataKey === data.dailyCost.dataKey
? data.dailyCost.name
: data.metric.name,
value:
p.dataKey === data.dailyCost.dataKey
? formatGraphValue(p.value as number, data.dailyCost.format)
: formatGraphValue(p.value as number, data.metric.format),
? formatGraphValue(Number(p.value), i, data.dailyCost.format)
: formatGraphValue(Number(p.value), i, data.metric.format),
fill:
p.dataKey === data.dailyCost.dataKey
? theme.palette.blue
@@ -186,7 +182,6 @@ export const CostOverviewChart = ({
dataKey="trend"
dot={false}
isAnimationActive={false}
label={false}
strokeWidth={2}
stroke={theme.palette.blue}
yAxisId={data.dailyCost.dataKey}
@@ -196,7 +191,6 @@ export const CostOverviewChart = ({
dataKey={data.metric.dataKey}
dot={false}
isAnimationActive={false}
label={false}
strokeWidth={2}
stroke={theme.palette.magenta}
yAxisId={data.metric.dataKey}
@@ -74,6 +74,22 @@ const renderProductInsightsCardInTestApp = async (
);
describe('<ProductInsightsCard/>', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('Should render the right subheader for products with cost data', async () => {
const entity = {
...mockProductCost,
@@ -15,11 +15,6 @@
*/
import React, { useMemo, useState } from 'react';
import {
ContentRenderer,
TooltipProps as RechartsTooltipProps,
RechartsFunction,
} from 'recharts';
import pluralize from 'pluralize';
import { Box, Typography } from '@material-ui/core';
import { default as FullScreenIcon } from '@material-ui/icons/Fullscreen';
@@ -55,6 +50,7 @@ import {
} from '../../utils/styles';
import { Duration, Entity, Maybe } from '../../types';
import { choose } from '../../utils/change';
import { TooltipRenderer } from '../../types/Tooltip';
export type ProductInsightsChartProps = {
billingDate: string;
@@ -96,7 +92,7 @@ export const ProductInsightsChart = ({
currentName: formatPeriod(duration, billingDate, true),
};
const onMouseMove: RechartsFunction = (
const onMouseMove: (...args: any[]) => void = (
data: Record<'activeLabel', string | undefined>,
) => {
if (isLabeled(data)) {
@@ -108,7 +104,9 @@ export const ProductInsightsChart = ({
}
};
const onClick: RechartsFunction = (data: Record<'activeLabel', string>) => {
const onClick: (...args: any[]) => void = (
data: Record<'activeLabel', string>,
) => {
if (isLabeled(data)) {
setSelected(data.activeLabel);
} else if (isUnlabeled(data)) {
@@ -118,7 +116,7 @@ export const ProductInsightsChart = ({
}
};
const renderProductInsightsTooltip: ContentRenderer<RechartsTooltipProps> = ({
const renderProductInsightsTooltip: TooltipRenderer = ({
label,
payload = [],
}) => {
@@ -45,6 +45,22 @@ const MockProjectGrowthAlert = createMockProjectGrowthData(data => ({
}));
describe('<ProjectGrowthAlertCard />', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('renders the correct title and subheader for multiple services', async () => {
const subheader = new RegExp(
`${MockAlertCosts.length} products, sorted by cost`,
@@ -40,6 +40,21 @@ const MockUnlabeledDataflowAlertSingleProject = createMockUnlabeledDataflowData(
);
describe('<UnlabeledDataflowAlertCard />', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('renders the correct subheader for multiple projects', async () => {
const subheader = new RegExp(
`Showing costs from ${MockUnlabeledDataflowAlertMultipleProjects.projects.length} ` +
@@ -0,0 +1,23 @@
/*
* Copyright 2020 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { ReactNode } from 'react';
import { TooltipProps } from 'recharts';
/** @public */
export type TooltipRenderer = (
props: TooltipProps<string, string>,
) => ReactNode;
+1
View File
@@ -27,6 +27,7 @@ export * from './Filters';
export * from './Icon';
export * from './Loading';
export * from './Theme';
export * from './Tooltip';
/**
* Deprecated types moved to `@backstage/plugin-cost-insights-common`
+11 -6
View File
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import { TooltipPayload, TooltipProps } from 'recharts';
import { TooltipProps } from 'recharts';
import { Payload } from 'recharts/types/component/DefaultTooltipContent';
import { AlertCost, DataKey, Entity, ResourceData } from '../types';
import {
currencyFormatter,
@@ -22,7 +23,11 @@ import {
lengthyCurrencyFormatter,
} from './formatters';
export function formatGraphValue(value: number, format?: string) {
export function formatGraphValue(
value: number,
_index: number,
format?: string,
) {
if (format === 'number') {
return value.toLocaleString();
}
@@ -37,12 +42,12 @@ export function formatGraphValue(value: number, format?: string) {
export const overviewGraphTickFormatter = (millis: string | number) =>
typeof millis === 'number' ? dateFormatter.format(millis) : millis;
export const tooltipItemOf = (payload: TooltipPayload) => {
export const tooltipItemOf = (payload: Payload<string, string>) => {
const value =
typeof payload.value === 'number'
? currencyFormatter.format(payload.value)
: (payload.value as string);
const fill = payload.fill as string;
: payload.value;
const fill = payload.color as string;
switch (payload.dataKey) {
case DataKey.Current:
@@ -67,7 +72,7 @@ export const titleOf = (label?: string | number) => {
return label ? String(label) : 'Unlabeled';
};
export const isInvalid = ({ label, payload }: TooltipProps) => {
export const isInvalid = ({ label, payload }: TooltipProps<string, string>) => {
// null labels are empty strings, which are valid
return label === undefined || !payload || !payload.length;
};
+1 -1
View File
@@ -34,7 +34,7 @@
"luxon": "^3.0.0",
"qs": "^6.10.1",
"react-use": "^17.2.4",
"recharts": "^1.8.5"
"recharts": "^2.0.0"
},
"peerDependencies": {
"@types/react": "^16.13.1 || ^17.0.0",
+1 -1
View File
@@ -33,7 +33,7 @@
"lodash": "^4.17.21",
"luxon": "^3.0.0",
"react-use": "^17.2.4",
"recharts": "^1.8.5"
"recharts": "^2.0.0"
},
"peerDependencies": {
"react": "^16.13.1 || ^17.0.0"
@@ -20,14 +20,45 @@ import { BuildTimeline } from './BuildTimeline';
jest.mock('../../api/XcmetricsClient');
const client = require('../../api/XcmetricsClient');
jest.mock('recharts', () => {
const OriginalModule = jest.requireActual('recharts');
return {
...OriginalModule,
ResponsiveContainer: ({ children }: any) => (
<OriginalModule.ResponsiveContainer width={100} aspect={1}>
{children}
</OriginalModule.ResponsiveContainer>
),
};
});
describe('BuildTimeline', () => {
const { ResizeObserver } = window;
beforeEach(() => {
// @ts-expect-error
delete window.ResizeObserver;
window.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}));
});
afterEach(() => {
window.ResizeObserver = ResizeObserver;
jest.restoreAllMocks();
});
it('should render', async () => {
const rendered = await renderInTestApp(
<BuildTimeline targets={[client.mockTarget]} height={100} width={100} />,
);
expect(
await rendered.findByText(client.mockTarget.name),
).toBeInTheDocument();
const [element] = await rendered.findAllByText(client.mockTarget.name);
expect(element).toBeInTheDocument();
});
it('should render a message if no targets are provided', async () => {
+1 -1
View File
@@ -8,7 +8,7 @@
"build-storybook": "build-storybook --output-dir dist"
},
"dependencies": {
"@swc/core": "^1.2.239",
"@swc/core": "^1.3.9",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-hot-loader": "^4.13.0",
+57 -57
View File
@@ -2977,126 +2977,126 @@ __metadata:
languageName: node
linkType: hard
"@swc/core-android-arm-eabi@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-android-arm-eabi@npm:1.3.5"
"@swc/core-android-arm-eabi@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-android-arm-eabi@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.122
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"@swc/core-android-arm64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-android-arm64@npm:1.3.5"
"@swc/core-android-arm64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-android-arm64@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"@swc/core-darwin-arm64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-darwin-arm64@npm:1.3.5"
"@swc/core-darwin-arm64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-darwin-arm64@npm:1.3.9"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@swc/core-darwin-x64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-darwin-x64@npm:1.3.5"
"@swc/core-darwin-x64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-darwin-x64@npm:1.3.9"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@swc/core-freebsd-x64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-freebsd-x64@npm:1.3.5"
"@swc/core-freebsd-x64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-freebsd-x64@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
"@swc/core-linux-arm-gnueabihf@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.5"
"@swc/core-linux-arm-gnueabihf@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@swc/core-linux-arm64-gnu@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.5"
"@swc/core-linux-arm64-gnu@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-arm64-musl@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm64-musl@npm:1.3.5"
"@swc/core-linux-arm64-musl@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm64-musl@npm:1.3.9"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@swc/core-linux-x64-gnu@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-x64-gnu@npm:1.3.5"
"@swc/core-linux-x64-gnu@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-x64-gnu@npm:1.3.9"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-x64-musl@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-x64-musl@npm:1.3.5"
"@swc/core-linux-x64-musl@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-x64-musl@npm:1.3.9"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@swc/core-win32-arm64-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.5"
"@swc/core-win32-arm64-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@swc/core-win32-ia32-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.5"
"@swc/core-win32-ia32-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@swc/core-win32-x64-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-x64-msvc@npm:1.3.5"
"@swc/core-win32-x64-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-x64-msvc@npm:1.3.9"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@swc/core@npm:^1.2.239":
version: 1.3.5
resolution: "@swc/core@npm:1.3.5"
"@swc/core@npm:^1.3.9":
version: 1.3.9
resolution: "@swc/core@npm:1.3.9"
dependencies:
"@swc/core-android-arm-eabi": 1.3.5
"@swc/core-android-arm64": 1.3.5
"@swc/core-darwin-arm64": 1.3.5
"@swc/core-darwin-x64": 1.3.5
"@swc/core-freebsd-x64": 1.3.5
"@swc/core-linux-arm-gnueabihf": 1.3.5
"@swc/core-linux-arm64-gnu": 1.3.5
"@swc/core-linux-arm64-musl": 1.3.5
"@swc/core-linux-x64-gnu": 1.3.5
"@swc/core-linux-x64-musl": 1.3.5
"@swc/core-win32-arm64-msvc": 1.3.5
"@swc/core-win32-ia32-msvc": 1.3.5
"@swc/core-win32-x64-msvc": 1.3.5
"@swc/core-android-arm-eabi": 1.3.9
"@swc/core-android-arm64": 1.3.9
"@swc/core-darwin-arm64": 1.3.9
"@swc/core-darwin-x64": 1.3.9
"@swc/core-freebsd-x64": 1.3.9
"@swc/core-linux-arm-gnueabihf": 1.3.9
"@swc/core-linux-arm64-gnu": 1.3.9
"@swc/core-linux-arm64-musl": 1.3.9
"@swc/core-linux-x64-gnu": 1.3.9
"@swc/core-linux-x64-musl": 1.3.9
"@swc/core-win32-arm64-msvc": 1.3.9
"@swc/core-win32-ia32-msvc": 1.3.9
"@swc/core-win32-x64-msvc": 1.3.9
dependenciesMeta:
"@swc/core-android-arm-eabi":
optional: true
@@ -3126,7 +3126,7 @@ __metadata:
optional: true
bin:
swcx: run_swcx.js
checksum: f0bcd0aa1d1a0b7d48ee5c416f8a384e19e4c0eed1e0be940d8893bf3981d98bf00f27d03bebf9cdedd34bf316d68c2db68e7bb7d1940d7b6062541e6e4cc738
checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa
languageName: node
linkType: hard
@@ -10734,7 +10734,7 @@ __metadata:
"@storybook/node-logger": ^6.5.9
"@storybook/react": ^6.5.9
"@storybook/testing-library": ^0.0.13
"@swc/core": ^1.2.239
"@swc/core": ^1.3.9
react: ^17.0.2
react-dom: ^17.0.2
react-hot-loader: ^4.13.0
+120 -244
View File
@@ -3361,7 +3361,7 @@ __metadata:
"@svgr/plugin-svgo": 6.5.x
"@svgr/rollup": 6.5.x
"@svgr/webpack": 6.5.x
"@swc/core": ^1.2.239
"@swc/core": ^1.3.9
"@swc/helpers": ^0.4.7
"@swc/jest": ^0.2.22
"@types/diff": ^5.0.0
@@ -4445,7 +4445,7 @@ __metadata:
msw: ^0.47.0
qs: ^6.9.6
react-use: ^17.2.4
recharts: ^1.8.5
recharts: ^2.0.0
peerDependencies:
react: ^16.13.1 || ^17.0.0
languageName: unknown
@@ -5182,7 +5182,7 @@ __metadata:
luxon: ^3.0.0
msw: ^0.47.0
react-use: ^17.2.4
recharts: ^1.8.5
recharts: ^2.0.0
peerDependencies:
react: ^16.13.1 || ^17.0.0
react-router: 6.0.0-beta.0 || ^6.3.0
@@ -5294,7 +5294,7 @@ __metadata:
pluralize: ^8.0.0
qs: ^6.9.4
react-use: ^17.2.4
recharts: ^1.8.5
recharts: ^2.0.0
regression: ^2.0.1
yup: ^0.32.9
peerDependencies:
@@ -5532,7 +5532,7 @@ __metadata:
msw: ^0.47.0
qs: ^6.10.1
react-use: ^17.2.4
recharts: ^1.8.5
recharts: ^2.0.0
peerDependencies:
"@types/react": ^16.13.1 || ^17.0.0
react: ^16.13.1 || ^17.0.0
@@ -7626,7 +7626,7 @@ __metadata:
luxon: ^3.0.0
msw: ^0.47.0
react-use: ^17.2.4
recharts: ^1.8.5
recharts: ^2.0.0
peerDependencies:
react: ^16.13.1 || ^17.0.0
languageName: unknown
@@ -12507,126 +12507,126 @@ __metadata:
languageName: node
linkType: hard
"@swc/core-android-arm-eabi@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-android-arm-eabi@npm:1.3.5"
"@swc/core-android-arm-eabi@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-android-arm-eabi@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.122
conditions: os=android & cpu=arm
languageName: node
linkType: hard
"@swc/core-android-arm64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-android-arm64@npm:1.3.5"
"@swc/core-android-arm64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-android-arm64@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=android & cpu=arm64
languageName: node
linkType: hard
"@swc/core-darwin-arm64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-darwin-arm64@npm:1.3.5"
"@swc/core-darwin-arm64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-darwin-arm64@npm:1.3.9"
conditions: os=darwin & cpu=arm64
languageName: node
linkType: hard
"@swc/core-darwin-x64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-darwin-x64@npm:1.3.5"
"@swc/core-darwin-x64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-darwin-x64@npm:1.3.9"
conditions: os=darwin & cpu=x64
languageName: node
linkType: hard
"@swc/core-freebsd-x64@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-freebsd-x64@npm:1.3.5"
"@swc/core-freebsd-x64@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-freebsd-x64@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=freebsd & cpu=x64
languageName: node
linkType: hard
"@swc/core-linux-arm-gnueabihf@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.5"
"@swc/core-linux-arm-gnueabihf@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm-gnueabihf@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=linux & cpu=arm
languageName: node
linkType: hard
"@swc/core-linux-arm64-gnu@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.5"
"@swc/core-linux-arm64-gnu@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm64-gnu@npm:1.3.9"
conditions: os=linux & cpu=arm64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-arm64-musl@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-arm64-musl@npm:1.3.5"
"@swc/core-linux-arm64-musl@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-arm64-musl@npm:1.3.9"
conditions: os=linux & cpu=arm64 & libc=musl
languageName: node
linkType: hard
"@swc/core-linux-x64-gnu@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-x64-gnu@npm:1.3.5"
"@swc/core-linux-x64-gnu@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-x64-gnu@npm:1.3.9"
conditions: os=linux & cpu=x64 & libc=glibc
languageName: node
linkType: hard
"@swc/core-linux-x64-musl@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-linux-x64-musl@npm:1.3.5"
"@swc/core-linux-x64-musl@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-linux-x64-musl@npm:1.3.9"
conditions: os=linux & cpu=x64 & libc=musl
languageName: node
linkType: hard
"@swc/core-win32-arm64-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.5"
"@swc/core-win32-arm64-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-arm64-msvc@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=win32 & cpu=arm64
languageName: node
linkType: hard
"@swc/core-win32-ia32-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.5"
"@swc/core-win32-ia32-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-ia32-msvc@npm:1.3.9"
dependencies:
"@swc/wasm": 1.2.130
conditions: os=win32 & cpu=ia32
languageName: node
linkType: hard
"@swc/core-win32-x64-msvc@npm:1.3.5":
version: 1.3.5
resolution: "@swc/core-win32-x64-msvc@npm:1.3.5"
"@swc/core-win32-x64-msvc@npm:1.3.9":
version: 1.3.9
resolution: "@swc/core-win32-x64-msvc@npm:1.3.9"
conditions: os=win32 & cpu=x64
languageName: node
linkType: hard
"@swc/core@npm:^1.2.239":
version: 1.3.5
resolution: "@swc/core@npm:1.3.5"
"@swc/core@npm:^1.3.9":
version: 1.3.9
resolution: "@swc/core@npm:1.3.9"
dependencies:
"@swc/core-android-arm-eabi": 1.3.5
"@swc/core-android-arm64": 1.3.5
"@swc/core-darwin-arm64": 1.3.5
"@swc/core-darwin-x64": 1.3.5
"@swc/core-freebsd-x64": 1.3.5
"@swc/core-linux-arm-gnueabihf": 1.3.5
"@swc/core-linux-arm64-gnu": 1.3.5
"@swc/core-linux-arm64-musl": 1.3.5
"@swc/core-linux-x64-gnu": 1.3.5
"@swc/core-linux-x64-musl": 1.3.5
"@swc/core-win32-arm64-msvc": 1.3.5
"@swc/core-win32-ia32-msvc": 1.3.5
"@swc/core-win32-x64-msvc": 1.3.5
"@swc/core-android-arm-eabi": 1.3.9
"@swc/core-android-arm64": 1.3.9
"@swc/core-darwin-arm64": 1.3.9
"@swc/core-darwin-x64": 1.3.9
"@swc/core-freebsd-x64": 1.3.9
"@swc/core-linux-arm-gnueabihf": 1.3.9
"@swc/core-linux-arm64-gnu": 1.3.9
"@swc/core-linux-arm64-musl": 1.3.9
"@swc/core-linux-x64-gnu": 1.3.9
"@swc/core-linux-x64-musl": 1.3.9
"@swc/core-win32-arm64-msvc": 1.3.9
"@swc/core-win32-ia32-msvc": 1.3.9
"@swc/core-win32-x64-msvc": 1.3.9
dependenciesMeta:
"@swc/core-android-arm-eabi":
optional: true
@@ -12656,7 +12656,7 @@ __metadata:
optional: true
bin:
swcx: run_swcx.js
checksum: f0bcd0aa1d1a0b7d48ee5c416f8a384e19e4c0eed1e0be940d8893bf3981d98bf00f27d03bebf9cdedd34bf316d68c2db68e7bb7d1940d7b6062541e6e4cc738
checksum: 761918f1bca5d494eaaafd49720717e3b3071df5bc6ef8b298a778ba4e4d20bc5a78c939a0b1c98623f9fe23e535a16a359179b72390cd1f5cbc891ea53c22fa
languageName: node
linkType: hard
@@ -16747,13 +16747,6 @@ __metadata:
languageName: node
linkType: hard
"balanced-match@npm:^0.4.2":
version: 0.4.2
resolution: "balanced-match@npm:0.4.2"
checksum: 205ebb42ce8529fa8e043a808b41bfb9818d5f98a8eb76a1cd5483f8a98dd0baefc8a9d940f36b591b1316a04f56b35c32b60ac9b1f848e41e4698672cec6c1e
languageName: node
linkType: hard
"balanced-match@npm:^1.0.0":
version: 1.0.2
resolution: "balanced-match@npm:1.0.2"
@@ -18805,7 +18798,7 @@ __metadata:
languageName: node
linkType: hard
"core-js@npm:^2.4.0, core-js@npm:^2.5.0, core-js@npm:^2.6.10":
"core-js@npm:^2.4.0, core-js@npm:^2.5.0":
version: 2.6.12
resolution: "core-js@npm:2.6.12"
checksum: 44fa9934a85f8c78d61e0c8b7b22436330471ffe59ec5076fe7f324d6e8cf7f824b14b1c81ca73608b13bdb0fef035bd820989bf059767ad6fa13123bb8bd016
@@ -19399,8 +19392,8 @@ __metadata:
linkType: hard
"cypress@npm:^10.0.0":
version: 10.8.0
resolution: "cypress@npm:10.8.0"
version: 10.10.0
resolution: "cypress@npm:10.10.0"
dependencies:
"@cypress/request": ^2.88.10
"@cypress/xvfb": ^1.2.4
@@ -19446,7 +19439,7 @@ __metadata:
yauzl: ^2.10.0
bin:
cypress: bin/cypress
checksum: c052690049980e7721e6fca563b724fde839d87d83c1478dfe26ce7d230992717c2c4028e7157bfb39ec274473e51929f49e5aab6a23c2b25cde2a439b1c3cf9
checksum: 668a32534a527dba79754abbf98af176b80c539a12ec00058932ba2a19c794c7888323e59e738c30f726ad740c5451c31d02548a0cb7c1b1c8ad01c55a984ca2
languageName: node
linkType: hard
@@ -19459,27 +19452,6 @@ __metadata:
languageName: node
linkType: hard
"d3-array@npm:^1.2.0":
version: 1.2.4
resolution: "d3-array@npm:1.2.4"
checksum: d0be1fa7d72dbfac8a3bcffbb669d42bcb9128d8818d84d2b1df0c60bbe4c8e54a798be0457c55a219b399e2c2fabcbd581cbb130eb638b5436b0618d7e56000
languageName: node
linkType: hard
"d3-collection@npm:1":
version: 1.0.7
resolution: "d3-collection@npm:1.0.7"
checksum: 9c6b910a9da0efb021e294509f98263ca4f62d10b997bb30ccfb6edd582b703da36e176b968b5bac815fbb0f328e49643c38cf93b5edf8572a179ba55cf4a09d
languageName: node
linkType: hard
"d3-color@npm:1":
version: 1.4.1
resolution: "d3-color@npm:1.4.1"
checksum: a214b61458b5fcb7ad1a84faed0e02918037bab6be37f2d437bf0e2915cbd854d89fbf93754f17b0781c89e39d46704633d05a2bfae77e6209f0f4b140f9894b
languageName: node
linkType: hard
"d3-color@npm:1 - 2":
version: 2.0.0
resolution: "d3-color@npm:2.0.0"
@@ -19529,13 +19501,6 @@ __metadata:
languageName: node
linkType: hard
"d3-format@npm:1":
version: 1.4.5
resolution: "d3-format@npm:1.4.5"
checksum: 1b8b2c0bca182173bccd290a43e8b635a83fc8cfe52ec878c7bdabb997d47daac11f2b175cebbe73f807f782ad655f542bdfe18180ca5eb3498a3a82da1e06ab
languageName: node
linkType: hard
"d3-format@npm:1 - 2":
version: 2.0.0
resolution: "d3-format@npm:2.0.0"
@@ -19552,15 +19517,6 @@ __metadata:
languageName: node
linkType: hard
"d3-interpolate@npm:1, d3-interpolate@npm:^1.3.0":
version: 1.4.0
resolution: "d3-interpolate@npm:1.4.0"
dependencies:
d3-color: 1
checksum: d98988bd1e2f59d01f100d0a19315ad8f82ef022aa09a65aff76f747a44f9b52f2d64c6578b8f47e01f2b14a8f0ef88f5460d11173c0dd2d58238c217ac0ec03
languageName: node
linkType: hard
"d3-interpolate@npm:1.2.0 - 2, d3-interpolate@npm:^2.0.0":
version: 2.0.1
resolution: "d3-interpolate@npm:2.0.1"
@@ -19570,13 +19526,6 @@ __metadata:
languageName: node
linkType: hard
"d3-path@npm:1":
version: 1.0.9
resolution: "d3-path@npm:1.0.9"
checksum: d4382573baf9509a143f40944baeff9fead136926aed6872f7ead5b3555d68925f8a37935841dd51f1d70b65a294fe35c065b0906fb6e42109295f6598fc16d0
languageName: node
linkType: hard
"d3-path@npm:1 - 2":
version: 2.0.0
resolution: "d3-path@npm:2.0.0"
@@ -19598,20 +19547,6 @@ __metadata:
languageName: node
linkType: hard
"d3-scale@npm:^2.1.0":
version: 2.2.2
resolution: "d3-scale@npm:2.2.2"
dependencies:
d3-array: ^1.2.0
d3-collection: 1
d3-format: 1
d3-interpolate: 1
d3-time: 1
d3-time-format: 2
checksum: 42086d4b9db9f8492a99dbbdacf546983faef1bb6260fe875c0c1884f1ca9cf5fd233de3702c2f9e24145b1c5383945e929c8682d80fa57ab515ef2c4f2c61f6
languageName: node
linkType: hard
"d3-scale@npm:^3.0.0":
version: 3.3.0
resolution: "d3-scale@npm:3.3.0"
@@ -19632,15 +19567,6 @@ __metadata:
languageName: node
linkType: hard
"d3-shape@npm:^1.2.0":
version: 1.3.7
resolution: "d3-shape@npm:1.3.7"
dependencies:
d3-path: 1
checksum: 46566a3ab64a25023653bf59d64e81e9e6c987e95be985d81c5cedabae5838bd55f4a201a6b69069ca862eb63594cd263cac9034afc2b0e5664dfe286c866129
languageName: node
linkType: hard
"d3-shape@npm:^2.0.0":
version: 2.1.0
resolution: "d3-shape@npm:2.1.0"
@@ -19659,15 +19585,6 @@ __metadata:
languageName: node
linkType: hard
"d3-time-format@npm:2":
version: 2.3.0
resolution: "d3-time-format@npm:2.3.0"
dependencies:
d3-time: 1
checksum: 5445eaaf2b3b2095cdc1fa75dfd2f361a61c39b677dcc1c2ba4cb6bc0442953de0fbaaa397d7d7a9325ad99c63d869f162a713e150e826ff8af482615664cb3f
languageName: node
linkType: hard
"d3-time-format@npm:2 - 3":
version: 3.0.0
resolution: "d3-time-format@npm:3.0.0"
@@ -19677,13 +19594,6 @@ __metadata:
languageName: node
linkType: hard
"d3-time@npm:1":
version: 1.1.0
resolution: "d3-time@npm:1.1.0"
checksum: 33fcfff94ff093dde2048c190ecca8b39fe0ec8b3c61e9fc39c5f6072ce5b86dd2b91823f086366995422bbbac7f74fd9abdb7efe4f292a73b1c6197c699cc78
languageName: node
linkType: hard
"d3-time@npm:1 - 2, d3-time@npm:^2.1.1":
version: 2.1.1
resolution: "d3-time@npm:2.1.1"
@@ -28334,13 +28244,6 @@ __metadata:
languageName: node
linkType: hard
"lodash.throttle@npm:^4.1.1":
version: 4.1.1
resolution: "lodash.throttle@npm:4.1.1"
checksum: 129c0a28cee48b348aef146f638ef8a8b197944d4e9ec26c1890c19d9bf5a5690fe11b655c77a4551268819b32d27f4206343e30c78961f60b561b8608c8c805
languageName: node
linkType: hard
"lodash.union@npm:^4.6.0":
version: 4.6.0
resolution: "lodash.union@npm:4.6.0"
@@ -28355,7 +28258,7 @@ __metadata:
languageName: node
linkType: hard
"lodash@npm:4.17.21, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.17.5, lodash@npm:^4.7.0, lodash@npm:~4.17.0, lodash@npm:~4.17.15, lodash@npm:~4.17.4":
"lodash@npm:4.17.21, lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.19, lodash@npm:^4.17.20, lodash@npm:^4.17.21, lodash@npm:^4.17.4, lodash@npm:^4.7.0, lodash@npm:~4.17.0, lodash@npm:~4.17.15":
version: 4.17.21
resolution: "lodash@npm:4.17.21"
checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7
@@ -28793,13 +28696,6 @@ __metadata:
languageName: node
linkType: hard
"math-expression-evaluator@npm:^1.2.14":
version: 1.2.22
resolution: "math-expression-evaluator@npm:1.2.22"
checksum: 97b46e3311025699209d5178ea197e4df8286ac378075f105ab0cbc467f55a926a522a7e5a5ce8fc2d88881b6d32f1e3eacd81f34f265e7907cc5715e0f61a38
languageName: node
linkType: hard
"md5.js@npm:^1.3.4":
version: 1.3.5
resolution: "md5.js@npm:1.3.5"
@@ -32853,7 +32749,7 @@ __metadata:
languageName: node
linkType: hard
"prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.0, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
"prop-types@npm:^15.0.0, prop-types@npm:^15.5.10, prop-types@npm:^15.5.7, prop-types@npm:^15.5.8, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1":
version: 15.8.1
resolution: "prop-types@npm:15.8.1"
dependencies:
@@ -33695,20 +33591,6 @@ __metadata:
languageName: node
linkType: hard
"react-resize-detector@npm:^2.3.0":
version: 2.3.0
resolution: "react-resize-detector@npm:2.3.0"
dependencies:
lodash.debounce: ^4.0.8
lodash.throttle: ^4.1.1
prop-types: ^15.6.0
resize-observer-polyfill: ^1.5.0
peerDependencies:
react: ^0.14.7 || ^15.0.0 || ^16.0.0
checksum: c409cc31edaa6bb943aa1098c5830f1c430b448ebc7d2a1c4c14b1ad0eb4ea0d0bd1f48e4315569692af52270f7dc8d7fb0862c1b6121411589c4d5cd39fc1e4
languageName: node
linkType: hard
"react-resize-detector@npm:^6.6.3":
version: 6.7.8
resolution: "react-resize-detector@npm:6.7.8"
@@ -33723,6 +33605,18 @@ __metadata:
languageName: node
linkType: hard
"react-resize-detector@npm:^7.1.2":
version: 7.1.2
resolution: "react-resize-detector@npm:7.1.2"
dependencies:
lodash: ^4.17.21
peerDependencies:
react: ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
checksum: 55f4abad7f7523d16b081b5ab20f75c539a54a08253ce7e9df473d48386f42ceca6c31584ba9fa26e3528b498ef6685ec77fb9a22cffc97df05fb326d0bf1b26
languageName: node
linkType: hard
"react-router-beta@npm:react-router@6.0.0-beta.0, react-router@npm:6.0.0-beta.0":
version: 6.0.0-beta.0
resolution: "react-router@npm:6.0.0-beta.0"
@@ -33782,21 +33676,6 @@ __metadata:
languageName: node
linkType: hard
"react-smooth@npm:^1.0.5":
version: 1.0.5
resolution: "react-smooth@npm:1.0.5"
dependencies:
lodash: ~4.17.4
prop-types: ^15.6.0
raf: ^3.4.0
react-transition-group: ^2.5.0
peerDependencies:
react: ^15.0.0 || ^16.0.0
react-dom: ^15.0.0 || ^16.0.0
checksum: 29a2a00e09e0f5d4dea4424f945dc7dab9b611184c60b01bd24082b6293f9e5e4bafe0e4386d4c52a2c9c651caff3eeb5ce0966917a0bd06ba1165306853c822
languageName: node
linkType: hard
"react-smooth@npm:^2.0.0":
version: 2.0.0
resolution: "react-smooth@npm:2.0.0"
@@ -33812,6 +33691,20 @@ __metadata:
languageName: node
linkType: hard
"react-smooth@npm:^2.0.1":
version: 2.0.1
resolution: "react-smooth@npm:2.0.1"
dependencies:
fast-equals: ^2.0.0
react-transition-group: 2.9.0
peerDependencies:
prop-types: ^15.6.0
react: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0
checksum: 65678491cbd506573f2dba82778ebf8259714d68dd227e0ee7c0e204bcbc7839cf97401620b4223814066581f1dce0493f97162a03dc2a68058b5a7ad2b41085
languageName: node
linkType: hard
"react-sparklines@npm:^1.7.0":
version: 1.7.0
resolution: "react-sparklines@npm:1.7.0"
@@ -33865,7 +33758,7 @@ __metadata:
languageName: node
linkType: hard
"react-transition-group@npm:2.9.0, react-transition-group@npm:^2.5.0":
"react-transition-group@npm:2.9.0":
version: 2.9.0
resolution: "react-transition-group@npm:2.9.0"
dependencies:
@@ -34113,7 +34006,7 @@ __metadata:
languageName: node
linkType: hard
"recharts-scale@npm:^0.4.2, recharts-scale@npm:^0.4.4":
"recharts-scale@npm:^0.4.4":
version: 0.4.5
resolution: "recharts-scale@npm:0.4.5"
dependencies:
@@ -34122,25 +34015,29 @@ __metadata:
languageName: node
linkType: hard
"recharts@npm:^1.8.5":
version: 1.8.5
resolution: "recharts@npm:1.8.5"
"recharts@npm:^2.0.0":
version: 2.1.15
resolution: "recharts@npm:2.1.15"
dependencies:
"@types/d3-interpolate": ^2.0.0
"@types/d3-scale": ^3.0.0
"@types/d3-shape": ^2.0.0
classnames: ^2.2.5
core-js: ^2.6.10
d3-interpolate: ^1.3.0
d3-scale: ^2.1.0
d3-shape: ^1.2.0
lodash: ^4.17.5
prop-types: ^15.6.0
react-resize-detector: ^2.3.0
react-smooth: ^1.0.5
recharts-scale: ^0.4.2
reduce-css-calc: ^1.3.0
d3-interpolate: ^2.0.0
d3-scale: ^3.0.0
d3-shape: ^2.0.0
eventemitter3: ^4.0.1
lodash: ^4.17.19
react-is: ^16.10.2
react-resize-detector: ^7.1.2
react-smooth: ^2.0.1
recharts-scale: ^0.4.4
reduce-css-calc: ^2.1.8
peerDependencies:
react: ^15.0.0 || ^16.0.0
react-dom: ^15.0.0 || ^16.0.0
checksum: bdc1b712b90a3e5f5fcc1bbb7755dde8666c056f67cad90f4e4a2dd726ed45f9fcc82fce4a679ae168c2ed2e243a4c1acffb3e1f45ad4d96c47bcf9e764b5c8f
prop-types: ^15.6.0
react: ^16.0.0 || ^17.0.0 || ^18.0.0
react-dom: ^16.0.0 || ^17.0.0 || ^18.0.0
checksum: 2f0be89eca6da8a6d899dac8676de145001353b6072b7853d3f04091c38604f80b241b4ef04d4b28268a95df4a8134b565a192077cb6a2903048fc90f19a5def
languageName: node
linkType: hard
@@ -34222,17 +34119,6 @@ __metadata:
languageName: node
linkType: hard
"reduce-css-calc@npm:^1.3.0":
version: 1.3.0
resolution: "reduce-css-calc@npm:1.3.0"
dependencies:
balanced-match: ^0.4.2
math-expression-evaluator: ^1.2.14
reduce-function-call: ^1.0.1
checksum: 72696db02ede8772fe5ba9c47c6d451557bea0d11525f4e54b6adfcc4e540558755bb0ad454824cb6b998f0bd940eb2ef594f35b3d509dfa37934d93ece0f707
languageName: node
linkType: hard
"reduce-css-calc@npm:^2.1.8":
version: 2.1.8
resolution: "reduce-css-calc@npm:2.1.8"
@@ -34243,15 +34129,6 @@ __metadata:
languageName: node
linkType: hard
"reduce-function-call@npm:^1.0.1":
version: 1.0.3
resolution: "reduce-function-call@npm:1.0.3"
dependencies:
balanced-match: ^1.0.0
checksum: d0169016ea22b59d55fa3206507c8f2d009574abd0f9b86552035a8405d52f6d7d5b60d084c5950d6f2884df7de42f87a6260b1b386b79ede63bfc87ea0c3ce8
languageName: node
linkType: hard
"redux-immutable@npm:^4.0.0":
version: 4.0.0
resolution: "redux-immutable@npm:4.0.0"
@@ -34670,7 +34547,7 @@ __metadata:
languageName: node
linkType: hard
"resize-observer-polyfill@npm:^1.5.0, resize-observer-polyfill@npm:^1.5.1":
"resize-observer-polyfill@npm:^1.5.1":
version: 1.5.1
resolution: "resize-observer-polyfill@npm:1.5.1"
checksum: 57e7f79489867b00ba43c9c051524a5c8f162a61d5547e99333549afc23e15c44fd43f2f318ea0261ea98c0eb3158cca261e6f48d66e1ed1cd1f340a43977094
@@ -38739,16 +38616,15 @@ __metadata:
linkType: hard
"util@npm:^0.12.3, util@npm:^0.12.4":
version: 0.12.4
resolution: "util@npm:0.12.4"
version: 0.12.5
resolution: "util@npm:0.12.5"
dependencies:
inherits: ^2.0.3
is-arguments: ^1.0.4
is-generator-function: ^1.0.7
is-typed-array: ^1.1.3
safe-buffer: ^5.1.2
which-typed-array: ^1.1.2
checksum: 8eac7a6e6b341c0f1b3eb73bbe5dfcae31a7e9699c8fc3266789f3e95f7637946a7700dcf1904dbd3749a58a36760ebf7acf4bb5b717f7468532a8a79f44eff0
checksum: 705e51f0de5b446f4edec10739752ac25856541e0254ea1e7e45e5b9f9b0cb105bc4bd415736a6210edc68245a7f903bf085ffb08dd7deb8a0e847f60538a38a
languageName: node
linkType: hard