Merge branch 'backstage:master' into awanlin/azure-devops-frontend-plugin

This commit is contained in:
Andre Wanlin
2021-10-12 12:44:13 -05:00
committed by GitHub
237 changed files with 1867 additions and 991 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-api-docs': patch
---
Bump `swagger-ui-react` to `^4.0.0-rc.3`.
+7
View File
@@ -0,0 +1,7 @@
---
'@backstage/core-app-api': patch
'@backstage/core-components': patch
'@backstage/theme': patch
---
Internal refactor to avoid importing all of `@material-ui/core`.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog': patch
---
Support `material-ui` overrides in SystemDiagramCard and EmptityLinksEmptyState components
+15
View File
@@ -0,0 +1,15 @@
---
'@backstage/plugin-home': patch
---
Adds a `<WelcomeTitle>` component that shows a playful greeting on the home page.
To use it, pass it to the home page header:
```typescript
<Page themeId="home">
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
<HomepageTimer />
</Header>
</Page>
```
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': patch
---
Fix search in Firefox. When the search was performed by pressing enter, the query parameter was first set but then reverted back.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/core-components': minor
---
The syntax highlighting library used by the `CodeSnippet` component is now lazy loaded. This most likely has no effect on existing code, but may break tests as the content of the `CodeSnippet` is now rendered asynchronously.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
This change refactors the internal package structure to remove the `next` catalog folder that was used during the implementation and testing phase of the new catalog engine. The implementation is now the default and is therefore restructured to no longer be packaged under `next/`. This refactor does not change catalog imports from other parts of the project.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/cli': patch
---
Update default backend ESLint configuration to allow usage of `__dirname` in tests.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-azure-devops-backend': patch
---
Expands the Azure DevOps backend plugin to provide pull request data to be used by the front end plugin
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Fix `<ComponentTabs>` to display only the selected tab, not the other way around.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-react': patch
---
Support `material-ui` overrides in plugin-catalog-react components
+1
View File
@@ -55,3 +55,4 @@
| [Santagostino](https://santagostino.it) | [@santagostino](https://github.com/santagostino) | Developer portal, gateway to our infrastructure, documentation, service catalog and internal tooling. |
| [Peak](https://peak.ai) | [Luke Beamish](https://github.com/lukebeamish-peak) | Developer portal for all internal engineers to access documentation and tooling. |
| [Gelato](https://gelato.com/) | [Dmitry Makarenko](https://github.com/dmitry-makarenko-gelato) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal and third-party systems🚀. |
| [GoCardless](https://gocardless.com/) | [James Turley](https://github.com/tragiclifestories) | Developer portal: documentation, service templates, org structure, service catalog, plugins for integration with internal systems. |
+4 -3
View File
@@ -129,9 +129,10 @@ In general, changesets are not needed for the documentation, build utilities, co
1. Run `yarn changeset`
2. Select which packages you want to include a changeset for
3. Select impact of change that you're introducing, using `minor` for breaking changes and `patch` otherwise. We do not use `major` changes while packages are at version `0.x`.
4. Add generated changeset to Git
5. Push the commit with your changeset to the branch associated with your PR
6. Accept our gratitude for making the release process easier on the maintainers
4. Explain your changes in the generated changeset. See [examples of well written changesets](https://backstage.io/docs/getting-started/contributors#writing-changesets).
5. Add generated changeset to Git
6. Push the commit with your changeset to the branch associated with your PR
7. Accept our gratitude for making the release process easier on the maintainers
For more information, checkout [adding a changeset](https://github.com/atlassian/changesets/blob/master/docs/adding-a-changeset.md) documentation in the changesets repository.
+89
View File
@@ -139,3 +139,92 @@ default app configs.
You can learn more about the local configuration in
[Static Configuration in Backstage](../conf/) section.
## Writing changesets
Changesets are an important part of the development process. They are used to
generate Changelog entries for all changes to the project. Ultimately they are
read by the end users to learn about important changes and fixes to the project.
Some of these fixes might require manual intervention from users so it's
important to write changesets that users understand and can take action on.
Here are some important do's and don'ts when writing changesets:
### Changeset should give a clear description to what has changed
#### Bad
```
---
'@backstage/catalog': patch
---
Fixed table layout
```
#### Good
```
---
'@backstage/catalog': patch
---
Fixed bug in EntityTable component where table layout did not readjust properly below 1080x768 pixels.
```
### Breaking changes not caught by the type checker should be clearly marked with bold **BREAKING** text
#### Bad
```
---
'@backstage/catalog': minor
---
getEntity is now a function that returns a Promise.
```
#### Good
```
---
'@backstage/catalog': minor
---
**BREAKING** The getEntity function now returns a Promise and **must** be awaited from now on.
```
### Changes to code should include a diff of the files that need updating
#### Bad
```
---
'@backstage/catalog': patch
---
**BREAKING** The catalogEngine now requires a flux capacitor to be passed.
```
#### Good
---
'@backstage/catalog': patch
---
**BREAKING** The catalog createRouter now requires that a `FluxCapacitor` is
passed to the router.
These changes are **required** to `packages/backend/src/plugins/catalog.ts`
```diff
+ import { FluxCapacitor } from '@backstage/time';
+ const fluxCapacitor = new FluxCapacitor();
return await createRouter({
entitiesCatalog,
locationAnalyzer,
locationService,
+ fluxCapacitor,
logger: env.logger,
config: env.config,
});
```
@@ -1,23 +0,0 @@
---
id: installation
title: Google Analytics Installation
sidebar_label: Installation
# prettier-ignore
description: Adding Google Analytics to Your App
---
There is a basic
[Google Analytics](https://marketingplatform.google.com/about/analytics/)
integration built into Backstage. You can enable it by adding the following to
your app configuration:
```yaml
app:
googleAnalyticsTrackingId: UA-000000-0
```
Replace the tracking ID with the one generated for you after signing up for the
Google Analytics service.
The default behavior is only to send a pageview hit. To record more, review the
[Google Analytics developer documentation](https://developers.google.com/analytics/devguides/collection/gtagjs).
+298
View File
@@ -0,0 +1,298 @@
---
id: analytics
title: Plugin Analytics
description: Measuring usage of your Backstage instance.
---
Setting up, maintaining, and iterating on an instance of Backstage can be a
large investment. To help measure return on this investment, Backstage comes
with an event-based Analytics API that grants app integrators the flexibility to
collect and analyze Backstage usage in the analytics tool of their choice, while
providing plugin developers a standard interface for instrumenting key user
interactions.
## Concepts
- **Events** consist of, at a minimum, an `action` (like `click`) and a
`subject` (like `thing that was clicked on`).
- **Attributes** represent additional dimensional data (in the form of key/value
pairs) that may be provided on an event-by-event basis. To continue the above
example, the URL a user clicked to might look like `{ "to": "/a/page" }`.
- **Context** represents the broader context in which an event took place. By
default, information like `pluginId`, `extension`, and `routeRef` are
provided.
This composition of events aims to allow analysis at different levels of detail,
enabling very granular questions (like "what is the most clicked on thing on a
particular route") as well as very high-level questions (like "what is the most
used plugin in my Backstage instance") to be answered.
## Supported Analytics Tools
While all that's needed to consume and forward these events to an analytics tool
is a concrete implementation of [AnalyticsApi][analytics-api-type], common
integrations are packaged and provided as plugins. Find your analytics tool of
choice below.
| Analytics Tool | Support Status |
| ---------------------- | -------------- |
| [Google Analytics][ga] | Yes ✅ |
To suggest an integration, please [open an issue][add-tool] for the analytics
tool your organization uses. Or jump to [Writing Integrations][int-howto] to
learn how to contribute the integration yourself!
[ga]:
https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md
[add-tool]:
https://github.com/backstage/backstage/issues/new?assignees=&labels=plugin&template=plugin_template.md&title=%5BAnalytics+Module%5D+THE+ANALYTICS+TOOL+TO+INTEGRATE
[int-howto]: #writing-integrations
[analytics-api-type]:
https://backstage.io/docs/reference/core-plugin-api.analyticsapi
## Key Events
The following table summarizes events that, depending on the plugins you have
installed, may be captured.
| Action | Provided By | Subject |
| ---------- | -------------- | ----------------------------------------- |
| `navigate` | Backstage Core | The URL of the page that was navigated to |
| `click` | Backstage Core | The text of the link that was clicked on |
If there is an event you'd like to see captured, please [open an
issue][add-event] describing the event you want to see and the questions it
would help you answer. Or jump to [Capturing Events][event-howto] to learn how
to contribute the instrumentation yourself!
_OSS plugin maintainers: feel free to document your events in the table above._
[add-event]:
https://github.com/backstage/backstage/issues/new?assignees=&labels=enhancement&template=feature_template.md&title=[Analytics%20Event]:%20THE+EVENT+TO+CAPTURE
[event-howto]: #capturing-events
## Writing Integrations
Analytics event forwarding is implemented as a Backstage utility API. Just as
you might provide a custom API implementation for errors or SCM Authentication,
you can provide one for analytics.
The provided API need only provide a single method `captureEvent`, which takes
an `AnalyticsEvent` object.
```ts
import {
analyticsApiRef,
AnalyticsEvent,
AnyApiFactory,
createApiFactory,
} from '@backstage/core-plugin-api';
export const apis: AnyApiFactory[] = [
createApiFactory(analyticsApiRef, {
captureEvent: (event: AnalyticsEvent) => {
window._AcmeAnalyticsQ.push(event);
},
}),
];
```
In reality, you would likely want to encapsulate instantiation logic and pull
some details from configuration. A more complete example might look like:
```ts
import {
AnalyticsApi,
analyticsApiRef,
AnalyticsEvent,
AnyApiFactory,
configApiRef,
createApiFactory,
} from '@backstage/core-plugin-api';
import { AcmeAnalytics } from 'acme-analytics';
class AcmeAnalytics implements AnalyticsApi {
private constructor(accountId: number) {
AcmeAnalytics.init(accountId);
}
static fromConfig(config) {
const accountId = config.getString('app.analytics.acme.id');
return new AcmeAnalytics(accountId);
}
captureEvent(event: AnalyticsEvent) {
const { action, ...rest } = event;
AcmeAnalytics.send(action, rest);
}
}
export const apis: AnyApiFactory[] = [
createApiFactory({
api: analyticsApiRef,
deps: { configApi: configApiRef },
factory: ({ configApi }) => AcmeAnalytics.fromConfig(configApi),
}),
];
```
If you are integrating with an analytics service (as opposed to an internal
tool), consider contributing your API implementation as a plugin!
By convention, such packages should be named
`@backstage/analytics-module-[name]`, and any configuration should be keyed
under `app.analytics.[name]`.
## Capturing Events
To instrument an event in a component, start by retrieving an analytics tracker
using the `useAnalytics()` hook provided by `@backstage/core-plugin-api`. The
tracker includes a `captureEvent` method which takes an `action` and a `subject`
as arguments.
```ts
import { useAnalytics } from '@backstage/core-plugin-api';
const analytics = useAnalytics();
analytics.captureEvent('deploy', serviceName);
```
### Providing Extra Attributes
Additional dimensional `attributes` as well as a numeric `value` can be provided
on a third `options` argument if/when relevant for the event:
```ts
analytics.captureEvent('merge', pullRequestName, {
value: pullRequestAgeInMinutes,
attributes: {
org,
repo,
},
});
```
In the above example, an event resembling the following object would be
captured:
```json
{
"action": "merge",
"subject": "Name of Pull Request",
"value": 60,
"attributes": {
"org": "some-org",
"repo": "some-repo"
}
}
```
### Providing Context for Events
The `attributes` option is good for capturing details available to you within
the component that you're instrumenting. For capturing metadata only available
further up the react tree, or to help app integrators aggregate distinct events
by some common value, use an `<AnalyticsContext>`.
```tsx
import { AnalyticsContext, useAnalytics } from '@backstage/core-plugin-api';
const MyComponent = ({ value }) => {
const analytics = useAnalytics();
const handleClick = () => analytics.captureEvent('check', value);
return <SomeThing value={value} onClick={handleClick} />;
};
const MyWrapper = () => {
return (
<AnalyticsContext attributes={{ segment: 'xyz' }}>
<MyComponent value={'Some Value'} />
</AnalyticsContext>
);
};
```
In the above example, clicking on `<SomeThing />` would result in an analytics
event resembling:
```json
{
"action": "check",
"subject": "Some Value",
"context": {
"segment": "xyz"
}
}
```
Note that, for brevity in the example above, the context keys provided by
Backstage core (`pluginId`, `extension`, and `routeRef`) have been omitted. In
reality, those details would be included alongside any additional context
provided by you.
Analytics contexts can be nested; their values are merged down the react tree,
allowing keys to be overwritten.
### Event Naming Considerations
An event is split into its constituent parts to enable analysis at various
levels of granularity. In order to maintain this flexibility at analysis-time,
it's important to keep each of these levels of detail disaggregated.
- Avoid providing an overly specific `action`. For example, instead of
`filterEntityTable`, consider just using `filter` as the action, and allowing
`EntityTable` to be specified as part of the event's `context` (most likely
automatically as part of the `extension` in which the `filter` event was
captured).
- On the flip side, when adding `attributes` to an event, look at existing
events and see if the data you are capturing matches the intention, type, or
even the content of _their_ `attributes`. For instance, it may be common for
events that involve the Catalog to add details like entity `name`, `kind`,
and/or `namespace` as `attributes`. Using the same keys in your event will
ensure that events instrumented across plugins can easily be aggregated.
### Unit Testing Event Capture
The `@backstage/test-utils` package includes a `MockAnalyticsApi` implementation
that you can use in your unit tests to spy on and make assertions about any
analytics events captured.
Use it like this:
```tsx
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
import { analyticsApiRef } from '@backstage/core-plugin-api';
import { MockAnalyticsApi, wrapInTestApp } from '@backstage/test-utils';
import { render, fireEvent, waitFor } from '@testing-library/react';
describe('SomeComponent', () => {
it('should capture event on click', () => {
// Use the Mock Analytics API to spy on event captures.
const apiSpy = new MockAnalyticsApi();
// Render the component being tested
const { getByText } = render(
wrapInTestApp(
<ApiProvider apis={ApiRegistry.from([[analyticsApiRef, apiSpy]])}>
<SomeComponentUnderTest />
</ApiProvider>,
),
);
// Fire the event that triggers event capture.
fireEvent.click(getByText('some component text'));
// Assert that the event was captured with the expected data.
await waitFor(() => {
expect(apiSpy.getEvents()[0]).toMatchObject({
action: 'expected action',
subject: 'expected subject'',
attributes: {
foo: 'bar',
},
});
});
});
});
```
+2 -2
View File
@@ -60,7 +60,7 @@ The YAML file must include the following information. Please note that the
indentation for the `privateKey` is required.
```yaml
appId: 1
appId: app id
clientId: client id
clientSecret: client secret
webhookSecret: webhook secret
@@ -95,7 +95,7 @@ If you want to limit the GitHub app installations visible to backstage you may
optionally include the `allowedInstallationOwners` option.
```yaml
appId: 1
appId: app id
allowedInstallationOwners: ['GlobexCorp']
clientId: client id
clientSecret: client secret
-5
View File
@@ -8,11 +8,6 @@ description: Adding Observability to Your Plugin
This article briefly describes the observability options that are available to a
Backstage integrator.
## Google Analytics
See how to install Google Analytics in your app
[here](../integrations/google-analytics/installation.md)
## Datadog RUM Events
See how to install Datadog Events in your app
@@ -0,0 +1,9 @@
---
title: 'Analytics Module: Google Analytics'
author: Spotify
authorUrl: https://github.com/spotify
category: Analytics
description: Track usage of your Backstage instance using Google Analytics.
documentation: https://github.com/backstage/backstage/blob/master/plugins/analytics-module-ga/README.md
iconUrl: img/ga-icon.png
npmPackageName: '@backstage/plugin-analytics-module-ga'
+13
View File
@@ -0,0 +1,13 @@
---
title: Grafana
author: K-Phoen
authorUrl: https://github.com/K-Phoen
category: Monitoring
description: Associate alerts and dashboards to components.
documentation: https://github.com/K-Phoen/backstage-plugin-grafana/
iconUrl: https://avatars.githubusercontent.com/u/7195757?s=200&v=4
npmPackageName: '@k-phoen/backstage-plugin-grafana'
tags:
- dashboards
- monitoring
- alerting
+1 -5
View File
@@ -154,11 +154,6 @@
"label": "GitLab",
"ids": ["integrations/gitlab/locations"]
},
{
"type": "subcategory",
"label": "Google Analytics",
"ids": ["integrations/google-analytics/installation"]
},
{
"type": "subcategory",
"label": "Google GCS",
@@ -178,6 +173,7 @@
"plugins/structure-of-a-plugin",
"plugins/integrating-plugin-into-software-catalog",
"plugins/composability",
"plugins/analytics",
{
"type": "subcategory",
"label": "Backends and APIs",
Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

+1 -2
View File
@@ -100,8 +100,6 @@ nav:
- Org Data: 'integrations/github/org.md'
- GitLab:
- Locations: 'integrations/gitlab/locations.md'
- Google Analytics:
- Installation: 'integrations/google-analytics/installation.md'
- Google GCS:
- Locations: 'integrations/google-cloud-storage/locations.md'
- LDAP:
@@ -115,6 +113,7 @@ nav:
- Plugin Development: 'plugins/plugin-development.md'
- Integrate into the Software Catalog: 'plugins/integrating-plugin-into-software-catalog.md'
- Composability System: 'plugins/composability.md'
- Plugin Analytics: 'plugins/analytics.md'
- Backends and APIs:
- Proxying: 'plugins/proxying.md'
- Backend plugin: 'plugins/backend-plugin.md'
-2
View File
@@ -61,7 +61,6 @@
"devDependencies": {
"@types/webpack": "^5.28.0",
"@changesets/cli": "^2.14.0",
"@octokit/openapi-types": "^2.2.0",
"@spotify/prettier-config": "^11.0.0",
"command-exists": "^1.2.9",
"concurrently": "^6.0.0",
@@ -71,7 +70,6 @@
"lerna": "^4.0.0",
"lint-staged": "^11.1.2",
"prettier": "^2.2.1",
"recursive-readdir": "^2.2.2",
"shx": "^0.3.2",
"yarn-lock-check": "^1.0.5"
},
+11 -10
View File
@@ -14,25 +14,26 @@
* limitations under the License.
*/
import React from 'react';
import Grid from '@material-ui/core/Grid';
import {
HomePageRandomJoke,
ComponentAccordion,
ComponentTabs,
ComponentTab,
} from '@backstage/plugin-home';
import {
Content,
Header,
Page,
HomepageTimer,
Page,
} from '@backstage/core-components';
import {
ComponentAccordion,
ComponentTab,
ComponentTabs,
HomePageRandomJoke,
WelcomeTitle,
} from '@backstage/plugin-home';
import { HomePageSearchBar } from '@backstage/plugin-search';
import Grid from '@material-ui/core/Grid';
import React from 'react';
export const HomePage = () => (
<Page themeId="home">
<Header title="Home">
<Header title={<WelcomeTitle />} pageTitleOverride="Home">
<HomepageTimer />
</Header>
<Content>
@@ -135,13 +135,7 @@ describe('AwsS3UrlReader', () => {
'getObject',
Buffer.from(
require('fs').readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'awsS3',
'awsS3-mock-object.yaml',
),
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
),
),
);
@@ -187,13 +181,7 @@ describe('AwsS3UrlReader', () => {
'getObject',
Buffer.from(
require('fs').readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'awsS3',
'awsS3-mock-object.yaml',
),
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
),
),
);
@@ -249,13 +237,7 @@ describe('AwsS3UrlReader', () => {
'getObject',
Buffer.from(
require('fs').readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'awsS3',
'awsS3-mock-object.yaml',
),
path.resolve(__dirname, '__fixtures__/awsS3/awsS3-mock-object.yaml'),
),
),
);
@@ -152,7 +152,7 @@ describe('AzureUrlReader', () => {
describe('readTree', () => {
const repoBuffer = fs.readFileSync(
path.resolve('src', 'reading', '__fixtures__', 'mock-main.zip'),
path.resolve(__dirname, '__fixtures__/mock-main.zip'),
);
const processor = new AzureUrlReader(
@@ -264,7 +264,7 @@ describe('AzureUrlReader', () => {
describe('search', () => {
const repoBuffer = fs.readFileSync(
path.resolve('src', 'reading', '__fixtures__', 'mock-main.zip'),
path.resolve(__dirname, '__fixtures__/mock-main.zip'),
);
const processor = new AzureUrlReader(
@@ -104,20 +104,13 @@ describe('BitbucketUrlReader', () => {
describe('readTree', () => {
const repoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'bitbucket-repo-with-commit-hash.tar.gz',
__dirname,
'__fixtures__/bitbucket-repo-with-commit-hash.tar.gz',
),
);
const privateBitbucketRepoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'bitbucket-server-repo.tar.gz',
),
path.resolve(__dirname, '__fixtures__/bitbucket-server-repo.tar.gz'),
);
beforeEach(() => {
@@ -298,10 +291,8 @@ describe('BitbucketUrlReader', () => {
describe('search hosted', () => {
const repoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'bitbucket-repo-with-commit-hash.tar.gz',
__dirname,
'__fixtures__/bitbucket-repo-with-commit-hash.tar.gz',
),
);
@@ -386,12 +377,7 @@ describe('BitbucketUrlReader', () => {
describe('search private', () => {
const privateBitbucketRepoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'bitbucket-server-repo.tar.gz',
),
path.resolve(__dirname, '__fixtures__/bitbucket-server-repo.tar.gz'),
);
beforeEach(() => {
@@ -254,12 +254,7 @@ describe('GithubUrlReader', () => {
describe('readTree', () => {
const repoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'backstage-mock-etag123.tar.gz',
),
path.resolve(__dirname, '__fixtures__/backstage-mock-etag123.tar.gz'),
);
const reposGithubApiResponse = {
@@ -540,12 +535,7 @@ describe('GithubUrlReader', () => {
describe('search', () => {
const repoBuffer = fs.readFileSync(
path.resolve(
'src',
'reading',
'__fixtures__',
'backstage-mock-etag123.tar.gz',
),
path.resolve(__dirname, '__fixtures__/backstage-mock-etag123.tar.gz'),
);
const githubTreeContents: GhTreeResponse['tree'] = [
@@ -223,7 +223,7 @@ describe('GitlabUrlReader', () => {
describe('readTree', () => {
const archiveBuffer = fs.readFileSync(
path.resolve('src', 'reading', '__fixtures__', 'gitlab-archive.tar.gz'),
path.resolve(__dirname, '__fixtures__/gitlab-archive.tar.gz'),
);
const projectGitlabApiResponse = {
@@ -495,7 +495,7 @@ describe('GitlabUrlReader', () => {
describe('search', () => {
const archiveBuffer = fs.readFileSync(
path.resolve('src', 'reading', '__fixtures__', 'gitlab-archive.tar.gz'),
path.resolve(__dirname, '__fixtures__/gitlab-archive.tar.gz'),
);
const projectGitlabApiResponse = {
+2
View File
@@ -46,6 +46,8 @@ describe('paths', () => {
const dir = resolvePath(__dirname, '..');
const root = resolvePath(__dirname, '../../..');
jest.spyOn(process, 'cwd').mockReturnValue(dir);
const paths = findPaths(__dirname);
expect(paths.ownDir).toBe(dir);
+11 -6
View File
@@ -14,6 +14,15 @@
* limitations under the License.
*/
const globalRestrictedSyntax = [
{
message:
'Default import from winston is not allowed, import `* as winston` instead.',
selector:
'ImportDeclaration[source.value="winston"] ImportDefaultSpecifier',
},
];
module.exports = {
extends: [
'@spotify/eslint-config-base',
@@ -69,17 +78,12 @@ module.exports = {
// Avoid default import from winston as it breaks at runtime
'no-restricted-syntax': [
'error',
{
message:
'Default import from winston is not allowed, import `* as winston` instead.',
selector:
'ImportDeclaration[source.value="winston"] ImportDefaultSpecifier',
},
{
message:
"`__dirname` doesn't refer to the same dir in production builds, try `resolvePackagePath()` from `@backstage/backend-common` instead.",
selector: 'Identifier[name="__dirname"]',
},
...globalRestrictedSyntax,
],
},
overrides: [
@@ -103,6 +107,7 @@ module.exports = {
bundledDependencies: true,
},
],
'no-restricted-syntax': ['error', ...globalRestrictedSyntax],
},
},
],
+3 -2
View File
@@ -18,7 +18,7 @@ const fs = require('fs-extra');
const path = require('path');
const glob = require('util').promisify(require('glob'));
async function getProjectConfig(targetPath) {
async function getProjectConfig(targetPath, displayName) {
const configJsPath = path.resolve(targetPath, 'jest.config.js');
const configTsPath = path.resolve(targetPath, 'jest.config.ts');
// If the package has it's own jest config, we use that instead.
@@ -73,6 +73,7 @@ async function getProjectConfig(targetPath) {
const transformModulePattern = transformModules && `(?!${transformModules})`;
const options = {
displayName,
rootDir: path.resolve(targetPath, 'src'),
coverageDirectory: path.resolve(targetPath, 'coverage'),
collectCoverageFrom: ['**/*.{js,jsx,ts,tsx}', '!**/*.d.ts'],
@@ -143,7 +144,7 @@ async function getRootConfig() {
const packageData = await fs.readJson(packagePath);
const testScript = packageData.scripts && packageData.scripts.test;
if (testScript && testScript.includes('backstage-cli test')) {
return await getProjectConfig(projectPath);
return await getProjectConfig(projectPath, packageData.name);
}
return undefined;
@@ -15,7 +15,8 @@
*/
import React, { useMemo, useEffect, useState, PropsWithChildren } from 'react';
import { ThemeProvider, CssBaseline } from '@material-ui/core';
import { ThemeProvider } from '@material-ui/core/styles';
import CssBaseline from '@material-ui/core/CssBaseline';
import { useApi, appThemeApiRef, AppTheme } from '@backstage/core-plugin-api';
import { useObservable } from 'react-use';
+17
View File
@@ -1,8 +1,25 @@
const base = require('@backstage/cli/config/eslint');
const [, baseRestrictedImports] = base.rules['no-restricted-imports'];
module.exports = {
extends: [require.resolve('@backstage/cli/config/eslint')],
rules: {
// TODO: add prop types to JS and remove
'react/prop-types': 0,
'jest/expect-expect': 0,
'no-restricted-imports': [
2,
{
...baseRestrictedImports,
paths: [
{
// Importing the entire MUI icons packages kills build performance as the list of icons is huge.
name: '@material-ui/core',
message: "Please import '@material-ui/core/...' instead.",
},
...baseRestrictedImports.paths,
],
},
],
},
};
+10 -10
View File
@@ -8,9 +8,8 @@
import { ApiRef } from '@backstage/core-plugin-api';
import { BackstageIdentityApi } from '@backstage/core-plugin-api';
import { BackstageTheme } from '@backstage/theme';
import { Breadcrumbs as Breadcrumbs_2 } from '@material-ui/core';
import { ButtonProps as ButtonProps_2 } from '@material-ui/core';
import { CardHeaderProps } from '@material-ui/core';
import { ButtonProps as ButtonProps_2 } from '@material-ui/core/Button';
import { CardHeaderProps } from '@material-ui/core/CardHeader';
import { Column } from '@material-table/core';
import { ComponentClass } from 'react';
import { ComponentProps } from 'react';
@@ -20,9 +19,10 @@ import { CSSProperties } from 'react';
import { ElementType } from 'react';
import { ErrorInfo } from 'react';
import { IconComponent } from '@backstage/core-plugin-api';
import { LinearProgressProps } from '@material-ui/core';
import { LinkProps as LinkProps_2 } from '@material-ui/core';
import { LinearProgressProps } from '@material-ui/core/LinearProgress';
import { LinkProps as LinkProps_2 } from '@material-ui/core/Link';
import { LinkProps as LinkProps_3 } from 'react-router-dom';
import MaterialBreadcrumbs from '@material-ui/core/Breadcrumbs';
import { MaterialTableProps } from '@material-table/core';
import { NavLinkProps } from 'react-router-dom';
import { Overrides } from '@material-ui/core/styles/overrides';
@@ -36,14 +36,14 @@ import { SessionApi } from '@backstage/core-plugin-api';
import { SignInPageProps } from '@backstage/core-plugin-api';
import { SparklinesLineProps } from 'react-sparklines';
import { SparklinesProps } from 'react-sparklines';
import { StyledComponentProps } from '@material-ui/core';
import { StyledComponentProps } from '@material-ui/core/styles';
import { StyleRules } from '@material-ui/styles';
import { StyleRules as StyleRules_2 } from '@material-ui/core/styles/withStyles';
import { TabProps } from '@material-ui/core';
import { TabProps } from '@material-ui/core/Tab';
import { TextTruncateProps } from 'react-text-truncate';
import { Theme } from '@material-ui/core';
import { TooltipProps } from '@material-ui/core';
import { WithStyles } from '@material-ui/core';
import { Theme } from '@material-ui/core/styles';
import { TooltipProps } from '@material-ui/core/Tooltip';
import { WithStyles } from '@material-ui/core/styles';
// Warning: (ae-missing-release-tag) "AlertDisplay" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
@@ -15,7 +15,8 @@
*/
import React, { useEffect, useState } from 'react';
import { Snackbar, IconButton } from '@material-ui/core';
import Snackbar from '@material-ui/core/Snackbar';
import IconButton from '@material-ui/core/IconButton';
import CloseIcon from '@material-ui/icons/Close';
import { Alert } from '@material-ui/lab';
import { AlertMessage, useApi, alertApiRef } from '@backstage/core-plugin-api';
@@ -14,12 +14,8 @@
* limitations under the License.
*/
import React, { CSSProperties } from 'react';
import {
Avatar as MaterialAvatar,
createStyles,
makeStyles,
Theme,
} from '@material-ui/core';
import { createStyles, makeStyles, Theme } from '@material-ui/core/styles';
import MaterialAvatar from '@material-ui/core/Avatar';
import { extractInitials, stringToColor } from './utils';
export type AvatarClassKey = 'avatar';
@@ -17,15 +17,13 @@ import React, { ComponentType } from 'react';
import { Button } from './Button';
import { useLocation } from 'react-router-dom';
import { createRouteRef, useRouteRef } from '@backstage/core-plugin-api';
import {
Divider,
Link,
List,
ListItem,
ListItemText,
Typography,
Button as MaterialButton,
} from '@material-ui/core';
import Divider from '@material-ui/core/Divider';
import Link from '@material-ui/core/Link';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import Typography from '@material-ui/core/Typography';
import MaterialButton from '@material-ui/core/Button';
import { wrapInTestApp } from '@backstage/test-utils';
const routeRef = createRouteRef({
@@ -14,10 +14,9 @@
* limitations under the License.
*/
import {
Button as MaterialButton,
import MaterialButton, {
ButtonProps as MaterialButtonProps,
} from '@material-ui/core';
} from '@material-ui/core/Button';
import React from 'react';
import { Link, LinkProps } from '../Link';
@@ -15,7 +15,7 @@
*/
import React from 'react';
import { Chip } from '@material-ui/core';
import Chip from '@material-ui/core/Chip';
export default {
title: 'Data Display/Chip',
@@ -14,12 +14,56 @@
* limitations under the License.
*/
import React from 'react';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco, dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import { useTheme } from '@material-ui/core';
import React, { lazy, Suspense } from 'react';
import { useTheme } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import { CopyTextButton } from '../CopyTextButton';
import { Progress } from '../Progress';
const LazySyntaxHighlighter = lazy(async () => {
const [{ default: SyntaxHighlighter }, { docco, dark }] = await Promise.all([
import('react-syntax-highlighter'),
import('react-syntax-highlighter/dist/cjs/styles/hljs'),
]);
function LazyHighlighter(props: CodeSnippetProps) {
const {
text,
language,
showLineNumbers = false,
highlightedNumbers,
customStyle,
} = props;
const theme = useTheme<BackstageTheme>();
const mode = theme.palette.type === 'dark' ? dark : docco;
const highlightColor =
theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';
return (
<SyntaxHighlighter
customStyle={customStyle}
language={language}
style={mode}
showLineNumbers={showLineNumbers}
wrapLines
lineNumberStyle={{ color: theme.palette.textVerySubtle }}
lineProps={(lineNumber: number) =>
highlightedNumbers?.includes(lineNumber)
? {
style: {
backgroundColor: highlightColor,
},
}
: {}
}
>
{text}
</SyntaxHighlighter>
);
}
return { default: LazyHighlighter };
});
/**
* Properties for {@link CodeSnippet}
@@ -68,38 +112,12 @@ export interface CodeSnippetProps {
* providing consistent theming and copy code button
*/
export function CodeSnippet(props: CodeSnippetProps) {
const {
text,
language,
showLineNumbers = false,
showCopyCodeButton = false,
highlightedNumbers,
customStyle,
} = props;
const theme = useTheme<BackstageTheme>();
const mode = theme.palette.type === 'dark' ? dark : docco;
const highlightColor = theme.palette.type === 'dark' ? '#256bf3' : '#e6ffed';
const { text, showCopyCodeButton = false } = props;
return (
<div style={{ position: 'relative' }}>
<SyntaxHighlighter
customStyle={customStyle}
language={language}
style={mode}
showLineNumbers={showLineNumbers}
wrapLines
lineNumberStyle={{ color: theme.palette.textVerySubtle }}
lineProps={(lineNumber: number) =>
highlightedNumbers?.includes(lineNumber)
? {
style: {
backgroundColor: highlightColor,
},
}
: {}
}
>
{text}
</SyntaxHighlighter>
<Suspense fallback={<Progress />}>
<LazySyntaxHighlighter {...props} />
</Suspense>
{showCopyCodeButton && (
<div style={{ position: 'absolute', top: 0, right: 0 }}>
<CopyTextButton text={text} />
@@ -15,7 +15,8 @@
*/
import { errorApiRef, useApi } from '@backstage/core-plugin-api';
import { IconButton, Tooltip } from '@material-ui/core';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import CopyIcon from '@material-ui/icons/FileCopy';
import React, { MouseEventHandler, useEffect, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
@@ -15,7 +15,9 @@
*/
import { BackstageTheme } from '@backstage/theme';
import { Button, IconButton, useMediaQuery } from '@material-ui/core';
import Button from '@material-ui/core/Button';
import IconButton from '@material-ui/core/IconButton';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import React from 'react';
import { Link as RouterLink, LinkProps } from 'react-router-dom';
import AddCircleOutline from '@material-ui/icons/AddCircleOutline';
@@ -14,15 +14,13 @@
* limitations under the License.
*/
import {
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
IconButton,
Typography,
} from '@material-ui/core';
import Button from '@material-ui/core/Button';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import CloseIcon from '@material-ui/icons/Close';
import React, { useState } from 'react';
@@ -16,7 +16,8 @@
import React from 'react';
import { DismissableBanner } from './DismissableBanner';
import { Link, Typography } from '@material-ui/core';
import Link from '@material-ui/core/Link';
import Typography from '@material-ui/core/Typography';
import { ApiProvider, ApiRegistry, WebStorage } from '@backstage/core-app-api';
import {
ErrorApi,
@@ -18,7 +18,7 @@ import React, { ReactNode, useState, useEffect } from 'react';
import { useApi, storageApiRef } from '@backstage/core-plugin-api';
import { useObservable } from 'react-use';
import classNames from 'classnames';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import Snackbar from '@material-ui/core/Snackbar';
import SnackbarContent from '@material-ui/core/SnackbarContent';
@@ -15,15 +15,11 @@
*/
import React, { useState } from 'react';
import {
Drawer,
Button,
Typography,
makeStyles,
IconButton,
createStyles,
Theme,
} from '@material-ui/core';
import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import IconButton from '@material-ui/core/IconButton';
import Close from '@material-ui/icons/Close';
export default {
@@ -16,7 +16,7 @@
import React from 'react';
import { EmptyState } from './EmptyState';
import { Button } from '@material-ui/core';
import Button from '@material-ui/core/Button';
import { MissingAnnotationEmptyState } from './MissingAnnotationEmptyState';
export default {
@@ -17,7 +17,7 @@
import React from 'react';
import { EmptyState } from './EmptyState';
import { renderWithEffects, wrapInTestApp } from '@backstage/test-utils';
import { Button } from '@material-ui/core';
import Button from '@material-ui/core/Button';
describe('<EmptyState />', () => {
it('render EmptyState component with type annotaion is missing', async () => {
@@ -15,7 +15,9 @@
*/
import React from 'react';
import { makeStyles, Typography, Grid } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
import Grid from '@material-ui/core/Grid';
import { EmptyStateImage } from './EmptyStateImage';
export type EmptyStateClassKey = 'root' | 'action' | 'imageContainer';
@@ -19,7 +19,7 @@ import missingAnnotation from './assets/missingAnnotation.svg';
import noInformation from './assets/noInformation.svg';
import createComponent from './assets/createComponent.svg';
import noBuild from './assets/noBuild.svg';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
type Props = {
missing: 'field' | 'info' | 'content' | 'data';
@@ -15,7 +15,9 @@
*/
import React from 'react';
import { Button, makeStyles, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import { BackstageTheme } from '@backstage/theme';
import { Link } from '../Link';
import { EmptyState } from './EmptyState';
@@ -14,7 +14,10 @@
* limitations under the License.
*/
import { List, ListItem, ListItemText, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import React, { PropsWithChildren } from 'react';
import { CopyTextButton } from '../CopyTextButton';
import { WarningPanel } from '../WarningPanel';
@@ -14,7 +14,9 @@
* limitations under the License.
*/
import { ClickAwayListener, makeStyles, Typography } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import Typography from '@material-ui/core/Typography';
import React, {
PropsWithChildren,
useCallback,
@@ -15,7 +15,7 @@
*/
import React from 'react';
import { IconLinkVertical, IconLinkVerticalProps } from './IconLinkVertical';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
export type HeaderIconLinkRowClassKey = 'links';
@@ -15,7 +15,8 @@
*/
import React from 'react';
import classnames from 'classnames';
import { makeStyles, Link } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Link from '@material-ui/core/Link';
import LinkIcon from '@material-ui/icons/Link';
import { Link as RouterLink } from '../Link';
@@ -18,7 +18,7 @@ import React from 'react';
import { fireEvent } from '@testing-library/react';
import { renderInTestApp } from '@backstage/test-utils';
import { HorizontalScrollGrid } from './HorizontalScrollGrid';
import { Grid } from '@material-ui/core';
import Grid from '@material-ui/core/Grid';
describe('<HorizontalScrollGrid />', () => {
beforeEach(() => {
@@ -18,7 +18,9 @@ import React, { PropsWithChildren } from 'react';
import classNames from 'classnames';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import { Grid, IconButton, makeStyles, Theme } from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import IconButton from '@material-ui/core/IconButton';
const generateGradientStops = (themeType: 'dark' | 'light') => {
// 97% corresponds to the theme.palette.background.default for the light theme
@@ -16,7 +16,7 @@
import React from 'react';
import CSS from 'csstype';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
type Props = CSS.Properties & {
shorthand?: boolean;
@@ -15,10 +15,9 @@
*/
import { useAnalytics } from '@backstage/core-plugin-api';
import {
Link as MaterialLink,
import MaterialLink, {
LinkProps as MaterialLinkProps,
} from '@material-ui/core';
} from '@material-ui/core/Link';
import React, { ElementType } from 'react';
import {
Link as RouterLink,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import ReactMarkdown from 'react-markdown';
import gfm from 'remark-gfm';
import React from 'react';
@@ -14,15 +14,12 @@
* limitations under the License.
*/
import {
ListItem,
ListItemAvatar,
ListItemText,
makeStyles,
Typography,
Theme,
Button,
} from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import ListItem from '@material-ui/core/ListItem';
import ListItemAvatar from '@material-ui/core/ListItemAvatar';
import ListItemText from '@material-ui/core/ListItemText';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import React, { useState } from 'react';
import { PendingAuthRequest } from '@backstage/core-plugin-api';
@@ -14,16 +14,13 @@
* limitations under the License.
*/
import {
Dialog,
DialogActions,
DialogContent,
DialogTitle,
List,
makeStyles,
Theme,
Button,
} from '@material-ui/core';
import { makeStyles, Theme } from '@material-ui/core/styles';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogTitle from '@material-ui/core/DialogTitle';
import List from '@material-ui/core/List';
import Button from '@material-ui/core/Button';
import React, { useMemo, useState } from 'react';
import { useObservable } from 'react-use';
import LoginRequestListItem from './LoginRequestListItem';
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Box } from '@material-ui/core';
import Box from '@material-ui/core/Box';
import React from 'react';
import { OverflowTooltip } from './OverflowTooltip';
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import { makeStyles, Tooltip, TooltipProps } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Tooltip, { TooltipProps } from '@material-ui/core/Tooltip';
import React, { useState } from 'react';
import TextTruncate, { TextTruncateProps } from 'react-text-truncate';
@@ -15,7 +15,9 @@
*/
import React, { useState, useEffect, PropsWithChildren } from 'react';
import { LinearProgress, LinearProgressProps } from '@material-ui/core';
import LinearProgress, {
LinearProgressProps,
} from '@material-ui/core/LinearProgress';
export function Progress(props: PropsWithChildren<LinearProgressProps>) {
const [isVisible, setIsVisible] = useState(false);
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { makeStyles, useTheme } from '@material-ui/core';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import { Circle } from 'rc-progress';
import React from 'react';
@@ -16,7 +16,7 @@
import React, { PropsWithChildren } from 'react';
import { GaugeCard } from './GaugeCard';
import { Grid } from '@material-ui/core';
import Grid from '@material-ui/core/Grid';
import { MemoryRouter } from 'react-router';
const linkInfo = { title: 'Go to XYZ Location', link: '#' };
@@ -15,7 +15,7 @@
*/
import React from 'react';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { InfoCard, InfoCardVariants } from '../../layout/InfoCard';
import { BottomLinkProps } from '../../layout/BottomLink';
import { Gauge } from './Gauge';
@@ -15,7 +15,8 @@
*/
import React from 'react';
import { Tooltip, useTheme } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';
// @ts-ignore
import { Line } from 'rc-progress';
import { BackstageTheme } from '@backstage/theme';
@@ -15,7 +15,10 @@
*/
import { ResponseError } from '@backstage/errors';
import { Divider, ListItem, ListItemText, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Divider from '@material-ui/core/Divider';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
import React from 'react';
import { CodeSnippet } from '../CodeSnippet';
import { CopyTextButton } from '../CopyTextButton';
@@ -14,16 +14,14 @@
* limitations under the License.
*/
import {
Checkbox,
Chip,
ClickAwayListener,
FormControl,
InputBase,
MenuItem,
Select,
Typography,
} from '@material-ui/core';
import Checkbox from '@material-ui/core/Checkbox';
import Chip from '@material-ui/core/Chip';
import ClickAwayListener from '@material-ui/core/ClickAwayListener';
import FormControl from '@material-ui/core/FormControl';
import InputBase from '@material-ui/core/InputBase';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
import Typography from '@material-ui/core/Typography';
import {
createStyles,
makeStyles,
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { SvgIcon, makeStyles, createStyles } from '@material-ui/core';
import { makeStyles, createStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
export type ClosedDropdownClassKey = 'icon';
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { SvgIcon, makeStyles, createStyles } from '@material-ui/core';
import { makeStyles, createStyles } from '@material-ui/core/styles';
import SvgIcon from '@material-ui/core/SvgIcon';
export type OpenedDropdownClassKey = 'icon';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { TextField } from '@material-ui/core';
import TextField from '@material-ui/core/TextField';
import React, { useState } from 'react';
import { SimpleStepper } from './SimpleStepper';
import { SimpleStepperStep } from './SimpleStepperStep';
@@ -20,7 +20,7 @@ import React, {
useEffect,
PropsWithChildren,
} from 'react';
import { Stepper as MuiStepper } from '@material-ui/core';
import MuiStepper from '@material-ui/core/Stepper';
type InternalState = {
stepperLength: number;
@@ -14,7 +14,8 @@
* limitations under the License.
*/
import React, { useContext, ReactNode, PropsWithChildren } from 'react';
import { Button, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import { StepActions } from './types';
import { VerticalStepperContext } from './SimpleStepper';
@@ -14,13 +14,11 @@
* limitations under the License.
*/
import React, { PropsWithChildren } from 'react';
import {
Step as MuiStep,
StepContent,
StepLabel,
Typography,
makeStyles,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import MuiStep from '@material-ui/core/Step';
import StepContent from '@material-ui/core/StepContent';
import StepLabel from '@material-ui/core/StepLabel';
import Typography from '@material-ui/core/Typography';
import { SimpleStepperFooter } from './SimpleStepperFooter';
import { StepProps } from './types';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
import classNames from 'classnames';
import React, { PropsWithChildren } from 'react';
@@ -16,15 +16,15 @@
import React from 'react';
import {
Table,
TableBody,
TableCell,
TableRow,
withStyles,
createStyles,
WithStyles,
Theme,
} from '@material-ui/core';
} from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableBody from '@material-ui/core/TableBody';
import TableCell from '@material-ui/core/TableCell';
import TableRow from '@material-ui/core/TableRow';
export type MetadataTableTitleCellClassKey = 'root';
@@ -15,7 +15,7 @@
*/
import React, { PropsWithChildren } from 'react';
import { InfoCard } from '../../layout/InfoCard';
import { Grid } from '@material-ui/core';
import Grid from '@material-ui/core/Grid';
import { StructuredMetadataTable } from './StructuredMetadataTable';
const cardContentStyle = { heightX: 200, width: 500 };
@@ -15,7 +15,12 @@
*/
import React, { Fragment, ReactElement } from 'react';
import { withStyles, createStyles, WithStyles, Theme } from '@material-ui/core';
import {
withStyles,
createStyles,
WithStyles,
Theme,
} from '@material-ui/core/styles';
import startCase from 'lodash/startCase';
import {
@@ -16,20 +16,18 @@
import { useApp } from '@backstage/core-plugin-api';
import { BackstageTheme } from '@backstage/theme';
import {
Box,
Button,
DialogActions,
IconButton,
List,
ListItem,
ListItemIcon,
ListItemText,
makeStyles,
Popover,
Typography,
useMediaQuery,
} from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import useMediaQuery from '@material-ui/core/useMediaQuery';
import Box from '@material-ui/core/Box';
import Button from '@material-ui/core/Button';
import DialogActions from '@material-ui/core/DialogActions';
import IconButton from '@material-ui/core/IconButton';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import Popover from '@material-ui/core/Popover';
import Typography from '@material-ui/core/Typography';
import React, { MouseEventHandler, useState } from 'react';
import { SupportItem, SupportItemLink, useSupportConfig } from '../../hooks';
import { HelpIcon } from '../../icons';
@@ -23,7 +23,7 @@ import React, {
ReactNode,
} from 'react';
import { RoutedTabs } from './RoutedTabs';
import { TabProps } from '@material-ui/core';
import { TabProps } from '@material-ui/core/Tab';
type SubRoute = {
path: string;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { TabProps } from '@material-ui/core';
import { TabProps } from '@material-ui/core/Tab';
import * as React from 'react';
export type SubRoute = {
@@ -16,7 +16,8 @@
import React, { useEffect, useState } from 'react';
import { BackstageTheme } from '@backstage/theme';
import { Button, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Button from '@material-ui/core/Button';
import { Select } from '../Select';
import { SelectProps } from '../Select/Select';
@@ -16,7 +16,7 @@
import React from 'react';
import { BackstageTheme } from '@backstage/theme';
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
export type SubvalueCellClassKey = 'value' | 'subvalue';
@@ -14,7 +14,7 @@
* limitations under the License.
*/
import { makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import React from 'react';
import { Link } from '../Link';
import { SubvalueCell, Table, TableColumn } from '.';
@@ -15,13 +15,9 @@
*/
import { BackstageTheme } from '@backstage/theme';
import {
IconButton,
makeStyles,
Typography,
useTheme,
withStyles,
} from '@material-ui/core';
import { makeStyles, useTheme, withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
// Material-table is not using the standard icons available in in material-ui. https://github.com/mbrn/material-table/issues/51
import AddBox from '@material-ui/icons/AddBox';
import ArrowUpward from '@material-ui/icons/ArrowUpward';
@@ -15,7 +15,8 @@
*/
import React from 'react';
import { Tab, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Tab from '@material-ui/core/Tab';
import { BackstageTheme } from '@backstage/theme';
interface StyledTabProps {
@@ -15,7 +15,8 @@
*/
import React, { PropsWithChildren } from 'react';
import { Tabs, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Tabs from '@material-ui/core/Tabs';
import { BackstageTheme } from '@backstage/theme';
interface StyledTabsProps {
@@ -15,7 +15,8 @@
*/
import React from 'react';
import { IconButton, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import { BackstageTheme } from '@backstage/theme';
interface StyledIconProps {
@@ -16,7 +16,7 @@
import React, { useRef, useEffect, MutableRefObject, useState } from 'react';
import { BackstageTheme } from '@backstage/theme';
import { AppBar } from '@material-ui/core';
import AppBar from '@material-ui/core/AppBar';
import { makeStyles } from '@material-ui/core/styles';
import NavigateBeforeIcon from '@material-ui/icons/NavigateBefore';
import NavigateNextIcon from '@material-ui/icons/NavigateNext';
@@ -21,7 +21,7 @@ import {
SparklinesLineProps,
SparklinesProps,
} from 'react-sparklines';
import { useTheme } from '@material-ui/core';
import { useTheme } from '@material-ui/core/styles';
import { BackstageTheme } from '@backstage/theme';
function color(data: number[], theme: BackstageTheme): string | undefined {
@@ -16,7 +16,9 @@
import React from 'react';
import { WarningPanel } from './WarningPanel';
import { Button, Link, Typography } from '@material-ui/core';
import Button from '@material-ui/core/Button';
import Link from '@material-ui/core/Link';
import Typography from '@material-ui/core/Typography';
export default {
title: 'Feedback/Warning Panel',
@@ -17,7 +17,7 @@
import React from 'react';
import { fireEvent, screen } from '@testing-library/react';
import { renderInTestApp } from '@backstage/test-utils';
import { Typography } from '@material-ui/core';
import Typography from '@material-ui/core/Typography';
import { WarningPanel, WarningProps } from './WarningPanel';
@@ -14,16 +14,12 @@
* limitations under the License.
*/
import { BackstageTheme } from '@backstage/theme';
import {
Accordion,
AccordionSummary,
AccordionDetails,
Grid,
makeStyles,
Typography,
darken,
lighten,
} from '@material-ui/core';
import { makeStyles, darken, lighten } from '@material-ui/core/styles';
import Accordion from '@material-ui/core/Accordion';
import AccordionSummary from '@material-ui/core/AccordionSummary';
import AccordionDetails from '@material-ui/core/AccordionDetails';
import Grid from '@material-ui/core/Grid';
import Typography from '@material-ui/core/Typography';
import ErrorOutline from '@material-ui/icons/ErrorOutline';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import React from 'react';
@@ -15,7 +15,9 @@
*/
import React from 'react';
import { Divider, Typography, makeStyles } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import Divider from '@material-ui/core/Divider';
import Typography from '@material-ui/core/Typography';
import ArrowIcon from '@material-ui/icons/ArrowForward';
import { BackstageTheme } from '@backstage/theme';
import Box from '@material-ui/core/Box';
@@ -13,7 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Box, List, ListItem, Popover, Typography } from '@material-ui/core';
import Box from '@material-ui/core/Box';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import Popover from '@material-ui/core/Popover';
import Typography from '@material-ui/core/Typography';
import ExpandLessIcon from '@material-ui/icons/ExpandLess';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import React, { Fragment } from 'react';

Some files were not shown because too many files have changed in this diff Show More