mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 04:27:29 +00:00
Dashboard UI update
This commit is contained in:
@@ -43,7 +43,7 @@ export default function NavHeader({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ml-6 flex flex-row items-center pt-8">
|
<div className="ml-6 flex flex-row items-center pt-6">
|
||||||
<div className="mr-2 flex h-6 w-6 items-center justify-center rounded-md bg-primary-900 text-mineshaft-100">
|
<div className="mr-2 flex h-6 w-6 items-center justify-center rounded-md bg-primary-900 text-mineshaft-100">
|
||||||
{currentOrg?.name?.charAt(0)}
|
{currentOrg?.name?.charAt(0)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ const buttonVariants = cva(
|
|||||||
selected: '',
|
selected: '',
|
||||||
outline_bg: '',
|
outline_bg: '',
|
||||||
// a constant color not in use on hover or click goes colorSchema color
|
// a constant color not in use on hover or click goes colorSchema color
|
||||||
star: 'text-bunker-200 bg-mineshaft-500'
|
star: 'text-bunker-200 bg-mineshaft-700 border-mineshaft-600'
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-mineshaft text-white opacity-50 cursor-not-allowed',
|
true: 'bg-mineshaft-700 border border-mineshaft-600 text-white opacity-50 cursor-not-allowed',
|
||||||
false: ''
|
false: 'border border-primary-400'
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
true: 'w-full',
|
true: 'w-full',
|
||||||
@@ -61,7 +61,7 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
colorSchema: 'primary',
|
colorSchema: 'primary',
|
||||||
variant: 'star',
|
variant: 'star',
|
||||||
className: 'hover:bg-primary hover:text-black'
|
className: 'bg-mineshaft-700 border border-mineshaft-600 hover:bg-primary hover:text-black hover:border-primary-400 duration-100'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'primary',
|
colorSchema: 'primary',
|
||||||
@@ -71,7 +71,7 @@ const buttonVariants = cva(
|
|||||||
{
|
{
|
||||||
colorSchema: 'primary',
|
colorSchema: 'primary',
|
||||||
variant: 'outline_bg',
|
variant: 'outline_bg',
|
||||||
className: 'bg-mineshaft-800 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60 text-bunker-200'
|
className: 'bg-mineshaft-700 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60 text-bunker-200 duration-100'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'secondary',
|
colorSchema: 'secondary',
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ const iconButtonVariants = cva(
|
|||||||
solid: '',
|
solid: '',
|
||||||
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
outline: ['bg-transparent', 'border-2', 'border-solid'],
|
||||||
plain: '',
|
plain: '',
|
||||||
star: 'text-bunker-200 bg-mineshaft-500'
|
star: 'text-bunker-200 bg-mineshaft-500',
|
||||||
|
outline_bg: ''
|
||||||
},
|
},
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'bg-opacity-70 cursor-not-allowed',
|
true: 'bg-opacity-70 cursor-not-allowed',
|
||||||
@@ -53,6 +54,11 @@ const iconButtonVariants = cva(
|
|||||||
variant: 'star',
|
variant: 'star',
|
||||||
className: 'hover:bg-primary hover:text-black'
|
className: 'hover:bg-primary hover:text-black'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
colorSchema: 'primary',
|
||||||
|
variant: 'outline_bg',
|
||||||
|
className: 'bg-mineshaft-700 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60 text-bunker-200 hover:text-bunker-100 duration-100'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
colorSchema: 'danger',
|
colorSchema: 'danger',
|
||||||
variant: 'star',
|
variant: 'star',
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ const inputVariants = cva(
|
|||||||
},
|
},
|
||||||
isError: {
|
isError: {
|
||||||
true: 'focus:ring-red/50 placeholder-red-300',
|
true: 'focus:ring-red/50 placeholder-red-300',
|
||||||
false: 'focus:ring-primary/50'
|
false: 'focus:ring-mineshaft-400/80 duration-200 focus:ring-1'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
compoundVariants: []
|
compoundVariants: []
|
||||||
@@ -48,7 +48,7 @@ const inputParentContainerVariants = cva('inline-flex font-inter items-center bo
|
|||||||
},
|
},
|
||||||
isError: {
|
isError: {
|
||||||
true: 'border-red',
|
true: 'border-red',
|
||||||
false: 'border-mineshaft-500'
|
false: 'border-mineshaft-600'
|
||||||
},
|
},
|
||||||
isFullWidth: {
|
isFullWidth: {
|
||||||
true: 'w-full',
|
true: 'w-full',
|
||||||
|
|||||||
@@ -29,11 +29,13 @@ const Dashboard = () => {
|
|||||||
<meta property="og:title" content={String(t('dashboard:og-title'))} />
|
<meta property="og:title" content={String(t('dashboard:og-title'))} />
|
||||||
<meta name="og:description" content={String(t('dashboard:og-description'))} />
|
<meta name="og:description" content={String(t('dashboard:og-description'))} />
|
||||||
</Head>
|
</Head>
|
||||||
{isOverviewMode ? (
|
<div className="h-full">
|
||||||
<DashboardEnvOverview onEnvChange={onExploreEnv} />
|
{isOverviewMode ? (
|
||||||
) : (
|
<DashboardEnvOverview onEnvChange={onExploreEnv} />
|
||||||
<DashboardPage envFromTop={queryEnv} />
|
) : (
|
||||||
)}
|
<DashboardPage envFromTop={queryEnv} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -95,10 +95,10 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
|
|||||||
<FormProvider {...method}>
|
<FormProvider {...method}>
|
||||||
<form autoComplete="off">
|
<form autoComplete="off">
|
||||||
{/* breadcrumb row */}
|
{/* breadcrumb row */}
|
||||||
<div className="relative right-5">
|
<div className="relative right-6">
|
||||||
<NavHeader pageName={t('dashboard:title')} isProjectRelated />
|
<NavHeader pageName={t('dashboard:title')} isProjectRelated />
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-6 ml-1">
|
<div className="mt-6">
|
||||||
<p className="text-3xl font-semibold text-bunker-100">Secrets Overview</p>
|
<p className="text-3xl font-semibold text-bunker-100">Secrets Overview</p>
|
||||||
<p className="text-md text-bunker-300">
|
<p className="text-md text-bunker-300">
|
||||||
Inject your secrets using
|
Inject your secrets using
|
||||||
@@ -182,16 +182,8 @@ export const DashboardEnvOverview = ({ onEnvChange }: { onEnvChange: any }) => {
|
|||||||
</TableContainer>
|
</TableContainer>
|
||||||
)}
|
)}
|
||||||
{isDashboardSecretEmpty && (
|
{isDashboardSecretEmpty && (
|
||||||
<div className="mt-1 flex h-40 w-full flex-row rounded-md">
|
<div className="flex h-40 w-full flex-row rounded-md">
|
||||||
<div className="sticky top-0 flex w-10 items-center justify-center border-none px-4">
|
<div className="flex w-full min-w-[11rem] flex-col items-center justify-center rounded-md border-none bg-mineshaft-800 text-bunker-300">
|
||||||
<div className="w-10 text-center text-xs text-transparent">{0}</div>
|
|
||||||
</div>
|
|
||||||
<div className="sticky top-0 border-none">
|
|
||||||
<div className="relative flex h-full w-full min-w-[200px] items-center justify-start lg:min-w-[220px] xl:min-w-[250px]">
|
|
||||||
<div className="text-sm font-medium text-transparent">Secret</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mx-2 flex w-full min-w-[11rem] flex-col items-center justify-center rounded-md border-none bg-mineshaft-800 text-bunker-300">
|
|
||||||
<span className="mb-1">No secrets are available in this project yet.</span>
|
<span className="mb-1">No secrets are available in this project yet.</span>
|
||||||
<span>You can go into any environment to add secrets there.</span>
|
<span>You can go into any environment to add secrets there.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -413,11 +413,11 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="container mx-auto px-6 text-mineshaft-50 dark:[color-scheme:dark]">
|
<div className="mr-auto container px-6 text-mineshaft-50 dark:[color-scheme:dark] h-full">
|
||||||
<FormProvider {...method}>
|
<FormProvider {...method}>
|
||||||
<form autoComplete="off">
|
<form autoComplete="off">
|
||||||
{/* breadcrumb row */}
|
{/* breadcrumb row */}
|
||||||
<div className="relative right-5">
|
<div className="relative right-6 mb-6 -top-2">
|
||||||
<NavHeader
|
<NavHeader
|
||||||
pageName={t('dashboard:title')}
|
pageName={t('dashboard:title')}
|
||||||
currentEnv={
|
currentEnv={
|
||||||
@@ -428,20 +428,18 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
onEnvChange={onEnvChange}
|
onEnvChange={onEnvChange}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{/* Secrets, commit and save button section */}
|
{/* This is only for rollbacks */}
|
||||||
<div className="mt-6 flex items-center justify-between">
|
{isRollbackMode &&
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center justify-between">
|
||||||
<h1 className="text-3xl font-semibold">
|
<div className="flex items-center space-x-4">
|
||||||
{isRollbackMode ? 'Secret Snapshot' : 'Secrets'}
|
<h1 className="text-3xl font-semibold">Secret Snapshot</h1>
|
||||||
</h1>
|
{isRollbackMode && Boolean(snapshotSecret) && (
|
||||||
{isRollbackMode && Boolean(snapshotSecret) && (
|
<Tag colorSchema="green">
|
||||||
<Tag colorSchema="green">
|
{new Date(snapshotSecret?.createdAt || '').toLocaleString()}
|
||||||
{new Date(snapshotSecret?.createdAt || '').toLocaleString()}
|
</Tag>
|
||||||
</Tag>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
<div className="flex items-center space-x-2">
|
||||||
<div className="flex items-center space-x-2">
|
|
||||||
{isRollbackMode && (
|
|
||||||
<Button
|
<Button
|
||||||
variant="star"
|
variant="star"
|
||||||
leftIcon={<FontAwesomeIcon icon={faArrowLeft} />}
|
leftIcon={<FontAwesomeIcon icon={faArrowLeft} />}
|
||||||
@@ -453,33 +451,13 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
>
|
>
|
||||||
Go back
|
Go back
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
</div>
|
||||||
<Button
|
</div>}
|
||||||
variant="star"
|
|
||||||
onClick={() => handlePopUpOpen('secretSnapshots')}
|
|
||||||
leftIcon={<FontAwesomeIcon icon={faCodeCommit} />}
|
|
||||||
isLoading={isLoadingSnapshotCount}
|
|
||||||
isDisabled={!canDoRollback}
|
|
||||||
className="h-10"
|
|
||||||
>
|
|
||||||
{snapshotCount} Commits
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
isDisabled={isSubmitDisabled}
|
|
||||||
isLoading={isSubmitting}
|
|
||||||
leftIcon={<FontAwesomeIcon icon={isRollbackMode ? faClockRotateLeft : faCheck} />}
|
|
||||||
onClick={handleSubmit(onSaveSecret)}
|
|
||||||
className="h-10"
|
|
||||||
>
|
|
||||||
{isRollbackMode ? 'Rollback' : 'Save Changes'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{/* Environment, search and other action row */}
|
{/* Environment, search and other action row */}
|
||||||
<div className="mt-4 flex items-center space-x-2">
|
<div className="mt-2 flex items-center space-x-2 justify-between">
|
||||||
<div className="flex-grow">
|
<div className="flex-grow max-w-sm">
|
||||||
<Input
|
<Input
|
||||||
className="h-[2.3rem] bg-mineshaft-600 placeholder-mineshaft-50"
|
className="h-[2.3rem] bg-mineshaft-800 focus:bg-mineshaft-700/80 duration-200 placeholder-mineshaft-50"
|
||||||
placeholder="Search keys..."
|
placeholder="Search keys..."
|
||||||
value={searchFilter}
|
value={searchFilter}
|
||||||
onChange={(e) => setSearchFilter(e.target.value)}
|
onChange={(e) => setSearchFilter(e.target.value)}
|
||||||
@@ -490,7 +468,7 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
<div>
|
<div>
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<IconButton ariaLabel="download" variant="star">
|
<IconButton ariaLabel="download" variant="outline_bg">
|
||||||
<FontAwesomeIcon icon={faDownload} />
|
<FontAwesomeIcon icon={faDownload} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
@@ -501,7 +479,8 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
<div className="flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
<Button
|
<Button
|
||||||
onClick={() => downloadSecret(getValues('secrets'), selectedEnv?.slug)}
|
onClick={() => downloadSecret(getValues('secrets'), selectedEnv?.slug)}
|
||||||
variant="star"
|
colorSchema="primary"
|
||||||
|
variant="outline_bg"
|
||||||
className="h-8 bg-bunker-700"
|
className="h-8 bg-bunker-700"
|
||||||
>
|
>
|
||||||
Download as .env
|
Download as .env
|
||||||
@@ -514,45 +493,92 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
<Tooltip content={isSecretValueHidden ? 'Reveal Secrets' : 'Hide secrets'}>
|
<Tooltip content={isSecretValueHidden ? 'Reveal Secrets' : 'Hide secrets'}>
|
||||||
<IconButton
|
<IconButton
|
||||||
ariaLabel="reveal"
|
ariaLabel="reveal"
|
||||||
variant="star"
|
variant="outline_bg"
|
||||||
onClick={() => setIsSecretValueHidden.toggle()}
|
onClick={() => setIsSecretValueHidden.toggle()}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={isSecretValueHidden ? faEye : faEyeSlash} />
|
<FontAwesomeIcon icon={isSecretValueHidden ? faEye : faEyeSlash} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
{!isReadOnly && !isRollbackMode && (
|
<div className='block xl:hidden'>
|
||||||
|
<Tooltip content='Point-in-time Recovery'>
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="recovery"
|
||||||
|
variant="outline_bg"
|
||||||
|
onClick={() => setIsSecretValueHidden.toggle()}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faCodeCommit} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div className='hidden xl:block'>
|
||||||
<Button
|
<Button
|
||||||
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
variant="outline_bg"
|
||||||
onClick={() => {
|
onClick={() => handlePopUpOpen('secretSnapshots')}
|
||||||
if (secretContainer.current) {
|
leftIcon={<FontAwesomeIcon icon={faCodeCommit} />}
|
||||||
secretContainer.current.scroll({
|
isLoading={isLoadingSnapshotCount}
|
||||||
top: 0,
|
isDisabled={!canDoRollback}
|
||||||
behavior: 'smooth'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
prepend(DEFAULT_SECRET_VALUE, { shouldFocus: false });
|
|
||||||
}}
|
|
||||||
isDisabled={isReadOnly || isRollbackMode}
|
|
||||||
variant="star"
|
|
||||||
className="h-10"
|
className="h-10"
|
||||||
>
|
>
|
||||||
Add Secret
|
{snapshotCount} Commits
|
||||||
</Button>
|
</Button>
|
||||||
|
</div>
|
||||||
|
{!isReadOnly && !isRollbackMode && (
|
||||||
|
<>
|
||||||
|
<div className='block lg:hidden'>
|
||||||
|
<Tooltip content='Point-in-time Recovery'>
|
||||||
|
<IconButton
|
||||||
|
ariaLabel="recovery"
|
||||||
|
variant="outline_bg"
|
||||||
|
onClick={() => setIsSecretValueHidden.toggle()}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faPlus} />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div className='hidden lg:block'>
|
||||||
|
<Button
|
||||||
|
leftIcon={<FontAwesomeIcon icon={faPlus} />}
|
||||||
|
onClick={() => {
|
||||||
|
if (secretContainer.current) {
|
||||||
|
secretContainer.current.scroll({
|
||||||
|
top: 0,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
prepend(DEFAULT_SECRET_VALUE, { shouldFocus: false });
|
||||||
|
}}
|
||||||
|
isDisabled={isReadOnly || isRollbackMode}
|
||||||
|
variant="outline_bg"
|
||||||
|
className="h-10"
|
||||||
|
>
|
||||||
|
Add Secret
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
|
<Button
|
||||||
|
isDisabled={isSubmitDisabled}
|
||||||
|
isLoading={isSubmitting}
|
||||||
|
leftIcon={<FontAwesomeIcon icon={isRollbackMode ? faClockRotateLeft : faCheck} />}
|
||||||
|
onClick={handleSubmit(onSaveSecret)}
|
||||||
|
className="h-10"
|
||||||
|
>
|
||||||
|
{isRollbackMode ? 'Rollback' : 'Save Changes'}
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${
|
||||||
isSecretEmpty ? 'flex flex-col items-center justify-center' : ''
|
isSecretEmpty ? 'flex flex-col items-center justify-center' : ''
|
||||||
} no-scrollbar::-webkit-scrollbar mt-4 h-[calc(100vh-270px)] overflow-x-hidden overflow-y-scroll no-scrollbar`}
|
} no-scrollbar::-webkit-scrollbar mt-3 h-[calc(100vh-220px)] overflow-x-hidden overflow-y-scroll no-scrollbar`}
|
||||||
ref={secretContainer}
|
ref={secretContainer}
|
||||||
>
|
>
|
||||||
{!isSecretEmpty && (
|
{!isSecretEmpty && (
|
||||||
<TableContainer>
|
<TableContainer className="max-h-[calc(100%-40px)] no-scrollbar no-scrollbar::-webkit-scrollbar">
|
||||||
<table className="secret-table relative">
|
<table className="secret-table relative">
|
||||||
<SecretTableHeader sortDir={sortDir} onSort={onSortSecrets} />
|
<SecretTableHeader sortDir={sortDir} onSort={onSortSecrets} />
|
||||||
<tbody className="max-h-screen overflow-y-auto">
|
<tbody className="max-h-96 overflow-y-auto">
|
||||||
{fields.map(({ id, _id }, index) => (
|
{fields.map(({ id, _id }, index) => (
|
||||||
<SecretInputRow
|
<SecretInputRow
|
||||||
key={id}
|
key={id}
|
||||||
@@ -573,7 +599,7 @@ export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => {
|
|||||||
<td colSpan={3} className="hover:bg-mineshaft-700">
|
<td colSpan={3} className="hover:bg-mineshaft-700">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="ml-12 flex h-8 items-center justify-start font-normal text-bunker-300"
|
className="pl-12 cursor-default w-full flex h-8 items-center justify-start font-normal text-bunker-300"
|
||||||
onClick={onAppendSecret}
|
onClick={onAppendSecret}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faPlus} />
|
<FontAwesomeIcon icon={faPlus} />
|
||||||
|
|||||||
@@ -78,53 +78,55 @@ export const SecretDropzone = ({ isSmaller, onParsedEnv, onAddNewSecret }: Props
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="mx-1">
|
||||||
onDragEnter={handleDrag}
|
<div
|
||||||
onDragLeave={handleDrag}
|
onDragEnter={handleDrag}
|
||||||
onDragOver={handleDrag}
|
onDragLeave={handleDrag}
|
||||||
onDrop={handleDrop}
|
onDragOver={handleDrag}
|
||||||
className={twMerge(
|
onDrop={handleDrop}
|
||||||
'relative mb-4 mt-4 max-w-[calc(100vw-292px)] flex w-full cursor-pointer text-mineshaft-200 items-center py-8 justify-center space-x-2 rounded-md bg-mineshaft-900 px-2 mx-0.5 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100',
|
className={twMerge(
|
||||||
isDragActive && 'opacity-100',
|
'relative mb-4 mt-4 max-w-[calc(100vw-292px)] flex w-full cursor-pointer text-mineshaft-200 items-center py-8 justify-center space-x-2 rounded-md bg-mineshaft-900 px-2 opacity-60 outline-dashed outline-2 outline-chicago-600 duration-200 hover:opacity-100',
|
||||||
!isSmaller && 'flex-col space-y-4 max-w-3xl py-20',
|
isDragActive && 'opacity-100',
|
||||||
isLoading && 'bg-bunker-800'
|
!isSmaller && 'flex-col space-y-4 max-w-3xl py-20',
|
||||||
)}
|
isLoading && 'bg-bunker-800'
|
||||||
>
|
)}
|
||||||
{isLoading ? (
|
>
|
||||||
<div className="mb-16 flex items-center justify-center pt-16">
|
{isLoading ? (
|
||||||
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
<div className="mb-16 flex items-center justify-center pt-16">
|
||||||
</div>
|
<img src="/images/loading/loading.gif" height={70} width={120} alt="loading animation" />
|
||||||
) : (
|
|
||||||
<>
|
|
||||||
<div>
|
|
||||||
<FontAwesomeIcon icon={faUpload} size={isSmaller ? '2x' : '5x'} />
|
|
||||||
</div>
|
</div>
|
||||||
<div>
|
) : (
|
||||||
<p className="">{t(isSmaller ? 'common:drop-zone-keys' : 'common:drop-zone')}</p>
|
<>
|
||||||
</div>
|
<div>
|
||||||
<input
|
<FontAwesomeIcon icon={faUpload} size={isSmaller ? '2x' : '5x'} />
|
||||||
id="fileSelect"
|
</div>
|
||||||
type="file"
|
<div>
|
||||||
className="absolute h-full w-full cursor-pointer opacity-0"
|
<p className="">{t(isSmaller ? 'common:drop-zone-keys' : 'common:drop-zone')}</p>
|
||||||
accept=".txt,.env,.yml,.yaml"
|
</div>
|
||||||
onChange={handleFileUpload}
|
<input
|
||||||
/>
|
id="fileSelect"
|
||||||
{!isSmaller && (
|
type="file"
|
||||||
<>
|
className="absolute h-full w-full cursor-pointer opacity-0"
|
||||||
<div className="flex w-full flex-row items-center justify-center py-4">
|
accept=".txt,.env,.yml,.yaml"
|
||||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
onChange={handleFileUpload}
|
||||||
<p className="mx-4 text-xs text-mineshaft-400">OR</p>
|
/>
|
||||||
<div className="w-1/5 border-t border-mineshaft-700" />
|
{!isSmaller && (
|
||||||
</div>
|
<>
|
||||||
<div>
|
<div className="flex w-full flex-row items-center justify-center py-4">
|
||||||
<Button variant="star" onClick={onAddNewSecret}>
|
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||||
Add a new secret
|
<p className="mx-4 text-xs text-mineshaft-400">OR</p>
|
||||||
</Button>
|
<div className="w-1/5 border-t border-mineshaft-700" />
|
||||||
</div>
|
</div>
|
||||||
</>
|
<div>
|
||||||
)}{' '}
|
<Button variant="star" onClick={onAddNewSecret}>
|
||||||
</>
|
Add a new secret
|
||||||
)}
|
</Button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}{' '}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
faComment,
|
faComment,
|
||||||
faEllipsis,
|
faEllipsis,
|
||||||
faInfoCircle,
|
faInfoCircle,
|
||||||
|
faKey,
|
||||||
faPlus,
|
faPlus,
|
||||||
faTags,
|
faTags,
|
||||||
faXmark
|
faXmark
|
||||||
@@ -158,8 +159,9 @@ export const SecretInputRow = memo(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<tr className="group flex flex-row items-center" key={index}>
|
<tr className="group flex flex-row items-center" key={index}>
|
||||||
<td className="flex h-10 w-10 items-center justify-center px-4">
|
<td className="flex h-10 w-10 items-center justify-center px-4 border-none">
|
||||||
<div className="w-10 text-center text-xs text-bunker-400">{index + 1}</div>
|
{/* <div className="w-10 text-center text-xs text-bunker-400">{index + 1}</div> */}
|
||||||
|
<div className="w-10 text-center text-xs text-bunker-400"><FontAwesomeIcon icon={faKey} className="w-4 h-4 text-bunker-400/60 pl-2.5 pt-0.5" /></div>
|
||||||
</td>
|
</td>
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
@@ -184,65 +186,6 @@ export const SecretInputRow = memo(
|
|||||||
field.onBlur();
|
field.onBlur();
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="flex w-max flex-row items-center justify-end">
|
|
||||||
<Tooltip content="Comment">
|
|
||||||
<div
|
|
||||||
className={`${
|
|
||||||
hasComment ? 'w-5' : 'w-0'
|
|
||||||
} mt-0.5 overflow-hidden group-hover:w-5`}
|
|
||||||
>
|
|
||||||
<Popover>
|
|
||||||
<PopoverTrigger asChild>
|
|
||||||
<IconButton
|
|
||||||
className={twMerge(
|
|
||||||
'w-0 overflow-hidden p-0 group-hover:w-5',
|
|
||||||
hasComment && 'w-5 text-primary'
|
|
||||||
)}
|
|
||||||
variant="plain"
|
|
||||||
size="md"
|
|
||||||
ariaLabel="add-tag"
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faComment} />
|
|
||||||
</IconButton>
|
|
||||||
</PopoverTrigger>
|
|
||||||
<PopoverContent className="w-auto border border-mineshaft-600 bg-mineshaft-800 p-2 drop-shadow-2xl">
|
|
||||||
<FormControl label="Comment" className="mb-0">
|
|
||||||
<TextArea
|
|
||||||
isDisabled={
|
|
||||||
isReadOnly || isRollbackMode || shouldBeBlockedInAddOnly
|
|
||||||
}
|
|
||||||
className="border border-mineshaft-600 text-sm"
|
|
||||||
{...register(`secrets.${index}.comment`)}
|
|
||||||
rows={8}
|
|
||||||
cols={30}
|
|
||||||
/>
|
|
||||||
</FormControl>
|
|
||||||
</PopoverContent>
|
|
||||||
</Popover>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
{!isAddOnly && (
|
|
||||||
<div>
|
|
||||||
<Tooltip content="Override with a personal value">
|
|
||||||
<IconButton
|
|
||||||
variant="plain"
|
|
||||||
className={twMerge(
|
|
||||||
'mt-0.5 w-0 overflow-hidden p-0 group-hover:ml-1 group-hover:w-6',
|
|
||||||
isOverridden && 'ml-1 w-6 text-primary'
|
|
||||||
)}
|
|
||||||
onClick={onSecretOverride}
|
|
||||||
size="md"
|
|
||||||
isDisabled={isRollbackMode || isReadOnly}
|
|
||||||
ariaLabel="info"
|
|
||||||
>
|
|
||||||
<div className="flex items-center space-x-1">
|
|
||||||
<FontAwesomeIcon icon={faCodeBranch} className="text-base" />
|
|
||||||
</div>
|
|
||||||
</IconButton>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</HoverCardTrigger>
|
</HoverCardTrigger>
|
||||||
@@ -257,7 +200,7 @@ export const SecretInputRow = memo(
|
|||||||
</HoverCard>
|
</HoverCard>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<td className="flex h-8 w-full flex-grow flex-row items-center justify-center">
|
<td className="flex h-10 border-none w-full flex-grow flex-row items-center justify-center border-r border-red">
|
||||||
<MaskedInput
|
<MaskedInput
|
||||||
isReadOnly={
|
isReadOnly={
|
||||||
isReadOnly || isRollbackMode || (isOverridden ? isAddOnly : shouldBeBlockedInAddOnly)
|
isReadOnly || isRollbackMode || (isOverridden ? isAddOnly : shouldBeBlockedInAddOnly)
|
||||||
@@ -283,14 +226,14 @@ export const SecretInputRow = memo(
|
|||||||
</Tag>
|
</Tag>
|
||||||
))}
|
))}
|
||||||
{!(isReadOnly || isAddOnly || isRollbackMode) && (
|
{!(isReadOnly || isAddOnly || isRollbackMode) && (
|
||||||
<div className="w-0 overflow-hidden group-hover:w-8">
|
<div className="overflow-hidden duration-0 ml-1">
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<div>
|
<div className="w-0 data-[state=open]:w-6 group-hover:w-6">
|
||||||
<Tooltip content="Add tags">
|
<Tooltip content="Add tags">
|
||||||
<IconButton
|
<IconButton
|
||||||
variant="star"
|
variant="plain"
|
||||||
size="xs"
|
size="md"
|
||||||
ariaLabel="add-tag"
|
ariaLabel="add-tag"
|
||||||
className="py-[0.42rem]"
|
className="py-[0.42rem]"
|
||||||
>
|
>
|
||||||
@@ -348,9 +291,67 @@ export const SecretInputRow = memo(
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="duration-0 invisible flex w-0 items-center justify-end space-x-2 overflow-hidden transition-all group-hover:visible group-hover:w-14">
|
<div className="flex flex-row items-center h-full pr-2">
|
||||||
{!isAddOnly && (
|
{!isAddOnly && (
|
||||||
<div>
|
<div>
|
||||||
|
<Tooltip content="Override with a personal value">
|
||||||
|
<IconButton
|
||||||
|
variant="plain"
|
||||||
|
className={twMerge(
|
||||||
|
'mt-0.5 w-0 overflow-hidden p-0 group-hover:ml-1 group-hover:w-7',
|
||||||
|
isOverridden && 'ml-1 w-7 text-primary'
|
||||||
|
)}
|
||||||
|
onClick={onSecretOverride}
|
||||||
|
size="md"
|
||||||
|
isDisabled={isRollbackMode || isReadOnly}
|
||||||
|
ariaLabel="info"
|
||||||
|
>
|
||||||
|
<div className="flex items-center space-x-1">
|
||||||
|
<FontAwesomeIcon icon={faCodeBranch} className="text-base" />
|
||||||
|
</div>
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<Tooltip content="Comment">
|
||||||
|
<div
|
||||||
|
className={`mt-0.5 overflow-hidden `}
|
||||||
|
>
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<IconButton
|
||||||
|
className={twMerge(
|
||||||
|
'overflow-hidden p-0 w-7',
|
||||||
|
'data-[state=open]:w-7 group-hover:w-7 w-0',
|
||||||
|
hasComment ? 'text-primary w-7' : 'group-hover:w-7'
|
||||||
|
)}
|
||||||
|
variant="plain"
|
||||||
|
size="md"
|
||||||
|
ariaLabel="add-tag"
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faComment} />
|
||||||
|
</IconButton>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-auto border border-mineshaft-600 bg-mineshaft-800 p-2 drop-shadow-2xl" sticky="always">
|
||||||
|
<FormControl label="Comment" className="mb-0">
|
||||||
|
<TextArea
|
||||||
|
isDisabled={
|
||||||
|
isReadOnly || isRollbackMode || shouldBeBlockedInAddOnly
|
||||||
|
}
|
||||||
|
className="border border-mineshaft-600 text-sm"
|
||||||
|
{...register(`secrets.${index}.comment`)}
|
||||||
|
rows={8}
|
||||||
|
cols={30}
|
||||||
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
<div className="duration-0 w-0 flex items-center justify-end space-x-2.5 overflow-hidden transition-all w-16 border-l border-mineshaft-600 h-10">
|
||||||
|
{!isAddOnly && (
|
||||||
|
<div className="opacity-0 group-hover:opacity-100">
|
||||||
<Tooltip content="Settings">
|
<Tooltip content="Settings">
|
||||||
<IconButton
|
<IconButton
|
||||||
size="lg"
|
size="lg"
|
||||||
@@ -364,7 +365,7 @@ export const SecretInputRow = memo(
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<div className="opacity-0 group-hover:opacity-100">
|
||||||
<Tooltip content="Delete">
|
<Tooltip content="Delete">
|
||||||
<IconButton
|
<IconButton
|
||||||
size="md"
|
size="md"
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ type Props = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const SecretTableHeader = ({ sortDir, onSort }: Props): JSX.Element => (
|
export const SecretTableHeader = ({ sortDir, onSort }: Props): JSX.Element => (
|
||||||
<thead>
|
<thead className="sticky top-0 z-50 bg-mineshaft-800">
|
||||||
<tr className="sticky top-0 flex flex-row">
|
<tr className="top-0 flex flex-row">
|
||||||
<td className="flex w-10 items-center justify-center px-4">
|
<td className="flex w-10 items-center justify-center px-4 border-none">
|
||||||
<div className="w-10 text-center text-xs text-transparent">{0}</div>
|
<div className="w-10 text-center text-xs text-transparent">{0}</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="flex items-center">
|
<td className="flex items-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user