From e4d77a9c54dbc62160eb9e61859fedcbb957a980 Mon Sep 17 00:00:00 2001 From: Emma Indal Date: Sun, 20 Feb 2022 22:19:37 +0100 Subject: [PATCH] add new stack overflow plugin Signed-off-by: Emma Indal --- plugins/stack-overflow/.eslintrc.js | 3 + plugins/stack-overflow/README.md | 73 ++++++++++++++++ plugins/stack-overflow/package.json | 56 ++++++++++++ .../home/StackOverflowQuestions/Content.tsx | 85 +++++++++++++++++++ .../StackOverflowQuestions.stories.tsx | 62 ++++++++++++++ .../src/home/StackOverflowQuestions/index.ts | 17 ++++ plugins/stack-overflow/src/index.ts | 21 +++++ plugins/stack-overflow/src/plugin.test.ts | 22 +++++ plugins/stack-overflow/src/plugin.ts | 56 ++++++++++++ .../StackOverflowQuestionsCollator.tsx | 72 ++++++++++++++++ .../StackOverflowQuestionsCollator/index.ts | 17 ++++ ...ckOverflowSearchResultListItem.stories.tsx | 40 +++++++++ ...StackOverflowSearchResultListItem.test.tsx | 43 ++++++++++ .../StackOverflowSearchResultListItem.tsx | 59 +++++++++++++ .../index.ts | 17 ++++ plugins/stack-overflow/src/setupTests.ts | 17 ++++ plugins/stack-overflow/src/types.ts | 31 +++++++ 17 files changed, 691 insertions(+) create mode 100644 plugins/stack-overflow/.eslintrc.js create mode 100644 plugins/stack-overflow/README.md create mode 100644 plugins/stack-overflow/package.json create mode 100644 plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx create mode 100644 plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx create mode 100644 plugins/stack-overflow/src/home/StackOverflowQuestions/index.ts create mode 100644 plugins/stack-overflow/src/index.ts create mode 100644 plugins/stack-overflow/src/plugin.test.ts create mode 100644 plugins/stack-overflow/src/plugin.ts create mode 100644 plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/StackOverflowQuestionsCollator.tsx create mode 100644 plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/index.ts create mode 100644 plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx create mode 100644 plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx create mode 100644 plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx create mode 100644 plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/index.ts create mode 100644 plugins/stack-overflow/src/setupTests.ts create mode 100644 plugins/stack-overflow/src/types.ts diff --git a/plugins/stack-overflow/.eslintrc.js b/plugins/stack-overflow/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/stack-overflow/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/stack-overflow/README.md b/plugins/stack-overflow/README.md new file mode 100644 index 0000000000..cea63c41c4 --- /dev/null +++ b/plugins/stack-overflow/README.md @@ -0,0 +1,73 @@ +# Stack Overflow + +A plugin that provides stack overflow specific functionality that can be used in different ways (e.g. for homepage and search) to compose your Backstage App. + +## Getting started + +Before we begin, make sure: + +- You have created your own standalone Backstage app using @backstage/create-app and not using a fork of the backstage repository. If you haven't setup Backstage already, start [here](https://backstage.io/docs/getting-started/). + +To use any of the functionality this plugin provides, you need to start by configuring your App with the following config: + +```yaml +stackoverflow: + baseUrl: https://api.stackexchange.com/2.2 # alternative: your internal stack overflow instance +``` + +## Areas of Responsibility + +This search plugin is primarily responsible for the following: + +- Exposing various stack-overflow related components like `` which can be used for composing the searchpage, and `` which can be used for composing the homepage. +- Provides a `StackOverflowQuestionsCollator`, which can be used in the search backend to index stack overflow questions to your Backstage Search. + +### Index Stack Overflow Questions to search + +Before you are able to start index stack overflow questions to search, you need to go through the [search getting started guide](https://backstage.io/docs/features/search/getting-started). + +When you have your `packages/backend/src/plugins/search.ts` file ready to make modifications, add the following code snippet to add the `StackOverflowQuestionsCollator`. Note that you can modify the request params. + +```ts +indexBuilder.addCollator({ + defaultRefreshIntervalSeconds: 60, + collator: new StackOverflowQuestionsCollator({ + config, + requestParams: { + tagged: ['backstage'], + site: 'stackoverflow', + pagesize: 100, + }, + }), +}); +``` + +#### Use specific search result list item for Stack Overflow Question + +When you have your `packages/app/src/components/search/SearchPage.tsx` file ready to make modifications, add the following code snippet to add the `StackOverflowSearchResultListItem` when the type of the search results are `stack-overflow`. + +```tsx + case 'stack-overflow': + return ( + + ); +``` + +#### Use Stack Overflow Questions on your homepage + +Before you are able to add the stack overflow question component to your homepage, you need to go through the [homepage getting started guide](https://backstage.io/docs/getting-started/homepage). When its ready, add the following code snippet to your `packages/app/src/components/home/HomePage.tsx` file. + +```tsx + + + +``` diff --git a/plugins/stack-overflow/package.json b/plugins/stack-overflow/package.json new file mode 100644 index 0000000000..350f4aa0ca --- /dev/null +++ b/plugins/stack-overflow/package.json @@ -0,0 +1,56 @@ +{ + "name": "@backstage/plugin-stack-overflow", + "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" + }, + "scripts": { + "build": "backstage-cli plugin:build", + "start": "backstage-cli plugin:serve", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "diff": "backstage-cli plugin:diff", + "prepack": "backstage-cli prepack", + "postpack": "backstage-cli postpack", + "clean": "backstage-cli clean" + }, + "dependencies": { + "@backstage/core-components": "^0.8.8", + "@backstage/plugin-home": "^0.4.15", + "@backstage/core-plugin-api": "^0.6.0", + "@backstage/search-common": "^0.2.2", + "@backstage/config": "^0.1.13", + "@backstage/theme": "^0.2.14", + "@material-ui/core": "^4.12.2", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.57", + "qs": "^6.10.3", + "cross-fetch": "^3.0.6", + "lodash": "^4.17.21", + "react-use": "^17.2.4", + "@testing-library/jest-dom": "^5.10.1" + }, + "peerDependencies": { + "react": "^16.13.1 || ^17.0.0" + }, + "devDependencies": { + "@backstage/cli": "^0.13.2-next.0", + "@backstage/core-app-api": "^0.5.2", + "@backstage/dev-utils": "^0.2.21-next.0", + "@backstage/test-utils": "^0.2.4", + "@testing-library/react": "^11.2.5", + "@testing-library/user-event": "^13.1.8", + "@types/jest": "*", + "@types/node": "*", + "msw": "^0.35.0", + "cross-fetch": "^3.0.6" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx b/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx new file mode 100644 index 0000000000..a0832fc1f1 --- /dev/null +++ b/plugins/stack-overflow/src/home/StackOverflowQuestions/Content.tsx @@ -0,0 +1,85 @@ +/* + * 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 { useApi, configApiRef } from '@backstage/core-plugin-api'; +import { Link } from '@backstage/core-components'; +import { + IconButton, + List, + ListItem, + ListItemText, + ListItemSecondaryAction, +} from '@material-ui/core'; +import OpenInNewIcon from '@material-ui/icons/OpenInNew'; +import { useAsync } from 'react-use'; +import qs from 'qs'; +import React from 'react'; +import { + StackOverflowQuestion, + StackOverflowQuestionsContentProps, +} from '../../types'; + +/** + * A component to display a list of stack overflow questions on the homepage. + * + * @public + */ + +export const Content = (props: StackOverflowQuestionsContentProps) => { + const { requestParams } = props; + const configApi = useApi(configApiRef); + const baseUrl = configApi.getOptionalString('stackoverflow.baseUrl'); + + const { value, loading, error } = useAsync(async (): Promise< + StackOverflowQuestion[] + > => { + const params = requestParams ? `?${qs.stringify(requestParams)}` : ''; + const response = await fetch(`${baseUrl}/questions${params}`); + const data = await response.json(); + return data.items; + }, []); + + if (loading) { + return

loading...

; + } + + if (error || !value || !value.length) { + return

could not load questions

; + } + + const getSecondaryText = (answer_count: Number) => + answer_count > 1 ? `${answer_count} answers` : `${answer_count} answer`; + + return ( + + {value.map(question => ( + + + + + + + + + + + ))} + + ); +}; diff --git a/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx b/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx new file mode 100644 index 0000000000..e19e0f807b --- /dev/null +++ b/plugins/stack-overflow/src/home/StackOverflowQuestions/StackOverflowQuestions.stories.tsx @@ -0,0 +1,62 @@ +/* + * 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 { HomePageStackOverflowQuestions } from '../../plugin'; +import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { configApiRef } from '@backstage/core-plugin-api'; +import { ConfigReader } from '@backstage/config'; +import { Grid } from '@material-ui/core'; +import React, { ComponentType } from 'react'; + +export default { + title: 'Plugins/Home/Components/StackOverflow', + component: HomePageStackOverflowQuestions, + decorators: [ + (Story: ComponentType<{}>) => + wrapInTestApp( + <> + + + + , + ), + ], +}; + +export const Default = () => { + return ( + + + + ); +}; diff --git a/plugins/stack-overflow/src/home/StackOverflowQuestions/index.ts b/plugins/stack-overflow/src/home/StackOverflowQuestions/index.ts new file mode 100644 index 0000000000..1faa9a2426 --- /dev/null +++ b/plugins/stack-overflow/src/home/StackOverflowQuestions/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 { Content } from './Content'; diff --git a/plugins/stack-overflow/src/index.ts b/plugins/stack-overflow/src/index.ts new file mode 100644 index 0000000000..9e71988100 --- /dev/null +++ b/plugins/stack-overflow/src/index.ts @@ -0,0 +1,21 @@ +/* + * 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 { + stackOverflowPlugin, + StackOverflowSearchResultListItem, + HomePageStackOverflowQuestions, +} from './plugin'; +export { StackOverflowQuestionsCollator } from './search/StackOverflowQuestionsCollator'; diff --git a/plugins/stack-overflow/src/plugin.test.ts b/plugins/stack-overflow/src/plugin.test.ts new file mode 100644 index 0000000000..b25cfe01ee --- /dev/null +++ b/plugins/stack-overflow/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 { stackOverflowPlugin } from './plugin'; + +describe('stack-overflow', () => { + it('should export plugin', () => { + expect(stackOverflowPlugin).toBeDefined(); + }); +}); diff --git a/plugins/stack-overflow/src/plugin.ts b/plugins/stack-overflow/src/plugin.ts new file mode 100644 index 0000000000..90a82da719 --- /dev/null +++ b/plugins/stack-overflow/src/plugin.ts @@ -0,0 +1,56 @@ +/* + * 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, + createComponentExtension, +} from '@backstage/core-plugin-api'; +import { createCardExtension } from '@backstage/plugin-home'; +import { StackOverflowQuestionsContentProps } from './types'; + +export const stackOverflowPlugin = createPlugin({ + id: 'stack-overflow', +}); + +/** + * A component to display a stack overflow search result + * + * @public + */ + +export const StackOverflowSearchResultListItem = stackOverflowPlugin.provide( + createComponentExtension({ + name: 'StackOverflowResultListItem', + component: { + lazy: () => + import('./search/StackOverflowSearchResultListItem').then( + m => m.StackOverflowSearchResultListItem, + ), + }, + }), +); + +/** + * A component to display a list of stack overflow questions on the homepage. + * + * @public + */ +export const HomePageStackOverflowQuestions = stackOverflowPlugin.provide( + createCardExtension({ + name: 'HomePageStackOverflowQuestions', + title: 'Stack Overflow Questions', + components: () => import('./home/StackOverflowQuestions'), + }), +); diff --git a/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/StackOverflowQuestionsCollator.tsx b/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/StackOverflowQuestionsCollator.tsx new file mode 100644 index 0000000000..a44b2f4742 --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/StackOverflowQuestionsCollator.tsx @@ -0,0 +1,72 @@ +/* + * 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 { IndexableDocument, DocumentCollator } from '@backstage/search-common'; +import { Config } from '@backstage/config'; +import fetch from 'cross-fetch'; +import qs from 'qs'; +import { + StackOverflowQuestion, + StackOverflowQuestionsRequestParams, +} from '../../types'; + +interface StackOverflowDocument extends IndexableDocument { + answers: number; + tags: string[]; +} + +export class StackOverflowQuestionsCollator implements DocumentCollator { + protected baseUrl: string; + protected requestParams: StackOverflowQuestionsRequestParams; + public readonly type: string = 'stack-overflow'; + + constructor({ + config, + requestParams, + }: { + config: Config; + requestParams: StackOverflowQuestionsRequestParams; + }) { + this.baseUrl = config.getString('stackoverflow.baseUrl'); + this.requestParams = requestParams; + } + + async execute() { + const params = this.requestParams + ? `?${qs.stringify(this.requestParams)}` + : ''; + const res = await fetch(`${this.baseUrl}/questions${params}`); + + const data = await res.json(); + return data.items.map( + ({ + title, + link, + owner: { display_name }, + tags, + answer_count, + }: StackOverflowQuestion): StackOverflowDocument => { + return { + title: title, + location: link, + text: display_name, + tags: tags, + answers: answer_count, + }; + }, + ); + } +} diff --git a/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/index.ts b/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/index.ts new file mode 100644 index 0000000000..d5fecd0dce --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowQuestionsCollator/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 { StackOverflowQuestionsCollator } from './StackOverflowQuestionsCollator'; diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx new file mode 100644 index 0000000000..171a6203ef --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.stories.tsx @@ -0,0 +1,40 @@ +/* + * 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 { StackOverflowSearchResultListItem } from '../../plugin'; +import { wrapInTestApp } from '@backstage/test-utils'; +import React, { ComponentType } from 'react'; +import OpenInNewIcon from '@material-ui/icons/OpenInNew'; + +export default { + title: 'Plugins/Search/StackOverflowResultListItem', + component: StackOverflowSearchResultListItem, + decorators: [(Story: ComponentType<{}>) => wrapInTestApp()], +}; + +export const Default = () => { + return ( + + ); +}; diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx new file mode 100644 index 0000000000..61e901591e --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.test.tsx @@ -0,0 +1,43 @@ +/* + * 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 { renderInTestApp } from '@backstage/test-utils'; +import { screen } from '@testing-library/react'; +import { StackOverflowSearchResultListItem } from './StackOverflowSearchResultListItem'; + +describe('', () => { + it('should render without exploding', async () => { + await renderInTestApp( + , + ); + expect( + screen.getByText(/Customizing Spotify backstage UI/i), + ).toBeInTheDocument(); + expect(screen.getByText(/Tag: backstage/i)).toBeInTheDocument(); + expect( + screen.getByText(/Customizing Spotify backstage UI/i).closest('a'), + ).toHaveAttribute('href', 'https://stackoverflow.com/questions/7'); + }); +}); diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx new file mode 100644 index 0000000000..52c16eeb77 --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/StackOverflowSearchResultListItem.tsx @@ -0,0 +1,59 @@ +/* + * 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 _unescape from 'lodash/unescape'; +import { Link } from '@backstage/core-components'; +import { + Divider, + ListItem, + ListItemText, + ListItemIcon, + Box, + Chip, +} from '@material-ui/core'; + +type StackOverflowSearchResultListItemProps = { + result: any; // TODO(emmaindal): type to StackOverflowDocument. + icon?: React.ReactNode; +}; + +export const StackOverflowSearchResultListItem = ( + props: StackOverflowSearchResultListItemProps, +) => { + const { location, title, text, answers, tags } = props.result; + + return ( + + + {props.icon && {props.icon}} + + + + {tags && + tags.map((tag: string) => ( + + ))} + + + + + ); +}; diff --git a/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/index.ts b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/index.ts new file mode 100644 index 0000000000..499f7273aa --- /dev/null +++ b/plugins/stack-overflow/src/search/StackOverflowSearchResultListItem/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 { StackOverflowSearchResultListItem } from './StackOverflowSearchResultListItem'; diff --git a/plugins/stack-overflow/src/setupTests.ts b/plugins/stack-overflow/src/setupTests.ts new file mode 100644 index 0000000000..9bb3e72355 --- /dev/null +++ b/plugins/stack-overflow/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/plugins/stack-overflow/src/types.ts b/plugins/stack-overflow/src/types.ts new file mode 100644 index 0000000000..a23585ed3c --- /dev/null +++ b/plugins/stack-overflow/src/types.ts @@ -0,0 +1,31 @@ +/* + * 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 type StackOverflowQuestion = { + title: string; + link: string; + owner: Record; + tags: string[]; + answer_count: number; +}; + +export type StackOverflowQuestionsContentProps = { + requestParams: StackOverflowQuestionsRequestParams; +}; + +export type StackOverflowQuestionsRequestParams = { + [key: string]: string | string[] | number; +};