From 6331ec1ebcf5c38cda32773fc2afb3ea54823d4f Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 1 Apr 2022 12:21:59 +0200 Subject: [PATCH] scaffolder: add context menu with links to preview and actions Signed-off-by: Patrik Oldsberg --- .changeset/cold-steaks-provide.md | 5 + plugins/scaffolder/api-report.md | 4 + plugins/scaffolder/src/components/Router.tsx | 10 ++ .../ScaffolderPage/ScaffolderPage.tsx | 10 +- .../ScaffolderPageContextMenu.tsx | 107 ++++++++++++++++++ 5 files changed, 135 insertions(+), 1 deletion(-) create mode 100644 .changeset/cold-steaks-provide.md create mode 100644 plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx diff --git a/.changeset/cold-steaks-provide.md b/.changeset/cold-steaks-provide.md new file mode 100644 index 0000000000..8a107f7b53 --- /dev/null +++ b/.changeset/cold-steaks-provide.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder': minor +--- + +Added a context menu to the scaffolder page that provides links to the template editor and actions reference. These links and the presence of the context menu can be toggled through the `contextMenu` prop of the scaffolder page. diff --git a/plugins/scaffolder/api-report.md b/plugins/scaffolder/api-report.md index f1ab23c320..20945d08a6 100644 --- a/plugins/scaffolder/api-report.md +++ b/plugins/scaffolder/api-report.md @@ -217,6 +217,10 @@ export type RouterProps = { filter: (entity: Entity) => boolean; }>; defaultPreviewTemplate?: string; + contextMenu?: { + editor?: boolean; + actions?: boolean; + }; }; // @public diff --git a/plugins/scaffolder/src/components/Router.tsx b/plugins/scaffolder/src/components/Router.tsx index f46a4cc111..c3efce1020 100644 --- a/plugins/scaffolder/src/components/Router.tsx +++ b/plugins/scaffolder/src/components/Router.tsx @@ -49,6 +49,15 @@ export type RouterProps = { filter: (entity: Entity) => boolean; }>; defaultPreviewTemplate?: string; + /** + * Options for the context menu on the scaffolder page. + */ + contextMenu?: { + /** Whether to show a link to the template editor */ + editor?: boolean; + /** Whether to show a link to the actions documentation */ + actions?: boolean; + }; }; /** @@ -92,6 +101,7 @@ export const Router = (props: RouterProps) => { } /> diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx index a68e320c13..79d176cd11 100644 --- a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPage.tsx @@ -39,6 +39,7 @@ import { TemplateList } from '../TemplateList'; import { TemplateTypePicker } from '../TemplateTypePicker'; import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common'; import { usePermission } from '@backstage/plugin-permission-react'; +import { ScaffolderPageContextMenu } from './ScaffolderPageContextMenu'; export type ScaffolderPageProps = { TemplateCardComponent?: @@ -48,11 +49,16 @@ export type ScaffolderPageProps = { title?: React.ReactNode; filter: (entity: Entity) => boolean; }>; + contextMenu?: { + editor?: boolean; + actions?: boolean; + }; }; export const ScaffolderPageContents = ({ TemplateCardComponent, groups, + contextMenu, }: ScaffolderPageProps) => { const registerComponentLink = useRouteRef(registerComponentRouteRef); const otherTemplatesGroup = { @@ -73,7 +79,9 @@ export const ScaffolderPageContents = ({ pageTitleOverride="Create a New Component" title="Create a New Component" subtitle="Create new software components using standard templates" - /> + > + + {allowed && ( diff --git a/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx new file mode 100644 index 0000000000..b79f8917f6 --- /dev/null +++ b/plugins/scaffolder/src/components/ScaffolderPage/ScaffolderPageContextMenu.tsx @@ -0,0 +1,107 @@ +/* + * Copyright 2020 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 { useRouteRef } from '@backstage/core-plugin-api'; +import IconButton from '@material-ui/core/IconButton'; +import ListItemIcon from '@material-ui/core/ListItemIcon'; +import ListItemText from '@material-ui/core/ListItemText'; +import MenuItem from '@material-ui/core/MenuItem'; +import MenuList from '@material-ui/core/MenuList'; +import Popover from '@material-ui/core/Popover'; +import { makeStyles } from '@material-ui/core/styles'; +import Description from '@material-ui/icons/Description'; +import Edit from '@material-ui/icons/Edit'; +import MoreVert from '@material-ui/icons/MoreVert'; +import React, { useState } from 'react'; +import { useNavigate } from 'react-router'; +import { rootRouteRef } from '../../routes'; + +const useStyles = makeStyles({ + button: { + color: 'white', + }, +}); + +export type ScaffolderPageContextMenuProps = { + editor?: boolean; + actions?: boolean; +}; + +export function ScaffolderPageContextMenu( + props: ScaffolderPageContextMenuProps, +) { + const classes = useStyles(); + const [anchorEl, setAnchorEl] = useState(); + const pageLink = useRouteRef(rootRouteRef); + const navigate = useNavigate(); + + const showEditor = props.editor !== false; + const showActions = props.actions !== false; + + if (!showEditor && !showActions) { + return null; + } + + const onOpen = (event: React.SyntheticEvent) => { + setAnchorEl(event.currentTarget); + }; + + const onClose = () => { + setAnchorEl(undefined); + }; + + return ( + <> + + + + + + {showEditor && ( + navigate(`${pageLink()}/preview`)}> + + + + + + )} + {showActions && ( + navigate(`${pageLink()}/actions`)}> + + + + + + )} + + + + ); +}