feat(settings): set up some foundational configs and components

This commit is contained in:
Jody Heavener 2020-04-27 14:21:23 -04:00
Родитель e91822dff5
Коммит 7ee5f5fae7
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: E18320EE42109F37
32 изменённых файлов: 1938 добавлений и 137 удалений

Просмотреть файл

@ -81,6 +81,9 @@
"*.css": [
"prettier --write"
],
"*.scss": [
"sass-lint --config packages/fxa-settings/.sass-lint.yml 'packages/fxa-settings/**/*.scss' --verbose"
],
"*.md": [
"prettier --write"
]

Просмотреть файл

@ -0,0 +1,47 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from "react";
import { render } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import AppErrorBoundary from ".";
describe("AppErrorBoundary", () => {
beforeEach(() => {
// HACK: Swallow the exception thrown by BadComponent
// it bubbles up unnecesarily to jest and makes noise
jest.spyOn(console, "error");
(global.console.error as jest.Mock).mockImplementation(() => {});
});
afterEach(() => {
(global.console.error as jest.Mock).mockRestore();
});
it("renders children that do not cause exceptions", () => {
const GoodComponent = () => <p data-testid="good-component">Hi</p>;
const { queryByTestId } = render(
<AppErrorBoundary>
<GoodComponent />
</AppErrorBoundary>
);
expect(queryByTestId("error-loading-app")).not.toBeInTheDocument();
});
it("renders a general error dialog on exception in child component", () => {
const BadComponent = () => {
throw new Error("bad");
};
const { queryByTestId } = render(
<AppErrorBoundary>
<BadComponent />
</AppErrorBoundary>
);
expect(queryByTestId("error-loading-app")).toBeInTheDocument();
});
});

Просмотреть файл

@ -0,0 +1,35 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from "react";
import AppErrorDialog from "../AppErrorDialog";
class AppErrorBoundary extends React.Component {
state: {
error: undefined | Error;
};
constructor(props: {}) {
super(props);
this.state = { error: undefined };
}
static getDerivedStateFromError(error: Error) {
return { error };
}
componentDidCatch(error: Error, errorInfo: any) {
console.error("AppError", error);
// TODO: Add Sentry logging
// sentryMetrics.captureException(error);
}
render() {
const { error } = this.state;
return error ? <AppErrorDialog {...{ error }} /> : this.props.children;
}
}
export default AppErrorBoundary;

Просмотреть файл

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from "react";
import { render } from "@testing-library/react";
import "@testing-library/jest-dom/extend-expect";
import AppErrorDialog from ".";
describe("AppErrorDialog", () => {
it("renders a general error dialog", () => {
const { queryByTestId } = render(
<AppErrorDialog error={new Error("bad")} />
);
expect(queryByTestId("error-loading-app")).toBeInTheDocument();
});
});

Просмотреть файл

@ -0,0 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from "react";
const AppErrorDialog = ({ error: { message } }: { error: Error }) => {
return (
<div>
<h2 data-testid="error-loading-app">General application error</h2>
<p>Something went wrong. Please try again later.</p>
</div>
);
};
export default AppErrorDialog;

Просмотреть файл

@ -1,7 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const { resolve } = require("path");
const additionalJSImports = {
"@fxa-components": __dirname
"@fxa-components": __dirname,
"@fxa-shared": resolve(__dirname, "../fxa-shared")
};
const permitAdditionalJSImports = config => {

Просмотреть файл

@ -5,7 +5,12 @@
// "compilerOptions.paths must not be set", but
// this will still work.
"paths": {
"@fxa-components/*": ["../fxa-components/*"]
"@fxa-components/*": [
"../fxa-components/*"
],
"@fxa-shared/*": [
"../fxa-shared/*"
]
}
}
}

Просмотреть файл

@ -1,6 +1,9 @@
{
"extends": ["plugin:fxa/server", "plugin:jest/recommended"],
"plugins": ["fxa"],
"ignorePatterns": [
"build/"
],
"parser": "babel-eslint",
"parserOptions": {
"sourceType": "module"
@ -10,5 +13,9 @@
"strict": "off",
"no-useless-escape": "off",
"handle-callback-err": "off"
},
"env": {
"browser": true,
"node": true
}
}

