From 044c38e73982d0793686b203d9dd356397c9a544 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Mon, 1 Nov 2021 13:10:54 +0100 Subject: [PATCH 1/5] Lazy load all API definition widgets Signed-off-by: Oliver Sand --- .changeset/swift-turtles-provide.md | 7 + plugins/api-docs/api-report.md | 18 ++- ...t.test.tsx => AsyncApiDefinition.test.tsx} | 8 +- .../AsyncApiDefinition.tsx | 145 ++++++++++++++++++ .../AsyncApiDefinitionWidget.tsx | 137 ++--------------- ...et.test.tsx => GraphQlDefinition.test.tsx} | 6 +- .../GraphQlDefinition.tsx | 63 ++++++++ .../GraphQlDefinitionWidget.tsx | 55 ++----- ...et.test.tsx => OpenApiDefinition.test.tsx} | 8 +- .../OpenApiDefinition.tsx | 92 +++++++++++ .../OpenApiDefinitionWidget.tsx | 86 ++--------- 11 files changed, 375 insertions(+), 250 deletions(-) create mode 100644 .changeset/swift-turtles-provide.md rename plugins/api-docs/src/components/AsyncApiDefinitionWidget/{AsyncApiDefinitionWidget.test.tsx => AsyncApiDefinition.test.tsx} (87%) create mode 100644 plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx rename plugins/api-docs/src/components/GraphQlDefinitionWidget/{GraphQlDefinitionWidget.test.tsx => GraphQlDefinition.test.tsx} (89%) create mode 100644 plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx rename plugins/api-docs/src/components/OpenApiDefinitionWidget/{OpenApiDefinitionWidget.test.tsx => OpenApiDefinition.test.tsx} (87%) create mode 100644 plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx diff --git a/.changeset/swift-turtles-provide.md b/.changeset/swift-turtles-provide.md new file mode 100644 index 0000000000..52cf9a7c8f --- /dev/null +++ b/.changeset/swift-turtles-provide.md @@ -0,0 +1,7 @@ +--- +'@backstage/plugin-api-docs': patch +--- + +Lazy load all API definition widgets. The widgets use libraries like +`swagger-ui`, `graphiql`, and `@asyncapi/react-component` which are quite heavy +weight. To improve initial load times, the widgets are only loaded once used. diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index de36857945..8ec6175a6d 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -84,11 +84,13 @@ export const ApiTypeTitle: ({ apiEntity: ApiEntity; }) => JSX.Element; -// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "AsyncApiDefinitionWidgetProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "AsyncApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const AsyncApiDefinitionWidget: ({ definition }: Props_5) => JSX.Element; +export const AsyncApiDefinitionWidget: ({ + definition, +}: AsyncApiDefinitionWidgetProps) => JSX.Element; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ConsumedApisCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -100,7 +102,7 @@ export const ConsumedApisCard: ({ variant }: Props_2) => JSX.Element; // Warning: (ae-missing-release-tag) "ConsumingComponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const ConsumingComponentsCard: ({ variant }: Props_6) => JSX.Element; +export const ConsumingComponentsCard: ({ variant }: Props_5) => JSX.Element; // Warning: (ae-missing-release-tag) "defaultDefinitionWidgets" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -169,11 +171,13 @@ export const EntityProvidingComponentsCard: ({ // @public (undocumented) export const HasApisCard: ({ variant }: Props_3) => JSX.Element; -// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "OpenApiDefinitionWidgetProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "OpenApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const OpenApiDefinitionWidget: ({ definition }: Props_8) => JSX.Element; +export const OpenApiDefinitionWidget: ({ + definition, +}: OpenApiDefinitionWidgetProps) => JSX.Element; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "PlainApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -182,7 +186,7 @@ export const OpenApiDefinitionWidget: ({ definition }: Props_8) => JSX.Element; export const PlainApiDefinitionWidget: ({ definition, language, -}: Props_9) => JSX.Element; +}: Props_7) => JSX.Element; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ProvidedApisCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -194,5 +198,5 @@ export const ProvidedApisCard: ({ variant }: Props_4) => JSX.Element; // Warning: (ae-missing-release-tag) "ProvidingComponentsCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const ProvidingComponentsCard: ({ variant }: Props_7) => JSX.Element; +export const ProvidingComponentsCard: ({ variant }: Props_6) => JSX.Element; ``` diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.test.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx similarity index 87% rename from plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.test.tsx rename to plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx index 0170ada180..cb89476c03 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.test.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.test.tsx @@ -16,9 +16,9 @@ import { renderInTestApp } from '@backstage/test-utils'; import React from 'react'; -import { AsyncApiDefinitionWidget } from './AsyncApiDefinitionWidget'; +import { AsyncApiDefinition } from './AsyncApiDefinition'; -describe('', () => { +describe('', () => { it('renders asyncapi spec', async () => { const definition = ` asyncapi: 2.0.0 @@ -40,7 +40,7 @@ components: type: string `; const { getByText, getAllByText } = await renderInTestApp( - , + , ); expect(getByText(/Account Service/i)).toBeInTheDocument(); @@ -51,7 +51,7 @@ components: it('renders error if definition is missing', async () => { const { getByText } = await renderInTestApp( - , + , ); expect(getByText(/Error/i)).toBeInTheDocument(); expect(getByText(/Document can't be null or falsey/i)).toBeInTheDocument(); diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx new file mode 100644 index 0000000000..1c993f67d7 --- /dev/null +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinition.tsx @@ -0,0 +1,145 @@ +/* + * 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 AsyncApi from '@asyncapi/react-component'; +import '@asyncapi/react-component/lib/styles/fiori.css'; +import { alpha, makeStyles } from '@material-ui/core/styles'; +import React from 'react'; + +const useStyles = makeStyles(theme => ({ + root: { + '& .asyncapi': { + 'font-family': 'inherit', + background: 'none', + }, + '& h2': { + ...theme.typography.h6, + }, + '& .text-teal': { + color: theme.palette.primary.main, + }, + '& button': { + ...theme.typography.button, + background: 'none', + boxSizing: 'border-box', + minWidth: 64, + borderRadius: theme.shape.borderRadius, + transition: theme.transitions.create( + ['background-color', 'box-shadow', 'border'], + { + duration: theme.transitions.duration.short, + }, + ), + padding: '5px 15px', + color: theme.palette.primary.main, + border: `1px solid ${alpha(theme.palette.primary.main, 0.5)}`, + '&:hover': { + textDecoration: 'none', + '&.Mui-disabled': { + backgroundColor: 'transparent', + }, + border: `1px solid ${theme.palette.primary.main}`, + backgroundColor: alpha( + theme.palette.primary.main, + theme.palette.action.hoverOpacity, + ), + // Reset on touch devices, it doesn't add specificity + '@media (hover: none)': { + backgroundColor: 'transparent', + }, + }, + '&.Mui-disabled': { + color: theme.palette.action.disabled, + }, + }, + '& .asyncapi__collapse-button:hover': { + color: theme.palette.primary.main, + }, + '& button.asyncapi__toggle-button': { + 'min-width': 'inherit', + }, + '& .asyncapi__info-list li': { + 'border-color': theme.palette.primary.main, + '&:hover': { + color: theme.palette.text.primary, + 'border-color': theme.palette.primary.main, + 'background-color': theme.palette.primary.main, + }, + }, + '& .asyncapi__info-list li a': { + color: theme.palette.primary.main, + '&:hover': { + color: theme.palette.getContrastText(theme.palette.primary.main), + }, + }, + '& .asyncapi__enum': { + color: theme.palette.secondary.main, + }, + '& .asyncapi__info, .asyncapi__channel, .asyncapi__channels > div, .asyncapi__schema, .asyncapi__channel-operations-list .asyncapi__messages-list-item .asyncapi__message, .asyncapi__message, .asyncapi__server, .asyncapi__servers > div, .asyncapi__messages > div, .asyncapi__schemas > div': + { + 'background-color': 'inherit', + }, + '& .asyncapi__channel-parameters-header, .asyncapi__channel-operations-header, .asyncapi__channel-operation-oneOf-subscribe-header, .asyncapi__channel-operation-oneOf-publish-header, .asyncapi__channel-operation-message-header, .asyncapi__message-header, .asyncapi__message-header-title, .asyncapi__message-header-title > h3, .asyncapi__bindings, .asyncapi__bindings-header, .asyncapi__bindings-header > h4': + { + 'background-color': 'inherit', + color: theme.palette.text.primary, + }, + '& .asyncapi__additional-properties-notice': { + color: theme.palette.text.hint, + }, + '& .asyncapi__code, .asyncapi__code-pre': { + background: theme.palette.background.default, + }, + '& .asyncapi__schema-example-header-title': { + color: theme.palette.text.secondary, + }, + '& .asyncapi__message-headers-header, .asyncapi__message-payload-header, .asyncapi__server-variables-header, .asyncapi__server-security-header': + { + 'background-color': 'inherit', + color: theme.palette.text.secondary, + }, + '& .asyncapi__table-header': { + background: theme.palette.background.default, + }, + '& .asyncapi__table-body': { + color: theme.palette.text.primary, + }, + '& .asyncapi__server-security-flow': { + background: theme.palette.background.default, + border: 'none', + }, + '& .asyncapi__server-security-flows-list a': { + color: theme.palette.primary.main, + }, + '& .asyncapi__table-row--nested': { + color: theme.palette.text.secondary, + }, + }, +})); + +type Props = { + definition: string; +}; + +export const AsyncApiDefinition = ({ definition }: Props) => { + const classes = useStyles(); + + return ( +
+ +
+ ); +}; diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx index f32b5d01b5..a3d9bc1f64 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx @@ -14,132 +14,27 @@ * limitations under the License. */ -import AsyncApi from '@asyncapi/react-component'; -import '@asyncapi/react-component/lib/styles/fiori.css'; -import { fade, makeStyles } from '@material-ui/core/styles'; -import React from 'react'; +import { Progress } from '@backstage/core-components'; +import React, { Suspense } from 'react'; -const useStyles = makeStyles(theme => ({ - root: { - '& .asyncapi': { - 'font-family': 'inherit', - background: 'none', - }, - '& h2': { - ...theme.typography.h6, - }, - '& .text-teal': { - color: theme.palette.primary.main, - }, - '& button': { - ...theme.typography.button, - background: 'none', - boxSizing: 'border-box', - minWidth: 64, - borderRadius: theme.shape.borderRadius, - transition: theme.transitions.create( - ['background-color', 'box-shadow', 'border'], - { - duration: theme.transitions.duration.short, - }, - ), - padding: '5px 15px', - color: theme.palette.primary.main, - border: `1px solid ${fade(theme.palette.primary.main, 0.5)}`, - '&:hover': { - textDecoration: 'none', - '&.Mui-disabled': { - backgroundColor: 'transparent', - }, - border: `1px solid ${theme.palette.primary.main}`, - backgroundColor: fade( - theme.palette.primary.main, - theme.palette.action.hoverOpacity, - ), - // Reset on touch devices, it doesn't add specificity - '@media (hover: none)': { - backgroundColor: 'transparent', - }, - }, - '&.Mui-disabled': { - color: theme.palette.action.disabled, - }, - }, - '& .asyncapi__collapse-button:hover': { - color: theme.palette.primary.main, - }, - '& button.asyncapi__toggle-button': { - 'min-width': 'inherit', - }, - '& .asyncapi__info-list li': { - 'border-color': theme.palette.primary.main, - '&:hover': { - color: theme.palette.text.primary, - 'border-color': theme.palette.primary.main, - 'background-color': theme.palette.primary.main, - }, - }, - '& .asyncapi__info-list li a': { - color: theme.palette.primary.main, - '&:hover': { - color: theme.palette.getContrastText(theme.palette.primary.main), - }, - }, - '& .asyncapi__enum': { - color: theme.palette.secondary.main, - }, - '& .asyncapi__info, .asyncapi__channel, .asyncapi__channels > div, .asyncapi__schema, .asyncapi__channel-operations-list .asyncapi__messages-list-item .asyncapi__message, .asyncapi__message, .asyncapi__server, .asyncapi__servers > div, .asyncapi__messages > div, .asyncapi__schemas > div': - { - 'background-color': 'inherit', - }, - '& .asyncapi__channel-parameters-header, .asyncapi__channel-operations-header, .asyncapi__channel-operation-oneOf-subscribe-header, .asyncapi__channel-operation-oneOf-publish-header, .asyncapi__channel-operation-message-header, .asyncapi__message-header, .asyncapi__message-header-title, .asyncapi__message-header-title > h3, .asyncapi__bindings, .asyncapi__bindings-header, .asyncapi__bindings-header > h4': - { - 'background-color': 'inherit', - color: theme.palette.text.primary, - }, - '& .asyncapi__additional-properties-notice': { - color: theme.palette.text.hint, - }, - '& .asyncapi__code, .asyncapi__code-pre': { - background: theme.palette.background.default, - }, - '& .asyncapi__schema-example-header-title': { - color: theme.palette.text.secondary, - }, - '& .asyncapi__message-headers-header, .asyncapi__message-payload-header, .asyncapi__server-variables-header, .asyncapi__server-security-header': - { - 'background-color': 'inherit', - color: theme.palette.text.secondary, - }, - '& .asyncapi__table-header': { - background: theme.palette.background.default, - }, - '& .asyncapi__table-body': { - color: theme.palette.text.primary, - }, - '& .asyncapi__server-security-flow': { - background: theme.palette.background.default, - border: 'none', - }, - '& .asyncapi__server-security-flows-list a': { - color: theme.palette.primary.main, - }, - '& .asyncapi__table-row--nested': { - color: theme.palette.text.secondary, - }, - }, -})); +// The asyncapi component and related CSS has a significant size, only load it +// if the element is actually used. +const LazyAsyncApiDefinition = React.lazy(() => + import('./AsyncApiDefinition').then(m => ({ + default: m.AsyncApiDefinition, + })), +); -type Props = { +export type AsyncApiDefinitionWidgetProps = { definition: string; }; -export const AsyncApiDefinitionWidget = ({ definition }: Props) => { - const classes = useStyles(); - +export const AsyncApiDefinitionWidget = ({ + definition, +}: AsyncApiDefinitionWidgetProps) => { return ( -
- -
+ }> + + ); }; diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.test.tsx b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.test.tsx similarity index 89% rename from plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.test.tsx rename to plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.test.tsx index 63e5a73692..fd78fa9204 100644 --- a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.test.tsx +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.test.tsx @@ -16,9 +16,9 @@ import { renderInTestApp } from '@backstage/test-utils'; import React from 'react'; -import { GraphQlDefinitionWidget } from './GraphQlDefinitionWidget'; +import { GraphQlDefinition } from './GraphQlDefinition'; -describe('', () => { +describe('', () => { it('renders graphql schema', async () => { const definition = ` """Hello World!""" @@ -53,7 +53,7 @@ type Film { }; const { getByText } = await renderInTestApp( - , + , ); expect(getByText(/Film/i)).toBeInTheDocument(); diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx new file mode 100644 index 0000000000..d3fddf70cf --- /dev/null +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinition.tsx @@ -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 { BackstageTheme } from '@backstage/theme'; +import { makeStyles } from '@material-ui/core/styles'; +import GraphiQL from 'graphiql'; +import 'graphiql/graphiql.css'; +import { buildSchema } from 'graphql'; +import React from 'react'; + +const useStyles = makeStyles(() => ({ + root: { + height: '100%', + display: 'flex', + flexFlow: 'column nowrap', + }, + graphiQlWrapper: { + flex: 1, + '@global': { + '.graphiql-container': { + boxSizing: 'initial', + height: '100%', + minHeight: '600px', + flex: '1 1 auto', + }, + }, + }, +})); + +type Props = { + definition: string; +}; + +export const GraphQlDefinition = ({ definition }: Props) => { + const classes = useStyles(); + const schema = buildSchema(definition); + + return ( +
+
+ Promise.resolve(null) as any} + schema={schema} + docExplorerOpen + defaultSecondaryEditorOpen={false} + /> +
+
+ ); +}; diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx index 8d15ba08a2..e91387bffa 100644 --- a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx @@ -14,54 +14,27 @@ * limitations under the License. */ -import { BackstageTheme } from '@backstage/theme'; -import { makeStyles } from '@material-ui/core/styles'; -import 'graphiql/graphiql.css'; -import { buildSchema } from 'graphql'; -import React, { Suspense } from 'react'; import { Progress } from '@backstage/core-components'; +import React, { Suspense } from 'react'; -const GraphiQL = React.lazy(() => import('graphiql')); +// The graphql component, graphql and related CSS has a significant size, only +// load it if the element is actually used. +const LazyGraphQlDefinition = React.lazy(() => + import('./GraphQlDefinition').then(m => ({ + default: m.GraphQlDefinition, + })), +); -const useStyles = makeStyles(() => ({ - root: { - height: '100%', - display: 'flex', - flexFlow: 'column nowrap', - }, - graphiQlWrapper: { - flex: 1, - '@global': { - '.graphiql-container': { - boxSizing: 'initial', - height: '100%', - minHeight: '600px', - flex: '1 1 auto', - }, - }, - }, -})); - -type Props = { - definition: any; +export type GraphQlDefinitionWidgetProps = { + definition: string; }; -export const GraphQlDefinitionWidget = ({ definition }: Props) => { - const classes = useStyles(); - const schema = buildSchema(definition); - +export const GraphQlDefinitionWidget = ({ + definition, +}: GraphQlDefinitionWidgetProps) => { return ( }> -
-
- Promise.resolve(null) as any} - schema={schema} - docExplorerOpen - defaultSecondaryEditorOpen={false} - /> -
-
+
); }; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.test.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx similarity index 87% rename from plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.test.tsx rename to plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx index 080aa11a3a..735fba86f7 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.test.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.test.tsx @@ -17,9 +17,9 @@ import { renderInTestApp } from '@backstage/test-utils'; import { waitFor } from '@testing-library/react'; import React from 'react'; -import { OpenApiDefinitionWidget } from './OpenApiDefinitionWidget'; +import { OpenApiDefinition } from './OpenApiDefinition'; -describe('', () => { +describe('', () => { it('renders openapi spec', async () => { const definition = ` openapi: "3.0.0" @@ -39,7 +39,7 @@ paths: description: Success `; const { getByText } = await renderInTestApp( - , + , ); // swagger-ui loads the documentation asynchronously @@ -51,7 +51,7 @@ paths: it('renders error if definition is missing', async () => { const { getByText } = await renderInTestApp( - , + , ); expect(getByText(/No API definition provided/i)).toBeInTheDocument(); }); diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx new file mode 100644 index 0000000000..cc3df40ae5 --- /dev/null +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx @@ -0,0 +1,92 @@ +/* + * 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 { makeStyles } from '@material-ui/core/styles'; +import React, { useEffect, useState } from 'react'; +import SwaggerUI from 'swagger-ui-react'; +import 'swagger-ui-react/swagger-ui.css'; + +const useStyles = makeStyles(theme => ({ + root: { + '& .swagger-ui, .info h1, .info h2, .info h3, .info h4, .info h': { + 'font-family': 'inherit', + color: theme.palette.text.primary, + }, + '& .scheme-container': { + 'background-color': theme.palette.background.default, + }, + '& .opblock-tag, .opblock-tag small, table thead tr td, table thead tr th': + { + color: theme.palette.text.primary, + 'border-color': theme.palette.divider, + }, + '& section.models, section.models.is-open h4': { + 'border-color': theme.palette.divider, + }, + '& .opblock .opblock-summary-description, .parameter__type, table.headers td, .model-title, .model .property.primitive, section h3': + { + color: theme.palette.text.secondary, + }, + '& .opblock .opblock-summary-operation-id, .opblock .opblock-summary-path, .opblock .opblock-summary-path__deprecated, .opblock .opblock-section-header h4, .parameter__name, .response-col_status, .response-col_links, .responses-inner h4, .swagger-ui .responses-inner h5, .opblock-section-header .btn, .tab li, .info li, .info p, .info table, section.models h4, .info .title, table.model tr.description, .property-row': + { + color: theme.palette.text.primary, + }, + '& .opblock .opblock-section-header, .model-box, section.models .model-container': + { + background: theme.palette.background.default, + }, + '& .prop-format, .parameter__in': { + color: theme.palette.text.disabled, + }, + '& ': { + color: theme.palette.text.primary, + 'border-color': theme.palette.divider, + }, + '& .opblock-description-wrapper p, .opblock-external-docs-wrapper p, .opblock-title_normal p, .response-control-media-type__accept-message, .opblock .opblock-section-header>label, .scheme-container .schemes>label, .info .base-url, .model': + { + color: theme.palette.text.hint, + }, + '& .parameter__name.required:after': { + color: theme.palette.warning.dark, + }, + '& .prop-type': { + color: theme.palette.primary.main, + }, + }, +})); + +type Props = { + definition: string; +}; + +export const OpenApiDefinition = ({ definition }: Props) => { + const classes = useStyles(); + + // Due to a bug in the swagger-ui-react component, the component needs + // to be created without content first. + const [def, setDef] = useState(''); + + useEffect(() => { + const timer = setTimeout(() => setDef(definition), 0); + return () => clearTimeout(timer); + }, [definition, setDef]); + + return ( +
+ +
+ ); +}; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx index 4c22d29bc2..2c223243d1 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx @@ -14,81 +14,27 @@ * limitations under the License. */ -import { makeStyles } from '@material-ui/core/styles'; -import React, { useEffect, useState } from 'react'; -import SwaggerUI from 'swagger-ui-react'; -import 'swagger-ui-react/swagger-ui.css'; +import { Progress } from '@backstage/core-components'; +import React, { Suspense } from 'react'; -// TODO: Schemas +// The swagger-ui component and related CSS has a significant size, only load it +// if the element is actually used. +const LazyOpenApiDefinition = React.lazy(() => + import('./OpenApiDefinition').then(m => ({ + default: m.OpenApiDefinition, + })), +); -const useStyles = makeStyles(theme => ({ - root: { - '& .swagger-ui, .info h1, .info h2, .info h3, .info h4, .info h': { - 'font-family': 'inherit', - color: theme.palette.text.primary, - }, - '& .scheme-container': { - 'background-color': theme.palette.background.default, - }, - '& .opblock-tag, .opblock-tag small, table thead tr td, table thead tr th': - { - color: theme.palette.text.primary, - 'border-color': theme.palette.divider, - }, - '& section.models, section.models.is-open h4': { - 'border-color': theme.palette.divider, - }, - '& .opblock .opblock-summary-description, .parameter__type, table.headers td, .model-title, .model .property.primitive, section h3': - { - color: theme.palette.text.secondary, - }, - '& .opblock .opblock-summary-operation-id, .opblock .opblock-summary-path, .opblock .opblock-summary-path__deprecated, .opblock .opblock-section-header h4, .parameter__name, .response-col_status, .response-col_links, .responses-inner h4, .swagger-ui .responses-inner h5, .opblock-section-header .btn, .tab li, .info li, .info p, .info table, section.models h4, .info .title, table.model tr.description, .property-row': - { - color: theme.palette.text.primary, - }, - '& .opblock .opblock-section-header, .model-box, section.models .model-container': - { - background: theme.palette.background.default, - }, - '& .prop-format, .parameter__in': { - color: theme.palette.text.disabled, - }, - '& ': { - color: theme.palette.text.primary, - 'border-color': theme.palette.divider, - }, - '& .opblock-description-wrapper p, .opblock-external-docs-wrapper p, .opblock-title_normal p, .response-control-media-type__accept-message, .opblock .opblock-section-header>label, .scheme-container .schemes>label, .info .base-url, .model': - { - color: theme.palette.text.hint, - }, - '& .parameter__name.required:after': { - color: theme.palette.warning.dark, - }, - '& .prop-type': { - color: theme.palette.primary.main, - }, - }, -})); - -type Props = { +export type OpenApiDefinitionWidgetProps = { definition: string; }; -export const OpenApiDefinitionWidget = ({ definition }: Props) => { - const classes = useStyles(); - - // Due to a bug in the swagger-ui-react component, the component needs - // to be created without content first. - const [def, setDef] = useState(''); - - useEffect(() => { - const timer = setTimeout(() => setDef(definition), 0); - return () => clearTimeout(timer); - }, [definition, setDef]); - +export const OpenApiDefinitionWidget = ({ + definition, +}: OpenApiDefinitionWidgetProps) => { return ( -
- -
+ }> + + ); }; From fe5738fe1c8dd286f374bb0fe8f81e2009210e56 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Mon, 1 Nov 2021 16:25:46 +0100 Subject: [PATCH 2/5] Lazy load `LazyLog` as it is rarely used Signed-off-by: Oliver Sand --- .changeset/gold-cobras-stare.md | 6 ++ .../src/components/TaskPage/TaskPage.tsx | 60 +++++++++++-------- .../components/TechDocsBuildLogs.test.tsx | 21 ++++--- .../reader/components/TechDocsBuildLogs.tsx | 27 +++++---- 4 files changed, 66 insertions(+), 48 deletions(-) create mode 100644 .changeset/gold-cobras-stare.md diff --git a/.changeset/gold-cobras-stare.md b/.changeset/gold-cobras-stare.md new file mode 100644 index 0000000000..d3265c865a --- /dev/null +++ b/.changeset/gold-cobras-stare.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-scaffolder': patch +'@backstage/plugin-techdocs': patch +--- + +Lazy load `LazyLog` as it is rarely used. diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index aeb47b2789..8d22293cb1 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -14,38 +14,40 @@ * limitations under the License. */ -import React, { useState, useEffect, memo, useMemo } from 'react'; -import { makeStyles, Theme, createStyles } from '@material-ui/core/styles'; -import Stepper from '@material-ui/core/Stepper'; -import Step from '@material-ui/core/Step'; -import StepLabel from '@material-ui/core/StepLabel'; -import Grid from '@material-ui/core/Grid'; -import Typography from '@material-ui/core/Typography'; -import { useParams } from 'react-router'; -import { useTaskEventStream } from '../hooks/useEventStream'; -import LazyLog from 'react-lazylog/build/LazyLog'; +import { + Content, + ErrorPage, + Header, + Lifecycle, + Page, +} from '@backstage/core-components'; +import { BackstageTheme } from '@backstage/theme'; import { CircularProgress, + LinearProgress, Paper, StepButton, StepIconProps, } from '@material-ui/core'; -import { Status, TaskOutput } from '../../types'; -import { DateTime, Interval } from 'luxon'; -import { useInterval } from 'react-use'; -import Check from '@material-ui/icons/Check'; +import Grid from '@material-ui/core/Grid'; +import Step from '@material-ui/core/Step'; +import StepLabel from '@material-ui/core/StepLabel'; +import Stepper from '@material-ui/core/Stepper'; +import { createStyles, makeStyles, Theme } from '@material-ui/core/styles'; +import Typography from '@material-ui/core/Typography'; import Cancel from '@material-ui/icons/Cancel'; +import Check from '@material-ui/icons/Check'; import FiberManualRecordIcon from '@material-ui/icons/FiberManualRecord'; import classNames from 'classnames'; -import { BackstageTheme } from '@backstage/theme'; +import { DateTime, Interval } from 'luxon'; +import React, { memo, Suspense, useEffect, useMemo, useState } from 'react'; +import { useParams } from 'react-router'; +import { useInterval } from 'react-use'; +import { Status, TaskOutput } from '../../types'; +import { useTaskEventStream } from '../hooks/useEventStream'; import { TaskPageLinks } from './TaskPageLinks'; -import { - Page, - Header, - Lifecycle, - Content, - ErrorPage, -} from '@backstage/core-components'; + +const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); // typings are wrong for this library, so fallback to not parsing types. const humanizeDuration = require('humanize-duration'); @@ -213,9 +215,17 @@ export const TaskStatusStepper = memo( const TaskLogger = memo(({ log }: { log: string }) => { return ( -
- -
+ }> +
+ +
+
); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx index d1bb99b76c..fa82527282 100644 --- a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.test.tsx @@ -23,9 +23,9 @@ import { // react-lazylog is based on a react-virtualized component which doesn't // write the content to the dom, so we mock it. -jest.mock('react-lazylog', () => { +jest.mock('react-lazylog/build/LazyLog', () => { return { - LazyLog: ({ text }: { text: string }) => { + default: ({ text }: { text: string }) => { return

{text}

; }, }; @@ -46,18 +46,20 @@ describe('', () => { }); describe('', () => { - it('should render with empty log', () => { + it('should render with empty log', async () => { const onClose = jest.fn(); const rendered = render( , ); expect(rendered.getByText(/Build Details/i)).toBeInTheDocument(); - expect(rendered.getByText(/Waiting for logs.../i)).toBeInTheDocument(); + expect( + await rendered.findByText(/Waiting for logs.../i), + ).toBeInTheDocument(); expect(onClose).toBeCalledTimes(0); }); - it('should render with empty logs', () => { + it('should render logs', async () => { const onClose = jest.fn(); const rendered = render( ', () => { />, ); expect(rendered.getByText(/Build Details/i)).toBeInTheDocument(); - expect( - rendered.queryByText(/Waiting for logs.../i), - ).not.toBeInTheDocument(); - expect(rendered.getByText(/Line 1/i)).toBeInTheDocument(); - expect(rendered.getByText(/Line 2/i)).toBeInTheDocument(); + expect(await rendered.findByText(/Line 1/i)).toBeInTheDocument(); + expect(await rendered.findByText(/Line 2/i)).toBeInTheDocument(); expect(onClose).toBeCalledTimes(0); }); @@ -80,7 +79,7 @@ describe('', () => { const rendered = render( , ); - rendered.getByRole('button').click(); + rendered.getByTitle('Close the drawer').click(); expect(onClose).toBeCalledTimes(1); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx index 4283932fb3..0850c0e291 100644 --- a/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsBuildLogs.tsx @@ -20,14 +20,15 @@ import { Drawer, Grid, IconButton, + LinearProgress, makeStyles, Theme, Typography, } from '@material-ui/core'; import Close from '@material-ui/icons/Close'; -import * as React from 'react'; -import { useState } from 'react'; -import { LazyLog } from 'react-lazylog'; +import React, { Suspense, useState } from 'react'; + +const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); const useDrawerStyles = makeStyles((theme: Theme) => createStyles({ @@ -83,15 +84,17 @@ export const TechDocsBuildLogsDrawerContent = ({ - + }> + + ); }; From 7e5bd18cf7774f07eb54c072d2e48de73ebee899 Mon Sep 17 00:00:00 2001 From: Oliver Sand Date: Tue, 2 Nov 2021 09:58:11 +0100 Subject: [PATCH 3/5] Adjust to review comments Signed-off-by: Oliver Sand --- plugins/api-docs/api-report.md | 44 +++++++++++++------ .../AsyncApiDefinitionWidget.tsx | 8 ++-- .../AsyncApiDefinitionWidget/index.ts | 1 + .../GraphQlDefinitionWidget.tsx | 8 ++-- .../GraphQlDefinitionWidget/index.ts | 1 + .../OpenApiDefinitionWidget.tsx | 8 ++-- .../OpenApiDefinitionWidget/index.ts | 1 + .../PlainApiDefinitionWidget.tsx | 12 +++-- .../PlainApiDefinitionWidget/index.ts | 1 + .../src/components/TaskPage/TaskPage.tsx | 4 +- .../reader/components/TechDocsBuildLogs.tsx | 4 +- 11 files changed, 60 insertions(+), 32 deletions(-) diff --git a/plugins/api-docs/api-report.md b/plugins/api-docs/api-report.md index 8ec6175a6d..111660ae07 100644 --- a/plugins/api-docs/api-report.md +++ b/plugins/api-docs/api-report.md @@ -84,13 +84,19 @@ export const ApiTypeTitle: ({ apiEntity: ApiEntity; }) => JSX.Element; -// Warning: (ae-forgotten-export) The symbol "AsyncApiDefinitionWidgetProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "AsyncApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const AsyncApiDefinitionWidget: ({ - definition, -}: AsyncApiDefinitionWidgetProps) => JSX.Element; +export const AsyncApiDefinitionWidget: ( + props: AsyncApiDefinitionWidgetProps, +) => JSX.Element; + +// Warning: (ae-missing-release-tag) "AsyncApiDefinitionWidgetProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type AsyncApiDefinitionWidgetProps = { + definition: string; +}; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ConsumedApisCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -171,22 +177,34 @@ export const EntityProvidingComponentsCard: ({ // @public (undocumented) export const HasApisCard: ({ variant }: Props_3) => JSX.Element; -// Warning: (ae-forgotten-export) The symbol "OpenApiDefinitionWidgetProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "OpenApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const OpenApiDefinitionWidget: ({ - definition, -}: OpenApiDefinitionWidgetProps) => JSX.Element; +export const OpenApiDefinitionWidget: ( + props: OpenApiDefinitionWidgetProps, +) => JSX.Element; + +// Warning: (ae-missing-release-tag) "OpenApiDefinitionWidgetProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type OpenApiDefinitionWidgetProps = { + definition: string; +}; -// Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "PlainApiDefinitionWidget" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export const PlainApiDefinitionWidget: ({ - definition, - language, -}: Props_7) => JSX.Element; +export const PlainApiDefinitionWidget: ( + props: PlainApiDefinitionWidgetProps, +) => JSX.Element; + +// Warning: (ae-missing-release-tag) "PlainApiDefinitionWidgetProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export type PlainApiDefinitionWidgetProps = { + definition: any; + language: string; +}; // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ProvidedApisCard" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx index a3d9bc1f64..03bc6fa8a6 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/AsyncApiDefinitionWidget.tsx @@ -29,12 +29,12 @@ export type AsyncApiDefinitionWidgetProps = { definition: string; }; -export const AsyncApiDefinitionWidget = ({ - definition, -}: AsyncApiDefinitionWidgetProps) => { +export const AsyncApiDefinitionWidget = ( + props: AsyncApiDefinitionWidgetProps, +) => { return ( }> - + ); }; diff --git a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts index dcca901be2..7cc49e3138 100644 --- a/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts +++ b/plugins/api-docs/src/components/AsyncApiDefinitionWidget/index.ts @@ -15,3 +15,4 @@ */ export { AsyncApiDefinitionWidget } from './AsyncApiDefinitionWidget'; +export type { AsyncApiDefinitionWidgetProps } from './AsyncApiDefinitionWidget'; diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx index e91387bffa..1f8a796249 100644 --- a/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/GraphQlDefinitionWidget.tsx @@ -29,12 +29,12 @@ export type GraphQlDefinitionWidgetProps = { definition: string; }; -export const GraphQlDefinitionWidget = ({ - definition, -}: GraphQlDefinitionWidgetProps) => { +export const GraphQlDefinitionWidget = ( + props: GraphQlDefinitionWidgetProps, +) => { return ( }> - + ); }; diff --git a/plugins/api-docs/src/components/GraphQlDefinitionWidget/index.ts b/plugins/api-docs/src/components/GraphQlDefinitionWidget/index.ts index 9173f492b0..8645b3c372 100644 --- a/plugins/api-docs/src/components/GraphQlDefinitionWidget/index.ts +++ b/plugins/api-docs/src/components/GraphQlDefinitionWidget/index.ts @@ -15,3 +15,4 @@ */ export { GraphQlDefinitionWidget } from './GraphQlDefinitionWidget'; +export type { GraphQlDefinitionWidgetProps } from './GraphQlDefinitionWidget'; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx index 2c223243d1..606e476454 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinitionWidget.tsx @@ -29,12 +29,12 @@ export type OpenApiDefinitionWidgetProps = { definition: string; }; -export const OpenApiDefinitionWidget = ({ - definition, -}: OpenApiDefinitionWidgetProps) => { +export const OpenApiDefinitionWidget = ( + props: OpenApiDefinitionWidgetProps, +) => { return ( }> - + ); }; diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts index 94401c92a1..e317d42a59 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/index.ts @@ -15,3 +15,4 @@ */ export { OpenApiDefinitionWidget } from './OpenApiDefinitionWidget'; +export type { OpenApiDefinitionWidgetProps } from './OpenApiDefinitionWidget'; diff --git a/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx b/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx index efdd882564..b7f1e8afc0 100644 --- a/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx +++ b/plugins/api-docs/src/components/PlainApiDefinitionWidget/PlainApiDefinitionWidget.tsx @@ -17,13 +17,19 @@ import React from 'react'; import { CodeSnippet } from '@backstage/core-components'; -type Props = { +export type PlainApiDefinitionWidgetProps = { definition: any; language: string; }; -export const PlainApiDefinitionWidget = ({ definition, language }: Props) => { +export const PlainApiDefinitionWidget = ( + props: PlainApiDefinitionWidgetProps, +) => { return ( - + ); }; diff --git a/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts b/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts index c233652981..562a3e67c1 100644 --- a/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts +++ b/plugins/api-docs/src/components/PlainApiDefinitionWidget/index.ts @@ -15,3 +15,4 @@ */ export { PlainApiDefinitionWidget } from './PlainApiDefinitionWidget'; +export type { PlainApiDefinitionWidgetProps } from './PlainApiDefinitionWidget'; diff --git a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx index 8d22293cb1..11d12282d2 100644 --- a/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx +++ b/plugins/scaffolder/src/components/TaskPage/TaskPage.tsx @@ -20,11 +20,11 @@ import { Header, Lifecycle, Page, + Progress, } from '@backstage/core-components'; import { BackstageTheme } from '@backstage/theme'; import { CircularProgress, - LinearProgress, Paper, StepButton, StepIconProps, @@ -215,7 +215,7 @@ export const TaskStatusStepper = memo( const TaskLogger = memo(({ log }: { log: string }) => { return ( - }> + }>
- }> + }> Date: Tue, 2 Nov 2021 10:00:10 +0100 Subject: [PATCH 4/5] Use `` instead of `` in combination with `Suspense` Signed-off-by: Oliver Sand --- .changeset/dull-mangos-count.md | 6 ++++++ .../lib/ActionOutput/ActionOutput.tsx | 4 ++-- .../WorkflowRunLogs/WorkflowRunLogs.tsx | 19 +++++++++---------- 3 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 .changeset/dull-mangos-count.md diff --git a/.changeset/dull-mangos-count.md b/.changeset/dull-mangos-count.md new file mode 100644 index 0000000000..64a01c121d --- /dev/null +++ b/.changeset/dull-mangos-count.md @@ -0,0 +1,6 @@ +--- +'@backstage/plugin-circleci': patch +'@backstage/plugin-github-actions': patch +--- + +Use `` instead of `` in combination with `Suspense`. diff --git a/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx index bbfc1e468c..a4c2af241f 100644 --- a/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx +++ b/plugins/circleci/src/components/BuildWithStepsPage/lib/ActionOutput/ActionOutput.tsx @@ -14,11 +14,11 @@ * limitations under the License. */ +import { Progress } from '@backstage/core-components'; import { Accordion, AccordionDetails, AccordionSummary, - LinearProgress, Typography, } from '@material-ui/core'; import { makeStyles } from '@material-ui/core/styles'; @@ -85,7 +85,7 @@ export const ActionOutput = ({ {messages.length === 0 ? ( 'Nothing here...' ) : ( - }> + }>
diff --git a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx index ce33ae3781..399fed9557 100644 --- a/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx +++ b/plugins/github-actions/src/components/WorkflowRunLogs/WorkflowRunLogs.tsx @@ -14,12 +14,15 @@ * limitations under the License. */ +import { Entity } from '@backstage/catalog-model'; +import { Progress } from '@backstage/core-components'; +import { configApiRef, useApi } from '@backstage/core-plugin-api'; +import { readGitHubIntegrationConfigs } from '@backstage/integration'; import { Accordion, AccordionSummary, CircularProgress, Fade, - LinearProgress, makeStyles, Modal, Theme, @@ -27,15 +30,11 @@ import { Typography, Zoom, } from '@material-ui/core'; - -import React, { Suspense } from 'react'; -import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs'; -import { useProjectName } from '../useProjectName'; -import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import DescriptionIcon from '@material-ui/icons/Description'; -import { Entity } from '@backstage/catalog-model'; -import { readGitHubIntegrationConfigs } from '@backstage/integration'; -import { configApiRef, useApi } from '@backstage/core-plugin-api'; +import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; +import React, { Suspense } from 'react'; +import { useProjectName } from '../useProjectName'; +import { useDownloadWorkflowRunLogs } from './useDownloadWorkflowRunLogs'; const LazyLog = React.lazy(() => import('react-lazylog/build/LazyLog')); const LinePart = React.lazy(() => import('react-lazylog/build/LinePart')); @@ -72,7 +71,7 @@ const DisplayLog = ({ className: string; }) => { return ( - }> + }>
Date: Thu, 11 Nov 2021 11:33:12 +0100 Subject: [PATCH 5/5] Fix styling issues of swagger-ui Signed-off-by: Oliver Sand --- .../OpenApiDefinition.tsx | 108 ++++++++++++------ 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx index cc3df40ae5..4a74b238f7 100644 --- a/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx +++ b/plugins/api-docs/src/components/OpenApiDefinitionWidget/OpenApiDefinition.tsx @@ -21,58 +21,98 @@ import 'swagger-ui-react/swagger-ui.css'; const useStyles = makeStyles(theme => ({ root: { - '& .swagger-ui, .info h1, .info h2, .info h3, .info h4, .info h': { - 'font-family': 'inherit', + '& .swagger-ui': { + fontFamily: 'inherit', color: theme.palette.text.primary, - }, - '& .scheme-container': { - 'background-color': theme.palette.background.default, - }, - '& .opblock-tag, .opblock-tag small, table thead tr td, table thead tr th': - { + + [`& .info h1, + .info h2, + .info h3, + .info h4, + .info h5, + .info h6`]: { + fontFamily: 'inherit', color: theme.palette.text.primary, - 'border-color': theme.palette.divider, }, - '& section.models, section.models.is-open h4': { - 'border-color': theme.palette.divider, - }, - '& .opblock .opblock-summary-description, .parameter__type, table.headers td, .model-title, .model .property.primitive, section h3': - { + [`& .scheme-container`]: { + backgroundColor: theme.palette.background.default, + }, + [`& .opblock-tag, + .opblock-tag small, + table thead tr td, + table thead tr th`]: { + fontFamily: 'inherit', + color: theme.palette.text.primary, + borderColor: theme.palette.divider, + }, + [`& section.models, + section.models.is-open h4`]: { + borderColor: theme.palette.divider, + }, + [`& .opblock .opblock-summary-description, + .parameter__type, + table.headers td, + .model-title, + .model .property.primitive, + section h3`]: { + fontFamily: 'inherit', color: theme.palette.text.secondary, }, - '& .opblock .opblock-summary-operation-id, .opblock .opblock-summary-path, .opblock .opblock-summary-path__deprecated, .opblock .opblock-section-header h4, .parameter__name, .response-col_status, .response-col_links, .responses-inner h4, .swagger-ui .responses-inner h5, .opblock-section-header .btn, .tab li, .info li, .info p, .info table, section.models h4, .info .title, table.model tr.description, .property-row': - { + [`& .opblock .opblock-summary-operation-id, + .opblock .opblock-summary-path, + .opblock .opblock-summary-path__deprecated, + .opblock .opblock-section-header h4, + .parameter__name, + .response-col_status, + .response-col_links, + .responses-inner h4, + .responses-inner h5, + .opblock-section-header .btn, + .tab li, + .info li, + .info p, + .info table, + section.models h4, + .info .title, + table.model tr.description, + .property-row`]: { + fontFamily: 'inherit', color: theme.palette.text.primary, }, - '& .opblock .opblock-section-header, .model-box, section.models .model-container': - { + [`& .opblock .opblock-section-header, + .model-box, + section.models .model-container`]: { background: theme.palette.background.default, }, - '& .prop-format, .parameter__in': { - color: theme.palette.text.disabled, - }, - '& ': { - color: theme.palette.text.primary, - 'border-color': theme.palette.divider, - }, - '& .opblock-description-wrapper p, .opblock-external-docs-wrapper p, .opblock-title_normal p, .response-control-media-type__accept-message, .opblock .opblock-section-header>label, .scheme-container .schemes>label, .info .base-url, .model': - { + [`& .prop-format, + .parameter__in`]: { + color: theme.palette.text.disabled, + }, + [`& .opblock-description-wrapper p, + .opblock-external-docs-wrapper p, + .opblock-title_normal p, + .response-control-media-type__accept-message, + .opblock .opblock-section-header>label, + .scheme-container .schemes>label, + .info .base-url, + .model`]: { color: theme.palette.text.hint, }, - '& .parameter__name.required:after': { - color: theme.palette.warning.dark, - }, - '& .prop-type': { - color: theme.palette.primary.main, + [`& .parameter__name.required:after`]: { + color: theme.palette.warning.dark, + }, + [`& .prop-type`]: { + color: theme.palette.primary.main, + }, }, }, })); -type Props = { +export type OpenApiDefinitionProps = { definition: string; }; -export const OpenApiDefinition = ({ definition }: Props) => { +export const OpenApiDefinition = ({ definition }: OpenApiDefinitionProps) => { const classes = useStyles(); // Due to a bug in the swagger-ui-react component, the component needs