Create app namespace for all absolute requires of app modules. Move all packages under packages yarn workspace

This commit is contained in:
SleepWalker
2019-12-07 21:02:00 +02:00
parent d8d2df0702
commit f9d3bb4e20
404 changed files with 758 additions and 742 deletions

View File

@@ -0,0 +1,91 @@
import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
import { connect } from 'react-redux';
import {
fetchAvailableApps,
resetApp,
deleteApp,
} from 'app/components/dev/apps/actions';
import ApplicationsIndex from 'app/components/dev/apps/ApplicationsIndex';
import { User } from 'app/components/user';
import { OauthAppResponse } from 'app/services/api/oauth';
import { RootState } from 'app/reducers';
interface Props extends RouteComponentProps {
user: User;
apps: OauthAppResponse[];
fetchAvailableApps: () => Promise<void>;
deleteApp: (clientId: string) => Promise<void>;
resetApp: (clientId: string, resetClientSecret: boolean) => Promise<void>;
}
type State = {
isLoading: boolean;
forceUpdate: boolean;
};
class ApplicationsListPage extends React.Component<Props, State> {
state = {
isLoading: false,
forceUpdate: false,
};
componentDidMount() {
!this.props.user.isGuest && this.loadApplicationsList();
}
componentDidUpdate({ user }: Props) {
if (this.props.user !== user) {
// eslint-disable-next-line react/no-did-update-set-state
this.setState({ forceUpdate: true });
this.loadApplicationsList();
}
}
render() {
const { user, apps, resetApp, deleteApp, location } = this.props;
const { isLoading, forceUpdate } = this.state;
const clientId = location.hash.substr(1) || null;
return (
<ApplicationsIndex
displayForGuest={user.isGuest}
applications={forceUpdate ? [] : apps}
isLoading={isLoading}
deleteApp={deleteApp}
resetApp={resetApp}
clientId={clientId}
resetClientId={this.resetClientId}
/>
);
}
loadApplicationsList = async () => {
this.setState({ isLoading: true });
await this.props.fetchAvailableApps();
this.setState({
isLoading: false,
forceUpdate: false,
});
};
resetClientId = () => {
const { history, location } = this.props;
if (location.hash) {
history.push({ ...location, hash: '' });
}
};
}
export default connect(
(state: RootState) => ({
user: state.user,
apps: state.apps.available,
}),
{
fetchAvailableApps,
resetApp,
deleteApp,
},
)(ApplicationsListPage);

View File