Просмотреть файл

@ -0,0 +1,11 @@
LICENSE
.*
*.ico
*.png
*.svg
*.docker
Dockerfile*
public/images/*
coverage/*
build/*
node_modules/*

Просмотреть файл

@ -0,0 +1,4 @@
{
"singleQuote": true,
"trailingComma": "es5"
}

Просмотреть файл

@ -1,11 +1,15 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {
permitAdditionalJSImports,
setupAliasedPaths,
componentsJestMapper
} = require("../fxa-components/rescripts");
componentsJestMapper,
} = require('../fxa-components/rescripts');
module.exports = [
permitAdditionalJSImports,
setupAliasedPaths,
componentsJestMapper
componentsJestMapper,
];

Просмотреть файл

@ -0,0 +1,33 @@
files:
include:
- 'src/**/*.scss'
exclude:
- 'node_modules'
rules:
border-zero: [2, convention: '0']
class-name-format: 0
clean-import-paths: 0
empty-args: [2, include: true]
force-attribute-nesting: 0
force-element-nesting: 0
force-pseudo-nesting: 0
indentation: 0
leading-zero: 1
mixins-before-declarations: 0
nesting-depth: [2, max-depth: 4]
no-color-literals: 0
no-css-comments: 0
no-empty-args: 0
no-ids: 0
no-important: 0
no-mergeable-selectors: 0
no-misspelled-properties: 0
no-qualifying-elements: 0
no-vendor-prefixes: 0
no-warn: 0
placeholder-in-extend: 0
property-sort-order: [2, ignore-custom-properties: true]
quotes: [2, style: 'single']
shorthand-values: 0
space-after-comma: [2, include: true]
space-around-operator: 0

Просмотреть файл

@ -11,7 +11,36 @@ You can import React components into this project. This is currently restricted
```javascript
// e.g. assuming the component HelloWorld exists
import HelloWorld from "@fxa-components/HelloWorld";
import HelloWorld from '@fxa-components/HelloWorld';
```
**Working with SVGs**
Create React App allows us to use SVGs in a variety of ways, right out of the box.
```javascript
// Inline, full markup:
import { ReactComponent as Logo } from './logo.svg';
const LogoImage = () => <Logo role="img" aria-label="logo" />;
// As an image source:
import logoUrl from './logo.svg';
const LogoImage = () => <img src={logoUrl} alt="Logo" />;
// As a background-image (inline style)
import logoUrl from './logo.svg';
const LogoImage = () => (
<div
style={{ backgroundImage: `url(${logoUrl})` }}
role="img"
aria-label="logo"
></div>
);
// As a background-image (external style)
// Just reference it in CSS, the loader will find it
// .logo { background-image: url('logo.svg'); }
const LogoImage = () => <div class="logo" role="img" aria-label="logo"></div>;
```
## License

1562
packages/fxa-settings/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -11,6 +11,7 @@
"@types/node": "^12.12.35",
"@types/react": "^16.9.34",
"@types/react-dom": "^16.9.6",
"modern-normalize": "^0.6.0",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "3.4.1",
@ -22,7 +23,10 @@
"stop": "pm2 stop pm2.config.js",
"build": "INLINE_RUNTIME_CHUNK=false rescripts build",
"test": "rescripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"lint": "npm-run-all --parallel lint:*",
"lint:eslint": "eslint .",
"lint:sass": "sass-lint -v"
},
"eslintConfig": {
"extends": "react-app"
@ -41,9 +45,12 @@
},
"devDependencies": {
"@rescripts/cli": "0.0.14",
"eslint-plugin-fxa": "^2.0.1",
"eslint-plugin-jest": "^23.8.1",
"eslint-plugin-react": "^7.18.3",
"pm2": "^4.2.3"
"eslint": "^6.8.0",
"eslint-plugin-fxa": "^2.0.2",
"eslint-plugin-jest": "^23.8.2",
"eslint-plugin-react": "^7.19.0",
"node-sass": "^4.14.0",
"pm2": "^4.2.3",
"sass-lint": "^1.13.1"
}
}

Просмотреть файл

