Skip to content

Commit

Permalink
feat(web): implement regenerate integration token functionality (#1157)
Browse files Browse the repository at this point in the history
* add regenerate token mutation to gql

* implement regenerate token

* add japanese translations

* fix: translation

---------

Co-authored-by: Kazuma Tsuchiya <caichi0424@gmail.com>
  • Loading branch information
nourbalaha and caichi-t authored May 22, 2024
1 parent b22fbc9 commit 8008b5d
Show file tree
Hide file tree
Showing 10 changed files with 1,201 additions and 997 deletions.
3 changes: 3 additions & 0 deletions web/src/components/molecules/MyIntegrations/Content/index.tsx
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

0 comments on commit 8008b5d

Please sign in to comment.