Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): implement regenerate integration token functionality #1157

Merged
merged 8 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Props = {
webhookInitialValues?: any;
onIntegrationUpdate: (data: { name: string; description: string; logoUrl: string }) => void;
onIntegrationDelete: () => Promise<void>;
onRegenerateToken: () => Promise<void>;
onWebhookCreate: (data: {
name: string;
url: string;
Expand All @@ -38,6 +39,7 @@ const MyIntegrationContent: React.FC<Props> = ({
integration,
webhookInitialValues,
onIntegrationUpdate,
onRegenerateToken,
onWebhookCreate,
onWebhookDelete,
onWebhookUpdate,
Expand All @@ -56,6 +58,7 @@ const MyIntegrationContent: React.FC<Props> = ({
integration={integration}
onIntegrationUpdate={onIntegrationUpdate}
onIntegrationDelete={onIntegrationDelete}
onRegenerateToken={onRegenerateToken}
/>
</TabPane>
<TabPane tab="Webhook" key="webhooks">
Expand Down
35 changes: 33 additions & 2 deletions web/src/components/molecules/MyIntegrations/Settings/Form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Col from "@reearth-cms/components/atoms/Col";
import Divider from "@reearth-cms/components/atoms/Divider";
import Form from "@reearth-cms/components/atoms/Form";
import Input from "@reearth-cms/components/atoms/Input";
import Modal from "@reearth-cms/components/atoms/Modal";
import Row from "@reearth-cms/components/atoms/Row";
import TextArea from "@reearth-cms/components/atoms/TextArea";
import { Integration } from "@reearth-cms/components/molecules/MyIntegrations/types";
Expand All @@ -14,9 +15,14 @@ import { useT } from "@reearth-cms/i18n";
export type Props = {
integration: Integration;
onIntegrationUpdate: (data: { name: string; description: string; logoUrl: string }) => void;
onRegenerateToken: () => Promise<void>;
};

const MyIntegrationForm: React.FC<Props> = ({ integration, onIntegrationUpdate }) => {
const MyIntegrationForm: React.FC<Props> = ({
integration,
onIntegrationUpdate,
onRegenerateToken,
}) => {
const t = useT();
const [form] = Form.useForm();

Expand All @@ -30,6 +36,19 @@ const MyIntegrationForm: React.FC<Props> = ({ integration, onIntegrationUpdate }
}
}, [form, onIntegrationUpdate]);

const handleRegenerateToken = useCallback(() => {
Modal.confirm({
title: t("Regenerate The Integration Token?"),
content: t(
"If you regenerate the integration token, the previous token will become invalid, and this action cannot be undone. Are you sure you want to proceed?",
),
okText: t("Reset"),
onOk() {
onRegenerateToken();
},
});
}, [t, onRegenerateToken]);

return (
<Form form={form} layout="vertical" initialValues={integration}>
<Row gutter={32}>
Expand All @@ -49,7 +68,10 @@ const MyIntegrationForm: React.FC<Props> = ({ integration, onIntegrationUpdate }
<TextArea rows={3} showCount maxLength={100} />
</Form.Item>
<Form.Item label={t("Integration Token")}>
<Input.Password value={integration.config.token} contentEditable={false} />
<StyledTokenInput value={integration.config.token} contentEditable={false} />
<StyledRegenerateTokenButton type="primary" onClick={handleRegenerateToken}>
{t("Regenerate")}
</StyledRegenerateTokenButton>
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit" onClick={handleSubmit}>
Expand Down Expand Up @@ -100,4 +122,13 @@ const StyledDivider = styled(Divider)`
height: 100%;
`;

const StyledTokenInput = styled(Input.Password)`
width: calc(100% - 120px);
`;

const StyledRegenerateTokenButton = styled(Button)`
width: "115px";
margin-left: 5px;
`;

export default MyIntegrationForm;
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ export type Props = {
integration: Integration;
onIntegrationUpdate: (data: { name: string; description: string; logoUrl: string }) => void;
onIntegrationDelete: () => Promise<void>;
onRegenerateToken: () => Promise<void>;
};

const MyIntegrationSettings: React.FC<Props> = ({
integration,
onIntegrationUpdate,
onIntegrationDelete,
onRegenerateToken,
}) => {
return (
<Wrapper>
<MyIntegrationForm integration={integration} onIntegrationUpdate={onIntegrationUpdate} />
<MyIntegrationForm
integration={integration}
onIntegrationUpdate={onIntegrationUpdate}
onRegenerateToken={onRegenerateToken}
/>
<DangerZone onIntegrationDelete={onIntegrationDelete} />
</Wrapper>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
useUpdateWebhookMutation,
useDeleteWebhookMutation,
useDeleteIntegrationMutation,
useRegenerateTokenMutation,
} from "@reearth-cms/gql/graphql-client-api";
import { useT } from "@reearth-cms/i18n";
import { useWorkspace } from "@reearth-cms/state";
Expand Down Expand Up @@ -77,6 +78,28 @@ export default ({ integrationId }: Params) => {
}
}, [currentWorkspace, integrationId, deleteIntegrationMutation, navigate, t]);

const [regenerateTokenMutation] = useRegenerateTokenMutation({
refetchQueries: ["GetMe"],
});

const handleRegenerateToken = useCallback(async () => {
if (!integrationId) return;
const result = await regenerateTokenMutation({
variables: {
integrationId,
},
});
if (result.errors) {
Notification.error({
message: t("The attempt to regenerate the integration token has failed."),
});
} else {
Notification.success({
message: t("The integration token has been successfully regenerated!"),
});
}
}, [integrationId, regenerateTokenMutation, t]);

const [createNewWebhook] = useCreateWebhookMutation({
refetchQueries: ["GetMe"],
});
Expand Down Expand Up @@ -178,6 +201,7 @@ export default ({ integrationId }: Params) => {
webhookInitialValues,
handleIntegrationUpdate,
handleIntegrationDelete,
handleRegenerateToken,
handleWebhookCreate,
handleWebhookDelete,
handleWebhookUpdate,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const MyIntegrationDetails: React.FC = () => {
webhookInitialValues,
handleIntegrationUpdate,
handleIntegrationDelete,
handleRegenerateToken,
handleWebhookCreate,
handleWebhookDelete,
handleWebhookUpdate,
Expand All @@ -32,6 +33,7 @@ const MyIntegrationDetails: React.FC = () => {
webhookInitialValues={webhookInitialValues}
onIntegrationUpdate={handleIntegrationUpdate}
onIntegrationDelete={handleIntegrationDelete}
onRegenerateToken={handleRegenerateToken}
onWebhookCreate={handleWebhookCreate}
onWebhookDelete={handleWebhookDelete}
onWebhookUpdate={handleWebhookUpdate}
Expand Down
56 changes: 56 additions & 0 deletions web/src/gql/graphql-client-api.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ export type Mutation = {
deleteWorkspace?: Maybe<DeleteWorkspacePayload>;
publishItem?: Maybe<PublishItemPayload>;
publishModel?: Maybe<PublishModelPayload>;
regenerateToken?: Maybe<IntegrationPayload>;
removeIntegrationFromWorkspace?: Maybe<RemoveMemberFromWorkspacePayload>;
removeMyAuth?: Maybe<UpdateMePayload>;
removeUserFromWorkspace?: Maybe<RemoveMemberFromWorkspacePayload>;
Expand Down Expand Up @@ -977,6 +978,11 @@ export type MutationPublishModelArgs = {
};


export type MutationRegenerateTokenArgs = {
input: RegenerateTokenInput;
};


export type MutationRemoveIntegrationFromWorkspaceArgs = {
input: RemoveIntegrationFromWorkspaceInput;
};
Expand Down Expand Up @@ -1397,6 +1403,10 @@ export type QueryViewArgs = {
modelId: Scalars['ID']['input'];
};

export type RegenerateTokenInput = {
integrationId: Scalars['ID']['input'];
};

export type RemoveIntegrationFromWorkspaceInput = {
integrationId: Scalars['ID']['input'];
workspaceId: Scalars['ID']['input'];
Expand Down Expand Up @@ -2437,6 +2447,13 @@ export type DeleteIntegrationMutationVariables = Exact<{

export type DeleteIntegrationMutation = { __typename?: 'Mutation', deleteIntegration?: { __typename?: 'DeleteIntegrationPayload', integrationId: string } | null };

export type RegenerateTokenMutationVariables = Exact<{
integrationId: Scalars['ID']['input'];
}>;


export type RegenerateTokenMutation = { __typename?: 'Mutation', regenerateToken?: { __typename?: 'IntegrationPayload', integration: { __typename?: 'Integration', id: string, name: string, description?: string | null, logoUrl: string, iType: IntegrationType } } | null };

export type GetItemsQueryVariables = Exact<{
query: ItemQueryInput;
pagination?: InputMaybe<Pagination>;
Expand Down Expand Up @@ -4383,6 +4400,45 @@ export function useDeleteIntegrationMutation(baseOptions?: Apollo.MutationHookOp
export type DeleteIntegrationMutationHookResult = ReturnType<typeof useDeleteIntegrationMutation>;
export type DeleteIntegrationMutationResult = Apollo.MutationResult<DeleteIntegrationMutation>;
export type DeleteIntegrationMutationOptions = Apollo.BaseMutationOptions<DeleteIntegrationMutation, DeleteIntegrationMutationVariables>;
export const RegenerateTokenDocument = gql`
mutation regenerateToken($integrationId: ID!) {
regenerateToken(input: {integrationId: $integrationId}) {
integration {
id
name
description
logoUrl
iType
}
}
}
`;
export type RegenerateTokenMutationFn = Apollo.MutationFunction<RegenerateTokenMutation, RegenerateTokenMutationVariables>;

/**
* __useRegenerateTokenMutation__
*
* To run a mutation, you first call `useRegenerateTokenMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useRegenerateTokenMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [regenerateTokenMutation, { data, loading, error }] = useRegenerateTokenMutation({
* variables: {
* integrationId: // value for 'integrationId'
* },
* });
*/
export function useRegenerateTokenMutation(baseOptions?: Apollo.MutationHookOptions<RegenerateTokenMutation, RegenerateTokenMutationVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useMutation<RegenerateTokenMutation, RegenerateTokenMutationVariables>(RegenerateTokenDocument, options);
}
export type RegenerateTokenMutationHookResult = ReturnType<typeof useRegenerateTokenMutation>;
export type RegenerateTokenMutationResult = Apollo.MutationResult<RegenerateTokenMutation>;
export type RegenerateTokenMutationOptions = Apollo.BaseMutationOptions<RegenerateTokenMutation, RegenerateTokenMutationVariables>;
export const GetItemsDocument = gql`
query GetItems($query: ItemQueryInput!, $pagination: Pagination) {
searchItem(input: {query: $query, pagination: $pagination}) {
Expand Down
56 changes: 56 additions & 0 deletions web/src/gql/graphql.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7554,6 +7554,35 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "regenerateToken",
"description": null,
"args": [
{
"name": "input",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "INPUT_OBJECT",
"name": "RegenerateTokenInput",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"type": {
"kind": "OBJECT",
"name": "IntegrationPayload",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "removeIntegrationFromWorkspace",
"description": null,
Expand Down Expand Up @@ -10522,6 +10551,33 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "RegenerateTokenInput",
"description": null,
"fields": null,
"inputFields": [
{
"name": "integrationId",
"description": null,
"type": {
"kind": "NON_NULL",
"name": null,
"ofType": {
"kind": "SCALAR",
"name": "ID",
"ofType": null
}
},
"defaultValue": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"interfaces": null,
"enumValues": null,
"possibleTypes": null
},
{
"kind": "INPUT_OBJECT",
"name": "RemoveIntegrationFromWorkspaceInput",
Expand Down
14 changes: 14 additions & 0 deletions web/src/gql/queries/integration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,17 @@ export const DELETE_INTEGRATION = gql`
}
}
`;

export const REGENERATE_TOKEN = gql`
mutation regenerateToken($integrationId: ID!) {
regenerateToken(input: { integrationId: $integrationId }) {
integration {
id
name
description
logoUrl
iType
}
}
}
`;
Loading
Loading