From 3e9e8203f34164d459834c714397b9c45f684d01 Mon Sep 17 00:00:00 2001 From: djamaile Date: Wed, 5 Oct 2022 16:42:36 +0200 Subject: [PATCH 01/24] feat: add GroupListPicker component Signed-off-by: djamaile --- .../GroupListPicker/GroupListPicker.test.tsx | 114 ++++++++++++++ .../GroupListPicker/GroupListPicker.tsx | 140 ++++++++++++++++++ .../src/components/GroupListPicker/index.ts | 17 +++ plugins/catalog-react/src/components/index.ts | 1 + 4 files changed, 272 insertions(+) create mode 100644 plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx create mode 100644 plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx create mode 100644 plugins/catalog-react/src/components/GroupListPicker/index.ts diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx new file mode 100644 index 0000000000..77d1eead6d --- /dev/null +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -0,0 +1,114 @@ +/* + * Copyright 2022 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 React from 'react'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import { ApiProvider } from '@backstage/core-app-api'; +import { catalogApiRef } from '../../api'; +import { CatalogApi } from '@backstage/catalog-client'; +import { GroupListPicker } from '../GroupListPicker'; +import { GroupEntity } from '@backstage/catalog-model'; +import { TestApiRegistry } from '@backstage/test-utils'; + +const mockGroups: GroupEntity[] = [ + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + namespace: 'default', + name: 'group-a', + }, + spec: { + type: 'org', + profile: { + displayName: 'Group A', + }, + children: [], + }, + }, + { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Group', + metadata: { + namespace: 'default', + name: 'group-b', + }, + spec: { + type: 'department', + profile: { + displayName: 'Group B', + }, + children: [], + }, + }, +]; + +const mockCatalogApi = { + getEntities: () => Promise.resolve({ items: mockGroups }), +} as Partial; + +const apis = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); + +describe('', () => { + it('renders group list picker', () => { + const { queryByText } = render( + + + , + ); + + expect(queryByText('test')).toBeInTheDocument(); + }); + + it('open group list picker', () => { + const { getByTestId, getAllByText } = render( + + + , + ); + + fireEvent.click(getByTestId('group-list-picker-button')); + expect(getAllByText('Search unique').length).toBeGreaterThan(0); + }); + + it('can choose a group', async () => { + const { getByText, queryByText, getByTestId } = render( + + + , + ); + + fireEvent.click(getByTestId('group-list-picker-button')); + const input = getByTestId('group-list-picker-input').querySelector('input'); + fireEvent.change(input as HTMLElement, { target: { value: 'GR' } }); + + await waitFor(() => { + expect(queryByText('Group A')).toBeInTheDocument(); + fireEvent.click(getByText('Group A')); + expect(getByText('Group A')).toBeInTheDocument(); + }); + }); +}); diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx new file mode 100644 index 0000000000..ba0e2841af --- /dev/null +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -0,0 +1,140 @@ +/* + * Copyright 2022 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 React from 'react'; +import { catalogApiRef } from '../../api'; +import TextField from '@material-ui/core/TextField'; +import Autocomplete from '@material-ui/lab/Autocomplete'; +import useAsync from 'react-use/lib/useAsync'; +import Popover from '@material-ui/core/Popover'; +import { useApi } from '@backstage/core-plugin-api'; +import { ResponseErrorPanel } from '@backstage/core-components'; +import { GroupEntity } from '@backstage/catalog-model'; +import { makeStyles, Box, Typography } from '@material-ui/core'; +import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; +import PeopleIcon from '@material-ui/icons/People'; + +const useStyles = makeStyles({ + btn: { + backgroundColor: 'transparent', + border: 'none', + margin: 0, + padding: 0, + }, + title: { + fontStyle: 'normal', + fontWeight: 700, + fontSize: '24px', + lineHeight: '32px', + letterSpacing: '-0.25px', + }, +}); + +type GroupListPickerProps = { + label: string; + groupTypes: Array; + defaultGroup?: string; +}; +export const GroupListPicker = (props: GroupListPickerProps) => { + const classes = useStyles(); + const catalogApi = useApi(catalogApiRef); + const { label, groupTypes, defaultGroup = '' } = props; + const [anchorEl, setAnchorEl] = React.useState(null); + const [inputValue, setInputValue] = React.useState(''); + const [group, setGroup] = React.useState(defaultGroup); + + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + + const handleClose = () => { + setAnchorEl(null); + }; + + const open = Boolean(anchorEl); + const id = open ? 'simple-popover' : undefined; + + const { + loading, + error, + value: groups, + } = useAsync(async () => { + const groupsList = await catalogApi.getEntities({ + filter: { + kind: 'Group', + 'spec.type': groupTypes, + }, + }); + + return groupsList.items as GroupEntity[]; + }, [catalogApi]); + + if (error) { + return ; + } + + return ( + <> + + option.spec.type} + getOptionLabel={option => option.spec.profile?.displayName ?? ''} + inputValue={inputValue} + onInputChange={(_, value) => setInputValue(value)} + onChange={(_, newValue) => { + if (newValue) { + setGroup(newValue.spec.profile?.displayName ?? ''); + } + setInputValue(''); + }} + style={{ width: '200px', margin: '8px' }} + renderInput={params => ( + + )} + /> + + + + ); +}; diff --git a/plugins/catalog-react/src/components/GroupListPicker/index.ts b/plugins/catalog-react/src/components/GroupListPicker/index.ts new file mode 100644 index 0000000000..be2819c850 --- /dev/null +++ b/plugins/catalog-react/src/components/GroupListPicker/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 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. + */ + +export { GroupListPicker } from './GroupListPicker'; diff --git a/plugins/catalog-react/src/components/index.ts b/plugins/catalog-react/src/components/index.ts index c604306ead..90fe108ab7 100644 --- a/plugins/catalog-react/src/components/index.ts +++ b/plugins/catalog-react/src/components/index.ts @@ -28,3 +28,4 @@ export * from './InspectEntityDialog'; export * from './UnregisterEntityDialog'; export * from './UserListPicker'; export * from './EntityProcessingStatusPicker'; +export * from './GroupListPicker'; From bcc4686e367323fdda371b01ea9d5c908e06e8f7 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 6 Oct 2022 09:34:43 +0200 Subject: [PATCH 02/24] chore: add changeset Signed-off-by: djamaile --- .changeset/hungry-rocks-bathe.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/hungry-rocks-bathe.md diff --git a/.changeset/hungry-rocks-bathe.md b/.changeset/hungry-rocks-bathe.md new file mode 100644 index 0000000000..7c22f1b368 --- /dev/null +++ b/.changeset/hungry-rocks-bathe.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-catalog-react': patch +--- + +Added a `AutoComplete` component that will give the user the ability to choose a group From 6797f03690f25534f26ce757d8471bffcd12c155 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 6 Oct 2022 09:49:22 +0200 Subject: [PATCH 03/24] chore: add api-report Signed-off-by: djamaile --- plugins/catalog-react/api-report.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index e8f0b0e6ee..bea429d047 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -446,6 +446,16 @@ export function getEntitySourceLocation( scmIntegrationsApi: ScmIntegrationRegistry, ): EntitySourceLocation | undefined; +// @public (undocumented) +export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; + +// @public +export type GroupListPickerProps = { + label: string; + groupTypes: Array; + defaultGroup?: string; +}; + // @public (undocumented) export function humanizeEntityRef( entityRef: Entity | CompoundEntityRef, From b8a2a96d13ff31005d90202600492397ab6024a5 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 6 Oct 2022 10:43:21 +0200 Subject: [PATCH 04/24] chore: add api-report Signed-off-by: djamaile --- .../src/components/GroupListPicker/GroupListPicker.tsx | 9 ++++++++- .../src/components/GroupListPicker/index.ts | 1 + 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index ba0e2841af..98e7be3624 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -43,11 +43,18 @@ const useStyles = makeStyles({ }, }); -type GroupListPickerProps = { +/** + * Props for {@link GroupListPicker}. + * + * @public + */ +export type GroupListPickerProps = { label: string; groupTypes: Array; defaultGroup?: string; }; + +/** @public */ export const GroupListPicker = (props: GroupListPickerProps) => { const classes = useStyles(); const catalogApi = useApi(catalogApiRef); diff --git a/plugins/catalog-react/src/components/GroupListPicker/index.ts b/plugins/catalog-react/src/components/GroupListPicker/index.ts index be2819c850..fe1ba8e1ee 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/index.ts +++ b/plugins/catalog-react/src/components/GroupListPicker/index.ts @@ -15,3 +15,4 @@ */ export { GroupListPicker } from './GroupListPicker'; +export type { GroupListPickerProps } from './GroupListPicker'; From a115ce5132c529168d0a657ffc0371301b458d09 Mon Sep 17 00:00:00 2001 From: Mathias Bronner Date: Thu, 6 Oct 2022 12:07:44 +0200 Subject: [PATCH 05/24] fix layout for trigger button Signed-off-by: Mathias Bronner --- .../GroupListPicker/GroupListPicker.tsx | 25 ++++++++++--------- .../CatalogPage/DefaultCatalogPage.tsx | 6 +++++ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index ba0e2841af..f5ba1c7198 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -33,13 +33,15 @@ const useStyles = makeStyles({ border: 'none', margin: 0, padding: 0, + width: '100%', }, title: { + fontSize: '24px', fontStyle: 'normal', fontWeight: 700, - fontSize: '24px', - lineHeight: '32px', letterSpacing: '-0.25px', + lineHeight: '32px', + marginBottom: 0, }, }); @@ -51,6 +53,7 @@ type GroupListPickerProps = { export const GroupListPicker = (props: GroupListPickerProps) => { const classes = useStyles(); const catalogApi = useApi(catalogApiRef); + const { label, groupTypes, defaultGroup = '' } = props; const [anchorEl, setAnchorEl] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); @@ -109,9 +112,9 @@ export const GroupListPicker = (props: GroupListPickerProps) => { } setInputValue(''); }} - style={{ width: '200px', margin: '8px' }} + style={{ width: '200px' }} renderInput={params => ( - + )} /> @@ -122,17 +125,15 @@ export const GroupListPicker = (props: GroupListPickerProps) => { className={classes.btn} data-testid="group-list-picker-button" > - - + + {group} - + diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index 2bae104d90..c465dc7c85 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -35,6 +35,7 @@ import { UserListFilterKind, UserListPicker, EntityKindPicker, + GroupListPicker, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { createComponentRouteRef } from '../../routes'; @@ -84,6 +85,11 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { + From 0c0ac14bc43dabe459a22e132a3ae28c3825a1e3 Mon Sep 17 00:00:00 2001 From: Mathias Bronner Date: Thu, 6 Oct 2022 13:43:58 +0200 Subject: [PATCH 06/24] clean up dev instance of component Signed-off-by: Mathias Bronner --- .../src/components/CatalogPage/DefaultCatalogPage.tsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index c465dc7c85..ac010b539c 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -85,11 +85,6 @@ export function DefaultCatalogPage(props: DefaultCatalogPageProps) { - From 88d55868e59fb079cfe50098120cb9064a239294 Mon Sep 17 00:00:00 2001 From: Mathias Bronner Date: Thu, 6 Oct 2022 13:50:21 +0200 Subject: [PATCH 07/24] remove unused dep import Signed-off-by: Mathias Bronner --- .../catalog/src/components/CatalogPage/DefaultCatalogPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx index ac010b539c..2bae104d90 100644 --- a/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx +++ b/plugins/catalog/src/components/CatalogPage/DefaultCatalogPage.tsx @@ -35,7 +35,6 @@ import { UserListFilterKind, UserListPicker, EntityKindPicker, - GroupListPicker, } from '@backstage/plugin-catalog-react'; import React from 'react'; import { createComponentRouteRef } from '../../routes'; From aa2676dcbe3aed39bdb6db13144a8343d936dbe8 Mon Sep 17 00:00:00 2001 From: Mathias Bronner Date: Thu, 6 Oct 2022 14:23:16 +0200 Subject: [PATCH 08/24] rename label prop to placeholder and remove obsolete test case Signed-off-by: Mathias Bronner --- .../GroupListPicker/GroupListPicker.test.tsx | 18 ++---------------- .../GroupListPicker/GroupListPicker.tsx | 10 +++++++--- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx index 77d1eead6d..6b89612354 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -67,7 +67,7 @@ describe('', () => { const { queryByText } = render( @@ -77,25 +77,11 @@ describe('', () => { expect(queryByText('test')).toBeInTheDocument(); }); - it('open group list picker', () => { - const { getByTestId, getAllByText } = render( - - - , - ); - - fireEvent.click(getByTestId('group-list-picker-button')); - expect(getAllByText('Search unique').length).toBeGreaterThan(0); - }); - it('can choose a group', async () => { const { getByText, queryByText, getByTestId } = render( , diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index eb504880f3..d810d44d57 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -51,7 +51,7 @@ const useStyles = makeStyles({ * @public */ export type GroupListPickerProps = { - label: string; + placeholder: string; groupTypes: Array; defaultGroup?: string; }; @@ -61,7 +61,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { const classes = useStyles(); const catalogApi = useApi(catalogApiRef); - const { label, groupTypes, defaultGroup = '' } = props; + const { placeholder, groupTypes, defaultGroup = '' } = props; const [anchorEl, setAnchorEl] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); const [group, setGroup] = React.useState(defaultGroup); @@ -121,7 +121,11 @@ export const GroupListPicker = (props: GroupListPickerProps) => { }} style={{ width: '200px' }} renderInput={params => ( - + )} /> From 3bc5d044f8db78371b6f5b192959faa460b65dac Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 6 Oct 2022 14:35:07 +0200 Subject: [PATCH 09/24] chore: run api-report again Signed-off-by: djamaile --- plugins/catalog-react/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index bea429d047..5de39164be 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -451,7 +451,7 @@ export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; // @public export type GroupListPickerProps = { - label: string; + placeholder: string; groupTypes: Array; defaultGroup?: string; }; From 4d114d172d8e7e1803f1340860aff3f31937cedb Mon Sep 17 00:00:00 2001 From: djamaile Date: Fri, 7 Oct 2022 16:37:49 +0200 Subject: [PATCH 10/24] Update plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx Co-authored-by: Philipp Hugenroth Signed-off-by: djamaile --- .../src/components/GroupListPicker/GroupListPicker.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index d810d44d57..76bfbed22c 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -137,7 +137,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { data-testid="group-list-picker-button" > - + ({ marginRight: theme.spacing(1) }) } /> {group} From 97a6246539c890cbf3d61edc32882f7ecf153a02 Mon Sep 17 00:00:00 2001 From: djamaile Date: Fri, 7 Oct 2022 17:23:28 +0200 Subject: [PATCH 11/24] chore: clean up and respond to phillip comments Signed-off-by: djamaile --- plugins/catalog-react/api-report.md | 13 ++- .../GroupListPicker/GroupListPicker.tsx | 58 +++---------- .../GroupListPicker/GroupListPickerButton.tsx | 81 +++++++++++++++++++ .../src/components/GroupListPicker/index.ts | 2 + 4 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index 5de39164be..e4fcd59857 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -449,9 +449,20 @@ export function getEntitySourceLocation( // @public (undocumented) export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; +// @public (undocumented) +export const GroupListPickerButton: ( + props: GroupListPickerButtonProps, +) => JSX.Element; + +// @public +export type GroupListPickerButtonProps = { + handleClick: (event: React_2.MouseEvent) => void; + group: string; +}; + // @public export type GroupListPickerProps = { - placeholder: string; + placeholder?: string; groupTypes: Array; defaultGroup?: string; }; diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index 76bfbed22c..404ce2fc6f 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -23,27 +23,7 @@ import Popover from '@material-ui/core/Popover'; import { useApi } from '@backstage/core-plugin-api'; import { ResponseErrorPanel } from '@backstage/core-components'; import { GroupEntity } from '@backstage/catalog-model'; -import { makeStyles, Box, Typography } from '@material-ui/core'; -import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; -import PeopleIcon from '@material-ui/icons/People'; - -const useStyles = makeStyles({ - btn: { - backgroundColor: 'transparent', - border: 'none', - margin: 0, - padding: 0, - width: '100%', - }, - title: { - fontSize: '24px', - fontStyle: 'normal', - fontWeight: 700, - letterSpacing: '-0.25px', - lineHeight: '32px', - marginBottom: 0, - }, -}); +import { GroupListPickerButton } from './GroupListPickerButton'; /** * Props for {@link GroupListPicker}. @@ -51,22 +31,21 @@ const useStyles = makeStyles({ * @public */ export type GroupListPickerProps = { - placeholder: string; + placeholder?: string; groupTypes: Array; defaultGroup?: string; }; /** @public */ export const GroupListPicker = (props: GroupListPickerProps) => { - const classes = useStyles(); const catalogApi = useApi(catalogApiRef); - const { placeholder, groupTypes, defaultGroup = '' } = props; - const [anchorEl, setAnchorEl] = React.useState(null); + const { groupTypes, defaultGroup = '', placeholder = '' } = props; + const [anchorEl, setAnchorEl] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); const [group, setGroup] = React.useState(defaultGroup); - const handleClick = (event: React.MouseEvent) => { + const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); }; @@ -110,12 +89,16 @@ export const GroupListPicker = (props: GroupListPickerProps) => { loading={loading} options={groups ?? []} groupBy={option => option.spec.type} - getOptionLabel={option => option.spec.profile?.displayName ?? ''} + getOptionLabel={option => + option.spec.profile?.displayName ?? option.metadata.name + } inputValue={inputValue} onInputChange={(_, value) => setInputValue(value)} onChange={(_, newValue) => { if (newValue) { - setGroup(newValue.spec.profile?.displayName ?? ''); + setGroup( + newValue.spec.profile?.displayName ?? newValue.metadata.name, + ); } setInputValue(''); }} @@ -129,24 +112,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { )} /> - + ); }; diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx new file mode 100644 index 0000000000..a5a26ee9af --- /dev/null +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx @@ -0,0 +1,81 @@ +/* + * Copyright 2022 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 React from 'react'; +import { BackstageTheme } from '@backstage/theme'; +import { Box, makeStyles, Typography } from '@material-ui/core'; +import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; +import PeopleIcon from '@material-ui/icons/People'; + +const useStyles = makeStyles((theme: BackstageTheme) => ({ + btn: { + backgroundColor: 'transparent', + border: 'none', + margin: 0, + padding: 0, + width: '100%', + cursor: 'pointer', + }, + title: { + fontSize: '1.5rem', + fontStyle: 'normal', + fontWeight: theme.typography.fontWeightBold, + letterSpacing: '-0.25px', + lineHeight: '32px', + marginBottom: 0, + }, + peopleIcon: { + marginRight: theme.spacing(1), + }, + arrowDownIcon: { + marginLeft: 'auto', + }, +})); + +/** + * Props for {@link GroupListPickerButton}. + * + * @public + */ +export type GroupListPickerButtonProps = { + handleClick: (event: React.MouseEvent) => void; + group: string; +}; + +/** @public */ +export const GroupListPickerButton = (props: GroupListPickerButtonProps) => { + const { handleClick, group } = props; + const classes = useStyles(); + + return ( + + ); +}; diff --git a/plugins/catalog-react/src/components/GroupListPicker/index.ts b/plugins/catalog-react/src/components/GroupListPicker/index.ts index fe1ba8e1ee..20c4502838 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/index.ts +++ b/plugins/catalog-react/src/components/GroupListPicker/index.ts @@ -15,4 +15,6 @@ */ export { GroupListPicker } from './GroupListPicker'; +export { GroupListPickerButton } from './GroupListPickerButton'; export type { GroupListPickerProps } from './GroupListPicker'; +export type { GroupListPickerButtonProps } from './GroupListPickerButton'; From 6494177343044deda7a7dda4cff83711be427315 Mon Sep 17 00:00:00 2001 From: djamaile Date: Fri, 7 Oct 2022 17:32:58 +0200 Subject: [PATCH 12/24] chore: make areadescribedby hard coded Signed-off-by: djamaile --- .../src/components/GroupListPicker/GroupListPicker.tsx | 2 -- .../src/components/GroupListPicker/GroupListPickerButton.tsx | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx index 404ce2fc6f..ccb2690da0 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -54,7 +54,6 @@ export const GroupListPicker = (props: GroupListPickerProps) => { }; const open = Boolean(anchorEl); - const id = open ? 'simple-popover' : undefined; const { loading, @@ -85,7 +84,6 @@ export const GroupListPicker = (props: GroupListPickerProps) => { > option.spec.type} diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx index a5a26ee9af..8a952fb93c 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx +++ b/plugins/catalog-react/src/components/GroupListPicker/GroupListPickerButton.tsx @@ -65,6 +65,7 @@ export const GroupListPickerButton = (props: GroupListPickerButtonProps) => { onClick={handleClick} className={classes.btn} data-testid="group-list-picker-button" + aria-describedby="group-list-popover" > From e96274f1fe17587b33141f12d005019870dba176 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 14:26:18 +0200 Subject: [PATCH 13/24] feat: create new plugin called org-react Signed-off-by: djamaile --- .changeset/great-planes-arrive.md | 5 ++ plugins/catalog-react/api-report.md | 21 ------- plugins/catalog-react/src/components/index.ts | 1 - plugins/org-react/.eslintrc.js | 1 + plugins/org-react/README.md | 13 ++++ plugins/org-react/api-report.md | 15 +++++ plugins/org-react/package.json | 62 +++++++++++++++++++ .../GroupListPicker/GroupListPicker.test.tsx | 2 +- .../GroupListPicker/GroupListPicker.tsx | 21 ++++--- .../GroupListPicker/GroupListPickerButton.tsx | 7 +-- .../src/components/GroupListPicker/index.ts | 2 - plugins/org-react/src/index.ts | 16 +++++ plugins/org-react/src/plugin.test.ts | 22 +++++++ plugins/org-react/src/plugin.ts | 37 +++++++++++ plugins/org-react/src/routes.ts | 20 ++++++ plugins/org-react/src/setupTests.ts | 17 +++++ yarn.lock | 30 +++++++++ 17 files changed, 254 insertions(+), 38 deletions(-) create mode 100644 .changeset/great-planes-arrive.md create mode 100644 plugins/org-react/.eslintrc.js create mode 100644 plugins/org-react/README.md create mode 100644 plugins/org-react/api-report.md create mode 100644 plugins/org-react/package.json rename plugins/{catalog-react => org-react}/src/components/GroupListPicker/GroupListPicker.test.tsx (97%) rename plugins/{catalog-react => org-react}/src/components/GroupListPicker/GroupListPicker.tsx (84%) rename plugins/{catalog-react => org-react}/src/components/GroupListPicker/GroupListPickerButton.tsx (95%) rename plugins/{catalog-react => org-react}/src/components/GroupListPicker/index.ts (83%) create mode 100644 plugins/org-react/src/index.ts create mode 100644 plugins/org-react/src/plugin.test.ts create mode 100644 plugins/org-react/src/plugin.ts create mode 100644 plugins/org-react/src/routes.ts create mode 100644 plugins/org-react/src/setupTests.ts diff --git a/.changeset/great-planes-arrive.md b/.changeset/great-planes-arrive.md new file mode 100644 index 0000000000..92a5b985cd --- /dev/null +++ b/.changeset/great-planes-arrive.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-org-react': minor +--- + +Added a `GroupListPicker` component that will give the user the ability to choose a group diff --git a/plugins/catalog-react/api-report.md b/plugins/catalog-react/api-report.md index e4fcd59857..e8f0b0e6ee 100644 --- a/plugins/catalog-react/api-report.md +++ b/plugins/catalog-react/api-report.md @@ -446,27 +446,6 @@ export function getEntitySourceLocation( scmIntegrationsApi: ScmIntegrationRegistry, ): EntitySourceLocation | undefined; -// @public (undocumented) -export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; - -// @public (undocumented) -export const GroupListPickerButton: ( - props: GroupListPickerButtonProps, -) => JSX.Element; - -// @public -export type GroupListPickerButtonProps = { - handleClick: (event: React_2.MouseEvent) => void; - group: string; -}; - -// @public -export type GroupListPickerProps = { - placeholder?: string; - groupTypes: Array; - defaultGroup?: string; -}; - // @public (undocumented) export function humanizeEntityRef( entityRef: Entity | CompoundEntityRef, diff --git a/plugins/catalog-react/src/components/index.ts b/plugins/catalog-react/src/components/index.ts index 90fe108ab7..c604306ead 100644 --- a/plugins/catalog-react/src/components/index.ts +++ b/plugins/catalog-react/src/components/index.ts @@ -28,4 +28,3 @@ export * from './InspectEntityDialog'; export * from './UnregisterEntityDialog'; export * from './UserListPicker'; export * from './EntityProcessingStatusPicker'; -export * from './GroupListPicker'; diff --git a/plugins/org-react/.eslintrc.js b/plugins/org-react/.eslintrc.js new file mode 100644 index 0000000000..e2a53a6ad2 --- /dev/null +++ b/plugins/org-react/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require('@backstage/cli/config/eslint-factory')(__dirname); diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md new file mode 100644 index 0000000000..f89119f85e --- /dev/null +++ b/plugins/org-react/README.md @@ -0,0 +1,13 @@ +# org-react + +Welcome to the org-react plugin! + +_This plugin was created through the Backstage CLI_ + +## Getting started + +Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/org-react](http://localhost:3000/org-react). + +You can also serve the plugin in isolation by running `yarn start` in the plugin directory. +This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. +It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md new file mode 100644 index 0000000000..d3db0d62c4 --- /dev/null +++ b/plugins/org-react/api-report.md @@ -0,0 +1,15 @@ +## API Report File for "@backstage/plugin-org-react" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts +/// + +// Warning: (ae-forgotten-export) The symbol "GroupListPickerProps" needs to be exported by the entry point index.d.ts +// Warning: (ae-missing-release-tag) "GroupListPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; + +// (No @packageDocumentation comment for this package) +``` diff --git a/plugins/org-react/package.json b/plugins/org-react/package.json new file mode 100644 index 0000000000..b7b87f9aca --- /dev/null +++ b/plugins/org-react/package.json @@ -0,0 +1,62 @@ +{ + "name": "@backstage/plugin-org-react", + "version": "0.0.0", + "main": "src/index.ts", + "types": "src/index.ts", + "license": "Apache-2.0", + "publishConfig": { + "access": "public", + "main": "dist/index.esm.js", + "types": "dist/index.d.ts" + }, + "backstage": { + "role": "web-library" + }, + "repository": { + "type": "git", + "url": "https://github.com/backstage/backstage", + "directory": "plugins/org-react" + }, + "keywords": [ + "backstage" + ], + "scripts": { + "start": "backstage-cli package start", + "build": "backstage-cli package build", + "lint": "backstage-cli package lint", + "test": "backstage-cli package test", + "clean": "backstage-cli package clean", + "prepack": "backstage-cli package prepack", + "postpack": "backstage-cli package postpack" + }, + "dependencies": { + "@backstage/catalog-client": "workspace:^", + "@backstage/catalog-model": "workspace:^", + "@backstage/core-components": "workspace:^", + "@backstage/core-plugin-api": "workspace:^", + "@backstage/plugin-catalog-react": "workspace:^", + "@backstage/theme": "workspace:^", + "@material-ui/core": "^4.9.13", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "^4.0.0-alpha.57", + "react-use": "^17.2.4" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "workspace:^", + "@backstage/core-app-api": "workspace:^", + "@backstage/dev-utils": "workspace:^", + "@backstage/test-utils": "workspace:^", + "@testing-library/jest-dom": "^5.10.1", + "@testing-library/react": "^12.1.3", + "@testing-library/user-event": "^14.0.0", + "@types/node": "*", + "cross-fetch": "^3.1.5", + "msw": "^0.47.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx similarity index 97% rename from plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx rename to plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx index 6b89612354..5d8599528c 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.test.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -17,7 +17,7 @@ import React from 'react'; import { fireEvent, render, waitFor } from '@testing-library/react'; import { ApiProvider } from '@backstage/core-app-api'; -import { catalogApiRef } from '../../api'; +import { catalogApiRef } from '@backstage/plugin-catalog-react'; import { CatalogApi } from '@backstage/catalog-client'; import { GroupListPicker } from '../GroupListPicker'; import { GroupEntity } from '@backstage/catalog-model'; diff --git a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx similarity index 84% rename from plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx rename to plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx index ccb2690da0..fe01c91479 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -15,14 +15,17 @@ */ import React from 'react'; -import { catalogApiRef } from '../../api'; +import { + catalogApiRef, + humanizeEntityRef, +} from '@backstage/plugin-catalog-react'; import TextField from '@material-ui/core/TextField'; import Autocomplete from '@material-ui/lab/Autocomplete'; import useAsync from 'react-use/lib/useAsync'; import Popover from '@material-ui/core/Popover'; import { useApi } from '@backstage/core-plugin-api'; import { ResponseErrorPanel } from '@backstage/core-components'; -import { GroupEntity } from '@backstage/catalog-model'; +import { Entity, GroupEntity } from '@backstage/catalog-model'; import { GroupListPickerButton } from './GroupListPickerButton'; /** @@ -32,7 +35,7 @@ import { GroupListPickerButton } from './GroupListPickerButton'; */ export type GroupListPickerProps = { placeholder?: string; - groupTypes: Array; + groupTypes?: Array; defaultGroup?: string; }; @@ -63,7 +66,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { const groupsList = await catalogApi.getEntities({ filter: { kind: 'Group', - 'spec.type': groupTypes, + 'spec.type': groupTypes || [], }, }); @@ -74,6 +77,9 @@ export const GroupListPicker = (props: GroupListPickerProps) => { return ; } + const getHumanEntityRef = (entity: Entity) => + humanizeEntityRef(entity, { defaultNamespace: false }); + return ( <> { options={groups ?? []} groupBy={option => option.spec.type} getOptionLabel={option => - option.spec.profile?.displayName ?? option.metadata.name + option.spec.profile?.displayName ?? getHumanEntityRef(option) } inputValue={inputValue} onInputChange={(_, value) => setInputValue(value)} onChange={(_, newValue) => { if (newValue) { setGroup( - newValue.spec.profile?.displayName ?? newValue.metadata.name, + newValue.spec.profile?.displayName ?? + getHumanEntityRef(newValue), ); } setInputValue(''); }} - style={{ width: '200px' }} + style={{ width: '300px' }} renderInput={params => ( ({ }, })); -/** - * Props for {@link GroupListPickerButton}. - * - * @public - */ -export type GroupListPickerButtonProps = { +type GroupListPickerButtonProps = { handleClick: (event: React.MouseEvent) => void; group: string; }; diff --git a/plugins/catalog-react/src/components/GroupListPicker/index.ts b/plugins/org-react/src/components/GroupListPicker/index.ts similarity index 83% rename from plugins/catalog-react/src/components/GroupListPicker/index.ts rename to plugins/org-react/src/components/GroupListPicker/index.ts index 20c4502838..fe1ba8e1ee 100644 --- a/plugins/catalog-react/src/components/GroupListPicker/index.ts +++ b/plugins/org-react/src/components/GroupListPicker/index.ts @@ -15,6 +15,4 @@ */ export { GroupListPicker } from './GroupListPicker'; -export { GroupListPickerButton } from './GroupListPickerButton'; export type { GroupListPickerProps } from './GroupListPicker'; -export type { GroupListPickerButtonProps } from './GroupListPickerButton'; diff --git a/plugins/org-react/src/index.ts b/plugins/org-react/src/index.ts new file mode 100644 index 0000000000..5e834bbf2f --- /dev/null +++ b/plugins/org-react/src/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2022 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. + */ +export { GroupListPicker } from './plugin'; diff --git a/plugins/org-react/src/plugin.test.ts b/plugins/org-react/src/plugin.test.ts new file mode 100644 index 0000000000..4a9d976a89 --- /dev/null +++ b/plugins/org-react/src/plugin.test.ts @@ -0,0 +1,22 @@ +/* + * Copyright 2022 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 { orgReactPlugin } from './plugin'; + +describe('org-react', () => { + it('should export plugin', () => { + expect(orgReactPlugin).toBeDefined(); + }); +}); diff --git a/plugins/org-react/src/plugin.ts b/plugins/org-react/src/plugin.ts new file mode 100644 index 0000000000..bc51e3cd73 --- /dev/null +++ b/plugins/org-react/src/plugin.ts @@ -0,0 +1,37 @@ +/* + * Copyright 2022 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 { + createPlugin, + createRoutableExtension, +} from '@backstage/core-plugin-api'; + +import { rootRouteRef } from './routes'; + +export const orgReactPlugin = createPlugin({ + id: 'org-react', + routes: { + root: rootRouteRef, + }, +}); + +export const GroupListPicker = orgReactPlugin.provide( + createRoutableExtension({ + name: 'GroupListPicker', + component: () => + import('./components/GroupListPicker').then(m => m.GroupListPicker), + mountPoint: rootRouteRef, + }), +); diff --git a/plugins/org-react/src/routes.ts b/plugins/org-react/src/routes.ts new file mode 100644 index 0000000000..80acc0eb48 --- /dev/null +++ b/plugins/org-react/src/routes.ts @@ -0,0 +1,20 @@ +/* + * Copyright 2022 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 { createRouteRef } from '@backstage/core-plugin-api'; + +export const rootRouteRef = createRouteRef({ + id: 'org-react', +}); diff --git a/plugins/org-react/src/setupTests.ts b/plugins/org-react/src/setupTests.ts new file mode 100644 index 0000000000..9bb3e72355 --- /dev/null +++ b/plugins/org-react/src/setupTests.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2022 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 '@testing-library/jest-dom'; +import 'cross-fetch/polyfill'; diff --git a/yarn.lock b/yarn.lock index 9d8a6ff504..1252586b92 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6182,6 +6182,35 @@ __metadata: languageName: unknown linkType: soft +"@backstage/plugin-org-react@^0.0.0, @backstage/plugin-org-react@workspace:plugins/org-react": + version: 0.0.0-use.local + resolution: "@backstage/plugin-org-react@workspace:plugins/org-react" + dependencies: + "@backstage/catalog-client": "workspace:^" + "@backstage/catalog-model": "workspace:^" + "@backstage/cli": "workspace:^" + "@backstage/core-app-api": "workspace:^" + "@backstage/core-components": "workspace:^" + "@backstage/core-plugin-api": "workspace:^" + "@backstage/dev-utils": "workspace:^" + "@backstage/plugin-catalog-react": "workspace:^" + "@backstage/test-utils": "workspace:^" + "@backstage/theme": "workspace:^" + "@material-ui/core": ^4.9.13 + "@material-ui/icons": ^4.9.1 + "@material-ui/lab": ^4.0.0-alpha.57 + "@testing-library/jest-dom": ^5.10.1 + "@testing-library/react": ^12.1.3 + "@testing-library/user-event": ^14.0.0 + "@types/node": "*" + cross-fetch: ^3.1.5 + msw: ^0.47.0 + react-use: ^17.2.4 + peerDependencies: + react: ^16.13.1 || ^17.0.0 + languageName: unknown + linkType: soft + "@backstage/plugin-org@workspace:^, @backstage/plugin-org@workspace:plugins/org": version: 0.0.0-use.local resolution: "@backstage/plugin-org@workspace:plugins/org" @@ -22153,6 +22182,7 @@ __metadata: "@backstage/plugin-newrelic": "workspace:^" "@backstage/plugin-newrelic-dashboard": "workspace:^" "@backstage/plugin-org": "workspace:^" + "@backstage/plugin-org-react": "workspace:^" "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" From b4e86dc00a3ca1d832f44b86be3c2781d2c3d25a Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 15:14:54 +0200 Subject: [PATCH 14/24] fix: yarn lock Signed-off-by: djamaile --- .changeset/hungry-rocks-bathe.md | 5 ----- yarn.lock | 3 +-- 2 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 .changeset/hungry-rocks-bathe.md diff --git a/.changeset/hungry-rocks-bathe.md b/.changeset/hungry-rocks-bathe.md deleted file mode 100644 index 7c22f1b368..0000000000 --- a/.changeset/hungry-rocks-bathe.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@backstage/plugin-catalog-react': patch ---- - -Added a `AutoComplete` component that will give the user the ability to choose a group diff --git a/yarn.lock b/yarn.lock index 1252586b92..a5598f14cc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6182,7 +6182,7 @@ __metadata: languageName: unknown linkType: soft -"@backstage/plugin-org-react@^0.0.0, @backstage/plugin-org-react@workspace:plugins/org-react": +"@backstage/plugin-org-react@workspace:plugins/org-react": version: 0.0.0-use.local resolution: "@backstage/plugin-org-react@workspace:plugins/org-react" dependencies: @@ -22182,7 +22182,6 @@ __metadata: "@backstage/plugin-newrelic": "workspace:^" "@backstage/plugin-newrelic-dashboard": "workspace:^" "@backstage/plugin-org": "workspace:^" - "@backstage/plugin-org-react": "workspace:^" "@backstage/plugin-pagerduty": "workspace:^" "@backstage/plugin-permission-react": "workspace:^" "@backstage/plugin-playlist": "workspace:^" From 6e5f08d260b639538b2e0cba148c6fa83860e069 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 15:47:19 +0200 Subject: [PATCH 15/24] chore: update changeset Signed-off-by: djamaile --- .changeset/great-planes-arrive.md | 2 +- .../src/components/GroupListPicker/GroupListPicker.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.changeset/great-planes-arrive.md b/.changeset/great-planes-arrive.md index 92a5b985cd..563c061627 100644 --- a/.changeset/great-planes-arrive.md +++ b/.changeset/great-planes-arrive.md @@ -2,4 +2,4 @@ '@backstage/plugin-org-react': minor --- -Added a `GroupListPicker` component that will give the user the ability to choose a group +Implemented the org-react plugin, with it's first component being: a `GroupListPicker` component that will give the user the ability to choose a group diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx index fe01c91479..fbac4792ae 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -71,7 +71,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { }); return groupsList.items as GroupEntity[]; - }, [catalogApi]); + }, [catalogApi, groupTypes]); if (error) { return ; From 8be435714b24d198f03de83fa75e421a3fe2b41c Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 16:40:37 +0200 Subject: [PATCH 16/24] fix: export props and mark component public Signed-off-by: djamaile --- plugins/org-react/api-report.md | 10 +++++++--- plugins/org-react/src/index.ts | 1 + plugins/org-react/src/plugin.ts | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md index d3db0d62c4..da164ec053 100644 --- a/plugins/org-react/api-report.md +++ b/plugins/org-react/api-report.md @@ -5,11 +5,15 @@ ```ts /// -// Warning: (ae-forgotten-export) The symbol "GroupListPickerProps" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "GroupListPicker" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) -// // @public (undocumented) export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; +// @public +export type GroupListPickerProps = { + placeholder?: string; + groupTypes?: Array; + defaultGroup?: string; +}; + // (No @packageDocumentation comment for this package) ``` diff --git a/plugins/org-react/src/index.ts b/plugins/org-react/src/index.ts index 5e834bbf2f..731702c80c 100644 --- a/plugins/org-react/src/index.ts +++ b/plugins/org-react/src/index.ts @@ -14,3 +14,4 @@ * limitations under the License. */ export { GroupListPicker } from './plugin'; +export type { GroupListPickerProps } from './components/GroupListPicker'; diff --git a/plugins/org-react/src/plugin.ts b/plugins/org-react/src/plugin.ts index bc51e3cd73..0158ff1b06 100644 --- a/plugins/org-react/src/plugin.ts +++ b/plugins/org-react/src/plugin.ts @@ -27,6 +27,7 @@ export const orgReactPlugin = createPlugin({ }, }); +/** @public */ export const GroupListPicker = orgReactPlugin.provide( createRoutableExtension({ name: 'GroupListPicker', From 30de23453d5b5ba84ddbaab6ca717d1134f14411 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 17:29:10 +0200 Subject: [PATCH 17/24] chore: update the README Signed-off-by: djamaile --- .github/CODEOWNERS | 1 + plugins/org-react/README.md | 28 +++++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index cb1dd5d322..89b3d301fa 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -49,6 +49,7 @@ yarn.lock @backstage/reviewers @backst /plugins/kubernetes @backstage/reviewers @backstage/warpspeed /plugins/kubernetes-* @backstage/reviewers @backstage/warpspeed /plugins/newrelic-dashboard @backstage/reviewers @mufaddal7 +/plugins/org-react @backstage/reviewers /plugins/playlist @backstage/reviewers @kuangp /plugins/playlist-* @backstage/reviewers @kuangp /plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md index f89119f85e..9c51462f91 100644 --- a/plugins/org-react/README.md +++ b/plugins/org-react/README.md @@ -1,13 +1,27 @@ # org-react -Welcome to the org-react plugin! +## features -_This plugin was created through the Backstage CLI_ +- Group list picker component -## Getting started +### GroupListPicker -Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/org-react](http://localhost:3000/org-react). +The `GroupListPicker` component displays a select box which also has autocomplete functionality. -You can also serve the plugin in isolation by running `yarn start` in the plugin directory. -This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads. -It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory. +To use the `GroupListPicker` component you'll need to import it and add it to your desired place. + +```diff ++ import { GroupListPicker } from '@backstage/plugin-org-react'; + + + ++ + + +``` + +The `GroupListPicker` comes with three optional props: + +- **groupTypes**: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; +- **defaultGroup**: which group by default should be selected. For example, a group of the logged in user; +- **placeholder**: the placeholder that the select box in the component should display. This might be helpfull in informing your users what the functionality of the component is. From 443a65441963da12fae8d3b6a68df5ffe421cf17 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 17:33:25 +0200 Subject: [PATCH 18/24] fix: make vale happy or else Signed-off-by: djamaile --- plugins/org-react/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md index 9c51462f91..10afde4e65 100644 --- a/plugins/org-react/README.md +++ b/plugins/org-react/README.md @@ -22,6 +22,6 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo The `GroupListPicker` comes with three optional props: -- **groupTypes**: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; -- **defaultGroup**: which group by default should be selected. For example, a group of the logged in user; -- **placeholder**: the placeholder that the select box in the component should display. This might be helpfull in informing your users what the functionality of the component is. +- `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; +- `defaultGroup`: which group by default should be selected. For example, a group of the logged in user; +- `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is. From e9cd23670267df80abed0f4eb607dfccc4a11082 Mon Sep 17 00:00:00 2001 From: djamaile Date: Wed, 19 Oct 2022 09:58:51 +0200 Subject: [PATCH 19/24] chore: remove org-react from CODEOWNERS Signed-off-by: djamaile --- .github/CODEOWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 89b3d301fa..cb1dd5d322 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -49,7 +49,6 @@ yarn.lock @backstage/reviewers @backst /plugins/kubernetes @backstage/reviewers @backstage/warpspeed /plugins/kubernetes-* @backstage/reviewers @backstage/warpspeed /plugins/newrelic-dashboard @backstage/reviewers @mufaddal7 -/plugins/org-react @backstage/reviewers /plugins/playlist @backstage/reviewers @kuangp /plugins/playlist-* @backstage/reviewers @kuangp /plugins/scaffolder-backend-module-rails @backstage/reviewers @angeliski From 420fe8a7866d57eaa1174b11af48514b75ff4474 Mon Sep 17 00:00:00 2001 From: djamaile Date: Wed, 19 Oct 2022 13:06:27 +0200 Subject: [PATCH 20/24] chore: give onChange prop the GroupListPicker component Signed-off-by: djamaile --- plugins/org-react/README.md | 8 ++++-- .../GroupListPicker/GroupListPicker.tsx | 27 +++++++++---------- .../GroupListPicker/GroupListPickerButton.tsx | 2 +- plugins/org-react/src/plugin.ts | 11 ++++---- 4 files changed, 26 insertions(+), 22 deletions(-) diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md index 10afde4e65..134a26d03c 100644 --- a/plugins/org-react/README.md +++ b/plugins/org-react/README.md @@ -12,10 +12,13 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo ```diff + import { GroupListPicker } from '@backstage/plugin-org-react'; ++ import React, { useState } from 'react'; + ++ const [group, setGroup] = useState(); -+ ++ ``` @@ -23,5 +26,6 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo The `GroupListPicker` comes with three optional props: - `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; -- `defaultGroup`: which group by default should be selected. For example, a group of the logged in user; +- `initialGroup`: which group by default should be selected. For example, a group of the logged in user; - `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is. +- `onChange`: a prop to help the user to give access to the selected group diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx index fbac4792ae..f0d0efb454 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import React from 'react'; +import React, { useCallback } from 'react'; import { catalogApiRef, humanizeEntityRef, @@ -36,17 +36,17 @@ import { GroupListPickerButton } from './GroupListPickerButton'; export type GroupListPickerProps = { placeholder?: string; groupTypes?: Array; - defaultGroup?: string; + initialGroup?: string | undefined; + onChange: (value: GroupEntity | undefined) => void; }; /** @public */ export const GroupListPicker = (props: GroupListPickerProps) => { const catalogApi = useApi(catalogApiRef); - const { groupTypes, defaultGroup = '', placeholder = '' } = props; + const { onChange, groupTypes, initialGroup, placeholder = '' } = props; const [anchorEl, setAnchorEl] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); - const [group, setGroup] = React.useState(defaultGroup); const handleClick = (event: React.MouseEvent) => { setAnchorEl(event.currentTarget); @@ -73,6 +73,13 @@ export const GroupListPicker = (props: GroupListPickerProps) => { return groupsList.items as GroupEntity[]; }, [catalogApi, groupTypes]); + const handleChange = useCallback( + (_, v: GroupEntity | null) => { + onChange(v ?? undefined); + }, + [onChange], + ); + if (error) { return ; } @@ -98,15 +105,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { } inputValue={inputValue} onInputChange={(_, value) => setInputValue(value)} - onChange={(_, newValue) => { - if (newValue) { - setGroup( - newValue.spec.profile?.displayName ?? - getHumanEntityRef(newValue), - ); - } - setInputValue(''); - }} + onChange={handleChange} style={{ width: '300px' }} renderInput={params => ( { )} /> - + ); }; diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx index 9e022bdf57..63fc9a983e 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx @@ -47,7 +47,7 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ type GroupListPickerButtonProps = { handleClick: (event: React.MouseEvent) => void; - group: string; + group: string | undefined; }; /** @public */ diff --git a/plugins/org-react/src/plugin.ts b/plugins/org-react/src/plugin.ts index 0158ff1b06..8be5c11a4f 100644 --- a/plugins/org-react/src/plugin.ts +++ b/plugins/org-react/src/plugin.ts @@ -14,8 +14,8 @@ * limitations under the License. */ import { + createComponentExtension, createPlugin, - createRoutableExtension, } from '@backstage/core-plugin-api'; import { rootRouteRef } from './routes'; @@ -29,10 +29,11 @@ export const orgReactPlugin = createPlugin({ /** @public */ export const GroupListPicker = orgReactPlugin.provide( - createRoutableExtension({ + createComponentExtension({ name: 'GroupListPicker', - component: () => - import('./components/GroupListPicker').then(m => m.GroupListPicker), - mountPoint: rootRouteRef, + component: { + lazy: () => + import('./components/GroupListPicker').then(m => m.GroupListPicker), + }, }), ); From c71676c97e90291d598e501ce095f3cdae00fde2 Mon Sep 17 00:00:00 2001 From: djamaile Date: Wed, 19 Oct 2022 13:16:42 +0200 Subject: [PATCH 21/24] chore: clean up Signed-off-by: djamaile --- plugins/org-react/api-report.md | 5 ++++- .../src/components/GroupListPicker/GroupListPicker.test.tsx | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md index da164ec053..587f5595aa 100644 --- a/plugins/org-react/api-report.md +++ b/plugins/org-react/api-report.md @@ -5,6 +5,8 @@ ```ts /// +import { GroupEntity } from '@backstage/catalog-model'; + // @public (undocumented) export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; @@ -12,7 +14,8 @@ export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; export type GroupListPickerProps = { placeholder?: string; groupTypes?: Array; - defaultGroup?: string; + initialGroup?: string | undefined; + onChange: (value: GroupEntity | undefined) => void; }; // (No @packageDocumentation comment for this package) diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx index 5d8599528c..06d06d3b85 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -69,7 +69,8 @@ describe('', () => { {}} /> , ); @@ -83,6 +84,8 @@ describe('', () => { {}} /> , ); From eee9b5ac8947f4918b7818fb0402f9f31dade4e6 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 20 Oct 2022 10:18:44 +0200 Subject: [PATCH 22/24] chore: drop initialGroup prop Signed-off-by: djamaile --- plugins/org-react/README.md | 3 +- .../GroupListPicker/GroupListPicker.test.tsx | 16 -------- .../GroupListPicker/GroupListPicker.tsx | 5 +-- plugins/org-react/src/index.ts | 2 +- plugins/org-react/src/plugin.test.ts | 22 ----------- plugins/org-react/src/plugin.ts | 39 ------------------- 6 files changed, 4 insertions(+), 83 deletions(-) delete mode 100644 plugins/org-react/src/plugin.test.ts delete mode 100644 plugins/org-react/src/plugin.ts diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md index 134a26d03c..832e41bddd 100644 --- a/plugins/org-react/README.md +++ b/plugins/org-react/README.md @@ -18,7 +18,7 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo -+ ++ ``` @@ -26,6 +26,5 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo The `GroupListPicker` comes with three optional props: - `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; -- `initialGroup`: which group by default should be selected. For example, a group of the logged in user; - `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is. - `onChange`: a prop to help the user to give access to the selected group diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx index 06d06d3b85..a011e35333 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -63,28 +63,12 @@ const mockCatalogApi = { const apis = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); describe('', () => { - it('renders group list picker', () => { - const { queryByText } = render( - - {}} - /> - , - ); - - expect(queryByText('test')).toBeInTheDocument(); - }); - it('can choose a group', async () => { const { getByText, queryByText, getByTestId } = render( {}} /> , diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx index f0d0efb454..f08565fbfa 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -36,7 +36,6 @@ import { GroupListPickerButton } from './GroupListPickerButton'; export type GroupListPickerProps = { placeholder?: string; groupTypes?: Array; - initialGroup?: string | undefined; onChange: (value: GroupEntity | undefined) => void; }; @@ -44,7 +43,7 @@ export type GroupListPickerProps = { export const GroupListPicker = (props: GroupListPickerProps) => { const catalogApi = useApi(catalogApiRef); - const { onChange, groupTypes, initialGroup, placeholder = '' } = props; + const { onChange, groupTypes, placeholder = '' } = props; const [anchorEl, setAnchorEl] = React.useState(null); const [inputValue, setInputValue] = React.useState(''); @@ -116,7 +115,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { )} /> - + ); }; diff --git a/plugins/org-react/src/index.ts b/plugins/org-react/src/index.ts index 731702c80c..c3393bee48 100644 --- a/plugins/org-react/src/index.ts +++ b/plugins/org-react/src/index.ts @@ -13,5 +13,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { GroupListPicker } from './plugin'; +export { GroupListPicker } from './components/GroupListPicker'; export type { GroupListPickerProps } from './components/GroupListPicker'; diff --git a/plugins/org-react/src/plugin.test.ts b/plugins/org-react/src/plugin.test.ts deleted file mode 100644 index 4a9d976a89..0000000000 --- a/plugins/org-react/src/plugin.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright 2022 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 { orgReactPlugin } from './plugin'; - -describe('org-react', () => { - it('should export plugin', () => { - expect(orgReactPlugin).toBeDefined(); - }); -}); diff --git a/plugins/org-react/src/plugin.ts b/plugins/org-react/src/plugin.ts deleted file mode 100644 index 8be5c11a4f..0000000000 --- a/plugins/org-react/src/plugin.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2022 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 { - createComponentExtension, - createPlugin, -} from '@backstage/core-plugin-api'; - -import { rootRouteRef } from './routes'; - -export const orgReactPlugin = createPlugin({ - id: 'org-react', - routes: { - root: rootRouteRef, - }, -}); - -/** @public */ -export const GroupListPicker = orgReactPlugin.provide( - createComponentExtension({ - name: 'GroupListPicker', - component: { - lazy: () => - import('./components/GroupListPicker').then(m => m.GroupListPicker), - }, - }), -); From 1709bd952e4eaefeb7f841be6a6b811df15a3216 Mon Sep 17 00:00:00 2001 From: djamaile Date: Thu, 20 Oct 2022 10:21:17 +0200 Subject: [PATCH 23/24] chore: run api report command Signed-off-by: djamaile --- plugins/org-react/api-report.md | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/org-react/api-report.md b/plugins/org-react/api-report.md index 587f5595aa..60cd6944d0 100644 --- a/plugins/org-react/api-report.md +++ b/plugins/org-react/api-report.md @@ -14,7 +14,6 @@ export const GroupListPicker: (props: GroupListPickerProps) => JSX.Element; export type GroupListPickerProps = { placeholder?: string; groupTypes?: Array; - initialGroup?: string | undefined; onChange: (value: GroupEntity | undefined) => void; }; From 4c74b20a6aaaf21e0e8e20c71bbc94ff6f717850 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 25 Oct 2022 01:29:46 +0200 Subject: [PATCH 24/24] chore: respond to comments Signed-off-by: djamaile --- plugins/org-react/README.md | 2 +- .../GroupListPicker/GroupListPicker.test.tsx | 6 ++-- .../GroupListPicker/GroupListPicker.tsx | 3 +- .../GroupListPicker/GroupListPickerButton.tsx | 35 +++++++------------ plugins/org-react/src/routes.ts | 20 ----------- 5 files changed, 18 insertions(+), 48 deletions(-) delete mode 100644 plugins/org-react/src/routes.ts diff --git a/plugins/org-react/README.md b/plugins/org-react/README.md index 832e41bddd..91c7ebf48a 100644 --- a/plugins/org-react/README.md +++ b/plugins/org-react/README.md @@ -23,7 +23,7 @@ To use the `GroupListPicker` component you'll need to import it and add it to yo ``` -The `GroupListPicker` comes with three optional props: +The `GroupListPicker` comes with three props: - `groupTypes`: gives the user the option which group types the component should load. If no value is provided all group types will be loaded in; - `placeholder`: the placeholder that the select box in the component should display. This might be helpful in informing your users what the functionality of the component is. diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx index a011e35333..b8a499b8fe 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.test.tsx @@ -64,7 +64,7 @@ const apis = TestApiRegistry.from([catalogApiRef, mockCatalogApi]); describe('', () => { it('can choose a group', async () => { - const { getByText, queryByText, getByTestId } = render( + const { getByText, getByTestId } = render( ', () => { const input = getByTestId('group-list-picker-input').querySelector('input'); fireEvent.change(input as HTMLElement, { target: { value: 'GR' } }); - await waitFor(() => { - expect(queryByText('Group A')).toBeInTheDocument(); + await waitFor(async () => { + expect(getByText('Group A')).toBeInTheDocument(); fireEvent.click(getByText('Group A')); expect(getByText('Group A')).toBeInTheDocument(); }); diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx index f08565fbfa..1296c520c3 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPicker.tsx @@ -83,8 +83,7 @@ export const GroupListPicker = (props: GroupListPickerProps) => { return ; } - const getHumanEntityRef = (entity: Entity) => - humanizeEntityRef(entity, { defaultNamespace: false }); + const getHumanEntityRef = (entity: Entity) => humanizeEntityRef(entity); return ( <> diff --git a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx index 63fc9a983e..149bf778b1 100644 --- a/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx +++ b/plugins/org-react/src/components/GroupListPicker/GroupListPickerButton.tsx @@ -16,18 +16,17 @@ import React from 'react'; import { BackstageTheme } from '@backstage/theme'; -import { Box, makeStyles, Typography } from '@material-ui/core'; +import { makeStyles, Typography, Button } from '@material-ui/core'; import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown'; import PeopleIcon from '@material-ui/icons/People'; const useStyles = makeStyles((theme: BackstageTheme) => ({ btn: { - backgroundColor: 'transparent', - border: 'none', margin: 0, - padding: 0, + padding: 10, width: '100%', cursor: 'pointer', + justifyContent: 'space-between', }, title: { fontSize: '1.5rem', @@ -36,12 +35,10 @@ const useStyles = makeStyles((theme: BackstageTheme) => ({ letterSpacing: '-0.25px', lineHeight: '32px', marginBottom: 0, + textTransform: 'none', }, - peopleIcon: { - marginRight: theme.spacing(1), - }, - arrowDownIcon: { - marginLeft: 'auto', + icon: { + transform: 'scale(1.5)', }, })); @@ -56,22 +53,16 @@ export const GroupListPickerButton = (props: GroupListPickerButtonProps) => { const classes = useStyles(); return ( - + {group} + ); }; diff --git a/plugins/org-react/src/routes.ts b/plugins/org-react/src/routes.ts deleted file mode 100644 index 80acc0eb48..0000000000 --- a/plugins/org-react/src/routes.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright 2022 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 { createRouteRef } from '@backstage/core-plugin-api'; - -export const rootRouteRef = createRouteRef({ - id: 'org-react', -});