Skip to content

Commit

Permalink
Merge branch 'main' into feat-server/implement-geo-field-line-string
Browse files Browse the repository at this point in the history
  • Loading branch information
nourbalaha authored Jun 25, 2024
2 parents 5ce028c + 319782b commit fdc5de9
Show file tree
Hide file tree
Showing 9 changed files with 215 additions and 109 deletions.
32 changes: 20 additions & 12 deletions web/e2e/settings/integrations.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
import { closeNotification } from "@reearth-cms/e2e/common/notification";
import { expect, test } from "@reearth-cms/e2e/utils";

let id: string;

test.beforeEach(() => {
id = Math.ceil(Math.random() * (100000 - 10000) + 10000).toString();
});

test.afterEach(async ({ page }) => {
await page.getByText("My Integrations").click();
await page.getByText("e2e integration namee2e").first().click();
await page.getByText(id).first().click();
await page.getByRole("button", { name: "Remove Integration" }).click();
await page.getByRole("button", { name: "OK" }).click();
});
Expand All @@ -18,23 +24,22 @@ test("Integration CRUD and searching has succeeded", async ({ reearth, page }) =
.nth(1)
.click();
await page.getByLabel("Integration Name").click();
await page.getByLabel("Integration Name").fill("e2e integration name");
await page.getByLabel("Integration Name").fill(id);
await page.getByLabel("Description").click();
await page.getByLabel("Description").fill("e2e integration description");
await page.getByRole("button", { name: "Create" }).click();
await closeNotification(page);
await page.getByText("Integrations", { exact: true }).click();
await page.getByRole("button", { name: "api Connect Integration" }).first().click();
await page
.locator("div")
.filter({ hasText: /^e2e integration name$/ })
.first()
.click();
await page.getByText(id, { exact: true }).first().click();
await page.getByRole("button", { name: "Connect", exact: true }).click();
await closeNotification(page);
await expect(page.getByRole("cell", { name: "e2e integration name", exact: true })).toBeVisible();
await expect(page.getByRole("cell", { name: id, exact: true })).toBeVisible();
await page.getByRole("button", { name: "api Connect Integration" }).first().click();
await expect(page.getByRole("dialog").getByText(id, { exact: true })).toBeHidden();
await page.getByRole("button", { name: "Cancel", exact: true }).click();
await page.getByPlaceholder("input search text").click();
await page.getByPlaceholder("input search text").fill("e2e integration name");
await page.getByPlaceholder("input search text").fill(id);
await page.getByRole("button", { name: "search" }).click();
await page.getByRole("cell", { name: "setting" }).locator("svg").click();
await page
Expand All @@ -49,12 +54,15 @@ test("Integration CRUD and searching has succeeded", async ({ reearth, page }) =
await page.getByPlaceholder("input search text").click();
await page.getByPlaceholder("input search text").fill("no integration");
await page.getByRole("button", { name: "search" }).click();
await expect(page.getByRole("cell", { name: "e2e integration name", exact: true })).toBeHidden();
await expect(page.getByRole("cell", { name: id, exact: true })).toBeHidden();
await page.getByPlaceholder("input search text").click();
await page.getByPlaceholder("input search text").fill("e2e integration name");
await page.getByPlaceholder("input search text").fill(id);
await page.getByRole("button", { name: "search" }).click();
await expect(page.getByRole("cell", { name: "e2e integration name", exact: true })).toBeVisible();
await expect(page.getByRole("cell", { name: id, exact: true })).toBeVisible();
await page.getByLabel("", { exact: true }).check();
await page.getByText("Remove").click();
await closeNotification(page);
await page.getByRole("button", { name: "api Connect Integration" }).first().click();
await expect(page.getByRole("dialog").getByText(id, { exact: true })).toBeVisible();
await page.getByRole("button", { name: "Cancel", exact: true }).click();
});
54 changes: 26 additions & 28 deletions web/src/components/molecules/Member/MemberAddModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ interface FormValues {

interface Props {
open: boolean;
searchedUser?: User;
searchedUser?: User & { isMember: boolean };
searchedUserList: User[];
onUserSearch: (nameOrEmail: string) => void;
onUserSearch: (nameOrEmail: string) => Promise<void>;
onUserAdd: () => void;
onClose: () => void;
onSubmit: (users: MemberInput[]) => Promise<void>;
changeSearchedUser: (user: User | undefined) => void;
changeSearchedUser: (user?: User & { isMember: boolean }) => void;
changeSearchedUserList: React.Dispatch<React.SetStateAction<User[]>>;
}

Expand Down Expand Up @@ -116,7 +116,7 @@ const MemberAddModal: React.FC<Props> = ({
{open && (
<Form title="Search user" form={form} layout="vertical" initialValues={initialValues}>
<Form.Item name="name" label={t("Email address or user name")}>
<Search size="large" onSearch={handleMemberNameChange} type="text" />
<Search size="large" onSearch={handleMemberNameChange} type="text" allowClear />
</Form.Item>
{searchedUser && (
<SearchedUserResult>
Expand All @@ -125,42 +125,40 @@ const MemberAddModal: React.FC<Props> = ({
</SearchedUserAvatar>
<SearchedUserName>{searchedUser.name}</SearchedUserName>
<SearchedUserEmail>{searchedUser.email}</SearchedUserEmail>
<IconButton onClick={onUserAdd}>
<Icon icon="userAdd" />
</IconButton>
<Button
type="text"
shape="circle"
onClick={onUserAdd}
icon={<Icon icon="userAdd" />}
disabled={searchedUser.isMember}
/>
</SearchedUserResult>
)}
<StyledFormItem
name="names"
label={`${t("Selected Members")} (${searchedUserList.length})`}>
{searchedUserList &&
searchedUserList.length > 0 &&
searchedUserList
.filter(user => Boolean(user))
.map(user => (
<SearchedUserResult key={user.id}>
<SearchedUserAvatar>
<UserAvatar username={user.name} />
</SearchedUserAvatar>
<SearchedUserName>{user.name}</SearchedUserName>
<SearchedUserEmail>{user.email}</SearchedUserEmail>
<IconButton onClick={() => handleMemberRemove(user.id)}>
<Icon icon="close" />
</IconButton>
</SearchedUserResult>
))}
{searchedUserList.map(user => (
<SearchedUserResult key={user.id}>
<SearchedUserAvatar>
<UserAvatar username={user.name} />
</SearchedUserAvatar>
<SearchedUserName>{user.name}</SearchedUserName>
<SearchedUserEmail>{user.email}</SearchedUserEmail>
<Button
type="text"
shape="circle"
onClick={() => handleMemberRemove(user.id)}
icon={<Icon icon="close" />}
/>
</SearchedUserResult>
))}
</StyledFormItem>
</Form>
)}
</Modal>
);
};

const IconButton = styled.button`
all: unset;
cursor: pointer;
`;

const StyledFormItem = styled(Form.Item)`
margin-top: 16px;
`;
Expand Down
61 changes: 32 additions & 29 deletions web/src/components/organisms/Settings/Integration/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@ import { Key, useCallback, useMemo, useState } from "react";
import Notification from "@reearth-cms/components/atoms/Notification";
import { IntegrationMember, Role } from "@reearth-cms/components/molecules/Integration/types";
import { Integration } from "@reearth-cms/components/molecules/MyIntegrations/types";
import { fromGraphQLIntegration } from "@reearth-cms/components/organisms/DataConverters/setting";
import {
fromGraphQLIntegration,
fromGraphQLWorkspace,
} from "@reearth-cms/components/organisms/DataConverters/setting";
import {
useGetMeQuery,
useAddIntegrationToWorkspaceMutation,
Role as GQLRole,
useUpdateIntegrationOfWorkspaceMutation,
useRemoveIntegrationFromWorkspaceMutation,
Workspace as GQLWorkspace,
} from "@reearth-cms/gql/graphql-client-api";
import { useT } from "@reearth-cms/i18n";

Expand All @@ -29,34 +33,33 @@ export default (workspaceId?: string) => {
});
const t = useT();

const workspaces = useMemo(() => data?.me?.workspaces, [data?.me?.workspaces]);
const workspace = workspaces?.find(workspace => workspace.id === workspaceId);

const integrations = useMemo(() => {
return data?.me?.integrations
?.map(integration => fromGraphQLIntegration(integration))
.filter((integration): integration is Integration => !!integration);
}, [data?.me?.integrations]);

const workspaceIntegrationMembers = useMemo(() => {
return workspace?.members
?.map<IntegrationMember | undefined>(member =>
member && member.__typename === "WorkspaceIntegrationMember" && member.integration
? {
id: member.integration.id,
active: member.active,
integration: fromGraphQLIntegration(member.integration),
integrationRole: member.integrationRole,
invitedById: member.invitedById,
}
: undefined,
)
.filter(
(integrationMember): integrationMember is IntegrationMember =>
!!integrationMember?.integration &&
integrationMember.integration.name.toLowerCase().includes(searchTerm ?? ""),
);
}, [workspace, searchTerm]);
const workspace = useMemo(() => {
const foundWorkspace = data?.me?.workspaces?.find(workspace => workspace.id === workspaceId);
return foundWorkspace && fromGraphQLWorkspace(foundWorkspace as GQLWorkspace);
}, [data?.me?.workspaces]);

const workspaceIntegrationMembers = useMemo(
() =>
workspace?.members?.filter(
(member): member is IntegrationMember =>
"integration" in member &&
!!member.integration?.name.toLowerCase().includes(searchTerm ?? ""),
),
[workspace?.members, searchTerm],
);

const integrations = useMemo(
() =>
data?.me?.integrations
?.map(integration => fromGraphQLIntegration(integration))
.filter(
integration =>
!workspaceIntegrationMembers?.some(
workspaceIntegration => workspaceIntegration.id === integration.id,
),
),
[data?.me?.integrations, workspaceIntegrationMembers],
);

const handleIntegrationConnectModalClose = useCallback(() => {
setIntegrationConnectModalShown(false);
Expand Down
36 changes: 19 additions & 17 deletions web/src/components/organisms/Settings/Members/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default () => {
setPage(1);
}, []);

const [searchedUser, changeSearchedUser] = useState<User>();
const [searchedUser, changeSearchedUser] = useState<User & { isMember: boolean }>();
const [searchedUserList, changeSearchedUserList] = useState<User[]>([]);

const { data, refetch, loading } = useGetWorkspacesQuery({
Expand Down Expand Up @@ -70,25 +70,10 @@ export default () => {
setWorkspace(workspaces?.find(workspace => workspace.id === workspaceId));
}, [setWorkspace, workspaces, data?.me, workspaceId]);

const [searchUserQuery, { data: searchUserData }] = useGetUserBySearchLazyQuery({
const [searchUserQuery] = useGetUserBySearchLazyQuery({
fetchPolicy: "no-cache",
});

useEffect(() => {
changeSearchedUser(
searchUserData?.searchUser && searchUserData?.searchUser?.id !== data?.me?.id
? searchUserData.searchUser
: undefined,
);
}, [searchUserData?.searchUser, data?.me?.id]);

const handleUserSearch = useCallback(
(nameOrEmail: string) => {
if (nameOrEmail) searchUserQuery({ variables: { nameOrEmail } });
},
[searchUserQuery],
);

const handleUserAdd = useCallback(() => {
if (
searchedUser &&
Expand Down Expand Up @@ -117,6 +102,23 @@ export default () => {
.sort((user1, user2) => stringSortCallback(user1.userId, user2.userId));
}, [currentWorkspace, searchTerm]);

const handleUserSearch = useCallback(
async (nameOrEmail: string) => {
if (nameOrEmail) {
const res = await searchUserQuery({ variables: { nameOrEmail } });
if (res.data?.searchUser && res.data.searchUser?.id !== data?.me?.id) {
const isMember = !!workspaceUserMembers?.some(
member => member.userId === res.data?.searchUser?.id,
);
changeSearchedUser({ ...res.data?.searchUser, isMember });
} else {
changeSearchedUser(undefined);
}
}
},
[searchUserQuery, workspaceUserMembers],
);

const [addUsersToWorkspaceMutation] = useAddUsersToWorkspaceMutation();

const handleUsersAddToWorkspace = useCallback(
Expand Down
1 change: 1 addition & 0 deletions web/src/gql/fragmentMatcher.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"SchemaFieldGroup",
"SchemaFieldInteger",
"SchemaFieldMarkdown",
"SchemaFieldPoint",
"SchemaFieldReference",
"SchemaFieldRichText",
"SchemaFieldSelect",
Expand Down
3 changes: 2 additions & 1 deletion web/src/gql/fragments/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ export const workspaceFragment = gql`
role
}
... on WorkspaceIntegrationMember {
integrationId
integration {
...integrationFragment
}
integrationRole: role
role
active
invitedBy {
id
Expand Down
Loading

0 comments on commit fdc5de9

Please sign in to comment.