diff --git a/package.json b/package.json index b7c95e303a..3abf91797b 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.5.8", + "@devtron-labs/devtron-fe-common-lib": "1.5.9", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rjsf/core": "^5.13.3", "@rjsf/utils": "^5.13.3", diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx index 60cb89c957..a96aff6af3 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.tsx @@ -53,6 +53,7 @@ import { ENV_CONFIG_PATH_REG } from './AppConfig.constants' const getApprovalPolicyConfigForApp: (appId: number) => Promise = importComponentFromFELibrary('getApprovalPolicyConfigForApp', null, 'function') +const isFELibAvailable: boolean = importComponentFromFELibrary('isFELibAvailable', null, 'function') export const AppConfig = ({ appName, resourceKind, filteredEnvIds }: AppConfigProps) => { // HOOKS @@ -463,7 +464,9 @@ export const AppConfig = ({ appName, resourceKind, filteredEnvIds }: AppConfigPr : 'app-compose-with-no-gitops-config__nav' } ${isJob ? 'job-compose__side-nav' : ''} ${ !showCannotDeleteTooltip ? 'dc__position-rel' : '' - } ${hideConfigHelp ? 'hide-app-config-help' : ''} ${!canShowExternalLinks ? 'hide-external-links' : ''}` + } ${hideConfigHelp ? 'hide-app-config-help' : ''} ${!canShowExternalLinks ? 'hide-external-links' : ''} ${ + state.isUnlocked.workflowEditor && isFELibAvailable && !isJob ? 'config-protection__side-nav' : '' + }` } const toggleRepoSelectionTippy = () => { diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts index a4ad43b791..5eb33ed4f6 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.types.ts @@ -44,6 +44,7 @@ export enum STAGE_NAME { SECRETS = 'SECRETS', ENV_OVERRIDE = 'ENV_OVERRIDE', EXTERNAL_LINKS = 'EXTERNAL_LINKS', + PROTECT_CONFIGURATION = 'PROTECT_CONFIGURATION', REDIRECT_ITEM = 'REDIRECT_ITEM', } diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts index 753fd3f4bd..b527a252e0 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/AppConfig.utils.ts @@ -21,7 +21,7 @@ import { BASE_CONFIGURATION_ENV_ID, } from '@devtron-labs/devtron-fe-common-lib' -import { DOCUMENTATION } from '@Config/index' +import { URLS, DOCUMENTATION } from '@Config/index' import { AppConfigStatusItemType, EnvConfigDTO } from '../../service.types' import { AppConfigState, AppStageUnlockedType, CustomNavItemsType, EnvConfigType, STAGE_NAME } from './AppConfig.types' @@ -282,6 +282,12 @@ export const getNavItems = ({ flowCompletionPercent: completedPercent, currentStep: completedSteps, }, + { + title: 'Protect Configuration', + href: URLS.GLOBAL_CONFIG_APPROVAL_POLICY, + stage: STAGE_NAME.PROTECT_CONFIGURATION, + isLocked: false, + }, { title: 'Environment Override', href: `/app/${appId}/edit/env-override`, diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/AppNavigation.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/AppNavigation.tsx index 53b9e2b577..8988a6d4b6 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/AppNavigation.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/AppNavigation.tsx @@ -27,6 +27,8 @@ import { TippyCustomized, TippyTheme, } from '@devtron-labs/devtron-fe-common-lib' +import { importComponentFromFELibrary } from '@Components/common' +import { ReactComponent as ICArrowSquareOut } from '@Icons/ic-arrow-square-out.svg' import { DEVTRON_APPS_STEPS, STAGE_NAME } from '../AppConfig.types' import { URLS } from '../../../../../../config' import AppConfigurationCheckBox from './AppConfigurationCheckBox' @@ -38,6 +40,8 @@ import { useAppConfigurationContext } from '../AppConfiguration.provider' import { renderNavItem } from './Navigation.helper' import { EnvConfigurationsNav } from './EnvConfigurationsNav' +const isFELibAvailable = importComponentFromFELibrary('isFELibAvailable', null, 'function') + export const AppNavigation = () => { // HOOKS const { path } = useRouteMatch() @@ -49,6 +53,7 @@ export const AppNavigation = () => { deleteApp, canShowExternalLinks, showCannotDeleteTooltip, + isWorkflowEditorUnlocked, toggleRepoSelectionTippy, getRepo, isJobView, @@ -172,6 +177,23 @@ export const AppNavigation = () => { ) } + if (item.stage === STAGE_NAME.PROTECT_CONFIGURATION) { + return ( + isWorkflowEditorUnlocked && + isFELibAvailable && ( +
+ {!canShowExternalLinks &&
} + {renderNavItem(item, null, { + target: '_blank', + icon: , + tooltipContent: + 'Configuration change approval has been moved to Global Configuration', + })} +
+ ) + ) + } + if ( item.stage !== STAGE_NAME.ENV_OVERRIDE || (item.stage === STAGE_NAME.ENV_OVERRIDE && item.isLocked) diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/Navigation.helper.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/Navigation.helper.tsx index 7005f2e400..f9a6c59fce 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/Navigation.helper.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/Navigation/Navigation.helper.tsx @@ -4,15 +4,18 @@ import { ApprovalConfigDataKindType, ApprovalConfigDataType, CollapsibleListItem, + ConditionalWrap, EnvResourceType, getIsApprovalPolicyConfigured, ResourceIdToResourceApprovalPolicyConfigMapType, + Tooltip, } from '@devtron-labs/devtron-fe-common-lib' import { ReactComponent as Lock } from '@Icons/ic-locked.svg' import { ReactComponent as ICStamp } from '@Icons/ic-stamp.svg' import { ResourceConfigStage, ResourceConfigState } from '@Pages/Applications/DevtronApps/service.types' +import { AnchorHTMLAttributes, ReactElement } from 'react' import { CustomNavItemsType, EnvConfigRouteParams, @@ -32,29 +35,51 @@ const renderNavItemIcon = (isLocked: boolean, isApprovalPolicyConfigured: boolea return null } +const wrapWithTooltip = (content: string) => (children: ReactElement) => ( + + {children} + +) + /** * * @param item * @param hideApprovalPolicyIcon Used to hide the policy icon (applicable for jobs atm) */ -export const renderNavItem = (item: CustomNavItemsType, hideApprovalPolicyIcon?: boolean) => { +export const renderNavItem = ( + item: CustomNavItemsType, + hideApprovalPolicyIcon?: boolean, + options?: { + target?: AnchorHTMLAttributes['target'] + icon?: ReactElement + tooltipContent?: string + }, +) => { const linkDataTestName = item.title.toLowerCase().split(' ').join('-') return ( - { - if (item.isLocked) { - event.preventDefault() - } - }} - className="dc__nav-item cursor fs-13 lh-32 cn-7 w-100 br-4 px-8 flexbox dc__align-items-center dc__content-space dc__no-decor" - to={item.href} - > - {item.title} - {renderNavItemIcon(item.isLocked, !hideApprovalPolicyIcon && item.isProtectionAllowed, linkDataTestName)} - + + { + if (item.isLocked) { + event.preventDefault() + } + }} + className="dc__nav-item cursor fs-13 lh-32 cn-9 w-100 br-4 px-8 flexbox dc__align-items-center dc__content-space dc__no-decor" + to={item.href} + target={options?.target} + > + {item.title} + {options?.icon ?? + renderNavItemIcon( + item.isLocked, + !hideApprovalPolicyIcon && item.isProtectionAllowed, + linkDataTestName, + )} + + ) } diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/appConfig.scss b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/appConfig.scss index 8955834963..0af14630a0 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/appConfig.scss +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/appConfig.scss @@ -61,6 +61,22 @@ grid-template-rows: repeat(3, 32px) 1fr; } } + + &.config-protection__side-nav { + grid-template-rows: 110px repeat(4, 32px) 54px 32px 1fr auto; + + &.hide-external-links { + grid-template-rows: 110px repeat(4, 32px) 54px 1fr auto; + } + + &.hide-app-config-help { + grid-template-rows: repeat(4, 32px) 54px 32px 1fr auto; + + &.hide-external-links { + grid-template-rows: repeat(4, 32px) 54px 1fr auto; + } + } + } } &.app-compose-with-gitops-config__nav { @@ -73,6 +89,22 @@ grid-template-rows: repeat(5, 32px) 1fr auto; } } + + &.config-protection__side-nav { + grid-template-rows: 110px repeat(5, 32px) 54px 32px 1fr auto; + + &.hide-external-links { + grid-template-rows: 110px repeat(5, 32px) 54px 1fr auto; + } + + &.hide-app-config-help { + grid-template-rows: repeat(5, 32px) 54px 32px 1fr auto; + + &.hide-external-links { + grid-template-rows: repeat(5, 32px) 54px 1fr auto; + } + } + } } .help-container { diff --git a/src/components/cdPipeline/BuildCD.tsx b/src/components/cdPipeline/BuildCD.tsx index 7710388225..20cb6de1df 100644 --- a/src/components/cdPipeline/BuildCD.tsx +++ b/src/components/cdPipeline/BuildCD.tsx @@ -65,6 +65,7 @@ import { BuildCDProps } from './types' const VirtualEnvSelectionInfoText = importComponentFromFELibrary('VirtualEnvSelectionInfoText') const HelmManifestPush = importComponentFromFELibrary('HelmManifestPush') const MigrateHelmReleaseBody = importComponentFromFELibrary('MigrateHelmReleaseBody', null, 'function') +const ApprovalPolicyRedirectCard = importComponentFromFELibrary('ApprovalPolicyRedirectCard', null, 'function') export default function BuildCD({ isAdvanced, @@ -776,6 +777,9 @@ export default function BuildCD({ !noGitOpsModuleInstalledAndConfigured && renderDeploymentAppType()} {isAdvanced ? renderAdvancedDeploymentStrategy() : renderBasicDeploymentStrategy()} + {isAdvanced && + ApprovalPolicyRedirectCard && + } {isAdvanced && ( <>