Merge branch 'master' into feat/customSearchModal

This commit is contained in:
Emma Indal
2022-04-12 13:07:13 +02:00
committed by GitHub
218 changed files with 6456 additions and 1533 deletions
+3
View File
@@ -10,6 +10,7 @@
"@backstage/app-defaults": "^1.0.1-next.1",
"@backstage/catalog-model": "^1.0.1-next.0",
"@backstage/cli": "^0.17.0-next.1",
"@backstage/config": "^1.0.0",
"@backstage/core-app-api": "^1.0.1-next.0",
"@backstage/core-components": "^0.9.3-next.0",
"@backstage/core-plugin-api": "^1.0.0",
@@ -47,9 +48,11 @@
"@backstage/plugin-rollbar": "^0.4.4-next.0",
"@backstage/plugin-scaffolder": "^1.0.1-next.1",
"@backstage/plugin-search": "^0.7.5-next.0",
"@backstage/plugin-search-react": "^0.0.0",
"@backstage/plugin-search-common": "^0.3.3-next.1",
"@backstage/plugin-sentry": "^0.3.42-next.0",
"@backstage/plugin-shortcuts": "^0.2.5-next.0",
"@backstage/plugin-stack-overflow": "^0.1.0-next.0",
"@backstage/plugin-tech-radar": "^0.5.11-next.1",
"@backstage/plugin-techdocs": "^1.0.1-next.1",
"@backstage/plugin-todo": "^0.2.6-next.0",
@@ -0,0 +1,159 @@
/*
* 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 {
HomePageToolkit,
HomePageCompanyLogo,
HomePageStarredEntities,
TemplateBackstageLogo,
TemplateBackstageLogoIcon
} from '@backstage/plugin-home';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { Content, Page, InfoCard } from '@backstage/core-components';
import {
starredEntitiesApiRef,
MockStarredEntitiesApi,
entityRouteRef,
} from '@backstage/plugin-catalog-react';
import { configApiRef } from '@backstage/core-plugin-api';
import { ConfigReader } from '@backstage/config';
import {
HomePageSearchBar,
searchPlugin,
} from '@backstage/plugin-search';
import { searchApiRef, SearchContextProvider } from '@backstage/plugin-search-react';
import { HomePageStackOverflowQuestions } from '@backstage/plugin-stack-overflow';
import { Grid, makeStyles } from '@material-ui/core';
import React, { ComponentType } from 'react';
const starredEntitiesApi = new MockStarredEntitiesApi();
starredEntitiesApi.toggleStarred('component:default/example-starred-entity');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-2');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-3');
starredEntitiesApi.toggleStarred('component:default/example-starred-entity-4');
export default {
title: 'Plugins/Home/Templates',
decorators: [
(Story: ComponentType<{}>) =>
wrapInTestApp(
<>
<TestApiProvider
apis={[
[starredEntitiesApiRef, starredEntitiesApi],
[searchApiRef, { query: () => Promise.resolve({ results: [] }) }],
[
configApiRef,
new ConfigReader({
stackoverflow: {
baseUrl: 'https://api.stackexchange.com/2.2',
},
}),
],
]}
>
<Story />
</TestApiProvider>
</>,
{
mountedRoutes: {
'/hello-company': searchPlugin.routes.root,
'/catalog/:namespace/:kind/:name': entityRouteRef,
},
},
),
],
};
const useStyles = makeStyles(theme => ({
searchBar: {
display: 'flex',
maxWidth: '60vw',
backgroundColor: theme.palette.background.paper,
boxShadow: theme.shadows[1],
padding: '8px 0',
borderRadius: '50px',
margin: 'auto',
},
}));
const useLogoStyles = makeStyles(theme => ({
container: {
margin: theme.spacing(5, 0),
},
svg: {
width: 'auto',
height: 100,
},
path: {
fill: '#7df3e1',
},
}));
export const DefaultTemplate = () => {
const classes = useStyles();
const { svg, path, container } = useLogoStyles();
return (
<SearchContextProvider>
<Page themeId="home">
<Content>
<Grid container justifyContent="center" spacing={6}>
<HomePageCompanyLogo
className={container}
logo={<TemplateBackstageLogo classes={{ svg, path }} />}
/>
<Grid container item xs={12} alignItems="center" direction="row">
<HomePageSearchBar
classes={{ root: classes.searchBar }}
placeholder="Search"
/>
</Grid>
<Grid container item xs={12}>
<Grid item xs={12} md={6}>
<HomePageStarredEntities />
</Grid>
<Grid item xs={12} md={6}>
<HomePageToolkit
tools={Array(8).fill({
url: '#',
label: 'link',
icon: <TemplateBackstageLogoIcon />,
})}
/>
</Grid>
<Grid item xs={12} md={6}>
<InfoCard title="Composable Section">
{/* placeholder for content */}
<div style={{ height: 370 }} />
</InfoCard>
</Grid>
<Grid item xs={12} md={6}>
<HomePageStackOverflowQuestions
requestParams={{
tagged: 'backstage',
site: 'stackoverflow',
pagesize: 5,
}}
/>
</Grid>
</Grid>
</Grid>
</Content>
</Page>
</SearchContextProvider>
);
};
+1 -1
View File
@@ -41,7 +41,7 @@ const updateRedactionList = (
) => {
const secretAppConfigs = schema.process(configs, {
visibility: ['secret'],
withDeprecatedKeys: true,
ignoreSchemaErrors: true,
});
const secretConfig = ConfigReader.fromConfigs(secretAppConfigs);
const values = new Set<string>();
+3 -1
View File
@@ -68,6 +68,7 @@
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"express-prom-bundle": "^6.3.6",
"luxon": "^2.0.2",
"pg": "^8.3.0",
"pg-connection-string": "^2.3.0",
"prom-client": "^14.0.1",
@@ -77,7 +78,8 @@
"@backstage/cli": "^0.17.0-next.1",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
"@types/express-serve-static-core": "^4.17.5",
"@types/luxon": "^2.0.4"
},
"files": [
"dist"
+12 -5
View File
@@ -26,6 +26,7 @@ import {
} from '@backstage/plugin-search-backend-node';
import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
import { Router } from 'express';
import { Duration } from 'luxon';
import { PluginEnvironment } from '../types';
async function createSearchEngine(
@@ -55,10 +56,18 @@ export default async function createPlugin(
searchEngine,
});
const schedule = env.scheduler.createScheduledTaskRunner({
frequency: Duration.fromObject({ minutes: 10 }),
timeout: Duration.fromObject({ minutes: 15 }),
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
initialDelay: Duration.fromObject({ seconds: 3 }),
});
// Collators are responsible for gathering documents known to plugins. This
// particular collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
schedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
@@ -66,7 +75,7 @@ export default async function createPlugin(
});
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
schedule,
factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
logger: env.logger,
@@ -77,10 +86,8 @@ export default async function createPlugin(
// The scheduler controls when documents are gathered from collators and sent
// to the search engine for indexing.
const { scheduler } = await indexBuilder.build();
scheduler.start();
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
setTimeout(() => scheduler.start(), 3000);
useHotCleanup(module, () => scheduler.stop());
return await createRouter({
+5 -2
View File
@@ -23,8 +23,11 @@ import {
TokenManager,
UrlReader,
} from '@backstage/backend-common';
import { ServerPermissionClient } from '@backstage/plugin-permission-node';
import { PluginTaskScheduler } from '@backstage/backend-tasks';
import {
PermissionAuthorizer,
PermissionEvaluator,
} from '@backstage/plugin-permission-common';
export type PluginEnvironment = {
logger: Logger;
@@ -34,6 +37,6 @@ export type PluginEnvironment = {
reader: UrlReader;
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
permissions: ServerPermissionClient;
permissions: PermissionEvaluator | PermissionAuthorizer;
scheduler: PluginTaskScheduler;
};
+2 -2
View File
@@ -93,7 +93,7 @@
"mini-css-extract-plugin": "^2.4.2",
"minimatch": "5.0.1",
"node-libs-browser": "^2.2.1",
"npm-packlist": "^3.0.0",
"npm-packlist": "^5.0.0",
"ora": "^5.3.0",
"postcss": "^8.1.0",
"process": "^0.11.10",
@@ -153,7 +153,7 @@
"ts-node": "^10.0.0"
},
"peerDependencies": {
"@microsoft/api-extractor": "^7.19.2"
"@microsoft/api-extractor": "^7.21.2"
},
"peerDependenciesMeta": {
"@microsoft/api-extractor": {
+1 -1
View File
@@ -226,7 +226,7 @@ export async function createBackendConfig(
// See frontend config
const externalPkgs = packages.filter(p => !isChildPath(paths.root, p.dir));
const { loaders } = transforms(options);
const { loaders } = transforms({ ...options, isBackend: true });
const runScriptNodeArgs = new Array<string>();
if (options.inspectEnabled) {
+3 -2
View File
@@ -25,12 +25,13 @@ type Transforms = {
type TransformOptions = {
isDev: boolean;
isBackend?: boolean;
};
export const transforms = (options: TransformOptions): Transforms => {
const { isDev } = options;
const { isDev, isBackend } = options;
const extraTransforms = isDev ? ['react-hot-loader'] : [];
const extraTransforms = isDev && !isBackend ? ['react-hot-loader'] : [];
// This ensures that styles inserted from the style-loader and any
// async style chunks are always given lower priority than JSS styles.
+1
View File
@@ -19,6 +19,7 @@ export type ConfigSchema = {
// @public
export type ConfigSchemaProcessingOptions = {
visibility?: ConfigVisibility[];
ignoreSchemaErrors?: boolean;
valueTransform?: TransformFunc<any>;
withFilteredKeys?: boolean;
withDeprecatedKeys?: boolean;
@@ -275,5 +275,12 @@ describe('loadConfigSchema', () => {
).toThrow(
"Config must have required property 'x a' { missingProperty=x a } at /other",
);
expect(
schema.process([{ data: { other: {} }, context: 'test' }], {
visibility: ['frontend'],
ignoreSchemaErrors: true,
}),
).toEqual([{ data: {}, context: 'test' }]);
});
});
+17 -9
View File
@@ -82,18 +82,26 @@ export async function loadConfigSchema(
return {
process(
configs: AppConfig[],
{ visibility, valueTransform, withFilteredKeys, withDeprecatedKeys } = {},
{
visibility,
valueTransform,
withFilteredKeys,
withDeprecatedKeys,
ignoreSchemaErrors,
} = {},
): AppConfig[] {
const result = validate(configs);
const visibleErrors = filterErrorsByVisibility(
result.errors,
visibility,
result.visibilityByDataPath,
result.visibilityBySchemaPath,
);
if (visibleErrors.length > 0) {
throw errorsToError(visibleErrors);
if (!ignoreSchemaErrors) {
const visibleErrors = filterErrorsByVisibility(
result.errors,
visibility,
result.visibilityByDataPath,
result.visibilityBySchemaPath,
);
if (visibleErrors.length > 0) {
throw errorsToError(visibleErrors);
}
}
let processedConfigs = configs;
@@ -117,6 +117,11 @@ export type ConfigSchemaProcessingOptions = {
*/
visibility?: ConfigVisibility[];
/**
* When set to `true`, any schema errors in the provided configuration will be ignored.
*/
ignoreSchemaErrors?: boolean;
/**
* A transform function that can be used to transform primitive configuration values
* during validation. The value returned from the transform function will be used
@@ -37,6 +37,10 @@
"prettier": "^2.3.2",
"typescript": "~4.5.4"
},
"resolutions": {
"@types/react": "^17",
"@types/react-dom": "^17"
},
"prettier": "@spotify/prettier-config",
"lint-staged": {
"*.{js,jsx,ts,tsx,mjs,cjs}": [
@@ -35,11 +35,10 @@
{{/if}}
"@backstage/plugin-search-backend-node": "^{{version '@backstage/plugin-search-backend-node'}}",
"@backstage/plugin-techdocs-backend": "^{{version '@backstage/plugin-techdocs-backend'}}",
"@gitbeaker/node": "^34.6.0",
"@octokit/rest": "^18.5.3",
"dockerode": "^3.3.1",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"luxon": "^2.0.2",
{{#if dbTypePG}}
"pg": "^8.3.0",
{{/if}}
@@ -52,7 +51,8 @@
"@backstage/cli": "^{{version '@backstage/cli'}}",
"@types/dockerode": "^3.3.0",
"@types/express": "^4.17.6",
"@types/express-serve-static-core": "^4.17.5"
"@types/express-serve-static-core": "^4.17.5",
"@types/luxon": "^2.0.4"
},
"files": [
"dist"
@@ -11,6 +11,7 @@ import { PluginEnvironment } from '../types';
import { DefaultCatalogCollatorFactory } from '@backstage/plugin-catalog-backend';
import { DefaultTechDocsCollatorFactory } from '@backstage/plugin-techdocs-backend';
import { Router } from 'express';
import { Duration } from 'luxon';
export default async function createPlugin(
env: PluginEnvironment,
@@ -31,10 +32,18 @@ export default async function createPlugin(
searchEngine,
});
const schedule = env.scheduler.createScheduledTaskRunner({
frequency: Duration.fromObject({ minutes: 10 }),
timeout: Duration.fromObject({ minutes: 15 }),
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
initialDelay: Duration.fromObject({ seconds: 3 }),
});
// Collators are responsible for gathering documents known to plugins. This
// collator gathers entities from the software catalog.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
schedule,
factory: DefaultCatalogCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
tokenManager: env.tokenManager,
@@ -43,7 +52,7 @@ export default async function createPlugin(
// collator gathers entities from techdocs.
indexBuilder.addCollator({
defaultRefreshIntervalSeconds: 600,
schedule,
factory: DefaultTechDocsCollatorFactory.fromConfig(env.config, {
discovery: env.discovery,
logger: env.logger,
@@ -54,10 +63,8 @@ export default async function createPlugin(
// The scheduler controls when documents are gathered from collators and sent
// to the search engine for indexing.
const { scheduler } = await indexBuilder.build();
scheduler.start();
// A 3 second delay gives the backend server a chance to initialize before
// any collators are executed, which may attempt requests against the API.
setTimeout(() => scheduler.start(), 3000);
useHotCleanup(module, () => scheduler.stop());
return await createRouter({
@@ -8,7 +8,7 @@ import {
UrlReader,
} from '@backstage/backend-common';
import { PluginTaskScheduler } from '@backstage/backend-tasks';
import { PermissionAuthorizer } from '@backstage/plugin-permission-common';
import { PermissionEvaluator } from '@backstage/plugin-permission-common';
export type PluginEnvironment = {
logger: Logger;
@@ -19,5 +19,5 @@ export type PluginEnvironment = {
discovery: PluginEndpointDiscovery;
tokenManager: TokenManager;
scheduler: PluginTaskScheduler;
permissions: PermissionAuthorizer;
permissions: PermissionEvaluator;
};