Add public key to service account creation modal

This commit is contained in:
Tuan Dang
2023-04-09 19:51:13 +03:00
parent 192e3beb46
commit afa7b35d50
7 changed files with 89 additions and 6 deletions
@@ -4,8 +4,9 @@ import NavHeader from '@app/components/navigation/NavHeader';
import { SAProjectLevelPermissionsTable } from './components/SAProjectLevelPermissionsTable'; import { SAProjectLevelPermissionsTable } from './components/SAProjectLevelPermissionsTable';
import { import {
CopyServiceAccountIDSection, CopyServiceAccountPublicKeySection,
ServiceAccountNameChangeSection} from './components'; ServiceAccountNameChangeSection
} from './components';
export const CreateServiceAccountPage = () => { export const CreateServiceAccountPage = () => {
const router = useRouter(); const router = useRouter();
@@ -29,7 +30,7 @@ export const CreateServiceAccountPage = () => {
serviceAccountId={serviceAccountId} serviceAccountId={serviceAccountId}
/> />
<div className="mt-8"> <div className="mt-8">
<CopyServiceAccountIDSection <CopyServiceAccountPublicKeySection
serviceAccountId={serviceAccountId} serviceAccountId={serviceAccountId}
/> />
</div> </div>
@@ -0,0 +1,53 @@
import { useEffect } from 'react';
import { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { IconButton } from '@app/components/v2';
import { useToggle } from '@app/hooks';
import { useGetServiceAccountById } from '@app/hooks/api';
type Props = {
serviceAccountId: string;
}
export const CopyServiceAccountPublicKeySection = ({ serviceAccountId }: Props): JSX.Element => {
const { data: serviceAccount } = useGetServiceAccountById(serviceAccountId);
const [isServiceAccountIdCopied, setIsServiceAccountIdCopied] = useToggle(false);
useEffect(() => {
let timer: NodeJS.Timeout;
if (isServiceAccountIdCopied) {
timer = setTimeout(() => setIsServiceAccountIdCopied.off(), 2000);
}
return () => clearTimeout(timer);
}, [isServiceAccountIdCopied]);
const copyServiceAccountIdToClipboard = () => {
if (!serviceAccount) return;
navigator.clipboard.writeText(serviceAccount.publicKey);
setIsServiceAccountIdCopied.on();
};
return serviceAccount ? (
<div className="flex w-full flex-col items-start rounded-md bg-white/5 px-6 p-6">
<p className="text-xl font-semibold">Public Key</p>
<div className="mt-4 flex items-center justify-end rounded-md bg-white/[0.07] text-base text-gray-400 p-2">
<p className="mr-4 break-all">{serviceAccount.publicKey}</p>
<IconButton
ariaLabel="copy icon"
colorSchema="secondary"
className="group relative"
onClick={() => copyServiceAccountIdToClipboard()}
>
<FontAwesomeIcon icon={isServiceAccountIdCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
Copy
</span>
</IconButton>
</div>
</div>
) : <div />
}
@@ -0,0 +1 @@
export { CopyServiceAccountPublicKeySection } from './CopyServiceAccountPublicKeySection';
@@ -40,7 +40,8 @@ import {
useDeleteServiceAccountProjectLevelPermission, useDeleteServiceAccountProjectLevelPermission,
useGetServiceAccountById, useGetServiceAccountById,
useGetServiceAccountProjectLevelPermissions, useGetServiceAccountProjectLevelPermissions,
useGetUserWorkspaces} from '@app/hooks/api'; useGetUserWorkspaces
} from '@app/hooks/api';
import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey'; import getLatestFileKey from '@app/pages/api/workspace/getLatestFileKey';
const createProjectLevelPermissionSchema = yup.object({ const createProjectLevelPermissionSchema = yup.object({
@@ -58,7 +58,7 @@ export const ServiceAccountNameChangeSection = ({
onSubmit={handleSubmit(onFormSubmit)} onSubmit={handleSubmit(onFormSubmit)}
className="rounded-md bg-white/5 p-6" className="rounded-md bg-white/5 p-6"
> >
<p className="mb-4 text-xl font-semibold">Service Account Name</p> <p className="mb-4 text-xl font-semibold">Name</p>
<div className="mb-2 w-full max-w-lg"> <div className="mb-2 w-full max-w-lg">
{!isServiceAccountLoading && ( {!isServiceAccountLoading && (
<Controller <Controller
@@ -1,3 +1,4 @@
export { CopyServiceAccountIDSection } from './CopyServiceAccountIDSection'; export { CopyServiceAccountIDSection } from './CopyServiceAccountIDSection';
export { CopyServiceAccountPublicKeySection } from './CopyServiceAccountPublicKeySection';
export { SAProjectLevelPermissionsTable } from './SAProjectLevelPermissionsTable'; export { SAProjectLevelPermissionsTable } from './SAProjectLevelPermissionsTable';
export { ServiceAccountNameChangeSection } from './ServiceAccountNameChangeSection'; export { ServiceAccountNameChangeSection } from './ServiceAccountNameChangeSection';
@@ -65,8 +65,10 @@ export const OrgServiceAccountsTable = () => {
const orgId = currentOrg?._id || ''; const orgId = currentOrg?._id || '';
const [step, setStep] = useState(0); const [step, setStep] = useState(0);
const [isAccessKeyCopied, setIsAccessKeyCopied] = useToggle(false); const [isAccessKeyCopied, setIsAccessKeyCopied] = useToggle(false);
const [isPublicKeyCopied, setIsPublicKeyCopied] = useToggle(false);
const [isPrivateKeyCopied, setIsPrivateKeyCopied] = useToggle(false); const [isPrivateKeyCopied, setIsPrivateKeyCopied] = useToggle(false);
const [accessKey, setAccessKey] = useState(''); const [accessKey, setAccessKey] = useState('');
const [publicKey, setPublicKey] = useState('');
const [privateKey, setPrivateKey] = useState(''); const [privateKey, setPrivateKey] = useState('');
const [searchServiceAccountFilter, setSearchServiceAccountFilter] = useState(''); const [searchServiceAccountFilter, setSearchServiceAccountFilter] = useState('');
const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([ const { handlePopUpToggle, popUp, handlePopUpOpen, handlePopUpClose } = usePopUp([
@@ -85,12 +87,16 @@ export const OrgServiceAccountsTable = () => {
timer = setTimeout(() => setIsAccessKeyCopied.off(), 2000); timer = setTimeout(() => setIsAccessKeyCopied.off(), 2000);
} }
if (isPublicKeyCopied) {
timer = setTimeout(() => setIsPublicKeyCopied.off(), 2000);
}
if (isPrivateKeyCopied) { if (isPrivateKeyCopied) {
timer = setTimeout(() => setIsPrivateKeyCopied.off(), 2000); timer = setTimeout(() => setIsPrivateKeyCopied.off(), 2000);
} }
return () => clearTimeout(timer); return () => clearTimeout(timer);
}, [isAccessKeyCopied, isPrivateKeyCopied]); }, [isAccessKeyCopied, isPublicKeyCopied, isPrivateKeyCopied]);
const { const {
control, control,
@@ -103,6 +109,7 @@ export const OrgServiceAccountsTable = () => {
if (!currentOrg?._id) return; if (!currentOrg?._id) return;
const keyPair = generateKeyPair(); const keyPair = generateKeyPair();
setPublicKey(keyPair.publicKey);
setPrivateKey(keyPair.privateKey); setPrivateKey(keyPair.privateKey);
const serviceAccountDetails = await createServiceAccount.mutateAsync({ const serviceAccountDetails = await createServiceAccount.mutateAsync({
@@ -216,6 +223,24 @@ export const OrgServiceAccountsTable = () => {
</span> </span>
</IconButton> </IconButton>
</div> </div>
<p className="mt-4">Public Key</p>
<div className="flex items-center justify-end rounded-md p-2 text-base text-gray-400 bg-white/[0.07]">
<p className="mr-4 break-all">{publicKey}</p>
<IconButton
ariaLabel="copy icon"
colorSchema="secondary"
className="group relative"
onClick={() => {
navigator.clipboard.writeText(publicKey);
setIsPublicKeyCopied.on();
}}
>
<FontAwesomeIcon icon={isPublicKeyCopied ? faCheck : faCopy} />
<span className="absolute -left-8 -top-20 hidden w-28 translate-y-full rounded-md bg-bunker-800 py-2 pl-3 text-center text-sm text-gray-400 group-hover:flex group-hover:animate-fadeIn">
Copy
</span>
</IconButton>
</div>
<p className="mt-4">Private Key</p> <p className="mt-4">Private Key</p>
<div className="flex items-center justify-end rounded-md p-2 text-base text-gray-400 bg-white/[0.07]"> <div className="flex items-center justify-end rounded-md p-2 text-base text-gray-400 bg-white/[0.07]">
<p className="mr-4 break-all">{privateKey}</p> <p className="mr-4 break-all">{privateKey}</p>
@@ -234,6 +259,7 @@ export const OrgServiceAccountsTable = () => {
</span> </span>
</IconButton> </IconButton>
</div> </div>
</> </>
); );
default: default: