Skip to content

Commit

Permalink
chore(web): refactor graphQL and set new standard (#536)
Browse files Browse the repository at this point in the history
Co-authored-by: KaWaite <34051327+KaWaite@users.noreply.github.com>
  • Loading branch information
pyshx and KaWaite committed Jul 10, 2023
1 parent dd1b396 commit a002e67
Show file tree
Hide file tree
Showing 37 changed files with 1,515 additions and 21,155 deletions.
2 changes: 1 addition & 1 deletion web/.eslintignore
Expand Up @@ -4,5 +4,5 @@
/storybook-static
!/.storybook
/.storybook/public
/src/services/gql/graphql-client-api.tsx
/src/classic/gql/graphql-client-api.tsx
/src/services/gql/__gen__
79 changes: 79 additions & 0 deletions web/codegen.ts
@@ -0,0 +1,79 @@
import { CodegenConfig } from "@graphql-codegen/cli";

const rootGQLDirectory = "src/services/gql/";

const rootGenerateDirectory = `${rootGQLDirectory}__gen__/`;

const config: CodegenConfig = {
overwrite: true,
schema: "../server/gql/*.graphql",
documents: [`${rootGQLDirectory}fragments/*.ts`, `${rootGQLDirectory}queries/*.ts`],
generates: {
[rootGenerateDirectory]: {
preset: "client",
presetConfig: {
gqlTagName: "gql",
fragmentMasking: false,
},
config: {
useTypeImports: true,
scalars: {
DateTime: "Date",
FileSize: "number",
ID: "string",
Cursor: "string",
URL: "string",
Lang: "string",
TranslatedString: "{ [lang in string]?: string } | null",
},
},
},
[`${rootGenerateDirectory}/fragmentMatcher.json`]: {
plugins: ["fragment-matcher"],
},
},
ignoreNoDocuments: true,
};

export default config;

// CLASSIC CONFIG

// import { CodegenConfig } from "@graphql-codegen/cli";

// const config: CodegenConfig = {
// overwrite: true,
// schema: "../server/gql/*.graphql",
// documents: [
// "src/services/gql/fragments/*.ts",
// "src/services/gql/queries/*.ts",
// "src/services/**/*.graphql",
// ],
// generates: {
// "./src/services/gql/graphql-client-api.tsx": {
// plugins: ["typescript", "typescript-operations", "typescript-react-apollo"],
// config: {
// useTypeImports: true,
// scalars: {
// DateTime: "Date",
// FileSize: "number",
// ID: "string",
// Cursor: "string",
// URL: "string",
// Lang: "string",
// TranslatedString: "{ [lang in string]?: string } | null",
// },
// },
// },
// "./src/services/gql/graphql.schema.json": {
// plugins: ["introspection"],
// },
// "./src/services/gql/fragmentMatcher.json": {
// plugins: ["fragment-matcher"],
// },
// },
// };

// export default config;

// CLASSIC CONFIG
30 changes: 0 additions & 30 deletions web/codegen.yml

This file was deleted.

7 changes: 2 additions & 5 deletions web/package.json
Expand Up @@ -20,7 +20,7 @@
"format": "eslint --fix .",
"storybook": "storybook dev -p 9001",
"storybook:build": "storybook build --quiet -o dist/storybook",
"gql": "graphql-codegen --config codegen.yml",
"gql": "graphql-codegen",
"i18n": "i18next",
"gen:doc:plugin": "ts-node -O '{\"module\":\"CommonJS\"}' ./bin/pluginDoc"
},
Expand All @@ -33,11 +33,8 @@
"devDependencies": {
"@emotion/jest": "11.11.0",
"@graphql-codegen/cli": "3.3.1",
"@graphql-codegen/client-preset": "4.0.1",
"@graphql-codegen/fragment-matcher": "4.0.1",
"@graphql-codegen/introspection": "3.0.1",
"@graphql-codegen/typescript": "3.0.4",
"@graphql-codegen/typescript-operations": "3.0.4",
"@graphql-codegen/typescript-react-apollo": "3.3.7",
"@playwright/test": "1.33.0",
"@rollup/plugin-yaml": "4.1.0",
"@storybook/addon-essentials": "7.0.18",
Expand Down
3 changes: 3 additions & 0 deletions web/src/beta/components/Dropdown/index.tsx
Expand Up @@ -7,6 +7,7 @@ import { styled } from "@reearth/services/theme";
type Direction = "right" | "down" | "none";

export type Props = {
className?: string;
isOpen?: boolean;
label: ReactNode;
openOnClick?: boolean;
Expand All @@ -23,6 +24,7 @@ export type Ref = {

const Dropdown: React.ForwardRefRenderFunction<Ref, Props> = (
{
className,
isOpen = false,
openOnClick,
noHoverStyle,
Expand Down Expand Up @@ -51,6 +53,7 @@ const Dropdown: React.ForwardRefRenderFunction<Ref, Props> = (

return (
<Wrapper
className={className}
ref={wrapperRef}
onMouseEnter={openOnClick ? undefined : () => setOpen(true)}
onMouseLeave={openOnClick ? undefined : () => setOpen(false)}>
Expand Down
8 changes: 6 additions & 2 deletions web/src/beta/features/Navbar/Menus/WorkspaceMenu/index.tsx
Expand Up @@ -40,7 +40,7 @@ const WorkspaceMenu: React.FC<Props> = ({
const theme = useTheme();

return (
<Dropdown label={label} direction="right" hasIcon>
<StyledDropdown label={label} direction="right" hasIcon>
<DropdownInner>
<MenuList>
{workspaces.map(workspace => (
Expand Down Expand Up @@ -76,10 +76,14 @@ const WorkspaceMenu: React.FC<Props> = ({
</MenuListItem>
</MenuList>
</DropdownInner>
</Dropdown>
</StyledDropdown>
);
};

const StyledDropdown = styled(Dropdown)`
flex: 1;
`;

const DropdownInner = styled.div`
padding: 0;
max-width: 230px;
Expand Down
70 changes: 22 additions & 48 deletions web/src/beta/features/Navbar/hooks.ts
@@ -1,16 +1,11 @@
import { useApolloClient } from "@apollo/client";
import { useMemo, useCallback, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

import { useWorkspaceFetcher, useMeFetcher, useProjectFetcher } from "@reearth/services/api";
import { useAuth } from "@reearth/services/auth";
import { useCreateWorkspaceMutation, GetMeQuery, GetProjectQuery } from "@reearth/services/gql";
import { GET_PROJECT } from "@reearth/services/gql/queries/project";
import { GET_ME } from "@reearth/services/gql/queries/user";
import { useProject, useWorkspace } from "@reearth/services/state";
import { Workspace, useProject, useWorkspace } from "@reearth/services/state";

export default ({ projectId, workspaceId }: { projectId?: string; workspaceId?: string }) => {
const gqlClient = useApolloClient();

const navigate = useNavigate();
const { logout: handleLogout } = useAuth();

Expand All @@ -19,44 +14,26 @@ export default ({ projectId, workspaceId }: { projectId?: string; workspaceId?:

const [workspaceModalVisible, setWorkspaceModalVisible] = useState(false);

const workspaceData: GetMeQuery | null = gqlClient.readQuery({ query: GET_ME }); // todo: use custom readQuery from other PR
const { useProjectQuery } = useProjectFetcher();
const { useWorkspaceQuery, useWorkspacesQuery, useCreateWorkspace } = useWorkspaceFetcher();
const { useMeQuery } = useMeFetcher();

const workspaces = useMemo(
() => workspaceData?.me?.teams?.map(({ id, name }) => ({ id, name })),
[workspaceData?.me?.teams],
);
const { workspaces } = useWorkspacesQuery();
const { workspace } = useWorkspaceQuery(workspaceId);

const projectData: GetProjectQuery | null = gqlClient.readQuery({
query: GET_PROJECT,
variables: { projectId },
}); // todo: use custom readQuery from other PR

const project = useMemo(
() =>
projectData?.node?.__typename === "Project"
? { ...projectData.node, sceneId: projectData.node.scene?.id }
: undefined,
[projectData?.node],
);
const { project } = useProjectQuery(projectId);
const {
me: { name, myTeam },
} = useMeQuery();

const workspace = useMemo(
() => workspaceData?.me?.teams?.find(w => w.id === workspaceId),
[workspaceData?.me?.teams, workspaceId],
);
const personal = useMemo(() => workspaceId === myTeam?.id, [workspaceId, myTeam?.id]);

useEffect(() => {
if (!currentWorkspace || (workspace && workspace.id !== currentWorkspace?.id)) {
setCurrentWorkspace(workspace);
}
});

const username = useMemo(() => workspaceData?.me?.name || "", [workspaceData?.me]);

const personal = useMemo(
() => workspaceId === workspaceData?.me?.myTeam.id,
[workspaceId, workspaceData?.me],
);

const handleWorkspaceModalOpen = useCallback(() => setWorkspaceModalVisible(true), []);
const handleWorkspaceModalClose = useCallback(() => setWorkspaceModalVisible(false), []);

Expand All @@ -67,7 +44,7 @@ export default ({ projectId, workspaceId }: { projectId?: string; workspaceId?:
? {
id: project.id,
name: project.name,
sceneId: project.sceneId,
sceneId: project.scene?.id,
projectType: project.coreSupport ? "beta" : "classic",
}
: undefined
Expand All @@ -86,28 +63,25 @@ export default ({ projectId, workspaceId }: { projectId?: string; workspaceId?:
[workspaces, workspaceId, setCurrentWorkspace, navigate],
);

const [createWorkspaceMutation] = useCreateWorkspaceMutation();

const handleWorkspaceCreate = useCallback(
async (data: { name: string }) => {
const results = await createWorkspaceMutation({
variables: { name: data.name },
refetchQueries: ["GetTeams"],
});
if (results.data?.createTeam) {
setCurrentWorkspace(results.data.createTeam.team);

navigate(`/dashboard/${results.data.createTeam.team.id}`);
const results = await useCreateWorkspace(data.name);
const newWorkspace = results.data as Workspace; // Only needed for setting current workspace. Can remove after jotai use ends.

if (results.status === "success") {
setCurrentWorkspace(newWorkspace);

navigate(`/dashboard/${newWorkspace.id}`);
}
},
[createWorkspaceMutation, setCurrentWorkspace, navigate],
[useCreateWorkspace, setCurrentWorkspace, navigate],
);

return {
workspaces,
currentProject,
isPersonal: personal,
username,
username: name,
workspace,
workspaceModalVisible,
handleWorkspaceModalOpen,
Expand Down
30 changes: 12 additions & 18 deletions web/src/beta/pages/Page.tsx
@@ -1,8 +1,8 @@
import React, { ReactElement, ReactNode, useMemo } from "react";

import GlobalModal from "@reearth/classic/components/organisms/GlobalModal"; // todo: migrate to beta
import { useMeFetcher, useProjectFetcher, useSceneFetcher } from "@reearth/services/api";
import { AuthenticationRequiredPage } from "@reearth/services/auth";
import { useGetMeQuery, useGetProjectQuery, useGetSceneQuery } from "@reearth/services/gql";
import { useTheme } from "@reearth/services/theme";

import Loading from "../components/Loading";
Expand All @@ -17,31 +17,25 @@ type Props = {
const PageWrapper: React.FC<Props> = ({ sceneId, projectId, workspaceId, children }) => {
const theme = useTheme();

const { loading: loadingMe } = useGetMeQuery();
const { useMeQuery } = useMeFetcher();
const { useProjectQuery } = useProjectFetcher();
const { useSceneQuery } = useSceneFetcher();

const { data: sceneData, loading: loadingScene } = useGetSceneQuery({
variables: { sceneId: sceneId ?? "" },
skip: !sceneId,
});
const { loading: loadingMe } = useMeQuery();

const { scene, loading: loadingScene } = useSceneQuery(sceneId);

const currentProjectId = useMemo(
() =>
projectId ?? (sceneData?.node?.__typename === "Scene" ? sceneData.node.projectId : undefined),
[projectId, sceneData?.node],
() => projectId ?? scene?.projectId,
[projectId, scene?.projectId],
);

const currentWorkspaceId = useMemo(
() =>
workspaceId ?? (sceneData?.node?.__typename === "Scene" ? sceneData.node.teamId : undefined),
[workspaceId, sceneData?.node],
() => workspaceId ?? scene?.teamId,
[workspaceId, scene?.teamId],
);

const { loading: loadingProject } = useGetProjectQuery({
variables: {
projectId: currentProjectId ?? "",
},
skip: !currentProjectId,
});
const { loading: loadingProject } = useProjectQuery(currentProjectId);

const childrenWithProps = React.Children.map(children, child => {
return React.cloneElement(child as ReactElement<Props>, {
Expand Down
Expand Up @@ -6,7 +6,7 @@ import {
Maybe,
PropertyFragmentFragment,
ValueType,
} from "@reearth/services/gql";
} from "@reearth/classic/gql";

import {
processLayer,
Expand Down
4 changes: 4 additions & 0 deletions web/src/services/api/index.ts
@@ -0,0 +1,4 @@
export { default as useProjectFetcher } from "./projectApi";
export { default as useMeFetcher } from "./meApi";
export { default as useSceneFetcher } from "./sceneApi";
export { default as useWorkspaceFetcher } from "./workspacesApi";
18 changes: 18 additions & 0 deletions web/src/services/api/meApi.ts
@@ -0,0 +1,18 @@
import { useQuery } from "@apollo/client";
import { useCallback } from "react";

import { GET_ME } from "@reearth/services/gql/queries/user";

export default () => {
const useMeQuery = useCallback((options?: { skip?: boolean }) => {
const { data, ...rest } = useQuery(GET_ME, { ...options });
return {
me: { ...data?.me },
...rest,
};
}, []);

return {
useMeQuery,
};
};

0 comments on commit a002e67

Please sign in to comment.