Merge pull request #757 from spotify/rugvip/nav-targets
packages/core: added basic nav target implementation
This commit is contained in:
@@ -84,6 +84,19 @@ export default class AppBuilder {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'nav-target-component': {
|
||||
const { target, component, options = {} } = output;
|
||||
const { exact = true } = options;
|
||||
routes.push(
|
||||
<Route
|
||||
key={`${plugin.getId()}-${target.path}`}
|
||||
path={target.path}
|
||||
component={component}
|
||||
exact={exact}
|
||||
/>,
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'redirect-route': {
|
||||
const { path, target, options = {} } = output;
|
||||
const { exact = true } = options;
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
|
||||
export * from './api';
|
||||
export * from './apis';
|
||||
export * from './navTargets';
|
||||
export { FeatureFlags } from './app/FeatureFlags';
|
||||
export { useApp } from './app/AppContext';
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 type { NavTargetConfig, NavTargetOverrideConfig } from './types';
|
||||
|
||||
export class MutableNavTarget {
|
||||
private effectiveConfig: NavTargetConfig = this.config;
|
||||
|
||||
constructor(private readonly config: NavTargetConfig) {}
|
||||
|
||||
override(overrideConfig: NavTargetOverrideConfig) {
|
||||
this.effectiveConfig = { ...this.config, ...overrideConfig };
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.effectiveConfig.icon;
|
||||
}
|
||||
|
||||
get path() {
|
||||
return this.effectiveConfig.path;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return this.effectiveConfig.title;
|
||||
}
|
||||
}
|
||||
|
||||
export function createNavTarget(config: NavTargetConfig): MutableNavTarget {
|
||||
return new MutableNavTarget(config);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export type { NavTarget, NavTargetConfig, NavTargetOverrideConfig } from './types';
|
||||
export { createNavTarget } from './NavTarget';
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 { IconComponent } from '../../icons';
|
||||
|
||||
export type NavTarget = {
|
||||
path: string;
|
||||
icon: IconComponent;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type NavTargetConfig = {
|
||||
path: string;
|
||||
icon: IconComponent;
|
||||
title: string;
|
||||
};
|
||||
|
||||
export type NavTargetOverrideConfig = {
|
||||
path?: string;
|
||||
icon?: IconComponent;
|
||||
title?: string;
|
||||
};
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
FeatureFlagName,
|
||||
} from './types';
|
||||
import { validateBrowserCompat, validateFlagName } from '../app/FeatureFlags';
|
||||
import { NavTarget } from '../navTargets';
|
||||
|
||||
export type PluginConfig = {
|
||||
id: string;
|
||||
@@ -34,6 +35,12 @@ export type PluginHooks = {
|
||||
};
|
||||
|
||||
export type RouterHooks = {
|
||||
addRoute(
|
||||
target: NavTarget,
|
||||
Component: ComponentType<any>,
|
||||
options?: RouteOptions,
|
||||
): void;
|
||||
|
||||
registerRoute(
|
||||
path: RoutePath,
|
||||
Component: ComponentType<any>,
|
||||
@@ -75,6 +82,14 @@ export default class Plugin {
|
||||
|
||||
this.config.register({
|
||||
router: {
|
||||
addRoute(target, component, options) {
|
||||
outputs.push({
|
||||
type: 'nav-target-component',
|
||||
target,
|
||||
component,
|
||||
options,
|
||||
});
|
||||
},
|
||||
registerRoute(path, component, options) {
|
||||
outputs.push({ type: 'route', path, component, options });
|
||||
},
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
import { ComponentType } from 'react';
|
||||
import { NavTarget } from '../navTargets';
|
||||
|
||||
export type RouteOptions = {
|
||||
// Whether the route path must match exactly, defaults to true.
|
||||
@@ -30,6 +31,13 @@ export type RouteOutput = {
|
||||
options?: RouteOptions;
|
||||
};
|
||||
|
||||
export type RouteTargetOutput = {
|
||||
type: 'nav-target-component';
|
||||
target: NavTarget;
|
||||
component: ComponentType<{}>;
|
||||
options?: RouteOptions;
|
||||
};
|
||||
|
||||
export type RedirectRouteOutput = {
|
||||
type: 'redirect-route';
|
||||
path: RoutePath;
|
||||
@@ -46,5 +54,6 @@ export type FeatureFlagOutput = {
|
||||
|
||||
export type PluginOutput =
|
||||
| RouteOutput
|
||||
| RouteTargetOutput
|
||||
| RedirectRouteOutput
|
||||
| FeatureFlagOutput;
|
||||
|
||||
@@ -14,19 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Link,
|
||||
makeStyles,
|
||||
styled,
|
||||
SvgIcon,
|
||||
Theme,
|
||||
Typography,
|
||||
} from '@material-ui/core';
|
||||
import { Link, makeStyles, styled, Theme, Typography } from '@material-ui/core';
|
||||
import clsx from 'clsx';
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { sidebarConfig, SidebarContext } from './config';
|
||||
import { IconComponent } from '../../icons';
|
||||
|
||||
const useStyles = makeStyles<Theme>(theme => ({
|
||||
const useStyles = makeStyles<Theme>((theme) => ({
|
||||
root: {
|
||||
color: '#b5b5b5',
|
||||
display: 'flex',
|
||||
@@ -59,7 +53,7 @@ const useStyles = makeStyles<Theme>(theme => ({
|
||||
}));
|
||||
|
||||
type SidebarItemProps = {
|
||||
icon: typeof SvgIcon;
|
||||
icon: IconComponent;
|
||||
text: string;
|
||||
to?: string;
|
||||
onClick?: () => void;
|
||||
|
||||
@@ -127,6 +127,18 @@ class DevAppBuilder {
|
||||
);
|
||||
break;
|
||||
}
|
||||
case 'nav-target-component': {
|
||||
const { target } = output;
|
||||
sidebarItems.push(
|
||||
<SidebarItem
|
||||
key={target.path}
|
||||
to={target.path}
|
||||
text={target.title}
|
||||
icon={target.icon}
|
||||
/>,
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
|
||||
export { plugin } from './plugin';
|
||||
export * from './lib/api';
|
||||
export * from './navTargets';
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2020 Spotify AB
|
||||
*
|
||||
* 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 React, { FC } from 'react';
|
||||
import { createNavTarget } from '@backstage/core';
|
||||
import { SvgIcon, SvgIconProps } from '@material-ui/core';
|
||||
|
||||
const GraphiQLIcon: FC<SvgIconProps> = props => (
|
||||
<SvgIcon {...props}>
|
||||
<g id="surface1">
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 3.449219 18.160156 L 2.585938 17.660156 L 12.195312 1.019531 L 13.058594 1.515625 Z M 3.449219 18.160156 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 2.386719 16.332031 L 21.605469 16.332031 L 21.605469 17.328125 L 2.386719 17.328125 Z M 2.386719 16.332031 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 12.382812 22.441406 L 2.769531 16.890625 L 3.265625 16.027344 L 12.878906 21.578125 Z M 12.382812 22.441406 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 20.730469 7.976562 L 11.117188 2.425781 L 11.617188 1.5625 L 21.230469 7.113281 Z M 20.730469 7.976562 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 3.269531 7.972656 L 2.769531 7.109375 L 12.382812 1.558594 L 12.882812 2.421875 Z M 3.269531 7.972656 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 20.554688 18.160156 L 10.945312 1.515625 L 11.808594 1.019531 L 21.417969 17.660156 Z M 20.554688 18.160156 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 3.148438 6.449219 L 4.144531 6.449219 L 4.144531 17.550781 L 3.148438 17.550781 Z M 3.148438 6.449219 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 19.855469 6.449219 L 20.851562 6.449219 L 20.851562 17.550781 L 19.855469 17.550781 Z M 19.855469 6.449219 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 12.210938 22.019531 L 11.777344 21.265625 L 20.136719 16.441406 L 20.570312 17.191406 Z M 12.210938 22.019531 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 22.171875 17.875 C 21.59375 18.875 20.308594 19.21875 19.308594 18.640625 C 18.304688 18.066406 17.964844 16.78125 18.539062 15.78125 C 19.117188 14.777344 20.398438 14.4375 21.402344 15.011719 C 22.410156 15.59375 22.753906 16.871094 22.171875 17.875 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 5.453125 8.21875 C 4.878906 9.222656 3.59375 9.5625 2.59375 8.988281 C 1.589844 8.410156 1.246094 7.128906 1.824219 6.125 C 2.398438 5.125 3.683594 4.78125 4.6875 5.359375 C 5.6875 5.941406 6.03125 7.21875 5.453125 8.21875 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 1.828125 17.875 C 1.253906 16.871094 1.597656 15.59375 2.597656 15.011719 C 3.601562 14.4375 4.878906 14.777344 5.460938 15.78125 C 6.035156 16.78125 5.695312 18.058594 4.691406 18.640625 C 3.683594 19.21875 2.40625 18.875 1.828125 17.875 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 18.546875 8.21875 C 17.96875 7.21875 18.3125 5.941406 19.3125 5.359375 C 20.316406 4.78125 21.59375 5.125 22.175781 6.125 C 22.753906 7.128906 22.410156 8.40625 21.40625 8.988281 C 20.40625 9.5625 19.121094 9.222656 18.546875 8.21875 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 12 23.746094 C 10.84375 23.746094 9.90625 22.8125 9.90625 21.652344 C 9.90625 20.496094 10.84375 19.558594 12 19.558594 C 13.15625 19.558594 14.09375 20.496094 14.09375 21.652344 C 14.09375 22.804688 13.15625 23.746094 12 23.746094 "
|
||||
/>
|
||||
<path
|
||||
fill="#E535AB"
|
||||
d="M 12 4.441406 C 10.84375 4.441406 9.90625 3.503906 9.90625 2.347656 C 9.90625 1.1875 10.84375 0.253906 12 0.253906 C 13.15625 0.253906 14.09375 1.1875 14.09375 2.347656 C 14.09375 3.503906 13.15625 4.441406 12 4.441406 "
|
||||
/>
|
||||
</g>
|
||||
</SvgIcon>
|
||||
);
|
||||
|
||||
export const navTargetGraphiQL = createNavTarget({
|
||||
icon: GraphiQLIcon,
|
||||
path: '/graphiql',
|
||||
title: 'GraphiQL',
|
||||
});
|
||||
@@ -16,10 +16,11 @@
|
||||
|
||||
import { createPlugin } from '@backstage/core';
|
||||
import { GraphiQLPage } from './components';
|
||||
import { navTargetGraphiQL } from './navTargets';
|
||||
|
||||
export const plugin = createPlugin({
|
||||
id: 'graphiql',
|
||||
register({ router }) {
|
||||
router.registerRoute('/graphiql', GraphiQLPage);
|
||||
router.addRoute(navTargetGraphiQL, GraphiQLPage);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user