From 903560a2d17fe22814a10f6eb57ba58d83d4794c Mon Sep 17 00:00:00 2001 From: Vladyslav Matsiiako Date: Fri, 14 Apr 2023 18:20:19 -0700 Subject: [PATCH] Finished the env overview feature --- frontend/src/components/analytics/posthog.ts | 2 +- .../src/components/navigation/NavHeader.tsx | 59 ++++- frontend/src/components/v2/Select/Select.tsx | 6 +- frontend/src/components/v2/Table/Table.tsx | 2 +- frontend/src/hooks/api/secrets/queries.tsx | 29 +-- frontend/src/pages/dashboard/[id].tsx | 13 +- .../DashboardPage/DashboardEnvOverview.tsx | 236 +++++++++--------- .../src/views/DashboardPage/DashboardPage.tsx | 34 +-- .../EnvComparisonHeader/EnvComparison.tsx | 22 -- .../components/EnvComparisonHeader/index.tsx | 1 - .../EnvComparisonRow/EnvComparisonRow.tsx | 68 ++--- .../SecretInputRow/SecretInputRow.tsx | 4 +- .../SecretTagsSection/SecretTagsSection.tsx | 1 - 13 files changed, 222 insertions(+), 255 deletions(-) delete mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonHeader/EnvComparison.tsx delete mode 100644 frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx diff --git a/frontend/src/components/analytics/posthog.ts b/frontend/src/components/analytics/posthog.ts index 29208a795..b6f3e4341 100644 --- a/frontend/src/components/analytics/posthog.ts +++ b/frontend/src/components/analytics/posthog.ts @@ -6,7 +6,7 @@ import { ENV, POSTHOG_API_KEY, POSTHOG_HOST } from '../utilities/config'; export const initPostHog = () => { // @ts-ignore - console.log("Init Infisical") + console.log("Hi there 👋") try { if (typeof window !== 'undefined') { // @ts-ignore diff --git a/frontend/src/components/navigation/NavHeader.tsx b/frontend/src/components/navigation/NavHeader.tsx index e1ee09080..c8af1ce46 100644 --- a/frontend/src/components/navigation/NavHeader.tsx +++ b/frontend/src/components/navigation/NavHeader.tsx @@ -1,52 +1,89 @@ +import { useRouter } from 'next/router'; import { faAngleRight } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { useOrganization, useWorkspace } from '@app/context'; +import { Select, SelectItem, Tooltip } from '../v2'; + // TODO: make links clickable and clean up /** * This is the component at the top of almost every page. * It shows how to navigate to a certain page. * It future these links should also be clickable and hoverable - * @param obj - * @param obj.pageName - Name of the page - * @param obj.isProjectRelated - whether or not this page is related to project (determine if it's 2 or 3 navigation steps) - * @param obj.isOrganizationRelated - whether or not this page is related to organization (determine if it's 2 or 3 navigation steps) + * @param {object} obj + * @param {string} obj.pageName - Name of the page + * @param {boolean} obj.isProjectRelated - whether or not this page is related to project (determine if it's 2 or 3 navigation steps) + * @param {boolean} obj.isOrganizationRelated - whether or not this page is related to organization (determine if it's 2 or 3 navigation steps) + * @param {string} obj.currentEnv - current environment inside a project + * @param {string} obj.userAvailableEnvs - environments that are available to a user in this project (used for the dropdown) + * @param {string} obj.onEnvChange - the action that happens when an env is changed * @returns */ export default function NavHeader({ pageName, isProjectRelated, - isOrganizationRelated + isOrganizationRelated, + currentEnv, + userAvailableEnvs, + onEnvChange }: { pageName: string; isProjectRelated?: boolean; isOrganizationRelated?: boolean; + currentEnv?: string; + userAvailableEnvs?: any[]; + onEnvChange?: (slug: string) => void; }): JSX.Element { const { currentWorkspace } = useWorkspace(); const { currentOrg } = useOrganization(); + const router = useRouter() return (
{currentOrg?.name?.charAt(0)}
-
{currentOrg?.name}
+
{currentOrg?.name}
{isProjectRelated && ( <> - -
{currentWorkspace?.name}
+ +
{currentWorkspace?.name}
)} {isOrganizationRelated && ( <> - -
Organization Settings
+ +
Organization Settings
)} -
{pageName}
+ {pageName === 'Secrets' + ? {pageName} + :
{pageName}
} + {currentEnv && + <> + +
+ + + +
+ }
); } diff --git a/frontend/src/components/v2/Select/Select.tsx b/frontend/src/components/v2/Select/Select.tsx index ffeaf3c3f..46cd3fb03 100644 --- a/frontend/src/components/v2/Select/Select.tsx +++ b/frontend/src/components/v2/Select/Select.tsx @@ -1,6 +1,6 @@ import { forwardRef, ReactNode } from 'react'; import { IconProp } from '@fortawesome/fontawesome-svg-core'; -import { faCheck, faChevronDown, faChevronUp } from '@fortawesome/free-solid-svg-icons'; +import { faCaretDown, faCheck, faChevronUp } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import * as SelectPrimitive from '@radix-ui/react-select'; import { twMerge } from 'tailwind-merge'; @@ -49,7 +49,7 @@ export const Select = forwardRef( {!isDisabled && ( - + )} @@ -76,7 +76,7 @@ export const Select = forwardRef( )} - + diff --git a/frontend/src/components/v2/Table/Table.tsx b/frontend/src/components/v2/Table/Table.tsx index 411fffab1..dd4bb4e7b 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/hooks/api/secrets/queries.tsx b/frontend/src/hooks/api/secrets/queries.tsx index bc4c5e515..031c661d1 100644 --- a/frontend/src/hooks/api/secrets/queries.tsx +++ b/frontend/src/hooks/api/secrets/queries.tsx @@ -36,18 +36,7 @@ const fetchProjectEncryptedSecrets = async (workspaceId: string, env: string | s 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 @@ -59,19 +48,6 @@ const fetchProjectEncryptedSecrets = async (workspaceId: string, env: string | s }); allEnvData = allEnvData.concat(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 @@ -93,7 +69,6 @@ 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({ @@ -108,7 +83,7 @@ export const useGetProjectSecrets = ({ // this used for add-only mode in dashboard // type won't be there thus only one key is shown const duplicateSecretKey: Record = {}; - data.forEach((encSecret) => { + data.forEach((encSecret: EncryptedSecret) => { const secretKey = decryptSymmetric({ ciphertext: encSecret.secretKeyCiphertext, iv: encSecret.secretKeyIV, diff --git a/frontend/src/pages/dashboard/[id].tsx b/frontend/src/pages/dashboard/[id].tsx index e73d3033e..bb81245ec 100644 --- a/frontend/src/pages/dashboard/[id].tsx +++ b/frontend/src/pages/dashboard/[id].tsx @@ -1,12 +1,18 @@ import Head from 'next/head'; +import { useRouter } from 'next/router'; import { useTranslation } from 'next-i18next'; +import queryString from 'query-string'; import { getTranslatedServerSideProps } from '@app/components/utilities/withTranslateProps'; -// import { DashboardPage } from '@app/views/DashboardPage'; +import { DashboardPage } from '@app/views/DashboardPage'; import { DashboardEnvOverview } from '@app/views/DashboardPage/DashboardEnvOverview'; const Dashboard = () => { const { t } = useTranslation(); + const router = useRouter(); + + const env = queryString.parse(router.asPath.split('?')[1])?.env; + return ( <> @@ -16,8 +22,9 @@ const Dashboard = () => { - {/* */} - + {env + ? + : } ); }; diff --git a/frontend/src/views/DashboardPage/DashboardEnvOverview.tsx b/frontend/src/views/DashboardPage/DashboardEnvOverview.tsx index 75f79db9f..a7545fb1c 100644 --- a/frontend/src/views/DashboardPage/DashboardEnvOverview.tsx +++ b/frontend/src/views/DashboardPage/DashboardEnvOverview.tsx @@ -1,5 +1,5 @@ import { useEffect, useState } from 'react'; -import { FormProvider, useFieldArray, useForm, useWatch } from 'react-hook-form'; +import { FormProvider, useForm, useWatch } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useRouter } from 'next/router'; import { yupResolver } from '@hookform/resolvers/yup'; @@ -10,10 +10,11 @@ import { Button, Modal, ModalContent, - TableContainer + TableContainer, + Tooltip } from '@app/components/v2'; import { useWorkspace } from '@app/context'; -import { usePopUp, useToggle } from '@app/hooks'; +import { usePopUp } from '@app/hooks'; import { useCreateWsTag, useGetProjectSecrets, @@ -23,26 +24,13 @@ import { import { WorkspaceEnv } from '@app/hooks/api/types'; import { CreateTagModal } from './components/CreateTagModal'; -import { EnvComparisonHeader } from './components/EnvComparisonHeader'; import { EnvComparisonRow } from './components/EnvComparisonRow'; import { - DEFAULT_SECRET_VALUE, FormData, schema } from './DashboardPage.utils'; -/* - * Some imp aspects to consider. Here there are multiple stats changing - * Thus ideally we need to use a context. But instead we rely on react hook form - * React hook form provides context and high performance proxy based rendering - * It also handles error handling and transferring states between inputs - * - * Another thing is the purpose of overrideAction - * Before we would remove the value for personal secret when user toggle and user couldn't get it back - * They have to reload the browser or go back all over again - * Instead when user delete we raise a flag so if user decides to go back to toggle personal before saving - * They will get it back - */ + export const DashboardEnvOverview = () => { const { t } = useTranslation(); const router = useRouter(); @@ -57,11 +45,7 @@ export const DashboardEnvOverview = () => { 'uploadedSecOpts', 'compareSecrets' ] as const); - const [isSecretValueHidden, setIsSecretValueHidden] = useToggle(true); - const [snapshotId, setSnaphotId] = useState(null); - console.log(setIsSecretValueHidden, setSnaphotId) const [selectedEnv, setSelectedEnv] = useState(null); - // const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc'); const { currentWorkspace, isLoading } = useWorkspace(); const workspaceId = currentWorkspace?._id as string; @@ -77,26 +61,25 @@ export const DashboardEnvOverview = () => { workspaceId, onSuccess: (data) => { // get an env with one of the access available - const env = data.find(({ isReadDenied, isWriteDenied }) => !isWriteDenied || !isReadDenied); + const env = data.find(({ isReadDenied }) => !isReadDenied); if (env) { setSelectedEnv(env); } } }); + + const userAvailableEnvs = wsEnv?.filter( + ({ isReadDenied }) => !isReadDenied + ); const { data: secrets, isLoading: isSecretsLoading } = useGetProjectSecrets({ workspaceId, - env: wsEnv?.map(env => env.slug) ?? [], + env: userAvailableEnvs?.map(env => env.slug) ?? [], decryptFileKey: latestFileKey!, - isPaused: Boolean(snapshotId) + isPaused: false }); - console.log(333333, secrets, [... new Set(secrets?.secrets.map((secret: any) => secret.key))]) - // mutation calls - // const { mutateAsync: batchSecretOp } = useBatchSecretsOp(); - // const { mutateAsync: performSecretRollback } = usePerformSecretRollback(); - // const { mutateAsync: registerUserAction } = useRegisterUserAction(); const { mutateAsync: createWsTag } = useCreateWsTag(); const method = useForm({ @@ -116,27 +99,8 @@ export const DashboardEnvOverview = () => { // reset } = method; const formSecrets = useWatch({ control, name: 'secrets' }); - console.log(formSecrets) - const { fields, prepend, - // append, remove, update - } = useFieldArray({ control, name: 'secrets' }); - console.log(987, fields, secrets?.secrets.map((secret: any) => secret.key)) - const isRollbackMode = Boolean(snapshotId); const isReadOnly = selectedEnv?.isWriteDenied; - const isAddOnly = selectedEnv?.isReadDenied && !selectedEnv?.isWriteDenied; - // const canDoRollback = !isReadOnly && !isAddOnly; - - - // const onSortSecrets = () => { - // const dir = sortDir === 'asc' ? 'desc' : 'asc'; - // const sec = getValues('secrets') || []; - // const sortedSec = sec.sort((a, b) => - // dir === 'asc' ? a?.key?.localeCompare(b?.key || '') : b?.key?.localeCompare(a?.key || '') - // ); - // setValue('secrets', sortedSec); - // setSortDir(dir); - // }; const onCreateWsTag = async (tagName: string) => { try { @@ -169,11 +133,8 @@ export const DashboardEnvOverview = () => { // when secrets is not loading and secrets list is empty const isDashboardSecretEmpty = !isSecretsLoading && !formSecrets?.length; - const isSecretEmpty = (!isRollbackMode && isDashboardSecretEmpty); - const userAvailableEnvs = wsEnv?.filter( - ({ isReadDenied, isWriteDenied }) => !isReadDenied || !isWriteDenied - ); + const numSecretsMissingPerEnv = userAvailableEnvs?.map(envir => ({[envir.slug]: [... new Set(secrets?.secrets.map((secret: any) => secret.key))].length - [... new Set(secrets?.secrets.filter(s => s.env === envir.slug).map((secret: any) => secret.key))].length})).reduce((acc, cur) => ({ ...acc, ...cur }), {}) return (
@@ -183,71 +144,116 @@ export const DashboardEnvOverview = () => {
-
+

Secrets Overview

-

Put your secrets to work with the Infisical CLI

-
-
- {!isSecretEmpty && ( - -
- - - {[... 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}
-
- -
- - )} - {/*
- -
*/} + Infisical CLI + + or + + Infisical SDKs +

+ +
+
+
+
{0}
+
+
+
+
Secret
+
+
+ {numSecretsMissingPerEnv && userAvailableEnvs?.map(env => { + return
+
+ {env.name} + {numSecretsMissingPerEnv[env.slug] > 0 &&
+ {numSecretsMissingPerEnv[env.slug]} +
} +
+
+ })} +
+
+ {!isDashboardSecretEmpty && ( + + + + {[... new Set(secrets?.secrets.map((secret: any) => secret.key))].map((key, index) => ( + secret.key === key)} + isReadOnly={isReadOnly} + index={index} + isSecretValueHidden + userAvailableEnvs={userAvailableEnvs} + /> + ))} + +
+
+ )} + {isDashboardSecretEmpty && +
+
+
{0}
+
+
+
+
Secret
+
+
+
+ No secrets are available in this project yet. + You can go into any environment to add secrets there. +
+
} + {/* In future, we should add an option to add environments here +
+ +
*/} +
+
+
0
+
+ 0 + +
+ {userAvailableEnvs?.map(env => { + return
+ +
+ })} +
{ +export const DashboardPage = ({ envFromTop }: { envFromTop: string }) => { const { t } = useTranslation(); const router = useRouter(); const { createNotification } = useNotificationContext(); @@ -126,8 +124,8 @@ export const DashboardPage = () => { onSuccess: (data) => { // get an env with one of the access available const env = data.find(({ isReadDenied, isWriteDenied }) => !isWriteDenied || !isReadDenied); - if (env) { - setSelectedEnv(env); + if (env && data?.map(wsenv => wsenv.slug).includes(envFromTop)) { + setSelectedEnv(data?.filter(dp => dp.slug === envFromTop)[0]); } } }); @@ -357,6 +355,7 @@ export const DashboardPage = () => { } const env = wsEnv?.find((el) => el.slug === slug); if (env) setSelectedEnv(env); + router.push(`${router.asPath.split("?")[0]}?env=${slug}`) }; // record all deleted ids @@ -417,7 +416,13 @@ export const DashboardPage = () => {
{/* breadcrumb row */}
- + envir.slug === envFromTop)[0].name || ''} + isProjectRelated + userAvailableEnvs={userAvailableEnvs} + onEnvChange={onEnvChange} + />
{/* Secrets, commit and save button section */}
@@ -468,23 +473,6 @@ export const DashboardPage = () => {
{/* Environment, search and other action row */}
-
- - - -
( - - - -
{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 deleted file mode 100644 index 0bba0fb5f..000000000 --- a/frontend/src/views/DashboardPage/components/EnvComparisonHeader/index.tsx +++ /dev/null @@ -1 +0,0 @@ -export { EnvComparisonHeader } from './EnvComparison'; diff --git a/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx b/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx index 8dbe32bf3..acadf600d 100644 --- a/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx +++ b/frontend/src/views/DashboardPage/components/EnvComparisonRow/EnvComparisonRow.tsx @@ -1,27 +1,25 @@ /* eslint-disable react/jsx-no-useless-fragment */ -import { SyntheticEvent, useRef } from 'react'; +import { SyntheticEvent, useRef, useState } from 'react'; import { useFormContext, useWatch } from 'react-hook-form'; -import { faCircle } from '@fortawesome/free-solid-svg-icons'; +import { faCircle, faEye, faEyeSlash } 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'; +import { FormData } 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 DashboardInput = ({ isOverridden, isSecretValueHidden, isReadOnly, secret, index }: { isOverridden: boolean, isSecretValueHidden: boolean, isReadOnly?: boolean, secret: any, index: number } ): JSX.Element => { const ref = useRef(null); const syncScroll = (e: SyntheticEvent) => { if (ref.current === null) return; @@ -29,20 +27,19 @@ const DashboardInput = ({ isOverridden, isSecretValueHidden, isAddOnly, isReadOn ref.current.scrollTop = e.currentTarget.scrollTop; ref.current.scrollLeft = e.currentTarget.scrollLeft; }; - console.log(33333333, secret) - return + return
- {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').length === 0 && EMPTY} - {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split(REGEX).map((word: string) => { + {(secret?.value || secret?.value === '') && (isOverridden ? secret.valueOverride : secret?.value)?.split('').length === 0 && EMPTY} + {(secret?.value || secret?.value === '') && (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)} @@ -81,18 +78,19 @@ const DashboardInput = ({ isOverridden, isSecretValueHidden, isAddOnly, isReadOn ); })} + {!(secret?.value || secret?.value === '') && missing}
{(isSecretValueHidden && secret?.value) && (
- {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').map(() => ( + {(isOverridden ? secret.valueOverride : secret?.value || '')?.split('').map(() => ( ))} - {(isOverridden ? secret.valueOverride : secret?.value || '-')?.split('').length === 0 && EMPTY} + {(isOverridden ? secret.valueOverride : secret?.value || '')?.split('').length === 0 && EMPTY}
)} @@ -105,48 +103,28 @@ export const EnvComparisonRow = ({ 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) + const [areValuesHiddenThisRow, setAreValuesHiddenThisRow] = useState(true); return ( - -
{index + 1}
- -
- -
+ +
{index + 1}
+ +
{secret?.key || ''}
+ {userAvailableEnvs?.map(env => { - return <> - -
{0}
- - sec.env === env.slug)[0]} shouldBeBlockedInAddOnly={shouldBeBlockedInAddOnly} index={index} /> - + return sec.env === env.slug)[0]} index={index} /> })} ); diff --git a/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx b/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx index 850e8866c..f0b2cd092 100644 --- a/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx +++ b/frontend/src/views/DashboardPage/components/SecretInputRow/SecretInputRow.tsx @@ -156,7 +156,7 @@ export const SecretInputRow = ({ } return ( - +
{index + 1}
{ if (word.match(REGEX) !== null) { return ( - + {word.slice(0, 2)} {word.slice(2, word.length - 1)} diff --git a/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx b/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx index 98019e0ad..cbfc1aeed 100644 --- a/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx +++ b/frontend/src/views/Settings/ProjectSettingsPage/components/SecretTagsSection/SecretTagsSection.tsx @@ -64,7 +64,6 @@ export const SecretTagsSection = ({ }); const onFormSubmit = async (data: CreateWsTag) => { - console.log(19191, data); await onCreateTag(data); handlePopUpClose('CreateSecretTag'); };