diff --git a/package-lock.json b/package-lock.json index bcc9c0f6c..c47b15391 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.22.0-alpha-12", + "version": "1.22.8-beta-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.22.0-alpha-12", + "version": "1.22.8-beta-10", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 09462f1d5..26b0ca8f6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.22.0-alpha-12", + "version": "1.22.8-beta-10", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Assets/IconV2/ic-bell.svg b/src/Assets/IconV2/ic-bell.svg new file mode 100644 index 000000000..a67b2859b --- /dev/null +++ b/src/Assets/IconV2/ic-bell.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-bulb.svg b/src/Assets/IconV2/ic-bulb.svg new file mode 100644 index 000000000..a167e3b3a --- /dev/null +++ b/src/Assets/IconV2/ic-bulb.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Assets/IconV2/ic-close-circle.svg b/src/Assets/IconV2/ic-close-circle.svg new file mode 100644 index 000000000..5c48b3451 --- /dev/null +++ b/src/Assets/IconV2/ic-close-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-comment.svg b/src/Assets/IconV2/ic-comment.svg new file mode 100644 index 000000000..096533e21 --- /dev/null +++ b/src/Assets/IconV2/ic-comment.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-curved-arrow.svg b/src/Assets/IconV2/ic-curved-arrow.svg new file mode 100644 index 000000000..04b4044dd --- /dev/null +++ b/src/Assets/IconV2/ic-curved-arrow.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Assets/IconV2/ic-dot-circle.svg b/src/Assets/IconV2/ic-dot-circle.svg new file mode 100644 index 000000000..149c94bab --- /dev/null +++ b/src/Assets/IconV2/ic-dot-circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-medium-megaphone.svg b/src/Assets/IconV2/ic-medium-megaphone.svg new file mode 100644 index 000000000..8e94590f0 --- /dev/null +++ b/src/Assets/IconV2/ic-medium-megaphone.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Assets/IconV2/ic-nav-cursor.svg b/src/Assets/IconV2/ic-nav-cursor.svg new file mode 100644 index 000000000..295732275 --- /dev/null +++ b/src/Assets/IconV2/ic-nav-cursor.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/IconV2/ic-new-chat.svg b/src/Assets/IconV2/ic-new-chat.svg new file mode 100644 index 000000000..a5d366419 --- /dev/null +++ b/src/Assets/IconV2/ic-new-chat.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Assets/IconV2/ic-piggybank.svg b/src/Assets/IconV2/ic-piggybank.svg new file mode 100644 index 000000000..44619eebe --- /dev/null +++ b/src/Assets/IconV2/ic-piggybank.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-priority-high-fill.svg b/src/Assets/IconV2/ic-priority-high-fill.svg new file mode 100644 index 000000000..9e084e5ee --- /dev/null +++ b/src/Assets/IconV2/ic-priority-high-fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-priority-low-fill.svg b/src/Assets/IconV2/ic-priority-low-fill.svg new file mode 100644 index 000000000..0b7c7a735 --- /dev/null +++ b/src/Assets/IconV2/ic-priority-low-fill.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/Assets/IconV2/ic-priority-urgent-fill.svg b/src/Assets/IconV2/ic-priority-urgent-fill.svg new file mode 100644 index 000000000..ec8140320 --- /dev/null +++ b/src/Assets/IconV2/ic-priority-urgent-fill.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/src/Assets/IconV2/ic-red-bulb.svg b/src/Assets/IconV2/ic-red-bulb.svg new file mode 100644 index 000000000..f6d6482af --- /dev/null +++ b/src/Assets/IconV2/ic-red-bulb.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/Assets/IconV2/ic-thumb-down-fill.svg b/src/Assets/IconV2/ic-thumb-down-fill.svg new file mode 100644 index 000000000..424e814a4 --- /dev/null +++ b/src/Assets/IconV2/ic-thumb-down-fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-thumb-up-fill.svg b/src/Assets/IconV2/ic-thumb-up-fill.svg new file mode 100644 index 000000000..7b5a06ab7 --- /dev/null +++ b/src/Assets/IconV2/ic-thumb-up-fill.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/Illustration/cmd-bar-visual.webp b/src/Assets/Illustration/cmd-bar-visual.webp new file mode 100644 index 000000000..2ca70968f Binary files /dev/null and b/src/Assets/Illustration/cmd-bar-visual.webp differ diff --git a/src/Assets/Illustration/img-celebration.svg b/src/Assets/Illustration/img-celebration.svg new file mode 100644 index 000000000..1982add63 --- /dev/null +++ b/src/Assets/Illustration/img-celebration.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/Illustration/img-install-freemium-saas.svg b/src/Assets/Illustration/img-install-freemium-saas.svg new file mode 100644 index 000000000..3ee2d147b --- /dev/null +++ b/src/Assets/Illustration/img-install-freemium-saas.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Assets/Illustration/img-install-via-aws-marketplace.svg b/src/Assets/Illustration/img-install-via-aws-marketplace.svg new file mode 100644 index 000000000..e98457714 --- /dev/null +++ b/src/Assets/Illustration/img-install-via-aws-marketplace.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Assets/Illustration/img-installing-devtron.svg b/src/Assets/Illustration/img-installing-devtron.svg new file mode 100644 index 000000000..672175a5e --- /dev/null +++ b/src/Assets/Illustration/img-installing-devtron.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Assets/Illustration/img-page-not-found.svg b/src/Assets/Illustration/img-page-not-found.svg new file mode 100644 index 000000000..b0de197a2 --- /dev/null +++ b/src/Assets/Illustration/img-page-not-found.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Common/API/CoreAPI.ts b/src/Common/API/CoreAPI.ts index c5056e8d9..0cb8f0165 100644 --- a/src/Common/API/CoreAPI.ts +++ b/src/Common/API/CoreAPI.ts @@ -55,6 +55,13 @@ class CoreAPI { method: type, signal, body: data ? JSON.stringify(data) : undefined, + ...(data && !isMultipartRequest + ? { + headers: { + 'Content-Type': 'application/json', + }, + } + : {}), } // eslint-disable-next-line dot-notation options['credentials'] = 'include' as RequestCredentials diff --git a/src/Common/API/reactQueryHooks.ts b/src/Common/API/reactQueryHooks.ts index 4b1ceed8d..f37b12533 100644 --- a/src/Common/API/reactQueryHooks.ts +++ b/src/Common/API/reactQueryHooks.ts @@ -16,6 +16,9 @@ import { QueryKey, + useInfiniteQuery as rqUseInfiniteQuery, + UseInfiniteQueryOptions, + UseInfiniteQueryResult, useMutation as rqUseMutation, UseMutationOptions, UseMutationResult, @@ -43,7 +46,22 @@ export const useQuery = < ): UseQueryResult => rqUseQuery(options) export const useMutation = ( - options: UseMutationOptions, ServerErrors, TVariables, TContext>, -): UseMutationResult, ServerErrors, TVariables, TContext> => rqUseMutation(options) + options: UseMutationOptions, +): UseMutationResult => rqUseMutation(options) + +export const useInfiniteQuery = < + TQueryFnData = unknown, + TData = TQueryFnData, + TQueryKey extends QueryKey = QueryKey, + WrapWithResponseType extends boolean = true, +>( + options: UseInfiniteQueryOptions< + WrapWithResponseType extends true ? ResponseType : TQueryFnData, + ServerErrors, + TData, + WrapWithResponseType extends true ? ResponseType : TQueryFnData, + TQueryKey + >, +): UseInfiniteQueryResult => rqUseInfiniteQuery(options) export { useQueryClient } diff --git a/src/Common/API/utils.ts b/src/Common/API/utils.ts index 7d30db314..48a9451e6 100644 --- a/src/Common/API/utils.ts +++ b/src/Common/API/utils.ts @@ -17,6 +17,7 @@ import { MutableRefObject } from 'react' import { URLS } from '@Common/Constants' +import { getUrlWithSearchParams } from '@Common/Helper' import { ServerErrors } from '@Common/ServerError' import { RESPONSE_MESSAGES } from './constants' @@ -62,7 +63,9 @@ export const getIsRequestAborted = (error) => export const handleDashboardLogout = () => { const continueParam = `${window.location.pathname.replace(window.__BASE_URL__, '')}${window.location.search}` - window.location.href = `${window.location.origin}${window.__BASE_URL__}${URLS.LOGIN_SSO}?continue=${continueParam}` + window.location.href = getUrlWithSearchParams(`${window.location.origin}${window.__BASE_URL__}${URLS.LOGIN_SSO}`, { + continue: continueParam, + }) } export const handleRedirectToLicenseActivation = () => { diff --git a/src/Common/ClipboardButton/ClipboardButton.tsx b/src/Common/ClipboardButton/ClipboardButton.tsx index db62bd6da..dffdb197f 100644 --- a/src/Common/ClipboardButton/ClipboardButton.tsx +++ b/src/Common/ClipboardButton/ClipboardButton.tsx @@ -99,8 +99,6 @@ export const ClipboardButton = ({ const iconClassName = `icon-dim-${iconSize} dc__no-shrink` - const ariaLabel = `Copy ${content}` - const renderIcon = () => (
{copied ? : } @@ -109,10 +107,10 @@ export const ClipboardButton = ({ const tooltipContent = copied ? copiedTippyText : initialTippyText - if (variant === 'button--secondary') { + if (variant === 'button--secondary' || variant === 'borderLess') { return ( - - )} + !tempAppWindowConfig.open && } + ) => { - if (isFreemium) { - const freemiumLimitReached = licenseStatusError?.code === LicensingErrorCodes.ClusterLimitExceeded + isFreeForever, +}: LicenseCardSubTextProps) => { + const freemiumLimitReached = isFreemium && licenseStatusError?.code === LicensingErrorCodes.ClusterLimitExceeded + const showFreemiumMessage = + isFreeForever || freemiumLimitReached || (isFreemium && licenseStatus === LicenseStatus.ACTIVE) + if (showFreemiumMessage) { return (
@@ -130,10 +133,17 @@ export const DevtronLicenseCard = ({ appTheme, handleCopySuccess, licenseStatusError, + isSaasInstance, }: DevtronLicenseCardProps) => { - const { bgColor, textColor } = getLicenseColorsAccordingToStatus({ isFreemium, licenseStatus, licenseStatusError }) - const remainingTime = getTTLInHumanReadableFormat(ttl) - const remainingTimeString = ttl < 0 ? `Expired ${remainingTime} ago` : `${remainingTime} remaining` + const isFreeForever = isFreemium && !isSaasInstance + + const { bgColor, textColor } = getLicenseColorsAccordingToStatus({ + isFreemium, + licenseStatus, + licenseStatusError, + isSaasInstance, + }) + const isThemeDark = appTheme === AppThemeType.dark const cardRef = useRef(null) @@ -178,6 +188,15 @@ export const DevtronLicenseCard = ({ ? useMotionTemplate`linear-gradient(55deg, transparent, rgba(122, 127, 131, ${sheenOpacity}) ${sheenPosition}%, transparent)` : useMotionTemplate`linear-gradient(55deg, transparent, rgba(255, 255, 255, ${sheenOpacity}) ${sheenPosition}%, transparent)` + const getRemainingTimeString = () => { + if (isFreeForever) { + return null + } + + const remainingTime = getTTLInHumanReadableFormat(ttl) + return ttl < 0 ? `Expired ${remainingTime} ago` : `${remainingTime} remaining` + } + return (
@@ -217,12 +236,12 @@ export const DevtronLicenseCard = ({
- {isFreemium ? 'VALID FOREVER' : expiryDate} + {isFreeForever ? 'VALID FOREVER' : expiryDate} - {!isFreemium && ( + {!isFreeForever && ( <> ยท - {remainingTimeString} + {getRemainingTimeString()} )}
@@ -239,6 +258,7 @@ export const DevtronLicenseCard = ({ isFreemium={isFreemium} licenseStatusError={licenseStatusError} licenseStatus={licenseStatus} + isFreeForever={isFreeForever} />
) diff --git a/src/Shared/Components/License/index.tsx b/src/Shared/Components/License/index.tsx index 75fa48db5..52c765f60 100644 --- a/src/Shared/Components/License/index.tsx +++ b/src/Shared/Components/License/index.tsx @@ -17,5 +17,6 @@ export { default as ActivateLicenseDialog } from './ActivateLicenseDialog' export { default as DevtronLicenseCard } from './DevtronLicenseCard' export { ICDevtronWithBorder, default as InstallationFingerprintInfo } from './License.components' +export { activateLicense } from './services' export * from './types' export { parseDevtronLicenseData, parseDevtronLicenseDTOIntoLicenseCardData } from './utils' diff --git a/src/Shared/Components/License/types.ts b/src/Shared/Components/License/types.ts index 38b2be000..4c2d639ae 100644 --- a/src/Shared/Components/License/types.ts +++ b/src/Shared/Components/License/types.ts @@ -32,6 +32,7 @@ export type DevtronLicenseCardProps = { isFreemium: boolean appTheme: AppThemeType licenseStatusError: LicenseErrorStruct + isSaasInstance: boolean } & ( | { licenseKey: string @@ -45,6 +46,11 @@ export type DevtronLicenseCardProps = { } ) +export interface LicenseCardSubTextProps + extends Pick { + isFreeForever: boolean +} + export type DevtronLicenseInfo = Omit & Pick diff --git a/src/Shared/Components/License/utils.tsx b/src/Shared/Components/License/utils.tsx index 540d14613..423eb9648 100644 --- a/src/Shared/Components/License/utils.tsx +++ b/src/Shared/Components/License/utils.tsx @@ -27,16 +27,22 @@ export const getLicenseColorsAccordingToStatus = ({ isFreemium, licenseStatus, licenseStatusError, -}: Pick): { + isSaasInstance, +}: Pick): { bgColor: string textColor: string } => { if (isFreemium) { const freemiumLimitReached = licenseStatusError?.code === LicensingErrorCodes.ClusterLimitExceeded - return freemiumLimitReached - ? { bgColor: 'var(--R100)', textColor: 'var(--R500)' } - : { bgColor: 'var(--G100)', textColor: 'var(--G500)' } + if (freemiumLimitReached) { + return { bgColor: 'var(--R100)', textColor: 'var(--R500)' } + } + + if (!isSaasInstance) { + return { bgColor: 'var(--G100)', textColor: 'var(--G500)' } + } } + switch (licenseStatus) { case LicenseStatus.ACTIVE: return { bgColor: 'var(--G100)', textColor: 'var(--G500)' } @@ -68,16 +74,24 @@ export const parseDevtronLicenseDTOIntoLicenseCardData = => { const { isTrial, - expiry, - ttl, + expiry: onPremExpiry, + ttl: onPremTTL, reminderThreshold, organisationMetadata, license, claimedByUserDetails, isFreemium, licenseStatusError, + isSaasInstance, + timeElapsedSinceCreation, + creationTime, } = licenseDTO || {} + // In case of Saas expiry date is 30 days from creation time + const expiry = isSaasInstance && creationTime ? moment(creationTime).add(30, 'days').toISOString() : onPremExpiry + // For TTL will use timeElapsedSinceCreation to calculate remaining time for Saas license with 30 days validity, since browser time may differ from server time + const ttl = isSaasInstance && timeElapsedSinceCreation ? 30 * 24 * 60 * 60 - timeElapsedSinceCreation : onPremTTL + return { enterpriseName: organisationMetadata?.name || 'Devtron Enterprise', expiryDate: expiry ? moment(expiry).format(DATE_TIME_FORMATS['DD/MM/YYYY']) : '', @@ -86,6 +100,7 @@ export const parseDevtronLicenseDTOIntoLicenseCardData = (
diff --git a/src/Shared/Components/Textarea/Textarea.component.tsx b/src/Shared/Components/Textarea/Textarea.component.tsx index a50374557..8a6080be6 100644 --- a/src/Shared/Components/Textarea/Textarea.component.tsx +++ b/src/Shared/Components/Textarea/Textarea.component.tsx @@ -82,21 +82,22 @@ const Textarea = ({ }, []) const reInitHeight = () => { - const currentHeight = parseInt(textareaRef.current.style.height, 10) - let nextHeight = textareaRef.current.scrollHeight || 0 - - if (nextHeight < currentHeight || currentHeight > AUTO_EXPANSION_MAX_HEIGHT) { + const textarea = textareaRef.current + if (!textarea) { return } - if (nextHeight < MIN_HEIGHT) { - nextHeight = MIN_HEIGHT - } + textarea.style.height = 'auto' + let nextHeight = textarea.scrollHeight if (nextHeight > AUTO_EXPANSION_MAX_HEIGHT) { nextHeight = AUTO_EXPANSION_MAX_HEIGHT + textarea.style.overflowY = 'auto' + } else { + textarea.style.overflowY = 'hidden' } + nextHeight = Math.max(MIN_HEIGHT, nextHeight) updateRefsHeight(nextHeight) } diff --git a/src/Shared/Helpers.tsx b/src/Shared/Helpers.tsx index 902bd8d9a..6f5a16c46 100644 --- a/src/Shared/Helpers.tsx +++ b/src/Shared/Helpers.tsx @@ -54,7 +54,7 @@ import { ZERO_TIME_STRING, } from '../Common' import { getAggregator, GVKType } from '../Pages' -import { AggregatedNodes, PodMetadatum } from './Components' +import { AggregatedNodes } from './Components' import { CUBIC_BEZIER_CURVE, UNSAVED_CHANGES_PROMPT_MESSAGE } from './constants' import { AggregationKeys, @@ -65,6 +65,7 @@ import { IntersectionOptions, Node, Nodes, + PodMetaData, TargetPlatformItemDTO, TargetPlatformsDTO, WebhookEventNameType, @@ -298,7 +299,7 @@ export const renderValidInputButtonTippy = (children: ReactElement) => ( ) -export function aggregateNodes(nodes: any[], podMetadata: PodMetadatum[]): AggregatedNodes { +export function aggregateNodes(nodes: any[], podMetadata: PodMetaData[]): AggregatedNodes { const podMetadataMap = mapByKey(podMetadata, 'name') // group nodes const nodesGroup = nodes.reduce((agg, curr) => { diff --git a/src/Shared/Hooks/useGetResourceKindsOptions/index.ts b/src/Shared/Hooks/useGetResourceKindsOptions/index.ts index 86a41c642..0a1de1da2 100644 --- a/src/Shared/Hooks/useGetResourceKindsOptions/index.ts +++ b/src/Shared/Hooks/useGetResourceKindsOptions/index.ts @@ -14,5 +14,6 @@ * limitations under the License. */ +export { getProjectOptions } from './service' export type { UseGetResourceKindOptionsReturnType, UseGetResourceKindsOptionsProps } from './types' export { default as useGetResourceKindsOptions } from './useGetResourceKindsOptions' diff --git a/src/Shared/Providers/MainContextProvider/index.ts b/src/Shared/Providers/MainContextProvider/index.ts index 8c0dd4e1d..332cee39d 100644 --- a/src/Shared/Providers/MainContextProvider/index.ts +++ b/src/Shared/Providers/MainContextProvider/index.ts @@ -16,4 +16,4 @@ export * from './MainContextProvider' export type { MainContext, ReloadVersionConfigTypes, SidePanelConfig, TempAppWindowConfig } from './types' -export { SidePanelTab } from './types' +export { AIAgentContextSourceType, type AIAgentContextType, SidePanelTab } from './types' diff --git a/src/Shared/Providers/MainContextProvider/types.ts b/src/Shared/Providers/MainContextProvider/types.ts index f04949c4d..cff7ce452 100644 --- a/src/Shared/Providers/MainContextProvider/types.ts +++ b/src/Shared/Providers/MainContextProvider/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react' +import { Dispatch, FunctionComponent, MutableRefObject, ReactNode, SetStateAction } from 'react' import { SERVER_MODE } from '../../../Common' import { @@ -48,11 +48,71 @@ export interface SidePanelConfig { /** URL to documentation that should be displayed in the panel */ docLink: string | null aiSessionId?: string + isExpandedView?: boolean } -type AIAgentContextType = { - path: string - context: Record +export enum AIAgentContextSourceType { + APP_DETAILS = 'app-details', + RESOURCE_BROWSER_CLUSTER = 'resource-browser-cluster', +} + +export type AIAgentAppType = + | 'devtronApp' + | 'devtronHelmChart' + | 'externalHelmChart' + | 'externalArgoApp' + | 'externalFluxApp' + +type AIAgentAppDataMasterType = { + appId: number | string + appName: string + envId: number + envName: string + clusterId: number + namespace: string + appType: AIAgentAppType + fluxAppDeploymentType: string +} + +type AIAgentAppDataType = Pick< + AIAgentAppDataMasterType, + TRequiredFields +> & { + [K in Exclude]?: never +} & { + appType: TAppType +} + +type CommonContextDataType = Record & { + uiMarkup?: string +} + +export type AIAgentContextType = + | { + source: AIAgentContextSourceType.APP_DETAILS + data: + | AIAgentAppDataType< + 'devtronApp' | 'devtronHelmChart', + 'appId' | 'appName' | 'envId' | 'envName' | 'clusterId' + > + | AIAgentAppDataType<'externalHelmChart', 'appId' | 'appName' | 'clusterId' | 'namespace'> + | AIAgentAppDataType<'externalArgoApp', 'appName' | 'clusterId' | 'namespace'> + | (AIAgentAppDataType< + 'externalFluxApp', + 'appName' | 'clusterId' | 'namespace' | 'fluxAppDeploymentType' + > & + CommonContextDataType) + } + | { + source: AIAgentContextSourceType.RESOURCE_BROWSER_CLUSTER + data: { + clusterId: number + clusterName: string + } & CommonContextDataType + } + +export type DebugAgentContextType = AIAgentContextType & { + prompt?: string } export interface TempAppWindowConfig { @@ -118,6 +178,8 @@ type CommonMainContextProps = { setLicenseData: Dispatch> canFetchHelmAppStatus: boolean setIntelligenceConfig: Dispatch> + debugAgentContext: DebugAgentContextType | null + setDebugAgentContext: (aiAgentContext: DebugAgentContextType | null) => void setAIAgentContext: (aiAgentContext: AIAgentContextType) => void setSidePanelConfig: Dispatch> } & Pick @@ -152,6 +214,9 @@ export type MainContext = CommonMainContextProps & aiAgentContext: AIAgentContextType tempAppWindowConfig: TempAppWindowConfig setTempAppWindowConfig: Dispatch> + AIRecommendations?: FunctionComponent + featureAskDevtronExpert: EnvironmentDataValuesDTO['featureAskDevtronExpert'] + AskDevtronButton?: FunctionComponent } | { isLicenseDashboard: true @@ -170,6 +235,9 @@ export type MainContext = CommonMainContextProps & aiAgentContext: null tempAppWindowConfig: null setTempAppWindowConfig: null + AIRecommendations?: null + featureAskDevtronExpert?: null + AskDevtronButton?: null } ) diff --git a/src/Shared/Services/types.ts b/src/Shared/Services/types.ts index dd0ba0e8e..7a2fdf857 100644 --- a/src/Shared/Services/types.ts +++ b/src/Shared/Services/types.ts @@ -61,6 +61,7 @@ export interface EnvironmentDataValuesDTO extends Pick = { [RemoteConnectionType.Direct]: 'Direct Connection', diff --git a/src/Shared/types.ts b/src/Shared/types.ts index 76a6859f3..1179c6df8 100644 --- a/src/Shared/types.ts +++ b/src/Shared/types.ts @@ -175,13 +175,24 @@ export interface iNode extends Node { status: string pNode?: iNode } + +export interface HelmReleaseStatus { + status: string + message: string + description: string +} + export interface ResourceTree { - conditions: any + nodes: Node[] newGenerationReplicaSet: string - nodes: Array - podMetadata: Array status: string + podMetadata: PodMetaData[] + conditions?: any + releaseStatus?: HelmReleaseStatus resourcesSyncResult?: Record + hasDrift?: boolean + // lastSnapshotTime and wfrId are only available for isolated + lastSnapshotTime?: string wfrId?: number } @@ -193,12 +204,6 @@ export enum AppType { EXTERNAL_FLUX_APP = 'external_flux_app', } -export interface HelmReleaseStatus { - status: string - message: string - description: string -} - interface MaterialInfo { author: string branch: string @@ -222,7 +227,7 @@ export interface AppDetails { appStoreChartName?: string appStoreInstalledAppVersionId?: number ciArtifactId?: number - deprecated?: false + deprecated?: boolean environmentId?: number environmentName: string installedAppId?: number @@ -258,6 +263,12 @@ export interface AppDetails { FluxAppStatusDetail?: FluxAppStatusDetail isPipelineTriggered?: boolean releaseMode?: ReleaseMode + cdPipelineId?: number + triggerType?: string + parentEnvironmentName?: string + ciPipelineId?: number + trafficSwitched?: boolean + pcoId?: number } export interface ConfigDriftModalProps extends Required> { @@ -1106,18 +1117,10 @@ export interface LicenseErrorStruct { userMessage: string } -export interface DevtronLicenseBaseDTO { +export type DevtronLicenseBaseDTO = { fingerprint: string | null isTrial: boolean | null isFreemium: boolean | null - /** - * In timestamp format - */ - expiry: string | null - /** - * Can be negative, depicts time left in seconds for license to expire - */ - ttl: number | null /** * Show a reminder after these many DAYS left for license to expire, i.e, * Show if `ttl` is less than `reminderThreshold` [converted to seconds] @@ -1128,7 +1131,31 @@ export interface DevtronLicenseBaseDTO { domain: string | null } | null license: string | null -} +} & ( + | { + isSaasInstance: true + /** + * In seconds + */ + timeElapsedSinceCreation: number + creationTime: string + ttl?: never + expiry?: never + } + | { + isSaasInstance?: false + timeElapsedSinceCreation?: never + creationTime?: never + /** + * Can be negative, depicts time left in seconds for license to expire + */ + ttl: number | null + /** + * In timestamp format + */ + expiry: string | null + } +) export type DevtronLicenseDTO = DevtronLicenseBaseDTO & (isCentralDashboard extends true @@ -1141,9 +1168,14 @@ export type DevtronLicenseDTO = Devt showLicenseData?: never licenseStatusError?: never moduleLimits?: never + instanceData: { + devtronUrl: string + devtronPassword: string + } | null } : { claimedByUserDetails?: never + instanceData?: never showLicenseData: boolean licenseStatusError?: LicenseErrorStruct moduleLimits: { @@ -1327,7 +1359,7 @@ export interface DeploymentStatusDetailsBreakdownDataType { export interface IntelligenceConfig { clusterId: number - metadata: Record + metadata: Record prompt: string analyticsCategory: string } diff --git a/src/Shared/validations.tsx b/src/Shared/validations.tsx index 1f3d936a0..ac5d9cb75 100644 --- a/src/Shared/validations.tsx +++ b/src/Shared/validations.tsx @@ -561,3 +561,31 @@ export const validateCronExpression = (expression: string): ValidationResponseTy } } } + +export const validateAppName = (value: string): Required => { + const re = PATTERNS.APP_NAME + const regExp = new RegExp(re) + const test = regExp.test(value) + + if (value.length === 0) { + return { isValid: false, message: 'Please provide app name' } + } + + if (value.length < 3) { + return { isValid: false, message: MESSAGES.getMinCharMessage(3) } + } + + if (value.length > 30) { + return { isValid: false, message: MESSAGES.getMaxCharMessage(30) } + } + + if (!test) { + return { + isValid: false, + message: + "Min 3 chars; Start with alphabet; End with alphanumeric; Use only lowercase; Allowed:(-); Do not use 'spaces'", + } + } + + return { isValid: true, message: '' } +} diff --git a/src/index.ts b/src/index.ts index fbff34eac..6ccacbbaa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -155,7 +155,6 @@ export interface customEnv { GATEKEEPER_URL?: string FEATURE_AI_INTEGRATION_ENABLE?: boolean LOGIN_PAGE_IMAGE?: string - FEATURE_ASK_DEVTRON_EXPERT?: boolean /** * If true, the manage traffic feature is enabled in apps & app groups. * @@ -188,6 +187,9 @@ export interface customEnv { * @default false */ FEATURE_STORAGE_ENABLE?: boolean + FEATURE_ATHENA_DEBUG_MODE_ENABLE?: boolean + /** Org ID for grafana */ + GRAFANA_ORG_ID?: number } declare global { interface Window {