diff --git a/.env b/.env index 122d256c7a..d18d5279f4 100644 --- a/.env +++ b/.env @@ -62,3 +62,4 @@ FEATURE_PROMO_EMBEDDED_BUTTON_TEXT= FEATURE_PROMO_EMBEDDED_MODAL_TITLE= FEATURE_PROMO_EMBEDDED_IFRAME_URL= FEATURE_BULK_RESTART_WORKLOADS_FROM_RB=deployment,rollout,daemonset,statefulset +FEATURE_DEFAULT_LANDING_RB_ENABLE=false diff --git a/.github/workflows/pr-issue-validator.yaml b/.github/workflows/pr-issue-validator.yaml index 070e38da1d..8825384d0d 100644 --- a/.github/workflows/pr-issue-validator.yaml +++ b/.github/workflows/pr-issue-validator.yaml @@ -11,6 +11,7 @@ on: branches: - 'main' - 'release-**' + - 'develop' jobs: validate-PR-issue: diff --git a/package.json b/package.json index 249362b5a8..425b2691fa 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.1.6", + "@devtron-labs/devtron-fe-common-lib": "1.1.7", "@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/MainContent/ConfigHeader.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/ConfigHeader.tsx index cc633aed64..3b436bdce1 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/ConfigHeader.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/ConfigHeader.tsx @@ -67,15 +67,13 @@ const ConfigHeader = ({ showNoOverride, parsingError, restoreLastSavedYAML, - hideDryRunTab = false, + hideTabs = {}, }: ConfigHeaderProps) => { const validTabKeys = isOverridable ? CONFIG_HEADER_TAB_VALUES.OVERRIDE : CONFIG_HEADER_TAB_VALUES.BASE_DEPLOYMENT_TEMPLATE - const filteredTabKeys = validTabKeys.filter( - (currentTab: ConfigHeaderTabType) => !hideDryRunTab || currentTab !== ConfigHeaderTabType.DRY_RUN, - ) + const filteredTabKeys = validTabKeys.filter((tab) => !hideTabs[tab]) const activeTabIndex = filteredTabKeys.indexOf(configHeaderTab) diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/DeploymentConfigCompare.tsx b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/DeploymentConfigCompare.tsx index dcd57500a3..376e104d4b 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/DeploymentConfigCompare.tsx +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/DeploymentConfigCompare.tsx @@ -1,5 +1,5 @@ -import { useEffect, useMemo, useState } from 'react' -import { generatePath, useHistory, useRouteMatch } from 'react-router-dom' +import { useEffect, useMemo, useRef, useState } from 'react' +import { generatePath, useHistory, useLocation, useRouteMatch } from 'react-router-dom' import { useUrlFilters, @@ -57,9 +57,11 @@ export const DeploymentConfigCompare = ({ const { push } = useHistory() const { path, params } = useRouteMatch() const { compareTo, resourceType, resourceName, appId, envId } = params + const location = useLocation() // STATES const [convertVariables, setConvertVariables] = useState(false) + const isDefaultLandingPreviousDeploymentSet = useRef(false) // GLOBAL CONSTANTS const isManifestView = resourceType === EnvResourceType.Manifest @@ -133,6 +135,32 @@ export const DeploymentConfigCompare = ({ [options, optionsLoader], ) + useEffect(() => { + if (!compareEnvOptions || isDefaultLandingPreviousDeploymentSet.current) { + return + } + + isDefaultLandingPreviousDeploymentSet.current = true + + if (!compareEnvOptions.previousDeployments?.length) { + updateSearchParams({ + compareWith: null, + }) + + return + } + + const previousDeploymentData = compareEnvOptions.previousDeployments[0] + + updateSearchParams({ + [AppEnvDeploymentConfigQueryParams.COMPARE_WITH_CONFIG_TYPE]: + AppEnvDeploymentConfigType.PREVIOUS_DEPLOYMENTS, + compareWithIdentifierId: previousDeploymentData.deploymentTemplateHistoryId, + compareWithPipelineId: previousDeploymentData.pipelineId, + compareWithManifestChartRefId: isManifestView ? previousDeploymentData.chartRefId : null, + }) + }, [compareEnvOptions]) + const fetchManifestData = async () => { const [{ result: currentList }, { result: compareList }] = await Promise.all([ getDeploymentTemplateData({ type, appName, envName, configType, compareName: compareTo }), @@ -480,13 +508,49 @@ export const DeploymentConfigCompare = ({ if (_isManifestView) { setConvertVariables(false) } - push( - generatePath(path, { + + const currentSearchParams = new URLSearchParams(location.search) + + // NOTE: need to find the corresponding chartRefId(s) for compareWith and compareTo + // and set/delete them based on _isManifestView + const _compareWithManifestChartRefId = + currentSearchParams.has('compareWithIdentifierId') && _isManifestView + ? compareEnvOptions.previousDeployments.find( + (prev) => + prev.deploymentTemplateHistoryId === + Number(currentSearchParams.get('compareWithIdentifierId')), + )?.chartRefId ?? null + : null + + const _manifestChartRefId = + currentSearchParams.has('identifierId') && _isManifestView + ? currentEnvOptions.previousDeployments.find( + (prev) => prev.deploymentTemplateHistoryId === Number(currentSearchParams.get('identifierId')), + )?.chartRefId ?? null + : null + + if (_compareWithManifestChartRefId) { + currentSearchParams.set('compareWithManifestChartRefId', String(_compareWithManifestChartRefId)) + } else { + // NOTE: make sure to not set null as URLSearchParams will save the null as string + // i.e suppose we save 'hello' = null, we get ?hello=null as search param + currentSearchParams.delete('compareWithManifestChartRefId') + } + + if (_manifestChartRefId) { + currentSearchParams.set('manifestChartRefId', String(_manifestChartRefId)) + } else { + currentSearchParams.delete('manifestChartRefId') + } + + push({ + pathname: generatePath(path, { ...params, resourceType: _isManifestView ? EnvResourceType.Manifest : EnvResourceType.DeploymentTemplate, resourceName: null, }), - ) + search: currentSearchParams.toString(), + }) } const tabConfig: DeploymentConfigDiffProps['tabConfig'] = { diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/utils.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/utils.ts index d4863ba8df..e676bed082 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/utils.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/DeploymentConfigCompare/utils.ts @@ -120,7 +120,7 @@ export const parseCompareWithSearchParams = // If `type` is 'app' (Application), set `compareWith` to the first environment if available, // otherwise `null` (base configuration). if (type === 'app') { - compareWith = environments.length && !compareTo ? environments[0].name : null + compareWith = compareTo || (environments.length ? environments[0].name : null) } else { // If `type` is 'appGroup' (Application Groups), set `compareWith` to the first application. // If the application to compare (`compareTo`) is the same as the first application, diff --git a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/types.ts b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/types.ts index 672e58da83..0cc8c7c091 100644 --- a/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/types.ts +++ b/src/Pages/Applications/DevtronApps/Details/AppConfigurations/MainContent/types.ts @@ -28,12 +28,8 @@ export interface ConfigHeaderProps { showNoOverride: boolean parsingError: string restoreLastSavedYAML: () => void - /** - * This prop hides the dry run tab in the header - * This prop is meant to be removed after patch merge strategy is introduced - * @default - false - */ - hideDryRunTab?: boolean + /** A map indicating which tabs to hide, with their visibility as boolean values */ + hideTabs?: Partial> } export interface ConfigHeaderTabProps diff --git a/src/Pages/Shared/ConfigMapSecret/ConfigMapSecretContainer.tsx b/src/Pages/Shared/ConfigMapSecret/ConfigMapSecretContainer.tsx index aa2204a3e7..508382d294 100644 --- a/src/Pages/Shared/ConfigMapSecret/ConfigMapSecretContainer.tsx +++ b/src/Pages/Shared/ConfigMapSecret/ConfigMapSecretContainer.tsx @@ -182,8 +182,10 @@ export const ConfigMapSecretContainer = ({ }) : null, // Fetch Base Configuration (Inherited Tab Data) - cmSecretStateLabel === CM_SECRET_STATE.INHERITED || - cmSecretStateLabel === CM_SECRET_STATE.OVERRIDDEN + // Skipped for jobs as API support is unavailable + !isJob && + (cmSecretStateLabel === CM_SECRET_STATE.INHERITED || + cmSecretStateLabel === CM_SECRET_STATE.OVERRIDDEN) ? getConfigMapSecretConfigData({ appId: +appId, appName, @@ -372,7 +374,7 @@ export const ConfigMapSecretContainer = ({ // TAB HANDLING useEffect(() => { - if (cmSecretStateLabel === CM_SECRET_STATE.INHERITED && !draftData) { + if (!isJob && cmSecretStateLabel === CM_SECRET_STATE.INHERITED && !draftData) { setConfigHeaderTab(ConfigHeaderTabType.INHERITED) } else { setConfigHeaderTab(ConfigHeaderTabType.VALUES) @@ -430,7 +432,14 @@ export const ConfigMapSecretContainer = ({ const handleClearPopupNode = () => setPopupNodeType(null) - const handleViewInheritedConfig = () => setConfigHeaderTab(ConfigHeaderTabType.INHERITED) + const handleViewInheritedConfig = () => { + if (isJob) { + // Redirecting to the base config URL, since inherited tab is hidden + history.push(baseConfigurationURL) + } else { + setConfigHeaderTab(ConfigHeaderTabType.INHERITED) + } + } const handleProtectionViewTabChange = (tab: ProtectConfigTabsType) => { setSelectedProtectionViewTab(tab) @@ -746,7 +755,7 @@ export const ConfigMapSecretContainer = ({ } parsingError={parsingError} restoreLastSavedYAML={restoreLastSavedYAML} - hideDryRunTab + hideTabs={{ dryRun: true, inherited: isJob }} /> {!hideConfigToolbar && ( = ({ delete={handleDelete} closeDelete={toggleDeleteDialog} apiCallInProgress={apiCallInProgress} + showDeleteConfirmation + deleteConfirmationText={resourceData.name as string} >

{DELETE_MODAL_MESSAGING.description}

diff --git a/src/components/app/list-new/AppList.tsx b/src/components/app/list-new/AppList.tsx index e192b46791..3cc9a544ba 100644 --- a/src/components/app/list-new/AppList.tsx +++ b/src/components/app/list-new/AppList.tsx @@ -16,7 +16,16 @@ */ import React, { useState, useEffect, useMemo } from 'react' -import { Switch, Route, useHistory, useParams, useRouteMatch, useLocation } from 'react-router-dom' +import { + Switch, + Route, + useHistory, + useParams, + useRouteMatch, + useLocation, + Redirect, + RedirectProps, +} from 'react-router-dom' import { Progressing, stopPropagation, @@ -68,7 +77,7 @@ const AppList = ({ isArgoInstalled }: AppListPropType) => { const location = useLocation() const { url } = useRouteMatch() const params = useParams<{ appType: string }>() - const { serverMode } = useMainContext() + const { serverMode, isSuperAdmin } = useMainContext() const { setCurrentAppName } = useAppContext() const [lastDataSyncTimeString, setLastDataSyncTimeString] = useState('') @@ -284,70 +293,70 @@ const AppList = ({ isArgoInstalled }: AppListPropType) => { /> ) - const renderAppTabs = () => { - const tabs: TabProps[] = [ - ...(serverMode === SERVER_MODE.FULL - ? [ - { - id: 'devtron-apps', - label: 'Devtron Apps', - tabType: 'navLink' as const, - props: { - to: { - pathname: getChangeAppTabURL(AppListConstants.AppTabs.DEVTRON_APPS), - search: location.search, - }, - 'data-testid': 'devtron-app-list-button', + const tabs: TabProps[] = [ + ...(serverMode === SERVER_MODE.FULL + ? [ + { + id: AppListConstants.AppType.DEVTRON_APPS, + label: 'Devtron Apps', + tabType: 'navLink' as const, + props: { + to: { + pathname: getChangeAppTabURL(AppListConstants.AppTabs.DEVTRON_APPS), + search: location.search, }, + 'data-testid': 'devtron-app-list-button', }, - ] - : []), - { - id: 'helm-apps', - label: 'Helm Apps', - tabType: 'navLink', - props: { - to: { - pathname: getChangeAppTabURL(AppListConstants.AppTabs.HELM_APPS), - search: location.search, - }, - 'data-testid': 'helm-app-list-button', + }, + ] + : []), + { + id: AppListConstants.AppType.HELM_APPS, + label: 'Helm Apps', + tabType: 'navLink', + props: { + to: { + pathname: getChangeAppTabURL(AppListConstants.AppTabs.HELM_APPS), + search: location.search, }, + 'data-testid': 'helm-app-list-button', }, - ...(window._env_?.ENABLE_EXTERNAL_ARGO_CD - ? [ - { - id: 'argo-cd-apps', - label: AppListConstants.AppTabs.ARGO_APPS, - tabType: 'navLink' as const, - props: { - to: { - pathname: getChangeAppTabURL(AppListConstants.AppTabs.ARGO_APPS), - search: location.search, - }, - 'data-testid': 'argo-app-list-button', + }, + ...(window._env_?.ENABLE_EXTERNAL_ARGO_CD && isSuperAdmin + ? [ + { + id: AppListConstants.AppType.ARGO_APPS, + label: AppListConstants.AppTabs.ARGO_APPS, + tabType: 'navLink' as const, + props: { + to: { + pathname: getChangeAppTabURL(AppListConstants.AppTabs.ARGO_APPS), + search: location.search, }, + 'data-testid': 'argo-app-list-button', }, - ] - : []), - ...(window._env_?.FEATURE_EXTERNAL_FLUX_CD_ENABLE - ? [ - { - id: 'flux-cd-apps', - label: AppListConstants.AppTabs.FLUX_APPS, - tabType: 'navLink' as const, - props: { - to: { - pathname: getChangeAppTabURL(AppListConstants.AppTabs.FLUX_APPS), - search: location.search, - }, - 'data-testid': 'flux-app-list-button', + }, + ] + : []), + ...(window._env_?.FEATURE_EXTERNAL_FLUX_CD_ENABLE && isSuperAdmin + ? [ + { + id: AppListConstants.AppType.FLUX_APPS, + label: AppListConstants.AppTabs.FLUX_APPS, + tabType: 'navLink' as const, + props: { + to: { + pathname: getChangeAppTabURL(AppListConstants.AppTabs.FLUX_APPS), + search: location.search, }, + 'data-testid': 'flux-app-list-button', }, - ] - : []), - ] + }, + ] + : []), + ] + const renderAppTabs = () => { const rightComponent = (
{lastDataSyncTimeString && @@ -503,6 +512,7 @@ const AppList = ({ isArgoInstalled }: AppListPropType) => { setShowPulsatingDot={setShowPulsatingDot} /> )} + {tabs.every((tab) => tab.id !== params.appType) && }
) } diff --git a/src/components/common/navigation/Navigation.tsx b/src/components/common/navigation/Navigation.tsx index 92d67bf7eb..2f9d62cf8e 100644 --- a/src/components/common/navigation/Navigation.tsx +++ b/src/components/common/navigation/Navigation.tsx @@ -46,6 +46,7 @@ import { getModuleInfo } from '../../v2/devtronStackManager/DevtronStackManager. import { ReactComponent as ResourceWatcherIcon } from '../../../assets/icons/ic-monitoring.svg' import { importComponentFromFELibrary } from '../helpers/Helpers' import { OrganizationFrame, OrganizationTextLogo } from '../../../Pages/Shared' +import { MainContext } from './types' const hideResourceWatcher = !importComponentFromFELibrary('ResourceWatcherRouter') const hideSoftwareDistributionHub = !importComponentFromFELibrary('SoftwareDistributionHub', null, 'function') @@ -179,6 +180,7 @@ interface NavigationType extends RouteComponentProps<{}> { installedModuleMap: React.MutableRefObject> isSuperAdmin: boolean isAirgapped: boolean + currentServerInfo: MainContext['currentServerInfo'] } export default class Navigation extends Component< @@ -425,7 +427,9 @@ export default class Navigation extends Component< return this.renderNavLink(item) } })} - {!window._env_.K8S_CLIENT && !this.props.isAirgapped && ( + {!window._env_.K8S_CLIENT && + !this.props.isAirgapped && + this.props.currentServerInfo.serverInfo?.installationType !== 'enterprise' && ( <>
{this.renderNavLink(NavigationStack, 'short-nav__stack-manager')} diff --git a/src/components/common/navigation/NavigationRoutes.tsx b/src/components/common/navigation/NavigationRoutes.tsx index b5e79193c9..04b12a5e3b 100644 --- a/src/components/common/navigation/NavigationRoutes.tsx +++ b/src/components/common/navigation/NavigationRoutes.tsx @@ -384,6 +384,7 @@ export default function NavigationRoutes() {
{!_isOnboardingPage && ( , ] : []), - - - , + ...(currentServerInfo.serverInfo?.installationType !== 'enterprise' + ? [ + + + + ] + : []), { const { push } = useHistory() const { pathname } = useLocation() + const { serverMode } = useMainContext() useEffect(() => { if (pathname && pathname !== '/') { Sentry.captureMessage( @@ -610,6 +616,8 @@ export const RedirectUserWithSentry = ({ isFirstLoginUser }) => { push(URLS.RESOURCE_BROWSER) } else if (isFirstLoginUser) { push(URLS.GETTING_STARTED) + } else if (serverMode === SERVER_MODE.EA_ONLY && window._env_.FEATURE_DEFAULT_LANDING_RB_ENABLE) { + push(URLS.RESOURCE_BROWSER) } else { push(`${URLS.APP}/${URLS.APP_LIST}`) } diff --git a/src/components/login/Login.tsx b/src/components/login/Login.tsx index 8dd1acfafe..3836f81c65 100644 --- a/src/components/login/Login.tsx +++ b/src/components/login/Login.tsx @@ -151,7 +151,8 @@ class Login extends Component { return CommonURL.NETWORK_STATUS_INTERFACE } - return URLS.APP + // NOTE: we don't have serverMode therefore defaulting to flag value + return window._env_.FEATURE_DEFAULT_LANDING_RB_ENABLE ? URLS.RESOURCE_BROWSER : URLS.APP } login(e): void { diff --git a/src/index.tsx b/src/index.tsx index 105ce97e7b..19dea0a5ec 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -158,7 +158,8 @@ if (!window || !window._env_) { FEATURE_PROMO_EMBEDDED_BUTTON_TEXT: '', FEATURE_PROMO_EMBEDDED_MODAL_TITLE: '', FEATURE_PROMO_EMBEDDED_IFRAME_URL:'', - FEATURE_BULK_RESTART_WORKLOADS_FROM_RB: 'deployMent,rOllOut,daemonset, statefulset' + FEATURE_BULK_RESTART_WORKLOADS_FROM_RB: 'deployMent,rOllOut,daemonset, statefulset', + FEATURE_DEFAULT_LANDING_RB_ENABLE: false, } } diff --git a/src/services/service.types.ts b/src/services/service.types.ts index 8ac2fe9f77..fd106cace3 100644 --- a/src/services/service.types.ts +++ b/src/services/service.types.ts @@ -22,7 +22,6 @@ import { ChartMetadataType, EnvListMinDTO, ResponseType, - SeverityCount, Teams, } from '@devtron-labs/devtron-fe-common-lib' diff --git a/yarn.lock b/yarn.lock index f8e583a36d..ee0707457f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -974,10 +974,10 @@ dependencies: "@jridgewell/trace-mapping" "0.3.9" -"@devtron-labs/devtron-fe-common-lib@1.1.6": - version "1.1.6" - resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.1.6.tgz#13390eaef23265dfaf2525506fc37c263df3416c" - integrity sha512-t5o8rjIBxaUfL97yhXZHJUZDhiwhRQOgWGqaulD2PqzCei9I8rP+0wlwQbbRHh73HFSc3sxmesItYoHGeQhNJw== +"@devtron-labs/devtron-fe-common-lib@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@devtron-labs/devtron-fe-common-lib/-/devtron-fe-common-lib-1.1.7.tgz#a2e0184ba94afda20309f3a1e80f0399f8272518" + integrity sha512-0Ztp/HBvuvEUoHJz0MnjZvbT+SfoYiVr+PVxZ9AJKmrRYk5HkBBXTyIZFWc0XSn3oxPiwlfbc/0xxIeDIH64FA== dependencies: "@types/react-dates" "^21.8.6" ansi_up "^5.2.1" @@ -5894,7 +5894,7 @@ markdown-to-jsx@^7.4.1: marked@^13.0.3: version "13.0.3" - resolved "https://registry.npmjs.org/marked/-/marked-13.0.3.tgz" + resolved "https://registry.yarnpkg.com/marked/-/marked-13.0.3.tgz#5c5b4a5d0198060c7c9bc6ef9420a7fed30f822d" integrity sha512-rqRix3/TWzE9rIoFGIn8JmsVfhiuC8VIQ8IdX5TfzmeBucdY05/0UlzKaw0eVtpcN/OdVFpBk7CjKGo9iHJ/zA== memoize-one@^6.0.0: