diff --git a/packages/app/package.json b/packages/app/package.json index 2c8b10ffb3..a85c26f7f3 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -21,6 +21,7 @@ "@backstage/cli": "^0.1.1-alpha.4", "@backstage/core": "^0.1.1-alpha.4", "@backstage/plugin-home-page": "^0.1.1-alpha.4", + "@backstage/plugin-inventory": "^0.1.1-alpha.4", "@backstage/plugin-lighthouse": "^0.1.1-alpha.4", "@backstage/plugin-welcome": "^0.1.1-alpha.4", "@backstage/theme": "^0.1.1-alpha.4", diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index d4fead2dd9..61adbe9ddc 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -19,6 +19,7 @@ import PropTypes from 'prop-types'; import { Link, makeStyles, Typography } from '@material-ui/core'; import HomeIcon from '@material-ui/icons/Home'; import AccountCircle from '@material-ui/icons/AccountCircle'; +import AccountTreeIcon from '@material-ui/icons/AccountTree'; import { Sidebar, SidebarPage, @@ -79,6 +80,7 @@ const Root: FC<{}> = ({ children }) => ( + diff --git a/packages/app/src/plugins.ts b/packages/app/src/plugins.ts index 919ea0666b..c1cc2cce1a 100644 --- a/packages/app/src/plugins.ts +++ b/packages/app/src/plugins.ts @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export { plugin as HomePagePlugin } from '@backstage/plugin-home-page'; export { plugin as WelcomePlugin } from '@backstage/plugin-welcome'; export { plugin as LighthousePlugin } from '@backstage/plugin-lighthouse'; +export { plugin as InventoryPlugin } from '@backstage/plugin-inventory'; diff --git a/packages/backend/package.json b/packages/backend/package.json index c880f59893..0530f04452 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -9,18 +9,21 @@ }, "scripts": { "build": "tsc", - "start": "tsc-watch --onFirstSuccess nodemon", + "start": "backstage-cli watch-deps --build -- tsc-watch --onFirstSuccess nodemon", "lint": "backstage-cli lint", "test": "backstage-cli test", "clean": "backstage-cli clean" }, "dependencies": { + "@backstage/plugin-inventory-backend": "0.1.1-alpha.4", + "compression": "^1.7.4", "cors": "^2.8.5", "express": "^4.17.1", "helmet": "^3.22.0" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.4", + "@types/compression": "^1.7.0", "@types/cors": "^2.8.6", "@types/express": "^4.17.6", "@types/express-serve-static-core": "^4.17.5", diff --git a/packages/backend/src/index.ts b/packages/backend/src/index.ts index 307bd04be7..fd8015c328 100644 --- a/packages/backend/src/index.ts +++ b/packages/backend/src/index.ts @@ -25,15 +25,21 @@ import express from 'express'; import cors from 'cors'; import helmet from 'helmet'; +import compression from 'compression'; import { testRouter } from './test'; +import { router as inventoryRouter } from '@backstage/plugin-inventory-backend'; -const PORT = parseInt(process.env.PORT ?? '', 10) || 7000; +const DEFAULT_PORT = 7000; + +const PORT = parseInt(process.env.PORT ?? '', 10) || DEFAULT_PORT; const app = express(); app.use(helmet()); app.use(cors()); +app.use(compression()); app.use(express.json()); app.use('/test', testRouter); +app.use('/inventory', inventoryRouter); app.listen(PORT, () => { console.log(`Listening on port ${PORT}`); diff --git a/packages/backend/tsconfig.json b/packages/backend/tsconfig.json index 6a071b2b50..b463ac102f 100644 --- a/packages/backend/tsconfig.json +++ b/packages/backend/tsconfig.json @@ -5,6 +5,7 @@ "outDir": "dist", "incremental": true, "sourceMap": true, + "declaration": true, "strict": true, "target": "es5", "module": "commonjs", diff --git a/plugins/inventory-backend/.eslintrc.js b/plugins/inventory-backend/.eslintrc.js new file mode 100644 index 0000000000..f400a039e7 --- /dev/null +++ b/plugins/inventory-backend/.eslintrc.js @@ -0,0 +1,6 @@ +module.exports = { + rules: { + 'no-console': 0, // Permitted in console programs + 'new-cap': ['error', { capIsNew: false }], // Because Express constructs things e.g. like 'const r = express.Router()' + }, +}; diff --git a/plugins/inventory-backend/README.md b/plugins/inventory-backend/README.md new file mode 100644 index 0000000000..bc224ee42e --- /dev/null +++ b/plugins/inventory-backend/README.md @@ -0,0 +1,13 @@ +# Inventory Backend + +WORK IN PROGRESS + +This is the backend part of the default inventory plugin. + +It responds to requests from the frontend part, and fulfills them by delegating +to your existing inventory related services. + +## Links + +- (Frontend part of the plugin)[https://github.com/spotify/backstage/tree/master/plugins/inventory] +- (The Backstage homepage)[https://backstage.io] diff --git a/plugins/inventory-backend/package.json b/plugins/inventory-backend/package.json new file mode 100644 index 0000000000..37f3f27e78 --- /dev/null +++ b/plugins/inventory-backend/package.json @@ -0,0 +1,22 @@ +{ + "name": "@backstage/plugin-inventory-backend", + "version": "0.1.1-alpha.4", + "main": "dist", + "license": "Apache-2.0", + "private": true, + "scripts": { + "build": "tsc", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "clean": "backstage-cli clean" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.4" + }, + "dependencies": { + "express": "^4.17.1" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/inventory-backend/src/index.ts b/plugins/inventory-backend/src/index.ts new file mode 100644 index 0000000000..92c9090376 --- /dev/null +++ b/plugins/inventory-backend/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { router } from './plugin'; diff --git a/plugins/inventory-backend/src/plugin.test.ts b/plugins/inventory-backend/src/plugin.test.ts new file mode 100644 index 0000000000..b3e2f19771 --- /dev/null +++ b/plugins/inventory-backend/src/plugin.test.ts @@ -0,0 +1,21 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +describe('test', () => { + it('unbreaks the test runner', () => { + expect(true).toBeTruthy(); + }); +}); diff --git a/plugins/inventory-backend/src/plugin.ts b/plugins/inventory-backend/src/plugin.ts new file mode 100644 index 0000000000..88299a5c0f --- /dev/null +++ b/plugins/inventory-backend/src/plugin.ts @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import express from 'express'; + +export const router = express.Router(); + +router.get('/', async (_, res) => { + res + .status(200) + .send([ + { id: 'component1' }, + { id: 'component2' }, + { id: 'component3' }, + { id: 'component4' }, + ]); +}); diff --git a/plugins/inventory-backend/src/setupTests.ts b/plugins/inventory-backend/src/setupTests.ts new file mode 100644 index 0000000000..f3b69cc361 --- /dev/null +++ b/plugins/inventory-backend/src/setupTests.ts @@ -0,0 +1,15 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/plugins/inventory-backend/tsconfig.json b/plugins/inventory-backend/tsconfig.json new file mode 100644 index 0000000000..b463ac102f --- /dev/null +++ b/plugins/inventory-backend/tsconfig.json @@ -0,0 +1,15 @@ +{ + "include": ["src"], + "compilerOptions": { + "baseUrl": "src", + "outDir": "dist", + "incremental": true, + "sourceMap": true, + "declaration": true, + "strict": true, + "target": "es5", + "module": "commonjs", + "esModuleInterop": true, + "types": ["node", "jest"] + } +} diff --git a/plugins/inventory/.eslintrc.js b/plugins/inventory/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/plugins/inventory/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/plugins/inventory/README.md b/plugins/inventory/README.md new file mode 100644 index 0000000000..e77a77148f --- /dev/null +++ b/plugins/inventory/README.md @@ -0,0 +1,13 @@ +# Inventory Frontend + +WORK IN PROGRESS + +This is the frontend part of the default inventory plugin. + +It will implement the core API for handling your inventory of software, and +supply the base views to show and manage them. + +## Links + +- (Backend part of the plugin)[https://github.com/spotify/backstage/tree/master/plugins/inventory-backend] +- (The Backstage homepage)[https://backstage.io] diff --git a/plugins/inventory/package.json b/plugins/inventory/package.json new file mode 100644 index 0000000000..8a260d2778 --- /dev/null +++ b/plugins/inventory/package.json @@ -0,0 +1,38 @@ +{ + "name": "@backstage/plugin-inventory", + "version": "0.1.1-alpha.4", + "main": "dist/index.cjs.js", + "types": "dist/index.d.ts", + "license": "Apache-2.0", + "private": true, + "scripts": { + "build": "backstage-cli plugin:build", + "start": "backstage-cli plugin:serve", + "lint": "backstage-cli lint", + "test": "backstage-cli test", + "clean": "backstage-cli clean" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.4", + "@testing-library/jest-dom": "^4.2.4", + "@testing-library/react": "^9.3.2", + "@testing-library/user-event": "^7.1.2", + "@types/jest": "^24.0.0", + "@types/node": "^12.0.0", + "@types/testing-library__jest-dom": "5.0.2", + "jest-fetch-mock": "^3.0.3" + }, + "dependencies": { + "@backstage/core": "^0.1.1-alpha.4", + "@backstage/theme": "^0.1.1-alpha.4", + "@material-ui/core": "^4.9.1", + "@material-ui/icons": "^4.9.1", + "@material-ui/lab": "4.0.0-alpha.45", + "react": "16.13.1", + "react-dom": "16.13.1", + "react-use": "^13.0.0" + }, + "files": [ + "dist" + ] +} diff --git a/plugins/inventory/src/components/InventoryPage/InventoryPage.test.tsx b/plugins/inventory/src/components/InventoryPage/InventoryPage.test.tsx new file mode 100644 index 0000000000..fe17da308c --- /dev/null +++ b/plugins/inventory/src/components/InventoryPage/InventoryPage.test.tsx @@ -0,0 +1,34 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React from 'react'; +import { render } from '@testing-library/react'; +import mockFetch from 'jest-fetch-mock'; +import InventoryPage from './InventoryPage'; +import { ThemeProvider } from '@material-ui/core'; +import { lightTheme } from '@backstage/theme'; + +describe('InventoryPage', () => { + it('should render', async () => { + mockFetch.mockResponse(() => new Promise(() => {})); + const rendered = render( + + + , + ); + expect(await rendered.findByText('backstage-backend')).toBeInTheDocument(); + }); +}); diff --git a/plugins/inventory/src/components/InventoryPage/InventoryPage.tsx b/plugins/inventory/src/components/InventoryPage/InventoryPage.tsx new file mode 100644 index 0000000000..0b837d840c --- /dev/null +++ b/plugins/inventory/src/components/InventoryPage/InventoryPage.tsx @@ -0,0 +1,65 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import React, { FC } from 'react'; +import { Typography } from '@material-ui/core'; +import { Content, InfoCard, Header, Page, pageTheme } from '@backstage/core'; +import Table from '@material-ui/core/Table'; +import TableBody from '@material-ui/core/TableBody'; +import TableCell from '@material-ui/core/TableCell'; +import TableContainer from '@material-ui/core/TableContainer'; +import TableHead from '@material-ui/core/TableHead'; +import TableRow from '@material-ui/core/TableRow'; + +// TODO(freben): Connect to backend +const STATIC_DATA = [ + { id: 'backstage-frontend', kind: 'website' }, + { id: 'backstage-backend', kind: 'service' }, + { id: 'backstage-microsite', kind: 'website' }, +]; + +const InventoryPage: FC<{}> = () => { + return ( + +
+ + All of it + + + + + + ID + Kind + + + + {STATIC_DATA.map(d => ( + + {d.id} + {d.kind} + + ))} + +
+
+
+
+ + ); +}; + +export default InventoryPage; diff --git a/plugins/inventory/src/components/InventoryPage/index.ts b/plugins/inventory/src/components/InventoryPage/index.ts new file mode 100644 index 0000000000..7a11d39f10 --- /dev/null +++ b/plugins/inventory/src/components/InventoryPage/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { default } from './InventoryPage'; diff --git a/plugins/inventory/src/index.ts b/plugins/inventory/src/index.ts new file mode 100644 index 0000000000..3a0a0fe2d3 --- /dev/null +++ b/plugins/inventory/src/index.ts @@ -0,0 +1,17 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +export { plugin } from './plugin'; diff --git a/plugins/inventory/src/plugin.test.ts b/plugins/inventory/src/plugin.test.ts new file mode 100644 index 0000000000..4fac72593f --- /dev/null +++ b/plugins/inventory/src/plugin.test.ts @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { plugin } from './plugin'; + +describe('inventory', () => { + it('should export plugin', () => { + expect(plugin).toBeDefined(); + }); +}); diff --git a/plugins/inventory/src/plugin.ts b/plugins/inventory/src/plugin.ts new file mode 100644 index 0000000000..197dd3cd38 --- /dev/null +++ b/plugins/inventory/src/plugin.ts @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createPlugin } from '@backstage/core'; +import InventoryPage from './components/InventoryPage'; + +export const plugin = createPlugin({ + id: 'inventory', + register({ router }) { + router.registerRoute('/inventory', InventoryPage); + }, +}); diff --git a/plugins/inventory/src/setupTests.ts b/plugins/inventory/src/setupTests.ts new file mode 100644 index 0000000000..1a907ab8e6 --- /dev/null +++ b/plugins/inventory/src/setupTests.ts @@ -0,0 +1,18 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import '@testing-library/jest-dom/extend-expect'; +require('jest-fetch-mock').enableMocks(); diff --git a/plugins/inventory/tsconfig.json b/plugins/inventory/tsconfig.json new file mode 100644 index 0000000000..7b73db2f0f --- /dev/null +++ b/plugins/inventory/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"], + "compilerOptions": { + "baseUrl": "src" + } +} diff --git a/yarn.lock b/yarn.lock index 5126cfa721..12946641f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3821,6 +3821,13 @@ resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== +"@types/compression@^1.7.0": + version "1.7.0" + resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.0.tgz#8dc2a56604873cf0dd4e746d9ae4d31ae77b2390" + integrity sha512-3LzWUM+3k3XdWOUk/RO+uSjv7YWOatYq2QADJntK1pjkk4DfVP0KrIEPDnXRJxAAGKe0VpIPRmlINLDuCedZWw== + dependencies: + "@types/express" "*" + "@types/connect-history-api-fallback@*": version "1.3.3" resolved "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.3.tgz#4772b79b8b53185f0f4c9deab09236baf76ee3b4"