Merge branch 'master' into feat/githubMultiOrgReaderProcessor

This commit is contained in:
Phil Kuang
2021-06-28 09:32:28 -04:00
committed by GitHub
3776 changed files with 22528 additions and 43166 deletions
+31
View File
@@ -1,5 +1,36 @@
# @backstage/plugin-api-docs
## 0.6.0
### Minor Changes
- d719926d2: **BREAKING CHANGE** Remove deprecated route registrations, meaning that it is no longer enough to only import the plugin in the app and the exported page extension must be used instead.
### Patch Changes
- 48c9fcd33: Migrated to use the new `@backstage/core-*` packages rather than `@backstage/core`.
- 7bd46b19d: Move `EntityTypePicker` to be consistent with `CatalogPage` and remove `api:` prefix from entity names
- Updated dependencies
- @backstage/plugin-catalog@0.6.4
- @backstage/core-plugin-api@0.1.3
- @backstage/catalog-model@0.8.4
- @backstage/plugin-catalog-react@0.2.4
## 0.5.0
### Minor Changes
- 2ebc430c4: Rework `ApiExplorerPage` to utilize `EntityListProvider` to provide a consistent UI with the `CatalogIndexPage` which now exposes support for starring entities, pagination, and customizing columns.
### Patch Changes
- 14ce64b4f: Add pagination to ApiExplorerTable
- Updated dependencies
- @backstage/plugin-catalog-react@0.2.3
- @backstage/plugin-catalog@0.6.3
- @backstage/catalog-model@0.8.3
- @backstage/core@0.7.13
## 0.4.15
### Patch Changes
+115
View File
@@ -0,0 +1,115 @@
## API Report File for "@backstage/plugin-api-docs"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { ApiEntity } from '@backstage/catalog-model';
import { ApiRef } from '@backstage/core-plugin-api';
import { BackstagePlugin } from '@backstage/core-plugin-api';
import { CatalogTableRow } from '@backstage/plugin-catalog';
import { Entity } from '@backstage/catalog-model';
import { ExternalRouteRef } from '@backstage/core-plugin-api';
import { default as React_2 } from 'react';
import { RouteRef } from '@backstage/core-plugin-api';
import { TableColumn } from '@backstage/core-components';
import { UserListFilterKind } from '@backstage/plugin-catalog-react';
// @public (undocumented)
export const ApiDefinitionCard: (_: Props) => JSX.Element;
// @public (undocumented)
export type ApiDefinitionWidget = {
type: string;
title: string;
component: (definition: string) => React_2.ReactElement;
rawLanguage?: string;
};
// @public (undocumented)
export const apiDocsConfigRef: ApiRef<ApiDocsConfig>;
// @public (undocumented)
const apiDocsPlugin: BackstagePlugin<{
root: RouteRef<undefined>;
}, {
createComponent: ExternalRouteRef<undefined, true>;
}>;
export { apiDocsPlugin }
export { apiDocsPlugin as plugin }
// @public (undocumented)
export const ApiExplorerPage: ({ initiallySelectedFilter, columns, }: ApiExplorerPageProps) => JSX.Element;
// @public (undocumented)
export const ApiTypeTitle: ({ apiEntity }: {
apiEntity: ApiEntity;
}) => JSX.Element;
// @public (undocumented)
export const AsyncApiDefinitionWidget: ({ definition }: Props_5) => JSX.Element;
// @public (undocumented)
export const ConsumedApisCard: ({ variant }: Props_2) => JSX.Element;
// @public (undocumented)
export const ConsumingComponentsCard: ({ variant }: Props_6) => JSX.Element;
// @public (undocumented)
export function defaultDefinitionWidgets(): ApiDefinitionWidget[];
// @public (undocumented)
export const EntityApiDefinitionCard: (_: {
apiEntity?: ApiEntity | undefined;
}) => JSX.Element;
// @public (undocumented)
export const EntityConsumedApisCard: ({ variant }: {
entity?: Entity| undefined;
variant?: "gridItem" | undefined;
}) => JSX.Element;
// @public (undocumented)
export const EntityConsumingComponentsCard: ({ variant }: {
entity?: Entity| undefined;
variant?: "gridItem" | undefined;
}) => JSX.Element;
// @public (undocumented)
export const EntityHasApisCard: ({ variant }: {
variant?: "gridItem" | undefined;
}) => JSX.Element;
// @public (undocumented)
export const EntityProvidedApisCard: ({ variant }: {
entity?: Entity| undefined;
variant?: "gridItem" | undefined;
}) => JSX.Element;
// @public (undocumented)
export const EntityProvidingComponentsCard: ({ variant }: {
entity?: Entity| undefined;
variant?: "gridItem" | undefined;
}) => JSX.Element;
// @public (undocumented)
export const HasApisCard: ({ variant }: Props_3) => JSX.Element;
// @public (undocumented)
export const OpenApiDefinitionWidget: ({ definition }: Props_8) => JSX.Element;
// @public (undocumented)
export const PlainApiDefinitionWidget: ({ definition, language }: Props_9) => JSX.Element;
// @public (undocumented)
export const ProvidedApisCard: ({ variant }: Props_4) => JSX.Element;
// @public (undocumented)
export const ProvidingComponentsCard: ({ variant }: Props_7) => JSX.Element;
// (No @packageDocumentation comment for this package)
```
+13 -8
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { ApiEntity, Entity } from '@backstage/catalog-model';
import { Content, Header, Page } from '@backstage/core';
import { createDevApp } from '@backstage/dev-utils';
import { catalogApiRef, EntityProvider } from '@backstage/plugin-catalog-react';
import React from 'react';
@@ -29,6 +28,14 @@ import asyncapiApiEntity from './asyncapi-example-api.yaml';
import graphqlApiEntity from './graphql-example-api.yaml';
import openapiApiEntity from './openapi-example-api.yaml';
import otherApiEntity from './other-example-api.yaml';
import { Content, Header, Page } from '@backstage/core-components';
const mockEntities = ([
openapiApiEntity,
asyncapiApiEntity,
graphqlApiEntity,
otherApiEntity,
] as unknown) as Entity[];
createDevApp()
.registerApi({
@@ -38,14 +45,12 @@ createDevApp()
(({
async getEntities() {
return {
items: [
openapiApiEntity,
asyncapiApiEntity,
graphqlApiEntity,
otherApiEntity,
],
items: mockEntities.slice(),
};
},
async getEntityByName(name: string) {
return mockEntities.find(e => e.metadata.name === name);
},
} as unknown) as typeof catalogApiRef.T),
})
.registerApi({
+11 -8
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-api-docs",
"version": "0.4.15",
"version": "0.6.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -30,9 +30,11 @@
},
"dependencies": {
"@asyncapi/react-component": "^0.23.0",
"@backstage/catalog-model": "^0.8.2",
"@backstage/core": "^0.7.11",
"@backstage/plugin-catalog-react": "^0.2.2",
"@backstage/catalog-model": "^0.8.4",
"@backstage/core-components": "^0.1.3",
"@backstage/core-plugin-api": "^0.1.3",
"@backstage/plugin-catalog": "^0.6.4",
"@backstage/plugin-catalog-react": "^0.2.4",
"@backstage/theme": "^0.2.8",
"@material-icons/font": "^1.0.2",
"@material-ui/core": "^4.11.0",
@@ -49,9 +51,10 @@
"swagger-ui-react": "^3.37.2"
},
"devDependencies": {
"@backstage/cli": "^0.7.0",
"@backstage/dev-utils": "^0.1.17",
"@backstage/test-utils": "^0.1.13",
"@backstage/cli": "^0.7.2",
"@backstage/core-app-api": "^0.1.3",
"@backstage/dev-utils": "^0.2.0",
"@backstage/test-utils": "^0.1.14",
"@testing-library/jest-dom": "^5.10.1",
"@testing-library/react": "^11.2.5",
"@testing-library/user-event": "^13.1.8",
@@ -59,7 +62,7 @@
"@types/node": "^14.14.32",
"@types/swagger-ui-react": "^3.23.3",
"cross-fetch": "^3.0.6",
"msw": "^0.21.2"
"msw": "^0.29.0"
},
"files": [
"dist"
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { renderInTestApp } from '@backstage/test-utils';
import { waitFor } from '@testing-library/react';
@@ -23,6 +22,7 @@ import React from 'react';
import { ApiDocsConfig, apiDocsConfigRef } from '../../config';
import { OpenApiDefinitionWidget } from '../OpenApiDefinitionWidget';
import { ApiDefinitionCard } from './ApiDefinitionCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ApiDefinitionCard />', () => {
const apiDocsConfig: jest.Mocked<ApiDocsConfig> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,13 +15,15 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { CardTab, TabbedCard, useApi } from '@backstage/core';
import { useEntity } from '@backstage/plugin-catalog-react';
import { Alert } from '@material-ui/lab';
import React from 'react';
import { apiDocsConfigRef } from '../../config';
import { PlainApiDefinitionWidget } from '../PlainApiDefinitionWidget';
import { CardTab, TabbedCard } from '@backstage/core-components';
import { useApi } from '@backstage/core-plugin-api';
type Props = {
/** @deprecated The entity is now grabbed from context instead */
apiEntity?: ApiEntity;
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,11 +15,11 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import { renderInTestApp } from '@backstage/test-utils';
import React from 'react';
import { ApiDocsConfig, apiDocsConfigRef } from '../../config';
import { ApiTypeTitle } from './ApiTypeTitle';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ApiTypeTitle />', () => {
const apiDocsConfig: jest.Mocked<ApiDocsConfig> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,9 +15,9 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { useApi } from '@backstage/core';
import React from 'react';
import { apiDocsConfigRef } from '../../config';
import { useApi } from '@backstage/core-plugin-api';
export const ApiTypeTitle = ({ apiEntity }: { apiEntity: ApiEntity }) => {
const config = useApi(apiDocsConfigRef);
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,9 +14,11 @@
* limitations under the License.
*/
import { Header, Page, useApi, configApiRef } from '@backstage/core';
import React from 'react';
import { Header, Page } from '@backstage/core-components';
import { useApi, configApiRef } from '@backstage/core-plugin-api';
type Props = {
children?: React.ReactNode;
};
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,15 +14,7 @@
* limitations under the License.
*/
import { Entity } from '@backstage/catalog-model';
import {
ApiProvider,
ApiRegistry,
storageApiRef,
ConfigApi,
configApiRef,
ConfigReader,
} from '@backstage/core';
import { Entity, RELATION_MEMBER_OF } from '@backstage/catalog-model';
import { CatalogApi, catalogApiRef } from '@backstage/plugin-catalog-react';
import { MockStorageApi, wrapInTestApp } from '@backstage/test-utils';
import { render } from '@testing-library/react';
@@ -30,6 +22,17 @@ import React from 'react';
import { apiDocsConfigRef } from '../../config';
import { ApiExplorerPage } from './ApiExplorerPage';
import {
ApiProvider,
ApiRegistry,
ConfigReader,
} from '@backstage/core-app-api';
import {
storageApiRef,
ConfigApi,
configApiRef,
} from '@backstage/core-plugin-api';
describe('ApiCatalogPage', () => {
const catalogApi: Partial<CatalogApi> = {
getEntities: () =>
@@ -55,6 +58,19 @@ describe('ApiCatalogPage', () => {
}),
getLocationByEntity: () =>
Promise.resolve({ id: 'id', type: 'github', target: 'url' }),
getEntityByName: async entityName => {
return {
apiVersion: 'backstage.io/v1alpha1',
kind: 'User',
metadata: { name: entityName.name },
relations: [
{
type: RELATION_MEMBER_OF,
target: { namespace: 'default', kind: 'Group', name: 'tools' },
},
],
};
},
};
const configApi: ConfigApi = new ConfigReader({
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,40 +14,61 @@
* limitations under the License.
*/
import {
EntityKindPicker,
EntityLifecyclePicker,
EntityListProvider,
EntityOwnerPicker,
EntityTagPicker,
EntityTypePicker,
UserListFilterKind,
UserListPicker,
} from '@backstage/plugin-catalog-react';
import { CatalogTable, CatalogTableRow } from '@backstage/plugin-catalog';
import { Button, makeStyles } from '@material-ui/core';
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { createComponentRouteRef } from '../../routes';
import { ApiExplorerLayout } from './ApiExplorerLayout';
import {
Content,
ContentHeader,
SupportButton,
useApi,
useRouteRef,
} from '@backstage/core';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { Button } from '@material-ui/core';
import React from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { useAsync } from 'react-use';
import { createComponentRouteRef } from '../../routes';
import { ApiExplorerTable } from '../ApiExplorerTable';
import { ApiExplorerLayout } from './ApiExplorerLayout';
TableColumn,
} from '@backstage/core-components';
import { useRouteRef } from '@backstage/core-plugin-api';
export const ApiExplorerPage = () => {
const useStyles = makeStyles(theme => ({
contentWrapper: {
display: 'grid',
gridTemplateAreas: "'filters' 'table'",
gridTemplateColumns: '250px 1fr',
gridColumnGap: theme.spacing(2),
},
}));
const defaultColumns: TableColumn<CatalogTableRow>[] = [
CatalogTable.columns.createNameColumn({ defaultKind: 'API' }),
CatalogTable.columns.createSystemColumn(),
CatalogTable.columns.createOwnerColumn(),
CatalogTable.columns.createSpecTypeColumn(),
CatalogTable.columns.createSpecLifecycleColumn(),
CatalogTable.columns.createMetadataDescriptionColumn(),
CatalogTable.columns.createTagsColumn(),
];
export type ApiExplorerPageProps = {
initiallySelectedFilter?: UserListFilterKind;
columns?: TableColumn<CatalogTableRow>[];
};
export const ApiExplorerPage = ({
initiallySelectedFilter = 'all',
columns,
}: ApiExplorerPageProps) => {
const styles = useStyles();
const createComponentLink = useRouteRef(createComponentRouteRef);
const catalogApi = useApi(catalogApiRef);
const { loading, error, value: catalogResponse } = useAsync(() => {
return catalogApi.getEntities({
filter: { kind: 'API' },
fields: [
'apiVersion',
'kind',
'metadata',
'relations',
'spec.lifecycle',
'spec.owner',
'spec.type',
'spec.system',
],
});
}, [catalogApi]);
return (
<ApiExplorerLayout>
@@ -65,11 +86,19 @@ export const ApiExplorerPage = () => {
)}
<SupportButton>All your APIs</SupportButton>
</ContentHeader>
<ApiExplorerTable
entities={catalogResponse?.items ?? []}
loading={loading}
error={error}
/>
<div className={styles.contentWrapper}>
<EntityListProvider>
<div>
<EntityKindPicker initialFilter="api" hidden />
<EntityTypePicker />
<UserListPicker initialFilter={initiallySelectedFilter} />
<EntityOwnerPicker />
<EntityLifecyclePicker />
<EntityTagPicker />
</div>
<CatalogTable columns={columns || defaultColumns} />
</EntityListProvider>
</div>
</Content>
</ApiExplorerLayout>
);
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,81 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* 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 { Entity } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import { wrapInTestApp } from '@backstage/test-utils';
import { render } from '@testing-library/react';
import * as React from 'react';
import { apiDocsConfigRef } from '../../config';
import { ApiExplorerTable } from './ApiExplorerTable';
const entities: Entity[] = [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'API',
metadata: { name: 'api1' },
spec: { type: 'openapi' },
},
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'API',
metadata: { name: 'api2' },
spec: { type: 'openapi' },
},
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'API',
metadata: { name: 'api3' },
spec: { type: 'grpc' },
},
];
const apiRegistry = ApiRegistry.with(apiDocsConfigRef, {
getApiDefinitionWidget: () => undefined,
});
describe('ApiCatalogTable component', () => {
it('should render error message when error is passed in props', async () => {
const rendered = render(
wrapInTestApp(
<ApiProvider apis={apiRegistry}>
<ApiExplorerTable
entities={[]}
loading={false}
error={{ code: 'error' }}
/>
</ApiProvider>,
),
);
const errorMessage = await rendered.findByText(
/Could not fetch catalog entities./,
);
expect(errorMessage).toBeInTheDocument();
});
it('should display entity names when loading has finished and no error occurred', async () => {
const rendered = render(
wrapInTestApp(
<ApiProvider apis={apiRegistry}>
<ApiExplorerTable entities={entities} loading={false} />
</ApiProvider>,
),
);
expect(rendered.getByText(/api1/)).toBeInTheDocument();
expect(rendered.getByText(/api2/)).toBeInTheDocument();
expect(rendered.getByText(/api3/)).toBeInTheDocument();
});
});
@@ -1,214 +0,0 @@
/*
* Copyright 2020 Spotify AB
*
* 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 {
ApiEntityV1alpha1,
Entity,
EntityName,
RELATION_OWNED_BY,
RELATION_PART_OF,
} from '@backstage/catalog-model';
import {
CodeSnippet,
OverflowTooltip,
Table,
TableColumn,
TableFilter,
TableState,
useQueryParamState,
WarningPanel,
} from '@backstage/core';
import {
EntityRefLink,
EntityRefLinks,
formatEntityRefTitle,
getEntityRelations,
} from '@backstage/plugin-catalog-react';
import { Chip } from '@material-ui/core';
import React from 'react';
import { ApiTypeTitle } from '../ApiDefinitionCard';
type EntityRow = {
entity: ApiEntityV1alpha1;
resolved: {
name: string;
partOfSystemRelationTitle?: string;
partOfSystemRelations: EntityName[];
ownedByRelationsTitle?: string;
ownedByRelations: EntityName[];
};
};
const columns: TableColumn<EntityRow>[] = [
{
title: 'Name',
field: 'resolved.name',
highlight: true,
render: ({ entity }) => (
<EntityRefLink entityRef={entity} defaultKind="API" />
),
},
{
title: 'System',
field: 'resolved.partOfSystemRelationTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.partOfSystemRelations}
defaultKind="system"
/>
),
},
{
title: 'Owner',
field: 'resolved.ownedByRelationsTitle',
render: ({ resolved }) => (
<EntityRefLinks
entityRefs={resolved.ownedByRelations}
defaultKind="group"
/>
),
},
{
title: 'Lifecycle',
field: 'entity.spec.lifecycle',
},
{
title: 'Type',
field: 'entity.spec.type',
render: ({ entity }) => <ApiTypeTitle apiEntity={entity} />,
},
{
title: 'Description',
field: 'entity.metadata.description',
render: ({ entity }) => (
<OverflowTooltip
text={entity.metadata.description}
placement="bottom-start"
/>
),
width: 'auto',
},
{
title: 'Tags',
field: 'entity.metadata.tags',
cellStyle: {
padding: '0px 16px 0px 20px',
},
render: ({ entity }) => (
<>
{entity.metadata.tags &&
entity.metadata.tags.map(t => (
<Chip
key={t}
label={t}
size="small"
variant="outlined"
style={{ marginBottom: '0px' }}
/>
))}
</>
),
},
];
const filters: TableFilter[] = [
{
column: 'Owner',
type: 'select',
},
{
column: 'Type',
type: 'multiple-select',
},
{
column: 'Lifecycle',
type: 'multiple-select',
},
{
column: 'Tags',
type: 'checkbox-tree',
},
];
type ExplorerTableProps = {
entities: Entity[];
loading: boolean;
error?: any;
};
export const ApiExplorerTable = ({
entities,
loading,
error,
}: ExplorerTableProps) => {
const [queryParamState, setQueryParamState] = useQueryParamState<TableState>(
'apiTable',
);
if (error) {
return (
<WarningPanel severity="error" title="Could not fetch catalog entities.">
<CodeSnippet language="text" text={error.toString()} />
</WarningPanel>
);
}
const rows = entities.map(entity => {
const partOfSystemRelations = getEntityRelations(entity, RELATION_PART_OF, {
kind: 'system',
});
const ownedByRelations = getEntityRelations(entity, RELATION_OWNED_BY);
return {
entity: entity as ApiEntityV1alpha1,
resolved: {
name: formatEntityRefTitle(entity, {
defaultKind: 'API',
}),
ownedByRelationsTitle: ownedByRelations
.map(r => formatEntityRefTitle(r, { defaultKind: 'group' }))
.join(', '),
ownedByRelations,
partOfSystemRelationTitle: partOfSystemRelations
.map(r =>
formatEntityRefTitle(r, {
defaultKind: 'system',
}),
)
.join(', '),
partOfSystemRelations,
},
};
});
return (
<Table<EntityRow>
isLoading={loading}
columns={columns}
options={{
paging: false,
actionsColumnIndex: -1,
loadingType: 'linear',
padding: 'dense',
showEmptyDataSourceMessage: !loading,
}}
data={rows}
filters={filters}
initialState={queryParamState}
onStateChange={setQueryParamState}
/>
);
};
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { Entity, RELATION_CONSUMES_API } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import {
CatalogApi,
catalogApiRef,
@@ -26,6 +25,7 @@ import { waitFor } from '@testing-library/react';
import React from 'react';
import { ApiDocsConfig, apiDocsConfigRef } from '../../config';
import { ConsumedApisCard } from './ConsumedApisCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ConsumedApisCard />', () => {
const apiDocsConfig: jest.Mocked<ApiDocsConfig> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -19,13 +19,6 @@ import {
Entity,
RELATION_CONSUMES_API,
} from '@backstage/catalog-model';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core';
import { Typography } from '@material-ui/core';
import {
EntityTable,
@@ -34,6 +27,13 @@ import {
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { apiEntityColumns } from './presets';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core-components';
type Props = {
/** @deprecated The entity is now grabbed from context instead */
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { Entity, RELATION_HAS_PART } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import {
CatalogApi,
catalogApiRef,
@@ -26,6 +25,7 @@ import { waitFor } from '@testing-library/react';
import React from 'react';
import { ApiDocsConfig, apiDocsConfigRef } from '../../config';
import { HasApisCard } from './HasApisCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<HasApisCard />', () => {
const apiDocsConfig: jest.Mocked<ApiDocsConfig> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,14 +15,6 @@
*/
import { ApiEntity, RELATION_HAS_PART } from '@backstage/catalog-model';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
TableColumn,
WarningPanel,
} from '@backstage/core';
import { Typography } from '@material-ui/core';
import {
EntityTable,
@@ -31,6 +23,14 @@ import {
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { createSpecApiTypeColumn } from './presets';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
TableColumn,
WarningPanel,
} from '@backstage/core-components';
type Props = {
variant?: 'gridItem';
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { Entity, RELATION_PROVIDES_API } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import {
CatalogApi,
catalogApiRef,
@@ -26,6 +25,7 @@ import { waitFor } from '@testing-library/react';
import React from 'react';
import { ApiDocsConfig, apiDocsConfigRef } from '../../config';
import { ProvidedApisCard } from './ProvidedApisCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ProvidedApisCard />', () => {
const apiDocsConfig: jest.Mocked<ApiDocsConfig> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -19,13 +19,6 @@ import {
Entity,
RELATION_PROVIDES_API,
} from '@backstage/catalog-model';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core';
import { Typography } from '@material-ui/core';
import {
EntityTable,
@@ -34,6 +27,13 @@ import {
} from '@backstage/plugin-catalog-react';
import React from 'react';
import { apiEntityColumns } from './presets';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core-components';
type Props = {
/** @deprecated The entity is now grabbed from context instead */
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,10 +15,10 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { TableColumn } from '@backstage/core';
import { EntityTable } from '@backstage/plugin-catalog-react';
import React from 'react';
import { ApiTypeTitle } from '../ApiDefinitionCard';
import { TableColumn } from '@backstage/core-components';
export function createSpecApiTypeColumn(): TableColumn<ApiEntity> {
return {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { Entity, RELATION_API_CONSUMED_BY } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import {
CatalogApi,
catalogApiRef,
@@ -25,6 +24,7 @@ import { renderInTestApp } from '@backstage/test-utils';
import { waitFor } from '@testing-library/react';
import React from 'react';
import { ConsumingComponentsCard } from './ConsumingComponentsCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ConsumingComponentsCard />', () => {
const catalogApi: jest.Mocked<CatalogApi> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -19,13 +19,6 @@ import {
Entity,
RELATION_API_CONSUMED_BY,
} from '@backstage/catalog-model';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core';
import { Typography } from '@material-ui/core';
import {
EntityTable,
@@ -33,6 +26,13 @@ import {
useRelatedEntities,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core-components';
type Props = {
/** @deprecated The entity is now grabbed from context instead */
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,7 +15,6 @@
*/
import { Entity, RELATION_API_PROVIDED_BY } from '@backstage/catalog-model';
import { ApiProvider, ApiRegistry } from '@backstage/core';
import {
CatalogApi,
catalogApiRef,
@@ -25,6 +24,7 @@ import { renderInTestApp } from '@backstage/test-utils';
import { waitFor } from '@testing-library/react';
import React from 'react';
import { ProvidingComponentsCard } from './ProvidingComponentsCard';
import { ApiProvider, ApiRegistry } from '@backstage/core-app-api';
describe('<ProvidingComponentsCard />', () => {
const catalogApi: jest.Mocked<CatalogApi> = {
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -19,13 +19,6 @@ import {
Entity,
RELATION_API_PROVIDED_BY,
} from '@backstage/catalog-model';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core';
import { Typography } from '@material-ui/core';
import {
EntityTable,
@@ -33,6 +26,13 @@ import {
useRelatedEntities,
} from '@backstage/plugin-catalog-react';
import React from 'react';
import {
CodeSnippet,
InfoCard,
Link,
Progress,
WarningPanel,
} from '@backstage/core-components';
type Props = {
/** @deprecated The entity is now grabbed from context instead */
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,12 +14,12 @@
* limitations under the License.
*/
import { Progress } from '@backstage/core';
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';
const GraphiQL = React.lazy(() => import('graphiql'));
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,8 +14,8 @@
* limitations under the License.
*/
import { CodeSnippet } from '@backstage/core';
import React from 'react';
import { CodeSnippet } from '@backstage/core-components';
type Props = {
definition: any;
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,8 +15,8 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { createApiRef } from '@backstage/core';
import { ApiDefinitionWidget } from './components/ApiDefinitionCard/ApiDefinitionWidget';
import { createApiRef } from '@backstage/core-plugin-api';
export const apiDocsConfigRef = createApiRef<ApiDocsConfig>({
id: 'plugin.api-docs.config',
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+5 -9
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,16 +15,15 @@
*/
import { ApiEntity } from '@backstage/catalog-model';
import { defaultDefinitionWidgets } from './components/ApiDefinitionCard';
import { apiDocsConfigRef } from './config';
import { createComponentRouteRef, rootRoute } from './routes';
import {
createApiFactory,
createComponentExtension,
createPlugin,
createRoutableExtension,
} from '@backstage/core';
import { defaultDefinitionWidgets } from './components/ApiDefinitionCard';
import { ApiExplorerPage as Page } from './components/ApiExplorerPage/ApiExplorerPage';
import { apiDocsConfigRef } from './config';
import { createComponentRouteRef, rootRoute } from './routes';
} from '@backstage/core-plugin-api';
export const apiDocsPlugin = createPlugin({
id: 'api-docs',
@@ -48,9 +47,6 @@ export const apiDocsPlugin = createPlugin({
externalRoutes: {
createComponent: createComponentRouteRef,
},
register({ router }) {
router.addRoute(rootRoute, Page);
},
});
export const ApiExplorerPage = apiDocsPlugin.provide(
+5 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -14,7 +14,10 @@
* limitations under the License.
*/
import { createExternalRouteRef, createRouteRef } from '@backstage/core';
import {
createExternalRouteRef,
createRouteRef,
} from '@backstage/core-plugin-api';
const NoIcon = () => null;
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+9
View File
@@ -1,5 +1,14 @@
# @backstage/plugin-app-backend
## 0.3.14
### Patch Changes
- 3108ff7bf: Make `yarn dev` respect the `PLUGIN_PORT` environment variable.
- Updated dependencies
- @backstage/backend-common@0.8.3
- @backstage/config-loader@0.6.4
## 0.3.13
### Patch Changes
+28
View File
@@ -0,0 +1,28 @@
## API Report File for "@backstage/plugin-app-backend"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { Config } from '@backstage/config';
import express from 'express';
import { Logger } from 'winston';
// @public (undocumented)
export function createRouter(options: RouterOptions): Promise<express.Router>;
// @public (undocumented)
export interface RouterOptions {
appPackageName: string;
// (undocumented)
config: Config;
disableConfigInjection?: boolean;
// (undocumented)
logger: Logger;
staticFallbackHandler?: express.Handler;
}
// (No @packageDocumentation comment for this package)
```
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-app-backend",
"version": "0.3.13",
"version": "0.3.14",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -29,8 +29,8 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.8.2",
"@backstage/config-loader": "^0.6.1",
"@backstage/backend-common": "^0.8.3",
"@backstage/config-loader": "^0.6.4",
"@backstage/config": "^0.1.5",
"@types/express": "^4.17.6",
"express": "^4.17.1",
@@ -40,9 +40,9 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.7.0",
"@backstage/cli": "^0.7.1",
"@types/supertest": "^2.0.8",
"msw": "^0.20.5",
"msw": "^0.29.0",
"supertest": "^6.1.3"
},
"files": [
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -38,7 +38,9 @@ export async function startStandaloneServer(
appPackageName: 'example-app',
});
const service = createServiceBuilder(module).addRouter('', router);
const service = createServiceBuilder(module)
.setPort(options.port)
.addRouter('', router);
return await service.start().catch(err => {
logger.error(err);
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+41
View File
@@ -1,5 +1,46 @@
# @backstage/plugin-auth-backend
## 0.3.14
### Patch Changes
- 36e9a4084: Don't export the `defaultGoogleAuthProvider`
- c467cc4b9: Adds support for custom sign-in resolvers and profile transformations for the
Google auth provider.
Adds an `ent` claim in Backstage tokens, with a list of
[entity references](https://backstage.io/docs/features/software-catalog/references)
related to your signed-in user's identities and groups across multiple systems.
Adds an optional `providerFactories` argument to the `createRouter` exported by
the `auth-backend` plugin.
Updates `BackstageIdentity` so that
- `idToken` is deprecated in favor of `token`
- An optional `entity` field is added which represents the entity that the user is represented by within Backstage.
More information:
- [The identity resolver documentation](https://backstage.io/docs/auth/identity-resolver)
explains the concepts and shows how to implement your own.
- The [From Identity to Ownership](https://github.com/backstage/backstage/issues/4089)
RFC contains details about how this affects ownership in the catalog
- Updated dependencies
- @backstage/catalog-client@0.3.14
- @backstage/catalog-model@0.8.4
- @backstage/test-utils@0.1.14
## 0.3.13
### Patch Changes
- 1aa31f0af: Add support for refreshing GitLab auth sessions.
- Updated dependencies
- @backstage/backend-common@0.8.3
- @backstage/catalog-model@0.8.3
## 0.3.12
### Patch Changes
+229
View File
@@ -0,0 +1,229 @@
## API Report File for "@backstage/plugin-auth-backend"
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { CatalogApi } from '@backstage/catalog-client';
import { Config } from '@backstage/config';
import { Entity } from '@backstage/catalog-model';
import express from 'express';
import { JSONWebKey } from 'jose';
import { Logger } from 'winston';
import { PluginDatabaseManager } from '@backstage/backend-common';
import { PluginEndpointDiscovery } from '@backstage/backend-common';
import { Profile } from 'passport';
import { UserEntity } from '@backstage/catalog-model';
// @public (undocumented)
export type AuthProviderFactory = (options: AuthProviderFactoryOptions) => AuthProviderRouteHandlers;
// @public (undocumented)
export type AuthProviderFactoryOptions = {
providerId: string;
globalConfig: AuthProviderConfig;
config: Config;
logger: Logger;
tokenIssuer: TokenIssuer;
discovery: PluginEndpointDiscovery;
catalogApi: CatalogApi;
identityResolver?: ExperimentalIdentityResolver;
};
// @public
export interface AuthProviderRouteHandlers {
frameHandler(req: express.Request, res: express.Response): Promise<void>;
logout?(req: express.Request, res: express.Response): Promise<void>;
refresh?(req: express.Request, res: express.Response): Promise<void>;
start(req: express.Request, res: express.Response): Promise<void>;
}
// @public (undocumented)
export type AuthResponse<ProviderInfo> = {
providerInfo: ProviderInfo;
profile: ProfileInfo;
backstageIdentity?: BackstageIdentity;
};
// @public (undocumented)
export type BackstageIdentity = {
id: string;
idToken?: string;
token?: string;
entity?: Entity;
};
// @public (undocumented)
export const createGoogleProvider: (options?: GoogleProviderOptions | undefined) => AuthProviderFactory;
// @public (undocumented)
export function createRouter({ logger, config, discovery, database, providerFactories, }: RouterOptions): Promise<express.Router>;
// @public (undocumented)
export const defaultAuthProviderFactories: {
[providerId: string]: AuthProviderFactory;
};
// @public (undocumented)
export const encodeState: (state: OAuthState) => string;
// @public (undocumented)
export const ensuresXRequestedWith: (req: express.Request) => boolean;
// @public (undocumented)
export const googleEmailSignInResolver: SignInResolver<OAuthResult>;
// @public (undocumented)
export type GoogleProviderOptions = {
authHandler?: AuthHandler<OAuthResult>;
signIn?: {
resolver?: SignInResolver<OAuthResult>;
};
};
// @public
export class IdentityClient {
constructor(options: {
discovery: PluginEndpointDiscovery;
issuer: string;
});
authenticate(token: string | undefined): Promise<BackstageIdentity>;
static getBearerToken(authorizationHeader: string | undefined): string | undefined;
listPublicKeys(): Promise<{
keys: JSONWebKey[];
}>;
}
// @public (undocumented)
export class OAuthAdapter implements AuthProviderRouteHandlers {
constructor(handlers: OAuthHandlers, options: Options);
// (undocumented)
frameHandler(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
static fromConfig(config: AuthProviderConfig, handlers: OAuthHandlers, options: Pick<Options, 'providerId' | 'persistScopes' | 'disableRefresh' | 'tokenIssuer'>): OAuthAdapter;
// (undocumented)
logout(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
refresh(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
start(req: express.Request, res: express.Response): Promise<void>;
}
// @public (undocumented)
export class OAuthEnvironmentHandler implements AuthProviderRouteHandlers {
constructor(handlers: Map<string, AuthProviderRouteHandlers>);
// (undocumented)
frameHandler(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
logout(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
static mapConfig(config: Config, factoryFunc: (envConfig: Config) => AuthProviderRouteHandlers): OAuthEnvironmentHandler;
// (undocumented)
refresh(req: express.Request, res: express.Response): Promise<void>;
// (undocumented)
start(req: express.Request, res: express.Response): Promise<void>;
}
// @public
export interface OAuthHandlers {
handler(req: express.Request): Promise<{
response: AuthResponse<OAuthProviderInfo>;
refreshToken?: string;
}>;
logout?(): Promise<void>;
refresh?(req: OAuthRefreshRequest): Promise<AuthResponse<OAuthProviderInfo>>;
start(req: OAuthStartRequest): Promise<RedirectInfo>;
}
// @public (undocumented)
export type OAuthProviderInfo = {
accessToken: string;
idToken?: string;
expiresInSeconds?: number;
scope: string;
refreshToken?: string;
};
// @public
export type OAuthProviderOptions = {
clientId: string;
clientSecret: string;
callbackUrl: string;
};
// @public (undocumented)
export type OAuthRefreshRequest = express.Request<{}> & {
scope: string;
refreshToken: string;
};
// @public (undocumented)
export type OAuthResponse = AuthResponse<OAuthProviderInfo>;
// @public (undocumented)
export type OAuthResult = {
fullProfile: Profile;
params: {
id_token?: string;
scope: string;
expires_in: number;
};
accessToken: string;
refreshToken?: string;
};
// @public (undocumented)
export type OAuthStartRequest = express.Request<{}> & {
scope: string;
state: OAuthState;
};
// @public (undocumented)
export type OAuthState = {
nonce: string;
env: string;
};
// @public (undocumented)
export const postMessageResponse: (res: express.Response, appOrigin: string, response: WebMessageResponse) => void;
// @public
export type ProfileInfo = {
email?: string;
displayName?: string;
picture?: string;
};
// @public (undocumented)
export const readState: (stateString: string) => OAuthState;
// @public (undocumented)
export interface RouterOptions {
// (undocumented)
config: Config;
// (undocumented)
database: PluginDatabaseManager;
// (undocumented)
discovery: PluginEndpointDiscovery;
// (undocumented)
logger: Logger;
// (undocumented)
providerFactories?: ProviderFactories;
}
// @public (undocumented)
export const verifyNonce: (req: express.Request, providerId: string) => void;
// @public
export type WebMessageResponse = {
type: 'authorization_response';
response: AuthResponse<unknown>;
} | {
type: 'authorization_response';
error: Error;
};
// (No @packageDocumentation comment for this package)
```
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-auth-backend",
"version": "0.3.12",
"version": "0.3.14",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
@@ -29,12 +29,12 @@
"clean": "backstage-cli clean"
},
"dependencies": {
"@backstage/backend-common": "^0.8.2",
"@backstage/catalog-client": "^0.3.13",
"@backstage/catalog-model": "^0.8.2",
"@backstage/backend-common": "^0.8.3",
"@backstage/catalog-client": "^0.3.14",
"@backstage/catalog-model": "^0.8.4",
"@backstage/config": "^0.1.5",
"@backstage/errors": "^0.1.1",
"@backstage/test-utils": "^0.1.12",
"@backstage/test-utils": "^0.1.14",
"@types/express": "^4.17.6",
"@types/passport": "^1.0.3",
"compression": "^1.7.4",
@@ -68,7 +68,7 @@
"yn": "^4.0.0"
},
"devDependencies": {
"@backstage/cli": "^0.7.0",
"@backstage/cli": "^0.7.2",
"@types/body-parser": "^1.19.0",
"@types/cookie-parser": "^1.4.2",
"@types/express-session": "^1.17.2",
@@ -79,7 +79,7 @@
"@types/passport-saml": "^1.1.2",
"@types/passport-strategy": "^0.2.35",
"@types/xml2js": "^0.4.7",
"msw": "^0.21.2"
"msw": "^0.29.0"
},
"files": [
"dist",
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -67,13 +67,14 @@ export class TokenFactory implements TokenIssuer {
const iss = this.issuer;
const sub = params.claims.sub;
const ent = params.claims.ent;
const aud = 'backstage';
const iat = Math.floor(Date.now() / MS_IN_S);
const exp = iat + this.keyDurationSeconds;
this.logger.info(`Issuing token for ${sub}`);
this.logger.info(`Issuing token for ${sub}, with entities ${ent ?? []}`);
return JWS.sign({ iss, sub, aud, iat, exp }, key, {
return JWS.sign({ iss, sub, aud, iat, exp, ent }, key, {
alg: key.alg,
kid: key.kid,
});
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+3 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -28,6 +28,8 @@ export type TokenParams = {
claims: {
/** The token subject, i.e. User ID */
sub: string;
/** A list of entity references that the user claims ownership through */
ent?: string[];
};
};
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -16,6 +16,7 @@
import { CatalogApi } from '@backstage/catalog-client';
import { UserEntity } from '@backstage/catalog-model';
import { TokenIssuer } from '../../identity';
import { CatalogIdentityClient } from './CatalogIdentityClient';
describe('CatalogIdentityClient', () => {
@@ -29,25 +30,36 @@ describe('CatalogIdentityClient', () => {
getLocationByEntity: jest.fn(),
removeEntityByUid: jest.fn(),
};
const tokenIssuer: jest.Mocked<TokenIssuer> = {
issueToken: jest.fn(),
listPublicKeys: jest.fn(),
};
afterEach(() => jest.resetAllMocks());
it('passes through the correct search params', async () => {
catalogApi.getEntities.mockResolvedValueOnce({ items: [{} as UserEntity] });
tokenIssuer.issueToken.mockResolvedValue('my-token');
const client = new CatalogIdentityClient({
catalogApi: catalogApi as CatalogApi,
catalogApi: catalogApi,
tokenIssuer: tokenIssuer,
});
client.findUser({ annotations: { key: 'value' } });
await client.findUser({ annotations: { key: 'value' } });
expect(catalogApi.getEntities).toBeCalledWith(
expect(catalogApi.getEntities).toHaveBeenCalledWith(
{
filter: {
kind: 'user',
'metadata.annotations.key': 'value',
},
},
undefined,
{ token: 'my-token' },
);
expect(tokenIssuer.issueToken).toHaveBeenCalledWith({
claims: {
sub: 'backstage.io/auth-backend',
},
});
});
});
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -17,6 +17,7 @@
import { ConflictError, NotFoundError } from '@backstage/errors';
import { CatalogApi } from '@backstage/catalog-client';
import { UserEntity } from '@backstage/catalog-model';
import { TokenIssuer } from '../../identity';
type UserQuery = {
annotations: Record<string, string>;
@@ -27,9 +28,11 @@ type UserQuery = {
*/
export class CatalogIdentityClient {
private readonly catalogApi: CatalogApi;
private readonly tokenIssuer: TokenIssuer;
constructor(options: { catalogApi: CatalogApi }) {
constructor(options: { catalogApi: CatalogApi; tokenIssuer: TokenIssuer }) {
this.catalogApi = options.catalogApi;
this.tokenIssuer = options.tokenIssuer;
}
/**
@@ -37,10 +40,7 @@ export class CatalogIdentityClient {
*
* Throws a NotFoundError or ConflictError if 0 or multiple users are found.
*/
async findUser(
query: UserQuery,
options?: { token?: string },
): Promise<UserEntity> {
async findUser(query: UserQuery): Promise<UserEntity> {
const filter: Record<string, string> = {
kind: 'user',
};
@@ -48,7 +48,11 @@ export class CatalogIdentityClient {
filter[`metadata.annotations.${key}`] = value;
}
const { items } = await this.catalogApi.getEntities({ filter }, options);
// TODO(Rugvip): cache the token
const token = await this.tokenIssuer.issueToken({
claims: { sub: 'backstage.io/auth-backend' },
});
const { items } = await this.catalogApi.getEntities({ filter }, { token });
if (items.length !== 1) {
if (items.length > 1) {
@@ -0,0 +1,40 @@
/*
* Copyright 2021 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 {
RELATION_MEMBER_OF,
stringifyEntityRef,
UserEntity,
} from '@backstage/catalog-model';
import { TokenParams } from '../../identity';
export function getEntityClaims(entity: UserEntity): TokenParams['claims'] {
const userRef = stringifyEntityRef(entity);
const membershipRefs =
entity.relations
?.filter(
r =>
r.type === RELATION_MEMBER_OF &&
r.target.kind.toLocaleLowerCase('en-US') === 'group',
)
.map(r => stringifyEntityRef(r.target)) ?? [];
return {
sub: userRef,
ent: [userRef, ...membershipRefs],
};
}
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -15,3 +15,4 @@
*/
export { CatalogIdentityClient } from './CatalogIdentityClient';
export { getEntityClaims } from './helpers';
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
+1 -1
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Spotify AB
* Copyright 2021 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Spotify AB
* Copyright 2021 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.
@@ -1,5 +1,5 @@
/*
* Copyright 2020 Spotify AB
* 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.

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