Merge branch 'backstage:master' into feature/upgrade-aws-sdk-elasticsearch

This commit is contained in:
Andrew Ochsner
2023-05-08 10:54:18 -05:00
committed by GitHub
22 changed files with 165 additions and 80 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-home': patch
---
Remove object-hash dependency
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-events-backend-module-aws-sqs': minor
---
Allow endpoint configuration for sqs, enabling use of localstack for testing.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend': patch
---
Internal refactoring for performance in the service handlers
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-tech-radar': patch
---
Fix description links when clicking entry in radar.
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-search-react': minor
---
<SearchBar/> accepts InputProp property that can override keys from default
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-catalog-backend-module-github': major
---
Updated the `team.edited` event emitted from `GithubOrgEntityProvider` to also include teams description.
+1
View File
@@ -92,6 +92,7 @@ Scope: The TechDocs plugin and related tooling
| Adam Harvey | Cisco | [adamdmharvey](https://github.com/adamdmharvey) | `adamharvey#3739` |
| Andre Wanlin | Keyloop | [awanlin](https://github.com/awanlin) | `Ahhhndre#3095` |
| Andrew Thauer | Wealthsimple | [andrewthauer](https://github.com/andrewthauer) | `andrewthauer#3060` |
| Aramis Sennyey | | [sennyeya](https://github.com/sennyeya) | `Aramis#7984` |
| Brian Fletcher | Roadie.io | [punkle](https://github.com/punkle) | `Brian Fletcher#7051` |
| Carlos Esteban Lopez Jaramillo | VMWare | [luchillo17](https://github.com/luchillo17) | `luchillo17#8777` |
| David Tuite | Roadie.io | [dtuite](https://github.com/dtuite) | `David Tuite (roadie.io)#1010` |
+1 -1
View File
@@ -241,7 +241,7 @@ module.exports = {
},
{
label: 'Subscribe to our newsletter',
to: 'https://mailchi.mp/spotify/backstage-community',
to: 'https://info.backstage.spotify.com/newsletter_subscribe',
},
{
label: 'CNCF Incubation',
+29 -1
View File
@@ -21,12 +21,15 @@ import {
ClockConfig,
HomePageStarredEntities,
CustomHomepageGrid,
HomePageToolkit,
HomePageCompanyLogo,
} from '@backstage/plugin-home';
import { Content, Header, Page } from '@backstage/core-components';
import { HomePageSearchBar } from '@backstage/plugin-search';
import { HomePageCalendar } from '@backstage/plugin-gcalendar';
import { MicrosoftCalendarCard } from '@backstage/plugin-microsoft-calendar';
import React from 'react';
import HomeIcon from '@material-ui/icons/Home';
const clockConfigs: ClockConfig[] = [
{
@@ -55,12 +58,26 @@ const timeFormat: Intl.DateTimeFormatOptions = {
const defaultConfig = [
{
component: 'HomePageSearchBar',
component: 'CompanyLogo',
x: 0,
y: 0,
width: 12,
height: 1,
},
{
component: 'WelcomeTitle',
x: 0,
y: 1,
width: 12,
height: 1,
},
{
component: 'HomePageSearchBar',
x: 0,
y: 2,
width: 12,
height: 1,
},
];
export const homePage = (
@@ -78,6 +95,17 @@ export const homePage = (
<HomePageCalendar />
<MicrosoftCalendarCard />
<HomePageStarredEntities />
<HomePageCompanyLogo />
<WelcomeTitle />
<HomePageToolkit
tools={[
{
url: 'https://backstage.io',
label: 'Backstage Homepage',
icon: <HomeIcon />,
},
]}
/>
</CustomHomepageGrid>
</Content>
</Page>
@@ -833,6 +833,7 @@ describe('GithubOrgEntityProvider', () => {
'url:https://github.com/orgs/backstage/teams/mygroup-with-spaces',
},
name: 'mygroup-with-spaces',
description: 'description-from-the-new-team',
},
apiVersion: 'backstage.io/v1alpha1',
kind: 'Group',
@@ -371,14 +371,21 @@ export class GithubOrgEntityProvider
assignGroupsToUsers(usersToRebuild, groups);
buildOrgHierarchy(groups);
const oldName = event.changes.name?.from || '';
const oldName = event.changes.name?.from || event.team.name;
const oldSlug = oldName.toLowerCase().replaceAll(/\s/gi, '-');
const oldDescription =
event.changes.description?.from || event.team.description;
const oldDescriptionSlug = oldDescription
?.toLowerCase()
.replaceAll(/\s/gi, '-');
const { removed } = createDeltaOperation(org, [
{
...group,
metadata: {
name: oldSlug,
description: oldDescriptionSlug,
},
},
]);
@@ -64,43 +64,47 @@ const defaultSortField: EntityOrder = {
const DEFAULT_LIMIT = 20;
function parsePagination(input?: EntityPagination): {
limit?: number;
offset?: number;
} {
function parsePagination(input?: EntityPagination): EntityPagination {
if (!input) {
return {};
}
let { limit, offset } = input;
if (input.after !== undefined) {
let cursor;
try {
const json = Buffer.from(input.after, 'base64').toString('utf8');
cursor = JSON.parse(json);
} catch {
throw new InputError('Malformed after cursor, could not be parsed');
if (input.after === undefined) {
return { limit, offset };
}
let cursor;
try {
const json = Buffer.from(input.after, 'base64').toString('utf8');
cursor = JSON.parse(json);
} catch {
throw new InputError('Malformed after cursor, could not be parsed');
}
if (cursor.limit !== undefined) {
if (!Number.isInteger(cursor.limit)) {
throw new InputError('Malformed after cursor, limit was not an number');
}
if (cursor.limit !== undefined) {
if (!Number.isInteger(cursor.limit)) {
throw new InputError('Malformed after cursor, limit was not an number');
}
limit = cursor.limit;
}
if (cursor.offset !== undefined) {
if (!Number.isInteger(cursor.offset)) {
throw new InputError('Malformed after cursor, offset was not a number');
}
offset = cursor.offset;
limit = cursor.limit;
}
if (cursor.offset !== undefined) {
if (!Number.isInteger(cursor.offset)) {
throw new InputError('Malformed after cursor, offset was not a number');
}
offset = cursor.offset;
}
return { limit, offset };
}
function stringifyPagination(input: { limit: number; offset: number }) {
const json = JSON.stringify({ limit: input.limit, offset: input.offset });
function stringifyPagination(
input: Required<Omit<EntityPagination, 'after'>>,
): string {
const { limit, offset } = input;
const json = JSON.stringify({ limit, offset });
const base64 = Buffer.from(json, 'utf8').toString('base64');
return base64;
}
@@ -111,24 +115,21 @@ function addCondition(
filter: EntitiesSearchFilter,
negate: boolean = false,
entityIdField = 'entity_id',
) {
): void {
const key = filter.key.toLowerCase();
const values = filter.values?.map(v => v.toLowerCase());
// NOTE(freben): This used to be a set of OUTER JOIN, which may seem to
// make a lot of sense. However, it had abysmal performance on sqlite
// when datasets grew large, so we're using IN instead.
const matchQuery = db<DbSearchRow>('search')
.select('search.entity_id')
.where({ key: filter.key.toLowerCase() })
.where({ key })
.andWhere(function keyFilter() {
if (filter.values) {
if (filter.values.length === 1) {
this.where({ value: filter.values[0].toLowerCase() });
} else {
this.andWhere(
'value',
'in',
filter.values.map(v => v.toLowerCase()),
);
}
if (values?.length === 1) {
this.where({ value: values.at(0) });
} else if (values) {
this.andWhere('value', 'in', values);
}
});
queryBuilder.andWhere(entityIdField, negate ? 'not in' : 'in', matchQuery);
@@ -159,16 +160,16 @@ function parseFilter(
negate: boolean = false,
entityIdField = 'entity_id',
): Knex.QueryBuilder {
if (isNegationEntityFilter(filter)) {
return parseFilter(filter.not, query, db, !negate, entityIdField);
}
if (isEntitiesSearchFilter(filter)) {
return query.andWhere(function filterFunction() {
addCondition(this, db, filter, negate, entityIdField);
});
}
if (isNegationEntityFilter(filter)) {
return parseFilter(filter.not, query, db, !negate, entityIdField);
}
return query[negate ? 'andWhereNot' : 'andWhere'](function filterFunction() {
if (isOrEntityFilter(filter)) {
for (const subFilter of filter.anyOf ?? []) {
@@ -68,7 +68,11 @@ export class AwsSqsConsumingEventPublisher implements EventPublisher {
VisibilityTimeout: config.visibilityTimeout?.as('seconds'),
WaitTimeSeconds: config.pollingWaitTime.as('seconds'),
};
this.sqs = new SQSClient({ region: config.region });
this.sqs = new SQSClient({
region: config.region,
endpoint: config.endpoint,
});
this.queueUrl = config.queueUrl;
this.taskTimeoutSeconds = config.timeout.as('seconds');
@@ -79,6 +79,7 @@ describe('readConfig', () => {
url: 'https://fake1.queue.url',
visibilityTimeout: { minutes: 5 },
waitTime: { seconds: 10 },
endpoint: 'https://fake.endpoint.url',
},
timeout: { minutes: 5 },
waitTimeAfterEmptyReceive: { seconds: 30 },
@@ -97,6 +98,7 @@ describe('readConfig', () => {
expect(publisherConfigs[0].topic).toEqual('fake1');
expect(publisherConfigs[0].region).toEqual('eu-west-1');
expect(publisherConfigs[0].queueUrl).toEqual('https://fake1.queue.url');
expect(publisherConfigs[0].endpoint).toEqual('https://fake.endpoint.url');
expect(publisherConfigs[0].pollingWaitTime.as('seconds')).toBe(10);
expect(publisherConfigs[0].timeout.as('seconds')).toBe(300);
expect(publisherConfigs[0].waitTimeAfterEmptyReceive.as('seconds')).toBe(
@@ -31,6 +31,7 @@ export interface AwsSqsEventSourceConfig {
topic: string;
visibilityTimeout?: Duration;
waitTimeAfterEmptyReceive: Duration;
endpoint?: string;
}
// TODO(pjungermann): validation could be improved similar to `convertToHumanDuration` at @backstage/backend-tasks
@@ -74,6 +75,7 @@ export function readConfig(config: Config): AwsSqsEventSourceConfig[] {
}
const queueUrl = topicConfig.getString('queue.url');
const region = topicConfig.getString('queue.region');
const endpoint = topicConfig.getOptionalString('queue.endpoint');
const visibilityTimeout = readOptionalDuration(
topicConfig,
'queue.visibilityTimeout',
@@ -106,6 +108,7 @@ export function readConfig(config: Config): AwsSqsEventSourceConfig[] {
return {
pollingWaitTime,
queueUrl,
endpoint,
region,
timeout,
topic,
-1
View File
@@ -48,7 +48,6 @@
"@rjsf/validator-ajv8": "5.6.0",
"@types/react": "^16.13.1 || ^17.0.0",
"lodash": "^4.17.21",
"object-hash": "^3.0.0",
"react-grid-layout": "^1.3.4",
"react-resizable": "^3.0.4",
"react-use": "^17.2.4",
@@ -46,7 +46,6 @@ import { CardConfig } from '../../extensions';
// eslint-disable-next-line new-cap
const ResponsiveGrid = WidthProvider(Responsive);
const hash = require('object-hash');
const useStyles = makeStyles((theme: Theme) =>
createStyles({
@@ -336,14 +335,14 @@ export const CustomHomepageGrid = (props: CustomHomepageGridProps) => {
...widget.component.props,
...(w.settings ?? {}),
};
const propsHash = hash(widgetProps, {});
return (
<div
key={l.i}
className={`${styles.widgetWrapper} ${editMode && 'edit'}`}
>
<ErrorBoundary>
<widget.component.type key={propsHash} {...widgetProps} />
<widget.component.type {...widgetProps} />
</ErrorBoundary>
{editMode && (
<WidgetSettingsOverlay
@@ -92,13 +92,18 @@ const useStyles = makeStyles({
borderRadius: '50px',
margin: 'auto',
},
notchedOutline: {
borderStyle: 'none',
},
});
export const CustomStyles = () => {
const classes = useStyles();
return (
<Paper className={classes.search}>
<SearchBar />
<SearchBar
InputProps={{ classes: { notchedOutline: classes.notchedOutline } }}
/>
</Paper>
);
};
@@ -80,7 +80,8 @@ export const SearchBarBase: ForwardRefExoticComponent<SearchBarBaseProps> =
value: defaultValue,
label,
placeholder,
inputProps: defaultInputProps = {},
inputProps = {},
InputProps = {},
endAdornment,
...rest
} = props;
@@ -168,10 +169,11 @@ export const SearchBarBase: ForwardRefExoticComponent<SearchBarBaseProps> =
endAdornment: clearButton
? clearButtonEndAdornment
: endAdornment,
...InputProps,
}}
inputProps={{
'aria-label': ariaLabel,
...defaultInputProps,
...inputProps,
}}
fullWidth={fullWidth}
onChange={handleChange}
@@ -26,6 +26,7 @@ export type Props = {
value: number;
color: string;
url?: string;
links?: Array<{ title: string; url: string }>;
moved?: number;
description?: string;
timeline?: EntrySnapshot[];
@@ -73,6 +74,7 @@ const RadarEntry = (props: Props): JSX.Element => {
title,
color,
url,
links,
value,
x,
y,
@@ -112,6 +114,7 @@ const RadarEntry = (props: Props): JSX.Element => {
description={description ? description : 'no description'}
timeline={timeline ? timeline : []}
url={url}
links={links}
/>
)}
{description ? (
@@ -73,6 +73,7 @@ const RadarPlot = (props: Props): JSX.Element => {
color={entry.color || ''}
value={(entry?.index || 0) + 1}
url={entry.url}
links={entry.links}
description={entry.description}
moved={entry.moved}
title={entry.title}
+28 -29
View File
@@ -7268,7 +7268,6 @@ __metadata:
cross-fetch: ^3.1.5
lodash: ^4.17.21
msw: ^1.0.0
object-hash: ^3.0.0
react-grid-layout: ^1.3.4
react-resizable: ^3.0.4
react-use: ^17.2.4
@@ -12317,11 +12316,11 @@ __metadata:
linkType: hard
"@keyv/redis@npm:^2.5.3":
version: 2.5.7
resolution: "@keyv/redis@npm:2.5.7"
version: 2.5.8
resolution: "@keyv/redis@npm:2.5.8"
dependencies:
ioredis: ^5.3.1
checksum: e0ed1b6602afcc339bb2bf014d8801e6b7a3b6392d0f8e4ccfc59d919f59229b8787c50c48fc51636625ffdf55cf1ef6c450425a73bd88f9b866e74f1b3e25f8
ioredis: ^5.3.2
checksum: 1050c4997b62e701112b48e5375c4e53a5e49454c1621fbb00b1c2272e55a575f9ace49c5179800f73e6f07ce247a4cf6e1260a6713ad1392fd8f8825079771f
languageName: node
linkType: hard
@@ -16436,9 +16435,9 @@ __metadata:
linkType: hard
"@types/node@npm:*, @types/node@npm:>=12.12.47, @types/node@npm:>=13.7.0":
version: 20.0.0
resolution: "@types/node@npm:20.0.0"
checksum: 7dadc41081eee634fd0b19e46dfb0a74f8296ee562533118f7c2f2b54dcaba7124961d506db425fff74d8e8288610b93939cd06fa723f053c72b1a7e87aa4ddc
version: 20.1.0
resolution: "@types/node@npm:20.1.0"
checksum: c6d9afa9aa78b4b4348c69ece94975be70346b144c278f1395694a10ef919d7db300018101b6f9245e6bdd76674a5327d2d14829092f3d5295e858cff5f22a66
languageName: node
linkType: hard
@@ -16457,9 +16456,9 @@ __metadata:
linkType: hard
"@types/node@npm:^14.14.31":
version: 14.18.44
resolution: "@types/node@npm:14.18.44"
checksum: 650527d288956649da15917512236815c3e00f8a72a8d4f316dac88180d0b074884eab944ef2d404f0b394ef56e62e7e5891c786c19f4474365672782a1923b0
version: 14.18.45
resolution: "@types/node@npm:14.18.45"
checksum: 2857cd1912d70f6a97b9d8085088b12ab80bcaa06e4ea20535020167bfcbc6bea9469fafc437acddd34b07e3d94b1d35bcbd51d960c8841ab1a675166e97d8b9
languageName: node
linkType: hard
@@ -16471,16 +16470,16 @@ __metadata:
linkType: hard
"@types/node@npm:^16.0.0, @types/node@npm:^16.11.26, @types/node@npm:^16.9.2":
version: 16.18.25
resolution: "@types/node@npm:16.18.25"
checksum: 181760ad6b54fcc498dfeb249e98bbf0be51d7c35e92e760e1a82004fa42b86e8c33a8f8dd7743b5ef872bda0753d9e6a5b8e3f0aed63e9eb79b4e65760c1fbe
version: 16.18.26
resolution: "@types/node@npm:16.18.26"
checksum: 2a746b3f9e97e00aa5d1d8cce36c5b75d5504df15e82647ad1fadbc3435ea4491203d044bbaa595edc2ab25a9ab820793f9d38dba753ad150929335fa21e24d4
languageName: node
linkType: hard
"@types/node@npm:^18.11.17":
version: 18.16.4
resolution: "@types/node@npm:18.16.4"
checksum: 21d575391c88be9f3568675de59d571597cfc122efa32939ae2697c2218c6ccfb6ba0d4b5d9301905e6c4964f43add42569249b15d2e12d68b0aedaf891ec9a5
version: 18.16.5
resolution: "@types/node@npm:18.16.5"
checksum: b6df96a76a7655cd944794197cf63f5269e5034041bc355f4f243cb3f185ad3e1948011b6f0ac66c22434e50bc53a20ec3a9d95ad284f0e3819813d309d1650b
languageName: node
linkType: hard
@@ -26750,9 +26749,9 @@ __metadata:
languageName: node
linkType: hard
"ioredis@npm:^5.3.1":
version: 5.3.1
resolution: "ioredis@npm:5.3.1"
"ioredis@npm:^5.3.2":
version: 5.3.2
resolution: "ioredis@npm:5.3.2"
dependencies:
"@ioredis/commands": ^1.1.1
cluster-key-slot: ^1.1.0
@@ -26763,7 +26762,7 @@ __metadata:
redis-errors: ^1.2.0
redis-parser: ^3.0.0
standard-as-callback: ^2.1.0
checksum: 6c98cb8f8772ad4bb2b6b7a0a224e4a63f4759f9a28e84205f18788552f08221d51f391c10892dca01a1b10b2804d0a7e6082b0b7decd65538a5fb6b0f4f1f82
checksum: 9a23559133e862a768778301efb68ae8c2af3c33562174b54a4c2d6574b976e85c75a4c34857991af733e35c48faf4c356e7daa8fb0a3543d85ff1768c8754bc
languageName: node
linkType: hard
@@ -38464,14 +38463,14 @@ __metadata:
linkType: hard
"terser-webpack-plugin@npm:*, terser-webpack-plugin@npm:^5.1.3":
version: 5.3.7
resolution: "terser-webpack-plugin@npm:5.3.7"
version: 5.3.8
resolution: "terser-webpack-plugin@npm:5.3.8"
dependencies:
"@jridgewell/trace-mapping": ^0.3.17
jest-worker: ^27.4.5
schema-utils: ^3.1.1
serialize-javascript: ^6.0.1
terser: ^5.16.5
terser: ^5.16.8
peerDependencies:
webpack: ^5.1.0
peerDependenciesMeta:
@@ -38481,13 +38480,13 @@ __metadata:
optional: true
uglify-js:
optional: true
checksum: 095e699fdeeb553cdf2c6f75f983949271b396d9c201d7ae9fc633c45c1c1ad14c7257ef9d51ccc62213dd3e97f875870ba31550f6d4f1b6674f2615562da7f7
checksum: 0ffc2a1949b1fd60ef9c815c4629b9817656db612bb58c5db96e3b04204c86afd142b115392e48733364edc7bf95131f54c10174c05f046ba8f2adead6b06c3c
languageName: node
linkType: hard
"terser@npm:^5.10.0, terser@npm:^5.16.5":
version: 5.16.6
resolution: "terser@npm:5.16.6"
"terser@npm:^5.10.0, terser@npm:^5.16.8":
version: 5.17.1
resolution: "terser@npm:5.17.1"
dependencies:
"@jridgewell/source-map": ^0.3.2
acorn: ^8.5.0
@@ -38495,7 +38494,7 @@ __metadata:
source-map-support: ~0.5.20
bin:
terser: bin/terser
checksum: f763a7bcc7b98cb2bfc41434f7b92bfe8a701a12c92ea6049377736c8e6de328240d654a20dfe15ce170fd783491b9873fad9f4cd8fee4f6c6fb8ca407859dee
checksum: 69b0e80e3c4084db2819de4d6ae8a2ba79f2fcd7ed6df40fe4b602ec7bfd8e889cc63c7d5268f30990ffecbf6eeda18f857adad9386fe2c2331b398d58ed855c
languageName: node
linkType: hard