- )}
- {isJobView && (
-
-
-
- {renderBlockWithBorder()}
-
- {renderBlockWithBorder()}
+ {!!triggerMetadata && !!renderDeploymentHistoryTriggerMetaText && (
+
+
+
+ {renderBlockWithBorder()}
+ {renderDeploymentHistoryTriggerMetaText(triggerMetadata, true)}
+ {renderBlockWithBorder()}
+
+
+ {renderDeploymentHistoryTriggerMetaText(triggerMetadata)}
+ )}
-
-
Env
-
- {environmentName !== '' ? environmentName : DEFAULT_ENV}
-
- {environmentName === '' &&
(Default) }
+ {isJobView && (
+
+
+
+ {renderBlockWithBorder()}
+
+ {renderBlockWithBorder()}
+
+
+
+
+ Env
+
+ {environmentName !== '' ? environmentName : DEFAULT_ENV}
+
+ {environmentName === '' && (Default) }
+
-
- )}
+ )}
+
+ {!!executionInfo?.executionStartedOn && (
+
+
+
+ {renderBlockWithBorder()}
+ {renderDetailsSuccessIconBlock()}
+
+
+
+
+
Execution started
+
+ {getFormattedTriggerTime(executionInfo.executionStartedOn)}
+
+
+
+ )}
- {!!executionInfo?.executionStartedOn && (
{renderBlockWithBorder()}
- {renderDetailsSuccessIconBlock()}
+
+
+
+
-
-
Execution started
-
- {getFormattedTriggerTime(executionInfo.executionStartedOn)}
-
-
+
- )}
-
-
-
-
- {renderBlockWithBorder()}
-
-
-
-
+
+
+ {showResourceConflictInfoBlock && (
+
+ ,
+ onClick: handleShowRedeployDialog,
+ variant: ButtonVariantType.text,
+ style: ButtonStyleType.warning,
+ size: ComponentSizeType.medium,
+ }}
+ />
+
+ )}
+
-
-
-
-
-
-
-
+
+ {renderDialogs()}
+ >
)
},
)
diff --git a/src/Shared/Components/CICDHistory/TriggerOutput.tsx b/src/Shared/Components/CICDHistory/TriggerOutput.tsx
index f3929c229..df565dcae 100644
--- a/src/Shared/Components/CICDHistory/TriggerOutput.tsx
+++ b/src/Shared/Components/CICDHistory/TriggerOutput.tsx
@@ -47,8 +47,9 @@ import {
statusSet,
terminalStatus,
TriggerOutputProps,
+ TriggerOutputURLParamsType,
} from './types'
-import { getTriggerOutputTabs } from './utils'
+import { getSortedTriggerHistory, getTriggerOutputTabs } from './utils'
import './cicdHistory.scss'
@@ -250,12 +251,7 @@ const TriggerOutput = ({
renderTargetConfigInfo,
appName,
}: TriggerOutputProps) => {
- const { appId, triggerId, envId, pipelineId } = useParams<{
- appId: string
- triggerId: string
- envId: string
- pipelineId: string
- }>()
+ const { appId, triggerId, envId, pipelineId } = useParams
()
const triggerDetails = triggerHistory.get(+triggerId)
const [triggerDetailsLoading, triggerDetailsResult, triggerDetailsError, reloadTriggerDetails] = useAsync(
() => getTriggerDetails({ appId, envId, pipelineId, triggerId, fetchIdData }),
@@ -363,6 +359,8 @@ const TriggerOutput = ({
useInterval(reloadTriggerDetails, timeout)
+ const latestTriggerHistoryId = useMemo(() => getSortedTriggerHistory(triggerHistory)?.[0]?.[0], [triggerHistory])
+
if (
(!areTagDetailsRequired && triggerDetailsLoading && !triggerDetails) ||
!triggerId ||
@@ -411,6 +409,8 @@ const TriggerOutput = ({
renderTargetConfigInfo={renderTargetConfigInfo}
workflowExecutionStages={triggerDetails.workflowExecutionStages}
namespace={triggerDetails.namespace}
+ isLatest={latestTriggerHistoryId === triggerDetails.id}
+ appName={appName}
/>
diff --git a/src/Shared/Components/CICDHistory/WorkerStatus.tsx b/src/Shared/Components/CICDHistory/WorkerStatus.tsx
index ccf7c79fa..69ce4d7bd 100644
--- a/src/Shared/Components/CICDHistory/WorkerStatus.tsx
+++ b/src/Shared/Components/CICDHistory/WorkerStatus.tsx
@@ -41,6 +41,7 @@ const WorkerStatus = memo(
titleClassName = 'cn-9 fs-13 fw-4 lh-20',
viewWorkerPodClassName = 'fs-13',
hideShowMoreMessageButton = false,
+ children,
}: WorkerStatusType): JSX.Element | null => {
if (!message && !podStatus) {
return null
@@ -98,6 +99,8 @@ const WorkerStatus = memo(
hideShowMore={hideShowMoreMessageButton}
/>
)}
+
+ {children}
>
)
diff --git a/src/Shared/Components/CICDHistory/constants.tsx b/src/Shared/Components/CICDHistory/constants.tsx
index 9d3d366f5..e0b4a3cf6 100644
--- a/src/Shared/Components/CICDHistory/constants.tsx
+++ b/src/Shared/Components/CICDHistory/constants.tsx
@@ -14,10 +14,12 @@
* limitations under the License.
*/
+import { stringComparatorBySortOrder } from '@Shared/Helpers'
import { WorkflowStatusEnum } from '@Shared/types'
import { multiSelectStyles } from '../../../Common/MultiSelectCustomization'
-import { WorkflowStageStatusType } from './types'
+import { FiltersTypeEnum, TableProps } from '../Table'
+import { ResourceConflictItemType, WorkflowStageStatusType } from './types'
export const HISTORY_LABEL = {
APPLICATION: 'Application',
@@ -170,3 +172,48 @@ export const FAILED_WORKFLOW_STAGE_STATUS_MAP: Record<
}
export const APP_HEALTH_DROP_DOWN_LIST = ['inprogress', 'failed', 'disconnect', 'timed_out']
+
+export const RESOURCE_CONFLICT_DEPLOY_ERROR = 'cannot be imported into the current release: invalid ownership metadata;'
+
+export const CONFLICTED_RESOURCES_COLUMNS: TableProps['columns'] = [
+ {
+ field: 'name' satisfies keyof ResourceConflictItemType,
+ label: 'Name',
+ size: {
+ range: {
+ startWidth: 250,
+ maxWidth: 400,
+ minWidth: 120,
+ },
+ },
+ isSortable: true,
+ comparator: stringComparatorBySortOrder,
+ horizontallySticky: true,
+ },
+ {
+ field: 'namespace' satisfies keyof ResourceConflictItemType,
+ label: 'Namespace',
+ size: {
+ range: {
+ startWidth: 150,
+ maxWidth: 400,
+ minWidth: 100,
+ },
+ },
+ comparator: stringComparatorBySortOrder,
+ isSortable: true,
+ },
+ {
+ field: 'gvkTitle' satisfies keyof ResourceConflictItemType,
+ label: 'GVK',
+ size: {
+ range: {
+ startWidth: 250,
+ maxWidth: 400,
+ minWidth: 100,
+ },
+ },
+ isSortable: true,
+ comparator: stringComparatorBySortOrder,
+ },
+]
diff --git a/src/Shared/Components/CICDHistory/service.tsx b/src/Shared/Components/CICDHistory/service.tsx
index 6a130c68c..1a85c464d 100644
--- a/src/Shared/Components/CICDHistory/service.tsx
+++ b/src/Shared/Components/CICDHistory/service.tsx
@@ -15,11 +15,23 @@
*/
/* eslint-disable dot-notation */
+import { generatePath } from 'react-router-dom'
import moment from 'moment'
-import { get, getUrlWithSearchParams, ResponseType, ROUTES, sanitizeUserApprovalMetadata, trash } from '../../../Common'
+import { ToastManager, ToastVariantType } from '@Shared/Services'
+import { GVKType, K8S_EMPTY_GROUP } from '@Pages/ResourceBrowser'
+
+import {
+ get,
+ getUrlWithSearchParams,
+ post,
+ ResponseType,
+ ROUTES,
+ sanitizeUserApprovalMetadata,
+ trash,
+} from '../../../Common'
import { DATE_TIME_FORMAT_STRING, DEPLOYMENT_HISTORY_CONFIGURATION_LIST_MAP, EXTERNAL_TYPES } from '../../constants'
-import { decode, isNullOrUndefined } from '../../Helpers'
+import { decode, getGVKTitle, getUniqueId, isNullOrUndefined } from '../../Helpers'
import { ResourceKindType, ResourceVersionType } from '../../types'
import {
DeploymentHistoryDetail,
@@ -27,7 +39,12 @@ import {
DeploymentHistorySingleValue,
DeploymentStatusDetailsResponse,
FetchIdDataStatus,
+ GetResourceConflictDetailsParamsType,
ModuleConfigResponse,
+ ResourceConflictItemType,
+ ResourceConflictListItemDTO,
+ ResourceConflictRedeployParamsType,
+ ResourceConflictRedeployPayloadType,
TriggerDetailsResponseType,
TriggerHistoryParamsType,
} from './types'
@@ -292,3 +309,51 @@ export const getTriggerHistory = async ({
export const getModuleConfigured = (moduleName: string): Promise =>
get(`${ROUTES.MODULE_CONFIGURED}?name=${moduleName}`)
+
+export const resourceConflictRedeploy = async ({
+ pipelineId,
+ triggerId,
+ appId,
+}: ResourceConflictRedeployParamsType) => {
+ await post(ROUTES.CD_TRIGGER_POST, {
+ pipelineId: +pipelineId,
+ wfrIdForDeploymentWithSpecificTrigger: +triggerId,
+ appId: +appId,
+ helmRedeploymentRequest: true,
+ })
+
+ ToastManager.showToast({
+ variant: ToastVariantType.success,
+ title: 'Redeployment initiated',
+ description: 'Redeployment for application has been successfully initiated.',
+ })
+}
+
+export const getResourceConflictDetails = async ({
+ appId,
+ pipelineId,
+ triggerId,
+ signal,
+}: GetResourceConflictDetailsParamsType): Promise => {
+ const { result } = await get(
+ generatePath(ROUTES.RESOURCE_CONFLICTS_LIST, {
+ appId,
+ pipelineId,
+ wfrId: triggerId,
+ }),
+ { signal },
+ )
+
+ return (result?.conflictingResources || []).map((resource) => ({
+ name: resource.name || '',
+ namespace: resource.namespace || '',
+ gvk: {
+ Group: resource.groupVersionKind.Group || K8S_EMPTY_GROUP,
+ Version: resource.groupVersionKind.Version || '',
+ Kind: resource.groupVersionKind.Kind || ('' as GVKType['Kind']),
+ },
+ gvkTitle: getGVKTitle(resource.groupVersionKind),
+ clusterId: result.clusterId,
+ id: getUniqueId(),
+ }))
+}
diff --git a/src/Shared/Components/CICDHistory/types.tsx b/src/Shared/Components/CICDHistory/types.tsx
index 7f6f8483f..58a299b95 100644
--- a/src/Shared/Components/CICDHistory/types.tsx
+++ b/src/Shared/Components/CICDHistory/types.tsx
@@ -17,6 +17,7 @@
import { CSSProperties, MutableRefObject, ReactElement, ReactNode } from 'react'
import { SupportedKeyboardKeysType } from '@Common/Hooks/UseRegisterShortcut/types'
+import { GVKType } from '@Pages/ResourceBrowser'
import {
DeploymentAppTypes,
@@ -35,6 +36,7 @@ import { DeploymentStageType } from '../../constants'
import {
AggregationKeys,
AppDetails,
+ BaseURLParams,
DeploymentStatusDetailsBreakdownDataType,
DeploymentStatusDetailsType,
DeploymentStatusTimelineType,
@@ -331,6 +333,32 @@ export interface TriggerDetailsType
workerPodName?: string
triggerMetadata?: string
renderDeploymentHistoryTriggerMetaText: (triggerMetaData: string, onlyRenderIcon?: boolean) => JSX.Element
+ /**
+ * Only present in case of CD trigger details as of now
+ */
+ isLatest?: boolean
+ /**
+ * Only present in case of CD trigger details as of now
+ */
+ appName?: string
+}
+
+export enum ResourceConflictModalType {
+ DEPLOY_DIALOG = 'DEPLOY_DIALOG',
+ RESOURCE_DETAIL_MODAL = 'RESOURCE_DETAIL_MODAL',
+}
+
+interface ResourceConflictDialogBaseProps extends Required> {
+ handleClose: () => void
+}
+
+export interface ResourceConflictDeployDialogProps extends ResourceConflictDialogBaseProps {}
+
+export interface ResourceConflictDetailsModalProps extends ResourceConflictDialogBaseProps {}
+
+export interface TriggerOutputURLParamsType extends Pick {
+ triggerId: string
+ pipelineId: string
}
export type ProgressingStatusType = {
@@ -362,6 +390,7 @@ export interface WorkerStatusType
* @default false
*/
hideShowMoreMessageButton?: boolean
+ children?: ReactNode
}
export type FinishedType = { artifact: string; type: HistoryComponentType } & (
@@ -856,3 +885,50 @@ export interface CIPipelineSourceConfigInterface {
primaryBranchAfterRegex?: string
rootClassName?: string
}
+
+export interface ResourceConflictItemType {
+ name: string
+ namespace: string
+ gvk: GVKType
+ gvkTitle: string
+ clusterId: number
+ /**
+ * Generated at ui
+ */
+ id: string
+}
+
+export interface ConflictedResourcesTableProps {
+ resourceConflictDetails: ResourceConflictItemType[]
+}
+
+export interface ResourceConflictDeployDialogURLParamsType
+ extends Pick {}
+
+export interface ResourceConflictRedeployParamsType
+ extends Pick {}
+
+export interface ResourceConflictRedeployPayloadType {
+ pipelineId: number
+ appId: number
+ wfrIdForDeploymentWithSpecificTrigger: number
+ helmRedeploymentRequest: true
+}
+
+export interface GetResourceConflictDetailsParamsType
+ extends Pick {
+ signal: AbortSignal
+}
+
+export interface ResourceConflictListItemDTO {
+ clusterId: number
+ conflictingResources: {
+ name: string
+ namespace: string
+ groupVersionKind: {
+ Group: string
+ Version: string
+ Kind: NodeType
+ }
+ }[]
+}
diff --git a/src/Shared/Components/CICDHistory/utils.tsx b/src/Shared/Components/CICDHistory/utils.tsx
index 90f66bd1f..430d4622f 100644
--- a/src/Shared/Components/CICDHistory/utils.tsx
+++ b/src/Shared/Components/CICDHistory/utils.tsx
@@ -460,3 +460,6 @@ export const getTriggerOutputTabs = (
]
: []),
]
+
+export const getSortedTriggerHistory = (triggerHistory: Map) =>
+ Array.from(triggerHistory).sort(([a], [b]) => b - a)
diff --git a/src/Shared/Components/DocLink/constants.ts b/src/Shared/Components/DocLink/constants.ts
index c4775d779..029e3d3af 100644
--- a/src/Shared/Components/DocLink/constants.ts
+++ b/src/Shared/Components/DocLink/constants.ts
@@ -42,23 +42,24 @@ export const DOCUMENTATION = {
CHART_STORE: 'usage/deploy-chart',
CHART_STORE_METRICS_SERVER: 'dashboard//chart-store/discover?appStoreName=metrics-server',
CUSTOM_VALUES: 'usage/deploy-chart/overview-of-charts#custom-values',
+ CONFIGURING_WEBHOOK: 'usage/applications/creating-application/workflow/ci-pipeline#configuring-webhook',
DEPLOYMENT: 'usage/applications/creating-application/deployment-template/deployment',
DEPLOYMENT_TEMPLATE: 'usage/applications/creating-application/deployment-template',
DEVTRON_UPGRADE: 'getting-started/upgrade',
- CONFIGURING_WEBHOOK: 'usage/applications/creating-application/workflow/ci-pipeline#configuring-webhook',
+ DOC_HOME_PAGE: DOCUMENTATION_HOME_PAGE,
ENTERPRISE_LICENSE: 'enterprise-license',
EXECUTE_CUSTOM_SCRIPT:
'usage/applications/creating-application/workflow/ci-pipeline/ci-build-pre-post-plugins#execute-custom-script',
EXTERNAL_LINKS: 'getting-started/global-configurations/external-links',
EXTERNAL_SECRET: 'usage/applications/creating-application/secrets#external-secrets',
HOME_PAGE: 'https://devtron.ai',
- DOC_HOME_PAGE: DOCUMENTATION_HOME_PAGE,
- KUBE_CONFIG: 'usage/resource-browser#running-kubectl-commands-locally',
JOBS: 'usage/jobs',
- TAINT: 'usage/resource-browser#taint-a-node',
+ KUBE_CONFIG: 'usage/resource-browser#running-kubectl-commands-locally',
RESOURCE_BROWSER: 'usage/resource-browser',
+ TAINT: 'usage/resource-browser#taint-a-node',
// Global Configurations
+ GLOBAL_CONFIGUDATIONS: 'getting-started/global-configurations',
GLOBAL_CONFIG_API_TOKEN: 'getting-started/global-configurations/authorization/api-tokens',
GLOBAL_CONFIG_BUILD_INFRA: 'global-configurations/build-infra',
GLOBAL_CONFIG_CHART: 'getting-started/global-configurations/chart-repo',
@@ -117,6 +118,9 @@ export const DOCUMENTATION = {
GLOBAL_CONFIG_PULL_IMAGE_DIGEST: 'global-configurations/pull-image-digest',
GLOBAL_CONFIG_TAGS: 'getting-started/global-configurations/tags-policy',
+ // Application Management
+ APP_MANAGEMENT: 'docs/user-guide/app-management',
+
// Software Release Management
SOFTWARE_DISTRIBUTION_HUB: 'usage/software-distribution-hub',
RELEASE_TRACKS: 'usage/software-distribution-hub/release-hub#creating-release-tracks-and-versions',
@@ -126,8 +130,21 @@ export const DOCUMENTATION = {
TENANTS_INSTALLATION: 'usage/software-distribution-hub/tenants',
// Infrastructure Management
- AUTOSCALER_DETECTION: 'user-guide/infra-management/infrastructure-overview#troubleshooting-autoscaler-detection',
+ AUTOSCALER_DETECTION:
+ 'docs/user-guide/infra-management/infrastructure-overview#troubleshooting-autoscaler-detection',
+ INFRA_MANAGEMENT: 'docs/user-guide/infra-management',
// Cost Visibility
- COST_CALCULATION: 'user-guide/finops/overview-cost-visibility#how-is-the-cost-calculated',
+ COST_BREAKDOWN: 'docs/user-guide/finops',
+ COST_CALCULATION: 'docs/user-guide/finops/overview-cost-visibility#how-is-the-cost-calculated',
+ COST_VISIBILITY_OVERVIEW: 'docs/user-guide/finops/overview-cost-visibility',
+
+ // Security Center
+ SECURITY_CENTER: 'docs/user-guide/security-features',
+
+ // AI Recommendations
+ AI_RECOMMENDATIONS: 'docs/user-guide/ai-recommendations',
+
+ // Automation & Enablement
+ AUTOMATION_AND_ENABLEMENT: 'docs/user-guide/automation',
} as const
diff --git a/src/Shared/Components/Header/HeaderWithCreateButton/HeaderWithCreateButon.tsx b/src/Shared/Components/Header/HeaderWithCreateButton/HeaderWithCreateButon.tsx
index 9301b40e3..f7000d997 100644
--- a/src/Shared/Components/Header/HeaderWithCreateButton/HeaderWithCreateButon.tsx
+++ b/src/Shared/Components/Header/HeaderWithCreateButton/HeaderWithCreateButon.tsx
@@ -22,6 +22,7 @@ import { BreadCrumb, BreadcrumbText, useBreadcrumb } from '@Common/index'
import { ActionMenu } from '@Shared/Components/ActionMenu'
import { ButtonComponentType } from '@Shared/Components/Button'
import Button from '@Shared/Components/Button/Button.component'
+import { DOCUMENTATION } from '@Shared/Components/DocLink'
import { Icon } from '@Shared/Components/Icon'
import { ComponentSizeType } from '@Shared/constants'
import { useMainContext } from '@Shared/Providers'
@@ -93,6 +94,16 @@ export const HeaderWithCreateButton = ({ viewType }: HeaderWithCreateButtonProps
)
const renderBreadcrumbs = () =>
+ const getDocPath = () => {
+ if (viewType === 'jobs') {
+ return DOCUMENTATION.AUTOMATION_AND_ENABLEMENT
+ }
+ if (viewType === 'infra-apps') {
+ return DOCUMENTATION.INFRA_MANAGEMENT
+ }
+ return DOCUMENTATION.APP_MANAGEMENT
+ }
+
return (
)
diff --git a/src/Shared/Components/Header/HelpButton.tsx b/src/Shared/Components/Header/HelpButton.tsx
index 975f046ea..7e745eb14 100644
--- a/src/Shared/Components/Header/HelpButton.tsx
+++ b/src/Shared/Components/Header/HelpButton.tsx
@@ -55,7 +55,13 @@ const CheckForUpdates = ({
)
-export const HelpButton = ({ serverInfo, fetchingServerInfo, onClick, hideGettingStartedCard }: HelpButtonProps) => {
+export const HelpButton = ({
+ serverInfo,
+ fetchingServerInfo,
+ onClick,
+ hideGettingStartedCard,
+ docPath,
+}: HelpButtonProps) => {
// STATES
const [isActionMenuOpen, setIsActionMenuOpen] = useState(false)
const [expiryDate, setExpiryDate] = useState(0)
@@ -96,7 +102,7 @@ export const HelpButton = ({ serverInfo, fetchingServerInfo, onClick, hideGettin
setSidePanelConfig((prev) => ({
...prev,
state: SidePanelTab.DOCUMENTATION,
- docLink: DOCUMENTATION_HOME_PAGE,
+ docLink: `${DOCUMENTATION_HOME_PAGE}${docPath ? `/${docPath}` : ''}`,
reinitialize: true,
}))
}
@@ -150,6 +156,7 @@ export const HelpButton = ({ serverInfo, fetchingServerInfo, onClick, hideGettin
options={getHelpActionMenuOptions({
isTrialOrFreemium: (licenseData?.isTrial || licenseData?.isFreemium) ?? false,
isEnterprise,
+ docPath,
})}
onClick={handleActionMenuClick}
onOpen={setIsActionMenuOpen}
diff --git a/src/Shared/Components/Header/PageHeader.tsx b/src/Shared/Components/Header/PageHeader.tsx
index 2ccb423ff..fd3f84b5d 100644
--- a/src/Shared/Components/Header/PageHeader.tsx
+++ b/src/Shared/Components/Header/PageHeader.tsx
@@ -50,6 +50,7 @@ const PageHeader = ({
onClose,
tippyProps,
closeIcon,
+ docPath,
}: PageHeaderType) => {
const { setLoginCount, setShowGettingStartedCard, setSidePanelConfig, sidePanelConfig, tempAppWindowConfig } =
useMainContext()
@@ -158,6 +159,7 @@ const PageHeader = ({
fetchingServerInfo={currentServerInfo.fetchingServerInfo}
onClick={handleHelpButtonClick}
hideGettingStartedCard={hideGettingStartedCard}
+ docPath={docPath}
/>
{!window._env_.K8S_CLIENT && (
): HelpButtonActionMenuProps['options'][number]['items'] => [
...((!window._env_?.K8S_CLIENT
? [
{
@@ -36,7 +38,7 @@ export const COMMON_HELP_ACTION_MENU_ITEMS: HelpButtonActionMenuProps['options']
label: 'View documentation',
startIcon: { name: 'ic-book-open' },
componentType: 'anchor',
- href: DOCUMENTATION_HOME_PAGE,
+ href: `${DOCUMENTATION_HOME_PAGE}${docPath ? `/${docPath}` : ''}`,
},
{
id: HelpMenuItems.DEVTRON_GPT,
diff --git a/src/Shared/Components/Header/types.ts b/src/Shared/Components/Header/types.ts
index c97da44dc..4065c8a4e 100644
--- a/src/Shared/Components/Header/types.ts
+++ b/src/Shared/Components/Header/types.ts
@@ -39,6 +39,7 @@ export interface PageHeaderType {
}
onClose?: () => void
closeIcon?: JSX.Element
+ docPath?: string
}
export interface ServerInfo {
@@ -52,7 +53,7 @@ export interface ServerInfoResponse extends ResponseType {
result?: ServerInfo
}
-export interface HelpButtonProps {
+export interface HelpButtonProps extends Pick {
serverInfo: ServerInfo
fetchingServerInfo: boolean
onClick: () => void
@@ -79,3 +80,8 @@ export interface ProfileMenuProps {
user: string
onClick?: () => void
}
+
+export interface HelpActionOptionTypes extends Pick {
+ isEnterprise: boolean
+ isTrialOrFreemium: boolean
+}
diff --git a/src/Shared/Components/Header/utils.ts b/src/Shared/Components/Header/utils.ts
index 50dae36d9..af79adaf6 100644
--- a/src/Shared/Components/Header/utils.ts
+++ b/src/Shared/Components/Header/utils.ts
@@ -17,13 +17,13 @@
import { LOGIN_COUNT } from '@Common/Constants'
import {
- COMMON_HELP_ACTION_MENU_ITEMS,
ENTERPRISE_HELP_ACTION_MENU_ITEMS,
ENTERPRISE_TRIAL_HELP_ACTION_MENU_ITEMS,
+ getCommonHelpActionMenuItems,
OSS_HELP_ACTION_MENU_ITEMS,
} from './constants'
import { updatePostHogEvent } from './service'
-import { HelpButtonActionMenuProps } from './types'
+import { HelpActionOptionTypes, HelpButtonActionMenuProps } from './types'
const millisecondsInDay = 86400000
export const getDateInMilliseconds = (days) => 1 + new Date().valueOf() + (days ?? 0) * millisecondsInDay
@@ -45,12 +45,10 @@ export const setActionWithExpiry = (key: string, days: number): void => {
export const getHelpActionMenuOptions = ({
isEnterprise,
isTrialOrFreemium,
-}: {
- isEnterprise: boolean
- isTrialOrFreemium: boolean
-}): HelpButtonActionMenuProps['options'] => [
+ docPath,
+}: HelpActionOptionTypes): HelpButtonActionMenuProps['options'] => [
{
- items: COMMON_HELP_ACTION_MENU_ITEMS,
+ items: getCommonHelpActionMenuItems({ docPath }),
},
...(isEnterprise
? [
diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx
index 4d80ff930..f9517d50e 100644
--- a/src/Shared/Components/Icon/Icon.tsx
+++ b/src/Shared/Components/Icon/Icon.tsx
@@ -64,6 +64,7 @@ import { ReactComponent as ICCaretLeft } from '@IconsV2/ic-caret-left.svg'
import { ReactComponent as ICCaretRight } from '@IconsV2/ic-caret-right.svg'
import { ReactComponent as ICCd } from '@IconsV2/ic-cd.svg'
import { ReactComponent as ICChartLineUp } from '@IconsV2/ic-chart-line-up.svg'
+import { ReactComponent as ICChartRepo } from '@IconsV2/ic-chart-repo.svg'
import { ReactComponent as ICChatCircleDots } from '@IconsV2/ic-chat-circle-dots.svg'
import { ReactComponent as ICChatCircleOnline } from '@IconsV2/ic-chat-circle-online.svg'
import { ReactComponent as ICCheck } from '@IconsV2/ic-check.svg'
@@ -129,6 +130,7 @@ import { ReactComponent as ICError } from '@IconsV2/ic-error.svg'
import { ReactComponent as ICExitFullscreen } from '@IconsV2/ic-exit-fullscreen.svg'
import { ReactComponent as ICExpandRightSm } from '@IconsV2/ic-expand-right-sm.svg'
import { ReactComponent as ICExpandSm } from '@IconsV2/ic-expand-sm.svg'
+import { ReactComponent as ICExternalLink } from '@IconsV2/ic-external-link.svg'
import { ReactComponent as ICFailure } from '@IconsV2/ic-failure.svg'
import { ReactComponent as ICFastForward } from '@IconsV2/ic-fast-forward.svg'
import { ReactComponent as ICFile } from '@IconsV2/ic-file.svg'
@@ -378,6 +380,7 @@ export const iconMap = {
'ic-caret-right': ICCaretRight,
'ic-cd': ICCd,
'ic-chart-line-up': ICChartLineUp,
+ 'ic-chart-repo': ICChartRepo,
'ic-chat-circle-dots': ICChatCircleDots,
'ic-chat-circle-online': ICChatCircleOnline,
'ic-check-all': ICCheckAll,
@@ -443,6 +446,7 @@ export const iconMap = {
'ic-exit-fullscreen': ICExitFullscreen,
'ic-expand-right-sm': ICExpandRightSm,
'ic-expand-sm': ICExpandSm,
+ 'ic-external-link': ICExternalLink,
'ic-failure': ICFailure,
'ic-fast-forward': ICFastForward,
'ic-file-code': ICFileCode,
diff --git a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx
index 9ebecb106..194cd67a1 100644
--- a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx
+++ b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx
@@ -98,7 +98,7 @@ const InfoBlock = ({
if (layout === 'row') {
return (
-
+
{renderIcon()}
{renderContent()}
diff --git a/src/Shared/Components/SelectPicker/SelectPickerTextArea.component.tsx b/src/Shared/Components/SelectPicker/SelectPickerTextArea.component.tsx
index 5fe8fdb38..2f7181d94 100644
--- a/src/Shared/Components/SelectPicker/SelectPickerTextArea.component.tsx
+++ b/src/Shared/Components/SelectPicker/SelectPickerTextArea.component.tsx
@@ -183,10 +183,8 @@ export const SelectPickerTextArea = ({
selectRef.current.inputRef.selectionEnd = selectionStart + 1
})
- return
+ updateValueIfOnlyDirty()
}
-
- updateValueIfOnlyDirty()
}
return (
diff --git a/src/Shared/Components/Table/InternalTable.tsx b/src/Shared/Components/Table/InternalTable.tsx
index fc93f5203..d179c91a4 100644
--- a/src/Shared/Components/Table/InternalTable.tsx
+++ b/src/Shared/Components/Table/InternalTable.tsx
@@ -24,7 +24,7 @@ import { UseRegisterShortcutProvider } from '@Common/Hooks'
import { NO_ROWS_OR_GET_ROWS_ERROR } from './constants'
import TableContent from './TableContent'
-import { FiltersTypeEnum, InternalTableProps, PaginationEnum, RowsResultType } from './types'
+import { FiltersTypeEnum, InternalTableProps, RowsResultType } from './types'
import { getFilteringPromise, searchAndSortRows } from './utils'
const InternalTable = <
@@ -79,8 +79,6 @@ const InternalTable = <
const wrapperDivRef = useRef
(null)
- const { setIdentifiers } = bulkSelectionReturnValue ?? {}
-
const searchSortTimeoutRef = useRef(-1)
useEffect(() => {
@@ -182,26 +180,6 @@ const InternalTable = <
const areFilteredRowsLoading = _areFilteredRowsLoading || filteredRowsError === NO_ROWS_OR_GET_ROWS_ERROR
- const visibleRows = useMemo(() => {
- const normalizedFilteredRows = filteredRows ?? []
-
- const paginatedRows =
- paginationVariant !== PaginationEnum.PAGINATED
- ? normalizedFilteredRows
- : normalizedFilteredRows.slice(offset, offset + pageSize)
-
- return paginatedRows
- }, [paginationVariant, offset, pageSize, filteredRows])
-
- useEffect(() => {
- setIdentifiers?.(
- visibleRows.reduce((acc, row) => {
- acc[row.id] = row
- return acc
- }, {}),
- )
- }, [visibleRows])
-
const Wrapper = ViewWrapper ?? Fragment
const renderContent = () => {
diff --git a/src/Shared/Helpers.tsx b/src/Shared/Helpers.tsx
index be06ee862..902bd8d9a 100644
--- a/src/Shared/Helpers.tsx
+++ b/src/Shared/Helpers.tsx
@@ -53,7 +53,7 @@ import {
UserApprovalInfo,
ZERO_TIME_STRING,
} from '../Common'
-import { getAggregator } from '../Pages'
+import { getAggregator, GVKType } from '../Pages'
import { AggregatedNodes, PodMetadatum } from './Components'
import { CUBIC_BEZIER_CURVE, UNSAVED_CHANGES_PROMPT_MESSAGE } from './constants'
import {
@@ -767,3 +767,24 @@ export const explainCronExpression = (expression: string): string => {
parseCronExpression(expression, { hasSeconds: expression.trim().split(' ').length > 5 })
return cronstrue.toString(expression)
}
+
+export const getGVKTitle = (gvk: GVKType): string => {
+ if (!gvk) {
+ return ''
+ }
+
+ let title: string = ''
+ if (gvk.Group) {
+ title += gvk.Group
+ }
+
+ if (gvk.Version) {
+ title += title ? ` / ${gvk.Version}` : gvk.Version
+ }
+
+ if (gvk.Kind) {
+ title += title ? ` / ${gvk.Kind}` : gvk.Kind
+ }
+
+ return title
+}
diff --git a/src/Shared/Hooks/useUserPreferences/types.ts b/src/Shared/Hooks/useUserPreferences/types.ts
index a3c2db55d..a03c7eb10 100644
--- a/src/Shared/Hooks/useUserPreferences/types.ts
+++ b/src/Shared/Hooks/useUserPreferences/types.ts
@@ -17,74 +17,7 @@
import { USER_PREFERENCES_ATTRIBUTE_KEY } from '@Shared/Hooks/useUserPreferences/constants'
import { AppThemeType, ThemeConfigType, ThemePreferenceType } from '@Shared/Providers/ThemeProvider/types'
import { ResourceKindType } from '@Shared/types'
-
-export type NavigationItemID =
- | 'application-management-overview'
- | 'application-management-devtron-applications'
- | 'application-management-application-groups'
- | 'application-management-bulk-edit'
- | 'application-management-application-templates'
- | 'application-management-projects'
- | 'application-management-configurations'
- | 'application-management-policies'
- | 'infrastructure-management-overview'
- | 'infrastructure-management-applications'
- | 'infrastructure-management-chart-store'
- | 'infrastructure-management-resource-browser'
- | 'infrastructure-management-resource-watcher'
- | 'infrastructure-management-catalog-framework'
- | 'software-release-management-overview'
- | 'software-release-management-release-hub'
- | 'software-release-management-tenants'
- | 'cost-visibility-overview'
- | 'cost-visibility-cost-breakdown'
- | 'cost-visibility-configurations'
- | 'security-center-overview'
- | 'security-center-security-vulnerabilities'
- | 'security-center-security-enablement'
- | 'security-center-security-policy'
- | 'automation-and-enablement-jobs'
- | 'automation-and-enablement-alerting'
- | 'automation-and-enablement-incident-response'
- | 'automation-and-enablement-api-portal'
- | 'automation-and-enablement-runbook-automation'
- | 'global-configuration-sso-login-services'
- | 'global-configuration-host-urls'
- | 'global-configuration-cluster-and-environments'
- | 'global-configuration-container-oci-registry'
- | 'global-configuration-authorization'
- | 'data-protection-overview'
- | 'data-protection-backup-and-schedule'
- | 'data-protection-restores'
- | 'data-protection-backup-repositories'
- | 'data-protection-backup-locations'
- | 'data-protection-history-and-logs'
-
-export type NavigationSubMenuItemID =
- | 'application-management-configurations-gitops'
- | 'application-management-configurations-git-accounts'
- | 'application-management-configurations-external-links'
- | 'application-management-configurations-chart-repository'
- | 'application-management-configurations-deployment-charts'
- | 'application-management-configurations-notifications'
- | 'application-management-configurations-catalog-frameworks'
- | 'application-management-configurations-scoped-variables'
- | 'application-management-configurations-build-infra'
- | 'application-management-policies-deployment-window'
- | 'application-management-policies-approval-policy'
- | 'application-management-policies-plugin-policy'
- | 'application-management-policies-pull-image-digest'
- | 'application-management-policies-tag-policy'
- | 'application-management-policies-filter-conditions'
- | 'application-management-policies-image-promotion'
- | 'application-management-policies-lock-deployment-configuration'
- | 'cost-visibility-cost-breakdown-clusters'
- | 'cost-visibility-cost-breakdown-environments'
- | 'cost-visibility-cost-breakdown-projects'
- | 'cost-visibility-cost-breakdown-applications'
- | 'global-configuration-authorization-user-permissions'
- | 'global-configuration-authorization-permission-groups'
- | 'global-configuration-authorization-api-tokens'
+import { NavigationItemID, NavigationSubMenuItemID } from '@PagesDevtron2.0/Navigation'
export interface GetUserPreferencesQueryParamsType {
key: typeof USER_PREFERENCES_ATTRIBUTE_KEY