From 111f163d4105bdda296c2cb71caf0b3e09a71689 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Tue, 24 Mar 2020 10:23:43 +0100 Subject: [PATCH] cli: add create-app --- .../cli/src/commands/create-app/createApp.ts | 150 ++++++++++++++++++ packages/cli/src/index.ts | 6 + packages/cli/templates/default-app/README.md | 3 + packages/cli/templates/default-app/lerna.json | 6 + .../templates/default-app/package.json.hbs | 24 +++ .../default-app/packages/app/package.json.hbs | 39 +++++ .../app/public/android-chrome-192x192.png | Bin 0 -> 4352 bytes .../packages/app/public/apple-touch-icon.png | Bin 0 -> 4311 bytes .../packages/app/public/favicon-16x16.png | Bin 0 -> 890 bytes .../packages/app/public/favicon-32x32.png | Bin 0 -> 1296 bytes .../packages/app/public/favicon.ico | Bin 0 -> 15086 bytes .../packages/app/public/index.html | 93 +++++++++++ .../packages/app/public/manifest.json | 15 ++ .../packages/app/public/robots.txt | 2 + .../packages/app/public/safari-pinned-tab.svg | 28 ++++ .../default-app/packages/app/src/App.test.tsx | 10 ++ .../default-app/packages/app/src/App.tsx | 42 +++++ .../default-app/packages/app/src/index.tsx | 5 + .../default-app/packages/app/src/plugins.ts | 1 + .../packages/app/src/setupTests.ts | 1 + .../default-app/packages/app/tsconfig.json | 20 +++ .../default-app/plugins/welcome/README.md | 3 + .../plugins/welcome/package.json.hbs | 20 +++ .../welcome/src/components/Timer/Timer.tsx | 58 +++++++ .../welcome/src/components/Timer/index.ts | 1 + .../WelcomePage/WelcomePage.test.tsx | 16 ++ .../components/WelcomePage/WelcomePage.tsx | 106 +++++++++++++ .../src/components/WelcomePage/index.ts | 1 + .../default-app/plugins/welcome/src/index.ts | 1 + .../plugins/welcome/src/plugin.test.ts | 7 + .../default-app/plugins/welcome/src/plugin.ts | 9 ++ .../plugins/welcome/src/setupTests.ts | 1 + .../default-app/plugins/welcome/tsconfig.json | 4 + .../templates/default-app/prettier.config.js | 1 + .../cli/templates/default-app/tsconfig.json | 10 ++ 35 files changed, 683 insertions(+) create mode 100644 packages/cli/src/commands/create-app/createApp.ts create mode 100644 packages/cli/templates/default-app/README.md create mode 100644 packages/cli/templates/default-app/lerna.json create mode 100644 packages/cli/templates/default-app/package.json.hbs create mode 100644 packages/cli/templates/default-app/packages/app/package.json.hbs create mode 100644 packages/cli/templates/default-app/packages/app/public/android-chrome-192x192.png create mode 100644 packages/cli/templates/default-app/packages/app/public/apple-touch-icon.png create mode 100644 packages/cli/templates/default-app/packages/app/public/favicon-16x16.png create mode 100644 packages/cli/templates/default-app/packages/app/public/favicon-32x32.png create mode 100644 packages/cli/templates/default-app/packages/app/public/favicon.ico create mode 100644 packages/cli/templates/default-app/packages/app/public/index.html create mode 100644 packages/cli/templates/default-app/packages/app/public/manifest.json create mode 100644 packages/cli/templates/default-app/packages/app/public/robots.txt create mode 100644 packages/cli/templates/default-app/packages/app/public/safari-pinned-tab.svg create mode 100644 packages/cli/templates/default-app/packages/app/src/App.test.tsx create mode 100644 packages/cli/templates/default-app/packages/app/src/App.tsx create mode 100644 packages/cli/templates/default-app/packages/app/src/index.tsx create mode 100644 packages/cli/templates/default-app/packages/app/src/plugins.ts create mode 100644 packages/cli/templates/default-app/packages/app/src/setupTests.ts create mode 100644 packages/cli/templates/default-app/packages/app/tsconfig.json create mode 100644 packages/cli/templates/default-app/plugins/welcome/README.md create mode 100644 packages/cli/templates/default-app/plugins/welcome/package.json.hbs create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/components/Timer/Timer.tsx create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/components/Timer/index.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.tsx create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/index.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/index.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/plugin.test.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/plugin.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/src/setupTests.ts create mode 100644 packages/cli/templates/default-app/plugins/welcome/tsconfig.json create mode 100644 packages/cli/templates/default-app/prettier.config.js create mode 100644 packages/cli/templates/default-app/tsconfig.json diff --git a/packages/cli/src/commands/create-app/createApp.ts b/packages/cli/src/commands/create-app/createApp.ts new file mode 100644 index 0000000000..71e8ec50e9 --- /dev/null +++ b/packages/cli/src/commands/create-app/createApp.ts @@ -0,0 +1,150 @@ +/* + * 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 fs from 'fs-extra'; +import path from 'path'; +import { promisify } from 'util'; +import chalk from 'chalk'; +import inquirer, { Answers, Question } from 'inquirer'; +import { exec as execCb } from 'child_process'; +import { resolve as resolvePath } from 'path'; +import { realpathSync } from 'fs'; +import os from 'os'; +import { Task, templatingTask } from '../../helpers/tasks'; +const exec = promisify(execCb); + +async function checkExists(rootDir: string, name: string) { + await Task.forItem('checking', name, async () => { + const destination = path.join(rootDir, 'plugins', name); + + if (await fs.pathExists(destination)) { + const existing = chalk.cyan(destination.replace(`${rootDir}/`, '')); + throw new Error( + `A directory with the same name already exists: ${existing}\nPlease try again with a different app name`, + ); + } + }); +} + +export async function createTemporaryAppFolder(tempDir: string) { + await Task.forItem('creating', 'temporary directory', async () => { + try { + await fs.mkdir(tempDir); + } catch (error) { + throw new Error( + `Failed to create temporary app directory: ${error.message}`, + ); + } + }); +} + +async function cleanUp(tempDir: string) { + await Task.forItem('remove', 'temporary directory', async () => { + await fs.remove(tempDir); + }); +} + +async function buildApp(pluginFolder: string) { + const commands = ['yarn install', 'yarn build']; + for (const command of commands) { + await Task.forItem('executing', command, async () => { + process.chdir(pluginFolder); + + await exec(command).catch(error => { + process.stdout.write(error.stderr); + process.stdout.write(error.stdout); + throw new Error(`Could not execute command ${chalk.cyan(command)}`); + }); + }); + } +} + +export async function moveApp( + tempDir: string, + destination: string, + id: string, +) { + await Task.forItem('moving', id, async () => { + await fs.move(tempDir, destination).catch(error => { + throw new Error( + `Failed to move plugin from ${tempDir} to ${destination}: ${error.message}`, + ); + }); + }); +} + +export default async () => { + const questions: Question[] = [ + { + type: 'input', + name: 'name', + message: chalk.blue('Enter a name for the app [required]'), + validate: (value: any) => { + if (!value) { + return chalk.red('Please enter a name for the app'); + } else if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(value)) { + return chalk.red( + 'Plugin name must be kebab-cased and contain only letters, digits, and dashes.', + ); + } + return true; + }, + }, + ]; + const answers: Answers = await inquirer.prompt(questions); + + const rootDir = realpathSync(process.cwd()); + const cliPackage = resolvePath(__dirname, '../../..'); + const templateDir = resolvePath(cliPackage, 'templates', 'default-app'); + const tempDir = path.join(os.tmpdir(), answers.name); + const appDir = path.join(rootDir, answers.name); + const version = require(resolvePath(cliPackage, 'package.json')).version; + + Task.log(); + Task.log('Creating the app...'); + + try { + Task.section('Checking if the directory is available'); + await checkExists(rootDir, answers.name); + + Task.section('Creating a temporary app directory'); + await createTemporaryAppFolder(tempDir); + + Task.section('Preparing files'); + await templatingTask(templateDir, tempDir, { ...answers, version }); + + Task.section('Moving to final location'); + await moveApp(tempDir, appDir, answers.name); + + Task.section('Building the app'); + await buildApp(appDir); + + Task.log(); + Task.log( + chalk.green(`🥇 Successfully created ${chalk.cyan(answers.name)}`), + ); + Task.log(); + } catch (error) { + Task.error(error.message); + + Task.log('It seems that something went wrong when creating the app 🤔'); + Task.log('We are going to clean up, and then you can try again.'); + + Task.section('Cleanup'); + await cleanUp(tempDir); + Task.error('🔥 Failed to create app!'); + } +}; diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts index 5f24190237..3eafc6dc6b 100644 --- a/packages/cli/src/index.ts +++ b/packages/cli/src/index.ts @@ -17,6 +17,7 @@ import program from 'commander'; import chalk from 'chalk'; import fs from 'fs'; +import createAppCommand from './commands/create-app/createApp'; import createPluginCommand from './commands/create-plugin/createPlugin'; import watch from './commands/watch-deps'; import lintCommand from './commands/lint'; @@ -32,6 +33,11 @@ const main = (argv: string[]) => { program.name('backstage-cli').version(packageJson.version ?? '0.0.0'); + program + .command('create-app') + .description('Creates a new app in a new directory') + .action(actionHandler(createAppCommand)); + program .command('app:build') .description('Build an app for a production release') diff --git a/packages/cli/templates/default-app/README.md b/packages/cli/templates/default-app/README.md new file mode 100644 index 0000000000..b2594d1e53 --- /dev/null +++ b/packages/cli/templates/default-app/README.md @@ -0,0 +1,3 @@ +# [Backstage](https://backstage.io) + +This is your newly scaffolded Backstage App, Good Luck! diff --git a/packages/cli/templates/default-app/lerna.json b/packages/cli/templates/default-app/lerna.json new file mode 100644 index 0000000000..322929db1d --- /dev/null +++ b/packages/cli/templates/default-app/lerna.json @@ -0,0 +1,6 @@ +{ + "packages": ["packages/*", "plugins/*"], + "npmClient": "yarn", + "useWorkspaces": true, + "version": "0.1.0" +} diff --git a/packages/cli/templates/default-app/package.json.hbs b/packages/cli/templates/default-app/package.json.hbs new file mode 100644 index 0000000000..def7b3178b --- /dev/null +++ b/packages/cli/templates/default-app/package.json.hbs @@ -0,0 +1,24 @@ +{ + "name": "root", + "private": true, + "scripts": { + "start": "yarn build && yarn workspace app start", + "build": "lerna run build", + "test": "cross-env CI=true lerna run test -- --coverage", + "create-plugin": "backstage-cli create-plugin", + "lint": "lerna run lint" + }, + "workspaces": { + "packages": [ + "packages/*", + "plugins/*" + ] + }, + "version": "1.0.0", + "devDependencies": { + "@backstage/cli": "^{{version}}", + "cross-env": "^7.0.0", + "lerna": "^3.20.2", + "prettier": "^1.19.1" + } +} diff --git a/packages/cli/templates/default-app/packages/app/package.json.hbs b/packages/cli/templates/default-app/packages/app/package.json.hbs new file mode 100644 index 0000000000..fd0a19fed0 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/package.json.hbs @@ -0,0 +1,39 @@ +{ + "name": "app", + "version": "0.0.0", + "private": true, + "dependencies": { + "@material-ui/core": "^4.9.1", + "@material-ui/icons": "^4.9.1", + "@backstage/cli": "^{{version}}", + "@backstage/core": "^{{version}}", + "@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/react-router-dom": "^5.1.3", + "plugin-welcome": "0.0.0", + "react": "^16.12.0", + "react-dom": "^16.12.0", + "react-router-dom": "^5.1.2" + }, + "scripts": { + "start": "backstage-cli app:serve", + "build": "backstage-cli app:build", + "test": "backstage-cli test", + "lint": "backstage-cli lint" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/packages/cli/templates/default-app/packages/app/public/android-chrome-192x192.png b/packages/cli/templates/default-app/packages/app/public/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..3d56edbb0dce7b1c12f644090e3522d9b992fd1d GIT binary patch literal 4352 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 RoeFdlgQu&X%Q~loCID><@&Nz< literal 0 HcmV?d00001 diff --git a/packages/cli/templates/default-app/packages/app/public/favicon-32x32.png b/packages/cli/templates/default-app/packages/app/public/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..e2707f2d1e6f17270c8728efcb7230310aefdefc GIT binary patch literal 1296 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyEa{HEjtmSN`?>!lvVtU&J%W50 z7^>757#dm_7=8hT8eT9klo~KFyh>nTu$sZZAYL$MSD+081LL6ppAc7|0tRMAnGIgd zg6z^8JOwj#q}O=JZuFK~=P9+;LuS2~^m;G3O_H2?+zGJ^OOSp?2T3kG1g zVM@V8fDE8|G%ltHTmhQlXeyDF0onim|F2@Y_Zg^Ya!HV1Fsfcg9$t3QwWm%T+c7yr zSo+SdBOWgTFUhZ5wf@Za>?9@@!B2}5I5ux*o4bZt_Iy>fhPHmdzk9D@mA3D z-b1QO^Xm4#vs8O5aif`C$5xTay+V5KtFQMexN-zUf-kVn{F#3FqLkW`ecY)gA1(-e zZIZmSj3pxNvo(KzUwghIYv`tv3oUuil%F>NI*T#M+udaFdh=h+CN7 zRPLi&;zFRbr>Bc!h{fsTgau3w9*Z|H)j8VbaJ96!x+psM#5e_U1vhRvlfp7#>g4B# zS0{W*VRdEVQq$H<4pmsRXw|ZHjA08qLmS1KxAm=CCfBj@e7kQWV@GBNOOn*=2O$R% zxRPegd>oRH$e9$CSlYa`ckSH08<{6O&FBtooHu!Mw|2+FXMOfEHa1&7YJd0?c5FS+ z0{QqgTz^dd{$*x5xbA}Zk(a)V`4h~WnhM!NJTyAq_D4HLSair9Ja9rpQdCy>bjv~o zKAGr`JU*PAo+mX|X8LfjzLcCfQ!MhP!m`!2#eVNZ6i%E@PioZW2-VUkXj#&JNa@-m zp$SczOH+L!4mmEK)3|n#(3%CSq`I4CMLDxA+f}upsm+at)wIa>KtfVdejekgRmjRy*V;jCKX z8c~vxSdwa$T$Bo=7>o=IEp!bHbqy^;3{9;}jjfCgv<(cc3=G%>mENIf$jwj5OsmAL zq0DC%s6Yy@3W+EQN-S3>D9TUE%t=)!sVqoU$Sf#HW?-n8^Y{}FM`4(T#wq{PXFQ(< zF)%B0>m_pwD+_y17GV}vaA`0(oWiWUIYi;~jVmXPoH-(Mg#C1b#{w@shF9W(C7+y3 Rrvj~D@O1TaS?83{1OQGQaIF9U literal 0 HcmV?d00001 diff --git a/packages/cli/templates/default-app/packages/app/public/favicon.ico b/packages/cli/templates/default-app/packages/app/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..5b582704a10d20240034385f14c210db96d51603 GIT binary patch literal 15086 zcmeI2d2AF_9LJ{=UG5^DSg*Ti8pU{EyyAuN zh&M`6142+i#ef%xF&Z`4phlws8xbwKw0^$3^S0C1Id*4fh=1%a`RqG?@AsYS&6}BZ zoGPc<88ylwt#@8L$Z?K#9H+kCEe~{@P1Fq}Rr}1Ij&nO5M$iWrXDX;ZXT$PI<+rj2 zDtn-^2h!XF6BpN3pWZyA_r&HQ%t$5KNP16!OJgt@pL1a>)IkPHGBgi@Y48HP3yWYj z>{sMK*VC^9+GCQ%?@#z1mcR@c43UP$VelsW3mqPIl7Al#j~v8tjDBrH5@>rqg^OW# z@HMp6z!LE4w)1Ofuk{_EvodM@W*_L7+y;F+Lv`lRH3@b^=-2jK+v(+-OH04D;~!{( zZr3Eb9xFn-^e^L@4!f?>)UR#$9nOG)G1v4&SJb&<&ZUp(TT^iEo=IE3wqZH+H=!pi z8eD~@C&6e8OINV}dl_G!G)n(cd@h4&9;TC@3s1l%kj5~!(LN3ehW5+Ao_GAVDM*TZ5~16J}?t>-(3Z-!CZ)%_Z3r? zlz!cJ!}PD9y_V^&8rAkKqEAgrxI1nd`n7g$hGL#S%H6!A z^=mye1$vh&tVsW)_3t3=2QU%RnD6b)N?O0UCVnN*C3dhB%2E11C+6dzwX)$k^4iCm zlZ;-!bTjQ~&HD_Uvnc(3>*p#w`@u=D8vL}Ix|eD11!-9v{a!5xQ_vi5^xCQJy~lVR z63&;aUvlmOTer7-b;6px!zH2rstElLdIKh$PeT7~5&EA>ShIJya`g{kuus5yzS#MP zy#W)>$JM_ZIyOa8bDeBmC3SzmvENAg$*vvsr2A*E5^0k%1;iifNMiv*=t8dRMxu z*8loGpku9P@KX63pRMpUyaduc78?PdqoRbJHd_ZLsR|{W7h2zf7Bz+Hnf;OdLBkaZPH)XEWFi zeu_#*aBS=0L@4}EYggPQiC3}z*B;;-R|fh+*u76{?;AjC!FwanbIM#82YZ085pOrR z5MBp;Cwv-?^X=?7`VRLUaF!R1*4-b#B-QL zcbNNw!}!DD$AI|nP~TVmJQfuHO8RK#+RJ4q>G`k$ys?$nJLz-4nb=&bbMH}~`1&u+ z73yPIQ2eP@KU17Q<`1wnG@1^?sfC5`D{KdydyUY?^zo#n#@`R$ufdM5@8bm{mahFn z;CMI?dK4PFW=f4e9Cw`?cKkVAhb_8PO8owedJov&<@AgaG`~a%35u_G@UubNC2j(J z%hb7MZ+ki4FN5OSF@nnPq30loYjNZMOh6rry10Q|zqs+g!T&r6I)L{a?D`T2Op@9|x5;61XmIaQw=N{|o--mJwU7apM1jpVq&pLEPhx zYtHuO_f^pGUK_%Pw7ms-?|K332}zjr_k;cssE^kAgNHiAQ-#eF># z-c#65Mzkel8o8H+&ZTZ^2iD1bU?6zUv&r;*2UdDmLH=pb8bo86XP;(#^}pUps&j1~ zY0&)j7j2E|htJJmo)z`Kay|RVjK9_(55YBXKWKfTaW})TGv6FK3!khz#!^yUQ!?ZK zC;73tn*7h*B=T>A@iSV7_r+%p%!fnrU2?x({}bH$0i@4>{I|kU5M;(*-#=EvB3J{8 ztGY)($0x{)zu!J=#%Z4*N4MViYu?nlUf)`mgJQSB6bLip@7;g<;;;dvX(fbx&oTab zUohV7dkm@8Zt`CX+MhvY{CCpfOIQa#f!QDTk@udj6uX%5H~mejb5Hm7`Yye@7j$gr s!c{JFNN2*y5T={v@+|-E({Wa9gK6CKM)ODZG0;F+H04p*TW9?K1Dt;TIRF3v literal 0 HcmV?d00001 diff --git a/packages/cli/templates/default-app/packages/app/public/index.html b/packages/cli/templates/default-app/packages/app/public/index.html new file mode 100644 index 0000000000..ac2e9a6a73 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/public/index.html @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + Backstage + + + +
+ + + diff --git a/packages/cli/templates/default-app/packages/app/public/manifest.json b/packages/cli/templates/default-app/packages/app/public/manifest.json new file mode 100644 index 0000000000..4a7c1b4ec4 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/public/manifest.json @@ -0,0 +1,15 @@ +{ + "short_name": "Backstage", + "name": "Backstage", + "icons": [ + { + "src": "favicon.ico", + "sizes": "48x48", + "type": "image/png" + } + ], + "start_url": "./index.html", + "display": "standalone", + "theme_color": "#000000", + "background_color": "#ffffff" +} diff --git a/packages/cli/templates/default-app/packages/app/public/robots.txt b/packages/cli/templates/default-app/packages/app/public/robots.txt new file mode 100644 index 0000000000..01b0f9a107 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/public/robots.txt @@ -0,0 +1,2 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * diff --git a/packages/cli/templates/default-app/packages/app/public/safari-pinned-tab.svg b/packages/cli/templates/default-app/packages/app/public/safari-pinned-tab.svg new file mode 100644 index 0000000000..3b0f666390 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/public/safari-pinned-tab.svg @@ -0,0 +1,28 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + + diff --git a/packages/cli/templates/default-app/packages/app/src/App.test.tsx b/packages/cli/templates/default-app/packages/app/src/App.test.tsx new file mode 100644 index 0000000000..0074416375 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/src/App.test.tsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import App from './App'; + +describe('App', () => { + it('should render', () => { + const rendered = render(); + expect(rendered.baseElement).toBeInTheDocument(); + }); +}); diff --git a/packages/cli/templates/default-app/packages/app/src/App.tsx b/packages/cli/templates/default-app/packages/app/src/App.tsx new file mode 100644 index 0000000000..14a07870b2 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/src/App.tsx @@ -0,0 +1,42 @@ +import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core'; +import { BackstageTheme, createApp } from '@backstage/core'; +import React, { FC } from 'react'; +import { BrowserRouter as Router } from 'react-router-dom'; +import * as plugins from './plugins'; + +const useStyles = makeStyles(theme => ({ + '@global': { + html: { + height: '100%', + fontFamily: theme.typography.fontFamily, + }, + body: { + height: '100%', + fontFamily: theme.typography.fontFamily, + 'overscroll-behavior-y': 'none', + }, + a: { + color: 'inherit', + textDecoration: 'none', + }, + }, +})); + +const app = createApp(); +app.registerPlugin(...Object.values(plugins)); +const AppComponent = app.build(); + +const App: FC<{}> = () => { + useStyles(); + return ( + + + + + + + + ); +}; + +export default App; diff --git a/packages/cli/templates/default-app/packages/app/src/index.tsx b/packages/cli/templates/default-app/packages/app/src/index.tsx new file mode 100644 index 0000000000..b597a44232 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/src/index.tsx @@ -0,0 +1,5 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import App from './App'; + +ReactDOM.render(, document.getElementById('root')); diff --git a/packages/cli/templates/default-app/packages/app/src/plugins.ts b/packages/cli/templates/default-app/packages/app/src/plugins.ts new file mode 100644 index 0000000000..6639319bbd --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/src/plugins.ts @@ -0,0 +1 @@ +export { default as WelcomePlugin } from 'plugin-welcome'; diff --git a/packages/cli/templates/default-app/packages/app/src/setupTests.ts b/packages/cli/templates/default-app/packages/app/src/setupTests.ts new file mode 100644 index 0000000000..666127af39 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/src/setupTests.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/extend-expect'; diff --git a/packages/cli/templates/default-app/packages/app/tsconfig.json b/packages/cli/templates/default-app/packages/app/tsconfig.json new file mode 100644 index 0000000000..0457810645 --- /dev/null +++ b/packages/cli/templates/default-app/packages/app/tsconfig.json @@ -0,0 +1,20 @@ +{ + "extends": "@spotify/web-scripts/config/tsconfig.json", + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react", + "incremental": false + }, + "include": ["src"] +} diff --git a/packages/cli/templates/default-app/plugins/welcome/README.md b/packages/cli/templates/default-app/plugins/welcome/README.md new file mode 100644 index 0000000000..e9b9dd0edf --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/README.md @@ -0,0 +1,3 @@ +# Title + +Welcome to the welcome plugin! diff --git a/packages/cli/templates/default-app/plugins/welcome/package.json.hbs b/packages/cli/templates/default-app/plugins/welcome/package.json.hbs new file mode 100644 index 0000000000..1aa7f2c5c7 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/package.json.hbs @@ -0,0 +1,20 @@ +{ + "name": "plugin-welcome", + "version": "0.0.0", + "main": "dist/cjs/index.js", + "types": "dist/cjs/index.d.ts", + "private": true, + "scripts": { + "build": "backstage-cli plugin:build", + "lint": "backstage-cli lint", + "test": "backstage-cli test" + }, + "devDependencies": { + "@backstage/core": "^{{version}}", + "@backstage/cli": "^{{version}}", + "@types/testing-library__jest-dom": "5.0.2" + }, + "dependencies": { + "@material-ui/lab": "4.0.0-alpha.45" + } +} diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/Timer.tsx b/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/Timer.tsx new file mode 100644 index 0000000000..24c79f91ee --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/Timer.tsx @@ -0,0 +1,58 @@ +import React, { FC } from 'react'; +import { HeaderLabel } from '@backstage/core'; + +const timeFormat = { hour: '2-digit', minute: '2-digit' }; +const utcOptions = { timeZone: 'UTC', ...timeFormat }; +const nycOptions = { timeZone: 'America/New_York', ...timeFormat }; +const tyoOptions = { timeZone: 'Asia/Tokyo', ...timeFormat }; +const stoOptions = { timeZone: 'Europe/Stockholm', ...timeFormat }; + +const defaultTimes = { + timeNY: '', + timeUTC: '', + timeTYO: '', + timeSTO: '', +}; + +function getTimes() { + const d = new Date(); + const lang = window.navigator.language; + + // Using the browser native toLocaleTimeString instead of huge moment-tz + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleTimeString + const timeNY = d.toLocaleTimeString(lang, nycOptions); + const timeUTC = d.toLocaleTimeString(lang, utcOptions); + const timeTYO = d.toLocaleTimeString(lang, tyoOptions); + const timeSTO = d.toLocaleTimeString(lang, stoOptions); + + return { timeNY, timeUTC, timeTYO, timeSTO }; +} + +const HomePageTimer: FC<{}> = () => { + const [{ timeNY, timeUTC, timeTYO, timeSTO }, setTimes] = React.useState( + defaultTimes, + ); + + React.useEffect(() => { + setTimes(getTimes()); + + const intervalId = setInterval(() => { + setTimes(getTimes()); + }, 1000); + + return () => { + clearInterval(intervalId); + }; + }, []); + + return ( + <> + + + + + + ); +}; + +export default HomePageTimer; diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/index.ts b/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/index.ts new file mode 100644 index 0000000000..f1fc55bfe9 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/Timer/index.ts @@ -0,0 +1 @@ +export { default } from './Timer'; diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx new file mode 100644 index 0000000000..4b9b12913d --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.test.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import WelcomePage from './WelcomePage'; +import { ThemeProvider } from '@material-ui/core'; +import { BackstageTheme } from '@backstage/core'; + +describe('WelcomePage', () => { + it('should render', () => { + const rendered = render( + + + , + ); + expect(rendered.baseElement).toBeInTheDocument(); + }); +}); diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.tsx b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.tsx new file mode 100644 index 0000000000..19f9ee55e2 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/WelcomePage.tsx @@ -0,0 +1,106 @@ +import React, { FC } from 'react'; +import { Link as RouterLink } from 'react-router-dom'; +import { + Typography, + Grid, + List, + ListItem, + ListItemText, + Link, +} from '@material-ui/core'; +import Timer from '../Timer'; +import { + Content, + InfoCard, + Header, + Page, + pageTheme, + ContentHeader, + SupportButton, +} from '@backstage/core'; + +const WelcomePage: FC<{}> = () => { + const profile = { givenName: '' }; + + return ( + +
+ +
+ + + + + + + + + You now have a running instance of Backstage! + + 🎉 + + Let's make sure you get the most out of this platform by walking + you through the basics. + + + The Setup + + + Backstage is put together from three base concepts: the core, + the app and the plugins. + + + + + + + + + + + + + + Try It Out + + + We suggest you either check out the documentation for{' '} + + creating a plugin + {' '} + or have a look in the code for the{' '} + + Home Page + {' '} + in the directory "plugins/home-page/src". + + + + + + Quick Links + + + backstage.io + + + + Create a plugin + + + + + + + +
+ ); +}; + +export default WelcomePage; diff --git a/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/index.ts b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/index.ts new file mode 100644 index 0000000000..b031301e7e --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/components/WelcomePage/index.ts @@ -0,0 +1 @@ +export { default } from './WelcomePage'; diff --git a/packages/cli/templates/default-app/plugins/welcome/src/index.ts b/packages/cli/templates/default-app/plugins/welcome/src/index.ts new file mode 100644 index 0000000000..b68aea57f9 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/index.ts @@ -0,0 +1 @@ +export { default } from './plugin'; diff --git a/packages/cli/templates/default-app/plugins/welcome/src/plugin.test.ts b/packages/cli/templates/default-app/plugins/welcome/src/plugin.test.ts new file mode 100644 index 0000000000..f61dee5690 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/plugin.test.ts @@ -0,0 +1,7 @@ +import plugin from './plugin'; + +describe('welcome', () => { + it('should export plugin', () => { + expect(plugin).toBeDefined(); + }); +}); diff --git a/packages/cli/templates/default-app/plugins/welcome/src/plugin.ts b/packages/cli/templates/default-app/plugins/welcome/src/plugin.ts new file mode 100644 index 0000000000..35ceddd65f --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/plugin.ts @@ -0,0 +1,9 @@ +import { createPlugin } from '@backstage/core'; +import WelcomePage from './components/WelcomePage'; + +export default createPlugin({ + id: 'welcome', + register({ router }) { + router.registerRoute('/', WelcomePage); + }, +}); diff --git a/packages/cli/templates/default-app/plugins/welcome/src/setupTests.ts b/packages/cli/templates/default-app/plugins/welcome/src/setupTests.ts new file mode 100644 index 0000000000..666127af39 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/src/setupTests.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/extend-expect'; diff --git a/packages/cli/templates/default-app/plugins/welcome/tsconfig.json b/packages/cli/templates/default-app/plugins/welcome/tsconfig.json new file mode 100644 index 0000000000..596e2cf729 --- /dev/null +++ b/packages/cli/templates/default-app/plugins/welcome/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src"] +} diff --git a/packages/cli/templates/default-app/prettier.config.js b/packages/cli/templates/default-app/prettier.config.js new file mode 100644 index 0000000000..93df970dd6 --- /dev/null +++ b/packages/cli/templates/default-app/prettier.config.js @@ -0,0 +1 @@ +module.exports = require('@spotify/web-scripts/config/prettier.config.js'); diff --git a/packages/cli/templates/default-app/tsconfig.json b/packages/cli/templates/default-app/tsconfig.json new file mode 100644 index 0000000000..25f61cc933 --- /dev/null +++ b/packages/cli/templates/default-app/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "@spotify/web-scripts/config/tsconfig.json", + "exclude": ["**/*.test.*"], + "compilerOptions": { + "allowJs": true, + "noEmit": false, + "declarationMap": true, + "incremental": true + } +}