diff --git a/.changeset/dull-peaches-approve.md b/.changeset/dull-peaches-approve.md new file mode 100644 index 0000000000..f2edcc9e11 --- /dev/null +++ b/.changeset/dull-peaches-approve.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-kubernetes-backend': patch +'@backstage/plugin-kubernetes-common': patch +--- + +Added `DaemonSets` to the default kubernetes resources. diff --git a/.changeset/funny-oranges-switch.md b/.changeset/funny-oranges-switch.md new file mode 100644 index 0000000000..23c3104441 --- /dev/null +++ b/.changeset/funny-oranges-switch.md @@ -0,0 +1,5 @@ +--- +'@backstage/cli': patch +--- + +Fixed a bug where `NODE_ENV` was not set in the environment when starting the backend in development mode. It has always been the case that Webpack transformed `NODE_ENV` when running in development mode, but this did not affect dependencies in `node_modules` as they are treated as external. diff --git a/.changeset/popular-ears-allow.md b/.changeset/popular-ears-allow.md new file mode 100644 index 0000000000..1af2fcbd81 --- /dev/null +++ b/.changeset/popular-ears-allow.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-cost-insights': patch +--- + +Display minus sign in trends in `CostOverviewCard` diff --git a/.changeset/pre.json b/.changeset/pre.json index 0d89198dec..012728eb38 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "next", "initialVersions": { "example-app": "0.2.73", diff --git a/.changeset/renovate-34c125c.md b/.changeset/renovate-34c125c.md new file mode 100644 index 0000000000..5f59ab4124 --- /dev/null +++ b/.changeset/renovate-34c125c.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-catalog-graphql': patch +'@backstage/plugin-graphql-backend': patch +--- + +Updated dependency `@graphql-tools/schema` to `^9.0.0`. diff --git a/.changeset/strong-birds-pretend.md b/.changeset/strong-birds-pretend.md new file mode 100644 index 0000000000..9ad3bae97b --- /dev/null +++ b/.changeset/strong-birds-pretend.md @@ -0,0 +1,21 @@ +--- +'@backstage/plugin-catalog-backend-module-openapi': patch +--- + +Add an `$openapi` placeholder resolver that supports more use cases for resolving `$ref` instances. This means that the quite recently added `OpenApiRefProcessor` has been deprecated in favor of the `openApiPlaceholderResolver`. + +An example of how to use it can be seen below. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: example + description: Example API +spec: + type: openapi + lifecycle: production + owner: team + definition: + $openapi: ./spec/openapi.yaml # by using $openapi Backstage will now resolve all $ref instances +``` diff --git a/.changeset/witty-seas-tie.md b/.changeset/witty-seas-tie.md new file mode 100644 index 0000000000..e0ee2f57d4 --- /dev/null +++ b/.changeset/witty-seas-tie.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-tech-radar': patch +--- + +Move CSS overflow property to quadrant block element (i.e. to a div element) in RadarLegend component. diff --git a/README.md b/README.md index a6e740a427..5dba1fdf52 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ ![headline](docs/assets/headline.png) -> 🏖 From July 7th due to Summer Vacations for some of the maintainers, expect the project to move a little slower than normal, and support to be limited. Normal service will resume on August 8th 🏝 - # [Backstage](https://backstage.io) [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) diff --git a/docs/getting-started/app-custom-theme.md b/docs/getting-started/app-custom-theme.md index da4f10a64b..9ca82d01a1 100644 --- a/docs/getting-started/app-custom-theme.md +++ b/docs/getting-started/app-custom-theme.md @@ -273,6 +273,71 @@ const LogoFull = () => { }; ``` +## Custom Icons + +You can also customize the Project's _default_ icons. + +You can change the following [icons](https://github.com/backstage/backstage/blob/master/packages/app-defaults/src/defaults/icons.tsx). + +### Requirements + +- Files in `.svg` format +- React components created for the icons + +### Create React Component + +In your front-end application, locate the `src` folder. We suggest creating the `assets/icons` directory and `CustomIcons.tsx` file. + +> Another example [here](https://github.com/backstage/backstage/blob/master/plugins/azure-devops/src/components/AzurePipelinesIcon/AzurePipelinesIcon.tsx), if you want to ensure proper behavior in light and dark themes. + +```tsx +// customIcons.tsx +import { SvgIcon, SvgIconProps } from '@material-ui/core'; + +import React from 'react'; + +export const ExampleIcon = (props: SvgIconProps) => ( + + + +); +``` + +### Using the custom icon + +Supply your custom icon in `packages/app/src/App.tsx` + +```diff + ++ import { ExampleIcon } from './assets/customIcons' + +[...] + +const app = createApp({ + apis, + components: { + [...] + }, + themes: [ + [...] + ], ++ icons: { ++ github: ExampleIcon, ++ }, + bindRoutes({ bind }) { + [...] + } +}) + +[...] +``` + ## Custom Homepage In addition to a custom theme, a custom logo, you can also customize the diff --git a/docs/tutorials/switching-sqlite-postgres.md b/docs/tutorials/switching-sqlite-postgres.md index c4e4bd83b6..c0c35999c6 100644 --- a/docs/tutorials/switching-sqlite-postgres.md +++ b/docs/tutorials/switching-sqlite-postgres.md @@ -86,3 +86,16 @@ backend: + # ca: # if you have a CA file and want to verify it you can uncomment this section + # $file: /ca/server.crt ``` + +### Using a single database + +By default, each plugin will get its own logical database, to ensure that there's no conflict in table names throughout the plugins that you install and to keep their concerns separate for other use cases further down the line. If you are limited in that you can only make use of a single database, you can use a special option `pluginDivisionMode` with `client: pg` in the config to create separate [PostgreSQL Schemas](https://www.postgresql.org/docs/current/ddl-schemas.html) instead of creating separate databases. + +You can enable this using the following config: + +```yaml +backend: + database: + client: pg + pluginDivisionMode: schema # defaults to database, but changing this to schema means plugins will be given their own schema (in the specified/default database) +``` diff --git a/packages/backend-defaults/src/CreateBackend.ts b/packages/backend-defaults/src/CreateBackend.ts index 8d61d6e915..7cc116a052 100644 --- a/packages/backend-defaults/src/CreateBackend.ts +++ b/packages/backend-defaults/src/CreateBackend.ts @@ -28,6 +28,7 @@ import { tokenManagerFactory, urlReaderFactory, } from '@backstage/backend-app-api'; +import { AnyServiceFactory } from '@backstage/backend-plugin-api'; export const defaultServiceFactories = [ cacheFactory, @@ -42,8 +43,6 @@ export const defaultServiceFactories = [ httpRouterFactory, ]; -import { AnyServiceFactory } from '@backstage/backend-plugin-api'; - /** * @public */ @@ -55,8 +54,17 @@ export interface CreateBackendOptions { * @public */ export function createBackend(options?: CreateBackendOptions): Backend { - // TODO: merge with provided APIs + const services = new Map( + defaultServiceFactories.map(sf => [sf.service.id, sf]), + ); + + if (options?.services) { + for (const sf of options.services) { + services.set(sf.service.id, sf); + } + } + return createSpecializedBackend({ - services: [...defaultServiceFactories, ...(options?.services || [])], + services: Array.from(services.values()), }); } diff --git a/packages/cli/src/lib/bundler/backend.ts b/packages/cli/src/lib/bundler/backend.ts index 1b161976e3..3094450d4b 100644 --- a/packages/cli/src/lib/bundler/backend.ts +++ b/packages/cli/src/lib/bundler/backend.ts @@ -26,6 +26,10 @@ export async function serveBackend(options: BackendServeOptions) { isDev: true, }); + // Webpack only replaces occurrences of this in code it touches, which does + // not include dependencies in node_modules. So we set it here at runtime as well. + (process.env as { NODE_ENV: string }).NODE_ENV = 'development'; + const compiler = webpack(config, (err: Error | undefined) => { if (err) { console.error(err); diff --git a/plugins/catalog-backend-module-openapi/README.md b/plugins/catalog-backend-module-openapi/README.md index 1a133521c6..f80798e267 100644 --- a/plugins/catalog-backend-module-openapi/README.md +++ b/plugins/catalog-backend-module-openapi/README.md @@ -15,6 +15,32 @@ yarn add --cwd packages/backend @backstage/plugin-catalog-backend-module-openapi ### Adding the plugin to your `packages/backend` +#### **openApiPlaceholderResolver** + +The placeholder resolver can be added by importing `openApiPlaceholderResolver` in `src/plugins/catalog.ts` in your `backend` package and adding the following. + +```ts +builder.setPlaceholderResolver('openapi', openApiPlaceholderResolver); +``` + +This allows you to use the `$openapi` placeholder when referencing your OpenAPI specification. This will then resolve all `$ref` instances in your specification. + +```yaml +apiVersion: backstage.io/v1alpha1 +kind: API +metadata: + name: example + description: Example API +spec: + type: openapi + lifecycle: production + owner: team + definition: + $openapi: ./spec/openapi.yaml # by using $openapi Backstage will now resolve all $ref instances +``` + +#### **OpenAPIRefProcessor** (deprecated) + The processor can be added by importing `OpenApiRefProcessor` in `src/plugins/catalog.ts` in your `backend` package and adding the following. ```ts diff --git a/plugins/catalog-backend-module-openapi/api-report.md b/plugins/catalog-backend-module-openapi/api-report.md index 92ddd1e3cd..d3a40067c5 100644 --- a/plugins/catalog-backend-module-openapi/api-report.md +++ b/plugins/catalog-backend-module-openapi/api-report.md @@ -6,12 +6,19 @@ import { CatalogProcessor } from '@backstage/plugin-catalog-backend'; import { Config } from '@backstage/config'; import { Entity } from '@backstage/catalog-model'; +import { JsonValue } from '@backstage/types'; import { LocationSpec } from '@backstage/plugin-catalog-backend'; import { Logger } from 'winston'; +import { PlaceholderResolverParams } from '@backstage/plugin-catalog-backend'; import { ScmIntegrations } from '@backstage/integration'; import { UrlReader } from '@backstage/backend-common'; // @public (undocumented) +export function openApiPlaceholderResolver( + params: PlaceholderResolverParams, +): Promise; + +// @public @deprecated (undocumented) export class OpenApiRefProcessor implements CatalogProcessor { constructor(options: { integrations: ScmIntegrations; diff --git a/plugins/catalog-backend-module-openapi/package.json b/plugins/catalog-backend-module-openapi/package.json index d2d4d4989c..81f8875247 100644 --- a/plugins/catalog-backend-module-openapi/package.json +++ b/plugins/catalog-backend-module-openapi/package.json @@ -39,6 +39,8 @@ "@backstage/config": "^1.0.1", "@backstage/integration": "^1.3.0-next.0", "@backstage/plugin-catalog-backend": "^1.3.1-next.0", + "@backstage/plugin-catalog-node": "^1.0.1-next.0", + "@backstage/types": "^1.0.0", "winston": "^3.2.1", "yaml": "^2.1.1" }, diff --git a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts index 8f2cc571c2..21080202b5 100644 --- a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts +++ b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.test.ts @@ -86,7 +86,7 @@ describe('OpenApiRefProcessor', () => { it('should ignore other specification types', async () => { const { entity, processor } = setupTest({ - kind: 'Group', + kind: 'API', spec: { type: 'asyncapi' }, }); diff --git a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts index 01875e0779..f4cffdf48f 100644 --- a/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts +++ b/plugins/catalog-backend-module-openapi/src/OpenApiRefProcessor.ts @@ -24,7 +24,10 @@ import { import { bundleOpenApiSpecification } from './lib'; import { Logger } from 'winston'; -/** @public */ +/** + * @public + * @deprecated replaced by the openApiPlaceholderResolver + */ export class OpenApiRefProcessor implements CatalogProcessor { private readonly integrations: ScmIntegrations; private readonly logger: Logger; @@ -69,17 +72,23 @@ export class OpenApiRefProcessor implements CatalogProcessor { } const scmIntegration = this.integrations.byUrl(location.target); - if (!scmIntegration) { + const definition = entity.spec!.definition; + + if (!scmIntegration || !definition) { return entity; } + const resolveUrl = (url: string, base: string): string => { + return scmIntegration.resolveUrl({ url, base }); + }; + this.logger.debug(`Bundling OpenAPI specification from ${location.target}`); try { const bundledSpec = await bundleOpenApiSpecification( - entity.spec!.definition?.toString(), + definition.toString(), location.target, - this.reader, - scmIntegration, + this.reader.read, + resolveUrl, ); return { diff --git a/plugins/catalog-backend-module-openapi/src/index.ts b/plugins/catalog-backend-module-openapi/src/index.ts index f98bee6bac..ccd3ced71e 100644 --- a/plugins/catalog-backend-module-openapi/src/index.ts +++ b/plugins/catalog-backend-module-openapi/src/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { OpenApiRefProcessor } from './OpenApiRefProcessor'; +export { openApiPlaceholderResolver } from './openApiPlaceholderResolver'; diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts index 4505f158b5..0ecd9f7fd1 100644 --- a/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.test.ts @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ConfigReader } from '@backstage/config'; -import { ScmIntegrations } from '@backstage/integration'; import { bundleOpenApiSpecification } from './bundle'; const specification = ` @@ -73,43 +71,21 @@ paths: `; describe('bundleOpenApiSpecification', () => { - const readUrl = jest.fn(); - const reader = { - readUrl, - read: jest.fn(), - readTree: jest.fn(), - search: jest.fn(), - }; - - const scmIntegration = ScmIntegrations.fromConfig(new ConfigReader({})).byUrl( - 'https://github.com/owner/repo/blob/main/openapi.yaml', - ); + const read = jest.fn(); + const resolveUrl = jest.fn(); beforeEach(() => { jest.clearAllMocks(); }); - it('should return undefined if no specification is supplied', async () => { - expect( - await bundleOpenApiSpecification( - undefined, - 'https://github.com/owner/repo/blob/main/openapi.yaml', - reader, - scmIntegration as any, - ), - ).toBeUndefined(); - }); - it('should return the bundled specification', async () => { - readUrl.mockResolvedValue({ - buffer: jest.fn().mockResolvedValue(list), - }); + read.mockResolvedValue(list); const result = await bundleOpenApiSpecification( specification, - 'https://github.com/owner/repo/blob/main/openapi.yaml', - reader, - scmIntegration as any, + 'https://github.com/owner/repo/blob/main/catalog-info.yaml', + read, + resolveUrl, ); expect(result).toEqual(expectedResult.trimStart()); diff --git a/plugins/catalog-backend-module-openapi/src/lib/bundle.ts b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts index 3d35429d8b..6ac8d211e2 100644 --- a/plugins/catalog-backend-module-openapi/src/lib/bundle.ts +++ b/plugins/catalog-backend-module-openapi/src/lib/bundle.ts @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { UrlReader } from '@backstage/backend-common'; -import { ScmIntegration } from '@backstage/integration'; import SwaggerParser from '@apidevtools/swagger-parser'; import { parse, stringify } from 'yaml'; import * as path from 'path'; @@ -28,12 +26,16 @@ const getProtocol = (refPath: string) => { return undefined; }; +export type BundlerRead = (url: string) => Promise; + +export type BundlerResolveUrl = (url: string, base: string) => string; + export async function bundleOpenApiSpecification( - specification: string | undefined, - targetUrl: string, - reader: UrlReader, - scmIntegration: ScmIntegration, -): Promise { + specification: string, + baseUrl: string, + read: BundlerRead, + resolveUrl: BundlerResolveUrl, +): Promise { const fileUrlReaderResolver: SwaggerParser.ResolverOptions = { canRead: file => { const protocol = getProtocol(file.url); @@ -41,22 +43,11 @@ export async function bundleOpenApiSpecification( }, read: async file => { const relativePath = path.relative('.', file.url); - const url = scmIntegration.resolveUrl({ - base: targetUrl, - url: relativePath, - }); - if (reader.readUrl) { - const data = await reader.readUrl(url); - return data.buffer(); - } - throw new Error('UrlReader has no readUrl method defined'); + const url = resolveUrl(relativePath, baseUrl); + return await read(url); }, }; - if (!specification) { - return undefined; - } - const options: SwaggerParser.Options = { resolve: { file: fileUrlReaderResolver, diff --git a/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.test.ts b/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.test.ts new file mode 100644 index 0000000000..f58a818ba5 --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.test.ts @@ -0,0 +1,63 @@ +/* + * 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 { PlaceholderResolverParams } from '@backstage/plugin-catalog-backend'; +import { openApiPlaceholderResolver } from './openApiPlaceholderResolver'; +import { bundleOpenApiSpecification } from './lib'; + +jest.mock('./lib', () => ({ + bundleOpenApiSpecification: jest.fn(), +})); + +const bundledSpecification = ''; + +describe('openApiPlaceholderResolver', () => { + const mockResolveUrl = jest.fn(); + mockResolveUrl.mockReturnValue('mockUrl'); + + const mockRead = jest.fn(); + mockRead.mockResolvedValue(Buffer.from('mockData')); + + const params: PlaceholderResolverParams = { + key: 'openapi', + value: './spec/openapi.yaml', + baseUrl: 'https://github.com/owner/repo/blob/main/catalog-info.yaml', + resolveUrl: mockResolveUrl, + read: mockRead, + emit: jest.fn(), + }; + + beforeEach(() => { + (bundleOpenApiSpecification as any).mockResolvedValue(bundledSpecification); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error if unable to bundle the OpenAPI specification', async () => { + (bundleOpenApiSpecification as any).mockRejectedValue(new Error('TEST')); + + await expect(openApiPlaceholderResolver(params)).rejects.toThrow( + 'Placeholder $openapi unable to bundle OpenAPI specification', + ); + }); + + it('should bundle the OpenAPI specification', async () => { + const result = await openApiPlaceholderResolver(params); + + expect(result).toEqual(bundledSpecification); + }); +}); diff --git a/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.ts b/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.ts new file mode 100644 index 0000000000..96fadb3cbc --- /dev/null +++ b/plugins/catalog-backend-module-openapi/src/openApiPlaceholderResolver.ts @@ -0,0 +1,85 @@ +/* + * 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 { PlaceholderResolverParams } from '@backstage/plugin-catalog-backend'; +import { JsonValue } from '@backstage/types'; +import { processingResult } from '@backstage/plugin-catalog-node'; +import { bundleOpenApiSpecification } from './lib'; + +/** @public */ +export async function openApiPlaceholderResolver( + params: PlaceholderResolverParams, +): Promise { + const { content, url } = await readTextLocation(params); + + params.emit(processingResult.refresh(`url:${url}`)); + + try { + return await bundleOpenApiSpecification( + content, + url, + params.read, + params.resolveUrl, + ); + } catch (error) { + throw new Error( + `Placeholder \$${params.key} unable to bundle OpenAPI specification at ${params.value}, ${error}`, + ); + } +} + +/* + * Helpers, copied from PlaceholderProcessor + */ + +async function readTextLocation( + params: PlaceholderResolverParams, +): Promise<{ content: string; url: string }> { + const newUrl = relativeUrl(params); + + try { + const data = await params.read(newUrl); + return { content: data.toString('utf-8'), url: newUrl }; + } catch (e) { + throw new Error( + `Placeholder \$${params.key} could not read location ${params.value}, ${e}`, + ); + } +} + +function relativeUrl({ + key, + value, + baseUrl, + resolveUrl, +}: PlaceholderResolverParams): string { + if (typeof value !== 'string') { + throw new Error( + `Placeholder \$${key} expected a string value parameter, in the form of an absolute URL or a relative path`, + ); + } + + try { + return resolveUrl(value, baseUrl); + } catch (e) { + // The only remaining case that isn't support is a relative file path that should be + // resolved using a relative file location. Accessing local file paths can lead to + // path traversal attacks and access to any file on the host system. Implementing this + // would require additional security measures. + throw new Error( + `Placeholder \$${key} could not form a URL out of ${baseUrl} and ${value}, ${e}`, + ); + } +} diff --git a/plugins/catalog-graphql/package.json b/plugins/catalog-graphql/package.json index 082bd43c34..12eafe58d4 100644 --- a/plugins/catalog-graphql/package.json +++ b/plugins/catalog-graphql/package.json @@ -52,7 +52,7 @@ "@graphql-codegen/graphql-modules-preset": "^2.3.2", "@graphql-codegen/typescript": "^2.4.2", "@graphql-codegen/typescript-resolvers": "^2.4.3", - "@graphql-tools/schema": "^8.3.1", + "@graphql-tools/schema": "^9.0.0", "msw": "^0.44.0" }, "files": [ diff --git a/plugins/cost-insights/api-report.md b/plugins/cost-insights/api-report.md index 94cab949c7..2a4cecc4eb 100644 --- a/plugins/cost-insights/api-report.md +++ b/plugins/cost-insights/api-report.md @@ -320,7 +320,12 @@ export const CostGrowthIndicator: ({ // @public (undocumented) export type CostGrowthIndicatorProps = TypographyProps & { change: ChangeStatistic; - formatter?: (change: ChangeStatistic) => Maybe; + formatter?: ( + change: ChangeStatistic, + options?: { + absolute: boolean; + }, + ) => Maybe; }; // Warning: (ae-missing-release-tag) "CostGrowthProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/cost-insights/src/components/CostGrowth/CostGrowthIndicator.tsx b/plugins/cost-insights/src/components/CostGrowth/CostGrowthIndicator.tsx index 592f57d389..e7746495d6 100644 --- a/plugins/cost-insights/src/components/CostGrowth/CostGrowthIndicator.tsx +++ b/plugins/cost-insights/src/components/CostGrowth/CostGrowthIndicator.tsx @@ -25,7 +25,10 @@ import { useCostGrowthStyles as useStyles } from '../../utils/styles'; export type CostGrowthIndicatorProps = TypographyProps & { change: ChangeStatistic; - formatter?: (change: ChangeStatistic) => Maybe; + formatter?: ( + change: ChangeStatistic, + options?: { absolute: boolean }, + ) => Maybe; }; export const CostGrowthIndicator = ({ @@ -44,7 +47,7 @@ export const CostGrowthIndicator = ({ return ( - {formatter ? formatter(change) : change.ratio} + {formatter ? formatter(change, { absolute: true }) : change.ratio} {growth === GrowthType.Excess && } {growth === GrowthType.Savings && } diff --git a/plugins/cost-insights/src/utils/formatters.test.ts b/plugins/cost-insights/src/utils/formatters.test.ts index 9fe17f277f..8bf0a6a9d7 100644 --- a/plugins/cost-insights/src/utils/formatters.test.ts +++ b/plugins/cost-insights/src/utils/formatters.test.ts @@ -73,6 +73,9 @@ describe.each` ${0.123123} | ${'12%'} ${1.123} | ${'112%'} ${10.123} | ${'>1000%'} + ${-0.123123} | ${'-12%'} + ${-1.123} | ${'-112%'} + ${-10.123} | ${'>-1000%'} `('formatPercent', ({ ratio, expected }) => { it(`correctly formats ${ratio} as ${expected}`, () => { expect(formatPercent(ratio)).toBe(expected); diff --git a/plugins/cost-insights/src/utils/formatters.ts b/plugins/cost-insights/src/utils/formatters.ts index 70782123cd..e9b19097a4 100644 --- a/plugins/cost-insights/src/utils/formatters.ts +++ b/plugins/cost-insights/src/utils/formatters.ts @@ -81,9 +81,17 @@ export function formatCurrency(amount: number, currency?: string): string { return currency ? `${numString} ${pluralize(currency, n)}` : numString; } -export function formatChange(change: ChangeStatistic): string { +export function formatChange( + change: ChangeStatistic, + options?: { absolute: boolean }, +): string { if (notEmpty(change.ratio)) { - return formatPercent(Math.abs(change.ratio)); + return formatPercent( + options?.absolute ? Math.abs(change.ratio) : change.ratio, + ); + } + if (options?.absolute) { + return '∞'; } return change.amount >= 0 ? '∞' : '-∞'; } @@ -95,7 +103,7 @@ export function formatPercent(n: number): string { } if (Math.abs(n) > 10) { - return `>1000%`; + return `>${n < 0 ? '-' : ''}1000%`; } return `${(n * 100).toFixed(0)}%`; diff --git a/plugins/graphql-backend/package.json b/plugins/graphql-backend/package.json index 64cd268e00..d772e84dde 100644 --- a/plugins/graphql-backend/package.json +++ b/plugins/graphql-backend/package.json @@ -37,7 +37,7 @@ "@backstage/backend-common": "^0.15.0-next.0", "@backstage/config": "^1.0.1", "@backstage/plugin-catalog-graphql": "^0.3.11", - "@graphql-tools/schema": "^8.3.1", + "@graphql-tools/schema": "^9.0.0", "@types/express": "^4.17.6", "apollo-server": "^3.0.0", "apollo-server-express": "^3.0.0", diff --git a/plugins/kubernetes-backend/api-report.md b/plugins/kubernetes-backend/api-report.md index 03ecefa79d..d98d80ddb1 100644 --- a/plugins/kubernetes-backend/api-report.md +++ b/plugins/kubernetes-backend/api-report.md @@ -227,7 +227,8 @@ export type KubernetesObjectTypes = | 'cronjobs' | 'ingresses' | 'customresources' - | 'statefulsets'; + | 'statefulsets' + | 'daemonsets'; // @alpha export interface KubernetesServiceLocator { diff --git a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts index 3b96dc783f..7fcc9836a3 100644 --- a/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts +++ b/plugins/kubernetes-backend/src/service/KubernetesFanOutHandler.ts @@ -118,6 +118,12 @@ export const DEFAULT_OBJECTS: ObjectToFetch[] = [ plural: 'statefulsets', objectType: 'statefulsets', }, + { + group: 'apps', + apiVersion: 'v1', + plural: 'daemonsets', + objectType: 'daemonsets', + }, ]; export interface KubernetesFanOutHandlerOptions diff --git a/plugins/kubernetes-backend/src/types/types.ts b/plugins/kubernetes-backend/src/types/types.ts index 6bdcfc24da..33fde70b24 100644 --- a/plugins/kubernetes-backend/src/types/types.ts +++ b/plugins/kubernetes-backend/src/types/types.ts @@ -108,7 +108,8 @@ export type KubernetesObjectTypes = | 'cronjobs' | 'ingresses' | 'customresources' - | 'statefulsets'; + | 'statefulsets' + | 'daemonsets'; /** * Used to load cluster details from different sources diff --git a/plugins/kubernetes-common/api-report.md b/plugins/kubernetes-common/api-report.md index 2ca33d1a97..f8a8c6b460 100644 --- a/plugins/kubernetes-common/api-report.md +++ b/plugins/kubernetes-common/api-report.md @@ -7,6 +7,7 @@ import { Entity } from '@backstage/catalog-model'; import type { JsonObject } from '@backstage/types'; import { V1ConfigMap } from '@kubernetes/client-node'; import { V1CronJob } from '@kubernetes/client-node'; +import { V1DaemonSet } from '@kubernetes/client-node'; import { V1Deployment } from '@kubernetes/client-node'; import { V1HorizontalPodAutoscaler } from '@kubernetes/client-node'; import { V1Ingress } from '@kubernetes/client-node'; @@ -114,6 +115,16 @@ export interface CustomResourceFetchResponse { type: 'customresources'; } +// Warning: (ae-missing-release-tag) "DaemonSetsFetchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface DaemonSetsFetchResponse { + // (undocumented) + resources: Array; + // (undocumented) + type: 'daemonsets'; +} + // Warning: (ae-missing-release-tag) "DeploymentFetchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -139,7 +150,8 @@ export type FetchResponse = | CronJobsFetchResponse | IngressesFetchResponse | CustomResourceFetchResponse - | StatefulSetsFetchResponse; + | StatefulSetsFetchResponse + | DaemonSetsFetchResponse; // Warning: (ae-missing-release-tag) "HorizontalPodAutoscalersFetchResponse" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/plugins/kubernetes-common/src/types.ts b/plugins/kubernetes-common/src/types.ts index 9b8b790c79..53f6a5a640 100644 --- a/plugins/kubernetes-common/src/types.ts +++ b/plugins/kubernetes-common/src/types.ts @@ -18,6 +18,7 @@ import type { JsonObject } from '@backstage/types'; import { V1ConfigMap, V1CronJob, + V1DaemonSet, V1Deployment, V1HorizontalPodAutoscaler, V1Ingress, @@ -105,7 +106,8 @@ export type FetchResponse = | CronJobsFetchResponse | IngressesFetchResponse | CustomResourceFetchResponse - | StatefulSetsFetchResponse; + | StatefulSetsFetchResponse + | DaemonSetsFetchResponse; export interface PodFetchResponse { type: 'pods'; @@ -167,6 +169,11 @@ export interface StatefulSetsFetchResponse { resources: Array; } +export interface DaemonSetsFetchResponse { + type: 'daemonsets'; + resources: Array; +} + export interface KubernetesFetchError { errorType: KubernetesErrorTypes; statusCode?: number; diff --git a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx index 705dc9f47b..a398113b98 100644 --- a/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx +++ b/plugins/tech-radar/src/components/RadarLegend/RadarLegend.tsx @@ -32,15 +32,11 @@ export type Props = { }; const useStyles = makeStyles(theme => ({ - quadrantLegend: { - overflowY: 'auto', - scrollbarWidth: 'thin', - }, quadrant: { height: '100%', width: '100%', + overflowY: 'auto', scrollbarWidth: 'thin', - pointerEvents: 'none', }, quadrantHeading: { pointerEvents: 'none', @@ -229,7 +225,6 @@ const RadarLegend = (props: Props): JSX.Element => { y={quadrant.legendY} width={quadrant.legendWidth} height={quadrant.legendHeight} - className={classes.quadrantLegend} data-testid="radar-quadrant" >
diff --git a/yarn.lock b/yarn.lock index 7cf1217bf2..9bd862beb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2815,11 +2815,11 @@ meros "^1.1.4" "@graphql-codegen/cli@^2.3.1": - version "2.11.5" - resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.5.tgz#6e781d9e77b8a9192456a8f50059e4281be12b73" - integrity sha512-0RntZ/F/d7M7KJU24nDwfKTuuhpwQ8nSs00RgKIqsk4xSX/U9HgOp29pWZfJjHCppb0EiXKBDvK4DtQIqe3n3w== + version "2.11.6" + resolved "https://registry.npmjs.org/@graphql-codegen/cli/-/cli-2.11.6.tgz#3acfd7cd3bac40999ba1262063d84ca7c96172dc" + integrity sha512-0R2Bhgjt3XZTSdsn8MGGuJjDEN2z+KCo7920zLZz9boy6bQ0EyuxS9AUATePS9aC3djy2POAIPCHz8iHK68IlQ== dependencies: - "@graphql-codegen/core" "2.6.1" + "@graphql-codegen/core" "2.6.2" "@graphql-codegen/plugin-helpers" "^2.6.2" "@graphql-tools/apollo-engine-loader" "^7.3.6" "@graphql-tools/code-file-loader" "^7.3.1" @@ -2851,13 +2851,13 @@ yaml "^1.10.0" yargs "^17.0.0" -"@graphql-codegen/core@2.6.1": - version "2.6.1" - resolved "https://registry.npmjs.org/@graphql-codegen/core/-/core-2.6.1.tgz#57599a2e97d3c5109d888781587eba65f3c6cabe" - integrity sha512-X6IIQCIvEm+g6xcd/5ml/Tmz8U6pd4q9s1mM4WcstBQ26v+gzzlj6lc7+6ALhrNm25gHKQ4PiVoG2W0pw503Dw== +"@graphql-codegen/core@2.6.2": + version "2.6.2" + resolved "https://registry.npmjs.org/@graphql-codegen/core/-/core-2.6.2.tgz#29c766d2e9e5a3deeeb4f1728c1f7b1aca054a22" + integrity sha512-58T5yf9nEfAhDwN1Vz1hImqpdJ/gGpCGUaroQ5tqskZPf7eZYYVkEXbtqRZZLx1MCCKwjWX4hMtTPpHhwKCkng== dependencies: "@graphql-codegen/plugin-helpers" "^2.6.2" - "@graphql-tools/schema" "^8.5.0" + "@graphql-tools/schema" "^9.0.0" "@graphql-tools/utils" "^8.8.0" tslib "~2.4.0" @@ -3159,6 +3159,14 @@ "@graphql-tools/utils" "8.9.0" tslib "^2.4.0" +"@graphql-tools/merge@8.3.3": + version "8.3.3" + resolved "https://registry.npmjs.org/@graphql-tools/merge/-/merge-8.3.3.tgz#74dd4816c3fc7af38730fc59d1cba6e687d7fb2d" + integrity sha512-EfULshN2s2s2mhBwbV9WpGnoehRLe7eIMdZrKfHhxlBWOvtNUd3KSCN0PUdAMd7lj1jXUW9KYdn624JrVn6qzg== + dependencies: + "@graphql-tools/utils" "8.10.0" + tslib "^2.4.0" + "@graphql-tools/mock@^8.1.2": version "8.6.8" resolved "https://registry.npmjs.org/@graphql-tools/mock/-/mock-8.6.8.tgz#232a23c0c14dcfca88012886230b93e6fc2303e2" @@ -3220,7 +3228,7 @@ tslib "~2.3.0" value-or-promise "1.0.11" -"@graphql-tools/schema@8.5.0", "@graphql-tools/schema@^8.5.0": +"@graphql-tools/schema@8.5.0": version "8.5.0" resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.5.0.tgz#0332b3a2e674d16e9bf8a58dfd47432449ce2368" integrity sha512-VeFtKjM3SA9/hCJJfr95aEdC3G0xIKM9z0Qdz4i+eC1g2fdZYnfWFt2ucW4IME+2TDd0enHlKzaV0qk2SLVUww== @@ -3240,6 +3248,16 @@ tslib "^2.4.0" value-or-promise "1.0.11" +"@graphql-tools/schema@^9.0.0": + version "9.0.1" + resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-9.0.1.tgz#ba8629107c1f0b9ffad14c08c2a85961967682fd" + integrity sha512-Y6apeiBmvXEz082IAuS/ainnEEQrzMECP1MRIV72eo2WPa6ZtLYPycvIbd56Z5uU2LKP4XcWRgK6WUbCyN16Rw== + dependencies: + "@graphql-tools/merge" "8.3.3" + "@graphql-tools/utils" "8.10.0" + tslib "^2.4.0" + value-or-promise "1.0.11" + "@graphql-tools/url-loader@7.13.2", "@graphql-tools/url-loader@^7.13.2": version "7.13.2" resolved "https://registry.npmjs.org/@graphql-tools/url-loader/-/url-loader-7.13.2.tgz#4663ea817aa60d3d4ce81a47a36cba8fdfff069f" @@ -3282,6 +3300,13 @@ value-or-promise "^1.0.11" ws "^8.3.0" +"@graphql-tools/utils@8.10.0": + version "8.10.0" + resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.10.0.tgz#8e76db7487e19b60cf99fb90c2d6343b2105b331" + integrity sha512-yI+V373FdXQbYfqdarehn9vRWDZZYuvyQ/xwiv5ez2BbobHrqsexF7qs56plLRaQ8ESYpVAjMQvJWe9s23O0Jg== + dependencies: + tslib "^2.4.0" + "@graphql-tools/utils@8.6.9": version "8.6.9" resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.9.tgz#fe1b81df29c9418b41b7a1ffe731710b93d3a1fe" @@ -5812,19 +5837,19 @@ resolved "https://registry.npmjs.org/@octokit/webhooks-methods/-/webhooks-methods-3.0.0.tgz#4f4443605233f46abc5f85a857ba105095aa1181" integrity sha512-FAIyAchH9JUKXugKMC17ERAXM/56vVJekwXOON46pmUDYfU7uXB4cFY8yc8nYr5ABqVI7KjRKfFt3mZF7OcyUA== -"@octokit/webhooks-types@6.3.2": - version "6.3.2" - resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.3.2.tgz#752497434e735874ba985ea0d53d63e2568e838d" - integrity sha512-6DSvdzg7AIVgLjIjqf5BDrloMs7zUfpF0EJhLiOjXtuLr38W5pWSC7aHr7V59LCEDueJRfKZ6c9ZyuLLqVgx8g== +"@octokit/webhooks-types@6.3.4": + version "6.3.4" + resolved "https://registry.npmjs.org/@octokit/webhooks-types/-/webhooks-types-6.3.4.tgz#b553da7479edfb04218160c85f16dbbc68251533" + integrity sha512-9E0HNgHqc5v22+9IzCSEZ9iXnBJ/n+GM9gZye0kp7XmzcOfrnAKZzd4km269n6/vVOkmXwT11DbbQFukWOvbdw== "@octokit/webhooks@^10.0.0": - version "10.1.2" - resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-10.1.2.tgz#78396b6d32c60789f6031d2551a2cd598c157627" - integrity sha512-jxISKMLiYebQ/EByLXDEWQMcHASKUVl1T0EuCnpHTYjELsDXg7BEw0FCInlc8RpWmmPp4sMsh3Dd86spXAIp1A== + version "10.1.3" + resolved "https://registry.npmjs.org/@octokit/webhooks/-/webhooks-10.1.3.tgz#415bb4f826167b15da4dede81c14cb7a8978ac9a" + integrity sha512-c5uQW0HJbI5mcQpUFcM7LVs1gbdEiHD6OLXZcwxLJeNUmI8Cy9uzfCib6HguARKgnz3tSavYX/teHq7brm05iQ== dependencies: "@octokit/request-error" "^3.0.0" "@octokit/webhooks-methods" "^3.0.0" - "@octokit/webhooks-types" "6.3.2" + "@octokit/webhooks-types" "6.3.4" aggregate-error "^3.1.0" "@open-draft/until@^1.0.3": @@ -6931,7 +6956,7 @@ resolved "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz#8288e51737bf7e3ab5d7c77bfa695883745264e5" integrity sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg== -"@types/express-serve-static-core@*", "@types/express-serve-static-core@4.17.29", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.5": +"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18", "@types/express-serve-static-core@^4.17.5": version "4.17.29" resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.29.tgz#2a1795ea8e9e9c91b4a4bbe475034b20c1ec711c" integrity sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q== @@ -6940,6 +6965,15 @@ "@types/qs" "*" "@types/range-parser" "*" +"@types/express-serve-static-core@4.17.30": + version "4.17.30" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.30.tgz#0f2f99617fa8f9696170c46152ccf7500b34ac04" + integrity sha512-gstzbTWro2/nFed1WXtf+TtrpwxH7Ggs4RLYTLbeVgIkUQOI3WG/JKjgeOU1zXDvezllupjrf8OPIdvTbIaVOQ== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/express-session@^1.17.2": version "1.17.5" resolved "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.5.tgz#13f48852b4aa60ff595835faeb4b4dda0ba0866e" @@ -7444,9 +7478,9 @@ "@types/passport" "*" "@types/passport@*", "@types/passport@^1.0.3": - version "1.0.9" - resolved "https://registry.npmjs.org/@types/passport/-/passport-1.0.9.tgz#b32fa8f7485dace77a9b58e82d0c92908f6e8387" - integrity sha512-9+ilzUhmZQR4JP49GdC2O4UdDE3POPLwpmaTC/iLkW7l0TZCXOo1zsTnnlXPq6rP1UsUZPfbAV4IUdiwiXyC7g== + version "1.0.10" + resolved "https://registry.npmjs.org/@types/passport/-/passport-1.0.10.tgz#c518f2bae8b1538b7be71ee7f9220fbd3f569f05" + integrity sha512-IZamnXuN7mY+2/v8bAW6nuTcKiay7gXBBcMBZ8n7YHB4u5DwsWoJaNrHdAQ8PZEODRjCv3oHOg76CYJ40j9RqA== dependencies: "@types/express" "*" @@ -8604,10 +8638,10 @@ apollo-reporting-protobuf@^3.3.2: dependencies: "@apollo/protobufjs" "1.2.4" -apollo-server-core@^3.10.0: - version "3.10.0" - resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.10.0.tgz#6680b4eb4699829ed50d8a592721ee5e5e11e041" - integrity sha512-ln5drIk3oW/ycYhcYL9TvM7vRf7OZwJrgHWlnjnMakozBQIBSumdMi4pN001DhU9mVBWTfnmBv3CdcxJdGXIvA== +apollo-server-core@^3.10.1: + version "3.10.1" + resolved "https://registry.npmjs.org/apollo-server-core/-/apollo-server-core-3.10.1.tgz#01f9ffc57c7d15c27bd7f89d65f45522aa3f3c3d" + integrity sha512-UFFziv6h15QbKRZOA6wLyr1Sle9kns3JuQ5DEB7OYe5AIoOJNjZkWXX/tmLFUrSmlnDDryi6Sf5pDzpYmUC/UA== dependencies: "@apollo/utils.keyvaluecache" "^1.0.1" "@apollo/utils.logger" "^1.0.0" @@ -8644,18 +8678,18 @@ apollo-server-errors@^3.3.1: resolved "https://registry.npmjs.org/apollo-server-errors/-/apollo-server-errors-3.3.1.tgz#ba5c00cdaa33d4cbd09779f8cb6f47475d1cd655" integrity sha512-xnZJ5QWs6FixHICXHxUfm+ZWqqxrNuPlQ+kj5m6RtEgIpekOPssH/SD9gf2B4HuWV0QozorrygwZnux8POvyPA== -apollo-server-express@^3.0.0, apollo-server-express@^3.10.0: - version "3.10.0" - resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.10.0.tgz#fd276cf36031f7a02936cce6d170a35e1c084701" - integrity sha512-ww3tZq9I/x3Oxtux8xlHAZcSB0NNQ17lRlY6yCLk1F+jCzdcjuj0x8XNg0GdTrMowt5v43o786bU9VYKD5OVnA== +apollo-server-express@^3.0.0, apollo-server-express@^3.10.1: + version "3.10.1" + resolved "https://registry.npmjs.org/apollo-server-express/-/apollo-server-express-3.10.1.tgz#b0262d3c4919b554cff5872639bb13b694b5a217" + integrity sha512-r0esst3YGNdlphYiOrflfBqJ15VAZAhYhWSFo2kPF4knsIGK5HUkeqwjMr+fFDBn4DEfYzC+I1+LnsF/hFN8VQ== dependencies: "@types/accepts" "^1.3.5" "@types/body-parser" "1.19.2" "@types/cors" "2.8.12" "@types/express" "4.17.13" - "@types/express-serve-static-core" "4.17.29" + "@types/express-serve-static-core" "4.17.30" accepts "^1.3.5" - apollo-server-core "^3.10.0" + apollo-server-core "^3.10.1" apollo-server-types "^3.6.2" body-parser "^1.19.0" cors "^2.8.5" @@ -8679,13 +8713,13 @@ apollo-server-types@^3.6.2: apollo-server-env "^4.2.1" apollo-server@^3.0.0: - version "3.10.0" - resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-3.10.0.tgz#ed4b0b4cc5e1f44260923a4317caa663f1a3824e" - integrity sha512-6PAz1XZFM9+K2+QUCXXxQIlZy5mhSOhg0rTx3ZNbIdy1fFNP+6ZjvQAJxBIyEtaKlC2yEPAOg4yi3u8WfuA3bA== + version "3.10.1" + resolved "https://registry.npmjs.org/apollo-server/-/apollo-server-3.10.1.tgz#ed0c39d706a6a232885680c001df3b90c5cb0902" + integrity sha512-2e7EN7Pw+vV7vP236zozuFVMLjeY6Q8lF1VzT+j32pZ2oYuTrDv+9lFjMjTBPK2yV5kzuOwJU4dWkWx5OKDEiQ== dependencies: "@types/express" "4.17.13" - apollo-server-core "^3.10.0" - apollo-server-express "^3.10.0" + apollo-server-core "^3.10.1" + apollo-server-express "^3.10.1" express "^4.17.1" aproba@^1.0.3: @@ -9072,9 +9106,9 @@ aws-sdk-mock@^5.2.1: traverse "^0.6.6" aws-sdk@^2.1122.0, aws-sdk@^2.814.0, aws-sdk@^2.840.0, aws-sdk@^2.948.0: - version "2.1191.0" - resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1191.0.tgz#2748567252c68ef37a8ce29f48aa063681083918" - integrity sha512-G8hWvuc+3rxTfHqsnUwGx/fy8zlnVPtlNesXMHlwU/l4oBx3+Weg0Nhng6HvLGzUJifzlnSKDXrOsWVkHtuZ1w== + version "2.1192.0" + resolved "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1192.0.tgz#13fe38ec8dae3232f17d52b370e69daa9c7a0e9c" + integrity sha512-6uzrlG1Ow3qcOnL0+et+DBTGhYgJzgNydVvos1Eg01vPc/ZhxR7roZ3epZQcPmOR0thQuzzckTq7FBO6wzZA2w== dependencies: buffer "4.9.2" events "1.1.1" @@ -23320,9 +23354,9 @@ rollup@^0.63.4: "@types/node" "*" rollup@^2.60.2: - version "2.77.2" - resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.2.tgz#6b6075c55f9cc2040a5912e6e062151e42e2c4e3" - integrity sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g== + version "2.77.3" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.77.3.tgz#8f00418d3a2740036e15deb653bed1a90ee0cc12" + integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g== optionalDependencies: fsevents "~2.3.2"