From 810554e13c8fe4c67d80787b741719ec8102d26e Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Wed, 12 Apr 2023 13:41:12 -0700 Subject: [PATCH] First commit of env overview --- frontend/src/components/v2/Button/Button.tsx | 6 + frontend/src/components/v2/Table/Table.tsx | 2 +- .../src/ee/components/SecretVersionList.tsx | 4 +- frontend/src/hooks/api/secrets/queries.tsx | 71 ++++- frontend/src/hooks/api/secrets/types.ts | 2 +- frontend/src/layouts/AppLayout/AppLayout.tsx | 7 +- frontend/src/pages/dashboard/[id].tsx | 6 +- .../DashboardPage/DashboardEnvOverview.tsx | 269 ++++++++++++++++++ .../EnvComparisonHeader/EnvComparison.tsx | 22 ++ .../components/EnvComparisonHeader/index.tsx | 1 + .../EnvComparisonRow/EnvComparisonRow.tsx | 153 ++++++++++ .../components/EnvComparisonRow/index.tsx | 1 + 12 files changed, 524 insertions(+), 20 deletions(-) create mode 100644 frontend/src/views/DashboardPage/DashboardEnvOverview.tsx create mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonHeader/EnvComparison.tsx create mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx create mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx create mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonRow/index.tsx diff --git a/frontend/src/components/v2/Button/Button.tsx b/frontend/src/components/v2/Button/Button.tsx index c4a89023c..17ae7b867 100644 --- a/frontend/src/components/v2/Button/Button.tsx +++ b/frontend/src/components/v2/Button/Button.tsx @@ -34,6 +34,7 @@ const buttonVariants = cva( outline: ['bg-transparent', 'border-2', 'border-solid'], plain: '', selected: '', + outline_bg: '', // a constant color not in use on hover or click goes colorSchema color star: 'text-bunker-200 bg-mineshaft-500' }, @@ -67,6 +68,11 @@ const buttonVariants = cva( variant: 'selected', className: 'bg-primary/10 border border-primary/50 text-bunker-200' }, + { + colorSchema: 'primary', + variant: 'outline_bg', + className: 'bg-mineshaft-800 border border-mineshaft-600 hover:bg-primary/[0.15] hover:border-primary/60 text-bunker-200' + }, { colorSchema: 'secondary', variant: 'star', diff --git a/frontend/src/components/v2/Table/Table.tsx b/frontend/src/components/v2/Table/Table.tsx index dd4bb4e7b..411fffab1 100644 --- a/frontend/src/components/v2/Table/Table.tsx +++ b/frontend/src/components/v2/Table/Table.tsx @@ -34,7 +34,7 @@ export type TableProps = { export const Table = ({ children, className }: TableProps): JSX.Element => ( diff --git a/frontend/src/ee/components/SecretVersionList.tsx b/frontend/src/ee/components/SecretVersionList.tsx index 3f16a228d..dbf7c5bf2 100644 --- a/frontend/src/ee/components/SecretVersionList.tsx +++ b/frontend/src/ee/components/SecretVersionList.tsx @@ -76,7 +76,7 @@ const SecretVersionList = ({ secretId }: { secretId: string }) => { }, [secretId]); return ( -
+

{t('dashboard:sidebar.version-history')}

{isLoading ? ( @@ -102,7 +102,7 @@ const SecretVersionList = ({ secretId }: { secretId: string }) => {
-
+
{new Date(version.createdAt).toLocaleDateString('en-US', { year: 'numeric', month: '2-digit', diff --git a/frontend/src/hooks/api/secrets/queries.tsx b/frontend/src/hooks/api/secrets/queries.tsx index 9b9c49df5..bc4c5e515 100644 --- a/frontend/src/hooks/api/secrets/queries.tsx +++ b/frontend/src/hooks/api/secrets/queries.tsx @@ -19,18 +19,66 @@ import { export const secretKeys = { // this is also used in secretSnapshot part - getProjectSecret: (workspaceId: string, env: string) => [{ workspaceId, env }, 'secrets'], + getProjectSecret: (workspaceId: string, env: string | string[]) => [{ workspaceId, env }, 'secrets'], getSecretVersion: (secretId: string) => [{ secretId }, 'secret-versions'] }; -const fetchProjectEncryptedSecrets = async (workspaceId: string, env: string) => { - const { data } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { - params: { - environment: env, - workspaceId +const fetchProjectEncryptedSecrets = async (workspaceId: string, env: string | string[]) => { + if (typeof env === 'string') { + const { data } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { + params: { + environment: env, + workspaceId + } + }); + return data.secrets; + } + + if (typeof env === 'object') { + let allEnvData: any = []; + // env.map(async (envPoint: string) => { + // const { data } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { + // params: { + // environment: envPoint, + // workspaceId + // } + // }); + // console.log(111, envPoint, data.secrets) + // allEnvData = allEnvData.concat(data.secrets); + // // await allEnvData.push(...data.secrets) + // console.log(222, allEnvData) + // }) + // eslint-disable-next-line no-restricted-syntax + for (const envPoint of env) { + // eslint-disable-next-line no-await-in-loop + const { data } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { + params: { + environment: envPoint, + workspaceId + } + }); + allEnvData = allEnvData.concat(data.secrets); } - }); - return data.secrets; + // const { data: data1 } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { + // params: { + // environment: env[0], + // workspaceId + // } + // }); + // const { data: data2 } = await apiRequest.get<{ secrets: EncryptedSecret[] }>('/api/v2/secrets', { + // params: { + // environment: env[1], + // workspaceId + // } + // }); + // allEnvData = data1.secrets.concat(data2.secrets); + + return allEnvData; + // eslint-disable-next-line no-else-return + } else { + return null; + } + }; export const useGetProjectSecrets = ({ @@ -45,6 +93,7 @@ export const useGetProjectSecrets = ({ queryKey: secretKeys.getProjectSecret(workspaceId, env), queryFn: () => fetchProjectEncryptedSecrets(workspaceId, env), select: (data) => { + console.log(878787878, data) const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY') as string; const latestKey = decryptFileKey; const key = decryptAssymmetric({ @@ -93,12 +142,12 @@ export const useGetProjectSecrets = ({ }; if (encSecret.type === 'personal') { - personalSecrets[decryptedSecret.key] = { id: encSecret._id, value: secretValue }; + personalSecrets[`${decryptedSecret.key}-${decryptedSecret.env}`] = { id: encSecret._id, value: secretValue }; } else { - if (!duplicateSecretKey?.[decryptedSecret.key]) { + if (!duplicateSecretKey?.[`${decryptedSecret.key}-${decryptedSecret.env}`]) { sharedSecrets.push(decryptedSecret); } - duplicateSecretKey[decryptedSecret.key] = true; + duplicateSecretKey[`${decryptedSecret.key}-${decryptedSecret.env}`] = true; } }); sharedSecrets.forEach((val) => { diff --git a/frontend/src/hooks/api/secrets/types.ts b/frontend/src/hooks/api/secrets/types.ts index 7888e64b3..567fecc9a 100644 --- a/frontend/src/hooks/api/secrets/types.ts +++ b/frontend/src/hooks/api/secrets/types.ts @@ -90,7 +90,7 @@ export type BatchSecretDTO = { export type GetProjectSecretsDTO = { workspaceId: string; - env: string; + env: string | string[]; decryptFileKey: UserWsKeyPair; isPaused?: boolean; onSuccess?: (data: DecryptedSecret[]) => void; diff --git a/frontend/src/layouts/AppLayout/AppLayout.tsx b/frontend/src/layouts/AppLayout/AppLayout.tsx index 93ed5b860..3e3641a0a 100644 --- a/frontend/src/layouts/AppLayout/AppLayout.tsx +++ b/frontend/src/layouts/AppLayout/AppLayout.tsx @@ -271,11 +271,12 @@ export const AppLayout = ({ children }: LayoutProps) => { {name} ))} -
+ {/*
*/}
+ + + {[... new Set(secrets?.secrets.map((secret: any) => secret.key))].map((key, index) => ( + secret.key === key)} + isReadOnly={isReadOnly} + isAddOnly={isAddOnly} + index={index} + isSecretValueHidden={isSecretValueHidden} + userAvailableEnvs={userAvailableEnvs} + /> + ))} + + + + + + {userAvailableEnvs?.map(env => { + return <> + + + + })} + + +
0
+
1
+
+
{0}
+
+ +
+ + )} + {/*
+ +
*/} + + + { + handlePopUpToggle('addTag', open); + }} + > + + + + + + + ); +}; diff --git a/frontend/src/views/DashboardPage/components/EnvComparisonHeader/EnvComparison.tsx b/frontend/src/views/DashboardPage/components/EnvComparisonHeader/EnvComparison.tsx new file mode 100644 index 000000000..136085d26 --- /dev/null +++ b/frontend/src/views/DashboardPage/components/EnvComparisonHeader/EnvComparison.tsx @@ -0,0 +1,22 @@ +export const EnvComparisonHeader = ({ userAvailableEnvs }: { userAvailableEnvs?: any[] }): JSX.Element => ( + + + +
{0}
+ + +
+
Secret
+
+ + {userAvailableEnvs?.map(env => { + return <> + +
{0}
+ +
{env.name}
+ + })} + + +); diff --git a/frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx b/frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx new file mode 100644 index 000000000..0bba0fb5f --- /dev/null +++ b/frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx @@ -0,0 +1 @@ +export { EnvComparisonHeader } from './EnvComparison'; diff --git a/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx b/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx new file mode 100644 index 000000000..8dbe32bf3 --- /dev/null +++ b/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx @@ -0,0 +1,153 @@ +/* eslint-disable react/jsx-no-useless-fragment */ +import { SyntheticEvent, useRef } from 'react'; +import { useFormContext, useWatch } from 'react-hook-form'; +import { faCircle } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; + +import guidGenerator from '@app/components/utilities/randomId'; +import { Input } from '@app/components/v2'; + +import { FormData, SecretActionType } from '../../DashboardPage.utils'; + +type Props = { + index: number; + secrets: any[] | undefined; + // permission and external state's that decided to hide or show + isReadOnly?: boolean; + isAddOnly?: boolean; + isSecretValueHidden: boolean; + userAvailableEnvs?: any[]; +}; + +const REGEX = /([$]{.*?})/g; + +const DashboardInput = ({ isOverridden, isSecretValueHidden, isAddOnly, isReadOnly, secret, shouldBeBlockedInAddOnly, index }: { isOverridden: boolean, isSecretValueHidden: boolean, isAddOnly?: boolean, isReadOnly?: boolean, secret: any, shouldBeBlockedInAddOnly?: boolean, index: number } ): JSX.Element => { + const ref = useRef(null); + const syncScroll = (e: SyntheticEvent) => { + if (ref.current === null) return; + + ref.current.scrollTop = e.currentTarget.scrollTop; + ref.current.scrollLeft = e.currentTarget.scrollLeft; + }; + console.log(33333333, secret) + + return +
+ +
+ {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').length === 0 && EMPTY} + {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split(REGEX).map((word: string) => { + if (word.match(REGEX) !== null) { + return ( + + {word.slice(0, 2)} + + {word.slice(2, word.length - 1)} + + {word.slice(word.length - 1, word.length) === '}' ? ( + + {word.slice(word.length - 1, word.length)} + + ) : ( + + {word.slice(word.length - 1, word.length)} + + )} + + ); + } + return ( + + {word} + + ); + })} +
+ {(isSecretValueHidden && secret?.value) && ( +
+
+ {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').map(() => ( + + ))} + {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').length === 0 && EMPTY} +
+
+ )} +
+ +} + +export const EnvComparisonRow = ({ + index, + secrets, + isSecretValueHidden, + isReadOnly, + isAddOnly, + userAvailableEnvs +}: Props): JSX.Element => { + const { + // register, setValue, + control } = useFormContext(); + console.log(1282828822, userAvailableEnvs) + + console.log('index', index) + // to get details on a secret + const secret = useWatch({ name: `secrets.${index}`, control }); + + // when secret is override by personal values + const isOverridden = + secret.overrideAction === SecretActionType.Created || + secret.overrideAction === SecretActionType.Modified; + + const isCreatedSecret = !secret?._id; + const shouldBeBlockedInAddOnly = !isCreatedSecret && isAddOnly; + console.log(893892749827097, secrets) + + return ( + +
{index + 1}
+ +
+ +
+ + {userAvailableEnvs?.map(env => { + return <> + +
{0}
+ + sec.env === env.slug)[0]} shouldBeBlockedInAddOnly={shouldBeBlockedInAddOnly} index={index} /> + + })} + + ); +}; diff --git a/frontend/src/views/DashboardPage/components/EnvComparisonRow/index.tsx b/frontend/src/views/DashboardPage/components/EnvComparisonRow/index.tsx new file mode 100644 index 000000000..e0c9f8847 --- /dev/null +++ b/frontend/src/views/DashboardPage/components/EnvComparisonRow/index.tsx @@ -0,0 +1 @@ +export { EnvComparisonRow } from './EnvComparisonRow';