Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: mandatory tags blocks trigger #2246

Merged
merged 45 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
1c7c3f0
feat: integrate api changes for mandatory tags on cd modal and materi…
arunjaindev Dec 2, 2024
81c4320
chore: version bump
arunjaindev Dec 2, 2024
aa5e421
feat: set warning message for buld cd trigger
arunjaindev Dec 3, 2024
48316c4
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 4, 2024
00c6b68
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 4, 2024
ed0946f
chore: version bump to 1.2.2-beta-2
shivani170 Dec 4, 2024
a6b3026
chore: remove this later
shivani170 Dec 5, 2024
78742f6
feat: use dynamic data table for mandatory and
arunjaindev Dec 5, 2024
9759ae8
feat: add support for configured tags
arunjaindev Dec 5, 2024
878c4bc
chore: move policy consequences api into promise.all
arunjaindev Dec 5, 2024
f467956
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 5, 2024
321ba55
chore: version bump
arunjaindev Dec 5, 2024
eb7d13c
Merge branch 'feat/mandatory-tags-v2' into feat/mandatory-tags-cd
shivani170 Dec 6, 2024
6ce7f5d
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 9, 2024
ba88bcb
chore: extend trigger cd node type
arunjaindev Dec 9, 2024
a63a0dc
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 9, 2024
1a313a7
chore: version bump
arunjaindev Dec 9, 2024
1db5da9
fix: pushing labels twice
arunjaindev Dec 9, 2024
08aed2e
fix: ignore empty rows
arunjaindev Dec 9, 2024
9d1e090
fix: update return statement for blovk state
arunjaindev Dec 9, 2024
583a8ef
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 9, 2024
0164408
fix: show auto trigger block reason info
arunjaindev Dec 9, 2024
cb714b7
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 9, 2024
2ce92a5
fix: page break if response list not available
arunjaindev Dec 10, 2024
97ec665
chore: extract promise in cd material
arunjaindev Dec 10, 2024
6bc129e
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 10, 2024
998ed46
chore: use common util for class and heading
arunjaindev Dec 10, 2024
c5e233b
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 10, 2024
5b8c83e
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 12, 2024
d82939e
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 12, 2024
3dbc362
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 15, 2024
6c619a1
Merge branch 'feat/mandatory-tags-cd' of https://github.com/devtron-l…
arunjaindev Dec 15, 2024
0b66722
feat: add validations in tags table
arunjaindev Dec 16, 2024
9a6ca73
Merge pull request #2266 from devtron-labs/feat/create-edit-app-tags
arunjaindev Dec 17, 2024
722c9b6
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 17, 2024
a70d501
chore: add validations and GA events
arunjaindev Dec 17, 2024
c78732f
chore: add appType for GA EVENT
arunjaindev Dec 17, 2024
efe76b0
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 17, 2024
e859de4
chore: version bump
arunjaindev Dec 18, 2024
5c37f47
Merge branch 'main' of https://github.com/devtron-labs/dashboard into…
arunjaindev Dec 19, 2024
6892013
chore: version bump
arunjaindev Dec 19, 2024
c041503
fix: validation errors on tags
arunjaindev Dec 19, 2024
26a1ff3
fix: error highlighting in tags table
arunjaindev Dec 19, 2024
6d28aa0
Merge branch 'main' of https://github.com/devtron-labs/dashboard into…
arunjaindev Dec 19, 2024
bc72bbe
Merge branch 'feat/mandatory-tags-v2' of https://github.com/devtron-l…
arunjaindev Dec 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "1.2.2",
"@devtron-labs/devtron-fe-common-lib": "1.2.2-beta-2",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@rjsf/core": "^5.13.3",
"@rjsf/utils": "^5.13.3",
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 @@ -42,14 +42,15 @@ import {
ToastManager,
ToastVariantType,
CommonNodeAttr,
TriggerBlockType,
} 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'
Expand Down Expand Up @@ -77,6 +78,7 @@ 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')

