mirror of
https://bitbucket.org/wisemapping/wisemapping-frontend.git
synced 2024-11-22 06:37:56 +01:00
Introduce react-query
This commit is contained in:
parent
60fd57b094
commit
fbb2b11175
@ -17,9 +17,6 @@
|
||||
"@babel/preset-env": "^7.12.7",
|
||||
"@babel/preset-react": "^7.12.7",
|
||||
"@formatjs/cli": "^2.13.15",
|
||||
"@types/react": "^17.0.0",
|
||||
"@types/react-dom": "^17.0.0",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"@typescript-eslint/eslint-plugin": "^4.8.1",
|
||||
"@typescript-eslint/parser": "^4.8.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
@ -49,14 +46,15 @@
|
||||
"@material-ui/icons": "^4.11.2",
|
||||
"@material-ui/lab": "^4.0.0-alpha.57",
|
||||
"@reduxjs/toolkit": "^1.5.0",
|
||||
"@types/axios": "^0.14.0",
|
||||
"@types/react-google-recaptcha": "^2.1.0",
|
||||
"react": "^17.0.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"axios": "^0.14.0",
|
||||
"react": "^17.0.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-google-recaptcha": "^2.1.0",
|
||||
"react-intl": "^5.10.6",
|
||||
"react-intl": "^3.0.0",
|
||||
"react-query": "^3.5.5",
|
||||
"react-redux": "^7.2.2",
|
||||
"react-router": "^5.1.8",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"styled-components": "^5.2.1"
|
||||
"styled-components": "^5.1.7"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { IntlProvider } from 'react-intl'
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { Route, Switch, Redirect, BrowserRouter as Router } from 'react-router-dom';
|
||||
|
||||
import { GlobalStyle } from './theme/global-style';
|
||||
import RegistrationSuccessPage from './components/registration-success-page';
|
||||
@ -7,14 +8,7 @@ import ForgotPasswordSuccessPage from './components/forgot-password-success-page
|
||||
import RegistationPage from './components/registration-page';
|
||||
import LoginPage from './components/login-page';
|
||||
import MapsPage from './components/maps-page';
|
||||
import store from "./store"
|
||||
|
||||
import {
|
||||
Route,
|
||||
Switch,
|
||||
Redirect,
|
||||
BrowserRouter as Router,
|
||||
} from 'react-router-dom';
|
||||
import store from "./store";
|
||||
|
||||
import { ForgotPasswordPage } from './components/forgot-password-page';
|
||||
import { Provider } from 'react-redux';
|
||||
|
@ -2,18 +2,18 @@ import React, { useEffect } from 'react'
|
||||
import { FormattedMessage, useIntl } from 'react-intl'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import {PageContent} from '../../theme/global-style';
|
||||
import { PageContent } from '../../theme/global-style';
|
||||
import FormErrorDialog from '../form-error-dialog'
|
||||
|
||||
|
||||
import Header from '../header'
|
||||
import Footer from '../footer'
|
||||
import SubmitButton from '../submit-button'
|
||||
|
||||
|
||||
|
||||
const ConfigStatusMessage = (props: any) => {
|
||||
const enabled = props.enabled
|
||||
let result = null;
|
||||
let result;
|
||||
if (enabled === true) {
|
||||
result = (<div className="db-warn-msg">
|
||||
<p>
|
||||
@ -21,7 +21,7 @@ const ConfigStatusMessage = (props: any) => {
|
||||
</p>
|
||||
</div>);
|
||||
}
|
||||
return result;
|
||||
return result ? result : null;
|
||||
}
|
||||
|
||||
const LoginError = () => {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import Button from '@material-ui/core/Button';
|
||||
import Dialog from '@material-ui/core/Dialog';
|
||||
import DialogActions from '@material-ui/core/DialogActions';
|
||||
@ -9,13 +9,11 @@ import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { ErrorInfo, MapInfo, Service } from '../../services/Service';
|
||||
import { FormControl, TextField } from '@material-ui/core';
|
||||
import { Alert, AlertTitle } from '@material-ui/lab';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useSelector } from 'react-redux';
|
||||
import {
|
||||
allMaps,
|
||||
remove,
|
||||
rename
|
||||
} from '../../reducers/mapsListSlice'
|
||||
import { Description } from '@material-ui/icons';
|
||||
activeInstance,
|
||||
} from '../../reducers/serviceSlice'
|
||||
import { useMutation, useQuery, useQueryClient } from 'react-query';
|
||||
|
||||
|
||||
type DialogProps = {
|
||||
@ -30,17 +28,32 @@ export type BasicMapInfo = {
|
||||
}
|
||||
|
||||
function DeleteDialog(props: DialogProps) {
|
||||
const dispatch = useDispatch()
|
||||
const service: Service = useSelector(activeInstance);
|
||||
const queryClient = useQueryClient();
|
||||
const mapId = props.mapId;
|
||||
|
||||
const mapInfo: MapInfo | undefined = useSelector(allMaps).
|
||||
find(m => m.id == mapId);
|
||||
const mutation = useMutation((id: number) => service.deleteMap(id),
|
||||
{
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries()
|
||||
props.onClose();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', () => {
|
||||
return service.fetchAllMaps();
|
||||
});
|
||||
|
||||
let mapInfo: MapInfo | undefined = undefined;
|
||||
if (data) {
|
||||
mapInfo = data.find((m) => m.id == mapId);
|
||||
}
|
||||
|
||||
const handleOnClose = (action: 'accept' | undefined): void => {
|
||||
if (action == 'accept' && mapInfo) {
|
||||
dispatch(remove({ id: mapId }))
|
||||
mutation.mutate(mapId);
|
||||
}
|
||||
props.onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
@ -78,22 +91,21 @@ function RenameDialog(props: DialogProps) {
|
||||
const defaultModel: RenameModel = { name: '', description: '', id: -1 };
|
||||
const [model, setModel] = React.useState<RenameModel>(defaultModel);
|
||||
const [errorInfo, setErroInfo] = React.useState<ErrorInfo>();
|
||||
const dispatch = useDispatch()
|
||||
const intl = useIntl();
|
||||
|
||||
useEffect(() => {
|
||||
const mapId: number = props.mapId;
|
||||
if (mapId != -1) {
|
||||
const mapInfo: MapInfo | undefined = useSelector(allMaps)
|
||||
.find(m => m.id == props.mapId);
|
||||
// useEffect(() => {
|
||||
// const mapId: number = props.mapId;
|
||||
// if (mapId != -1) {
|
||||
// const mapInfo: MapInfo | undefined = useSelector(activeInstance)
|
||||
// .find(m => m.id == props.mapId);
|
||||
|
||||
if (!mapInfo) {
|
||||
throw "Please, reflesh the page.";
|
||||
}
|
||||
// if (!mapInfo) {
|
||||
// throw "Please, reflesh the page.";
|
||||
// }
|
||||
|
||||
setModel({ ...mapInfo });
|
||||
}
|
||||
}, []);
|
||||
// setModel({ ...mapInfo });
|
||||
// }
|
||||
// }, []);
|
||||
|
||||
const handleOnClose = (): void => {
|
||||
// Clean Up ...
|
||||
@ -110,9 +122,9 @@ function RenameDialog(props: DialogProps) {
|
||||
// Fire rename ...
|
||||
const mapId: number = props.mapId;
|
||||
try {
|
||||
dispatch(rename({ id: mapId, name: model.name, description: model.description }))
|
||||
// dispatch(rename({ id: mapId, name: model.name, description: model.description }))
|
||||
handleOnClose();
|
||||
|
||||
|
||||
} catch (errorInfo) {
|
||||
setErroInfo(errorInfo)
|
||||
}
|
||||
|
@ -24,7 +24,11 @@ import { CSSProperties } from 'react';
|
||||
import MapActionMenu, { ActionType } from './MapActionMenu';
|
||||
import ActionDialog, { DialogType } from './ActionDialog';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { allMaps, MapInfo } from '../../reducers/mapsListSlice';
|
||||
import { activeInstance } from '../../reducers/serviceSlice';
|
||||
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
|
||||
import { ErrorInfo, MapInfo, Service } from '../../services/Service';
|
||||
|
||||
|
||||
|
||||
function descendingComparator<T>(a: T, b: T, orderBy: keyof T) {
|
||||
if (b[orderBy] < a[orderBy]) {
|
||||
@ -41,7 +45,7 @@ type Order = 'asc' | 'desc';
|
||||
function getComparator<Key extends keyof any>(
|
||||
order: Order,
|
||||
orderBy: Key,
|
||||
): (a: { [key in Key]: number | string | boolean | string[] }, b: { [key in Key]: number | string | string[] | boolean }) => number {
|
||||
): (a: { [key in Key]: number | string | boolean | string[] | undefined }, b: { [key in Key]: number | string | string[] | boolean }) => number {
|
||||
return order === 'desc'
|
||||
? (a, b) => descendingComparator(a, b, orderBy)
|
||||
: (a, b) => -descendingComparator(a, b, orderBy);
|
||||
@ -211,14 +215,22 @@ type ActionPanelState = {
|
||||
mapId: number
|
||||
}
|
||||
|
||||
function EnhancedTable() {
|
||||
const EnhancedTable = () => {
|
||||
const classes = useStyles();
|
||||
const [order, setOrder] = React.useState<Order>('asc');
|
||||
const [orderBy, setOrderBy] = React.useState<keyof MapInfo>('modified');
|
||||
const [selected, setSelected] = React.useState<number[]>([]);
|
||||
const [page, setPage] = React.useState(0);
|
||||
const [rowsPerPage, setRowsPerPage] = React.useState(5);
|
||||
const mapsInfo: MapInfo[] = useSelector(allMaps);
|
||||
const service: Service = useSelector(activeInstance);
|
||||
|
||||
const { isLoading, error, data } = useQuery<unknown, ErrorInfo, MapInfo[]>('maps', async () => {
|
||||
|
||||
const result = await service.fetchAllMaps();
|
||||
return result;
|
||||
});
|
||||
const mapsInfo: MapInfo[] = data ? data : [];
|
||||
|
||||
|
||||
const [activeRowAction, setActiveRowAction] = React.useState<ActionPanelState | undefined>(undefined);
|
||||
type ActiveDialog = {
|
||||
@ -322,7 +334,7 @@ function EnhancedTable() {
|
||||
rowCount={mapsInfo.length}
|
||||
/>
|
||||
<TableBody>
|
||||
{stableSort(mapsInfo, getComparator(order, orderBy))
|
||||
{isLoading ? (<TableRow></TableRow>) : stableSort(mapsInfo, getComparator(order, orderBy))
|
||||
.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
|
||||
.map((row: MapInfo) => {
|
||||
const isItemSelected = isSelected(row.id);
|
||||
@ -391,11 +403,14 @@ function EnhancedTable() {
|
||||
</Paper>
|
||||
|
||||
{/* Action Dialog */}
|
||||
<ActionDialog action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1}/>
|
||||
<ActionDialog action={activeDialog?.actionType} onClose={() => setActiveDialog(undefined)} mapId={activeDialog ? activeDialog.mapId : -1} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
const queryClient = new QueryClient();
|
||||
const MapsPage = () => {
|
||||
|
||||
useEffect(() => {
|
||||
@ -403,20 +418,21 @@ const MapsPage = () => {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageContainer>
|
||||
<HeaderArea>
|
||||
<h2>Header</h2>
|
||||
</HeaderArea>
|
||||
<NavArea>
|
||||
<h1> Nav </h1>
|
||||
</NavArea>
|
||||
<MapsListArea>
|
||||
<EnhancedTable/>
|
||||
</MapsListArea>
|
||||
</PageContainer>
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<PageContainer>
|
||||
<HeaderArea>
|
||||
<h2>Header</h2>
|
||||
</HeaderArea>
|
||||
<NavArea>
|
||||
<h1> Nav </h1>
|
||||
</NavArea>
|
||||
<MapsListArea>
|
||||
<EnhancedTable />
|
||||
</MapsListArea>
|
||||
</PageContainer>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default MapsPage;
|
||||
|
||||
|
||||
|
@ -1,17 +1,13 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import App from './app';
|
||||
import { BrowserRouter as Router } from 'react-router-dom';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
async function bootstrapApplication() {
|
||||
ReactDOM.render(
|
||||
<Router>
|
||||
<App/>
|
||||
</Router>,
|
||||
<App />,
|
||||
document.getElementById('root') as HTMLElement
|
||||
)
|
||||
}
|
||||
|
||||
bootstrapApplication()
|
||||
|
@ -1,113 +0,0 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import axios from 'axios';
|
||||
import { RestService, Service } from '../services/Service';
|
||||
|
||||
function createMapInfo(
|
||||
id: number,
|
||||
starred: boolean,
|
||||
name: string,
|
||||
labels: [string],
|
||||
creator: string,
|
||||
modified: number,
|
||||
description: string
|
||||
): MapInfo {
|
||||
return { id, name, labels, creator, modified, starred, description };
|
||||
}
|
||||
|
||||
const maps = [
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67, ""),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67, ""),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67, "")
|
||||
];
|
||||
|
||||
export type MapInfo = {
|
||||
id: number;
|
||||
starred: boolean;
|
||||
name: string;
|
||||
labels: [string];
|
||||
creator: string;
|
||||
modified: number;
|
||||
description: string
|
||||
}
|
||||
|
||||
interface MapsListState {
|
||||
maps: MapInfo[]
|
||||
}
|
||||
|
||||
type RutimeConfig = {
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
async function loadRuntimeConfig() {
|
||||
let result: RutimeConfig | undefined;
|
||||
|
||||
await axios.get("runtime-config.json"
|
||||
).then(response => {
|
||||
// All was ok, let's sent to success page ...
|
||||
result = response.data as RutimeConfig;
|
||||
console.log("Dynamic configuration->" + response.data);
|
||||
}).catch(e => {
|
||||
console.log(e)
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
// Ok, try to create a default configuration relative to the current path ...
|
||||
console.log("Configuration could not be loaded, falback to default config.")
|
||||
const location = window.location;
|
||||
const basePath = location.protocol + "//" + location.host + "/" + location.pathname.split('/')[1]
|
||||
|
||||
result = {
|
||||
apiBaseUrl: basePath
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
const initialState: MapsListState = { maps: maps };
|
||||
|
||||
const service: Service = new RestService("", () => { console.log("401 error") });
|
||||
|
||||
type RemovePayload = {
|
||||
id: number;
|
||||
}
|
||||
|
||||
type RenamePayload = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string | undefined;
|
||||
|
||||
}
|
||||
|
||||
export const mapsListSlice = createSlice({
|
||||
name: 'maps',
|
||||
initialState: initialState,
|
||||
reducers: {
|
||||
remove(state, action: PayloadAction<RemovePayload>) {
|
||||
const maps: MapInfo[] = state.maps as MapInfo[];
|
||||
const payload = action.payload;
|
||||
state.maps = maps.filter(map => map.id != payload.id);
|
||||
},
|
||||
rename(state, action: PayloadAction<RenamePayload>) {
|
||||
let maps: MapInfo[] = state.maps as MapInfo[];
|
||||
const payload = action.payload;
|
||||
|
||||
const mapInfo = maps.find(m => m.id == payload.id);
|
||||
if (mapInfo) {
|
||||
mapInfo.name = payload.name;
|
||||
mapInfo.description = payload.description ? payload.description: "";
|
||||
|
||||
// Remove and add the new map.
|
||||
maps = maps.filter(map => map.id != payload.id);
|
||||
maps.push(mapInfo);
|
||||
|
||||
state.maps = maps;
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const allMaps = (state: any): MapInfo[] => state.mapsList.maps;
|
||||
|
||||
export const { remove, rename } = mapsListSlice.actions
|
||||
export default mapsListSlice.reducer
|
58
packages/webapp/src/reducers/serviceSlice.ts
Normal file
58
packages/webapp/src/reducers/serviceSlice.ts
Normal file
@ -0,0 +1,58 @@
|
||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
|
||||
import axios from 'axios';
|
||||
import { ErrorInfo } from 'react';
|
||||
import { RestService, Service } from '../services/Service';
|
||||
|
||||
type RutimeConfig = {
|
||||
apiBaseUrl: string;
|
||||
}
|
||||
|
||||
async function loadRuntimeConfig() {
|
||||
let result: RutimeConfig | undefined;
|
||||
|
||||
await axios.get("runtime-config.json"
|
||||
).then(response => {
|
||||
// All was ok, let's sent to success page ...
|
||||
result = response.data as RutimeConfig;
|
||||
console.log("Dynamic configuration->" + response.data);
|
||||
}).catch(e => {
|
||||
console.log(e)
|
||||
});
|
||||
|
||||
if (!result) {
|
||||
// Ok, try to create a default configuration relative to the current path ...
|
||||
console.log("Configuration could not be loaded, falback to default config.")
|
||||
const location = window.location;
|
||||
const basePath = location.protocol + "//" + location.host + "/" + location.pathname.split('/')[1]
|
||||
|
||||
result = {
|
||||
apiBaseUrl: basePath
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
interface ServiceState {
|
||||
instance: Service
|
||||
}
|
||||
|
||||
const initialState: ServiceState = {
|
||||
instance: new RestService("", () => { console.log("401 error") })
|
||||
};
|
||||
|
||||
export const serviceSlice = createSlice({
|
||||
name: "service",
|
||||
initialState: initialState,
|
||||
reducers: {
|
||||
initialize(state, action: PayloadAction<void[]>) {
|
||||
state.instance = new RestService("", () => { console.log("401 error") });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
export const activeInstance = (state: any): Service => {
|
||||
return state.service.instance;
|
||||
}
|
||||
export default serviceSlice.reducer
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Description } from '@material-ui/icons'
|
||||
import axios from 'axios'
|
||||
|
||||
export type NewUser = {
|
||||
@ -47,11 +46,31 @@ interface Service {
|
||||
class RestService implements Service {
|
||||
private baseUrl: string;
|
||||
private authFailed: () => void
|
||||
private maps: MapInfo[] = [];
|
||||
|
||||
constructor(baseUrl: string, authFailed: () => void) {
|
||||
this.baseUrl = baseUrl;
|
||||
|
||||
// Remove, just for develop ....
|
||||
function createMapInfo(
|
||||
id: number,
|
||||
starred: boolean,
|
||||
name: string,
|
||||
labels: [string],
|
||||
creator: string,
|
||||
modified: number,
|
||||
description: string
|
||||
): MapInfo {
|
||||
return { id, name, labels, creator, modified, starred, description };
|
||||
}
|
||||
this.maps = [
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67, ""),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67, ""),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67, "")
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
loadMapInfo(id: number): Promise<BasicMapInfo> {
|
||||
return Promise.resolve({ name: 'My Map', description: 'My Description' });
|
||||
}
|
||||
@ -66,7 +85,8 @@ class RestService implements Service {
|
||||
});
|
||||
}
|
||||
|
||||
async deleteMap(id: number): Promise<void> {
|
||||
deleteMap(id: number): Promise<void> {
|
||||
this.maps = this.maps.filter(m => m.id != id);
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
@ -87,27 +107,8 @@ class RestService implements Service {
|
||||
return new Promise(handler);
|
||||
}
|
||||
|
||||
async fetchAllMaps(): Promise<MapInfo[]> {
|
||||
|
||||
function createMapInfo(
|
||||
id: number,
|
||||
starred: boolean,
|
||||
name: string,
|
||||
labels: [string],
|
||||
creator: string,
|
||||
modified: number,
|
||||
description: string
|
||||
): MapInfo {
|
||||
return { id, name, labels, creator, modified, starred, description};
|
||||
}
|
||||
|
||||
const maps = [
|
||||
createMapInfo(1, true, "El Mapa", [""], "Paulo", 67,""),
|
||||
createMapInfo(2, false, "El Mapa2", [""], "Paulo2", 67,""),
|
||||
createMapInfo(3, false, "El Mapa3", [""], "Paulo3", 67,"")
|
||||
];
|
||||
|
||||
return Promise.resolve(maps);
|
||||
fetchAllMaps(): Promise<MapInfo[]> {
|
||||
return Promise.resolve(this.maps);
|
||||
}
|
||||
|
||||
resetPassword(email: string): Promise<void> {
|
||||
|
@ -1,12 +1,12 @@
|
||||
|
||||
import { configureStore } from '@reduxjs/toolkit';
|
||||
import mapsListReducer from './reducers/mapsListSlice';
|
||||
import { configureStore, getDefaultMiddleware } from '@reduxjs/toolkit';
|
||||
import serviceReducer from './reducers/serviceSlice';
|
||||
|
||||
// Create Service object...
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
mapsList: mapsListReducer
|
||||
}
|
||||
});
|
||||
// Create Service object...
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
service: serviceReducer
|
||||
}
|
||||
});
|
||||
|
||||
export default store;
|
||||
export default store;
|
@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"jsx": "react",
|
||||
|
@ -2,7 +2,7 @@
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist/",
|
||||
"sourceMap": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitAny": false,
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"jsx": "react",
|
||||
|
Loading…
Reference in New Issue
Block a user