feat: 添加鉴权相关逻辑。
This commit is contained in:
parent
3644718b19
commit
4e493f79d1
@ -3,20 +3,23 @@ import { FC } from "react";
|
||||
import { Login } from "./login";
|
||||
|
||||
export interface AuthContext {
|
||||
accessToken: string | undefined;
|
||||
accessToken: string | null;
|
||||
setAccessToken: (token: string) => void;
|
||||
setRefreshToken: (token: string) => void;
|
||||
refreshToken: string | undefined;
|
||||
login: (dto: any) => void;
|
||||
account?: any;
|
||||
setAccount: (dto: any) => void;
|
||||
logout: () => void;
|
||||
}
|
||||
const Context = createContext({} as AuthContext);
|
||||
|
||||
export const useAuth = () => useContext(Context);
|
||||
|
||||
export const AuthProvider: FC = ({ children }) => {
|
||||
const [accessToken, setAccessToken] = useState<string>();
|
||||
const [accessToken, setAccessToken] = useState<string | null>(
|
||||
localStorage.getItem("accessToken")
|
||||
);
|
||||
const [refreshToken, setRefreshToken] = useState<string>();
|
||||
const [account, setAccount] = useState<any>();
|
||||
|
||||
@ -24,6 +27,12 @@ export const AuthProvider: FC = ({ children }) => {
|
||||
setAccessToken(dto.accessToken);
|
||||
setRefreshToken(dto.refreshToken);
|
||||
setAccount(dto.account);
|
||||
localStorage.setItem("accessToken", dto.accessToken);
|
||||
};
|
||||
const logout = () => {
|
||||
setAccessToken(null);
|
||||
setRefreshToken(undefined);
|
||||
setAccount(undefined);
|
||||
};
|
||||
|
||||
return (
|
||||
@ -36,6 +45,7 @@ export const AuthProvider: FC = ({ children }) => {
|
||||
login,
|
||||
account,
|
||||
setAccount,
|
||||
logout,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { makeStyles } from "@material-ui/core";
|
||||
import { FC, useEffect, useRef } from "react";
|
||||
import { FC, Fragment, useEffect, useRef } from "react";
|
||||
import { useAuth } from "./auth.provider";
|
||||
const useStyles = makeStyles({
|
||||
const useStyles = makeStyles((theme) => ({
|
||||
iframe: {
|
||||
height: "300px",
|
||||
width: "500px",
|
||||
@ -9,8 +9,20 @@ const useStyles = makeStyles({
|
||||
top: "100px",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
zIndex: theme.zIndex.modal,
|
||||
border: "none",
|
||||
boxShadow: theme.shadows[4],
|
||||
},
|
||||
});
|
||||
mask: {
|
||||
top: "0",
|
||||
left: "0",
|
||||
bottom: "0",
|
||||
right: "0",
|
||||
position: "absolute",
|
||||
backgroundColor: "rgba(0, 0, 0, 0.3)",
|
||||
zIndex: theme.zIndex.modal,
|
||||
},
|
||||
}));
|
||||
|
||||
export const Login: FC = () => {
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
@ -41,11 +53,14 @@ export const Login: FC = () => {
|
||||
|
||||
const classes = useStyles();
|
||||
return (
|
||||
<Fragment>
|
||||
<div className={classes.mask} />
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
className={classes.iframe}
|
||||
title="Auth"
|
||||
src="https://user.rpi.ivanli.cc/auth/login"
|
||||
></iframe>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
@ -5,6 +5,8 @@ import {
|
||||
InMemoryCache,
|
||||
split,
|
||||
ApolloProvider,
|
||||
fromPromise,
|
||||
FetchResult,
|
||||
} from "@apollo/client";
|
||||
import { withScalars } from "apollo-link-scalars";
|
||||
import { buildClientSchema, IntrospectionQuery } from "graphql";
|
||||
@ -13,9 +15,16 @@ import { FC } from "react";
|
||||
import introspectionResult from "../../generated/graphql.schema.json";
|
||||
import { onError } from "@apollo/client/link/error";
|
||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||
import { getMainDefinition } from "@apollo/client/utilities";
|
||||
import { getMainDefinition, Observable } from "@apollo/client/utilities";
|
||||
import { useSnackbar } from "notistack";
|
||||
import { deepOmit } from "../../utils/deep-omit";
|
||||
import { useMemo } from "react";
|
||||
import { EventEmitter } from "events";
|
||||
import { useState } from "react";
|
||||
import { useAuth } from "../auth/auth.provider";
|
||||
import { useEffect } from "react";
|
||||
import { useRef } from "react";
|
||||
import { setContext } from "@apollo/client/link/context";
|
||||
|
||||
const schema = buildClientSchema(
|
||||
introspectionResult as unknown as IntrospectionQuery
|
||||
@ -37,8 +46,73 @@ const cleanTypeName = new ApolloLink((operation, forward) => {
|
||||
);
|
||||
});
|
||||
|
||||
export const FennecApolloClientProvider: FC = ({ children }) => {
|
||||
export const AppApolloClientProvider: FC = ({ children }) => {
|
||||
const { enqueueSnackbar } = useSnackbar();
|
||||
const { accessToken, logout } = useAuth();
|
||||
|
||||
const [loggedEventTarget] = useState(() => new EventEmitter());
|
||||
const accessTokenRef = useRef(accessToken);
|
||||
const logoutRef = useRef(logout);
|
||||
|
||||
useEffect(() => {
|
||||
accessTokenRef.current = accessToken;
|
||||
if (accessToken) {
|
||||
loggedEventTarget.emit("logged", accessToken);
|
||||
}
|
||||
}, [loggedEventTarget, accessToken]);
|
||||
useEffect(() => {
|
||||
logoutRef.current = logout;
|
||||
}, [logout]);
|
||||
const client = useMemo(() => {
|
||||
const authLink = onError(
|
||||
({ graphQLErrors, networkError, operation, forward }) => {
|
||||
if (graphQLErrors) {
|
||||
for (const error of graphQLErrors) {
|
||||
if (error.extensions?.code === "401") {
|
||||
return fromPromise(
|
||||
new Promise<Observable<FetchResult>>((resolve) => {
|
||||
loggedEventTarget.once("logged", (accessToken: string) => {
|
||||
const oldHeaders = operation.getContext().headers;
|
||||
operation.setContext({
|
||||
headers: {
|
||||
...oldHeaders,
|
||||
authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
resolve(forward(operation));
|
||||
});
|
||||
logoutRef.current();
|
||||
})
|
||||
).flatMap((v) => v);
|
||||
}
|
||||
}
|
||||
}
|
||||
const httpResult = (networkError as any)?.result;
|
||||
if (httpResult?.statusCode === 401) {
|
||||
return fromPromise(
|
||||
new Promise<Observable<FetchResult>>((resolve) => {
|
||||
loggedEventTarget.once("logged", (accessToken: string) => {
|
||||
const oldHeaders = operation.getContext().headers;
|
||||
operation.setContext({
|
||||
headers: {
|
||||
...oldHeaders,
|
||||
authorization: `Bearer ${accessToken}`,
|
||||
},
|
||||
});
|
||||
resolve(forward(operation));
|
||||
});
|
||||
logoutRef.current();
|
||||
})
|
||||
).flatMap((v) => v);
|
||||
}
|
||||
}
|
||||
).concat(
|
||||
setContext(() => ({
|
||||
headers: {
|
||||
authorization: `Bearer ${accessTokenRef.current}`,
|
||||
},
|
||||
}))
|
||||
);
|
||||
const errorLink = onError(({ graphQLErrors, networkError }) => {
|
||||
if (graphQLErrors) {
|
||||
graphQLErrors.forEach((error) => {
|
||||
@ -65,6 +139,11 @@ export const FennecApolloClientProvider: FC = ({ children }) => {
|
||||
}:${window.location.port}/api/graphql`,
|
||||
options: {
|
||||
reconnect: true,
|
||||
connectionParams: {
|
||||
headers: {
|
||||
authorization: `Bearer ${accessTokenRef.current} `,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
const httpLink = new HttpLink({
|
||||
@ -83,6 +162,7 @@ export const FennecApolloClientProvider: FC = ({ children }) => {
|
||||
);
|
||||
const link = ApolloLink.from([
|
||||
errorLink,
|
||||
authLink,
|
||||
withScalars({ schema, typesMap }) as unknown as ApolloLink,
|
||||
cleanTypeName,
|
||||
splitLink,
|
||||
@ -92,22 +172,12 @@ export const FennecApolloClientProvider: FC = ({ children }) => {
|
||||
ssrMode: typeof window === "undefined",
|
||||
link,
|
||||
cache: new InMemoryCache({
|
||||
typePolicies: {
|
||||
// PipelineTaskLogs: {
|
||||
// keyFields: ["unit"],
|
||||
// },
|
||||
// PipelineTask: {
|
||||
// fields: {
|
||||
// logs: {
|
||||
// merge(existing = [], incoming: any[]) {
|
||||
// return [...existing, ...incoming];
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
},
|
||||
typePolicies: {},
|
||||
}),
|
||||
});
|
||||
|
||||
return client;
|
||||
}, [enqueueSnackbar, loggedEventTarget]);
|
||||
|
||||
return <ApolloProvider client={client}>{children}</ApolloProvider>;
|
||||
};
|
||||
|
@ -1,11 +1,8 @@
|
||||
import { gql } from '@apollo/client';
|
||||
export type Maybe<T> = T | null;
|
||||
export type Exact<T extends { [key: string]: unknown }> = {
|
||||
[K in keyof T]: T[K];
|
||||
};
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> &
|
||||
{ [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> &
|
||||
{ [SubKey in K]: Maybe<T[SubKey]> };
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
ID: string;
|
||||
@ -18,165 +15,174 @@ export type Scalars = {
|
||||
};
|
||||
|
||||
export type Commit = {
|
||||
__typename?: "Commit";
|
||||
hash: Scalars["String"];
|
||||
date: Scalars["DateTime"];
|
||||
message: Scalars["String"];
|
||||
refs: Scalars["String"];
|
||||
body: Scalars["String"];
|
||||
author_name: Scalars["String"];
|
||||
author_email: Scalars["String"];
|
||||
__typename?: 'Commit';
|
||||
hash: Scalars['String'];
|
||||
date: Scalars['DateTime'];
|
||||
message: Scalars['String'];
|
||||
refs: Scalars['String'];
|
||||
body: Scalars['String'];
|
||||
author_name: Scalars['String'];
|
||||
author_email: Scalars['String'];
|
||||
tasks: Array<PipelineTask>;
|
||||
};
|
||||
|
||||
export type CreatePipelineInput = {
|
||||
projectId: Scalars["String"];
|
||||
branch: Scalars["String"];
|
||||
name: Scalars["String"];
|
||||
projectId: Scalars['String'];
|
||||
branch: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
workUnitMetadata: WorkUnitMetadataInput;
|
||||
};
|
||||
|
||||
export type CreatePipelineTaskInput = {
|
||||
pipelineId: Scalars["String"];
|
||||
commit: Scalars["String"];
|
||||
pipelineId: Scalars['String'];
|
||||
commit: Scalars['String'];
|
||||
units: Array<PipelineUnits>;
|
||||
};
|
||||
|
||||
export type CreateProjectInput = {
|
||||
name: Scalars["String"];
|
||||
comment: Scalars["String"];
|
||||
sshUrl: Scalars["String"];
|
||||
webUrl?: Maybe<Scalars["String"]>;
|
||||
webHookSecret?: Maybe<Scalars["String"]>;
|
||||
name: Scalars['String'];
|
||||
comment: Scalars['String'];
|
||||
sshUrl: Scalars['String'];
|
||||
webUrl?: Maybe<Scalars['String']>;
|
||||
webHookSecret?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
|
||||
export type Hello = {
|
||||
__typename?: "Hello";
|
||||
message: Scalars["String"];
|
||||
__typename?: 'Hello';
|
||||
message: Scalars['String'];
|
||||
};
|
||||
|
||||
export type LogFields = {
|
||||
__typename?: "LogFields";
|
||||
hash: Scalars["String"];
|
||||
date: Scalars["String"];
|
||||
message: Scalars["String"];
|
||||
refs: Scalars["String"];
|
||||
body: Scalars["String"];
|
||||
author_name: Scalars["String"];
|
||||
author_email: Scalars["String"];
|
||||
__typename?: 'LogFields';
|
||||
hash: Scalars['String'];
|
||||
date: Scalars['String'];
|
||||
message: Scalars['String'];
|
||||
refs: Scalars['String'];
|
||||
body: Scalars['String'];
|
||||
author_name: Scalars['String'];
|
||||
author_email: Scalars['String'];
|
||||
tasks: Array<PipelineTask>;
|
||||
};
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: "Mutation";
|
||||
__typename?: 'Mutation';
|
||||
createProject: Project;
|
||||
updateProject: Project;
|
||||
removeProject: Scalars["Float"];
|
||||
removeProject: Scalars['Float'];
|
||||
createPipeline: Pipeline;
|
||||
updatePipeline: Pipeline;
|
||||
deletePipeline: Scalars["Float"];
|
||||
deletePipeline: Scalars['Float'];
|
||||
createPipelineTask: PipelineTask;
|
||||
stopPipelineTask: Scalars["Boolean"];
|
||||
stopPipelineTask: Scalars['Boolean'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateProjectArgs = {
|
||||
project: CreateProjectInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdateProjectArgs = {
|
||||
project: UpdateProjectInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRemoveProjectArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreatePipelineArgs = {
|
||||
pipeline: CreatePipelineInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationUpdatePipelineArgs = {
|
||||
pipeline: UpdatePipelineInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationDeletePipelineArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreatePipelineTaskArgs = {
|
||||
task: CreatePipelineTaskInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationStopPipelineTaskArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Pipeline = {
|
||||
__typename?: "Pipeline";
|
||||
id: Scalars["ID"];
|
||||
__typename?: 'Pipeline';
|
||||
id: Scalars['ID'];
|
||||
project: Project;
|
||||
projectId: Scalars["String"];
|
||||
branch: Scalars["String"];
|
||||
name: Scalars["String"];
|
||||
projectId: Scalars['String'];
|
||||
branch: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
workUnitMetadata: WorkUnitMetadata;
|
||||
};
|
||||
|
||||
export type PipelineTask = {
|
||||
__typename?: "PipelineTask";
|
||||
id: Scalars["ID"];
|
||||
__typename?: 'PipelineTask';
|
||||
id: Scalars['ID'];
|
||||
pipeline: Pipeline;
|
||||
pipelineId: Scalars["String"];
|
||||
commit: Scalars["String"];
|
||||
pipelineId: Scalars['String'];
|
||||
commit: Scalars['String'];
|
||||
units: Array<PipelineUnits>;
|
||||
logs: Array<PipelineTaskLogs>;
|
||||
status: TaskStatuses;
|
||||
startedAt?: Maybe<Scalars["DateTime"]>;
|
||||
endedAt?: Maybe<Scalars["DateTime"]>;
|
||||
runOn: Scalars["String"];
|
||||
startedAt?: Maybe<Scalars['DateTime']>;
|
||||
endedAt?: Maybe<Scalars['DateTime']>;
|
||||
runOn: Scalars['String'];
|
||||
};
|
||||
|
||||
export type PipelineTaskEvent = {
|
||||
__typename?: "PipelineTaskEvent";
|
||||
taskId: Scalars["String"];
|
||||
pipelineId: Scalars["String"];
|
||||
projectId: Scalars["String"];
|
||||
__typename?: 'PipelineTaskEvent';
|
||||
taskId: Scalars['String'];
|
||||
pipelineId: Scalars['String'];
|
||||
projectId: Scalars['String'];
|
||||
unit?: Maybe<PipelineUnits>;
|
||||
emittedAt: Scalars["DateTime"];
|
||||
message: Scalars["String"];
|
||||
messageType: Scalars["String"];
|
||||
emittedAt: Scalars['DateTime'];
|
||||
message: Scalars['String'];
|
||||
messageType: Scalars['String'];
|
||||
status: TaskStatuses;
|
||||
};
|
||||
|
||||
export type PipelineTaskLogs = {
|
||||
__typename?: "PipelineTaskLogs";
|
||||
__typename?: 'PipelineTaskLogs';
|
||||
unit: PipelineUnits;
|
||||
status: TaskStatuses;
|
||||
startedAt?: Maybe<Scalars["DateTime"]>;
|
||||
endedAt?: Maybe<Scalars["DateTime"]>;
|
||||
logs: Scalars["String"];
|
||||
startedAt?: Maybe<Scalars['DateTime']>;
|
||||
endedAt?: Maybe<Scalars['DateTime']>;
|
||||
logs: Scalars['String'];
|
||||
};
|
||||
|
||||
/** 流水线单元 */
|
||||
export enum PipelineUnits {
|
||||
Checkout = "checkout",
|
||||
InstallDependencies = "installDependencies",
|
||||
Test = "test",
|
||||
Deploy = "deploy",
|
||||
CleanUp = "cleanUp",
|
||||
Checkout = 'checkout',
|
||||
InstallDependencies = 'installDependencies',
|
||||
Test = 'test',
|
||||
Deploy = 'deploy',
|
||||
CleanUp = 'cleanUp'
|
||||
}
|
||||
|
||||
export type Project = {
|
||||
__typename?: "Project";
|
||||
id: Scalars["ID"];
|
||||
name: Scalars["String"];
|
||||
comment: Scalars["String"];
|
||||
sshUrl: Scalars["String"];
|
||||
webUrl?: Maybe<Scalars["String"]>;
|
||||
webHookSecret?: Maybe<Scalars["String"]>;
|
||||
__typename?: 'Project';
|
||||
id: Scalars['ID'];
|
||||
name: Scalars['String'];
|
||||
comment: Scalars['String'];
|
||||
sshUrl: Scalars['String'];
|
||||
webUrl?: Maybe<Scalars['String']>;
|
||||
webHookSecret?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: "Query";
|
||||
__typename?: 'Query';
|
||||
hello: Hello;
|
||||
projects: Array<Project>;
|
||||
project: Project;
|
||||
@ -187,92 +193,101 @@ export type Query = {
|
||||
pipelineTask: PipelineTask;
|
||||
};
|
||||
|
||||
|
||||
export type QueryProjectArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryPipelinesArgs = {
|
||||
projectId?: Maybe<Scalars["String"]>;
|
||||
projectId?: Maybe<Scalars['String']>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryPipelineArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryCommitsArgs = {
|
||||
pipelineId: Scalars["String"];
|
||||
pipelineId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryListPipelineTaskByPipelineIdArgs = {
|
||||
pipelineId: Scalars["String"];
|
||||
pipelineId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type QueryPipelineTaskArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
export type Subscription = {
|
||||
__typename?: "Subscription";
|
||||
syncCommits?: Maybe<Scalars["String"]>;
|
||||
__typename?: 'Subscription';
|
||||
syncCommits?: Maybe<Scalars['String']>;
|
||||
pipelineTaskEvent: PipelineTaskEvent;
|
||||
pipelineTaskChanged: PipelineTask;
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionSyncCommitsArgs = {
|
||||
appInstance?: Maybe<Scalars["String"]>;
|
||||
pipelineId: Scalars["String"];
|
||||
appInstance?: Maybe<Scalars['String']>;
|
||||
pipelineId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionPipelineTaskEventArgs = {
|
||||
taskId: Scalars["String"];
|
||||
taskId: Scalars['String'];
|
||||
};
|
||||
|
||||
|
||||
export type SubscriptionPipelineTaskChangedArgs = {
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
/** 任务状态 */
|
||||
export enum TaskStatuses {
|
||||
Success = "success",
|
||||
Failed = "failed",
|
||||
Working = "working",
|
||||
Pending = "pending",
|
||||
Success = 'success',
|
||||
Failed = 'failed',
|
||||
Working = 'working',
|
||||
Pending = 'pending'
|
||||
}
|
||||
|
||||
export type UpdatePipelineInput = {
|
||||
branch: Scalars["String"];
|
||||
name: Scalars["String"];
|
||||
branch: Scalars['String'];
|
||||
name: Scalars['String'];
|
||||
workUnitMetadata: WorkUnitMetadataInput;
|
||||
id: Scalars["String"];
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
export type UpdateProjectInput = {
|
||||
name: Scalars["String"];
|
||||
comment: Scalars["String"];
|
||||
sshUrl: Scalars["String"];
|
||||
webUrl?: Maybe<Scalars["String"]>;
|
||||
webHookSecret?: Maybe<Scalars["String"]>;
|
||||
id: Scalars["String"];
|
||||
name: Scalars['String'];
|
||||
comment: Scalars['String'];
|
||||
sshUrl: Scalars['String'];
|
||||
webUrl?: Maybe<Scalars['String']>;
|
||||
webHookSecret?: Maybe<Scalars['String']>;
|
||||
id: Scalars['String'];
|
||||
};
|
||||
|
||||
export type WorkUnit = {
|
||||
__typename?: "WorkUnit";
|
||||
__typename?: 'WorkUnit';
|
||||
type: PipelineUnits;
|
||||
scripts: Array<Scalars["String"]>;
|
||||
scripts: Array<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type WorkUnitInput = {
|
||||
type: PipelineUnits;
|
||||
scripts: Array<Scalars["String"]>;
|
||||
scripts: Array<Scalars['String']>;
|
||||
};
|
||||
|
||||
export type WorkUnitMetadata = {
|
||||
__typename?: "WorkUnitMetadata";
|
||||
version: Scalars["Int"];
|
||||
__typename?: 'WorkUnitMetadata';
|
||||
version: Scalars['Int'];
|
||||
units: Array<WorkUnit>;
|
||||
};
|
||||
|
||||
export type WorkUnitMetadataInput = {
|
||||
version?: Maybe<Scalars["Int"]>;
|
||||
version?: Maybe<Scalars['Int']>;
|
||||
units: Array<WorkUnitInput>;
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ import "./index.css";
|
||||
import "fontsource-roboto";
|
||||
import App from "./App";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
import { FennecApolloClientProvider } from "./commons/graphql/client";
|
||||
import { AppApolloClientProvider } from "./commons/graphql/client";
|
||||
import { MuiPickersUtilsProvider } from "@material-ui/pickers";
|
||||
import DateFnsUtils from "@date-io/date-fns";
|
||||
import zhLocale from "date-fns/locale/zh-CN";
|
||||
@ -17,15 +17,15 @@ ReactDOM.render(
|
||||
<React.StrictMode>
|
||||
<ConfirmProvider>
|
||||
<SnackbarProvider maxSnack={5}>
|
||||
<FennecApolloClientProvider>
|
||||
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={zhLocale}>
|
||||
<AuthProvider>
|
||||
<AppApolloClientProvider>
|
||||
<MuiPickersUtilsProvider utils={DateFnsUtils} locale={zhLocale}>
|
||||
<Router>
|
||||
<App />
|
||||
</Router>
|
||||
</AuthProvider>
|
||||
</MuiPickersUtilsProvider>
|
||||
</FennecApolloClientProvider>
|
||||
</AppApolloClientProvider>
|
||||
</AuthProvider>
|
||||
</SnackbarProvider>
|
||||
</ConfirmProvider>
|
||||
</React.StrictMode>,
|
||||
|
Loading…
Reference in New Issue
Block a user