@ -5,16 +5,16 @@
module.exports = {
apps: [
{
name: "settings-react",
name: 'settings-react',
cwd: __dirname,
script: "rescripts start",
max_restarts: "1",
min_uptime: "2m",
script: 'rescripts start',
max_restarts: '1',
min_uptime: '2m',
env: {
NODE_ENV: "development",
BROWSER: "NONE",
PORT: "3000"
}
}
]
NODE_ENV: 'development',
BROWSER: 'NONE',
PORT: '3000',
},
},
],
};

Двоичные данные
packages/fxa-settings/public/favicon.ico

Двоичный файл не отображается.

До

Ширина:  |  Высота:  |  Размер: 3.1 KiB

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Просмотреть файл

@ -1,19 +1,22 @@
<!DOCTYPE html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>FxA Settings</title>
<meta name="description" content="" />
<meta name="referrer" content="origin" />
<meta name="robots" content="noindex,nofollow" />
<meta
name="viewport"
content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,user-scalable=yes"
/>
</head>
<body>
<noscript>FxA Settings requires JavaScript.</noscript>
<div id="root"></div>
</body>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Firefox Accounts</title>
<meta name="description" content="" />
<meta name="referrer" content="origin" />
<meta name="robots" content="noindex,nofollow" />
<meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=2,user-scalable=yes" />
<!--iOS App Banner-->
<meta name="apple-itunes-app" content="app-id=989804926, affiliate-data=ct=smartbanner-fxa" />
</head>
<body>
<noscript>Firefox Accounts requires JavaScript.</noscript>
<div id="root"></div>
</body>
</html>

Просмотреть файл

@ -1,38 +0,0 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
}
.App-header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.App-link {
color: #61dafb;
}
@keyframes App-logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}

Просмотреть файл

@ -1,9 +0,0 @@
import React from "react";
import { render } from "@testing-library/react";
import App from "./App";
test("renders learn react link", () => {
const { getByText } = render(<App />);
const linkElement = getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

Просмотреть файл

@ -1,24 +0,0 @@
import React from "react";
import "./App.css";
function App() {
return (
<div className="App">
<header className="App-header">
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;

Просмотреть файл

@ -0,0 +1,5 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Add component-specific styles here

Просмотреть файл

@ -0,0 +1,12 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import App from '.';
it('renders', () => {
render(<App />);
});

Просмотреть файл

@ -0,0 +1,20 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import AppLayout from '../AppLayout';
import AppErrorBoundary from '@fxa-components/AppErrorBoundary';
import './index.scss';
export const App = () => {
return (
<AppErrorBoundary>
<AppLayout>
<p>Hello, world!</p>
</AppLayout>
</AppErrorBoundary>
);
};
export default App;

Просмотреть файл

@ -0,0 +1,5 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Add component-specific styles here

Просмотреть файл

@ -0,0 +1,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import { render } from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';
import AppLayout from '.';
it('renders the children', () => {
const rendered = render(
<AppLayout>
<p data-testid="test-child">Hello, world!</p>
</AppLayout>
);
expect(rendered.getByTestId('test-child')).toBeInTheDocument();
});

Просмотреть файл

@ -0,0 +1,16 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
import React from 'react';
import './index.scss';
type AppLayoutProps = {
children: React.ReactNode;
};
export const AppLayout = ({ children }: AppLayoutProps) => {
return <div>{children}</div>;
};
export default AppLayout;

Просмотреть файл

@ -1,13 +0,0 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}

Просмотреть файл

@ -0,0 +1,7 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
@import 'modern-normalize';
// Add app-wide styles here

Просмотреть файл

@ -1,11 +1,29 @@
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
import React from 'react';
import { render } from 'react-dom';
import './index.scss';
import App from './components/App';
export async function init() {
// TODO: Configure Sentry logging
// if (config.sentry.dsn) {
// sentryMetrics.configure(config.sentry.dsn, config.version);
// }
render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
}
init().then(
() => {},
error => {
console.log('Error initializing FXA Settings', error);
}
);

Просмотреть файл

@ -1 +1,5 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/// <reference types="react-scripts" />

Просмотреть файл

@ -1,5 +0,0 @@
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import "@testing-library/jest-dom/extend-expect";