Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:devtron-labs/dashboard into feat…
Browse files Browse the repository at this point in the history
…/build-cache
  • Loading branch information
Elessar1802 committed Dec 24, 2024
2 parents 67c239b + 7b834df commit 4bcd7d4
Show file tree
Hide file tree
Showing 45 changed files with 621 additions and 497 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ FEATURE_PROMO_EMBEDDED_IFRAME_URL=
FEATURE_RB_SYNC_CLUSTER_ENABLE=false
FEATURE_BULK_RESTART_WORKLOADS_FROM_RB=deployment,rollout,daemonset,statefulset
FEATURE_DEFAULT_MERGE_STRATEGY=
FEATURE_CLUSTER_MAP_ENABLE=false
FEATURE_CLUSTER_MAP_ENABLE=true
FEATURE_DEFAULT_LANDING_RB_ENABLE=false
1 change: 0 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ src/components/app/Overview/utils.tsx
src/components/app/ResourceTreeNodes.tsx
src/components/app/ResponsiveDrawer.tsx
src/components/app/WebWorker.ts
src/components/app/appLabelCommon.tsx
src/components/app/create/CreateApp.tsx
src/components/app/create/validationRules.ts
src/components/app/details/AboutAppInfoModal.tsx
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "dashboard",
"version": "1.2.0",
"version": "1.3.0",
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "1.3.0-beta-10",
"@devtron-labs/devtron-fe-common-lib": "1.3.2-beta-3",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
Expand Down
113 changes: 71 additions & 42 deletions src/Pages/App/Details/ExternalFlux/ExternalFluxAppDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import {
AppType,
ErrorScreenManager,
IndexStore,
useAsync,
useMainContext,
noop,
DeploymentAppTypes,
Progressing,
showError,
ResponseType,
noop,
ERROR_STATUS_CODE,
} from '@devtron-labs/devtron-fe-common-lib'
import { useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
Expand All @@ -37,62 +38,90 @@ let initTimer = null

const ExternalFluxAppDetails = () => {
const { clusterId, appName, namespace, templateType } = useParams<ExternalFluxAppDetailParams>()
const [isPublishing, setIsPublishing] = useState<boolean>(true)
const { isSuperAdmin } = useMainContext()
const isKustomization = templateType === FluxCDTemplateType.KUSTOMIZATION
const [initialLoading, setInitialLoading] = useState(true)
const [isReloadResourceTreeInProgress, setIsReloadResourceTreeInProgress] = useState(true)
const [appDetailsError, setAppDetailsError] = useState(null)

const [isAppDetailsLoading, appDetailsResult, appDetailsError, reloadAppDetails] = useAsync(
() => getExternalFluxCDAppDetails(clusterId, namespace, appName, isKustomization),
[clusterId, appName, namespace, templateType],
isSuperAdmin,
{
resetOnChange: false,
},
)
const handleUpdateIndexStoreWithDetails = (response: ResponseType<any>) => {
const genericAppDetail: AppDetails = {
...response.result,
appStatus: getAppStatus(response.result.appStatus),
deploymentAppType: DeploymentAppTypes.FLUX,
fluxTemplateType: templateType,
}

useEffect(
() => () => {
IndexStore.clearAppDetails()
clearTimeout(initTimer)
},
[],
)
IndexStore.publishAppDetails(genericAppDetail, AppType.EXTERNAL_FLUX_APP)
setAppDetailsError(null)
}

useEffect(() => {
if (appDetailsResult && !appDetailsError) {
initTimer = setTimeout(reloadAppDetails, window._env_.EA_APP_DETAILS_POLLING_INTERVAL || 30000)
const genericAppDetail: AppDetails = {
...appDetailsResult.result,
appStatus: getAppStatus(appDetailsResult.result.appStatus),
deploymentAppType: DeploymentAppTypes.FLUX,
fluxTemplateType: templateType,
}
IndexStore.publishAppDetails(genericAppDetail, AppType.EXTERNAL_FLUX_APP)
setIsPublishing(false)
}
}, [appDetailsResult])
const handleFetchExternalFluxCDAppDetails = () =>
// NOTE: returning a promise so that we can trigger the next timeout after this api call completes
new Promise<void>((resolve) => {
setIsReloadResourceTreeInProgress(true)

getExternalFluxCDAppDetails(clusterId, namespace, appName, isKustomization)
.then(handleUpdateIndexStoreWithDetails)
.catch((error) => {
if (!initialLoading) {
showError(error)
} else {
setAppDetailsError(error)
}
})
.finally(() => {
setIsReloadResourceTreeInProgress(false)
setInitialLoading(false)
resolve()
})
})

if (!isSuperAdmin) {
return <ErrorScreenManager code={403} />
const initializePageDetails = () => {
handleFetchExternalFluxCDAppDetails()
.then(() => {
// NOTE: using timeouts instead of intervals since we want the next api call after the last one finishes
// https://stackoverflow.com/questions/729921/whats-the-difference-between-recursive-settimeout-versus-setinterval
initTimer = setTimeout(initializePageDetails, window._env_.EA_APP_DETAILS_POLLING_INTERVAL || 30000)
})
.catch(noop)
}

if (appDetailsError) {
return <ErrorScreenManager code={appDetailsError.code} reload={reloadAppDetails} />
const handleReloadResourceTree = async () => {
await handleFetchExternalFluxCDAppDetails()
}

// To show loader on first render only
const isLoadingOnMount = isAppDetailsLoading && !appDetailsResult
useEffect(() => {
if (isSuperAdmin) {
setInitialLoading(true)
initializePageDetails()
}

return () => {
IndexStore.clearAppDetails()
clearTimeout(initTimer)
}
}, [clusterId, appName, namespace, templateType, isSuperAdmin])

if (isLoadingOnMount || isPublishing) {
return <Progressing pageLoader />
if (appDetailsError || !isSuperAdmin) {
return (
<ErrorScreenManager
code={appDetailsError?.code ?? ERROR_STATUS_CODE.PERMISSION_DENIED}
reload={handleReloadResourceTree}
/>
)
}

return (
<AppDetailsComponent
isExternalApp
// NOTE: in case of DA & Helm Apps, when we delete that app _init is called
// since we can't delete flux app, sending in noop
_init={noop}
loadingDetails={isLoadingOnMount}
loadingResourceTree={isLoadingOnMount}
loadingDetails={initialLoading}
loadingResourceTree={initialLoading}
handleReloadResourceTree={handleReloadResourceTree}
isReloadResourceTreeInProgress={isReloadResourceTreeInProgress}
/>
)
}
Expand Down
9 changes: 8 additions & 1 deletion src/components/ApplicationGroup/AppGroup.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export interface BulkCDDetailTypeResponse {
export interface BulkCDDetailType
extends BulkTriggerAppDetailType,
Pick<CDMaterialProps, 'isTriggerBlockedDueToPlugin' | 'configurePluginURL' | 'consequence'>,
Partial<Pick<CommonNodeAttr, 'showPluginWarning'>> {
Partial<Pick<CommonNodeAttr, 'showPluginWarning' | 'triggerBlockedInfo'>> {
cdPipelineName?: string
cdPipelineId?: string
stageType?: DeploymentNodeType
Expand Down Expand Up @@ -613,4 +613,11 @@ export enum AppGroupUrlFilters {

export interface AppGroupUrlFiltersType extends Record<AppGroupUrlFilters, string[]> {}

export interface SetFiltersInLocalStorageParamsType {
filterParentType: FilterParentType
resourceId: string
resourceList: MultiValue<OptionType>
groupList: MultiValue<GroupOptionType>
}

export type AppEnvLocalStorageKeyType = `${string}__filter`
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,25 @@ import {
ToastManager,
ToastVariantType,
CommonNodeAttr,
TriggerBlockType,
RuntimePluginVariables,
uploadCDPipelineFile,
UploadFileProps,
} from '@devtron-labs/devtron-fe-common-lib'
import { useHistory, useLocation } from 'react-router-dom'
import { ReactComponent as Close } from '../../../../assets/icons/ic-cross.svg'
import { ReactComponent as DeployIcon } from '../../../../assets/icons/ic-nav-rocket.svg'
import { ReactComponent as PlayIcon } from '../../../../assets/icons/ic-play-medium.svg'
import { ReactComponent as Error } from '../../../../assets/icons/ic-warning.svg'
import { ReactComponent as UnAuthorized } from '../../../../assets/icons/ic-locked.svg'
import { ReactComponent as Tag } from '../../../../assets/icons/ic-tag.svg'
import { ReactComponent as Close } from '@Icons/ic-cross.svg'
import { ReactComponent as DeployIcon } from '@Icons/ic-nav-rocket.svg'
import { ReactComponent as PlayIcon } from '@Icons/ic-play-medium.svg'
import { ReactComponent as Error } from '@Icons/ic-warning.svg'
import { ReactComponent as UnAuthorized } from '@Icons/ic-locked.svg'
import { ReactComponent as Tag } from '@Icons/ic-tag.svg'
import emptyPreDeploy from '../../../../assets/img/empty-pre-deploy.png'
import notAuthorized from '../../../../assets/img/ic-not-authorized.svg'
import CDMaterial from '../../../app/details/triggerView/cdMaterial'
import { BulkSelectionEvents, MATERIAL_TYPE, RuntimeParamsErrorState } from '../../../app/details/triggerView/types'
import { BulkCDDetailType, BulkCDTriggerType } from '../../AppGroup.types'
import { BULK_CD_DEPLOYMENT_STATUS, BULK_CD_MATERIAL_STATUS, BULK_CD_MESSAGING, BUTTON_TITLE } from '../../Constants'
import TriggerResponseModal from './TriggerResponseModal'
import { EmptyView } from '../../../app/details/cicdHistory/History.components'
import { ReactComponent as MechanicalOperation } from '../../../../assets/img/ic-mechanical-operation.svg'
import { importComponentFromFELibrary } from '../../../common'
import { BULK_ERROR_MESSAGES } from './constants'
Expand All @@ -79,6 +79,8 @@ const getDeploymentWindowStateAppGroup = importComponentFromFELibrary(
const RuntimeParamTabs = importComponentFromFELibrary('RuntimeParamTabs', null, 'function')
const MissingPluginBlockState = importComponentFromFELibrary('MissingPluginBlockState', null, 'function')
const PolicyEnforcementMessage = importComponentFromFELibrary('PolicyEnforcementMessage')
const TriggerBlockedError = importComponentFromFELibrary('TriggerBlockedError', null, 'function')
const TriggerBlockEmptyState = importComponentFromFELibrary('TriggerBlockEmptyState', null, 'function')
const validateRuntimeParameters = importComponentFromFELibrary(
'validateRuntimeParameters',
() => ({ isValid: true, cellError: {} }),
Expand Down Expand Up @@ -389,6 +391,10 @@ export default function BulkCDTrigger({
}

const renderEmptyView = (): JSX.Element => {
if (selectedApp.triggerBlockedInfo?.blockedBy === TriggerBlockType.MANDATORY_TAG) {
return <TriggerBlockEmptyState stageType={selectedApp.stageType} appId={selectedApp.appId} />
}

if (selectedApp.isTriggerBlockedDueToPlugin) {
const commonNodeAttrType: CommonNodeAttr['type'] =
selectedApp.stageType === DeploymentNodeType.PRECD ? 'PRECD' : 'POSTCD'
Expand All @@ -403,16 +409,16 @@ export default function BulkCDTrigger({

if (unauthorizedAppList[selectedApp.appId]) {
return (
<EmptyView
imgSrc={notAuthorized}
<GenericEmptyState
image={notAuthorized}
title={BULK_CD_MESSAGING.unauthorized.title}
subTitle={BULK_CD_MESSAGING.unauthorized.subTitle}
/>
)
}
return (
<EmptyView
imgSrc={emptyPreDeploy}
<GenericEmptyState
image={emptyPreDeploy}
title={`${selectedApp.name} ${BULK_CD_MESSAGING[stage].title}`}
subTitle={BULK_CD_MESSAGING[stage].subTitle}
/>
Expand Down Expand Up @@ -457,11 +463,14 @@ export default function BulkCDTrigger({
)
}

if (app.triggerBlockedInfo?.blockedBy === TriggerBlockType.MANDATORY_TAG) {
return <TriggerBlockedError stageType={app.stageType} />
}

if (!!warningMessage && !app.showPluginWarning) {
return (
<div className="flex left top dc__gap-4">
<Error className="icon-dim-12 dc__no-shrink mt-5 warning-icon-y7" />

<span className="fw-4 fs-12 cy-7 dc__truncate">{warningMessage}</span>
</div>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ import {
ToastManager,
ToastVariantType,
BlockedStateData,
getStageTitle,
TriggerBlockType,
RuntimePluginVariables,
uploadCIPipelineFile,
} from '@devtron-labs/devtron-fe-common-lib'
import Tippy from '@tippyjs/react'
import {
Expand Down Expand Up @@ -1764,7 +1765,10 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
const stageType = DeploymentNodeType[_selectedNode.type]
const isTriggerBlockedDueToPlugin =
_selectedNode.isTriggerBlocked && _selectedNode.showPluginWarning
const stageText = stageType === DeploymentNodeType.PRECD ? 'Pre-Deployment' : 'Post-Deployment'
const isTriggerBlockedDueToMandatoryTags =
_selectedNode.isTriggerBlocked &&
_selectedNode.triggerBlockedInfo?.blockedBy === TriggerBlockType.MANDATORY_TAG
const stageText = getStageTitle(stageType)

_selectedAppWorkflowList.push({
workFlowId: wf.id,
Expand Down Expand Up @@ -1798,7 +1802,11 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
true,
),
consequence: _selectedNode.pluginBlockState,
warningMessage: isTriggerBlockedDueToPlugin ? `${stageText} is blocked` : '',
warningMessage:
isTriggerBlockedDueToPlugin || isTriggerBlockedDueToMandatoryTags
? `${stageText} is blocked`
: '',
triggerBlockedInfo: _selectedNode.triggerBlockedInfo,
})
} else {
let warningMessage = ''
Expand Down
2 changes: 1 addition & 1 deletion src/components/ClusterNodes/ClusterOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ import {
ResourceKindType,
getUrlWithSearchParams,
showError,
ClusterCapacityType,
} from '@devtron-labs/devtron-fe-common-lib'
import {
ClusterErrorType,
ClusterOverviewProps,
DescriptionDataType,
ERROR_TYPE,
ClusterDetailsType,
ClusterCapacityType,
ClusterDescriptionResponse,
ClusterCapacityResponse,
} from './types'
Expand Down
Loading

0 comments on commit 4bcd7d4

Please sign in to comment.