Merge branch 'backstage:master' into feature/git-wrapper-branch-command

This commit is contained in:
Magnus Persson
2022-09-19 09:33:52 +02:00
committed by GitHub
344 changed files with 9177 additions and 2974 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-msgraph': patch
---
Added $select attribute to user query
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-kubernetes-backend': patch
---
Adds skipMetricsLookup to the kubernetes-backend schema
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-scaffolder': patch
---
Support displaying and ordering by counts in `EntityTagPicker` field. Add the `showCounts` option to enable this. Also support configuring `helperText`.
+25
View File
@@ -188,19 +188,24 @@
"clever-turtles-work",
"cold-frogs-kiss",
"cool-cameras-count",
"cuddly-clocks-dance",
"cuddly-needles-marry",
"curly-hounds-wait",
"dry-games-end",
"dry-tips-build",
"dull-spoons-doubt",
"eight-shrimps-call",
"eight-spies-protect",
"eleven-bees-marry",
"empty-colts-whisper",
"famous-cups-roll",
"famous-hounds-sit",
"famous-pianos-kick",
"famous-wombats-happen",
"fast-paws-press",
"five-carrots-pay",
"flat-crabs-love",
"flat-humans-dance",
"flat-plums-shout",
"flat-walls-kiss",
"fresh-rabbits-juggle",
@@ -211,17 +216,21 @@
"gold-laws-attend",
"good-avocados-grow",
"good-papayas-dress",
"gorgeous-boats-prove",
"gorgeous-pillows-retire",
"gorgeous-swans-kiss",
"great-cats-sit",
"great-rules-march",
"grumpy-kiwis-juggle",
"happy-kiwis-look",
"heavy-ligers-laugh",
"hot-brooms-drive",
"hot-files-begin",
"hot-suits-glow",
"hungry-dogs-agree",
"itchy-brooms-end",
"itchy-kiwis-warn",
"large-books-deny",
"large-eagles-shop",
"large-trainers-float",
"late-turtles-listen",
@@ -230,13 +239,17 @@
"light-donuts-obey",
"loud-comics-search",
"lovely-ants-invite",
"lucky-ads-worry",
"lucky-points-wash",
"many-rules-raise",
"mean-tomatoes-visit",
"metal-candles-tease",
"metal-crabs-wash",
"metal-weeks-kiss",
"moody-berries-sneeze",
"neat-kangaroos-turn",
"nervous-rivers-sneeze",
"new-taxis-vanish",
"old-lemons-switch",
"old-readers-provide",
"old-rockets-doubt",
@@ -247,7 +260,9 @@
"purple-jeans-bathe",
"purple-plums-travel",
"purple-wolves-confess",
"quick-items-invite",
"quick-lamps-talk",
"rare-tips-glow",
"red-numbers-suffer",
"renovate-16f36a0",
"renovate-1a6cc1f",
@@ -263,6 +278,7 @@
"rotten-books-crash",
"rude-books-rush",
"rude-tips-argue",
"rude-weeks-retire",
"search-feet-flash",
"search-planets-flash",
"search-zebras-tap",
@@ -273,11 +289,14 @@
"shiny-lobsters-fix",
"shiny-ties-leave",
"shiny-walls-kiss",
"short-mice-explode",
"silent-kings-live",
"slimy-stingrays-type",
"slimy-zebras-reply",
"slow-phones-count",
"small-lemons-brake",
"small-walls-promise",
"smart-sloths-search",
"smart-squids-change",
"smooth-yaks-hug",
"spicy-cherries-remember",
@@ -286,10 +305,13 @@
"strong-planes-return",
"stupid-pigs-appear",
"sweet-fishes-taste",
"sweet-grapes-explain",
"swift-readers-sin",
"tall-trains-remain",
"tame-papayas-protect",
"tame-socks-sniff",
"tame-trainers-rule",
"tasty-clouds-cover",
"techdocs-feet-dress",
"techdocs-jeans-wait",
"tender-ladybugs-relax",
@@ -298,13 +320,16 @@
"tiny-oranges-thank",
"tiny-rocks-flash",
"tough-dolphins-smile",
"twenty-dolls-smoke",
"two-planets-provide",
"veka-fingrar-drar",
"weak-camels-roll",
"weak-radios-sin",
"weak-yaks-learn",
"wild-sheep-roll",
"witty-cats-wink",
"witty-queens-happen",
"young-falcons-sleep",
"young-trees-rescue"
]
}
+283
View File
@@ -0,0 +1,283 @@
---
'@backstage/plugin-search-react': minor
---
The `<SearchResult/>` component now accepts a optional `query` prop to request results from the search api:
> Note: If a query prop is not defined, the results will by default be consumed from the context.
Example:
```jsx
import React, { useState, useCallback } from 'react';
import { Grid, List, Paper } from '@material-ui/core';
import { Page, Header, Content, Lifecycle } from '@backstage/core-components';
import {
DefaultResultListItem,
SearchBarBase,
SearchResult,
} from '@backstage/plugin-search-react';
const SearchPage = () => {
const [query, setQuery] = useState({
term: '',
types: [],
filters: {},
});
const handleChange = useCallback(
(term: string) => {
setQuery(prevQuery => ({ ...prevQuery, term }));
},
[setQuery],
);
return (
<Page themeId="home">
<Header title="Search" subtitle={<Lifecycle alpha />} />
<Content>
<Grid container direction="row">
<Grid item xs={12}>
<Paper>
<SearchBarBase debounceTime={100} onChange={handleChange} />
</Paper>
</Grid>
<Grid item xs>
<SearchResult query={query}>
{({ results }) => (
<List>
{results.map(({ document }) => (
<DefaultResultListItem
key={document.location}
result={document}
/>
))}
</List>
)}
</SearchResult>
</Grid>
</Grid>
</Content>
</Page>
);
};
```
Additionally, a search page can also be composed using these two new results layout components:
```jsx
// Example rendering results as list
<SearchResult>
{({ results }) => (
<SearchResultListLayout
resultItems={results}
renderResultItem={({ type, document }) => {
switch (type) {
case 'custom-result-item':
return (
<CustomResultListItem key={document.location} result={document} />
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
/>
);
}
}}
/>
)}
</SearchResult>
```
```jsx
// Example rendering results as groups
<SearchResult>
{({ results }) => (
<>
<SearchResultGroupLayout
icon={<CustomIcon />}
title="Custom"
link="See all custom results"
resultItems={results.filter(
({ type }) => type === 'custom-result-item',
)}
renderResultItem={({ document }) => (
<CustomResultListItem key={document.location} result={document} />
)}
/>
<SearchResultGroupLayout
icon={<DefaultIcon />}
title="Default"
resultItems={results.filter(
({ type }) => type !== 'custom-result-item',
)}
renderResultItem={({ document }) => (
<DefaultResultListItem key={document.location} result={document} />
)}
/>
</>
)}
</SearchResult>
```
A `SearchResultList` and `SearchResultGroup` components were also created for users who have search pages with multiple queries, both are specializations of `SearchResult` and also accept a `query` as a prop as well:
```jsx
// Example using the <SearchResultList />
const SearchPage = () => {
const query = {
term: 'example',
};
return (
<SearchResultList
query={query}
renderResultItem={({ type, document, highlight, rank }) => {
switch (type) {
case 'custom':
return (
<CustomResultListItem
key={document.location}
icon={<CatalogIcon />}
result={document}
highlight={highlight}
rank={rank}
/>
);
default:
return (
<DefaultResultListItem
key={document.location}
result={document}
/>
);
}
}}
/>
);
};
```
```jsx
// Example using the <SearchResultGroup /> for creating a component that search and group software catalog results
import React, { useState, useCallback } from 'react';
import { MenuItem } from '@material-ui/core';
import { JsonValue } from '@backstage/types';
import { CatalogIcon } from '@backstage/core-components';
import { CatalogSearchResultListItem } from '@backstage/plugin-catalog';
import {
SearchResultGroup,
SearchResultGroupTextFilterField,
SearchResultGroupSelectFilterField,
} from @backstage/plugin-search-react;
import { SearchQuery } from '@backstage/plugin-search-common';
const CatalogResultsGroup = () => {
const [query, setQuery] = useState<Partial<SearchQuery>>({
types: ['software-catalog'],
});
const filterOptions = [
{
label: 'Lifecycle',
value: 'lifecycle',
},
{
label: 'Owner',
value: 'owner',
},
];
const handleFilterAdd = useCallback(
(key: string) => () => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters, [key]: undefined };
return { ...rest, filters: newFilters };
});
},
[],
);
const handleFilterChange = useCallback(
(key: string) => (value: JsonValue) => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters, [key]: value };
return { ...rest, filters: newFilters };
});
},
[],
);
const handleFilterDelete = useCallback(
(key: string) => () => {
setQuery(prevQuery => {
const { filters: prevFilters, ...rest } = prevQuery;
const newFilters = { ...prevFilters };
delete newFilters[key];
return { ...rest, filters: newFilters };
});
},
[],
);
return (
<SearchResultGroup
query={query}
icon={<CatalogIcon />}
title="Software Catalog"
link="See all software catalog results"
filterOptions={filterOptions}
renderFilterOption={({ label, value }) => (
<MenuItem key={value} onClick={handleFilterAdd(value)}>
{label}
</MenuItem>
)}
renderFilterField={(key: string) => {
switch (key) {
case 'lifecycle':
return (
<SearchResultGroupSelectFilterField
key={key}
label="Lifecycle"
value={query.filters?.lifecycle}
onChange={handleFilterChange('lifecycle')}
onDelete={handleFilterDelete('lifecycle')}
>
<MenuItem value="production">Production</MenuItem>
<MenuItem value="experimental">Experimental</MenuItem>
</SearchResultGroupSelectFilterField>
);
case 'owner':
return (
<SearchResultGroupTextFilterField
key={key}
label="Owner"
value={query.filters?.owner}
onChange={handleFilterChange('owner')}
onDelete={handleFilterDelete('owner')}
/>
);
default:
return null;
}
}
renderResultItem={({ document, highlight, rank }) => (
<CatalogSearchResultListItem
key={document.location}
result={document}
highlight={highlight}
rank={rank}
/>
)}
/>
);
};
```