2023-11-23 09:39:46 +00:00
|
|
|
import { Dispatch, SetStateAction, useState, FC } from "react";
|
2023-11-15 10:26:57 +00:00
|
|
|
import { useForm } from "react-hook-form";
|
2023-11-23 09:39:46 +00:00
|
|
|
import { useRouter } from "next/router";
|
|
|
|
// helpers
|
2023-11-15 10:26:57 +00:00
|
|
|
import { addDays, renderDateFormat } from "helpers/date-time.helper";
|
|
|
|
import { csvDownload } from "helpers/download.helper";
|
2023-11-23 09:39:46 +00:00
|
|
|
// types
|
|
|
|
import { IApiToken } from "types/api_token";
|
|
|
|
// hooks
|
2023-11-15 10:26:57 +00:00
|
|
|
import { useMobxStore } from "lib/mobx/store-provider";
|
2023-11-23 09:39:46 +00:00
|
|
|
import useToast from "hooks/use-toast";
|
|
|
|
// services
|
|
|
|
import { APITokenService } from "services/api_token.service";
|
|
|
|
// components
|
|
|
|
import { APITokenTitle } from "./token-title";
|
|
|
|
import { APITokenDescription } from "./token-description";
|
|
|
|
import { APITokenExpiry, EXPIRY_OPTIONS } from "./token-expiry";
|
|
|
|
import { APITokenKeySection } from "./token-key-section";
|
|
|
|
// ui
|
2023-11-15 10:26:57 +00:00
|
|
|
import { Button } from "@plane/ui";
|
|
|
|
|
2023-11-23 09:39:46 +00:00
|
|
|
interface APITokenFormProps {
|
2023-11-15 10:26:57 +00:00
|
|
|
generatedToken: IApiToken | null | undefined;
|
|
|
|
setGeneratedToken: Dispatch<SetStateAction<IApiToken | null | undefined>>;
|
|
|
|
setDeleteTokenModal: Dispatch<SetStateAction<boolean>>;
|
|
|
|
}
|
|
|
|
|
2023-11-23 09:39:46 +00:00
|
|
|
export interface APIFormFields {
|
|
|
|
never_expires: boolean;
|
|
|
|
title: string;
|
|
|
|
description: string;
|
|
|
|
}
|
|
|
|
|
|
|
|
const apiTokenService = new APITokenService();
|
|
|
|
|
|
|
|
export const APITokenForm: FC<APITokenFormProps> = (props) => {
|
|
|
|
const { generatedToken, setGeneratedToken, setDeleteTokenModal } = props;
|
|
|
|
// states
|
2023-11-15 10:26:57 +00:00
|
|
|
const [loading, setLoading] = useState<boolean>(false);
|
|
|
|
const [neverExpires, setNeverExpire] = useState<boolean>(false);
|
|
|
|
const [focusTitle, setFocusTitle] = useState<boolean>(false);
|
|
|
|
const [focusDescription, setFocusDescription] = useState<boolean>(false);
|
|
|
|
const [selectedExpiry, setSelectedExpiry] = useState<number>(1);
|
2023-11-23 09:39:46 +00:00
|
|
|
// hooks
|
2023-11-15 10:26:57 +00:00
|
|
|
const { setToastAlert } = useToast();
|
2023-11-23 09:39:46 +00:00
|
|
|
// store
|
|
|
|
const {
|
|
|
|
theme: { sidebarCollapsed },
|
|
|
|
} = useMobxStore();
|
|
|
|
// router
|
2023-11-15 10:26:57 +00:00
|
|
|
const router = useRouter();
|
|
|
|
const { workspaceSlug } = router.query;
|
|
|
|
|
|
|
|
const {
|
|
|
|
control,
|
|
|
|
handleSubmit,
|
|
|
|
formState: { errors },
|
|
|
|
} = useForm({
|
|
|
|
defaultValues: {
|
|
|
|
never_expires: false,
|
|
|
|
title: "",
|
|
|
|
description: "",
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const getExpiryDate = (): string | null => {
|
|
|
|
if (neverExpires === true) return null;
|
2023-11-23 09:39:46 +00:00
|
|
|
return addDays({ date: new Date(), days: EXPIRY_OPTIONS[selectedExpiry].days }).toISOString();
|
2023-11-15 10:26:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
function renderExpiry(): string {
|
2023-11-23 09:39:46 +00:00
|
|
|
return renderDateFormat(addDays({ date: new Date(), days: EXPIRY_OPTIONS[selectedExpiry].days }), true);
|
2023-11-15 10:26:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const downloadSecretKey = (token: IApiToken) => {
|
|
|
|
const csvData = {
|
|
|
|
Label: token.label,
|
|
|
|
Description: token.description,
|
|
|
|
Expiry: renderDateFormat(token.expired_at ?? null),
|
|
|
|
"Secret Key": token.token,
|
|
|
|
};
|
|
|
|
csvDownload(csvData, `Secret-key-${Date.now()}`);
|
|
|
|
};
|
|
|
|
|
|
|
|
const generateToken = async (data: any) => {
|
|
|
|
if (!workspaceSlug) return;
|
|
|
|
setLoading(true);
|
|
|
|
await apiTokenService
|
|
|
|
.createApiToken(workspaceSlug.toString(), {
|
|
|
|
label: data.title,
|
|
|
|
description: data.description,
|
|
|
|
expired_at: getExpiryDate(),
|
|
|
|
})
|
|
|
|
.then((res) => {
|
|
|
|
setGeneratedToken(res);
|
|
|
|
downloadSecretKey(res);
|
|
|
|
setLoading(false);
|
|
|
|
})
|
|
|
|
.catch((err) => {
|
|
|
|
setToastAlert({
|
|
|
|
message: err.message,
|
|
|
|
type: "error",
|
|
|
|
title: "Error",
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
return (
|
|
|
|
<form
|
|
|
|
onSubmit={handleSubmit(generateToken, (err) => {
|
|
|
|
if (err.title) {
|
|
|
|
setFocusTitle(true);
|
|
|
|
}
|
|
|
|
})}
|
2023-11-23 09:39:46 +00:00
|
|
|
className={`${sidebarCollapsed ? "xl:w-[50%] lg:w-[60%] " : "w-[60%]"} mx-auto py-8`}
|
2023-11-15 10:26:57 +00:00
|
|
|
>
|
|
|
|
<div className="border-b border-custom-border-200 pb-4">
|
2023-11-23 09:39:46 +00:00
|
|
|
<APITokenTitle
|
2023-11-15 10:26:57 +00:00
|
|
|
generatedToken={generatedToken}
|
|
|
|
control={control}
|
|
|
|
errors={errors}
|
|
|
|
focusTitle={focusTitle}
|
|
|
|
setFocusTitle={setFocusTitle}
|
|
|
|
setFocusDescription={setFocusDescription}
|
|
|
|
/>
|
|
|
|
{errors.title && focusTitle && <p className=" text-red-600">{errors.title.message}</p>}
|
2023-11-23 09:39:46 +00:00
|
|
|
<APITokenDescription
|
2023-11-15 10:26:57 +00:00
|
|
|
generatedToken={generatedToken}
|
|
|
|
control={control}
|
|
|
|
focusDescription={focusDescription}
|
|
|
|
setFocusTitle={setFocusTitle}
|
|
|
|
setFocusDescription={setFocusDescription}
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
{!generatedToken && (
|
|
|
|
<div className="mt-12">
|
|
|
|
<>
|
2023-11-23 09:39:46 +00:00
|
|
|
<APITokenExpiry
|
2023-11-15 10:26:57 +00:00
|
|
|
neverExpires={neverExpires}
|
|
|
|
selectedExpiry={selectedExpiry}
|
|
|
|
setSelectedExpiry={setSelectedExpiry}
|
|
|
|
setNeverExpire={setNeverExpire}
|
|
|
|
renderExpiry={renderExpiry}
|
|
|
|
control={control}
|
|
|
|
/>
|
|
|
|
<Button variant="primary" type="submit">
|
|
|
|
{loading ? "generating..." : "Add Api key"}
|
|
|
|
</Button>
|
|
|
|
</>
|
|
|
|
</div>
|
|
|
|
)}
|
2023-11-23 09:39:46 +00:00
|
|
|
<APITokenKeySection
|
2023-11-15 10:26:57 +00:00
|
|
|
generatedToken={generatedToken}
|
|
|
|
renderExpiry={renderExpiry}
|
|
|
|
setDeleteTokenModal={setDeleteTokenModal}
|
|
|
|
/>
|
|
|
|
</form>
|
|
|
|
);
|
|
|
|
};
|