app,plugin/login: remove login page for now
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@spotify-backstage/core": "1.0.0",
|
||||
"@spotify-backstage/plugin-home-page": "0.0.0",
|
||||
"@spotify-backstage/plugin-login": "0.0.0",
|
||||
"@react-workspaces/react-scripts": "^3.3.0-alpha-08",
|
||||
"@testing-library/jest-dom": "^4.2.4",
|
||||
"@testing-library/react": "^9.3.2",
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import { BackstageTheme, createApp, InfoCard } from '@spotify-backstage/core';
|
||||
//import PageHeader from './components/PageHeader';
|
||||
import { LoginComponent } from '@spotify-backstage/plugin-login';
|
||||
import { BackstageTheme, createApp } from '@spotify-backstage/core';
|
||||
import { CssBaseline, makeStyles, ThemeProvider } from '@material-ui/core';
|
||||
import React, { FC } from 'react';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import * as plugins from './plugins';
|
||||
import SideBar from './components/SideBar';
|
||||
import entities from './entities';
|
||||
import { LoginBarrier } from './login/LoginBarrier';
|
||||
import { MockCurrentUser } from './login/MockCurrentUser';
|
||||
|
||||
const useStyles = makeStyles(theme => ({
|
||||
'@global': {
|
||||
@@ -36,16 +32,6 @@ const useStyles = makeStyles(theme => ({
|
||||
},
|
||||
}));
|
||||
|
||||
const currentUser = new MockCurrentUser();
|
||||
|
||||
const Login: FC<{}> = () => {
|
||||
return (
|
||||
<InfoCard title="Login Page">
|
||||
<LoginComponent onLogin={username => currentUser.login(username)} />
|
||||
</InfoCard>
|
||||
);
|
||||
};
|
||||
|
||||
const AppShell: FC<{}> = ({ children }) => {
|
||||
const classes = useStyles();
|
||||
|
||||
@@ -69,11 +55,9 @@ const App: FC<{}> = () => {
|
||||
<CssBaseline>
|
||||
<ThemeProvider theme={BackstageTheme}>
|
||||
<Router>
|
||||
<LoginBarrier fallback={Login} state$={currentUser.state}>
|
||||
<AppShell>
|
||||
<AppComponent />
|
||||
</AppShell>
|
||||
</LoginBarrier>
|
||||
<AppShell>
|
||||
<AppComponent />
|
||||
</AppShell>
|
||||
</Router>
|
||||
</ThemeProvider>
|
||||
</CssBaseline>
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
import { render, wait, act } from '@testing-library/react';
|
||||
import React from 'react';
|
||||
import Observable from 'zen-observable';
|
||||
import { LoginBarrier } from './LoginBarrier';
|
||||
import { LoginState } from './types';
|
||||
|
||||
describe('LoginBarrier', () => {
|
||||
it('passes through when logged in', async () => {
|
||||
const state$ = Observable.of<LoginState>({
|
||||
type: 'LOGGED_IN',
|
||||
user: 'apa',
|
||||
});
|
||||
const rendered = render(
|
||||
<LoginBarrier
|
||||
state$={state$}
|
||||
fallback={({ state }) => <div>{state.type}</div>}
|
||||
>
|
||||
Logged in!
|
||||
</LoginBarrier>,
|
||||
);
|
||||
await wait(() => rendered.getByText('Logged in!'));
|
||||
});
|
||||
|
||||
it('goes to fallback when not logged in', async () => {
|
||||
const state$ = Observable.of<LoginState>({ type: 'LOGGED_OUT' });
|
||||
const rendered = render(
|
||||
<LoginBarrier
|
||||
state$={state$}
|
||||
fallback={({ state }) => <div>{state.type}</div>}
|
||||
>
|
||||
Logged in!
|
||||
</LoginBarrier>,
|
||||
);
|
||||
await wait(() => rendered.getByText('LOGGED_OUT'));
|
||||
});
|
||||
|
||||
it('transitions between states', async () => {
|
||||
let subscriber: ZenObservable.SubscriptionObserver<LoginState> | undefined;
|
||||
const state$ = new Observable<LoginState>(s => {
|
||||
subscriber = s;
|
||||
});
|
||||
|
||||
const rendered = render(
|
||||
<LoginBarrier
|
||||
state$={state$}
|
||||
fallback={({ state }) => <div>{state.type}</div>}
|
||||
>
|
||||
Logged in!
|
||||
</LoginBarrier>,
|
||||
);
|
||||
|
||||
await wait(() => rendered.getByText('LOGGED_OUT'));
|
||||
// @ts-ignore: Object is possibly 'undefined'
|
||||
act(() => subscriber.next({ type: 'LOGGED_IN', user: 'apa' }));
|
||||
await wait(() => rendered.getByText('Logged in!'));
|
||||
});
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
import React, { FC } from 'react';
|
||||
import Observable from 'zen-observable';
|
||||
import { useObservable } from 'react-use';
|
||||
import { LoginState } from './types';
|
||||
|
||||
type LoginBarrierProps = {
|
||||
fallback: React.ComponentType<{ state: LoginState }>;
|
||||
state$: Observable<LoginState>;
|
||||
};
|
||||
|
||||
export const LoginBarrier: FC<LoginBarrierProps> = ({
|
||||
fallback: Fallback,
|
||||
state$,
|
||||
children,
|
||||
}) => {
|
||||
const state = useObservable(state$, { type: 'LOGGED_OUT' });
|
||||
if (state.type === 'LOGGED_IN') {
|
||||
return <>{children}</>;
|
||||
} else {
|
||||
return <Fallback state={state} />;
|
||||
}
|
||||
};
|
||||
@@ -1,38 +0,0 @@
|
||||
import { MockCurrentUser } from './MockCurrentUser';
|
||||
import { wait } from '@testing-library/react';
|
||||
|
||||
describe('MockCurrentUser', () => {
|
||||
it('notifies immediately on subscribe', async () => {
|
||||
const next = jest.fn();
|
||||
const current = new MockCurrentUser();
|
||||
current.state.subscribe(next);
|
||||
await wait();
|
||||
expect(next).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ type: 'LOGGED_OUT' }),
|
||||
);
|
||||
});
|
||||
|
||||
it('logs in and out', async () => {
|
||||
const next = jest.fn();
|
||||
const current = new MockCurrentUser();
|
||||
current.state.subscribe(next);
|
||||
await wait();
|
||||
expect(next).toHaveBeenNthCalledWith(
|
||||
1,
|
||||
expect.objectContaining({ type: 'LOGGED_OUT' }),
|
||||
);
|
||||
current.login('apa');
|
||||
await wait();
|
||||
expect(next).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
expect.objectContaining({ type: 'LOGGED_IN', user: 'apa' }),
|
||||
);
|
||||
current.logout();
|
||||
await wait();
|
||||
expect(next).toHaveBeenNthCalledWith(
|
||||
3,
|
||||
expect.objectContaining({ type: 'LOGGED_OUT' }),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,67 +0,0 @@
|
||||
import Observable from 'zen-observable';
|
||||
import { LoginState } from './types';
|
||||
|
||||
const LOCAL_STORAGE_KEY = 'mock_current_user';
|
||||
|
||||
export class MockCurrentUser {
|
||||
private listeners: ZenObservable.SubscriptionObserver<LoginState>[];
|
||||
private currentUser: string | undefined;
|
||||
|
||||
constructor() {
|
||||
this.listeners = [];
|
||||
this.currentUser = undefined;
|
||||
this.loadPrevious();
|
||||
}
|
||||
|
||||
login(user: string) {
|
||||
this.currentUser = user;
|
||||
this.saveCurrent();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
logout() {
|
||||
this.currentUser = undefined;
|
||||
this.saveCurrent();
|
||||
this.notify();
|
||||
}
|
||||
|
||||
get state(): Observable<LoginState> {
|
||||
return new Observable(subscriber => {
|
||||
this.listeners.push(subscriber);
|
||||
subscriber.next(this.getState());
|
||||
return () => {
|
||||
this.listeners = this.listeners.filter(x => x !== subscriber);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private loadPrevious() {
|
||||
const user = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (user) {
|
||||
try {
|
||||
this.currentUser = JSON.parse(user);
|
||||
} catch (e) {
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private saveCurrent() {
|
||||
if (!this.currentUser) {
|
||||
localStorage.removeItem(LOCAL_STORAGE_KEY);
|
||||
} else {
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(this.currentUser));
|
||||
}
|
||||
}
|
||||
|
||||
private notify() {
|
||||
const state = this.getState();
|
||||
this.listeners.forEach(listener => listener.next(state));
|
||||
}
|
||||
|
||||
private getState(): LoginState {
|
||||
return this.currentUser
|
||||
? { type: 'LOGGED_IN', user: this.currentUser }
|
||||
: { type: 'LOGGED_OUT' };
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
export type LoggedOutState = { type: 'LOGGED_OUT' };
|
||||
export type LoggingInState = { type: 'LOGGING_IN' };
|
||||
export type LoggedInState = { type: 'LOGGED_IN'; user: string };
|
||||
export type LoggingOutState = { type: 'LOGGING_OUT' };
|
||||
export type LoginFailedState = { type: 'LOGIN_FAILED'; error: Error };
|
||||
export type LoginState =
|
||||
| LoggedOutState
|
||||
| LoggingInState
|
||||
| LoggedInState
|
||||
| LoggingOutState
|
||||
| LoginFailedState;
|
||||
@@ -1 +0,0 @@
|
||||
Welcome to your login-page plugin!
|
||||
@@ -1,4 +0,0 @@
|
||||
module.exports = {
|
||||
...require('@spotify/web-scripts/config/jest.config.js'),
|
||||
setupFilesAfterEnv: ['../jest.setup.ts'],
|
||||
};
|
||||
@@ -1 +0,0 @@
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
@@ -1,27 +0,0 @@
|
||||
{
|
||||
"name": "@spotify-backstage/plugin-login",
|
||||
"version": "0.0.0",
|
||||
"main": "dist/cjs",
|
||||
"devDependencies": {
|
||||
"@spotify-backstage/cli": "^1.2.0",
|
||||
"@spotify-backstage/core": "1.0.0",
|
||||
"@spotify/web-scripts": "^6.0.0",
|
||||
"@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": "^16.9.0",
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"@material-ui/core": "^4.9.1",
|
||||
"@material-ui/icons": "^4.9.1"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc --outDir dist/cjs --noEmit false --module CommonJS",
|
||||
"lint": "web-scripts lint",
|
||||
"test": "web-scripts test"
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import LoginComponent from './LoginComponent';
|
||||
|
||||
describe('LoginComponent', () => {
|
||||
it('should render', () => {
|
||||
const onLogin = jest.fn();
|
||||
const rendered = render(<LoginComponent onLogin={onLogin} />);
|
||||
expect(rendered.getByText('Login')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@@ -1,67 +0,0 @@
|
||||
import React, { FC, useState } from 'react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import TextField from '@material-ui/core/TextField';
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import { Typography } from '@material-ui/core';
|
||||
|
||||
type Props = {
|
||||
onLogin: (username: string) => Promise<void> | void;
|
||||
};
|
||||
|
||||
const LoginComponent: FC<Props> = ({ onLogin }) => {
|
||||
const [error, setError] = useState('');
|
||||
const [username, setUsername] = useState('');
|
||||
|
||||
const onUsernameChanged = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setUsername(e.target.value);
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (!username) {
|
||||
setError('You have to supply a username');
|
||||
}
|
||||
|
||||
setError('');
|
||||
try {
|
||||
await onLogin(username);
|
||||
} catch (e) {
|
||||
setError(`Login failed: ${e.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={onSubmit} autoComplete="off">
|
||||
<Grid container spacing={8} alignItems="flex-end">
|
||||
<Grid item md={true} sm={true} xs={true}>
|
||||
<TextField
|
||||
id="username"
|
||||
label="Username"
|
||||
type="email"
|
||||
autoFocus
|
||||
required
|
||||
value={username}
|
||||
onChange={onUsernameChanged}
|
||||
/>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
container
|
||||
justify="flex-start"
|
||||
style={{ marginTop: '24px', marginBottom: '24px' }}
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
color="primary"
|
||||
onClick={onSubmit}
|
||||
disabled={!username}
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
</Grid>
|
||||
<Typography>{error || 'Use your github username'}</Typography>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default LoginComponent;
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './LoginComponent';
|
||||
@@ -1,2 +0,0 @@
|
||||
export { default } from './plugin';
|
||||
export { default as LoginComponent } from './components/LoginComponent';
|
||||
@@ -1,7 +0,0 @@
|
||||
import plugin from './plugin';
|
||||
|
||||
describe('login', () => {
|
||||
it('should export plugin', () => {
|
||||
expect(plugin).toBeDefined();
|
||||
});
|
||||
});
|
||||
@@ -1,5 +0,0 @@
|
||||
import { createPlugin } from '@spotify-backstage/core';
|
||||
|
||||
export default createPlugin({
|
||||
id: 'login',
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"include": ["src"]
|
||||
}
|
||||
+1
-12
@@ -2308,17 +2308,6 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
|
||||
"@material-ui/lab@4.0.0-alpha.45":
|
||||
version "4.0.0-alpha.45"
|
||||
resolved "https://registry.npmjs.org/@material-ui/lab/-/lab-4.0.0-alpha.45.tgz#6e1abbdd6e44b9ef7b3eff8ef892a3da5dc52f10"
|
||||
integrity sha512-zT6kUU87SHsPukiu3tlWg8V6o0tGS38c1b/xst/kPqX6eLbfqrROyxhHn1A8ZtHmqga1AKQdv/1llQoG80Afww==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@material-ui/utils" "^4.7.1"
|
||||
clsx "^1.0.4"
|
||||
prop-types "^15.7.2"
|
||||
react-is "^16.8.0"
|
||||
|
||||
"@material-ui/styles@^4.9.0":
|
||||
version "4.9.0"
|
||||
resolved "https://registry.npmjs.org/@material-ui/styles/-/styles-4.9.0.tgz#10c31859f6868cfa9d3adf6b6c3e32c9d676bc76"
|
||||
@@ -5068,7 +5057,7 @@ clone@^1.0.2:
|
||||
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e"
|
||||
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
|
||||
|
||||
clsx@^1.0.2, clsx@^1.0.4:
|
||||
clsx@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.0.tgz#62937c6adfea771247c34b54d320fb99624f5702"
|
||||
integrity sha512-3avwM37fSK5oP6M5rQ9CNe99lwxhXDOeSWVPAOYF6OazUTgZCMb0yWlJpmdD74REy1gkEaFiub2ULv4fq9GUhA==
|
||||
|
||||
Reference in New Issue
Block a user