@@ -0,0 +1,69 @@
import React, { Component } from 'react';
import { FormModel } from 'app/components/ui/form';
import ApplicationForm from 'app/components/dev/apps/applicationForm/ApplicationForm';
import oauth from 'app/services/api/oauth';
import { browserHistory } from 'app/services/history';
import { OauthAppResponse } from 'app/services/api/oauth';
import { ApplicationType } from 'app/components/dev/apps';
const app: OauthAppResponse = {
clientId: '',
clientSecret: '',
countUsers: 0,
createdAt: 0,
type: 'application',
name: '',
description: '',
websiteUrl: '',
redirectUri: '',
minecraftServerIp: '',
};
interface State {
type: ApplicationType | null;
}
export default class CreateNewApplicationPage extends Component<{}, State> {
state: State = {
type: null,
};
form: FormModel = new FormModel();
render() {
return (
<ApplicationForm
form={this.form}
displayTypeSwitcher
onSubmit={this.onSubmit}
type={this.state.type}
setType={this.setType}
app={app}
/>
);
}
onSubmit = async () => {
const { form } = this;
const { type } = this.state;
if (!type) {
throw new Error('Form was submitted without specified type');
}
form.beginLoading();
const result = await oauth.create(type, form.serialize());
form.endLoading();
this.goToMainPage(result.data.clientId);
};
setType = (type: ApplicationType) => {
this.setState({
type,
});
};
goToMainPage = (hash?: string) =>
browserHistory.push(`/dev/applications${hash ? `#${hash}` : ''}`);
}

View File

@@ -0,0 +1,39 @@
import React from 'react';
import { Redirect, Route, Switch } from 'react-router-dom';
import { FooterMenu } from 'app/components/footerMenu';
import PrivateRoute from 'app/containers/PrivateRoute';
import styles from './dev.scss';
import ApplicationsListPage from './ApplicationsListPage';
import CreateNewApplicationPage from './CreateNewApplicationPage';
import UpdateApplicationPage from './UpdateApplicationPage';
export default function DevPage() {
return (
<div className={styles.container}>
<div data-e2e-content>
<Switch>
<Route
path="/dev/applications"
exact
component={ApplicationsListPage}
/>
<PrivateRoute
path="/dev/applications/new"
exact
component={CreateNewApplicationPage}
/>
<PrivateRoute
path="/dev/applications/:clientId"
component={UpdateApplicationPage}
/>
<Redirect to="/dev/applications" />
</Switch>
</div>
<div className={styles.footer}>
<FooterMenu />
</div>
</div>
);
}

View File

@@ -0,0 +1,120 @@
import React from 'react';
import { connect } from 'react-redux';
import logger from 'app/services/logger';
import { RouteComponentProps } from 'react-router';
import { FormModel } from 'app/components/ui/form';
import { browserHistory } from 'app/services/history';
import oauth from 'app/services/api/oauth';
import loader from 'app/services/loader';
import PageNotFound from 'app/pages/404/PageNotFound';
import {
getApp,
fetchApp as fetchAppAction,
} from 'app/components/dev/apps/actions';
import ApplicationForm from 'app/components/dev/apps/applicationForm/ApplicationForm';
import { OauthAppResponse } from 'app/services/api/oauth';
import { RootState } from 'app/reducers';
type OwnProps = RouteComponentProps<{
clientId: string;
}>;
interface Props extends OwnProps {
app: OauthAppResponse | null;
fetchApp: (app: string) => Promise<void>;
}
class UpdateApplicationPage extends React.Component<
Props,
{
isNotFound: boolean;
}
> {
form: FormModel = new FormModel();
state = {
isNotFound: false,
};
componentDidMount() {
this.props.app === null && this.fetchApp();
}
render() {
const { app } = this.props;
if (this.state.isNotFound) {
return <PageNotFound />;
}
if (!app) {
// we are loading
return null;
}
return (
<ApplicationForm
form={this.form}
onSubmit={this.onSubmit}
app={app}
type={app.type}
/>
);
}
async fetchApp() {
const { fetchApp, match } = this.props;
try {
loader.show();
await fetchApp(match.params.clientId);
} catch (resp) {
const { status } = resp.originalResponse;
if (status === 403) {
this.goToMainPage();
return;
}
if (status === 404) {
this.setState({
isNotFound: true,
});
return;
}
logger.unexpected('Error fetching app', resp);
} finally {
loader.hide();
}
}
onSubmit = async () => {
const { form } = this;
const { app } = this.props;
if (!app || !app.clientId) {
throw new Error('Form has an invalid state');
}
form.beginLoading();
const result = await oauth.update(app.clientId, form.serialize());
form.endLoading();
this.goToMainPage(result.data.clientId);
};
goToMainPage = (hash?: string) =>
browserHistory.push(`/dev/applications${hash ? `#${hash}` : ''}`);
}
export default connect(
(state: RootState, props: OwnProps) => ({
app: getApp(state, props.match.params.clientId),
}),
{
fetchApp: fetchAppAction,
},
)(UpdateApplicationPage);

View File

@@ -0,0 +1,18 @@
.container {
padding: 55px 0 65px;
}
.footer {
width: 100%;
position: absolute;
bottom: 10px;
left: 0;
text-align: center;
}
@media (max-width: 720px) {
.container {
padding-top: 20px;
}
}