diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..2103055e --- /dev/null +++ b/.babelrc @@ -0,0 +1,11 @@ +{ + "presets": ["next/babel"], + "plugins": [ + "emotion", + "inline-react-svg", + [ + "styled-components", + { "ssr": true, "displayName": true, "preprocess": false } + ] + ] +} diff --git a/.commitlintrc.json b/.commitlintrc.json new file mode 100644 index 00000000..c30e5a97 --- /dev/null +++ b/.commitlintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["@commitlint/config-conventional"] +} diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..b942b38a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git +.gitignore +.cache +*.md +!README*.md +/node_modules +/.next +/docs +/.github +.env +.vscode +CHANGELOG.md \ No newline at end of file diff --git a/.gitignore b/.gitignore index 3c3629e6..e185c75f 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,31 @@ -node_modules +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..03e9d2e5 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,2 @@ +/.next +/.node_modules \ No newline at end of file diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..31fae040 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "printWidth": 80, + "arrowParens": "avoid" +} diff --git a/.storybook/config.js b/.storybook/config.js new file mode 100644 index 00000000..92fb6618 --- /dev/null +++ b/.storybook/config.js @@ -0,0 +1,24 @@ +import { configure, addDecorator, addParameters } from '@storybook/react'; +import themeDecorator from './themeDecorator'; +import { withKnobs } from '@storybook/addon-knobs'; +import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'; + +const customViewports = { + smallScreen: { + name: 'Small Screen', + styles: { + width: '578px', + height: '100%', + }, + }, +}; + +addParameters({ + viewport: { + viewports: { ...INITIAL_VIEWPORTS, ...customViewports }, + }, +}); +addDecorator(themeDecorator); +addDecorator(withKnobs); + +configure(require.context('../src/', true, /\.stories\.tsx?$/), module); diff --git a/.storybook/main.js b/.storybook/main.js new file mode 100644 index 00000000..9adf0e11 --- /dev/null +++ b/.storybook/main.js @@ -0,0 +1,7 @@ +module.exports = { + addons: [ + '@storybook/addon-knobs/register', + '@storybook/addon-actions', + '@storybook/addon-viewport/register', + ], +}; diff --git a/client/.storybook/manager.js b/.storybook/manager.js similarity index 68% rename from client/.storybook/manager.js rename to .storybook/manager.js index 2decfed3..a99ce84b 100644 --- a/client/.storybook/manager.js +++ b/.storybook/manager.js @@ -2,6 +2,6 @@ import { addons } from '@storybook/addons'; import { themes } from '@storybook/theming'; addons.setConfig({ - theme: themes.dark, - panelPosition: 'right', + theme: themes.dark, + panelPosition: 'right', }); diff --git a/.storybook/themeDecorator.js b/.storybook/themeDecorator.js new file mode 100644 index 00000000..e70dc21e --- /dev/null +++ b/.storybook/themeDecorator.js @@ -0,0 +1,35 @@ +import React from 'react'; +import styled, { ThemeProvider, css } from 'styled-components'; +import { select, boolean } from '@storybook/addon-knobs'; +import { backgroundColor, cardColor } from '../src/styles/Themes'; + +const StyledBackground = styled.div` + width: 100%; + height: 100%; + padding: 100px 0; + ${({ withBackground, cardBackground }) => + withBackground && + css` + background: ${cardBackground ? cardColor : backgroundColor}; + `} + display: flex; + justify-content: center; + align-items: center; +`; + +const ThemeDecorator = storyFn => { + const background = boolean('No Background', false); + const cardBackground = boolean('Card Background', true); + return ( + + + {storyFn()} + + + ); +}; + +export default ThemeDecorator; diff --git a/.storybook/webpack.config.js b/.storybook/webpack.config.js new file mode 100644 index 00000000..49421474 --- /dev/null +++ b/.storybook/webpack.config.js @@ -0,0 +1,12 @@ +module.exports = ({ config }) => { + config.module.rules.push({ + test: /\.(ts|tsx)$/, + loader: require.resolve('babel-loader'), + options: { + presets: [require.resolve('babel-preset-react-app')], + }, + }); + + config.resolve.extensions.push('.ts', '.tsx'); + return config; +}; diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..ad92582b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.formatOnSave": true +} diff --git a/@types/index.d.ts b/@types/index.d.ts new file mode 100644 index 00000000..da7fb7f6 --- /dev/null +++ b/@types/index.d.ts @@ -0,0 +1,5 @@ +declare module '*.png'; +declare module '*.jpg'; +declare module '*.jpeg'; +declare module '*.svg'; +declare module '*.gif'; diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..355b06f5 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,16 @@ +FROM node:alpine + +# Create app directory +# RUN mkdir -p /usr/src/app +WORKDIR /usr/src/app + +# Install app dependencies +COPY package.json /usr/src/app/ +COPY yarn.lock /usr/src/app/ +RUN yarn install --production=true + +# Bundle app source +COPY . /usr/src/app +RUN yarn build +EXPOSE 3000 +CMD [ "yarn", "start" ] \ No newline at end of file diff --git a/README.md b/README.md index bba85fee..6f634126 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # **ThunderHub - Lightning Node Manager** -![Home Screenshot](assets/Home.png) -[![license](https://img.shields.io/github/license/DAVFoundation/captain-n3m0.svg?style=flat-square)](https://github.com/DAVFoundation/captain-n3m0/blob/master/LICENSE) [![Known Vulnerabilities](https://snyk.io/test/github/apotdevin/thunderhub/badge.svg?targetFile=client/package.json)](https://snyk.io/test/github/apotdevin/thunderhub) [![Known Vulnerabilities](https://snyk.io/test/github/apotdevin/thunderhub/badge.svg?targetFile=server/package.json)](https://snyk.io/test/github/apotdevin/thunderhub) [![lerna](https://img.shields.io/badge/maintained%20with-lerna-cc00ff.svg)](https://lerna.js.org/) +![Home Screenshot](./docs/Home.png) +[![license](https://img.shields.io/github/license/DAVFoundation/captain-n3m0.svg?style=flat-square)](https://github.com/DAVFoundation/captain-n3m0/blob/master/LICENSE) ## Table Of Contents @@ -16,21 +16,13 @@ ThunderHub is an **open-source** LND node manager where you can manage and monit ### Tech Stack -The repository consists of two packages (client and server) and is maintained with LernaJS and Yarn Workspaces. - -#### Client - -[![Known Vulnerabilities](https://snyk.io/test/github/apotdevin/thunderhub/badge.svg?targetFile=client/package.json)](https://snyk.io/test/github/apotdevin/thunderhub) +This repository consists of a **NextJS** server that handles both the backend **Graphql Server** and the frontend **React App**. +- NextJS - ReactJS - Typescript - Styled-Components - Apollo - -#### Server - -[![Known Vulnerabilities](https://snyk.io/test/github/apotdevin/thunderhub/badge.svg?targetFile=server/package.json)](https://snyk.io/test/github/apotdevin/thunderhub) - - Apollo-Server - GraphQL - Ln-Service @@ -99,47 +91,29 @@ git clone https://github.com/apotdevin/thunderhub.git - Node installed - Yarn installed -After cloning the repository run `yarn` to get all the necessary modules installed. Yarn workspaces will handle installing modules for both the client and the server. +After cloning the repository run `yarn` to get all the necessary modules installed. -### **ThunderHub - Server** - -To be able to use the HodlHodl integration create a `.env` file in the `/server` folder with `HODL_KEY='[YOUR API KEY]'` and replace `[YOUR API KEY]` with the one that HodlHodl provides you. - -#### To get the server running use the following commands +After `yarn` has finished installing all the dependencies you can proceed to build and run the app with the following commands. ```javascript -yarn server:prod -yarn server:run +yarn build +yarn start ``` -If the server starts succesfully, you should see `info [server.js]: Server ready at http://localhost:3001/` in the terminal - -### **ThunderHub - Client** +This will start the server on port 3000, so just head to `localhost:3000` to see the app running. -#### To get the React frontend running use the following commands +#### HodlHodl Integration -##### This must be done in the `/client` folder - -```javascript -yarn start -``` - -If the frontend starts succesfully, you should see `Compiled successfully! You can now view app in the browser.` in the terminal and a browser window should have opened in your browser. +To be able to use the HodlHodl integration create a `.env` file in the root folder with `HODL_KEY='[YOUR API KEY]'` and replace `[YOUR API KEY]` with the one that HodlHodl provides you. ## Development If you want to develop on ThunderHub and want hot reloading when you do changes, use the following commands: -### ThunderHub - Server - ```javascript -yarn server:dev +yarn dev ``` -### ThunderHub - Client - -Running the commands `yarn start` in the `client` folder works for development. - #### Storybook You can also get storybook running for quicker component development. diff --git a/client/.dockerignore b/client/.dockerignore deleted file mode 100644 index 48c0cafa..00000000 --- a/client/.dockerignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -.git -.gitignore -build \ No newline at end of file diff --git a/client/.env b/client/.env deleted file mode 100644 index 1bfdf632..00000000 --- a/client/.env +++ /dev/null @@ -1 +0,0 @@ -REACT_APP_VERSION=$npm_package_version \ No newline at end of file diff --git a/client/.gitignore b/client/.gitignore deleted file mode 100644 index 77315343..00000000 --- a/client/.gitignore +++ /dev/null @@ -1,27 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# production -/build - -#webpack -/dist - -# misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/client/.prettierrc b/client/.prettierrc deleted file mode 100644 index 17c75dc8..00000000 --- a/client/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "printWidth": 80, - "trailingComma": "all", - "tabWidth": 4, - "semi": true, - "singleQuote": true -} diff --git a/client/.storybook/main.js b/client/.storybook/main.js deleted file mode 100644 index 5c627cbd..00000000 --- a/client/.storybook/main.js +++ /dev/null @@ -1,25 +0,0 @@ -module.exports = { - stories: ['../src/**/*.stories.tsx'], - addons: [ - '@storybook/addon-knobs/register', - '@storybook/addon-actions', - '@storybook/preset-create-react-app', - '@storybook/addon-links', - '@storybook/addon-viewport/register', - ], - webpackFinal: async (config) => { - config.module.rules.push({ - test: /\.(ts|tsx)$/, - use: [ - { - loader: require.resolve('awesome-typescript-loader'), - }, - { - loader: require.resolve('react-docgen-typescript-loader'), - }, - ], - }); - config.resolve.extensions.push('.ts', '.tsx'); - return config; - }, -}; diff --git a/client/.storybook/preview.js b/client/.storybook/preview.js deleted file mode 100644 index 6460aca4..00000000 --- a/client/.storybook/preview.js +++ /dev/null @@ -1,22 +0,0 @@ -import { addDecorator, addParameters } from '@storybook/react'; -import themeDecorator from './themeDecorator'; -import { withKnobs } from '@storybook/addon-knobs'; -import { INITIAL_VIEWPORTS } from '@storybook/addon-viewport'; - -const customViewports = { - smallScreen: { - name: 'Small Screen', - styles: { - width: '578px', - height: '100%', - }, - }, -}; - -addParameters({ - viewport: { - viewports: { ...INITIAL_VIEWPORTS, ...customViewports }, - }, -}); -addDecorator(themeDecorator); -addDecorator(withKnobs); diff --git a/client/.storybook/themeDecorator.js b/client/.storybook/themeDecorator.js deleted file mode 100644 index 335d6e16..00000000 --- a/client/.storybook/themeDecorator.js +++ /dev/null @@ -1,37 +0,0 @@ -import React from 'react'; -import styled, { ThemeProvider, css } from 'styled-components'; -import { select, boolean } from '@storybook/addon-knobs'; -import { backgroundColor, cardColor } from '../src/styles/Themes'; - -const StyledBackground = styled.div` - width: 100%; - height: 100%; - padding: 100px 0; - ${({ withBackground, cardBackground }) => - withBackground && - css` - background: ${cardBackground ? cardColor : backgroundColor}; - `} - display: flex; - justify-content: center; - align-items: center; -`; - -const ThemeDecorator = (storyFn) => { - const background = boolean('No Background', false); - const cardBackground = boolean('Card Background', true); - return ( - - - {storyFn()} - - - ); -}; - -export default ThemeDecorator; diff --git a/client/Dockerfile b/client/Dockerfile deleted file mode 100644 index 0725fd8c..00000000 --- a/client/Dockerfile +++ /dev/null @@ -1,14 +0,0 @@ -FROM node:11-alpine as build - -WORKDIR /usr/src/client - -COPY package.json /usr/src/client -COPY yarn.lock /usr/src/client -RUN yarn install --production=true - -COPY . /usr/src/client -RUN yarn build - -RUN yarn global add serve - -CMD ["serve", "-s", "build"] \ No newline at end of file diff --git a/client/config/nginx.conf b/client/config/nginx.conf deleted file mode 100644 index 5727b7e6..00000000 --- a/client/config/nginx.conf +++ /dev/null @@ -1,15 +0,0 @@ -server { - listen 80; - server_name localhost; - - location / { - root /usr/share/nginx/html; - index index.html index.htm; - try_files $uri /index.html; - } - - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } -} \ No newline at end of file diff --git a/client/package.json b/client/package.json deleted file mode 100644 index f8048550..00000000 --- a/client/package.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "name": "@thunderhub/client", - "version": "0.2.1", - "description": "", - "scripts": { - "start": "react-scripts start", - "build": "react-scripts build", - "test": "react-scripts test", - "eject": "react-scripts eject", - "storybook": "start-storybook -p 9009 -s public", - "build-storybook": "build-storybook -s public", - "deploy": "yarn build && aws s3 --profile EBFullAccess sync build/ s3://thunderhub-client", - "precommit": "pretty-quick --staged" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/apotdevin/thunderhub.git" - }, - "keywords": [], - "author": "apotdevin", - "license": "MIT", - "dependencies": { - "@apollo/react-hooks": "^3.1.3", - "@types/crypto-js": "^3.1.44", - "@types/jest": "25.1.5", - "@types/lodash.debounce": "^4.0.6", - "@types/lodash.merge": "^4.6.6", - "@types/lodash.sortby": "^4.7.6", - "@types/node": "13.11.0", - "@types/numeral": "^0.0.26", - "@types/qrcode.react": "^1.0.0", - "@types/react": "16.9.32", - "@types/react-copy-to-clipboard": "^4.3.0", - "@types/react-dom": "16.9.6", - "@types/react-modal": "^3.10.5", - "@types/react-qr-reader": "^2.1.2", - "@types/react-router-dom": "^5.1.2", - "@types/react-tooltip": "^3.11.0", - "@types/styled-components": "^5.0.1", - "@types/styled-react-modal": "^1.2.0", - "@types/styled-theming": "^2.2.2", - "@types/uuid": "^7.0.2", - "@types/victory": "^33.1.4", - "@types/zxcvbn": "^4.4.0", - "apollo-boost": "^0.4.4", - "crypto-js": "^4.0.0", - "intersection-observer": "^0.7.0", - "lodash.debounce": "^4.0.8", - "lodash.merge": "^4.6.2", - "lodash.sortby": "^4.7.0", - "node-sass": "^4.13.0", - "numeral": "^2.0.6", - "qrcode.react": "^1.0.0", - "qs": "^6.9.3", - "react": "^16.13.0", - "react-copy-to-clipboard": "^5.0.2", - "react-dom": "^16.13.0", - "react-intersection-observer": "^8.26.1", - "react-qr-reader": "^2.2.1", - "react-router-dom": "^5.1.2", - "react-scripts": "3.4.1", - "react-spinners": "^0.8.1", - "react-spring": "^8.0.27", - "react-toastify": "^5.4.1", - "react-tooltip": "^4.1.3", - "snyk": "^1.305.0", - "styled-components": "^5.0.1", - "styled-react-modal": "^2.0.0", - "styled-theming": "^2.2.0", - "typescript": "^3.8.3", - "uuid": "^7.0.3", - "victory": "^34.1.3", - "zxcvbn": "^4.4.2" - }, - "devDependencies": { - "@storybook/addon-actions": "^5.3.18", - "@storybook/addon-info": "^5.3.18", - "@storybook/addon-knobs": "^5.3.18", - "@storybook/addon-links": "^5.3.18", - "@storybook/addon-viewport": "^5.3.18", - "@storybook/addons": "^5.3.18", - "@storybook/preset-create-react-app": "^2.1.1", - "@storybook/react": "^5.3.18", - "awesome-typescript-loader": "^5.2.1", - "react-docgen-typescript-loader": "^3.7.2" - }, - "eslintConfig": { - "extends": "react-app" - }, - "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/client/public/apple-touch-icon-152x152.png b/client/public/apple-touch-icon-152x152.png deleted file mode 100644 index a10ba7ed..00000000 Binary files a/client/public/apple-touch-icon-152x152.png and /dev/null differ diff --git a/client/public/index.html b/client/public/index.html deleted file mode 100644 index e97a00c0..00000000 --- a/client/public/index.html +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - ThunderHub - Lightning Node Manager - - - -
- - diff --git a/client/public/manifest.json b/client/public/manifest.json deleted file mode 100644 index 70839658..00000000 --- a/client/public/manifest.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "short_name": "ThunderHub", - "name": "ThunderHub - Lightning Node Manager", - "icons": [ - { - "src": "favicon.ico", - "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" - }, - { - "src": "apple-touch-icon-152x152.png", - "type": "image/png", - "sizes": "152x152" - } - ], - "start_url": ".", - "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" -} diff --git a/client/public/robots.txt b/client/public/robots.txt deleted file mode 100644 index 01b0f9a1..00000000 --- a/client/public/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * diff --git a/client/src/App.test.tsx b/client/src/App.test.tsx deleted file mode 100644 index d1c2db98..00000000 --- a/client/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; - -it('renders without crashing', () => { - const div = document.createElement('div'); - ReactDOM.render(, div); - ReactDOM.unmountComponentAtNode(div); -}); diff --git a/client/src/App.tsx b/client/src/App.tsx deleted file mode 100644 index 16e75080..00000000 --- a/client/src/App.tsx +++ /dev/null @@ -1,80 +0,0 @@ -import React, { Suspense } from 'react'; -import { ThemeProvider } from 'styled-components'; -import { GlobalStyles } from './styles/GlobalStyle'; -import { ApolloProvider } from '@apollo/react-hooks'; -import { BrowserRouter } from 'react-router-dom'; -import ApolloClient from 'apollo-boost'; -import { useSettings } from './context/SettingsContext'; -import { ModalProvider } from 'styled-react-modal'; -import { useAccount } from './context/AccountContext'; -import { toast } from 'react-toastify'; -import 'react-toastify/dist/ReactToastify.css'; -import { Header } from './sections/header/Header'; -import { Footer } from './sections/footer/Footer'; -import { LoadingCard } from './components/loading/LoadingCard'; -import { ScrollToTop } from 'components/scrollToTop/ScrollToTop'; -import { ContextProvider } from 'context/ContextProvider'; -import { ConnectionCheck } from 'components/connectionCheck/ConnectionCheck'; -import { StatusCheck } from 'components/statusCheck/StatusCheck'; -import { BaseModalBackground } from 'styled-react-modal'; - -const EntryView = React.lazy(() => import('./views/entry/Entry')); -const ContentView = React.lazy(() => import('./sections/content/Content')); - -toast.configure({ draggable: false }); - -const client = new ApolloClient({ - uri: - process.env.REACT_APP_API_URL ?? process.env.NODE_ENV === 'production' - ? 'https://api.thunderhub.io' - : 'http://localhost:3001', -}); - -const ContextApp: React.FC = () => { - const { theme } = useSettings(); - const { loggedIn, admin, viewOnly, sessionAdmin } = useAccount(); - - const renderContent = () => ( - } - > - {!loggedIn && admin === '' ? ( - - ) : admin !== '' && viewOnly === '' && sessionAdmin === '' ? ( - - ) : ( - <> - - - - - )} - - ); - - return ( - - - - -
- {renderContent()} -