Merge branch 'master' into feat/customSearchModal
This commit is contained in:
@@ -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>
|
||||
);
|
||||
};
|
||||
@@ -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>();
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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' }]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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"
|
||||
|
||||
+12
-5
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user