From e96274f1fe17587b33141f12d005019870dba176 Mon Sep 17 00:00:00 2001 From: djamaile Date: Tue, 18 Oct 2022 14:26:18 +0200 Subject: [PATCH] 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:^"