Merge remote-tracking branch 'origin/master' into enhance-schema-validator
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-backend-module-aws': patch
|
||||
---
|
||||
|
||||
Update to import `LocationSpec` from the correct package.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/cli': patch
|
||||
---
|
||||
|
||||
Fixed Webpack loader patterns so that they properly match the file suffix only.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'@backstage/plugin-search': patch
|
||||
---
|
||||
|
||||
Implement a `showCounts` option to display result counts per type in `SearchType.Accordion`
|
||||
@@ -79,6 +79,7 @@ const SearchPage = () => {
|
||||
<SearchType.Accordion
|
||||
name="Result Type"
|
||||
defaultValue="software-catalog"
|
||||
showCounts
|
||||
types={[
|
||||
{
|
||||
value: 'software-catalog',
|
||||
|
||||
@@ -107,7 +107,7 @@ export const transforms = (options: TransformOptions): Transforms => {
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(js|mjs|cjs)/,
|
||||
test: /\.(js|mjs|cjs)$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
@@ -141,9 +141,10 @@ export const transforms = (options: TransformOptions): Transforms => {
|
||||
/\.gif$/,
|
||||
/\.jpe?g$/,
|
||||
/\.png$/,
|
||||
/\.frag/,
|
||||
{ and: [/\.svg/, { not: [/\.icon\.svg/] }] },
|
||||
/\.xml/,
|
||||
/\.frag$/,
|
||||
/\.vert$/,
|
||||
{ and: [/\.svg$/, { not: [/\.icon\.svg$/] }] },
|
||||
/\.xml$/,
|
||||
],
|
||||
type: 'asset/resource',
|
||||
generator: {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { Config } from '@backstage/config';
|
||||
import { Credentials } from 'aws-sdk';
|
||||
import { EntityProvider } from '@backstage/plugin-catalog-backend';
|
||||
import { EntityProviderConnection } from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import { Logger } from 'winston';
|
||||
import { PluginTaskScheduler } from '@backstage/backend-tasks';
|
||||
import { TaskRunner } from '@backstage/backend-tasks';
|
||||
|
||||
@@ -20,10 +20,12 @@ import aws from 'aws-sdk';
|
||||
|
||||
describe('AwsEKSClusterProcessor', () => {
|
||||
AWSMock.setSDKInstance(aws);
|
||||
|
||||
describe('readLocation', () => {
|
||||
const processor = new (AwsEKSClusterProcessor as any)({});
|
||||
const location = { type: 'aws-eks', target: '957140518395/us-west-2' };
|
||||
const emit = jest.fn();
|
||||
|
||||
it('generates cluster correctly', async () => {
|
||||
const clusters: aws.EKS.Types.ListClustersResponse = {
|
||||
clusters: ['backstage-test'],
|
||||
@@ -40,11 +42,12 @@ describe('AwsEKSClusterProcessor', () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
AWSMock.mock('EKS', 'listClusters', clusters);
|
||||
|
||||
AWSMock.mock('EKS', 'listClusters', clusters);
|
||||
AWSMock.mock('EKS', 'describeCluster', cluster);
|
||||
|
||||
await processor.readLocation(location, false, emit);
|
||||
|
||||
expect(emit).toHaveBeenCalledWith({
|
||||
type: 'entity',
|
||||
location,
|
||||
|
||||
@@ -13,16 +13,17 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
CatalogProcessor,
|
||||
CatalogProcessorEmit,
|
||||
LocationSpec,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import {
|
||||
ANNOTATION_KUBERNETES_API_SERVER,
|
||||
ANNOTATION_KUBERNETES_API_SERVER_CA,
|
||||
ANNOTATION_KUBERNETES_AUTH_PROVIDER,
|
||||
} from '@backstage/catalog-model';
|
||||
} from '@backstage/plugin-kubernetes-common';
|
||||
import { Credentials, EKS } from 'aws-sdk';
|
||||
import { AWSCredentialFactory } from '../types';
|
||||
|
||||
|
||||
+1
-1
@@ -19,9 +19,9 @@ import { Config } from '@backstage/config';
|
||||
import {
|
||||
CatalogProcessor,
|
||||
CatalogProcessorEmit,
|
||||
LocationSpec,
|
||||
processingResult,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import AWS, { Credentials, Organizations } from 'aws-sdk';
|
||||
import { Account, ListAccountsResponse } from 'aws-sdk/clients/organizations';
|
||||
import { Logger } from 'winston';
|
||||
|
||||
@@ -20,9 +20,9 @@ import {
|
||||
CatalogProcessor,
|
||||
CatalogProcessorEmit,
|
||||
CatalogProcessorParser,
|
||||
LocationSpec,
|
||||
processingResult,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import limiterFactory from 'p-limit';
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,9 +20,9 @@ import { AwsS3Integration, ScmIntegrations } from '@backstage/integration';
|
||||
import {
|
||||
EntityProvider,
|
||||
EntityProviderConnection,
|
||||
LocationSpec,
|
||||
locationSpecToLocationEntity,
|
||||
} from '@backstage/plugin-catalog-backend';
|
||||
import { LocationSpec } from '@backstage/plugin-catalog-common';
|
||||
import { AwsCredentials } from '../credentials/AwsCredentials';
|
||||
import { readAwsS3Configs } from './config';
|
||||
import { AwsS3Config } from './types';
|
||||
|
||||
@@ -97,6 +97,7 @@ export type SearchTypeAccordionProps = {
|
||||
icon: JSX.Element;
|
||||
}>;
|
||||
defaultValue?: string;
|
||||
showCounts?: boolean;
|
||||
};
|
||||
|
||||
// @public
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
import React from 'react';
|
||||
import { TestApiProvider } from '@backstage/test-utils';
|
||||
import { act, render } from '@testing-library/react';
|
||||
import { act, render, waitFor } from '@testing-library/react';
|
||||
import user from '@testing-library/user-event';
|
||||
import {
|
||||
searchApiRef,
|
||||
@@ -34,6 +34,8 @@ jest.mock('@backstage/plugin-search-react', () => ({
|
||||
setTypes: (types: any) => setTypesMock(types),
|
||||
pageCursor: '',
|
||||
setPageCursor: (pageCursor: any) => setPageCursorMock(pageCursor),
|
||||
term: 'abc',
|
||||
filters: { foo: 'bar' },
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -48,7 +50,7 @@ describe('SearchType.Accordion', () => {
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
query.mockResolvedValue({ results: [] });
|
||||
query.mockResolvedValue({ results: [], numberOfResults: 1234 });
|
||||
});
|
||||
|
||||
const Wrapper = ({ children }: { children: React.ReactNode }) => {
|
||||
@@ -132,4 +134,34 @@ describe('SearchType.Accordion', () => {
|
||||
|
||||
expect(queryByText('Collapse')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('should show result counts if enabled', async () => {
|
||||
const { getAllByText } = render(
|
||||
<Wrapper>
|
||||
<SearchType.Accordion
|
||||
name={expectedLabel}
|
||||
showCounts
|
||||
types={[expectedType]}
|
||||
/>
|
||||
</Wrapper>,
|
||||
);
|
||||
|
||||
expect(query).toHaveBeenCalledWith({
|
||||
term: 'abc',
|
||||
types: [],
|
||||
filters: { foo: 'bar' },
|
||||
pageLimit: 0,
|
||||
});
|
||||
expect(query).toHaveBeenCalledWith({
|
||||
term: 'abc',
|
||||
types: [expectedType.value],
|
||||
filters: {},
|
||||
pageLimit: 0,
|
||||
});
|
||||
await waitFor(() => {
|
||||
const countLabels = getAllByText('1234 results');
|
||||
expect(countLabels.length).toEqual(2);
|
||||
expect(countLabels[0]).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
|
||||
import React, { cloneElement, Fragment, useEffect, useState } from 'react';
|
||||
import { useSearch } from '@backstage/plugin-search-react';
|
||||
import { useApi } from '@backstage/core-plugin-api';
|
||||
import { searchApiRef, useSearch } from '@backstage/plugin-search-react';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionSummary,
|
||||
@@ -32,6 +33,7 @@ import {
|
||||
} from '@material-ui/core';
|
||||
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
|
||||
import AllIcon from '@material-ui/icons/FontDownload';
|
||||
import useAsync from 'react-use/lib/useAsync';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
card: {
|
||||
@@ -81,13 +83,15 @@ export type SearchTypeAccordionProps = {
|
||||
icon: JSX.Element;
|
||||
}>;
|
||||
defaultValue?: string;
|
||||
showCounts?: boolean;
|
||||
};
|
||||
|
||||
export const SearchTypeAccordion = (props: SearchTypeAccordionProps) => {
|
||||
const classes = useStyles();
|
||||
const { setPageCursor, setTypes, types } = useSearch();
|
||||
const { filters, setPageCursor, setTypes, term, types } = useSearch();
|
||||
const searchApi = useApi(searchApiRef);
|
||||
const [expanded, setExpanded] = useState(true);
|
||||
const { defaultValue, name, types: givenTypes } = props;
|
||||
const { defaultValue, name, showCounts, types: givenTypes } = props;
|
||||
|
||||
const toggleExpanded = () => setExpanded(prevState => !prevState);
|
||||
const handleClick = (type: string) => {
|
||||
@@ -116,6 +120,37 @@ export const SearchTypeAccordion = (props: SearchTypeAccordionProps) => {
|
||||
];
|
||||
const selected = types[0] || '';
|
||||
|
||||
const { value: resultCounts } = useAsync(async () => {
|
||||
if (!showCounts) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const counts = await Promise.all(
|
||||
definedTypes
|
||||
.map(t => t.value)
|
||||
.map(async type => {
|
||||
const { numberOfResults } = await searchApi.query({
|
||||
term,
|
||||
types: type ? [type] : [],
|
||||
filters:
|
||||
types.includes(type) || (!types.length && !type) ? filters : {},
|
||||
pageLimit: 0,
|
||||
});
|
||||
|
||||
return [
|
||||
type,
|
||||
numberOfResults !== undefined
|
||||
? `${
|
||||
numberOfResults >= 10000 ? `>10000` : numberOfResults
|
||||
} results`
|
||||
: ' -- ',
|
||||
];
|
||||
}),
|
||||
);
|
||||
|
||||
return Object.fromEntries(counts);
|
||||
}, [filters, showCounts, term, types]);
|
||||
|
||||
return (
|
||||
<Card className={classes.card}>
|
||||
<CardHeader title={name} titleTypographyProps={{ variant: 'overline' }} />
|
||||
@@ -161,7 +196,10 @@ export const SearchTypeAccordion = (props: SearchTypeAccordionProps) => {
|
||||
className: classes.listItemIcon,
|
||||
})}
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={type.name} />
|
||||
<ListItemText
|
||||
primary={type.name}
|
||||
secondary={resultCounts && resultCounts[type.value]}
|
||||
/>
|
||||
</ListItem>
|
||||
</Fragment>
|
||||
))}
|
||||
|
||||
Reference in New Issue
Block a user