// TODO: Fix release tags selection
export default function BulkCDTrigger({
Expand Down Expand Up @@ -426,16 +428,16 @@ export default function BulkCDTrigger({
)
}

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

if (tagNotFoundWarningsMap.has(app.appId)) {
return (
<div className="flex left top dc__gap-4">
<Error
className="icon-dim-12 dc__no-shrink mt-5 alert-icon-r5-imp"
/>
<Error className="icon-dim-12 dc__no-shrink mt-5 alert-icon-r5-imp" />

<span className="fw-4 fs-12 cr-5 dc__truncate">
{tagNotFoundWarningsMap.get(app.appId)}
</span>
<span className="fw-4 fs-12 cr-5 dc__truncate">{tagNotFoundWarningsMap.get(app.appId)}</span>
</div>
)
}
Expand All @@ -454,13 +456,9 @@ export default function BulkCDTrigger({
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"
/>
<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>
<span className="fw-4 fs-12 cy-7 dc__truncate">{warningMessage}</span>
</div>
)
}
Expand All @@ -473,7 +471,7 @@ export default function BulkCDTrigger({
nodeType={commonNodeAttrType}
shouldRenderAdditionalInfo={isAppSelected}
/>
)
)
}

return null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ import {
ToastManager,
ToastVariantType,
BlockedStateData,
getStageTitle,
TriggerBlockType,
} from '@devtron-labs/devtron-fe-common-lib'
import Tippy from '@tippyjs/react'
import {
Expand Down Expand Up @@ -1751,7 +1753,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 @@ -1785,7 +1790,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 Expand Up @@ -1982,9 +1991,7 @@ export default function EnvTriggerView({ filteredAppIds, isVirtualEnv }: AppGrou
if (selectedCINode?.id) {
return (
<Switch>
<Route
path={`${url}${URLS.BUILD}/:ciNodeId/${URLS.WEBHOOK_MODAL}`}
>
<Route path={`${url}${URLS.BUILD}/:ciNodeId/${URLS.WEBHOOK_MODAL}`}>
<WebhookReceivedPayloadModal
workflowId={workflowID}
webhookPayloads={webhookPayloads}
Expand Down
6 changes: 1 addition & 5 deletions src/components/app/details/triggerView/TriggerView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1095,7 +1095,6 @@ class TriggerView extends Component<TriggerViewProps, TriggerViewState> {
this.getWorkflowStatus()
}


onClickWebhookTimeStamp = () => {
if (this.state.webhookTimeStampOrder === TIME_STAMP_ORDER.DESCENDING) {
this.setState({ webhookTimeStampOrder: TIME_STAMP_ORDER.ASCENDING })
Expand Down Expand Up @@ -1172,16 +1171,13 @@ class TriggerView extends Component<TriggerViewProps, TriggerViewState> {
this.abortCIBuild = new AbortController()
}


renderCIMaterial = () => {
if (this.state.ciNodeId) {
const nd: CommonNodeAttr = this.getCINode()
const material = nd?.[this.state.materialType] || []
return (
<Switch>
<Route
path={`${this.props.match.url}${URLS.BUILD}/:ciNodeId/${URLS.WEBHOOK_MODAL}`}
>
<Route path={`${this.props.match.url}${URLS.BUILD}/:ciNodeId/${URLS.WEBHOOK_MODAL}`}>
<WebhookReceivedPayloadModal
workflowId={this.state.workflowId}
webhookPayloads={this.state.webhookPayloads}
Expand Down
29 changes: 26 additions & 3 deletions src/components/app/details/triggerView/cdMaterial.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ import {
ResponseType,
ApiResponseResultType,
CommonNodeAttr,
GetPolicyConsequencesProps,
PolicyConsequencesDTO,
} from '@devtron-labs/devtron-fe-common-lib'
import Tippy from '@tippyjs/react'
import {
Expand Down Expand Up @@ -139,7 +141,6 @@ const getIsImageApproverFromUserApprovalMetaData: (
email: string,
userApprovalMetadata: UserApprovalMetadataType,
) => boolean = importComponentFromFELibrary('getIsImageApproverFromUserApprovalMetaData', () => false, 'function')
const isFELibAvailable = importComponentFromFELibrary('isFELibAvailable', null, 'function')
const getSecurityScan: ({
appId,
envId,
Expand All @@ -152,6 +153,9 @@ const getSecurityScan: ({
const SecurityModalSidebar = importComponentFromFELibrary('SecurityModalSidebar', null, 'function')
const AllowedWithWarningTippy = importComponentFromFELibrary('AllowedWithWarningTippy')
const MissingPluginBlockState = importComponentFromFELibrary('MissingPluginBlockState', null, 'function')
const TriggerBlockEmptyState = importComponentFromFELibrary('TriggerBlockEmptyState', null, 'function')
const getPolicyConsequences: ({ appId, envId }: GetPolicyConsequencesProps) => Promise<PolicyConsequencesDTO> =
importComponentFromFELibrary('getPolicyConsequences', null, 'function')

const CDMaterial = ({
materialType,
Expand Down Expand Up @@ -219,6 +223,7 @@ const CDMaterial = ({
const allowWarningWithTippyNodeTypeProp: CommonNodeAttr['type'] =
stageType === DeploymentNodeType.PRECD ? 'PRECD' : 'POSTCD'


// TODO: Ask if pipelineId always changes on change of app else add appId as dependency
const [loadingMaterials, responseList, materialsError, reloadMaterials] = useAsync(
() =>
Expand Down Expand Up @@ -250,6 +255,7 @@ const CDMaterial = ({
getDeploymentWindowProfileMetaData && !isFromBulkCD
? getDeploymentWindowProfileMetaData(appId, envId)
: null,
getPolicyConsequences ? getPolicyConsequences({ appId, envId }) : null,
]),
abortControllerRef,
),
Expand All @@ -261,6 +267,20 @@ const CDMaterial = ({
const materialsResult: CDMaterialResponseType = responseList?.[0]
const deploymentWindowMetadata = responseList?.[1] ?? {}

// this function can be used for other trigger block reasons once api supports it
const getIsTriggerBlocked = () => {
switch (stageType) {
case DeploymentNodeType.PRECD:
return responseList[2]?.cd.pre.isBlocked
case DeploymentNodeType.POSTCD:
return responseList[2]?.cd.post.isBlocked
case DeploymentNodeType.CD:
return responseList[2]?.cd.node.isBlocked
default:
return false
}
}

const { onClickCDMaterial } = useContext<TriggerViewContextType>(TriggerViewContext)
const [noMoreImages, setNoMoreImages] = useState<boolean>(false)
const [tagsEditable, setTagsEditable] = useState<boolean>(false)
Expand Down Expand Up @@ -1075,6 +1095,9 @@ const CDMaterial = ({
consumedImagePresent?: boolean,
noEligibleImages?: boolean,
) => {
if (TriggerBlockEmptyState && getIsTriggerBlocked()) {
return <TriggerBlockEmptyState appId={appId} stageType={stageType} />
}
if (isTriggerBlockedDueToPlugin && MissingPluginBlockState) {
return (
<MissingPluginBlockState
Expand Down Expand Up @@ -1176,6 +1199,7 @@ const CDMaterial = ({
dataSource={materialData.dataSource}
deploymentWindowArtifactMetadata={materialData.deploymentWindowArtifactMetadata}
isFilterApplied={materialData.appliedFilters?.length > 0}
triggerBlockedInfo={materialData.deploymentBlockedState}
>
{(_gitCommit.WebhookData?.Data ||
_gitCommit.Author ||
Expand Down Expand Up @@ -1712,8 +1736,7 @@ const CDMaterial = ({
</Tippy>
)}
>
{AllowedWithWarningTippy &&
showPluginWarningBeforeTrigger ? (
{AllowedWithWarningTippy && showPluginWarningBeforeTrigger ? (
<AllowedWithWarningTippy
consequence={consequence}
configurePluginURL={configurePluginURL}
Expand Down
1 change: 1 addition & 0 deletions src/components/app/details/triggerView/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ export interface TriggerCDNodeProps extends RouteComponentProps<{ appId: string
deploymentAppType: DeploymentAppTypes
appId: number
isDeploymentBlocked?: boolean
isTriggerBlocked?: boolean
}

export interface TriggerCDNodeState {
Expand Down
6 changes: 4 additions & 2 deletions src/components/app/details/triggerView/workflow.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,7 @@
isDeploymentBlocked: cdPipeline.isDeploymentBlocked,
showPluginWarning: cdPipeline.preDeployStage?.isOffendingMandatoryPlugin,
isTriggerBlocked: cdPipeline.preDeployStage?.isTriggerBlocked,
triggerBlockedInfo: cdPipeline.preDeployStage?.triggerBlockedInfo || cdPipeline.preStage?.triggerBlockedInfo,

Check failure on line 695 in src/components/app/details/triggerView/workflow.service.ts

View workflow job for this annotation

GitHub Actions / ci

Property 'triggerBlockedInfo' does not exist on type 'CDStage'.
pluginBlockState: getParsedPluginPolicyConsequenceData(cdPipeline.preDeployStage?.pluginBlockState),
}
stageIndex++
Expand Down Expand Up @@ -744,8 +745,9 @@
isDeploymentBlocked: cdPipeline.isDeploymentBlocked,
// Will populate this after initializing postCD
showPluginWarning: false,
isTriggerBlocked: false,
pluginBlockState: getParsedPluginPolicyConsequenceData(),
isTriggerBlocked: cdPipeline.isTriggerBlocked,
triggerBlockedInfo: cdPipeline.triggerBlockedInfo,
}
stageIndex++

Expand Down Expand Up @@ -786,6 +788,7 @@
isDeploymentBlocked: cdPipeline.isDeploymentBlocked,
showPluginWarning: cdPipeline.postDeployStage?.isOffendingMandatoryPlugin,
isTriggerBlocked: cdPipeline.postDeployStage?.isTriggerBlocked,
triggerBlockedInfo: cdPipeline.postDeployStage?.triggerBlockedInfo || cdPipeline.postStage?.triggerBlockedInfo,

Check failure on line 791 in src/components/app/details/triggerView/workflow.service.ts

View workflow job for this annotation

GitHub Actions / ci

Property 'triggerBlockedInfo' does not exist on type 'CDStage'.
pluginBlockState: getParsedPluginPolicyConsequenceData(cdPipeline.postDeployStage?.pluginBlockState),
}
}
Expand All @@ -804,7 +807,6 @@
}

CD.showPluginWarning = preCD?.showPluginWarning || postCD?.showPluginWarning
CD.isTriggerBlocked = false
CD.pluginBlockState = getParsedPluginPolicyConsequenceData()
return CD
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ export class Workflow extends Component<WorkflowProps> {
deploymentAppType={node.deploymentAppType}
appId={this.props.appId}
isDeploymentBlocked={node.isDeploymentBlocked}
isTriggerBlocked={node.isTriggerBlocked}
/>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,30 @@ export class TriggerCDNode extends Component<TriggerCDNodeProps, TriggerCDNodeSt
this.handleShowGitOpsRepoConfiguredWarning()
}

getNodeSideHeadingContainerClassName = (): string => {
if (this.props.isTriggerBlocked) {
return 'bcr-1 er-2 bw-1 cr-5 dc__opacity-1'
}

if (this.props.isDeploymentBlocked) {
return 'bcy-5 cn-9 dc__opacity-1'
}

return ''
}

getNodeSideHeadingText = (): string => {
if (this.props.isTriggerBlocked) {
return 'BLOCKED'
}

if (this.props.isDeploymentBlocked) {
return DO_NOT_DEPLOY
}

return this.props.triggerType
}

renderCardContent() {
return (
<TriggerViewContext.Consumer>
Expand All @@ -150,9 +174,9 @@ export class TriggerCDNode extends Component<TriggerCDNodeProps, TriggerCDNodeSt
<>
<div className="workflow-node">
<div
className={`workflow-node__trigger-type workflow-node__trigger-type--cd fw-6 ${this.props.isDeploymentBlocked ? 'bcy-5 cn-9 dc__opacity-1' : ''}`}
className={`workflow-node__trigger-type workflow-node__trigger-type--cd fw-6 ${this.getNodeSideHeadingContainerClassName()}`}
>
{this.props.isDeploymentBlocked ? DO_NOT_DEPLOY : this.props.triggerType}
{this.getNodeSideHeadingText()}
</div>
<div className="workflow-node__title flex">
<div className="workflow-node__full-width-minus-Icon">
Expand Down
2 changes: 1 addition & 1 deletion vite.config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { ViteImageOptimizer } from 'vite-plugin-image-optimizer'
import tsconfigPaths from 'vite-tsconfig-paths'

const WRONG_CODE = `import { bpfrpt_proptype_WindowScroller } from "../WindowScroller.js";`
const TARGET_URL = 'https://devtron-ent-5.devtron.info/'
const TARGET_URL = 'https://devtron-ent-2.devtron.info/'

function reactVirtualized(): PluginOption {
return {
Expand Down
Loading