plane/web/components/web-hooks/form/generate-key.tsx
Bavisetti Narayan 870c4403e4 feat: api webhooks (#2543)
* dev: initiate external apis

* dev: external api

* dev: external public api implementation

* dev: add prefix to all api tokens

* dev: flag to enable disable api token api access

* dev: webhook model create and apis

* dev: webhook settings

* fix: webhook logs

* chore: removed drf spectacular

* dev: remove retry_count and fix api logging for get requests

* dev: refactor webhook logic

* fix: celery retry mechanism

* chore: event and action change

* chore: migrations changes

* dev: proxy setup for apis

* chore: changed retry time and cleanup

* chore: added issue comment and inbox issue api endpoints

* fix: migration files

* fix: added env variables

* fix: removed issue attachment from proxy

* fix: added new migration file

* fix: restricted wehbook access

* chore: changed urls

* chore: fixed porject serializer

* fix: set expire for api token

* fix: retrive endpoint for api token

* feat: Api Token screens & api integration

* dev: webhook endpoint changes

* dev: add fields for webhook updates

* feat: Download Api secret key

* chore: removed BASE API URL

* feat: revoke token access

* dev: migration fixes

* feat: workspace webhooks (#2748)

* feat: workspace webhook store, services integeration and rendered webhook list and create

* chore: handled webhook update and rengenerate token in workspace webhooks

* feat: regenerate key and delete functionality

---------

Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com>

* fix: url validation added

* fix: seperated env for webhook and api

* Web hooks refactoring

* add show option for generated hook key

* Api token restructure

* webhook minor fixes

* fix build errors

* chore: improvements in file structring

* dev: rate limiting the open apis

---------

Co-authored-by: pablohashescobar <nikhilschacko@gmail.com>
Co-authored-by: LAKHAN BAHETI <lakhanbaheti9@gmail.com>
Co-authored-by: rahulramesha <71900764+rahulramesha@users.noreply.github.com>
Co-authored-by: Ramesh Kumar <rameshkumar@rameshs-MacBook-Pro.local>
Co-authored-by: gurusainath <gurusainath007@gmail.com>
Co-authored-by: Ramesh Kumar Chandra <rameshkumar2299@gmail.com>
Co-authored-by: Nikhil <118773738+pablohashescobar@users.noreply.github.com>
Co-authored-by: sriram veeraghanta <veeraghanta.sriram@gmail.com>
Co-authored-by: rahulramesha <rahulramesham@gmail.com>
2023-12-07 19:59:35 +05:30

140 lines
4.6 KiB
TypeScript

import { useState, FC } from "react";
import { useRouter } from "next/router";
import { Button } from "@plane/ui";
import { Copy, Eye, EyeOff, RefreshCw } from "lucide-react";
import { observer } from "mobx-react-lite";
// hooks
import useToast from "hooks/use-toast";
// store
import { RootStore } from "store/root";
import { useMobxStore } from "lib/mobx/store-provider";
// helpers
import { copyTextToClipboard } from "helpers/string.helper";
import { csvDownload } from "helpers/download.helper";
// utils
import { getCurrentHookAsCSV } from "../utils";
// enum
import { WebHookFormTypes } from "./index";
interface IGenerateKey {
type: WebHookFormTypes.CREATE | WebHookFormTypes.EDIT;
}
export const GenerateKey: FC<IGenerateKey> = observer((props) => {
const { type } = props;
// states
const [regenerating, setRegenerate] = useState(false);
const [shouldShowKey, setShouldShowKey] = useState(false);
// router
const router = useRouter();
const { workspaceSlug, webhookId } = router.query as { workspaceSlug: string; webhookId: string };
// store
const { webhook: webhookStore, workspace: workspaceStore }: RootStore = useMobxStore();
// hooks
const { setToastAlert } = useToast();
const handleCopySecret = () => {
if (webhookStore?.webhookSecretKey) {
copyTextToClipboard(webhookStore.webhookSecretKey);
setToastAlert({
title: "Success",
type: "success",
message: "Secret key copied",
});
} else {
setToastAlert({
title: "Oops",
type: "error",
message: "Error occurred while copying secret key",
});
}
};
function handleRegenerate() {
setRegenerate(true);
webhookStore
.regenerate(workspaceSlug, webhookId)
.then(() => {
setToastAlert({
title: "Success",
type: "success",
message: "Successfully regenerated",
});
const csvData = getCurrentHookAsCSV(
workspaceStore.currentWorkspace,
webhookStore.currentWebhook,
webhookStore.webhookSecretKey
);
csvDownload(csvData, `Secret-key-${Date.now()}`);
})
.catch((err) => {
setToastAlert({
title: "Oops!",
type: "error",
message: err?.error,
});
})
.finally(() => {
setRegenerate(false);
});
}
const toggleShowKey = () => {
setShouldShowKey((prevState) => !prevState);
};
const icons = [
{ Component: Copy, onClick: handleCopySecret, key: "copy" },
{ Component: shouldShowKey ? EyeOff : Eye, onClick: toggleShowKey, key: "eye" },
];
return (
<>
{(type === WebHookFormTypes.EDIT || (type === WebHookFormTypes.CREATE && webhookStore?.webhookSecretKey)) && (
<div className="space-y-2">
<div className="text-sm font-medium">Secret Key</div>
<div className="text-sm text-neutral-400">Genarate a token to sign-in the webhook payload</div>
<div className="flex gap-5 items-center">
<div className="relative flex items-center p-2 rounded w-full border border-custom-border-200">
<div className="flex w-full overflow-hidden h-7 px-2 font-medium select-none">
{webhookStore?.webhookSecretKey && shouldShowKey ? (
<div>{webhookStore?.webhookSecretKey}</div>
) : (
<div className="flex items-center gap-1.5">
{[...Array(41)].map((_, index) => (
<div key={index} className="w-[4px] h-[4px] bg-gray-300 rounded-full" />
))}
</div>
)}
</div>
{webhookStore?.webhookSecretKey && (
<>
{icons.map(({ Component, onClick, key }) => (
<div
className="w-7 h-7 flex-shrink-0 flex justify-center items-center cursor-pointer hover:bg-custom-background-80 rounded"
onClick={onClick}
key={key}
>
<Component className="text-custom-text-400 w-4 h-4" />
</div>
))}
</>
)}
</div>
<div>
{type != WebHookFormTypes.CREATE && (
<Button disabled={regenerating} onClick={handleRegenerate} variant="accent-primary" className="">
<RefreshCw className={`h-3 w-3`} />
{regenerating ? "Re-generating..." : "Re-genarate Key"}
</Button>
)}
</div>
</div>
</div>
)}
</>
);
});