From ae1e375d4ecda40df438be42eff57cbe5fd341f9 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 7 Apr 2025 17:48:55 +0530 Subject: [PATCH 01/80] feat: add rocket launch icon --- src/Assets/IconV2/ic-rocket-launch.svg | 3 +++ src/Shared/Components/Icon/Icon.tsx | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 src/Assets/IconV2/ic-rocket-launch.svg diff --git a/src/Assets/IconV2/ic-rocket-launch.svg b/src/Assets/IconV2/ic-rocket-launch.svg new file mode 100644 index 000000000..652cd1197 --- /dev/null +++ b/src/Assets/IconV2/ic-rocket-launch.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index a859c144e..518480072 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -85,6 +85,7 @@ import { ReactComponent as ICPaperPlaneColor } from '@IconsV2/ic-paper-plane-col import { ReactComponent as ICPencil } from '@IconsV2/ic-pencil.svg' import { ReactComponent as ICQuay } from '@IconsV2/ic-quay.svg' import { ReactComponent as ICQuote } from '@IconsV2/ic-quote.svg' +import { ReactComponent as ICRocketLaunch } from '@IconsV2/ic-rocket-launch.svg' import { ReactComponent as ICShieldCheck } from '@IconsV2/ic-shield-check.svg' import { ReactComponent as ICSortAscending } from '@IconsV2/ic-sort-ascending.svg' import { ReactComponent as ICSortDescending } from '@IconsV2/ic-sort-descending.svg' @@ -193,6 +194,7 @@ export const iconMap = { 'ic-pencil': ICPencil, 'ic-quay': ICQuay, 'ic-quote': ICQuote, + 'ic-rocket-launch': ICRocketLaunch, 'ic-shield-check': ICShieldCheck, 'ic-sort-ascending': ICSortAscending, 'ic-sort-descending': ICSortDescending, From 07ff6e3892737440b50c11b92b12737d42508e08 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 7 Apr 2025 17:55:53 +0530 Subject: [PATCH 02/80] feat: AnimatedDeployButton - add support for exception user --- .../AnimatedDeployButton.tsx | 22 ++++++++++++++++--- .../Components/AnimatedDeployButton/types.tsx | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx index 28ede4e1b..a1634513a 100644 --- a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx +++ b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx @@ -19,11 +19,16 @@ import { ReactComponent as ICDeploy } from '@Icons/ic-nav-rocket.svg' import { ComponentSizeType } from '@Shared/constants' import { SyntheticEvent, useEffect, useRef, useState } from 'react' import DeployAudio from '@Sounds/DeployAudio.mp3' -import { Button } from '../Button' +import { Button, ButtonStyleType } from '../Button' import './animatedDeployButton.scss' import { AnimatedDeployButtonProps } from './types' -const AnimatedDeployButton = ({ isVirtualEnvironment, onButtonClick }: AnimatedDeployButtonProps) => { +const AnimatedDeployButton = ({ + isVirtualEnvironment, + onButtonClick, + canDeployWithoutApproval, + isBulkCDTrigger, +}: AnimatedDeployButtonProps) => { const audioRef = useRef(null) const timeoutRef = useRef>(null) const isAudioEnabled: boolean = window._env_.FEATURE_ACTION_AUDIOS_ENABLE @@ -63,7 +68,11 @@ const AnimatedDeployButton = ({ isVirtualEnvironment, onButtonClick }: AnimatedD - ) : ( -
- {label} - {!!headerComponent && headerComponent} -
- )} - - - - ) - - const renderErrorMessage = (errorMessage: string) => ( -
- -

{errorMessage}

-
- ) - - const renderErrorMessages = ( - value: Parameters[0], - key: Parameters[1], - rowId: KeyValueRow['id'], - ) => { - const showErrorMessages = showError && !validationSchema(value, key, rowId) - if (!showErrorMessages) { - return null + const onRowEdit: KeyValueTableInternalProps['onRowEdit'] = (row, headerKey, value) => { + const updatedRows = rows + const rowIndex = rows.findIndex(({ id }) => row.id === id) + const selectedRow = rows[rowIndex] + if (selectedRow) { + selectedRow.data[headerKey].value = value + updatedRows[rowIndex] = selectedRow } - return ( -
- {validateDuplicateKeys && renderErrorMessage(DUPLICATE_KEYS_VALIDATION_MESSAGE)} - {validateEmptyKeys && renderErrorMessage(EMPTY_KEY_VALIDATION_MESSAGE)} - {parentErrorMessages.map((error) => renderErrorMessage(error))} -
- ) + setUpdatedRows(updatedRows, true) } return ( - <> -
-
- {/* HEADER */} -
- {headers.map(({ key, label, className }) => - key === firstHeaderKey ? ( - renderFirstHeader(key, label, className) - ) : ( -
- {label} - {!!headerComponent && headerComponent} -
- ), - )} -
-
-
- - {hasRows && ( -
- {!!updatedRows.length && ( -
- {updatedRows.map((row) => ( -
- {headers.map(({ key }) => ( - - -
- {maskValue?.[key] && row.data[key].value ? ( -
- {DEFAULT_SECRET_PLACEHOLDER} -
- ) : ( - <> - - {row.data[key].required && ( - - * - - )} - {renderErrorMessages(row.data[key].value, key, row.id)} - - )} -
-
-
- ))} - {!readOnly && ( - - )} -
- ))} -
- )} -
- )} - + ) } diff --git a/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts b/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts index d437b514a..7b06308b5 100644 --- a/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts +++ b/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts @@ -14,47 +14,13 @@ * limitations under the License. */ -import { ReactNode } from 'react' +import { TooltipProps } from '@Common/Tooltip' -import { ResizableTagTextAreaProps } from '../../../Common' +import { DynamicDataTableProps } from '../DynamicDataTable' -/** - * Interface representing a key-value header. - * @template K - A string representing the key type. - */ -export interface KeyValueHeader { - /** The label of the header. */ - label: string - /** The key associated with the header. */ - key: K - /** An optional class name for the header. */ - className?: string -} - -/** - * Type representing a key-value row. - * @template K - A string representing the key type. - */ -export type KeyValueRow = { - data: { - [key in K]: Pick & { - /** An optional boolean indicating if an asterisk should be shown. */ - required?: boolean - } - } - id: string | number -} +export type KeyValueTableDataType = 'key' | 'value' -/** - * Interface representing the configuration for a key-value table. - * @template K - A string representing the key type. - */ -export interface KeyValueConfig { - /** An array containing two key-value headers. */ - headers: [KeyValueHeader, KeyValueHeader] - /** An array of key-value rows. */ - rows: KeyValueRow[] -} +export type KeyValueTableInternalProps = DynamicDataTableProps type ErrorUIProps = | { @@ -82,64 +48,91 @@ type ErrorUIProps = validateEmptyKeys?: never } -/** - * Type representing a mask for key-value pairs. - * @template K - A string representing the key type. - */ -export type KeyValueMask = { +export type KeyValueHeaderLabel = { + [key in K]: string +} + +export type KeyValueMask = { [key in K]?: boolean } -export type KeyValuePlaceholder = { +export type KeyValuePlaceholder = { [key in K]?: string } +export interface KeyValueTableRowType { + id: string | number + data: { + [key in K]: { + value: string + /** An optional boolean indicating if the cell should be marked as disabled. */ + disabled?: boolean + /** An optional boolean indicating if an asterisk should be shown. */ + required?: boolean + /** An optional tooltip to show when hovering over cell. */ + tooltip?: Partial> + } + } +} + +export interface KeyValueTableData extends Pick { + key: string + value: string +} + /** - * Interface representing the properties for a key-value table component. - * @template K - A string representing the key type. + * Props for the KeyValueTable component. */ -export type KeyValueTableProps = { - /** The configuration for the key-value table. */ - config: KeyValueConfig - /** An optional mask for the key-value pairs. */ - maskValue?: KeyValueMask - placeholder?: KeyValuePlaceholder - /** An optional boolean indicating if the table is sortable. */ - isSortable?: boolean - /** An optional React node for a custom header component. */ - headerComponent?: ReactNode - /** When true, data addition field will not be shown. */ - isAdditionNotAllowed?: boolean - /** When true, data add or update is disabled. */ - readOnly?: boolean +export type KeyValueTableProps = Pick< + DynamicDataTableProps, + 'isAdditionNotAllowed' | 'readOnly' | 'headerComponent' +> & { + /** + * The label for the table header. + */ + headerLabel: KeyValueHeaderLabel + /** + * The initial rows of the key-value table. + */ + initialRows: KeyValueTableRowType[] /** - * An optional function to handle changes in the table rows. - * @param rowId - The id of the row that changed. - * @param headerKey - The key of the header that changed. - * @param value - The value of the cell. + * An optional configuration to mask values in the table. */ - onChange?: (rowId: string | number, headerKey: K, value: string) => void + maskValue?: KeyValueMask + /** + * An optional placeholder configuration for the table columns. + */ + placeholder?: KeyValuePlaceholder + /** + * An optional boolean indicating if the `key` column is sortable. + */ + isSortable?: boolean /** - * An optional function to handle row deletions. - * @param deletedRowIndex - The index of the row that was deleted. + * A callback function triggered when the table rows change. + * + * @param data - The updated table data. */ - onDelete?: (deletedRowId: string | number) => void + onChange?: (data: KeyValueTableData[]) => void /** - * The function to use to validate the value of the cell. + * A function to validate the value of a cell. + * * @param value - The value to validate. - * @param key - The row key of the value. - * @param rowId - The id of the row. - * @returns Return true if the value is valid, otherwise false - * and set `showError` to `true` and provide errorMessages array to show error message. + * @param key - The key of the header associated with the value. + * @param rowId - The id of the row containing the value. + * @returns A boolean indicating whether the value is valid. If false, + * `showError` should be set to `true` and `errorMessages` should + * provide an array of error messages to display. */ - validationSchema?: (value: string, key: K, rowId: string | number) => boolean + validationSchema?: (value: string, key: KeyValueTableDataType, rowId: KeyValueTableRowType['id']) => boolean /** - * An array of error messages to be displayed in the cell error tooltip. + * An array of error messages to display in the cell error tooltip. */ errorMessages?: string[] /** - * A callback function called when an error occurs. - * @param errorState - The error state, true when any cell has error, otherwise false. + * A callback function triggered when an error occurs in the table. + * + * @param errorState - A boolean indicating the error state. True if any + * cell has an error, otherwise false. */ onError?: (errorState: boolean) => void } & ErrorUIProps diff --git a/src/Shared/Components/KeyValueTable/index.ts b/src/Shared/Components/KeyValueTable/index.ts index e81474570..058030a56 100644 --- a/src/Shared/Components/KeyValueTable/index.ts +++ b/src/Shared/Components/KeyValueTable/index.ts @@ -15,4 +15,4 @@ */ export * from './KeyValueTable.component' -export * from './KeyValueTable.types' +export type { KeyValueTableData, KeyValueTableProps } from './KeyValueTable.types' diff --git a/src/Shared/Components/KeyValueTable/utils.ts b/src/Shared/Components/KeyValueTable/utils.ts new file mode 100644 index 000000000..fba83b5f0 --- /dev/null +++ b/src/Shared/Components/KeyValueTable/utils.ts @@ -0,0 +1,81 @@ +import { getUniqueId } from '@Shared/Helpers' + +import { DynamicDataTableRowDataType } from '../DynamicDataTable' +import { KeyValueTableData, KeyValueTableInternalProps, KeyValueTableProps } from './KeyValueTable.types' + +export const getModifiedDataForOnChange = (rows: KeyValueTableInternalProps['rows']): KeyValueTableData[] => + rows.map(({ data, id }) => ({ id, key: data.key.value, value: data.value.value })) + +export const getEmptyRow = ( + placeholder: KeyValueTableProps['placeholder'], +): KeyValueTableInternalProps['rows'][number] => ({ + id: getUniqueId(), + data: { + key: { + type: DynamicDataTableRowDataType.TEXT, + props: { placeholder: placeholder.key }, + value: '', + }, + value: { + type: DynamicDataTableRowDataType.TEXT, + props: { placeholder: placeholder.value }, + value: '', + }, + }, +}) + +export const getKeyValueInitialRows = ({ + initialRows, + placeholder, +}: Pick): KeyValueTableInternalProps['rows'] => + initialRows.length + ? initialRows.map(({ data: { key, value }, id }) => ({ + data: { + key: { + ...key, + type: DynamicDataTableRowDataType.TEXT, + props: { placeholder: placeholder.key }, + }, + value: { + ...value, + type: DynamicDataTableRowDataType.TEXT, + props: { placeholder: placeholder.value }, + }, + }, + id, + })) + : [getEmptyRow(placeholder)] + +export const getKeyValueInitialCellError = ( + rows: KeyValueTableInternalProps['rows'], +): KeyValueTableInternalProps['cellError'] => + rows.reduce((acc, curr) => { + if (!acc[curr.id]) { + acc[curr.id] = { + key: { isValid: true, errorMessages: [] }, + value: { isValid: true, errorMessages: [] }, + } + } + + return acc + }, {}) + +export const getKeyValueHeaders = ({ + headerLabel, + isSortable, +}: Pick): KeyValueTableInternalProps['headers'] => [ + { key: 'key', label: headerLabel.key, width: '30%', isSortable }, + { key: 'value', label: headerLabel.value, width: '1fr' }, +] + +export const getKeyValueTableKeysFrequency = (rows: KeyValueTableInternalProps['rows']) => + rows.reduce( + (acc, curr) => { + const currentKey = curr.data.key.value + if (currentKey) { + acc[currentKey] = (acc[currentKey] || 0) + 1 + } + return acc + }, + {} as Record, + ) From fcf245a90adff00d92b110d01c9db7a36451420b Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Fri, 11 Apr 2025 15:50:55 +0530 Subject: [PATCH 09/80] refactor: update CMCS to use KeyValueTableData type instead of CMSecretYamlData type --- src/Shared/Components/CMCS/constants.ts | 5 ++-- src/Shared/Components/CMCS/utils.ts | 35 ++++++++++++----------- src/Shared/Components/CMCS/validations.ts | 5 ++-- src/Shared/Services/app.types.ts | 9 ++---- 4 files changed, 26 insertions(+), 28 deletions(-) diff --git a/src/Shared/Components/CMCS/constants.ts b/src/Shared/Components/CMCS/constants.ts index d24b0012f..616ccb1e0 100644 --- a/src/Shared/Components/CMCS/constants.ts +++ b/src/Shared/Components/CMCS/constants.ts @@ -14,8 +14,9 @@ * limitations under the License. */ -import { CMSecretExternalType, CMSecretYamlData } from '@Shared/Services' +import { CMSecretExternalType } from '@Shared/Services' +import { KeyValueTableData } from '../KeyValueTable' import { ConfigMapSecretDataTypeOptionType } from './types' export const CONFIG_MAP_SECRET_YAML_PARSE_ERROR = 'Please provide valid YAML' @@ -33,7 +34,7 @@ export const configMapDataTypeOptions: ConfigMapSecretDataTypeOptionType[] = [ { value: CMSecretExternalType.KubernetesConfigMap, label: 'Kubernetes External ConfigMap' }, ] -export const CONFIG_MAP_SECRET_DEFAULT_CURRENT_DATA: CMSecretYamlData[] = [{ k: '', v: '', id: 0 }] +export const CONFIG_MAP_SECRET_DEFAULT_CURRENT_DATA: KeyValueTableData[] = [{ key: '', value: '', id: 0 }] export const configMapSecretMountDataMap = { environment: { title: 'Environment Variable', value: 'environment' }, diff --git a/src/Shared/Components/CMCS/utils.ts b/src/Shared/Components/CMCS/utils.ts index 2d5347d49..6222d34c2 100644 --- a/src/Shared/Components/CMCS/utils.ts +++ b/src/Shared/Components/CMCS/utils.ts @@ -26,7 +26,6 @@ import { CMSecretConfigData, CMSecretExternalType, CMSecretPayloadType, - CMSecretYamlData, CODE_EDITOR_RADIO_STATE, ConfigDatum, ConfigMapSecretUseFormProps, @@ -36,6 +35,7 @@ import { } from '@Shared/Services' import { hasESO, OverrideMergeStrategyType } from '@Pages/index' +import { KeyValueTableData } from '../KeyValueTable' import { getSelectPickerOptionByValue } from '../SelectPicker' import { CONFIG_MAP_SECRET_DEFAULT_CURRENT_DATA, @@ -93,7 +93,7 @@ export const getSecretDataTypeOptions = ( return isJob ? kubernetesOptions : [...kubernetesOptions, ...esoOptions, ...(isHashiOrAWS ? kesOptions : [])] } -const secureValues = (data: Record, decodeData: boolean): CMSecretYamlData[] => { +const secureValues = (data: Record, decodeData: boolean): KeyValueTableData[] => { let decodedData = data || DEFAULT_SECRET_PLACEHOLDER if (decodeData) { @@ -104,9 +104,9 @@ const secureValues = (data: Record, decodeData: boolean): CMSecr } } - return Object.keys(decodedData).map((k, id) => ({ - k, - v: typeof decodedData[k] === 'object' ? YAMLStringify(decodedData[k]) : decodedData[k], + return Object.keys(decodedData).map((key, id) => ({ + key, + value: typeof decodedData[key] === 'object' ? YAMLStringify(decodedData[key]) : decodedData[key], id, })) } @@ -150,8 +150,8 @@ const processExternalSubPathValues = ({ return '' } -export const convertKeyValuePairToYAML = (currentData: CMSecretYamlData[]) => - currentData.length ? YAMLStringify(currentData.reduce((agg, { k, v }) => ({ ...agg, [k]: v }), {})) : '' +export const convertKeyValuePairToYAML = (currentData: KeyValueTableData[]) => + currentData.length ? YAMLStringify(currentData.reduce((agg, { key, value }) => ({ ...agg, [key]: value }), {})) : '' const getSecretDataFromConfigData = ({ secretData, @@ -368,29 +368,30 @@ export const getConfigMapSecretReadOnlyValues = ({ ? [ { displayName: 'Keys', - value: currentData?.length > 0 ? currentData.map((d) => d.k).join(', ') : 'No keys available', + value: + currentData?.length > 0 ? currentData.map((d) => d.key).join(', ') : 'No keys available', key: 'keys', }, ] : []), ], - data: !mountExistingExternal ? (currentData?.[0]?.k && yaml) || esoSecretYaml || secretDataYaml : null, + data: !mountExistingExternal ? (currentData?.[0]?.key && yaml) || esoSecretYaml || secretDataYaml : null, } } -export const convertYAMLToKeyValuePair = (yaml: string): CMSecretYamlData[] => { +export const convertYAMLToKeyValuePair = (yaml: string): KeyValueTableData[] => { try { const obj = yaml && YAML.parse(yaml) if (typeof obj !== 'object') { throw new Error() } - const keyValueArray: CMSecretYamlData[] = Object.keys(obj).reduce((agg, k, id) => { - if (!k && !obj[k]) { + const keyValueArray = Object.keys(obj).reduce((agg, key, id) => { + if (!key && !obj[key]) { return CONFIG_MAP_SECRET_DEFAULT_CURRENT_DATA } - const v = obj[k] && typeof obj[k] === 'object' ? YAMLStringify(obj[k]) : obj[k].toString() + const value = obj[key] && typeof obj[key] === 'object' ? YAMLStringify(obj[key]) : obj[key].toString() - return [...agg, { k, v: v ?? '', id }] + return [...agg, { key, value: value ?? '', id }] }, []) return keyValueArray } catch { @@ -449,14 +450,14 @@ export const getConfigMapSecretPayload = ({ const isESO = isSecret && hasESO(externalType) const _currentData = yamlMode ? convertYAMLToKeyValuePair(yaml) : currentData const data = _currentData.reduce((acc, curr) => { - if (!curr.k) { + if (!curr.key) { return acc } - const value = curr.v ?? '' + const value = curr.value ?? '' return { ...acc, - [curr.k]: isSecret && externalType === '' ? btoa(value) : value, + [curr.key]: isSecret && externalType === '' ? btoa(value) : value, } }, {}) diff --git a/src/Shared/Components/CMCS/validations.ts b/src/Shared/Components/CMCS/validations.ts index f1858649a..fa76dfe12 100644 --- a/src/Shared/Components/CMCS/validations.ts +++ b/src/Shared/Components/CMCS/validations.ts @@ -19,10 +19,11 @@ import YAML from 'yaml' import { PATTERNS } from '@Common/Constants' import { YAMLStringify } from '@Common/Helper' import { UseFormValidation, UseFormValidations } from '@Shared/Hooks' -import { CMSecretExternalType, CMSecretYamlData, ConfigMapSecretUseFormProps } from '@Shared/Services' +import { CMSecretExternalType, ConfigMapSecretUseFormProps } from '@Shared/Services' import { validateCMVolumeMountPath } from '@Shared/validations' import { hasESO } from '@Pages/index' +import { KeyValueTableData } from '../KeyValueTable' import { CONFIG_MAP_SECRET_YAML_PARSE_ERROR, SECRET_TOAST_INFO } from './constants' import { getESOSecretDataFromYAML } from './utils' @@ -310,7 +311,7 @@ export const getConfigMapSecretFormValidations: UseFormValidations !!value.filter(({ k }) => !!k).length, + isValid: (value: KeyValueTableData[]) => !!value.filter(({ key }) => !!key).length, message: 'This is a required field', }, }, diff --git a/src/Shared/Services/app.types.ts b/src/Shared/Services/app.types.ts index 399b195af..e04c22c39 100644 --- a/src/Shared/Services/app.types.ts +++ b/src/Shared/Services/app.types.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +import { KeyValueTableData } from '@Shared/Components' import { TargetPlatformsDTO } from '@Shared/types' import { OverrideMergeStrategyType } from '@Pages/Applications' @@ -241,12 +242,6 @@ export interface ConfigMapSecretDataType { isDeletable: boolean } -export interface CMSecretYamlData { - k: string - v: string - id: string | number -} - export interface ConfigMapSecretUseFormProps { name: string isSecret: boolean @@ -261,7 +256,7 @@ export interface ConfigMapSecretUseFormProps { roleARN: string yamlMode: boolean yaml: string - currentData: CMSecretYamlData[] + currentData: KeyValueTableData[] secretDataYaml: string esoSecretYaml: string hasCurrentDataErr: boolean From aa87441096c6408587083fe4c1a8e502f4f6aaff Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Fri, 11 Apr 2025 17:18:10 +0530 Subject: [PATCH 10/80] feat: replace ic-timeout-two-dash with ic-timeout-dash icon and update references --- .../{ic-timeout-two-dash.svg => ic-timeout-dash.svg} | 8 ++++---- src/Shared/Components/Icon/Icon.tsx | 4 ++-- src/Shared/Components/StatusComponent/utils.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) rename src/Assets/IconV2/{ic-timeout-two-dash.svg => ic-timeout-dash.svg} (53%) diff --git a/src/Assets/IconV2/ic-timeout-two-dash.svg b/src/Assets/IconV2/ic-timeout-dash.svg similarity index 53% rename from src/Assets/IconV2/ic-timeout-two-dash.svg rename to src/Assets/IconV2/ic-timeout-dash.svg index 85b6d9893..08932efac 100644 --- a/src/Assets/IconV2/ic-timeout-two-dash.svg +++ b/src/Assets/IconV2/ic-timeout-dash.svg @@ -14,8 +14,8 @@ - limitations under the License. --> - - - - + + + + diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index b14c24325..203ead883 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -98,7 +98,7 @@ import { ReactComponent as ICStamp } from '@IconsV2/ic-stamp.svg' import { ReactComponent as ICSuccess } from '@IconsV2/ic-success.svg' import { ReactComponent as ICSuspended } from '@IconsV2/ic-suspended.svg' import { ReactComponent as ICTata1mg } from '@IconsV2/ic-tata1mg.svg' -import { ReactComponent as ICTimeoutTwoDash } from '@IconsV2/ic-timeout-two-dash.svg' +import { ReactComponent as ICTimeoutDash } from '@IconsV2/ic-timeout-dash.svg' import { ReactComponent as ICTimer } from '@IconsV2/ic-timer.svg' import { ReactComponent as ICTravclan } from '@IconsV2/ic-travclan.svg' import { ReactComponent as ICUnknown } from '@IconsV2/ic-unknown.svg' @@ -209,7 +209,7 @@ export const iconMap = { 'ic-success': ICSuccess, 'ic-suspended': ICSuspended, 'ic-tata1mg': ICTata1mg, - 'ic-timeout-two-dash': ICTimeoutTwoDash, + 'ic-timeout-dash': ICTimeoutDash, 'ic-timer': ICTimer, 'ic-travclan': ICTravclan, 'ic-unknown': ICUnknown, diff --git a/src/Shared/Components/StatusComponent/utils.ts b/src/Shared/Components/StatusComponent/utils.ts index eddd95a1e..b6303d7c8 100644 --- a/src/Shared/Components/StatusComponent/utils.ts +++ b/src/Shared/Components/StatusComponent/utils.ts @@ -70,7 +70,7 @@ export const getIconName = (status: string, showAnimatedIcon: boolean): IconName return 'ic-hibernate' case 'timedout': case 'timed_out': - return 'ic-timeout-two-dash' + return 'ic-timeout-dash' default: return null } From 0e8816c1f6b5a5874f23b7031352bf8d74de12d1 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 15 Apr 2025 11:39:05 +0530 Subject: [PATCH 11/80] fix: KeyValueTable - fix sorting logic --- .../KeyValueTable/KeyValueTable.component.tsx | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx b/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx index bab6ea4d9..3903a49bb 100644 --- a/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx +++ b/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx @@ -14,8 +14,9 @@ * limitations under the License. */ -import { useCallback, useEffect, useMemo, useState } from 'react' +import { useCallback, useMemo, useState } from 'react' +import { SortingOrder } from '@Common/Constants' import { debounce, noop } from '@Common/Helper' import { useStateFilters } from '@Common/Hooks' import { DEFAULT_SECRET_PLACEHOLDER } from '@Shared/constants' @@ -99,19 +100,6 @@ export const KeyValueTable = ({ [], ) - // USE-EFFECTS - useEffect(() => { - if (isSortable) { - setRows((prevRows) => { - const sortedRows = prevRows - sortedRows.sort((a, b) => - stringComparatorBySortOrder(a.data[sortBy].value, b.data[sortBy].value, sortOrder), - ) - return sortedRows - }) - } - }, [sortOrder]) - // METHODS const validationSchema = ( value: Parameters[0], @@ -226,6 +214,24 @@ export const KeyValueTable = ({ setUpdatedRows(updatedRows, true) } + const onSorting = (_sortBy: KeyValueTableDataType) => { + handleSorting(_sortBy) + + if (isSortable) { + setRows((prevRows) => { + const sortedRows = prevRows + sortedRows.sort((a, b) => + stringComparatorBySortOrder( + a.data[_sortBy].value, + b.data[_sortBy].value, + sortOrder === SortingOrder.ASC ? SortingOrder.DESC : SortingOrder.ASC, + ), + ) + return sortedRows + }) + } + } + return ( ) From 7a8e4911eb45e0b70af8d9e8b3446ce801512cf6 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Wed, 16 Apr 2025 15:01:59 +0530 Subject: [PATCH 12/80] feat: TabGroup - add truncate to tabs --- src/Shared/Components/TabGroup/TabGroup.component.tsx | 8 +++++--- src/Shared/Components/TabGroup/TabGroup.scss | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 801a4d806..8532103e2 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -62,12 +62,14 @@ const Tab = ({ const getTabComponent = () => { const content = ( <> -

+ {getTabIcon({ className: iconClassName, icon, showError, showWarning, size, active })} - {label} + + {label} + {getTabBadge(badge, badgeClassName)} {getTabIndicator(showIndicator)} -

+ {getTabDescription(description)} ) diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index a4f18a8a5..c5a352898 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -90,6 +90,10 @@ color: var(--B500); font-weight: 600; @include svg-styles(var(--B500)); + + svg.icon-component-color { + --overrideIconColor: var(--B500); + } } &:not(.active) { From c1962beb95744d1d4473635ad2dbbbb00d760079 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Thu, 17 Apr 2025 15:36:06 +0530 Subject: [PATCH 13/80] feat: update AnimatedDeployButton to use exceptionUserConfig for deployment approval logic --- .../AnimatedDeployButton/AnimatedDeployButton.tsx | 13 +++++++------ .../Components/AnimatedDeployButton/types.tsx | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx index 0cf421422..f5e364133 100644 --- a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx +++ b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx @@ -30,7 +30,7 @@ const AnimatedDeployButton = ({ isLoading, isVirtualEnvironment, onButtonClick, - canDeployWithoutApproval, + exceptionUserConfig, isBulkCDTrigger, }: AnimatedDeployButtonProps) => { const audioRef = useRef(null) @@ -42,6 +42,7 @@ const AnimatedDeployButton = ({ rotate: 45, }, } + const isExceptionUser = exceptionUserConfig?.canDeploy || exceptionUserConfig?.isImageApprover const handleButtonClick = async (e: SyntheticEvent) => { if (clicked) { @@ -74,7 +75,7 @@ const AnimatedDeployButton = ({ dataTestId="cd-trigger-deploy-button" isLoading={isLoading} text={ - canDeployWithoutApproval + exceptionUserConfig?.canDeploy ? 'Deploy without approval' : `Deploy${isVirtualEnvironment ? ' to isolated env' : ''}` } @@ -99,12 +100,12 @@ const AnimatedDeployButton = ({ } size={ComponentSizeType.large} onClick={handleButtonClick} - style={canDeployWithoutApproval && !isBulkCDTrigger ? ButtonStyleType.warning : ButtonStyleType.default} - showTooltip={canDeployWithoutApproval} + style={isExceptionUser && !isBulkCDTrigger ? ButtonStyleType.warning : ButtonStyleType.default} + showTooltip={isExceptionUser} tooltipProps={{ content: isBulkCDTrigger - ? 'Non-approved image(s) are selected for some applications. You are authorized to deploy.' - : 'A non-approved image is selected. You are authorized to deploy.', + ? 'You are authorized to deploy as an exception user for some applications' + : 'You are authorized to deploy as an exception user', }} /> {/* Disabling es-lint as captions are not required */} diff --git a/src/Shared/Components/AnimatedDeployButton/types.tsx b/src/Shared/Components/AnimatedDeployButton/types.tsx index 4080cf3c7..4cb944cbc 100644 --- a/src/Shared/Components/AnimatedDeployButton/types.tsx +++ b/src/Shared/Components/AnimatedDeployButton/types.tsx @@ -18,6 +18,9 @@ export interface AnimatedDeployButtonProps { isLoading?: boolean isVirtualEnvironment: boolean onButtonClick: (e, disableDeployButton: boolean) => void - canDeployWithoutApproval?: boolean + exceptionUserConfig?: { + canDeploy: boolean + isImageApprover: boolean + } isBulkCDTrigger?: boolean } From c400d9bcaa585192ac3fbe4ee61e47b4e164e26a Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Thu, 17 Apr 2025 15:36:40 +0530 Subject: [PATCH 14/80] feat: display text for deployments by exception users --- src/Shared/Components/CICDHistory/Artifacts.tsx | 13 +++++++++++-- src/Shared/Components/CICDHistory/types.tsx | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/Shared/Components/CICDHistory/Artifacts.tsx b/src/Shared/Components/CICDHistory/Artifacts.tsx index 4069b2c6b..5298043fa 100644 --- a/src/Shared/Components/CICDHistory/Artifacts.tsx +++ b/src/Shared/Components/CICDHistory/Artifacts.tsx @@ -36,6 +36,7 @@ import { useGetUserRoles, } from '../../../Common' import { EMPTY_STATE_STATUS } from '../../constants' +import { Icon } from '../Icon' import { TargetPlatformBadgeList } from '../TargetPlatforms' import { TERMINAL_STATUS_MAP } from './constants' import { ArtifactType, CIListItemType } from './types' @@ -84,6 +85,13 @@ export const CIListItem = ({ )} + {isDeploymentWithoutApproval && ( +
+ +

Deployed by an exception user

+
+ )} + {headerMetaDataPresent && renderCIListHeader && renderCIListHeader({ @@ -93,12 +101,13 @@ export const CIListItem = ({ appliedFiltersTimestamp, promotionApprovalMetadata, selectedEnvironmentName, - isDeploymentWithoutApproval, })}
diff --git a/src/Shared/Components/CICDHistory/types.tsx b/src/Shared/Components/CICDHistory/types.tsx index 0864bbf4e..5b8c77b8b 100644 --- a/src/Shared/Components/CICDHistory/types.tsx +++ b/src/Shared/Components/CICDHistory/types.tsx @@ -446,7 +446,7 @@ export interface DeploymentDetailStepsType { renderDeploymentApprovalInfo: (userApprovalMetadata: UserApprovalMetadataType) => JSX.Element } -export interface RenderCIListHeaderProps extends Pick { +export interface RenderCIListHeaderProps { userApprovalMetadata: UserApprovalMetadataType triggeredBy: string appliedFilters: FilterConditionsListType[] From a63823e79149832c645e644d80dc672c621866d0 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 21 Apr 2025 12:57:11 +0530 Subject: [PATCH 15/80] refactor: update FormType to use KeyValueTableData for args --- src/Common/CIPipeline.Types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Common/CIPipeline.Types.ts b/src/Common/CIPipeline.Types.ts index 45ab04918..8dbddd04a 100644 --- a/src/Common/CIPipeline.Types.ts +++ b/src/Common/CIPipeline.Types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DynamicDataTableCellValidationState } from '@Shared/Components' +import { DynamicDataTableCellValidationState, KeyValueTableData } from '@Shared/Components' export interface MaterialType { name: string @@ -266,7 +266,7 @@ export enum WORKFLOW_CACHE_CONFIG_ENUM { export interface FormType { name: string - args: { key: string; value: string }[] + args: KeyValueTableData[] materials: MaterialType[] gitHost: Githost webhookEvents: WebhookEvent[] From a86a48ed02d5278a47d895b1a3d732f023519c52 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 21 Apr 2025 13:01:27 +0530 Subject: [PATCH 16/80] refactor: KeyValueTable - move methods to utils and code optimization for better state management --- .../KeyValueTable/KeyValueTable.component.tsx | 181 ++++-------------- .../KeyValueTable/KeyValueTable.types.ts | 33 +++- src/Shared/Components/KeyValueTable/utils.ts | 147 ++++++++++++-- 3 files changed, 186 insertions(+), 175 deletions(-) diff --git a/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx b/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx index 3903a49bb..968e3cb42 100644 --- a/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx +++ b/src/Shared/Components/KeyValueTable/KeyValueTable.component.tsx @@ -14,28 +14,18 @@ * limitations under the License. */ -import { useCallback, useMemo, useState } from 'react' +import { useEffect, useMemo, useState } from 'react' -import { SortingOrder } from '@Common/Constants' -import { debounce, noop } from '@Common/Helper' import { useStateFilters } from '@Common/Hooks' -import { DEFAULT_SECRET_PLACEHOLDER } from '@Shared/constants' -import { stringComparatorBySortOrder } from '@Shared/Helpers' -import { DynamicDataTable, DynamicDataTableCellValidationState } from '../DynamicDataTable' -import { DUPLICATE_KEYS_VALIDATION_MESSAGE, EMPTY_KEY_VALIDATION_MESSAGE } from './constants' -import { - KeyValueTableData, - KeyValueTableDataType, - KeyValueTableInternalProps, - KeyValueTableProps, -} from './KeyValueTable.types' +import { DynamicDataTable } from '../DynamicDataTable' +import { KeyValueTableDataType, KeyValueTableInternalProps, KeyValueTableProps } from './KeyValueTable.types' import { getEmptyRow, getKeyValueHeaders, - getKeyValueInitialCellError, - getKeyValueInitialRows, - getKeyValueTableKeysFrequency, + getKeyValueTableCellError, + getKeyValueTableRows, + getKeyValueTableSortedRows, getModifiedDataForOnChange, } from './utils' @@ -43,7 +33,7 @@ import './KeyValueTable.scss' export const KeyValueTable = ({ headerLabel, - initialRows, + rows: initialRows, placeholder, maskValue, isSortable, @@ -53,133 +43,50 @@ export const KeyValueTable = ({ readOnly, showError, validationSchema: parentValidationSchema, - errorMessages: parentErrorMessages = [], onError, validateDuplicateKeys = false, validateEmptyKeys = false, }: KeyValueTableProps) => { // STATES - const [rows, setRows] = useState( - getKeyValueInitialRows({ initialRows, placeholder }), - ) - - const [cellError, setCellError] = useState( - getKeyValueInitialCellError(rows), - ) + const [cellError, setCellError] = useState({}) // HOOKS const { sortBy, sortOrder, handleSorting } = useStateFilters({ initialSortKey: isSortable ? 'key' : null, }) - const rowWithMaskedValues = useMemo(() => { - if (maskValue && Object.keys(maskValue).length) { - return rows.map((row) => ({ - ...row, - data: { - ...row.data, - key: { - ...row.data.key, - value: maskValue.key ? DEFAULT_SECRET_PLACEHOLDER : row.data.key.value, - }, - value: { - ...row.data.value, - value: maskValue.value ? DEFAULT_SECRET_PLACEHOLDER : row.data.value.value, - }, - }, - })) - } - - return rows - }, [rows, maskValue]) - - const debounceOnChange = useCallback( - debounce((modifiedRows: KeyValueTableData[]) => - typeof onChange === 'function' ? onChange(modifiedRows) : noop, - ), - [], + // COMPUTED ROWS FOR DYNAMIC DATA TABLE + const rows = useMemo( + () => getKeyValueTableRows({ rows: initialRows, placeholder, maskValue }), + [initialRows, placeholder, maskValue, isSortable, sortOrder, sortBy], ) - // METHODS - const validationSchema = ( - value: Parameters[0], - key: Parameters[1], - rowId: Parameters[2], - keysFrequency: Record = {}, - ): DynamicDataTableCellValidationState => { - const trimmedValue = value.trim() - - if (validateDuplicateKeys && key === 'key' && (keysFrequency[trimmedValue] ?? 0) > 1) { - return { - isValid: false, - errorMessages: [DUPLICATE_KEYS_VALIDATION_MESSAGE], - } - } - - if (validateEmptyKeys && key === 'key' && !trimmedValue) { - const isValuePresentAtRow = rows.some(({ id, data }) => id === rowId && data.value.value.trim()) - if (isValuePresentAtRow) { - return { - isValid: false, - errorMessages: [EMPTY_KEY_VALIDATION_MESSAGE], - } - } - } - - if (parentValidationSchema) { - const isValid = parentValidationSchema(value, key, rowId) - return { - isValid, - errorMessages: !isValid ? parentErrorMessages : [], - } - } - - return { - isValid: true, - errorMessages: [], - } - } + // Set cell error on mount + useEffect(() => { + const { isValid, updatedCellError } = getKeyValueTableCellError({ + rows, + validateDuplicateKeys, + validateEmptyKeys, + validationSchema: parentValidationSchema, + }) - const checkAllRowsAreValid = (updatedRows: typeof rows) => { - let isValid = true - - const updatedCellError = updatedRows.reduce((acc, { data, id }) => { - const keyError = validationSchema( - data.key.value, - 'key', - id, - validateDuplicateKeys ? getKeyValueTableKeysFrequency(rows) : {}, - ) - const valueError = validationSchema(data.value.value, 'value', id) - - if (isValid && !(keyError.isValid && valueError.isValid)) { - isValid = false - } - - acc[id] = { - key: keyError, - value: valueError, - } - - return acc - }, {}) - - return { isValid, updatedCellError } - } + setCellError(updatedCellError) + onError?.(!isValid) + }, []) - const setUpdatedRows = (updatedRows: typeof rows, shouldDebounceChange = false) => { - const { isValid, updatedCellError } = checkAllRowsAreValid(updatedRows) + // METHODS + const setUpdatedRows = (updatedRows: typeof rows) => { + const { isValid, updatedCellError } = getKeyValueTableCellError({ + rows: updatedRows, + validateDuplicateKeys, + validateEmptyKeys, + validationSchema: parentValidationSchema, + }) - setRows(updatedRows) setCellError(updatedCellError) - onError?.(!isValid) - if (shouldDebounceChange) { - debounceOnChange(getModifiedDataForOnChange(updatedRows)) - } else { - onChange?.(getModifiedDataForOnChange(updatedRows)) - } + onChange(getModifiedDataForOnChange(updatedRows)) } const onRowAdd = () => { @@ -211,31 +118,13 @@ export const KeyValueTable = ({ updatedRows[rowIndex] = selectedRow } - setUpdatedRows(updatedRows, true) - } - - const onSorting = (_sortBy: KeyValueTableDataType) => { - handleSorting(_sortBy) - - if (isSortable) { - setRows((prevRows) => { - const sortedRows = prevRows - sortedRows.sort((a, b) => - stringComparatorBySortOrder( - a.data[_sortBy].value, - b.data[_sortBy].value, - sortOrder === SortingOrder.ASC ? SortingOrder.DESC : SortingOrder.ASC, - ), - ) - return sortedRows - }) - } + setUpdatedRows(updatedRows) } return ( ) diff --git a/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts b/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts index 7b06308b5..fff70a1b0 100644 --- a/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts +++ b/src/Shared/Components/KeyValueTable/KeyValueTable.types.ts @@ -92,9 +92,9 @@ export type KeyValueTableProps = Pick< */ headerLabel: KeyValueHeaderLabel /** - * The initial rows of the key-value table. + * The rows of the key-value table. */ - initialRows: KeyValueTableRowType[] + rows: KeyValueTableRowType[] /** * An optional configuration to mask values in the table. */ @@ -112,22 +112,29 @@ export type KeyValueTableProps = Pick< * * @param data - The updated table data. */ - onChange?: (data: KeyValueTableData[]) => void + onChange: (data: KeyValueTableData[]) => void /** * A function to validate the value of a cell. * * @param value - The value to validate. * @param key - The key of the header associated with the value. - * @param rowId - The id of the row containing the value. + * @param row - The row containing the value. * @returns A boolean indicating whether the value is valid. If false, * `showError` should be set to `true` and `errorMessages` should * provide an array of error messages to display. */ - validationSchema?: (value: string, key: KeyValueTableDataType, rowId: KeyValueTableRowType['id']) => boolean - /** - * An array of error messages to display in the cell error tooltip. - */ - errorMessages?: string[] + validationSchema?: ( + value: string, + key: KeyValueTableDataType, + row: KeyValueTableRowType, + ) => { + /** Boolean indicating if the cell data is valid or not. */ + isValid: boolean + /** + * An array of error messages to display in the cell error tooltip. + */ + errorMessages?: string[] + } /** * A callback function triggered when an error occurs in the table. * @@ -136,3 +143,11 @@ export type KeyValueTableProps = Pick< */ onError?: (errorState: boolean) => void } & ErrorUIProps + +export type KeyValueValidationSchemaProps = { + value: Parameters[0] + key: Parameters[1] + row: Parameters[2] + keysFrequency?: Record +} & Pick & + Partial> diff --git a/src/Shared/Components/KeyValueTable/utils.ts b/src/Shared/Components/KeyValueTable/utils.ts index fba83b5f0..e292aecbb 100644 --- a/src/Shared/Components/KeyValueTable/utils.ts +++ b/src/Shared/Components/KeyValueTable/utils.ts @@ -1,7 +1,16 @@ -import { getUniqueId } from '@Shared/Helpers' +import { UseStateFiltersReturnType } from '@Common/Hooks' +import { DEFAULT_SECRET_PLACEHOLDER } from '@Shared/constants' +import { getUniqueId, stringComparatorBySortOrder } from '@Shared/Helpers' -import { DynamicDataTableRowDataType } from '../DynamicDataTable' -import { KeyValueTableData, KeyValueTableInternalProps, KeyValueTableProps } from './KeyValueTable.types' +import { DynamicDataTableCellValidationState, DynamicDataTableRowDataType } from '../DynamicDataTable' +import { DUPLICATE_KEYS_VALIDATION_MESSAGE, EMPTY_KEY_VALIDATION_MESSAGE } from './constants' +import { + KeyValueTableData, + KeyValueTableDataType, + KeyValueTableInternalProps, + KeyValueTableProps, + KeyValueValidationSchemaProps, +} from './KeyValueTable.types' export const getModifiedDataForOnChange = (rows: KeyValueTableInternalProps['rows']): KeyValueTableData[] => rows.map(({ data, id }) => ({ id, key: data.key.value, value: data.value.value })) @@ -24,21 +33,26 @@ export const getEmptyRow = ( }, }) -export const getKeyValueInitialRows = ({ - initialRows, +export const getKeyValueTableRows = ({ + rows: initialRows, placeholder, -}: Pick): KeyValueTableInternalProps['rows'] => - initialRows.length + maskValue, +}: Required>): KeyValueTableInternalProps['rows'] => { + const isMaskValue = maskValue && Object.keys(maskValue).length + + const rows: KeyValueTableInternalProps['rows'] = initialRows.length ? initialRows.map(({ data: { key, value }, id }) => ({ data: { key: { ...key, type: DynamicDataTableRowDataType.TEXT, + value: isMaskValue && maskValue.key ? DEFAULT_SECRET_PLACEHOLDER : key.value, props: { placeholder: placeholder.key }, }, value: { ...value, type: DynamicDataTableRowDataType.TEXT, + value: isMaskValue && maskValue.value ? DEFAULT_SECRET_PLACEHOLDER : value.value, props: { placeholder: placeholder.value }, }, }, @@ -46,19 +60,25 @@ export const getKeyValueInitialRows = ({ })) : [getEmptyRow(placeholder)] -export const getKeyValueInitialCellError = ( - rows: KeyValueTableInternalProps['rows'], -): KeyValueTableInternalProps['cellError'] => - rows.reduce((acc, curr) => { - if (!acc[curr.id]) { - acc[curr.id] = { - key: { isValid: true, errorMessages: [] }, - value: { isValid: true, errorMessages: [] }, - } - } + return rows +} - return acc - }, {}) +export const getKeyValueTableSortedRows = ({ + isSortable, + rows, + sortBy, + sortOrder, +}: Required> & + Required, 'sortBy' | 'sortOrder'>> & + Pick) => { + if (isSortable) { + return rows + .map((item) => item) + .sort((a, b) => stringComparatorBySortOrder(a.data[sortBy].value, b.data[sortBy].value, sortOrder)) + } + + return rows +} export const getKeyValueHeaders = ({ headerLabel, @@ -68,7 +88,7 @@ export const getKeyValueHeaders = ({ { key: 'value', label: headerLabel.value, width: '1fr' }, ] -export const getKeyValueTableKeysFrequency = (rows: KeyValueTableInternalProps['rows']) => +const getKeyValueTableKeysFrequency = (rows: KeyValueTableInternalProps['rows']) => rows.reduce( (acc, curr) => { const currentKey = curr.data.key.value @@ -79,3 +99,90 @@ export const getKeyValueTableKeysFrequency = (rows: KeyValueTableInternalProps[' }, {} as Record, ) + +const validationSchema = ({ + value, + key, + row, + validateDuplicateKeys, + validateEmptyKeys, + validationSchema: parentValidationSchema, + rows = [], + keysFrequency = {}, +}: KeyValueValidationSchemaProps): DynamicDataTableCellValidationState => { + const trimmedValue = value.trim() + + if (validateDuplicateKeys && key === 'key' && (keysFrequency[trimmedValue] ?? 0) > 1) { + return { + isValid: false, + errorMessages: [DUPLICATE_KEYS_VALIDATION_MESSAGE], + } + } + + if (validateEmptyKeys && key === 'key' && !trimmedValue) { + const isValuePresentAtRow = rows.some(({ id, data }) => id === row.id && data.value.value.trim()) + if (isValuePresentAtRow) { + return { + isValid: false, + errorMessages: [EMPTY_KEY_VALIDATION_MESSAGE], + } + } + } + + if (parentValidationSchema) { + const { isValid, errorMessages } = parentValidationSchema(value, key, row) + return { + isValid, + errorMessages: errorMessages || [], + } + } + + return { + isValid: true, + errorMessages: [], + } +} + +export const getKeyValueTableCellError = ({ + validateDuplicateKeys, + validateEmptyKeys, + validationSchema: parentValidationSchema, + rows, +}: Pick & { + skipValidationIfValueIsEmpty?: boolean +}) => { + let isValid = true + + const updatedCellError = rows.reduce((acc, row) => { + const keyError = validationSchema({ + rows, + value: row.data.key.value, + key: 'key', + row, + validateDuplicateKeys, + validateEmptyKeys, + validationSchema: parentValidationSchema, + keysFrequency: validateDuplicateKeys ? getKeyValueTableKeysFrequency(rows) : {}, + }) + + const valueError = validationSchema({ + value: row.data.value.value, + key: 'value', + row, + validationSchema: parentValidationSchema, + }) + + if (isValid && !(keyError.isValid && valueError.isValid)) { + isValid = false + } + + acc[row.id] = { + key: keyError, + value: valueError, + } + + return acc + }, {}) + + return { isValid, updatedCellError } +} From 2007b0fb36b72ae03849c0dfd732e8546bc6e10a Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 21 Apr 2025 18:13:40 +0530 Subject: [PATCH 17/80] feat: add ConditionDetails interface and related error handling types --- src/Common/CIPipeline.Types.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Common/CIPipeline.Types.ts b/src/Common/CIPipeline.Types.ts index 8dbddd04a..04ebfd015 100644 --- a/src/Common/CIPipeline.Types.ts +++ b/src/Common/CIPipeline.Types.ts @@ -158,7 +158,7 @@ export interface PortMapType { portOnLocal: number portOnContainer: number } -interface ConditionDetails { +export interface ConditionDetails { id: number conditionOnVariable: string conditionOperator: string @@ -314,8 +314,16 @@ export enum InputOutputVariablesHeaderKeys { VALUE = 'val', } +export enum ConditionDataTableHeaderKeys { + VARIABLE = 'variable', + OPERATOR = 'operator', + VALUE = 'val', +} + export type InputOutputVariablesErrorObj = Record +export type ConditionDetailsErrorObj = Record + export interface TaskErrorObj { isValid: boolean name: ErrorObj @@ -324,12 +332,16 @@ export interface TaskErrorObj { outputVariables?: Record isInputVariablesValid?: boolean isOutputVariablesValid?: boolean + conditionDetails?: Record + isConditionDetailsValid?: boolean } pluginRefStepDetail?: { inputVariables?: Record outputVariables?: Record isInputVariablesValid?: boolean isOutputVariablesValid?: boolean + conditionDetails?: Record + isConditionDetailsValid?: boolean } } export interface FormErrorObjectType { From 638af5a34b4484f1db9368b1707d544999387900 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 21 Apr 2025 18:15:40 +0530 Subject: [PATCH 18/80] fix: update error handling in DynamicDataTableRow for SelectPicker and Dropdown --- .../Components/DynamicDataTable/DynamicDataTableRow.tsx | 8 +++++--- src/Shared/Components/KeyValueTable/utils.ts | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx b/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx index 3904c5147..40fb9a572 100644 --- a/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx +++ b/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx @@ -290,16 +290,18 @@ export const DynamicDataTableRow = {errorMessages.map((error) => renderErrorMessage(error))}
diff --git a/src/Shared/Components/KeyValueTable/utils.ts b/src/Shared/Components/KeyValueTable/utils.ts index e292aecbb..aaa7dc7b6 100644 --- a/src/Shared/Components/KeyValueTable/utils.ts +++ b/src/Shared/Components/KeyValueTable/utils.ts @@ -40,7 +40,7 @@ export const getKeyValueTableRows = ({ }: Required>): KeyValueTableInternalProps['rows'] => { const isMaskValue = maskValue && Object.keys(maskValue).length - const rows: KeyValueTableInternalProps['rows'] = initialRows.length + const rows: KeyValueTableInternalProps['rows'] = initialRows?.length ? initialRows.map(({ data: { key, value }, id }) => ({ data: { key: { From e00901e04a8585983c406f8db5eeff440d999efe Mon Sep 17 00:00:00 2001 From: shivani170 Date: Mon, 21 Apr 2025 19:43:11 +0530 Subject: [PATCH 19/80] chore: empty state css override --- src/Common/EmptyState/emptyState.scss | 2 +- src/Shared/Components/InfoBlock/InfoBlock.component.tsx | 4 ++-- src/Shared/Components/InfoBlock/constants.tsx | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Common/EmptyState/emptyState.scss b/src/Common/EmptyState/emptyState.scss index 3e94a442a..08d1f610e 100644 --- a/src/Common/EmptyState/emptyState.scss +++ b/src/Common/EmptyState/emptyState.scss @@ -27,7 +27,7 @@ max-height: 200px; width: auto; } - .button svg { + .button, .override-generic-empty svg { height: 100%; max-height: none; width: 100%; diff --git a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx index e87831c04..db5ec2299 100644 --- a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx +++ b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx @@ -94,7 +94,7 @@ const InfoBlock = ({ if (layout === 'row') { return ( -
+
{renderIcon()} {renderContent()} @@ -107,7 +107,7 @@ const InfoBlock = ({ if (layout === 'column') { return ( -
+
{renderContent()} {renderIcon()} diff --git a/src/Shared/Components/InfoBlock/constants.tsx b/src/Shared/Components/InfoBlock/constants.tsx index e372ad68b..93baa5e75 100644 --- a/src/Shared/Components/InfoBlock/constants.tsx +++ b/src/Shared/Components/InfoBlock/constants.tsx @@ -38,7 +38,7 @@ export const VARIANT_TO_ICON_MAP: Record, information: , success: , - warning: , + warning: , neutral: , } From a3cc114ec60c9d32c8841724f1ce844a5a575810 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Mon, 21 Apr 2025 19:45:35 +0530 Subject: [PATCH 20/80] chore: icon classname updated --- src/Shared/Components/InfoBlock/constants.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/Components/InfoBlock/constants.tsx b/src/Shared/Components/InfoBlock/constants.tsx index 93baa5e75..e372ad68b 100644 --- a/src/Shared/Components/InfoBlock/constants.tsx +++ b/src/Shared/Components/InfoBlock/constants.tsx @@ -38,7 +38,7 @@ export const VARIANT_TO_ICON_MAP: Record, information: , success: , - warning: , + warning: , neutral: , } From 4a31769a922a2208101aa20f0c32c8db9267dcbf Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 22 Apr 2025 11:39:47 +0530 Subject: [PATCH 21/80] chore: icon imported --- src/Assets/IconV2/ic-help-filled.svg | 4 ++++ src/Common/EmptyState/emptyState.scss | 2 +- src/Shared/Components/Icon/Icon.tsx | 2 ++ .../Components/InfoBlock/InfoBlock.component.tsx | 6 +++--- src/Shared/Components/InfoBlock/constants.tsx | 12 ++++-------- 5 files changed, 14 insertions(+), 12 deletions(-) create mode 100644 src/Assets/IconV2/ic-help-filled.svg diff --git a/src/Assets/IconV2/ic-help-filled.svg b/src/Assets/IconV2/ic-help-filled.svg new file mode 100644 index 000000000..c375921bd --- /dev/null +++ b/src/Assets/IconV2/ic-help-filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/Common/EmptyState/emptyState.scss b/src/Common/EmptyState/emptyState.scss index 08d1f610e..8a8ba4d62 100644 --- a/src/Common/EmptyState/emptyState.scss +++ b/src/Common/EmptyState/emptyState.scss @@ -27,7 +27,7 @@ max-height: 200px; width: auto; } - .button, .override-generic-empty svg { + .button, .override-empty-svg-dim svg { height: 100%; max-height: none; width: 100%; diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index 1b68f10d4..669c8348f 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -59,6 +59,7 @@ import { ReactComponent as ICHeartGreen } from '@IconsV2/ic-heart-green.svg' import { ReactComponent as ICHeartRed } from '@IconsV2/ic-heart-red.svg' import { ReactComponent as ICHeartRedAnimated } from '@IconsV2/ic-heart-red-animated.svg' import { ReactComponent as ICHelm } from '@IconsV2/ic-helm.svg' +import { ReactComponent as ICHelpFilled } from '@IconsV2/ic-help-filled.svg' import { ReactComponent as ICHelpOutline } from '@IconsV2/ic-help-outline.svg' import { ReactComponent as ICHibernate } from '@IconsV2/ic-hibernate.svg' import { ReactComponent as ICInProgress } from '@IconsV2/ic-in-progress.svg' @@ -172,6 +173,7 @@ export const iconMap = { 'ic-heart-red-animated': ICHeartRedAnimated, 'ic-heart-red': ICHeartRed, 'ic-helm': ICHelm, + 'ic-help-filled': ICHelpFilled, 'ic-help-outline': ICHelpOutline, 'ic-hibernate': ICHibernate, 'ic-in-progress': ICInProgress, diff --git a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx index db5ec2299..5588a0c87 100644 --- a/src/Shared/Components/InfoBlock/InfoBlock.component.tsx +++ b/src/Shared/Components/InfoBlock/InfoBlock.component.tsx @@ -38,7 +38,7 @@ const InfoBlock = ({ borderRadiusConfig, borderConfig, }: InfoBlockProps) => { - const baseContainerClass = `${CONTAINER_SIZE_TO_CLASS_MAP[size]} ${VARIANT_TO_BG_MAP[variant]} ${deriveBorderRadiusAndBorderClassFromConfig({ borderConfig, borderRadiusConfig })} w-100 py-8 br-4 bw-1` + const baseContainerClass = `override-empty-svg-dim ${CONTAINER_SIZE_TO_CLASS_MAP[size]} ${VARIANT_TO_BG_MAP[variant]} ${deriveBorderRadiusAndBorderClassFromConfig({ borderConfig, borderRadiusConfig })} w-100 py-8 br-4 bw-1` const iconClass = `dc__no-shrink flex dc__fill-available-space ${SIZE_TO_ICON_CLASS_MAP[size]}` const icon = customIcon ?? VARIANT_TO_ICON_MAP[variant] @@ -94,7 +94,7 @@ const InfoBlock = ({ if (layout === 'row') { return ( -
+
{renderIcon()} {renderContent()} @@ -107,7 +107,7 @@ const InfoBlock = ({ if (layout === 'column') { return ( -
+
{renderContent()} {renderIcon()} diff --git a/src/Shared/Components/InfoBlock/constants.tsx b/src/Shared/Components/InfoBlock/constants.tsx index e372ad68b..7d6867861 100644 --- a/src/Shared/Components/InfoBlock/constants.tsx +++ b/src/Shared/Components/InfoBlock/constants.tsx @@ -14,10 +14,6 @@ * limitations under the License. */ -import { ReactComponent as ICError } from '@Icons/ic-error.svg' -import { ReactComponent as ICHelp } from '@Icons/ic-help.svg' -import { ReactComponent as ICSuccess } from '@Icons/ic-success.svg' -import { ReactComponent as ICWarningY5 } from '@Icons/ic-warning-y5.svg' import { ComponentSizeType } from '@Shared/constants' import { ButtonProps } from '../Button' @@ -34,11 +30,11 @@ export const VARIANT_TO_BG_MAP: Record = { } export const VARIANT_TO_ICON_MAP: Record = { - error: , - help: , + error: , + help: , information: , - success: , - warning: , + success: , + warning: , neutral: , } From 7fa7c13b47cd081d265a637abfe8f3dda4eb621c Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 15:42:47 +0530 Subject: [PATCH 22/80] feat: DeploymentDetailSteps - virtual environment - show deployed by exception user --- .../Components/CICDHistory/Artifacts.tsx | 18 +++++------------- .../CICDHistory/DeploymentDetailSteps.tsx | 12 +++++++++++- .../CICDHistory/DeploymentStatusDetailRow.tsx | 4 +++- .../Components/CICDHistory/TriggerOutput.tsx | 1 + src/Shared/Components/CICDHistory/types.tsx | 8 ++++---- 5 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Shared/Components/CICDHistory/Artifacts.tsx b/src/Shared/Components/CICDHistory/Artifacts.tsx index 5298043fa..b35d1df90 100644 --- a/src/Shared/Components/CICDHistory/Artifacts.tsx +++ b/src/Shared/Components/CICDHistory/Artifacts.tsx @@ -36,7 +36,6 @@ import { useGetUserRoles, } from '../../../Common' import { EMPTY_STATE_STATUS } from '../../constants' -import { Icon } from '../Icon' import { TargetPlatformBadgeList } from '../TargetPlatforms' import { TERMINAL_STATUS_MAP } from './constants' import { ArtifactType, CIListItemType } from './types' @@ -75,6 +74,8 @@ export const CIListItem = ({ !!appliedFilters?.length || !!promotionApprovalMetadata?.promotedFromType + const showCIListHeader = (headerMetaDataPresent || isDeploymentWithoutApproval) && !!renderCIListHeader + return ( <> {type === 'deployed-artifact' && ( @@ -85,15 +86,7 @@ export const CIListItem = ({
)} - {isDeploymentWithoutApproval && ( -
- -

Deployed by an exception user

-
- )} - - {headerMetaDataPresent && - renderCIListHeader && + {showCIListHeader && renderCIListHeader({ userApprovalMetadata, triggeredBy, @@ -101,13 +94,12 @@ export const CIListItem = ({ appliedFiltersTimestamp, promotionApprovalMetadata, selectedEnvironmentName, + isDeploymentWithoutApproval, })}
diff --git a/src/Shared/Components/CICDHistory/DeploymentDetailSteps.tsx b/src/Shared/Components/CICDHistory/DeploymentDetailSteps.tsx index 08f56b220..115cab8cf 100644 --- a/src/Shared/Components/CICDHistory/DeploymentDetailSteps.tsx +++ b/src/Shared/Components/CICDHistory/DeploymentDetailSteps.tsx @@ -43,6 +43,7 @@ const DeploymentDetailSteps = ({ isVirtualEnvironment, processVirtualEnvironmentDeploymentData, renderDeploymentApprovalInfo, + isDeploymentWithoutApproval, }: DeploymentDetailStepsType) => { const history = useHistory() const { url } = useRouteMatch() @@ -51,6 +52,8 @@ const DeploymentDetailSteps = ({ deploymentStatus?.toUpperCase() !== TIMELINE_STATUS.ABORTED, ) const isVirtualEnv = useRef(isVirtualEnvironment) + const isDeploymentWithoutApprovalRef = useRef(isDeploymentWithoutApproval) + const processedData = isVirtualEnv.current && processVirtualEnvironmentDeploymentData ? processVirtualEnvironmentDeploymentData() @@ -69,7 +72,10 @@ const DeploymentDetailSteps = ({ .then((deploymentStatusDetailRes) => { if (deploymentStatus !== 'Aborted') { // eslint-disable-next-line no-use-before-define - processDeploymentStatusData(deploymentStatusDetailRes.result) + processDeploymentStatusData({ + ...deploymentStatusDetailRes.result, + isDeploymentWithoutApproval: isDeploymentWithoutApprovalRef.current, + }) } }) .catch(() => { @@ -97,6 +103,10 @@ const DeploymentDetailSteps = ({ isVirtualEnv.current = isVirtualEnvironment }, [isVirtualEnvironment]) + useEffect(() => { + isDeploymentWithoutApprovalRef.current = isDeploymentWithoutApproval + }, [isDeploymentWithoutApproval]) + const processDeploymentStatusData = (deploymentStatusDetailRes: DeploymentStatusDetailsType): void => { const processedDeploymentStatusDetailsData = isVirtualEnv.current && processVirtualEnvironmentDeploymentData diff --git a/src/Shared/Components/CICDHistory/DeploymentStatusDetailRow.tsx b/src/Shared/Components/CICDHistory/DeploymentStatusDetailRow.tsx index d55511dbd..56417d711 100644 --- a/src/Shared/Components/CICDHistory/DeploymentStatusDetailRow.tsx +++ b/src/Shared/Components/CICDHistory/DeploymentStatusDetailRow.tsx @@ -176,7 +176,9 @@ export const DeploymentStatusDetailRow = ({ > {renderIcon(statusBreakDownType.icon)} - {statusBreakDownType.displayText} + + {statusBreakDownType.displayText} + {statusBreakDownType.displaySubText && ( {statusBreakDownType.displaySubText} diff --git a/src/Shared/Components/CICDHistory/TriggerOutput.tsx b/src/Shared/Components/CICDHistory/TriggerOutput.tsx index 1f630f5b3..79690560d 100644 --- a/src/Shared/Components/CICDHistory/TriggerOutput.tsx +++ b/src/Shared/Components/CICDHistory/TriggerOutput.tsx @@ -133,6 +133,7 @@ const HistoryLogs: React.FC = ({ isVirtualEnvironment={triggerDetails.IsVirtualEnvironment} processVirtualEnvironmentDeploymentData={processVirtualEnvironmentDeploymentData} renderDeploymentApprovalInfo={renderDeploymentApprovalInfo} + isDeploymentWithoutApproval={triggerDetails.isDeploymentWithoutApproval ?? false} /> )} diff --git a/src/Shared/Components/CICDHistory/types.tsx b/src/Shared/Components/CICDHistory/types.tsx index 5b8c77b8b..417f5ed8b 100644 --- a/src/Shared/Components/CICDHistory/types.tsx +++ b/src/Shared/Components/CICDHistory/types.tsx @@ -390,7 +390,7 @@ export interface DeploymentStatusDetailsTimelineType { statusTime: string resourceDetails?: SyncStageResourceDetail[] } -export interface DeploymentStatusDetailsType { +export interface DeploymentStatusDetailsType extends Pick { deploymentFinishedOn: string deploymentStartedOn: string triggeredBy: string @@ -406,7 +406,7 @@ export interface DeploymentStatusDetailsResponse extends ResponseType { interface DeploymentStatusDetailRow { icon: string - displayText: string + displayText: ReactNode displaySubText: string time: string resourceDetails?: any @@ -432,7 +432,7 @@ export interface DeploymentStatusDetailsBreakdownDataType { } } -export interface DeploymentDetailStepsType { +export interface DeploymentDetailStepsType extends Pick { deploymentStatus?: string deploymentAppType?: DeploymentAppTypes isHelmApps?: boolean @@ -446,7 +446,7 @@ export interface DeploymentDetailStepsType { renderDeploymentApprovalInfo: (userApprovalMetadata: UserApprovalMetadataType) => JSX.Element } -export interface RenderCIListHeaderProps { +export interface RenderCIListHeaderProps extends Required> { userApprovalMetadata: UserApprovalMetadataType triggeredBy: string appliedFilters: FilterConditionsListType[] From 6799f341a1be3b402c862c00161ba6a7fde9db14 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 15:43:15 +0530 Subject: [PATCH 23/80] fix: update badge element in TabGroup to use span instead of div --- src/Shared/Components/TabGroup/TabGroup.helpers.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx index 3d515b910..861e7550b 100644 --- a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx @@ -47,7 +47,7 @@ export const getTabIcon = ({ } export const getTabBadge = (badge: TabProps['badge'], className: string) => - badge !== null &&
{badge}
+ badge !== null && {badge} export const getTabIndicator = (showIndicator: TabProps['showIndicator']) => showIndicator && From 9b912bb7c9a8c56111c680f07a41d3656f3fb6f1 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 22 Apr 2025 16:12:42 +0530 Subject: [PATCH 24/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- src/Common/EmptyState/emptyState.scss | 16 ---------------- 3 files changed, 3 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index b489ac89c..9231170a1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-7", + "version": "1.11.0-pre-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-7", + "version": "1.11.0-pre-8", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 085c75fd5..a78037dd4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-7", + "version": "1.11.0-pre-8", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Common/EmptyState/emptyState.scss b/src/Common/EmptyState/emptyState.scss index 3e94a442a..37b6e52a2 100644 --- a/src/Common/EmptyState/emptyState.scss +++ b/src/Common/EmptyState/emptyState.scss @@ -16,22 +16,6 @@ .empty-state { height: 100%; - img { - height: 40%; - max-height: 200px; - width: auto; - max-width: 250px; - } - svg { - height: 40%; - max-height: 200px; - width: auto; - } - .button svg { - height: 100%; - max-height: none; - width: 100%; - } h1, h2, h3, From 794725a39c8f793010d5ceeec4dc608f5db0ab29 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 16:52:42 +0530 Subject: [PATCH 25/80] chore: add ic-key icon --- src/Assets/IconV2/ic-key.svg | 3 +++ src/Shared/Components/Icon/Icon.tsx | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 src/Assets/IconV2/ic-key.svg diff --git a/src/Assets/IconV2/ic-key.svg b/src/Assets/IconV2/ic-key.svg new file mode 100644 index 000000000..fc4da3ebc --- /dev/null +++ b/src/Assets/IconV2/ic-key.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index 68cd908b3..080d8e05a 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -65,6 +65,7 @@ import { ReactComponent as ICInfoFilled } from '@IconsV2/ic-info-filled.svg' import { ReactComponent as ICInfoOutline } from '@IconsV2/ic-info-outline.svg' import { ReactComponent as ICJobColor } from '@IconsV2/ic-job-color.svg' import { ReactComponent as ICK8sJob } from '@IconsV2/ic-k8s-job.svg' +import { ReactComponent as ICKey } from '@IconsV2/ic-key.svg' import { ReactComponent as ICLdap } from '@IconsV2/ic-ldap.svg' import { ReactComponent as ICLightning } from '@IconsV2/ic-lightning.svg' import { ReactComponent as ICLightningFill } from '@IconsV2/ic-lightning-fill.svg' @@ -177,6 +178,7 @@ export const iconMap = { 'ic-info-outline': ICInfoOutline, 'ic-job-color': ICJobColor, 'ic-k8s-job': ICK8sJob, + 'ic-key': ICKey, 'ic-ldap': ICLdap, 'ic-lightning-fill': ICLightningFill, 'ic-lightning': ICLightning, From 3404e9c7a7ed969b8514ce1a0e79d0dfb0c9f5d4 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 16:53:14 +0530 Subject: [PATCH 26/80] feat: add UserIdentifier component --- .../UserIdentifier/UserIdentifier.tsx | 72 +++++++++++++++++++ src/Shared/Components/UserIdentifier/index.ts | 2 + src/Shared/Components/UserIdentifier/types.ts | 12 ++++ src/Shared/Components/index.ts | 1 + 4 files changed, 87 insertions(+) create mode 100644 src/Shared/Components/UserIdentifier/UserIdentifier.tsx create mode 100644 src/Shared/Components/UserIdentifier/index.ts create mode 100644 src/Shared/Components/UserIdentifier/types.ts diff --git a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx new file mode 100644 index 000000000..cdcf998b8 --- /dev/null +++ b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx @@ -0,0 +1,72 @@ +import { getAlphabetIcon } from '@Common/Helper' +import { Tooltip } from '@Common/Tooltip' +import { API_TOKEN_PREFIX } from '@Shared/constants' +import { useUserEmail } from '@Shared/Providers' + +import { Icon } from '../Icon' +import { UserIdentifierProps } from './types' + +const UserIdentifierTooltip = ({ + children, + tooltipContent, +}: Pick) => ( + +
{children}
+
+) + +export const UserIdentifier = ({ + email, + children, + rootClassName, + tooltipContent, + isUserGroup = false, +}: UserIdentifierProps) => { + // HOOKS + const { email: currentUserEmail } = useUserEmail() + + // CONSTANTS + const isCurrentUser = email === currentUserEmail + + return ( +
+ {email.startsWith(API_TOKEN_PREFIX) ? ( + + +
+ + + {isCurrentUser ? 'You' : email.split(':')?.[1] || '-'} + + + {children} +
+
+ ) : ( + + {isUserGroup ? ( + + + + ) : ( + getAlphabetIcon(email, 'dc__no-shrink m-0-imp') + )} +
+ + {isCurrentUser ? 'You' : email} + + {children} +
+
+ )} +
+ ) +} diff --git a/src/Shared/Components/UserIdentifier/index.ts b/src/Shared/Components/UserIdentifier/index.ts new file mode 100644 index 000000000..0b3e4d0e6 --- /dev/null +++ b/src/Shared/Components/UserIdentifier/index.ts @@ -0,0 +1,2 @@ +export * from './types' +export * from './UserIdentifier' diff --git a/src/Shared/Components/UserIdentifier/types.ts b/src/Shared/Components/UserIdentifier/types.ts new file mode 100644 index 000000000..17de36d4d --- /dev/null +++ b/src/Shared/Components/UserIdentifier/types.ts @@ -0,0 +1,12 @@ +import { ReactNode } from 'react' + +export interface UserIdentifierProps { + email: string + children?: ReactNode + isUserGroup?: boolean + rootClassName?: string + /** + * @description - If given, would show tooltip on div containing avatar, email and children + */ + tooltipContent?: string +} diff --git a/src/Shared/Components/index.ts b/src/Shared/Components/index.ts index 673dbe2ca..fa9c56524 100644 --- a/src/Shared/Components/index.ts +++ b/src/Shared/Components/index.ts @@ -94,5 +94,6 @@ export * from './ThemeSwitcher' export * from './ToggleResolveScopedVariables' export * from './UnsavedChanges' export * from './UnsavedChangesDialog' +export * from './UserIdentifier' export * from './VirtualizedList' export * from './WorkflowOptionsModal' From 70a706468c702c93228d0c83db316eb97345d54c Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 22 Apr 2025 17:21:43 +0530 Subject: [PATCH 27/80] chore: icon added for memory and cpu --- src/Assets/IconV2/ic-cpu.svg | 3 +++ src/Assets/IconV2/ic-memory.svg | 3 +++ src/Shared/Components/Icon/Icon.tsx | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 src/Assets/IconV2/ic-cpu.svg create mode 100644 src/Assets/IconV2/ic-memory.svg diff --git a/src/Assets/IconV2/ic-cpu.svg b/src/Assets/IconV2/ic-cpu.svg new file mode 100644 index 000000000..7aafefb1d --- /dev/null +++ b/src/Assets/IconV2/ic-cpu.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Assets/IconV2/ic-memory.svg b/src/Assets/IconV2/ic-memory.svg new file mode 100644 index 000000000..d7e872ce2 --- /dev/null +++ b/src/Assets/IconV2/ic-memory.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index 669c8348f..170d38bed 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -33,6 +33,7 @@ import { ReactComponent as ICCode } from '@IconsV2/ic-code.svg' import { ReactComponent as ICContainer } from '@IconsV2/ic-container.svg' import { ReactComponent as ICCookr } from '@IconsV2/ic-cookr.svg' import { ReactComponent as ICCopy } from '@IconsV2/ic-copy.svg' +import { ReactComponent as ICCpu } from '@IconsV2/ic-cpu.svg' import { ReactComponent as ICCrown } from '@IconsV2/ic-crown.svg' import { ReactComponent as ICCube } from '@IconsV2/ic-cube.svg' import { ReactComponent as ICDelete } from '@IconsV2/ic-delete.svg' @@ -75,6 +76,7 @@ import { ReactComponent as ICLoginDevtronLogo } from '@IconsV2/ic-login-devtron- import { ReactComponent as ICLogout } from '@IconsV2/ic-logout.svg' import { ReactComponent as ICMediumDelete } from '@IconsV2/ic-medium-delete.svg' import { ReactComponent as ICMediumPaintbucket } from '@IconsV2/ic-medium-paintbucket.svg' +import { ReactComponent as ICMemory } from '@IconsV2/ic-memory.svg' import { ReactComponent as ICMicrosoft } from '@IconsV2/ic-microsoft.svg' import { ReactComponent as ICMissing } from '@IconsV2/ic-missing.svg' import { ReactComponent as ICMonitoring } from '@IconsV2/ic-monitoring.svg' @@ -147,6 +149,7 @@ export const iconMap = { 'ic-container': ICContainer, 'ic-cookr': ICCookr, 'ic-copy': ICCopy, + 'ic-cpu': ICCpu, 'ic-crown': ICCrown, 'ic-cube': ICCube, 'ic-delete-lightning': ICDeleteLightning, @@ -189,6 +192,7 @@ export const iconMap = { 'ic-logout': ICLogout, 'ic-medium-delete': ICMediumDelete, 'ic-medium-paintbucket': ICMediumPaintbucket, + 'ic-memory': ICMemory, 'ic-microsoft': ICMicrosoft, 'ic-missing': ICMissing, 'ic-monitoring': ICMonitoring, From 4e9ee8432b48bdca0ca446dfa3a96eeccef82202 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 17:49:01 +0530 Subject: [PATCH 28/80] fix: remove isExceptionUser from CDMaterialResponseType and related logic --- src/Common/Common.service.ts | 2 -- src/Common/Types.ts | 1 - .../Components/AnimatedDeployButton/AnimatedDeployButton.tsx | 2 +- src/Shared/types.ts | 1 + 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index f193a95db..bb1c9fe72 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -320,7 +320,6 @@ export const processCDMaterialServiceResponse = ( ...processCDMaterialsMetaInfo(cdMaterialsResult), ...processCDMaterialsApprovalInfo(false, cdMaterialsResult), ...processImagePromotionInfo(cdMaterialsResult), - isExceptionUser: false, } } @@ -349,7 +348,6 @@ export const processCDMaterialServiceResponse = ( ...approvalInfo, ...metaInfo, ...imagePromotionInfo, - isExceptionUser: cdMaterialsResult.userApprovalConfig?.isExceptionUser ?? false, } } diff --git a/src/Common/Types.ts b/src/Common/Types.ts index 3dcdd5b5c..d78d333f5 100644 --- a/src/Common/Types.ts +++ b/src/Common/Types.ts @@ -785,7 +785,6 @@ export interface CDMaterialResponseType CDMaterialsApprovalInfo, ImagePromotionMaterialInfo { materials: CDMaterialType[] - isExceptionUser: boolean } export interface InputDetailType { diff --git a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx index f5e364133..43a301db4 100644 --- a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx +++ b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx @@ -100,7 +100,7 @@ const AnimatedDeployButton = ({ } size={ComponentSizeType.large} onClick={handleButtonClick} - style={isExceptionUser && !isBulkCDTrigger ? ButtonStyleType.warning : ButtonStyleType.default} + style={isExceptionUser ? ButtonStyleType.warning : ButtonStyleType.default} showTooltip={isExceptionUser} tooltipProps={{ content: isBulkCDTrigger diff --git a/src/Shared/types.ts b/src/Shared/types.ts index 9077d3f68..13e2cb7e4 100644 --- a/src/Shared/types.ts +++ b/src/Shared/types.ts @@ -299,6 +299,7 @@ export interface WorkflowType { appId?: number isSelected?: boolean isExceptionUser?: boolean + canApproverDeploy?: boolean approvalConfiguredIdsMap?: Record imageReleaseTags: string[] appReleaseTags?: string[] From 0450fbead0de73432f5cef6e4b0f918c906b1c37 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Tue, 22 Apr 2025 17:49:32 +0530 Subject: [PATCH 29/80] refactor: UserIdentifier - styling update --- src/Shared/Components/UserIdentifier/UserIdentifier.tsx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx index cdcf998b8..b8050c72e 100644 --- a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx +++ b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx @@ -49,9 +49,7 @@ export const UserIdentifier = ({ ) : ( {isUserGroup ? ( - - - + ) : ( getAlphabetIcon(email, 'dc__no-shrink m-0-imp') )} From 752cc14f4de6035ef3bfe52792e9abf30c05d436 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 22 Apr 2025 18:18:35 +0530 Subject: [PATCH 30/80] chore: cpu & memory icon removed --- src/Assets/Icon/ic-cpu.svg | 20 -------------------- src/Assets/Icon/ic-memory.svg | 19 ------------------- 2 files changed, 39 deletions(-) delete mode 100644 src/Assets/Icon/ic-cpu.svg delete mode 100644 src/Assets/Icon/ic-memory.svg diff --git a/src/Assets/Icon/ic-cpu.svg b/src/Assets/Icon/ic-cpu.svg deleted file mode 100644 index d1554b282..000000000 --- a/src/Assets/Icon/ic-cpu.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/src/Assets/Icon/ic-memory.svg b/src/Assets/Icon/ic-memory.svg deleted file mode 100644 index e7a41596b..000000000 --- a/src/Assets/Icon/ic-memory.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - \ No newline at end of file From 4f05c0b999334f94f1615467f4b2a2036b268c68 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Tue, 22 Apr 2025 18:34:59 +0530 Subject: [PATCH 31/80] chore: cpu icon replaced --- src/Pages/GlobalConfigurations/BuildInfra/constants.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Pages/GlobalConfigurations/BuildInfra/constants.tsx b/src/Pages/GlobalConfigurations/BuildInfra/constants.tsx index f2c82d192..69316efa4 100644 --- a/src/Pages/GlobalConfigurations/BuildInfra/constants.tsx +++ b/src/Pages/GlobalConfigurations/BuildInfra/constants.tsx @@ -14,11 +14,11 @@ * limitations under the License. */ -import { ReactComponent as ICCpu } from '@Icons/ic-cpu.svg' -import { ReactComponent as ICMemory } from '@Icons/ic-memory.svg' import { ReactComponent as ICSprayCan } from '@Icons/ic-spray-can.svg' import { ReactComponent as ICTag } from '@Icons/ic-tag.svg' import { ReactComponent as ICTimer } from '@Icons/ic-timer.svg' +import { ReactComponent as ICCpu } from '@IconsV2/ic-cpu.svg' +import { ReactComponent as ICMemory } from '@IconsV2/ic-memory.svg' import { UseBreadcrumbProps } from '@Common/BreadCrumb/Types' import { CMSecretComponentType } from '@Shared/Services' From e469d5989d6d9b8731645dc42dbed917549c9342 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Wed, 23 Apr 2025 14:00:10 +0530 Subject: [PATCH 32/80] feat: add other app list api from fe-lib --- src/Common/Common.service.ts | 14 ++++++++++++++ src/Common/Constants.ts | 2 ++ src/Common/Types.ts | 17 +++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index d94cd279c..f804a2ccb 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -49,6 +49,8 @@ import { GlobalVariableDTO, GlobalVariableOptionType, UserRole, + EnvAppsMetaDTO, + GetAppsInfoForEnvProps, } from './Types' import { ApiResourceType, STAGE_MAP } from '../Pages' import { RefVariableType, VariableTypeFormat } from './CIPipeline.Types' @@ -515,3 +517,15 @@ export const getGlobalVariables = async ({ throw err } } + +export const getAppsInfoForEnv = async ({ envId, appIds }: GetAppsInfoForEnvProps): Promise => { + const url = getUrlWithSearchParams(`${ROUTES.ENV}/${envId}/${ROUTES.APP_METADATA}`, { + appIds: appIds?.join(), + }) + const response = await get(url) + + return { + appCount: response.result?.appCount ?? 0, + apps: response.result?.apps ?? [], + } +} \ No newline at end of file diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index db6438898..ad1b89398 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -157,6 +157,8 @@ export const ROUTES = { ENVIRONMENT_DATA: 'global/environment-variables', DASHBOARD_EVENT: 'dashboard-event', LICENSE_DATA: 'license/data', + ENV: 'env', + APP_METADATA: 'app-metadata', } as const export enum KEY_VALUE { diff --git a/src/Common/Types.ts b/src/Common/Types.ts index fd9d9700f..3901e1193 100644 --- a/src/Common/Types.ts +++ b/src/Common/Types.ts @@ -27,6 +27,7 @@ import { TargetPlatformItemDTO, ButtonProps, ComponentLayoutType, + StatusType, } from '../Shared' import { ACTION_STATE, @@ -1109,3 +1110,19 @@ export enum ActionTypes { EDIT = 'edit', APPROVER = 'approver', } + +export interface GetAppsInfoForEnvProps { + envId: number + appIds?: number[] +} + +interface AppMeta { + appId: number + appStatus: StatusType + appName: string +} + +export interface EnvAppsMetaDTO { + appCount: number + apps: AppMeta[] +} \ No newline at end of file From c4da692ca0f838c680772f695aea6fa0c9389ea6 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Wed, 23 Apr 2025 17:37:26 +0530 Subject: [PATCH 33/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9231170a1..1a687fd5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-8-beta-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-8-beta-1", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index a78037dd4..a27b91e3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-8-beta-1", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From c88025af1c9c95bc6e57606dc03e23b80f94ac92 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Wed, 23 Apr 2025 18:42:57 +0530 Subject: [PATCH 34/80] fix: DeploymentHistoryConfigDiff - incorrect config diff showing fix --- .../DeploymentHistoryConfigDiff.tsx | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryConfigDiff.tsx b/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryConfigDiff.tsx index c032eb833..4c0721de8 100644 --- a/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryConfigDiff.tsx +++ b/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryConfigDiff.tsx @@ -21,9 +21,9 @@ import { ReactComponent as ICError } from '@Icons/ic-error.svg' import ErrorScreenManager from '@Common/ErrorScreenManager' import { useAsync } from '@Common/Helper' import { useUrlFilters } from '@Common/Hooks' -import { GenericEmptyState, InfoColourBar } from '@Common/index' +import { GenericEmptyState, InfoColourBar, SortingOrder } from '@Common/index' import { Progressing } from '@Common/Progressing' -import { getAppEnvDeploymentConfigList } from '@Shared/Components/DeploymentConfigDiff' +import { DEPLOYMENT_CONFIG_DIFF_SORT_KEY, getAppEnvDeploymentConfigList } from '@Shared/Components/DeploymentConfigDiff' import { groupArrayByObjectKey } from '@Shared/Helpers' import { useMainContext } from '@Shared/Providers' import { EnvResourceType, getAppEnvDeploymentConfig, getCompareSecretsData } from '@Shared/Services' @@ -125,7 +125,7 @@ export const DeploymentHistoryConfigDiff = ({ `${generatePath(path, { ...params })}/${resourceType}${resourceName ? `/${resourceName}` : ''}${search}` // Generate the deployment history config list - const deploymentConfigList = useMemo(() => { + const { deploymentConfigList, sortedDeploymentConfigList } = useMemo(() => { if (!compareDeploymentConfigLoader && compareDeploymentConfig) { const compareList = isPreviousDeploymentConfigAvailable && compareDeploymentConfig[1].status === 'fulfilled' @@ -140,6 +140,8 @@ export const DeploymentHistoryConfigDiff = ({ const currentList = compareDeploymentConfig[0].status === 'fulfilled' ? compareDeploymentConfig[0].value.result : null + // This data is displayed on the deployment history diff view page. + // It requires dynamic sorting based on the current sortBy and sortOrder, which the user can modify using the Sort Button. const configData = getAppEnvDeploymentConfigList({ currentList, compareList, @@ -147,10 +149,21 @@ export const DeploymentHistoryConfigDiff = ({ convertVariables, sortingConfig: { sortBy, sortOrder }, }) - return configData + + // Sorting is hardcoded here because this data is displayed on the deployment history configuration tab. + // The diff needs to be shown on sorted data, and no additional sorting will be applied. + const sortedConfigData = getAppEnvDeploymentConfigList({ + currentList, + compareList, + getNavItemHref, + convertVariables, + sortingConfig: { sortBy: DEPLOYMENT_CONFIG_DIFF_SORT_KEY, sortOrder: SortingOrder.ASC }, + }) + + return { deploymentConfigList: configData, sortedDeploymentConfigList: sortedConfigData } } - return null + return { deploymentConfigList: null, sortedDeploymentConfigList: null } }, [ isPreviousDeploymentConfigAvailable, compareDeploymentConfigLoader, @@ -170,8 +183,11 @@ export const DeploymentHistoryConfigDiff = ({ ) const groupedDeploymentConfigList = useMemo( - () => (deploymentConfigList ? groupArrayByObjectKey(deploymentConfigList.configList, 'groupHeader') : []), - [deploymentConfigList], + () => + sortedDeploymentConfigList + ? groupArrayByObjectKey(sortedDeploymentConfigList.configList, 'groupHeader') + : [], + [sortedDeploymentConfigList], ) /** Previous deployment config has 404 error. */ From 3376c4bb05e572231a7a3a8ec433f1e9de50b7e0 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Wed, 23 Apr 2025 22:56:04 +0530 Subject: [PATCH 35/80] refactor: types refactor --- src/Common/CIPipeline.Types.ts | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/src/Common/CIPipeline.Types.ts b/src/Common/CIPipeline.Types.ts index 04ebfd015..c0bcb8aa0 100644 --- a/src/Common/CIPipeline.Types.ts +++ b/src/Common/CIPipeline.Types.ts @@ -320,29 +320,23 @@ export enum ConditionDataTableHeaderKeys { VALUE = 'val', } -export type InputOutputVariablesErrorObj = Record +type InputOutputVariablesErrorObj = Record +type ConditionDetailsErrorObj = Record -export type ConditionDetailsErrorObj = Record +interface StepDetailTaskErrorObj { + inputVariables?: Record + outputVariables?: Record + isInputVariablesValid?: boolean + isOutputVariablesValid?: boolean + conditionDetails?: Record + isConditionDetailsValid?: boolean +} export interface TaskErrorObj { isValid: boolean name: ErrorObj - inlineStepDetail?: { - inputVariables?: Record - outputVariables?: Record - isInputVariablesValid?: boolean - isOutputVariablesValid?: boolean - conditionDetails?: Record - isConditionDetailsValid?: boolean - } - pluginRefStepDetail?: { - inputVariables?: Record - outputVariables?: Record - isInputVariablesValid?: boolean - isOutputVariablesValid?: boolean - conditionDetails?: Record - isConditionDetailsValid?: boolean - } + inlineStepDetail?: StepDetailTaskErrorObj + pluginRefStepDetail?: StepDetailTaskErrorObj } export interface FormErrorObjectType { name: ErrorObj From 756104bdbb6dd5207a18fa0a70b3a17f848fce33 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Thu, 24 Apr 2025 12:13:39 +0530 Subject: [PATCH 36/80] feat: add addBtnTooltip prop to DynamicDataTableHeader for customizable add button tooltip --- .../Components/DynamicDataTable/DynamicDataTableHeader.tsx | 4 ++-- src/Shared/Components/DynamicDataTable/types.ts | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Shared/Components/DynamicDataTable/DynamicDataTableHeader.tsx b/src/Shared/Components/DynamicDataTable/DynamicDataTableHeader.tsx index a6d59cb91..45bd7e2a6 100644 --- a/src/Shared/Components/DynamicDataTable/DynamicDataTableHeader.tsx +++ b/src/Shared/Components/DynamicDataTable/DynamicDataTableHeader.tsx @@ -27,6 +27,7 @@ export const DynamicDataTableHeader = } variant={ButtonVariantType.borderLess} size={ComponentSizeType.xs} - showAriaLabelInTippy={false} /> )} {key === lastHeaderKey && headerComponent} diff --git a/src/Shared/Components/DynamicDataTable/types.ts b/src/Shared/Components/DynamicDataTable/types.ts index 8d3785d17..f8e378eaf 100644 --- a/src/Shared/Components/DynamicDataTable/types.ts +++ b/src/Shared/Components/DynamicDataTable/types.ts @@ -169,6 +169,10 @@ export type DynamicDataTableProps void /** @@ -233,6 +237,7 @@ export interface DynamicDataTableHeaderProps Date: Thu, 24 Apr 2025 13:18:37 +0530 Subject: [PATCH 37/80] refactor: remove monaco-editor, codeMirror env flag --- package-lock.json | 143 ----- package.json | 6 - src/Common/CodeEditor/CodeEditor.reducer.ts | 91 --- src/Common/CodeEditor/CodeEditor.tsx | 556 ------------------ src/Common/CodeEditor/codeEditor.scss | 133 ----- src/Common/CodeEditor/index.ts | 18 - src/Common/CodeEditor/types.ts | 136 ----- src/Common/CodeEditor/utils.ts | 32 - src/Common/CodeMirror/codeEditor.scss | 4 + src/Common/index.ts | 1 - .../CodeEditorWrapper/CodeEditorWrapper.tsx | 54 +- .../Components/CodeEditorWrapper/index.ts | 2 +- .../Components/CodeEditorWrapper/types.ts | 20 +- src/index.ts | 5 - vite.config.ts | 9 +- 15 files changed, 28 insertions(+), 1182 deletions(-) delete mode 100644 src/Common/CodeEditor/CodeEditor.reducer.ts delete mode 100644 src/Common/CodeEditor/CodeEditor.tsx delete mode 100644 src/Common/CodeEditor/codeEditor.scss delete mode 100644 src/Common/CodeEditor/index.ts delete mode 100644 src/Common/CodeEditor/types.ts delete mode 100644 src/Common/CodeEditor/utils.ts diff --git a/package-lock.json b/package-lock.json index 9231170a1..6d1d6ac95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -39,7 +39,6 @@ "react-diff-viewer-continued": "^3.4.0", "react-draggable": "^4.4.5", "react-international-phone": "^4.5.0", - "react-monaco-editor": "^0.54.0", "react-virtualized-sticky-tree": "^3.0.0-beta18", "sass": "^1.69.7", "tslib": "2.7.0" @@ -75,8 +74,6 @@ "json-schema": "^0.4.0", "lint-staged": "^12.5.0", "moment": "^2.29.4", - "monaco-editor": "0.44.0", - "monaco-yaml": "5.1.1", "prettier": "^3.1.1", "react-ga4": "^1.4.1", "react-toastify": "9.1.3", @@ -8527,12 +8524,6 @@ "node": ">=6" } }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true - }, "node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -9304,96 +9295,6 @@ "node": "*" } }, - "node_modules/monaco-editor": { - "version": "0.44.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", - "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==" - }, - "node_modules/monaco-languageserver-types": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/monaco-languageserver-types/-/monaco-languageserver-types-0.3.4.tgz", - "integrity": "sha512-d58sP5yNhjs8uG1ESXs0hFnuX2YfdMhiGeWhdgTUZyG9aaWgyI4dDwrK1khf1mPF2u9Sljv42sfYqPFZnqYMYg==", - "dev": true, - "dependencies": { - "monaco-types": "^0.1.0", - "vscode-languageserver-protocol": "^3.0.0", - "vscode-uri": "^3.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/remcohaszing" - } - }, - "node_modules/monaco-marker-data-provider": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/monaco-marker-data-provider/-/monaco-marker-data-provider-1.2.4.tgz", - "integrity": "sha512-4DsPgsAqpTyUDs3humXRBPUJoihTv+L6v9aupQWD80X2YXaCXUd11mWYeSCYHuPgdUmjFaNWCEOjQ6ewf/QA1Q==", - "dev": true, - "dependencies": { - "monaco-types": "^0.1.0" - }, - "funding": { - "url": "https://github.com/sponsors/remcohaszing" - } - }, - "node_modules/monaco-types": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/monaco-types/-/monaco-types-0.1.0.tgz", - "integrity": "sha512-aWK7SN9hAqNYi0WosPoMjenMeXJjwCxDibOqWffyQ/qXdzB/86xshGQobRferfmNz7BSNQ8GB0MD0oby9/5fTQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/remcohaszing" - } - }, - "node_modules/monaco-worker-manager": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/monaco-worker-manager/-/monaco-worker-manager-2.0.1.tgz", - "integrity": "sha512-kdPL0yvg5qjhKPNVjJoym331PY/5JC11aPJXtCZNwWRvBr6jhkIamvYAyiY5P1AWFmNOy0aRDRoMdZfa71h8kg==", - "dev": true, - "peerDependencies": { - "monaco-editor": ">=0.30.0" - } - }, - "node_modules/monaco-yaml": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/monaco-yaml/-/monaco-yaml-5.1.1.tgz", - "integrity": "sha512-BuZ0/ZCGjrPNRzYMZ/MoxH8F/SdM+mATENXnpOhDYABi1Eh+QvxSszEct+ACSCarZiwLvy7m6yEF/pvW8XJkyQ==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.0", - "jsonc-parser": "^3.0.0", - "monaco-languageserver-types": "^0.3.0", - "monaco-marker-data-provider": "^1.0.0", - "monaco-types": "^0.1.0", - "monaco-worker-manager": "^2.0.0", - "path-browserify": "^1.0.0", - "prettier": "^2.0.0", - "vscode-languageserver-textdocument": "^1.0.0", - "vscode-languageserver-types": "^3.0.0", - "vscode-uri": "^3.0.0", - "yaml": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/remcohaszing" - }, - "peerDependencies": { - "monaco-editor": ">=0.36" - } - }, - "node_modules/monaco-yaml/node_modules/prettier": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", - "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, "node_modules/moo": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", @@ -10450,19 +10351,6 @@ "moment": ">=1.6.0" } }, - "node_modules/react-monaco-editor": { - "version": "0.54.0", - "resolved": "https://registry.npmjs.org/react-monaco-editor/-/react-monaco-editor-0.54.0.tgz", - "integrity": "sha512-9JwO69851mfpuhYLHlKbae7omQWJ/2ICE2lbL0VHyNyZR8rCOH7440u+zAtDgiOMpLwmYdY1sEZCdRefywX6GQ==", - "dependencies": { - "prop-types": "^15.8.1" - }, - "peerDependencies": { - "@types/react": ">=16 <= 18", - "monaco-editor": "^0.39.0", - "react": ">=16 <= 18" - } - }, "node_modules/react-outside-click-handler": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/react-outside-click-handler/-/react-outside-click-handler-1.3.0.tgz", @@ -12728,37 +12616,6 @@ "@esbuild/win32-x64": "0.21.5" } }, - "node_modules/vscode-jsonrpc": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", - "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", - "dev": true, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", - "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", - "dev": true, - "dependencies": { - "vscode-jsonrpc": "8.2.0", - "vscode-languageserver-types": "3.17.5" - } - }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", - "dev": true - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.5", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", - "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==", - "dev": true - }, "node_modules/vscode-uri": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.8.tgz", diff --git a/package.json b/package.json index a78037dd4..e982413c1 100644 --- a/package.json +++ b/package.json @@ -66,8 +66,6 @@ "json-schema": "^0.4.0", "lint-staged": "^12.5.0", "moment": "^2.29.4", - "monaco-editor": "0.44.0", - "monaco-yaml": "5.1.1", "prettier": "^3.1.1", "react-ga4": "^1.4.1", "react-toastify": "9.1.3", @@ -127,7 +125,6 @@ "react-diff-viewer-continued": "^3.4.0", "react-draggable": "^4.4.5", "react-international-phone": "^4.5.0", - "react-monaco-editor": "^0.54.0", "react-virtualized-sticky-tree": "^3.0.0-beta18", "sass": "^1.69.7", "tslib": "2.7.0" @@ -138,9 +135,6 @@ "react": "^17.0.2", "react-dom": "^17.0.2" }, - "react-monaco-editor": { - "monaco-editor": "0.44.0" - }, "vite-plugin-svgr": { "vite": "5.4.17" }, diff --git a/src/Common/CodeEditor/CodeEditor.reducer.ts b/src/Common/CodeEditor/CodeEditor.reducer.ts deleted file mode 100644 index 1def619f1..000000000 --- a/src/Common/CodeEditor/CodeEditor.reducer.ts +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import YAML from 'yaml' - -import { noop, YAMLStringify } from '@Common/Helper' - -import { MODES } from '../Constants' -import { Action, CodeEditorInitialValueType, CodeEditorState } from './types' -import { getCodeEditorThemeFromAppTheme } from './utils' - -export const CodeEditorReducer = (state: CodeEditorState, action: Action) => { - switch (action.type) { - case 'changeLanguage': - return { ...state, mode: action.value } - case 'setDiff': - return { ...state, diffMode: action.value } - case 'setTheme': - return { ...state, theme: action.value } - case 'setCode': - return { ...state, code: action.value } - case 'setDefaultCode': - return { ...state, defaultCode: action.value } - case 'setHeight': - return { ...state, height: action.value.toString() } - default: - return state - } -} - -export const parseValueToCode = (value: string, mode: string, tabSize: number) => { - let obj = null - - try { - obj = JSON.parse(value) - } catch { - try { - obj = YAML.parse(value) - } catch { - noop() - } - } - - let final = value - - if (obj) { - switch (mode) { - case MODES.JSON: - final = JSON.stringify(obj, null, tabSize) - break - case MODES.YAML: - final = YAMLStringify(obj) - break - default: - break - } - } - - return final -} - -export const initialState = ({ - mode, - theme, - value, - defaultValue, - diffView, - noParsing, - tabSize, - appTheme, -}: CodeEditorInitialValueType): CodeEditorState => ({ - mode: mode as MODES, - theme: getCodeEditorThemeFromAppTheme(theme, appTheme), - code: noParsing ? value : parseValueToCode(value, mode, tabSize), - defaultCode: noParsing ? defaultValue : parseValueToCode(defaultValue, mode, tabSize), - diffMode: diffView, - noParsing: [MODES.JSON, MODES.YAML].includes(mode as MODES) ? noParsing : true, -}) diff --git a/src/Common/CodeEditor/CodeEditor.tsx b/src/Common/CodeEditor/CodeEditor.tsx deleted file mode 100644 index d3e755da8..000000000 --- a/src/Common/CodeEditor/CodeEditor.tsx +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import React, { useEffect, useMemo, useReducer, useRef, useState } from 'react' -import MonacoEditor, { ChangeHandler, DiffEditorDidMount, EditorDidMount, MonacoDiffEditor } from 'react-monaco-editor' -import ReactGA from 'react-ga4' -import * as monaco from 'monaco-editor/esm/vs/editor/editor.api' -import { configureMonacoYaml } from 'monaco-yaml' - -import { ReactComponent as ICWarningY5 } from '@Icons/ic-warning-y5.svg' -import { ReactComponent as ICCompare } from '@Icons/ic-compare.svg' -import { useTheme } from '@Shared/Providers' -import { ReactComponent as Info } from '../../Assets/Icon/ic-info-filled.svg' -import { ReactComponent as ErrorIcon } from '../../Assets/Icon/ic-error-exclamation.svg' -import './codeEditor.scss' -import 'monaco-editor' - -import { cleanKubeManifest, useEffectAfterMount, useJsonYaml } from '../Helper' -import { useWindowSize } from '../Hooks' -import Select from '../Select/Select' -import RadioGroup from '../RadioGroup/RadioGroup' -import { ClipboardButton } from '../ClipboardButton/ClipboardButton' -import { Progressing } from '../Progressing' -import { - CodeEditorComposition, - CodeEditorHeaderComposition, - CodeEditorHeaderInterface, - CodeEditorInterface, - CodeEditorThemesKeys, - InformationBarProps, -} from './types' -import { CodeEditorReducer, initialState, parseValueToCode } from './CodeEditor.reducer' -import { DEFAULT_JSON_SCHEMA_URI, MODES } from '../Constants' -import { getCodeEditorThemeFromAppTheme } from './utils' - -const CodeEditorContext = React.createContext(null) - -function useCodeEditorContext() { - const context = React.useContext(CodeEditorContext) - if (!context) { - throw new Error(`cannot be rendered outside the component`) - } - return context -} - -const INITIAL_HEIGHT_WHEN_DYNAMIC_HEIGHT = 100 - -const CodeEditor: React.FC & CodeEditorComposition = React.memo( - ({ - value, - mode = MODES.JSON, - noParsing = false, - defaultValue = '', - children, - tabSize = 2, - lineDecorationsWidth = 0, - height = 450, - inline = false, - shebang = '', - onChange, - readOnly, - diffView, - theme, - loading, - customLoader, - focus, - validatorSchema, - schemaURI = DEFAULT_JSON_SCHEMA_URI, - isKubernetes = true, - cleanData = false, - onBlur, - onFocus, - adjustEditorHeightToContent = false, - disableSearch = false, - originalEditable = false, - }) => { - const { appTheme } = useTheme() - - if (cleanData) { - value = cleanKubeManifest(value) - defaultValue = cleanKubeManifest(defaultValue) - } - - const editorRef = useRef(null) - const monacoRef = useRef(null) - const { width, height: windowHeight } = useWindowSize() - const memoisedReducer = React.useCallback(CodeEditorReducer, []) - const [state, dispatch] = useReducer( - memoisedReducer, - initialState({ - mode, - theme, - value, - defaultValue, - diffView, - noParsing, - tabSize, - appTheme, - }), - ) - const [, json, yamlCode, error] = useJsonYaml(state.code, tabSize, state.mode, !state.noParsing) - const [, originalJson, originalYaml] = useJsonYaml(state.defaultCode, tabSize, state.mode, !state.noParsing) - const [contentHeight, setContentHeight] = useState( - adjustEditorHeightToContent ? INITIAL_HEIGHT_WHEN_DYNAMIC_HEIGHT : height, - ) - // TODO: upgrade to 0.56.2 to remove this - const onChangeRef = useRef(onChange) - onChangeRef.current = onChange - monaco.editor.defineTheme(CodeEditorThemesKeys.vsDarkDT, { - base: 'vs-dark', - inherit: true, - rules: [ - // @ts-ignore - { background: '#181920' }, - ], - colors: { - 'editor.background': '#181920', - }, - }) - - monaco.editor.defineTheme(CodeEditorThemesKeys.networkStatusInterface, { - base: 'vs-dark', - inherit: true, - rules: [ - // @ts-ignore - { background: '#1A1A1A' }, - ], - colors: { - 'editor.background': '#1A1A1A', - }, - }) - - useEffect(() => { - dispatch({ type: 'setTheme', value: getCodeEditorThemeFromAppTheme(theme, appTheme) }) - }, [appTheme]) - - useEffect(() => { - const rule = !disableSearch - ? null - : monaco.editor.addKeybindingRule({ - command: null, - keybinding: monaco.KeyCode.KeyF | monaco.KeyMod.CtrlCmd, - }) - return () => { - rule?.dispose() - } - }, [disableSearch]) - - const editorDidMount: EditorDidMount = (editor) => { - if ( - mode === MODES.YAML && - editor && - typeof editor.getModel === 'function' && - typeof editor.getModel().updateOptions === 'function' - ) { - editor.getModel().updateOptions({ tabSize: 2 }) - } - - if (editor) { - if (typeof editor.onDidFocusEditorWidget === 'function' && typeof onFocus === 'function') { - editor.onDidFocusEditorWidget(onFocus) - } - - if (typeof editor.onDidBlurEditorWidget === 'function' && typeof onBlur === 'function') { - editor.onDidBlurEditorWidget(onBlur) - } - } - - if (adjustEditorHeightToContent && editor) { - editor.onDidContentSizeChange(() => { - setContentHeight(editor.getContentHeight()) - }) - setContentHeight(editor.getContentHeight()) - } - - editorRef.current = editor - monacoRef.current = monaco - } - - const diffEditorDidMount: DiffEditorDidMount = (editor, monaco) => { - const originalEditor = editor.getOriginalEditor() - const modifiedEditor = editor.getModifiedEditor() - - if (adjustEditorHeightToContent) { - originalEditor.onDidContentSizeChange(() => { - setContentHeight( - Math.max( - typeof contentHeight === 'number' ? contentHeight : Number.MIN_SAFE_INTEGER, - originalEditor.getContentHeight(), - ), - ) - }) - - modifiedEditor.onDidContentSizeChange(() => { - setContentHeight( - Math.max( - typeof contentHeight === 'number' ? contentHeight : Number.MIN_SAFE_INTEGER, - modifiedEditor.getContentHeight(), - ), - ) - }) - - setContentHeight(Math.max(originalEditor.getContentHeight(), modifiedEditor.getContentHeight())) - } - if (originalEditable) { - originalEditor.onDidChangeModelContent(() => { - codeEditorOnChange(modifiedEditor.getValue(), originalEditor.getValue()) - }) - } - - editorRef.current = editor - monacoRef.current = monaco - } - - const editorHeight = useMemo(() => { - if (!adjustEditorHeightToContent) { - return height - } - return contentHeight - }, [height, contentHeight, adjustEditorHeightToContent]) - - useEffect(() => { - if (!validatorSchema) { - return - } - const config = configureMonacoYaml(monaco, { - enableSchemaRequest: true, - isKubernetes, - schemas: [ - { - uri: schemaURI, - fileMatch: ['*'], // associate with our model - schema: validatorSchema, - }, - ], - }) - return () => { - config.dispose() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [validatorSchema, schemaURI]) - useEffect(() => { - if (!editorRef.current) { - return - } - editorRef.current.updateOptions({ readOnly }) - }, [readOnly]) - - useEffect(() => { - if (!editorRef.current) { - return - } - editorRef.current.layout() - }, [width, windowHeight]) - - const setCode = (value: string, originalValue: string) => { - dispatch({ type: 'setCode', value }) - dispatch({ type: 'setDefaultCode', value: originalValue }) - onChangeRef.current?.(value, originalValue) - } - - useEffectAfterMount(() => { - if (noParsing) { - setCode(value, defaultValue) - - return - } - - if (value === state.code) { - return - } - - setCode(parseValueToCode(value, state.mode, tabSize), parseValueToCode(defaultValue, state.mode, tabSize)) - }, [value, defaultValue, noParsing]) - - useEffect(() => { - dispatch({ type: 'setDiff', value: diffView }) - }, [diffView]) - - useEffect(() => { - if (focus) { - editorRef.current.focus() - } - }, [focus]) - - const codeEditorOnChange = (newValue: string, newOriginalValue: string) => { - setCode(newValue, newOriginalValue) - } - - const handleOnChange: ChangeHandler = (newValue) => { - codeEditorOnChange(newValue, editorRef.current?.getOriginalEditor?.().getValue?.() ?? '') - } - - function handleLanguageChange(mode: 'json' | 'yaml') { - dispatch({ type: 'changeLanguage', value: mode }) - setCode(mode === 'json' ? json : yamlCode, mode === 'json' ? originalJson : originalYaml) - } - - const options: monaco.editor.IEditorConstructionOptions = { - selectOnLineNumbers: true, - roundedSelection: false, - readOnly, - lineDecorationsWidth, - automaticLayout: true, - scrollBeyondLastLine: false, - ...(adjustEditorHeightToContent - ? { - overviewRulerLanes: adjustEditorHeightToContent ? 0 : 1, - } - : {}), - minimap: { - enabled: false, - }, - scrollbar: { - alwaysConsumeMouseWheel: false, - vertical: inline ? 'hidden' : 'auto', - ...(adjustEditorHeightToContent - ? { - vertical: 'hidden', - verticalScrollbarSize: 0, - verticalSliderSize: 0, - } - : {}), - }, - lineNumbers(lineNumber) { - return `${lineNumber}` - }, - } - - const diffViewOptions: monaco.editor.IDiffEditorConstructionOptions = { - ...options, - originalEditable: originalEditable && !readOnly, - useInlineViewWhenSpaceIsLimited: false, - } - - return ( - - {children} - {loading ? ( - - ) : ( - <> - {shebang &&
{shebang}
} - {state.diffMode ? ( - - ) : ( - - )} - - )} -
- ) - }, -) - -const Header: React.FC & CodeEditorHeaderComposition = ({ - children, - className, - hideDefaultSplitHeader, -}) => { - const { defaultValue, state } = useCodeEditorContext() - return ( -
-
- {children} - {!hideDefaultSplitHeader && defaultValue && } -
- {state.diffMode ?
: null} -
- ) -} - -const ThemeChanger = ({}) => { - const { readOnly, state, dispatch } = useCodeEditorContext() - function handleChangeTheme(e) { - dispatch({ type: 'setTheme', value: e.target.value }) - } - - const themes = ['vs', 'vs-dark'] - return ( - - ) -} - -const LanguageChanger = ({}) => { - const { readOnly, handleLanguageChange, state } = useCodeEditorContext() - if (state.noParsing) { - return null - } - return ( -
- { - ReactGA.event({ - category: 'JSON-YAML Switch', - action: `${event.target.value} view`, - }) - handleLanguageChange(event.target.value) - }} - > - JSON - YAML - -
- ) -} - -const ValidationError = () => { - const { error } = useCodeEditorContext() - return error ?
{error}
: null -} - -const Warning: React.FC = (props) => ( -
- - {props.text} - {props.children} -
-) - -const ErrorBar: React.FC = (props) => ( -
- - {props.text} - {props.children} -
-) - -const Information: React.FC = (props) => ( -
- - {props.text} - {props.children} -
-) - -const Clipboard = () => { - const { state } = useCodeEditorContext() - return -} - -const SplitPane = ({}) => { - const { state, dispatch, readOnly } = useCodeEditorContext() - function handleToggle(e) { - if (readOnly) { - return - } - dispatch({ type: 'setDiff', value: !state.diffMode }) - } - return ( -
- - {state.diffMode ? 'Hide comparison' : 'Compare with default'} -
- ) -} -// TODO: CodeEditor should be composed of CodeEditorPlaceholder -const CodeEditorPlaceholder = ({ className = '', style = {}, customLoader }): JSX.Element => { - const { height } = useCodeEditorContext() - - if (customLoader) { - return customLoader - } - - return ( -
-
-
- -
-
-
- ) -} - -const Container = ({ - children, - flexExpand, - overflowHidden, -}: { - children: React.ReactNode - flexExpand?: boolean - overflowHidden?: boolean -}) => ( -
- {children} -
-) - -CodeEditor.LanguageChanger = LanguageChanger -CodeEditor.ThemeChanger = ThemeChanger -CodeEditor.ValidationError = ValidationError -CodeEditor.Clipboard = Clipboard -CodeEditor.Header = Header -CodeEditor.Warning = Warning -CodeEditor.ErrorBar = ErrorBar -CodeEditor.Information = Information -CodeEditor.Container = Container - -export default CodeEditor diff --git a/src/Common/CodeEditor/codeEditor.scss b/src/Common/CodeEditor/codeEditor.scss deleted file mode 100644 index 9415f8385..000000000 --- a/src/Common/CodeEditor/codeEditor.scss +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - .code-editor__header { - .radio-group { - height: 24px; - overflow: hidden; - } - - .radio-group input[type='checkbox']:checked + .radio__item-label { - background: var(--N700); - border-radius: 0; - color: var(--N0); - } - - .radio__item-label { - padding: 0 8px; - display: inline-block; - width: 100%; - height: 100%; - line-height: 24px; - cursor: pointer; - } - - .radio-group { - padding: 0; - } - - .code-editor__split-pane { - color: var(--N700); - margin-left: auto; - fill: var(--N700); - } - - label.form__error { - margin-left: 8px; - } - - button.clipboard { - margin-left: auto; - height: 20px; - width: 20px; - padding: 0; - background: transparent; - border: unset; - outline: unset; - - svg { - height: 100%; - width: 100%; - } - - &:active { - svg { - height: 90%; - width: 90%; - - path { - fill: var(--G500); - } - } - } - } -} - -.code-editor__header-error { - padding: 8px 16px; - font-size: 12px; - border: solid 1px var(--N200); - background-color: var(--R100); - font-weight: normal; - font-stretch: normal; - font-style: normal; - line-height: 1.33; - letter-spacing: normal; - color: var(--R500); -} - -.code-editor-container { - width: 100%; - border: 1px solid var(--N200); - border-radius: 4px; - overflow: hidden; -} - -.react-monaco-editor-container { - min-height: 300px; -} - -.code-editor__information-info-icon { - width: 16px; - height: 16px; - margin: 0 8px 0 0; - vertical-align: bottom; -} - -.code-editor__toggle { - .toggle__switch { - width: 32px; - margin: 0 12px; - } - - color: var(--N0); -} - -.monaco-editor-hover { - margin-left: 40px; -} - -.monaco-scrollable-element { - & > .visible { - z-index: 9; - } -} - -.code-editor-shebang { - padding: 0 52px; - color: var(--N900); - opacity: 0.6; -} diff --git a/src/Common/CodeEditor/index.ts b/src/Common/CodeEditor/index.ts deleted file mode 100644 index b3fc4c73c..000000000 --- a/src/Common/CodeEditor/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { default as CodeEditor } from './CodeEditor' -export * from './types' diff --git a/src/Common/CodeEditor/types.ts b/src/Common/CodeEditor/types.ts deleted file mode 100644 index 85f9a7813..000000000 --- a/src/Common/CodeEditor/types.ts +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { AppThemeType } from '@Shared/Providers' - -import { MODES } from '../Constants' - -export interface InformationBarProps { - text: string - className?: string - children?: React.ReactNode -} - -export enum CodeEditorThemesKeys { - vsDarkDT = 'vs-dark--dt', - vs = 'vs', - networkStatusInterface = 'network-status-interface', -} - -interface CodeEditorBaseInterface { - value?: string - lineDecorationsWidth?: number - responseType?: string - onChange?: (value: string, defaultValue: string) => void - onBlur?: () => void - onFocus?: () => void - children?: any - defaultValue?: string - mode?: MODES | string - tabSize?: number - readOnly?: boolean - noParsing?: boolean - inline?: boolean - shebang?: string | JSX.Element - diffView?: boolean - loading?: boolean - customLoader?: JSX.Element - theme?: CodeEditorThemesKeys - original?: string - focus?: boolean - validatorSchema?: any - isKubernetes?: boolean - cleanData?: boolean - schemaURI?: string - /** - * If true, disable the in-built search of monaco editor - * @default false - */ - disableSearch?: boolean - /** - * If true, Enable original value editing of monaco editor - * @default false - */ - originalEditable?: boolean -} - -export type CodeEditorInterface = CodeEditorBaseInterface & - ( - | { - adjustEditorHeightToContent?: boolean - height?: never - } - | { - adjustEditorHeightToContent?: never - height?: number | string - } - ) - -export interface CodeEditorHeaderInterface { - children?: any - className?: string - hideDefaultSplitHeader?: boolean -} -export interface CodeEditorComposition { - Header?: React.FC - LanguageChanger?: React.FC - ThemeChanger?: React.FC - ValidationError?: React.FC - Clipboard?: React.FC - Warning?: React.FC - ErrorBar?: React.FC - Information?: React.FC - Container?: React.FC<{ children: React.ReactNode; flexExpand?: boolean; overflowHidden?: boolean }> -} -export interface CodeEditorHeaderComposition { - LanguageChanger?: React.FC - ThemeChanger?: React.FC - ValidationError?: React.FC - Clipboard?: React.FC -} - -type ActionTypes = 'changeLanguage' | 'setDiff' | 'setTheme' | 'setCode' | 'setDefaultCode' | 'setHeight' - -export interface Action { - type: ActionTypes - value: any -} - -export interface CodeEditorInitialValueType extends Pick { - mode: string - diffView: boolean - value: string - defaultValue: string - noParsing?: boolean - tabSize: number - appTheme: AppThemeType -} - -export interface CodeEditorState { - mode: MODES - diffMode: boolean - theme: CodeEditorThemesKeys - code: string - defaultCode: string - noParsing: boolean -} - -export enum CodeEditorActionTypes { - reInit = 'reInit', - submitLoading = 'submitLoading', - overrideLoading = 'overrideLoading', - success = 'success', -} diff --git a/src/Common/CodeEditor/utils.ts b/src/Common/CodeEditor/utils.ts deleted file mode 100644 index 675519195..000000000 --- a/src/Common/CodeEditor/utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { AppThemeType } from '@Shared/Providers' - -import { CodeEditorInterface, CodeEditorThemesKeys } from './types' - -export const getCodeEditorThemeFromAppTheme = ( - editorTheme: CodeEditorInterface['theme'], - appTheme: AppThemeType, -): CodeEditorInterface['theme'] => { - if (!editorTheme) { - const editorThemeBasedOnAppTheme = - appTheme === AppThemeType.dark ? CodeEditorThemesKeys.vsDarkDT : CodeEditorThemesKeys.vs - return editorThemeBasedOnAppTheme - } - - return editorTheme -} diff --git a/src/Common/CodeMirror/codeEditor.scss b/src/Common/CodeMirror/codeEditor.scss index 202fa4ee0..b25e43aef 100644 --- a/src/Common/CodeMirror/codeEditor.scss +++ b/src/Common/CodeMirror/codeEditor.scss @@ -175,6 +175,10 @@ max-width: 300px; } + .cm-tooltip-autocomplete { + background-color: var(--bg-primary); + } + .cm-diagnostic-error { border-top-left-radius: 2px; border-bottom-left-radius: 2px; diff --git a/src/Common/index.ts b/src/Common/index.ts index a1aadbe5a..1a91abe1f 100644 --- a/src/Common/index.ts +++ b/src/Common/index.ts @@ -22,7 +22,6 @@ export { default as ChartVersionAndTypeSelector } from './ChartVersionAndTypeSel export * from './Checkbox' export * from './CIPipeline.Types' export { ClipboardButton } from './ClipboardButton/ClipboardButton' -export * from './CodeEditor/types' export * from './Common.service' export * from './Constants' export * from './CustomTagSelector' diff --git a/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx b/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx index c28e1bd06..a00c91dcd 100644 --- a/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx +++ b/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx @@ -14,66 +14,44 @@ * limitations under the License. */ -import { CodeEditor } from '@Common/CodeEditor' import { CodeEditor as CodeMirror, CodeEditorHeaderProps, CodeEditorStatusBarProps } from '@Common/CodeMirror' import { CodeEditorWrapperProps } from './types' -export const isCodeMirrorEnabled = () => window._env_.FEATURE_CODE_MIRROR_ENABLE - export const CodeEditorWrapper = ({ + /* eslint-disable @typescript-eslint/no-unused-vars */ codeEditorProps, codeMirrorProps, children, ...restProps -}: CodeEditorWrapperProps) => - isCodeMirrorEnabled() ? ( - {...(codeMirrorProps as any)} {...restProps}> - {children} - - ) : ( - - {children} - - ) - -const CodeEditorLanguageChangerWrapper = () => (isCodeMirrorEnabled() ? null : ) - -const CodeEditorThemeChangerWrapper = () => (isCodeMirrorEnabled() ? null : ) +}: CodeEditorWrapperProps) => ( + {...(codeMirrorProps as any)} {...restProps}> + {children} + +) -const CodeEditorValidationErrorWrapper = () => (isCodeMirrorEnabled() ? null : ) +const CodeEditorClipboardWrapper = () => -const CodeEditorClipboardWrapper = () => (isCodeMirrorEnabled() ? : ) +const CodeEditorHeaderWrapper = (props: CodeEditorHeaderProps) => -const CodeEditorHeaderWrapper = (props: CodeEditorHeaderProps) => - isCodeMirrorEnabled() ? : +const CodeEditorWarningWrapper = (props: CodeEditorStatusBarProps) => -const CodeEditorWarningWrapper = (props: CodeEditorStatusBarProps) => - isCodeMirrorEnabled() ? : +const CodeEditorErrorBarWrapper = (props: CodeEditorStatusBarProps) => -const CodeEditorErrorBarWrapper = (props: CodeEditorStatusBarProps) => - isCodeMirrorEnabled() ? : - -const CodeEditorInformationWrapper = (props: CodeEditorStatusBarProps) => - isCodeMirrorEnabled() ? : +const CodeEditorInformationWrapper = (props: CodeEditorStatusBarProps) => const CodeEditorContainerWrapper = ({ + children, + flexExpand, + // eslint-disable-next-line @typescript-eslint/no-unused-vars overflowHidden, - ...props }: { children: React.ReactNode flexExpand?: boolean + /** @deprecated this prop does not have any effect on codeEditor */ overflowHidden?: boolean -}) => - isCodeMirrorEnabled() ? ( - - ) : ( - - ) +}) => {children} -CodeEditorWrapper.LanguageChanger = CodeEditorLanguageChangerWrapper -CodeEditorWrapper.ThemeChanger = CodeEditorThemeChangerWrapper -CodeEditorWrapper.ValidationError = CodeEditorValidationErrorWrapper CodeEditorWrapper.Clipboard = CodeEditorClipboardWrapper CodeEditorWrapper.Header = CodeEditorHeaderWrapper CodeEditorWrapper.Warning = CodeEditorWarningWrapper diff --git a/src/Shared/Components/CodeEditorWrapper/index.ts b/src/Shared/Components/CodeEditorWrapper/index.ts index 0a036a17c..55dd23db1 100644 --- a/src/Shared/Components/CodeEditorWrapper/index.ts +++ b/src/Shared/Components/CodeEditorWrapper/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { CodeEditorWrapper as CodeEditor, isCodeMirrorEnabled } from './CodeEditorWrapper' +export { CodeEditorWrapper as CodeEditor } from './CodeEditorWrapper' diff --git a/src/Shared/Components/CodeEditorWrapper/types.ts b/src/Shared/Components/CodeEditorWrapper/types.ts index b69233712..a01a5a3c7 100644 --- a/src/Shared/Components/CodeEditorWrapper/types.ts +++ b/src/Shared/Components/CodeEditorWrapper/types.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { CodeEditorInterface } from '@Common/CodeEditor' import { CodeEditorProps } from '@Common/CodeMirror' export type CodeEditorWrapperProps = Pick< @@ -31,19 +30,12 @@ export type CodeEditorWrapperProps = Pick< | 'children' > & { diffView?: DiffView - codeEditorProps: Omit< - CodeEditorInterface, - | 'mode' - | 'tabSize' - | 'readOnly' - | 'placeholder' - | 'noParsing' - | 'loading' - | 'customLoader' - | 'cleanData' - | 'disableSearch' - | 'children' - > + /** + * @deprecated + * Monaco editor has been removed. \ + * This prop is no longer required and will be removed in future releases. + */ + codeEditorProps?: any codeMirrorProps: Omit< CodeEditorProps, | 'mode' diff --git a/src/index.ts b/src/index.ts index f582c59a3..62583371b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -87,11 +87,6 @@ export interface customEnv { FEATURE_DEFAULT_MERGE_STRATEGY?: OverrideMergeStrategyType FEATURE_DEFAULT_LANDING_RB_ENABLE?: boolean FEATURE_ACTION_AUDIOS_ENABLE?: boolean - /** - * If true, the code-editor will use codemirror engine - * @default false - */ - FEATURE_CODE_MIRROR_ENABLE?: boolean // ================== Feature flags for the enterprise release ================== /** * If true, only pipelines to which the user has access will be shown across the application diff --git a/vite.config.ts b/vite.config.ts index 232f92d82..e62fa6155 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -64,13 +64,6 @@ export default defineConfig({ assetFileNames: 'assets/[name][extname]', entryFileNames: '[name].js', manualChunks(id: string) { - if ( - id.includes('/node_modules/monaco-editor') || - id.includes('/node_modules/react-monaco-editor') - ) { - return '@monaco-editor' - } - if (id.includes('/node_modules/react-dates')) { return '@react-dates' } @@ -95,7 +88,7 @@ export default defineConfig({ return '@vendor' } - if (id.includes('src/Common/CodeEditor')) { + if (id.includes('codemirror') || id.includes('src/Common/CodeMirror')) { return '@code-editor' } From 673302fc1d90591fc953d46f0732d86c31995aed Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Thu, 24 Apr 2025 13:30:37 +0530 Subject: [PATCH 38/80] chore(version): bump to 1.11.0-beta-9 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d1d6ac95..7670fcef6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-beta-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-beta-9", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index e982413c1..0f42d859e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-beta-9", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From afd72f8b87b0b8a720f9b3a14c111b69e0c2d8e5 Mon Sep 17 00:00:00 2001 From: shivani170 Date: Thu, 24 Apr 2025 14:05:49 +0530 Subject: [PATCH 39/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9231170a1..35ca05a26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-9", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index a78037dd4..52c8ee5d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-8", + "version": "1.11.0-pre-9", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 0c33ac3528fdd451660ed2ae676a654ec88c7e47 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Thu, 24 Apr 2025 15:11:20 +0530 Subject: [PATCH 40/80] refactor: Artifacts, UserIdentifier - code optimization, remove redundancy --- .../Components/CICDHistory/Artifacts.tsx | 12 +-- .../UserIdentifier/UserIdentifier.tsx | 75 ++++++++++--------- 2 files changed, 46 insertions(+), 41 deletions(-) diff --git a/src/Shared/Components/CICDHistory/Artifacts.tsx b/src/Shared/Components/CICDHistory/Artifacts.tsx index b35d1df90..9e4f2beda 100644 --- a/src/Shared/Components/CICDHistory/Artifacts.tsx +++ b/src/Shared/Components/CICDHistory/Artifacts.tsx @@ -69,12 +69,12 @@ export const CIListItem = ({ targetPlatforms, isDeploymentWithoutApproval, }: CIListItemType) => { - const headerMetaDataPresent = - !!getIsApprovalPolicyConfigured(userApprovalMetadata?.approvalConfigData) || - !!appliedFilters?.length || - !!promotionApprovalMetadata?.promotedFromType - - const showCIListHeader = (headerMetaDataPresent || isDeploymentWithoutApproval) && !!renderCIListHeader + const showCIListHeader = + !!renderCIListHeader && + (!!getIsApprovalPolicyConfigured(userApprovalMetadata?.approvalConfigData) || + !!appliedFilters?.length || + !!promotionApprovalMetadata?.promotedFromType || + isDeploymentWithoutApproval) return ( <> diff --git a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx index b8050c72e..70cd6663c 100644 --- a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx +++ b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx @@ -25,46 +25,51 @@ export const UserIdentifier = ({ // HOOKS const { email: currentUserEmail } = useUserEmail() + if (!email) { + return null + } + // CONSTANTS const isCurrentUser = email === currentUserEmail + const isApiToken = email.startsWith(API_TOKEN_PREFIX) + + const renderIcon = () => { + if (isApiToken) { + return + } + + return isUserGroup ? ( + + ) : ( + getAlphabetIcon(email, 'dc__no-shrink m-0-imp') + ) + } + + const renderText = () => { + if (isCurrentUser) { + return 'You' + } + + if (isApiToken) { + return email.split(':')?.[1] || '-' + } + + return email + } return (
- {email.startsWith(API_TOKEN_PREFIX) ? ( - - -
- - - {isCurrentUser ? 'You' : email.split(':')?.[1] || '-'} - - - {children} -
-
- ) : ( - - {isUserGroup ? ( - - ) : ( - getAlphabetIcon(email, 'dc__no-shrink m-0-imp') - )} -
- - {isCurrentUser ? 'You' : email} - - {children} -
-
- )} + + {renderIcon()} +
+ + {renderText()} + + {children} +
+
) } From 2aaaa2bee1618e110aae2baeecd8b7b53b39eaad Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Thu, 24 Apr 2025 16:29:20 +0530 Subject: [PATCH 41/80] feat: filter apps if id isn't recieved --- package-lock.json | 4 ++-- package.json | 2 +- src/Common/Common.service.ts | 12 +++++++++++- src/Common/Types.ts | 2 +- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0cfa0c14f..0792e2708 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-2", + "version": "1.11.0-pre-9-beta-3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-2", + "version": "1.11.0-pre-9-beta-3", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 58c4e9312..e0dfeb86b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-2", + "version": "1.11.0-pre-9-beta-3", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index f804a2ccb..e79f57c3e 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -51,10 +51,12 @@ import { UserRole, EnvAppsMetaDTO, GetAppsInfoForEnvProps, + AppMeta, } from './Types' import { ApiResourceType, STAGE_MAP } from '../Pages' import { RefVariableType, VariableTypeFormat } from './CIPipeline.Types' import { get, post } from './API' +import { StatusType } from '@Shared/Components' export const getTeamListMin = (): Promise => { // ignore active field @@ -526,6 +528,14 @@ export const getAppsInfoForEnv = async ({ envId, appIds }: GetAppsInfoForEnvProp return { appCount: response.result?.appCount ?? 0, - apps: response.result?.apps ?? [], + apps: (response.result?.apps ?? []).reduce((agg, {appId, appName, appStatus}) => { + if (!appId) { + return agg + } + agg.push({ + appId, appName: appName || '', + appStatus: appStatus || StatusType.UNKNOWN, + }) + }, []), } } \ No newline at end of file diff --git a/src/Common/Types.ts b/src/Common/Types.ts index 3901e1193..e0dae3ba1 100644 --- a/src/Common/Types.ts +++ b/src/Common/Types.ts @@ -1116,7 +1116,7 @@ export interface GetAppsInfoForEnvProps { appIds?: number[] } -interface AppMeta { +export interface AppMeta { appId: number appStatus: StatusType appName: string From 9e4cb636355ff1dd59d576bdbe748b3624feba9b Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Thu, 24 Apr 2025 16:36:45 +0530 Subject: [PATCH 42/80] chore: update rocket icon --- src/Assets/Icon/ic-nav-rocket.svg | 19 ------------------- src/Assets/IconV2/ic-rocket-launch.svg | 3 +++ .../AnimatedDeployButton.tsx | 4 ++-- src/Shared/Components/Icon/Icon.tsx | 2 ++ .../ImageCard/ArtifactInfo/ArtifactInfo.tsx | 6 +++--- 5 files changed, 10 insertions(+), 24 deletions(-) delete mode 100644 src/Assets/Icon/ic-nav-rocket.svg create mode 100644 src/Assets/IconV2/ic-rocket-launch.svg diff --git a/src/Assets/Icon/ic-nav-rocket.svg b/src/Assets/Icon/ic-nav-rocket.svg deleted file mode 100644 index 5ee6b84c4..000000000 --- a/src/Assets/Icon/ic-nav-rocket.svg +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/src/Assets/IconV2/ic-rocket-launch.svg b/src/Assets/IconV2/ic-rocket-launch.svg new file mode 100644 index 000000000..652cd1197 --- /dev/null +++ b/src/Assets/IconV2/ic-rocket-launch.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx index f8dea6c50..7294f625e 100644 --- a/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx +++ b/src/Shared/Components/AnimatedDeployButton/AnimatedDeployButton.tsx @@ -17,11 +17,11 @@ import { SyntheticEvent, useEffect, useRef, useState } from 'react' import { motion } from 'framer-motion' -import { ReactComponent as ICDeploy } from '@Icons/ic-nav-rocket.svg' import DeployAudio from '@Sounds/DeployAudio.mp3' import { ComponentSizeType } from '@Shared/constants' import { Button } from '../Button' +import { Icon } from '../Icon' import { AnimatedDeployButtonProps } from './types' import './animatedDeployButton.scss' @@ -83,7 +83,7 @@ const AnimatedDeployButton = ({ isVirtualEnvironment, onButtonClick }: AnimatedD : {} } > - + } size={ComponentSizeType.large} diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index d7c1afd8f..0cef854e7 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -92,6 +92,7 @@ import { ReactComponent as ICPaperPlaneColor } from '@IconsV2/ic-paper-plane-col import { ReactComponent as ICPencil } from '@IconsV2/ic-pencil.svg' import { ReactComponent as ICQuay } from '@IconsV2/ic-quay.svg' import { ReactComponent as ICQuote } from '@IconsV2/ic-quote.svg' +import { ReactComponent as ICRocketLaunch } from '@IconsV2/ic-rocket-launch.svg' import { ReactComponent as ICShieldCheck } from '@IconsV2/ic-shield-check.svg' import { ReactComponent as ICSlidersVertical } from '@IconsV2/ic-sliders-vertical.svg' import { ReactComponent as ICSortAscending } from '@IconsV2/ic-sort-ascending.svg' @@ -209,6 +210,7 @@ export const iconMap = { 'ic-pencil': ICPencil, 'ic-quay': ICQuay, 'ic-quote': ICQuote, + 'ic-rocket-launch': ICRocketLaunch, 'ic-shield-check': ICShieldCheck, 'ic-sliders-vertical': ICSlidersVertical, 'ic-sort-ascending': ICSortAscending, diff --git a/src/Shared/Components/ImageCard/ArtifactInfo/ArtifactInfo.tsx b/src/Shared/Components/ImageCard/ArtifactInfo/ArtifactInfo.tsx index 35129d8c2..b51de46c8 100644 --- a/src/Shared/Components/ImageCard/ArtifactInfo/ArtifactInfo.tsx +++ b/src/Shared/Components/ImageCard/ArtifactInfo/ArtifactInfo.tsx @@ -16,11 +16,11 @@ import Tippy from '@tippyjs/react' +import { ReactComponent as ICBot } from '@Icons/ic-bot.svg' import { Tooltip } from '@Common/Tooltip' +import { Icon } from '@Shared/Components/Icon' import { RegistryIcon } from '@Shared/Components/RegistryIcon' -import { ReactComponent as ICBot } from '../../../../Assets/Icon/ic-bot.svg' -import { ReactComponent as DeployIcon } from '../../../../Assets/Icon/ic-nav-rocket.svg' import { ConditionalWrap, getRandomColor } from '../../../../Common/Helper' import { DefaultUserKey } from '../../../types' import { ArtifactInfoProps } from '../types' @@ -62,7 +62,7 @@ const ArtifactInfo = ({ return (
- + {deployedTime}
) From 020c41465dba689f95ab0a0372729febc862a206 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Thu, 24 Apr 2025 17:02:41 +0530 Subject: [PATCH 43/80] chore: formatting --- src/Common/Common.service.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index e79f57c3e..83703a9cc 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -22,11 +22,7 @@ import { sanitizeUserApprovalList, stringComparatorBySortOrder, } from '@Shared/Helpers' -import { - PolicyBlockInfo, - RuntimeParamsAPIResponseType, - RuntimePluginVariables, -} from '@Shared/types' +import { PolicyBlockInfo, RuntimeParamsAPIResponseType, RuntimePluginVariables } from '@Shared/types' import { GitProviderType, ROUTES } from './Constants' import { getUrlWithSearchParams, sortCallback } from './Helper' import { @@ -268,7 +264,7 @@ export const parseRuntimeParams = (response: RuntimeParamsAPIResponseType): Runt const runtimeParams = (response?.runtimePluginVariables ?? []).map((variable) => ({ ...variable, defaultValue: variable.value, - stepVariableId: variable.stepVariableId || Math.floor(new Date().valueOf() * Math.random()) + stepVariableId: variable.stepVariableId || Math.floor(new Date().valueOf() * Math.random()), })) runtimeParams.push(...envVariables) @@ -528,14 +524,15 @@ export const getAppsInfoForEnv = async ({ envId, appIds }: GetAppsInfoForEnvProp return { appCount: response.result?.appCount ?? 0, - apps: (response.result?.apps ?? []).reduce((agg, {appId, appName, appStatus}) => { + apps: (response.result?.apps ?? []).reduce((agg, { appId, appName, appStatus }) => { if (!appId) { return agg } agg.push({ - appId, appName: appName || '', + appId, + appName: appName || '', appStatus: appStatus || StatusType.UNKNOWN, }) }, []), } -} \ No newline at end of file +} From 2090a197c6af74060c076028bd9107710ee69095 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Fri, 25 Apr 2025 11:49:29 +0530 Subject: [PATCH 44/80] chore(version): bump to 1.11.0-beta-10 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 35ca05a26..3d84bc063 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9", + "version": "1.11.0-beta-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9", + "version": "1.11.0-beta-10", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 52c8ee5d2..7c462272d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9", + "version": "1.11.0-beta-10", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 98335a84f7649ee2151a996a5684a1bef21ef374 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 25 Apr 2025 14:09:11 +0530 Subject: [PATCH 45/80] feat: add animation in tab group tabs --- .../TabGroup/TabGroup.component.tsx | 78 ++++++++++++++----- .../Components/TabGroup/TabGroup.helpers.tsx | 19 +++++ src/Shared/Components/TabGroup/TabGroup.scss | 18 ----- 3 files changed, 76 insertions(+), 39 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 801a4d806..fd49c9b06 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -14,17 +14,33 @@ * limitations under the License. */ -import { Link, NavLink } from 'react-router-dom' +import { Link, NavLink, useRouteMatch } from 'react-router-dom' +import { motion } from 'framer-motion' import { Tooltip } from '@Common/Tooltip' import { ComponentSizeType } from '@Shared/constants' -import { getTabBadge, getTabDescription, getTabIcon, getTabIndicator } from './TabGroup.helpers' +import { getPathnameToMatch, getTabBadge, getTabDescription, getTabIcon, getTabIndicator } from './TabGroup.helpers' import { TabGroupProps, TabProps } from './TabGroup.types' import { getClassNameBySizeMap, tabGroupClassMap } from './TabGroup.utils' import './TabGroup.scss' +const MotionLayoutUnderline = ({ + layoutId, + alignActiveBorderWithContainer, +}: { + layoutId: string + alignActiveBorderWithContainer: boolean +}) => ( + +) + const Tab = ({ label, props, @@ -42,7 +58,13 @@ const Tab = ({ description, shouldWrapTooltip, tooltipProps, -}: TabProps & Pick) => { + uniqueGroupId, +}: TabProps & + Pick & { uniqueGroupId: string }) => { + const { path } = useRouteMatch() + const pathToMatch = tabType === 'navLink' || tabType === 'link' ? getPathnameToMatch(props.to, path) : '' + const match = useRouteMatch(pathToMatch) + const { tabClassName, iconClassName, badgeClassName } = getClassNameBySizeMap({ hideTopPadding, alignActiveBorderWithContainer, @@ -119,11 +141,19 @@ const Tab = ({ } } + const isTabActive = tabType === 'button' ? active : !!match + const renderTabContainer = () => (
  • {getTabComponent()} + {isTabActive && ( + + )}
  • ) @@ -140,20 +170,26 @@ export const TabGroup = ({ rightComponent, alignActiveBorderWithContainer, hideTopPadding, -}: TabGroupProps) => ( -
    -
      - {tabs.map(({ id, ...resProps }) => ( - - ))} -
    - {rightComponent || null} -
    -) +}: TabGroupProps) => { + // Unique layoutId for motion.div to handle multiple tab groups on same page + const uniqueGroupId = tabs.map((tab) => tab.label).join('-') + + return ( +
    +
      + {tabs.map(({ id, ...resProps }) => ( + + ))} +
    + {rightComponent || null} +
    + ) +} diff --git a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx index 3d515b910..3b50db019 100644 --- a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx @@ -14,6 +14,8 @@ * limitations under the License. */ +import { LinkProps, NavLinkProps } from 'react-router-dom' + import { ReactComponent as ICErrorExclamation } from '@Icons/ic-error-exclamation.svg' import { ReactComponent as ICWarning } from '@Icons/ic-warning.svg' @@ -65,3 +67,20 @@ export const getTabDescription = (description: TabProps['description']) => : description} ) + +const replaceTrailingSlash = (pathname: string) => pathname.replace(/\/+$/, '') + +export const getPathnameToMatch = (to: NavLinkProps['to'] | LinkProps['to'], currentPathname: string): string => { + // Handling both absolute and relative paths + if (typeof to === 'string') { + return to.startsWith('/') ? to : `${replaceTrailingSlash(currentPathname)}/${to}` + } + if (typeof to === 'function') { + return '' + } + if (to && typeof to === 'object' && 'pathname' in to) { + const pathname = to.pathname || '' + return pathname.startsWith('/') ? pathname : `${replaceTrailingSlash(currentPathname)}/${pathname}` + } + return '' +} diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index c5a352898..909ddd12b 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -45,10 +45,6 @@ border-top-right-radius: 2px; } - &--align-active-border::after { - bottom: -1px; - } - &:hover:not(.tab-group__tab--block):not(.dc__disabled) { color: var(--B500); @include svg-styles(var(--B500)); @@ -58,14 +54,6 @@ } } - &--active { - @include svg-styles(var(--B500)); - - &::after { - background-color: var(--B500); - } - } - &__badge { border-radius: 10px; min-width: 20px; @@ -104,11 +92,5 @@ color: var(--B500); } } - - &:has(.active) { - &::after { - background-color: var(--B500); - } - } } } From 3f1ebc01c53407d68efaec327328ab3c3ff0a547 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 25 Apr 2025 15:14:16 +0530 Subject: [PATCH 46/80] feat: add type for unique tab group id prop --- src/Shared/Components/TabGroup/TabGroup.component.tsx | 5 +++-- src/Shared/Components/TabGroup/TabGroup.types.ts | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index fd49c9b06..8073567cb 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -21,7 +21,7 @@ import { Tooltip } from '@Common/Tooltip' import { ComponentSizeType } from '@Shared/constants' import { getPathnameToMatch, getTabBadge, getTabDescription, getTabIcon, getTabIndicator } from './TabGroup.helpers' -import { TabGroupProps, TabProps } from './TabGroup.types' +import { AdditionalTabProps, TabGroupProps, TabProps } from './TabGroup.types' import { getClassNameBySizeMap, tabGroupClassMap } from './TabGroup.utils' import './TabGroup.scss' @@ -60,7 +60,8 @@ const Tab = ({ tooltipProps, uniqueGroupId, }: TabProps & - Pick & { uniqueGroupId: string }) => { + Pick & + AdditionalTabProps) => { const { path } = useRouteMatch() const pathToMatch = tabType === 'navLink' || tabType === 'link' ? getPathnameToMatch(props.to, path) : '' const match = useRouteMatch(pathToMatch) diff --git a/src/Shared/Components/TabGroup/TabGroup.types.ts b/src/Shared/Components/TabGroup/TabGroup.types.ts index 0ddb160f9..a1c81b693 100644 --- a/src/Shared/Components/TabGroup/TabGroup.types.ts +++ b/src/Shared/Components/TabGroup/TabGroup.types.ts @@ -163,3 +163,7 @@ export interface TabGroupProps { */ hideTopPadding?: boolean } + +export type AdditionalTabProps = { + uniqueGroupId: string +} From 1999c44ecfbc9dc53f18ae3b23ce03eab7660955 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 25 Apr 2025 16:10:23 +0530 Subject: [PATCH 47/80] chore: remove extra css --- src/Shared/Components/TabGroup/TabGroup.component.tsx | 4 ++-- src/Shared/Components/TabGroup/TabGroup.scss | 8 +------- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 8073567cb..0d7ee6d33 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -36,8 +36,8 @@ const MotionLayoutUnderline = ({ ) diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index 909ddd12b..89ed04960 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -33,14 +33,8 @@ @include svg-styles(var(--N700)); - &::after { - content: ''; - position: absolute; - bottom: 0; - left: 0; - width: 100%; + .underline { height: 2px; - background-color: transparent; border-top-left-radius: 2px; border-top-right-radius: 2px; } From 76082f8edc17a2c751032b3b23095964ddd75b18 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 25 Apr 2025 16:18:46 +0530 Subject: [PATCH 48/80] fix: return agg --- package-lock.json | 4 ++-- package.json | 2 +- src/Common/Common.service.ts | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0792e2708..033b8c76c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-3", + "version": "1.11.0-pre-9-beta-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-3", + "version": "1.11.0-pre-9-beta-4", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index e0dfeb86b..6d70dc38d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.0-pre-9-beta-3", + "version": "1.11.0-pre-9-beta-4", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index 83703a9cc..c7d1a3f13 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -533,6 +533,7 @@ export const getAppsInfoForEnv = async ({ envId, appIds }: GetAppsInfoForEnvProp appName: appName || '', appStatus: appStatus || StatusType.UNKNOWN, }) + return agg }, []), } } From 26732d351e1f3a9658e0c9953154c761ed24b30e Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Fri, 25 Apr 2025 16:37:07 +0530 Subject: [PATCH 49/80] chore(version): bump to 1.12.0-pre-0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ec603ebe..40ebd223c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0", + "version": "1.12.0-pre-0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0", + "version": "1.12.0-pre-0", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 7a0801063..6fe84e4cf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0", + "version": "1.12.0-pre-0", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From aac6961f2a71ede2d0fe7f6e9dcbc1ba9701b5e0 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 28 Apr 2025 14:09:41 +0530 Subject: [PATCH 50/80] feat: remove prop for align active border with container, use default true --- .../TabGroup/TabGroup.component.tsx | 41 ++++++------------- .../Components/TabGroup/TabGroup.helpers.tsx | 12 ++---- src/Shared/Components/TabGroup/TabGroup.scss | 4 ++ .../Components/TabGroup/TabGroup.types.ts | 5 --- .../Components/TabGroup/TabGroup.utils.ts | 10 ++--- 5 files changed, 24 insertions(+), 48 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 0d7ee6d33..d7bcba5f8 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -14,6 +14,7 @@ * limitations under the License. */ +import { useMemo } from 'react' import { Link, NavLink, useRouteMatch } from 'react-router-dom' import { motion } from 'framer-motion' @@ -26,19 +27,8 @@ import { getClassNameBySizeMap, tabGroupClassMap } from './TabGroup.utils' import './TabGroup.scss' -const MotionLayoutUnderline = ({ - layoutId, - alignActiveBorderWithContainer, -}: { - layoutId: string - alignActiveBorderWithContainer: boolean -}) => ( - +const MotionLayoutUnderline = ({ layoutId }: { layoutId: string }) => ( + ) const Tab = ({ @@ -49,7 +39,6 @@ const Tab = ({ icon, size, badge = null, - alignActiveBorderWithContainer, hideTopPadding, showIndicator, showError, @@ -59,16 +48,18 @@ const Tab = ({ shouldWrapTooltip, tooltipProps, uniqueGroupId, -}: TabProps & - Pick & - AdditionalTabProps) => { +}: TabProps & Pick & AdditionalTabProps) => { const { path } = useRouteMatch() const pathToMatch = tabType === 'navLink' || tabType === 'link' ? getPathnameToMatch(props.to, path) : '' + + // using match to define if tab is active as useRouteMatch return an object if path is matched otherwise return null/undefined const match = useRouteMatch(pathToMatch) + const isTabActive = tabType === 'button' ? active : !!match + const { tabClassName, iconClassName, badgeClassName } = getClassNameBySizeMap({ hideTopPadding, - alignActiveBorderWithContainer, + isTabActive, })[size] const onClickHandler = ( @@ -142,19 +133,12 @@ const Tab = ({ } } - const isTabActive = tabType === 'button' ? active : !!match - const renderTabContainer = () => (
  • {getTabComponent()} - {isTabActive && ( - - )} + {isTabActive && }
  • ) @@ -169,11 +153,11 @@ export const TabGroup = ({ tabs = [], size = ComponentSizeType.large, rightComponent, - alignActiveBorderWithContainer, hideTopPadding, }: TabGroupProps) => { // Unique layoutId for motion.div to handle multiple tab groups on same page - const uniqueGroupId = tabs.map((tab) => tab.label).join('-') + // Using tab labels so that id remains same on re mount as well + const uniqueGroupId = useMemo(() => tabs.map((tab) => tab.label).join('-'), []) return (
    @@ -183,7 +167,6 @@ export const TabGroup = ({ key={id} id={id} size={size} - alignActiveBorderWithContainer={alignActiveBorderWithContainer} hideTopPadding={hideTopPadding} uniqueGroupId={uniqueGroupId} {...resProps} diff --git a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx index 3b50db019..9aec1c1da 100644 --- a/src/Shared/Components/TabGroup/TabGroup.helpers.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.helpers.tsx @@ -71,15 +71,9 @@ export const getTabDescription = (description: TabProps['description']) => const replaceTrailingSlash = (pathname: string) => pathname.replace(/\/+$/, '') export const getPathnameToMatch = (to: NavLinkProps['to'] | LinkProps['to'], currentPathname: string): string => { - // Handling both absolute and relative paths - if (typeof to === 'string') { - return to.startsWith('/') ? to : `${replaceTrailingSlash(currentPathname)}/${to}` - } - if (typeof to === 'function') { - return '' - } - if (to && typeof to === 'object' && 'pathname' in to) { - const pathname = to.pathname || '' + if (typeof to === 'string' || (to && typeof to === 'object' && 'pathname' in to)) { + const pathname = typeof to === 'string' ? to : to.pathname || '' + // handling absolute and relative paths return pathname.startsWith('/') ? pathname : `${replaceTrailingSlash(currentPathname)}/${pathname}` } return '' diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index 89ed04960..2ddaaf6b9 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -39,6 +39,10 @@ border-top-right-radius: 2px; } + &--active { + @include svg-styles(var(--B500)); + } + &:hover:not(.tab-group__tab--block):not(.dc__disabled) { color: var(--B500); @include svg-styles(var(--B500)); diff --git a/src/Shared/Components/TabGroup/TabGroup.types.ts b/src/Shared/Components/TabGroup/TabGroup.types.ts index a1c81b693..022b83254 100644 --- a/src/Shared/Components/TabGroup/TabGroup.types.ts +++ b/src/Shared/Components/TabGroup/TabGroup.types.ts @@ -152,11 +152,6 @@ export interface TabGroupProps { * Optional component to be rendered on the right side of the tab list. */ rightComponent?: React.ReactElement - /** - * Set to `true` to align the active tab's border with the bottom border of the parent container. - * @default false - */ - alignActiveBorderWithContainer?: boolean /** * Determines if the top padding of the tab group should be hidden. * @default false diff --git a/src/Shared/Components/TabGroup/TabGroup.utils.ts b/src/Shared/Components/TabGroup/TabGroup.utils.ts index e2f73bb93..5bc8aeb6f 100644 --- a/src/Shared/Components/TabGroup/TabGroup.utils.ts +++ b/src/Shared/Components/TabGroup/TabGroup.utils.ts @@ -21,8 +21,8 @@ import { TabGroupProps } from './TabGroup.types' export const getClassNameBySizeMap = ({ hideTopPadding, - alignActiveBorderWithContainer, -}: Pick): Record< + isTabActive, +}: Pick & { isTabActive: boolean }): Record< TabGroupProps['size'], { tabClassName: string @@ -31,17 +31,17 @@ export const getClassNameBySizeMap = ({ } > => ({ [ComponentSizeType.medium]: { - tabClassName: `fs-12 ${!hideTopPadding ? 'pt-6' : ''} ${alignActiveBorderWithContainer ? 'pb-5' : 'pb-6'}`, + tabClassName: `fs-12 ${!hideTopPadding ? 'pt-6' : ''} ${isTabActive ? 'pb-3' : 'pb-5'}`, iconClassName: 'icon-dim-14', badgeClassName: 'fs-11 lh-18 tab-group__tab__badge--medium', }, [ComponentSizeType.large]: { - tabClassName: `fs-13 ${!hideTopPadding ? 'pt-8' : ''} ${alignActiveBorderWithContainer ? 'pb-7' : 'pb-8'}`, + tabClassName: `fs-13 ${!hideTopPadding ? 'pt-8' : ''} ${isTabActive ? 'pb-5' : 'pb-7'}`, iconClassName: 'icon-dim-16', badgeClassName: 'fs-12 lh-20', }, [ComponentSizeType.xl]: { - tabClassName: `min-w-200 fs-13 ${!hideTopPadding ? 'pt-10' : ''} ${alignActiveBorderWithContainer ? 'pb-9' : 'pb-10'}`, + tabClassName: `min-w-200 fs-13 ${!hideTopPadding ? 'pt-10' : ''} ${isTabActive ? 'pb-7' : 'pb-9'}`, iconClassName: 'icon-dim-16', badgeClassName: 'fs-12 lh-20', }, From ffc73b7e3d60bde51667fa85a02255f40b948b0a Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 28 Apr 2025 15:32:30 +0530 Subject: [PATCH 51/80] chore(version): bump to 1.12.0-beta-2 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 40ebd223c..0304d5b37 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-beta-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-beta-2", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 6fe84e4cf..37ff28408 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-beta-2", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 6f1293b41bd23ffa4e6a7fce934e2eeb44bc928d Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 28 Apr 2025 16:15:05 +0530 Subject: [PATCH 52/80] feat: add about devtron dialog for oss --- .../AboutDevtron/AboutDevtronBody.tsx | 73 +++++++++++++++++++ .../AboutDevtron/AboutDevtronDialog.tsx | 25 +++++++ src/Shared/Components/AboutDevtron/index.tsx | 2 + src/Shared/Components/Header/HelpNav.tsx | 31 ++++---- src/Shared/Components/index.ts | 1 + src/Shared/constants.tsx | 2 + 6 files changed, 118 insertions(+), 16 deletions(-) create mode 100644 src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx create mode 100644 src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx create mode 100644 src/Shared/Components/AboutDevtron/index.tsx diff --git a/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx b/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx new file mode 100644 index 000000000..35f2da5cd --- /dev/null +++ b/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx @@ -0,0 +1,73 @@ +import ReactGA from 'react-ga4' + +import DevtronCopyright from '@Common/DevtronCopyright' +import { EULA_LINK, PRIVACY_POLICY_LINK, TERMS_OF_USE_LINK } from '@Shared/constants' +import { useMainContext } from '@Shared/Providers' + +import { Button, ButtonComponentType, ButtonStyleType, ButtonVariantType } from '../Button' +import { InstallationType } from '../Header/types' +import { Icon } from '../Icon' + +const AboutDevtronBody = () => { + const { currentServerInfo } = useMainContext() + + const currentVersion = currentServerInfo?.serverInfo?.currentVersion + const isEnterprise = currentServerInfo?.serverInfo?.installationType === InstallationType.ENTERPRISE + + const handleEULAClick = () => { + ReactGA.event({ + category: 'about-devtron', + action: 'ABOUT_DEVTRON_LICENSE_AGREEMENT_CLICKED', + }) + } + + return ( +
    +
    + +
    +
    +

    Devtron

    +

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    +
    + +
    +
    +
    + ) +} + +export default AboutDevtronBody diff --git a/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx b/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx new file mode 100644 index 000000000..11ff26ed1 --- /dev/null +++ b/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx @@ -0,0 +1,25 @@ +import { ComponentSizeType } from '@Shared/constants' + +import { Backdrop } from '../Backdrop' +import { Button } from '../Button' +import AboutDevtronBody from './AboutDevtronBody' + +const AboutDevtronDialog = ({ handleCloseLicenseInfoDialog }: { handleCloseLicenseInfoDialog }) => ( + +
    +
    + +
    +
    +
    +
    +
    +) + +export default AboutDevtronDialog diff --git a/src/Shared/Components/AboutDevtron/index.tsx b/src/Shared/Components/AboutDevtron/index.tsx new file mode 100644 index 000000000..70550e75a --- /dev/null +++ b/src/Shared/Components/AboutDevtron/index.tsx @@ -0,0 +1,2 @@ +export { default as AboutDevtronBody } from './AboutDevtronBody' +export { default as AboutDevtronDialog } from './AboutDevtronDialog' diff --git a/src/Shared/Components/Header/HelpNav.tsx b/src/Shared/Components/Header/HelpNav.tsx index 1c6cc2251..0916f53f9 100644 --- a/src/Shared/Components/Header/HelpNav.tsx +++ b/src/Shared/Components/Header/HelpNav.tsx @@ -76,7 +76,7 @@ const HelpNav = ({ onClickHelpOptions(option) } - const handleOpenLicenseDialog = () => { + const handleOpenAboutDevtron = () => { ReactGA.event({ category: 'help-nav__about-devtron', action: 'ABOUT_DEVTRON_CLICKED', @@ -100,23 +100,22 @@ const HelpNav = ({
    {option.name}
    - {/* licenseData is only set when showLicenseData is received true */} - {isEnterprise && index === 1 && ( + {index === 1 && ( <> - {licenseData && ( - + + {isEnterprise && ( +
    + Enterprise Support +
    )} -
    - Enterprise Support -
    )} diff --git a/src/Shared/Components/index.ts b/src/Shared/Components/index.ts index 14503779c..75d7f961e 100644 --- a/src/Shared/Components/index.ts +++ b/src/Shared/Components/index.ts @@ -14,6 +14,7 @@ * limitations under the License. */ +export * from './AboutDevtron' export * from './ActionMenu' export * from './ActivityIndicator' export * from './AnimatedDeployButton' diff --git a/src/Shared/constants.tsx b/src/Shared/constants.tsx index ae2c2d9be..d53848f04 100644 --- a/src/Shared/constants.tsx +++ b/src/Shared/constants.tsx @@ -538,6 +538,8 @@ export const DC_DELETE_SUBTITLES = { export const EULA_LINK = 'https://devtron.ai/end-user-license-agreement-eula' export const CONTACT_SUPPORT_LINK = 'https://devtron.ai/enterprise-support' +export const PRIVACY_POLICY_LINK = 'https://devtron.ai/privacy-policy' +export const TERMS_OF_USE_LINK = 'https://devtron.ai/terms-of-use' export const enum DeleteComponentsName { Cluster = 'cluster', From 593b7fe8727a9728782d551eb1aba526b6f8a6a8 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 28 Apr 2025 16:26:30 +0530 Subject: [PATCH 53/80] chore(version): bump to 1.12.0-pre-1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 925219602..999fd524b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-pre-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-pre-1", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index f587eddfc..21faa5d94 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-0", + "version": "1.12.0-pre-1", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 11a2ec58dc35d3eb4a866720312365d7bfda2d72 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 28 Apr 2025 16:33:16 +0530 Subject: [PATCH 54/80] chore: update dialog layout --- .../AboutDevtron/AboutDevtronBody.tsx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx b/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx index 35f2da5cd..21efee1ee 100644 --- a/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx +++ b/src/Shared/Components/AboutDevtron/AboutDevtronBody.tsx @@ -22,16 +22,18 @@ const AboutDevtronBody = () => { } return ( -
    -
    - +
    +
    +
    + +
    +
    +

    Devtron

    +

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    +
    +
    -
    -

    Devtron

    -

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    -
    - -
    +

    Devtron

    -

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    + {isVersionSame && ( +

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    + )}
    diff --git a/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx b/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx index 11ff26ed1..1b48138e6 100644 --- a/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx +++ b/src/Shared/Components/AboutDevtron/AboutDevtronDialog.tsx @@ -4,11 +4,17 @@ import { Backdrop } from '../Backdrop' import { Button } from '../Button' import AboutDevtronBody from './AboutDevtronBody' -const AboutDevtronDialog = ({ handleCloseLicenseInfoDialog }: { handleCloseLicenseInfoDialog }) => ( +const AboutDevtronDialog = ({ + handleCloseLicenseInfoDialog, + isFELibAvailable, +}: { + handleCloseLicenseInfoDialog: () => void + isFELibAvailable: boolean +}) => (
    - +

    Devtron

    - {isVersionSame && ( + {isVersionCompatible && (

    {`${isEnterprise ? 'Enterprise' : 'OSS'} Version${currentVersion ? `(${currentVersion})` : ''}`}

    )}
    From 5aa499d5acf1301dddcfd9fefea1159d345e7285 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 2 May 2025 10:47:10 +0530 Subject: [PATCH 63/80] feat: add intelligenceConfig in main context --- src/Assets/IconV2/ic-thumb-down.svg | 3 ++ src/Assets/IconV2/ic-thumb-up.svg | 3 ++ src/Common/Types.ts | 58 +++++++++++++---------------- src/Shared/Components/Icon/Icon.tsx | 4 ++ src/Shared/Providers/types.ts | 4 +- src/Shared/types.ts | 7 ++++ 6 files changed, 46 insertions(+), 33 deletions(-) create mode 100644 src/Assets/IconV2/ic-thumb-down.svg create mode 100644 src/Assets/IconV2/ic-thumb-up.svg diff --git a/src/Assets/IconV2/ic-thumb-down.svg b/src/Assets/IconV2/ic-thumb-down.svg new file mode 100644 index 000000000..54ef52337 --- /dev/null +++ b/src/Assets/IconV2/ic-thumb-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Assets/IconV2/ic-thumb-up.svg b/src/Assets/IconV2/ic-thumb-up.svg new file mode 100644 index 000000000..c98369a89 --- /dev/null +++ b/src/Assets/IconV2/ic-thumb-up.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/Common/Types.ts b/src/Common/Types.ts index e0dae3ba1..9f67632bd 100644 --- a/src/Common/Types.ts +++ b/src/Common/Types.ts @@ -231,25 +231,27 @@ interface InfoColourBarTextConfigType { actionButtonConfig?: ButtonProps } -type InfoColourBarMessageProp = { - message: ReactNode - linkText?: ReactNode - redirectLink?: string - linkOnClick?: () => void - linkClass?: string - internalLink?: boolean - - textConfig?: never -} | { - textConfig: InfoColourBarTextConfigType - - message?: never - linkText?: never - redirectLink?: never - linkOnClick?: () => never - linkClass?: never - internalLink?: never -} +type InfoColourBarMessageProp = + | { + message: ReactNode + linkText?: ReactNode + redirectLink?: string + linkOnClick?: () => void + linkClass?: string + internalLink?: boolean + + textConfig?: never + } + | { + textConfig: InfoColourBarTextConfigType + + message?: never + linkText?: never + redirectLink?: never + linkOnClick?: () => never + linkClass?: never + internalLink?: never + } export type InfoColourBarType = InfoColourBarMessageProp & { classname: string @@ -848,7 +850,7 @@ export interface Strategy { default?: boolean } -export interface CDStage extends Partial> { +export interface CDStage extends Partial> { status: string name: string triggerType: 'AUTOMATIC' | 'MANUAL' @@ -860,7 +862,9 @@ export interface CDStageConfigMapSecretNames { secrets: any[] } -export interface PrePostDeployStageType extends MandatoryPluginBaseStateType, Partial> { +export interface PrePostDeployStageType + extends MandatoryPluginBaseStateType, + Partial> { isValid: boolean steps: TaskErrorObj[] triggerType: string @@ -1067,16 +1071,6 @@ export interface EnvironmentHelmResult { export type EnvironmentListHelmResponse = ResponseType -export interface WidgetEventDetails { - message: string - namespace: string - object: string - source: string - count: number - age: string - lastSeen: string -} - export interface GlobalVariableDTO { name: string format: VariableTypeFormat @@ -1125,4 +1119,4 @@ export interface AppMeta { export interface EnvAppsMetaDTO { appCount: number apps: AppMeta[] -} \ No newline at end of file +} diff --git a/src/Shared/Components/Icon/Icon.tsx b/src/Shared/Components/Icon/Icon.tsx index 0cef854e7..82b29737f 100644 --- a/src/Shared/Components/Icon/Icon.tsx +++ b/src/Shared/Components/Icon/Icon.tsx @@ -105,6 +105,8 @@ import { ReactComponent as ICSuccess } from '@IconsV2/ic-success.svg' import { ReactComponent as ICSuspended } from '@IconsV2/ic-suspended.svg' import { ReactComponent as ICTata1mg } from '@IconsV2/ic-tata1mg.svg' import { ReactComponent as ICTerminalFill } from '@IconsV2/ic-terminal-fill.svg' +import { ReactComponent as ICThumbDown } from '@IconsV2/ic-thumb-down.svg' +import { ReactComponent as ICThumbUp } from '@IconsV2/ic-thumb-up.svg' import { ReactComponent as ICTimeoutTwoDash } from '@IconsV2/ic-timeout-two-dash.svg' import { ReactComponent as ICTimer } from '@IconsV2/ic-timer.svg' import { ReactComponent as ICTravclan } from '@IconsV2/ic-travclan.svg' @@ -223,6 +225,8 @@ export const iconMap = { 'ic-suspended': ICSuspended, 'ic-tata1mg': ICTata1mg, 'ic-terminal-fill': ICTerminalFill, + 'ic-thumb-down': ICThumbDown, + 'ic-thumb-up': ICThumbUp, 'ic-timeout-two-dash': ICTimeoutTwoDash, 'ic-timer': ICTimer, 'ic-travclan': ICTravclan, diff --git a/src/Shared/Providers/types.ts b/src/Shared/Providers/types.ts index 68af58238..d3d456ad2 100644 --- a/src/Shared/Providers/types.ts +++ b/src/Shared/Providers/types.ts @@ -18,7 +18,7 @@ import { Dispatch, MutableRefObject, ReactNode, SetStateAction } from 'react' import { SERVER_MODE } from '../../Common' import { ServerInfo } from '../Components/Header/types' -import { DevtronLicenseInfo, LicenseInfoDialogType } from '..' +import { DevtronLicenseInfo, IntelligenceConfig, LicenseInfoDialogType } from '..' export interface MainContext { serverMode: SERVER_MODE @@ -66,6 +66,8 @@ export interface MainContext { licenseData: DevtronLicenseInfo setLicenseData: Dispatch> canFetchHelmAppStatus: boolean + intelligenceConfig: IntelligenceConfig + setIntelligenceConfig: Dispatch> } export interface MainContextProviderProps { diff --git a/src/Shared/types.ts b/src/Shared/types.ts index 4b837338d..31d4d808c 100644 --- a/src/Shared/types.ts +++ b/src/Shared/types.ts @@ -1150,3 +1150,10 @@ export enum RegistryCredentialsType { USERNAME_PASSWORD = 'username_password', ANONYMOUS = 'anonymous', } + +export interface IntelligenceConfig { + clusterId: number + metadata: Record + prompt: string + analyticsCategory: string +} From 5daa0efc280625affe2663741f468ff73a2e9400 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 2 May 2025 12:46:06 +0530 Subject: [PATCH 64/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 386347e6d..b22a3d79b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-3-beta-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-3-beta-1", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 77e914d22..272e9d05c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-3-beta-1", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 0e052bc0c26c2c9f7070c22c707202d9bf419611 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Fri, 2 May 2025 16:03:19 +0530 Subject: [PATCH 65/80] fix: stop y axis animation on tab group --- src/Shared/Components/TabGroup/TabGroup.component.tsx | 10 +++++++++- src/Shared/Components/TabGroup/TabGroup.scss | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index d7bcba5f8..1d79f4f00 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -28,7 +28,15 @@ import { getClassNameBySizeMap, tabGroupClassMap } from './TabGroup.utils' import './TabGroup.scss' const MotionLayoutUnderline = ({ layoutId }: { layoutId: string }) => ( - + + // Replace the y value in translate3d(x, y, z) with 0px to omit y axis transitions + generatedTransform.replace(/translate3d\(([^,]+),\s*[^,]+,\s*([^)]+)\)/, 'translate3d($1, 0px, $2)') + } + layoutId={layoutId} + className="underline bcb-5" + /> ) const Tab = ({ diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index 2ddaaf6b9..ac743f2ee 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -34,7 +34,7 @@ @include svg-styles(var(--N700)); .underline { - height: 2px; + height: 2px !important; border-top-left-radius: 2px; border-top-right-radius: 2px; } From 623112d0bd9b59c1576a0628d326ba79b0e2ba7a Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 13:51:03 +0530 Subject: [PATCH 66/80] fix: DynamicDataTable - handled case where cell was getting autofocused on mount --- .../DynamicDataTable/DynamicDataTable.tsx | 22 ++++++++++++++++--- .../DynamicDataTable/DynamicDataTableRow.tsx | 9 ++++++-- .../Components/DynamicDataTable/types.ts | 7 ++++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Shared/Components/DynamicDataTable/DynamicDataTable.tsx b/src/Shared/Components/DynamicDataTable/DynamicDataTable.tsx index b98cf41bd..95349fc75 100644 --- a/src/Shared/Components/DynamicDataTable/DynamicDataTable.tsx +++ b/src/Shared/Components/DynamicDataTable/DynamicDataTable.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { useMemo } from 'react' +import { useMemo, useState } from 'react' import { DynamicDataTableHeader } from './DynamicDataTableHeader' import { DynamicDataTableRow } from './DynamicDataTableRow' @@ -24,14 +24,30 @@ import './styles.scss' export const DynamicDataTable = >({ headers, + onRowAdd, ...props }: DynamicDataTableProps) => { + // STATES + const [isAddRowButtonClicked, setIsAddRowButtonClicked] = useState(false) + + // CONSTANTS const filteredHeaders = useMemo(() => headers.filter(({ isHidden }) => !isHidden), [headers]) + // HANDLERS + const handleRowAdd = () => { + setIsAddRowButtonClicked(true) + onRowAdd() + } + return (
    - - + +
    ) } diff --git a/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx b/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx index 40fb9a572..45b141d80 100644 --- a/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx +++ b/src/Shared/Components/DynamicDataTable/DynamicDataTableRow.tsx @@ -73,6 +73,8 @@ export const DynamicDataTableRow = ) => { // CONSTANTS const isFirstRowEmpty = headers.every(({ key }) => !rows[0]?.data[key].value) @@ -105,6 +107,8 @@ export const DynamicDataTableRow = { setIsRowAdded(rows.length > 0 && Object.keys(cellRef.current).length < rows.length) + // When a new row is added, we create references for its cells. + // This logic ensures that references are created only for the newly added row, while retaining the existing references. const updatedCellRef = rowIds.reduce((acc, curr) => { if (cellRef.current[curr]) { acc[curr] = cellRef.current[curr] @@ -118,15 +122,16 @@ export const DynamicDataTableRow = { - if (isRowAdded) { + if (isAddRowButtonClicked && isRowAdded) { // Using the below logic to ensure the cell is focused after row addition. const cell = cellRef.current[rows[0].id][focusableFieldKey || headers[0].key].current if (cell) { cell.focus() setIsRowAdded(false) + setIsAddRowButtonClicked(false) } } - }, [isRowAdded]) + }, [isRowAdded, isAddRowButtonClicked]) // METHODS const onChange = diff --git a/src/Shared/Components/DynamicDataTable/types.ts b/src/Shared/Components/DynamicDataTable/types.ts index f8e378eaf..3e9574cb1 100644 --- a/src/Shared/Components/DynamicDataTable/types.ts +++ b/src/Shared/Components/DynamicDataTable/types.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { DetailedHTMLProps, ReactElement, ReactNode } from 'react' +import { DetailedHTMLProps, Dispatch, ReactElement, ReactNode, SetStateAction } from 'react' import { ResizableTagTextAreaProps } from '@Common/CustomTagSelector' import { UseStateFiltersReturnType } from '@Common/Hooks' @@ -261,4 +261,7 @@ export interface DynamicDataTableRowProps {} + > { + isAddRowButtonClicked: boolean + setIsAddRowButtonClicked: Dispatch> +} From 9a1074c54b1064ea79eacc5ea54a2d78cc0bef22 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 15:00:46 +0530 Subject: [PATCH 67/80] refactor: remove CodeEditorWrapper, move CodeEditor to Shared/Components, update instances of CodeEditor --- .../DeploymentHistoryDiffView.tsx | 13 +--- .../CMCS/ConfigMapSecretReadyOnly.tsx | 16 +---- .../CodeEditor}/CodeEditor.components.tsx | 0 .../CodeEditor}/CodeEditor.constants.ts | 0 .../CodeEditor}/CodeEditor.context.ts | 0 .../CodeEditor}/CodeEditor.theme.ts | 0 .../Components/CodeEditor}/CodeEditor.tsx | 0 .../CodeEditor}/CodeEditorRenderer.tsx | 0 .../CodeEditor}/Commands/findAndReplace.ts | 0 .../Components/CodeEditor}/Commands/index.ts | 0 .../CodeEditor}/Commands/keyMaps.ts | 0 .../CodeEditor}/Extensions/DiffMinimap.tsx | 0 .../CodeEditor}/Extensions/findAndReplace.tsx | 0 .../CodeEditor}/Extensions/index.ts | 0 .../CodeEditor}/Extensions/readOnlyTooltip.ts | 0 .../CodeEditor}/Extensions/yamlHighlight.ts | 0 .../CodeEditor}/Extensions/yamlParseLinter.ts | 0 .../Components/CodeEditor}/codeEditor.scss | 0 .../Components/CodeEditor}/index.ts | 0 .../Components/CodeEditor}/types.ts | 0 .../Components/CodeEditor}/utils.tsx | 0 .../CodeEditorWrapper/CodeEditorWrapper.tsx | 60 ------------------- .../Components/CodeEditorWrapper/index.ts | 17 ------ .../Components/CodeEditorWrapper/types.ts | 52 ---------------- src/Shared/Components/index.ts | 2 +- 25 files changed, 6 insertions(+), 154 deletions(-) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditor.components.tsx (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditor.constants.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditor.context.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditor.theme.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditor.tsx (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/CodeEditorRenderer.tsx (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Commands/findAndReplace.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Commands/index.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Commands/keyMaps.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/DiffMinimap.tsx (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/findAndReplace.tsx (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/index.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/readOnlyTooltip.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/yamlHighlight.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/Extensions/yamlParseLinter.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/codeEditor.scss (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/index.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/types.ts (100%) rename src/{Common/CodeMirror => Shared/Components/CodeEditor}/utils.tsx (100%) delete mode 100644 src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx delete mode 100644 src/Shared/Components/CodeEditorWrapper/index.ts delete mode 100644 src/Shared/Components/CodeEditorWrapper/types.ts diff --git a/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryDiffView.tsx b/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryDiffView.tsx index d121b3519..cc9448003 100644 --- a/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryDiffView.tsx +++ b/src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryDiffView.tsx @@ -18,7 +18,7 @@ import { useMemo, useState } from 'react' import { useParams } from 'react-router-dom' import Tippy from '@tippyjs/react' -import { CodeEditor } from '@Shared/Components/CodeEditorWrapper' +import { CodeEditor } from '@Shared/Components/CodeEditor' import { renderDiffViewNoDifferenceState } from '@Shared/Components/DeploymentConfigDiff' import { DiffViewer } from '@Shared/Components/DiffViewer' @@ -79,19 +79,12 @@ const DeploymentHistoryDiffView = ({ ) : ( ) diff --git a/src/Shared/Components/CMCS/ConfigMapSecretReadyOnly.tsx b/src/Shared/Components/CMCS/ConfigMapSecretReadyOnly.tsx index 2d37a3c96..2fd444652 100644 --- a/src/Shared/Components/CMCS/ConfigMapSecretReadyOnly.tsx +++ b/src/Shared/Components/CMCS/ConfigMapSecretReadyOnly.tsx @@ -18,7 +18,7 @@ import { MODES } from '@Common/Constants' import { Progressing } from '@Common/Progressing' import { hasHashiOrAWS } from '@Pages/index' -import { CodeEditor } from '../CodeEditorWrapper' +import { CodeEditor } from '../CodeEditor' import { renderHashiOrAwsDeprecatedInfo } from './helpers' import { ConfigMapSecretReadyOnlyProps } from './types' import { getConfigMapSecretReadOnlyValues } from './utils' @@ -68,19 +68,7 @@ const ConfigMapSecretReadyOnly = ({
    {!hideCodeEditor && displayValues.data && ( - +

    Data

    diff --git a/src/Common/CodeMirror/CodeEditor.components.tsx b/src/Shared/Components/CodeEditor/CodeEditor.components.tsx similarity index 100% rename from src/Common/CodeMirror/CodeEditor.components.tsx rename to src/Shared/Components/CodeEditor/CodeEditor.components.tsx diff --git a/src/Common/CodeMirror/CodeEditor.constants.ts b/src/Shared/Components/CodeEditor/CodeEditor.constants.ts similarity index 100% rename from src/Common/CodeMirror/CodeEditor.constants.ts rename to src/Shared/Components/CodeEditor/CodeEditor.constants.ts diff --git a/src/Common/CodeMirror/CodeEditor.context.ts b/src/Shared/Components/CodeEditor/CodeEditor.context.ts similarity index 100% rename from src/Common/CodeMirror/CodeEditor.context.ts rename to src/Shared/Components/CodeEditor/CodeEditor.context.ts diff --git a/src/Common/CodeMirror/CodeEditor.theme.ts b/src/Shared/Components/CodeEditor/CodeEditor.theme.ts similarity index 100% rename from src/Common/CodeMirror/CodeEditor.theme.ts rename to src/Shared/Components/CodeEditor/CodeEditor.theme.ts diff --git a/src/Common/CodeMirror/CodeEditor.tsx b/src/Shared/Components/CodeEditor/CodeEditor.tsx similarity index 100% rename from src/Common/CodeMirror/CodeEditor.tsx rename to src/Shared/Components/CodeEditor/CodeEditor.tsx diff --git a/src/Common/CodeMirror/CodeEditorRenderer.tsx b/src/Shared/Components/CodeEditor/CodeEditorRenderer.tsx similarity index 100% rename from src/Common/CodeMirror/CodeEditorRenderer.tsx rename to src/Shared/Components/CodeEditor/CodeEditorRenderer.tsx diff --git a/src/Common/CodeMirror/Commands/findAndReplace.ts b/src/Shared/Components/CodeEditor/Commands/findAndReplace.ts similarity index 100% rename from src/Common/CodeMirror/Commands/findAndReplace.ts rename to src/Shared/Components/CodeEditor/Commands/findAndReplace.ts diff --git a/src/Common/CodeMirror/Commands/index.ts b/src/Shared/Components/CodeEditor/Commands/index.ts similarity index 100% rename from src/Common/CodeMirror/Commands/index.ts rename to src/Shared/Components/CodeEditor/Commands/index.ts diff --git a/src/Common/CodeMirror/Commands/keyMaps.ts b/src/Shared/Components/CodeEditor/Commands/keyMaps.ts similarity index 100% rename from src/Common/CodeMirror/Commands/keyMaps.ts rename to src/Shared/Components/CodeEditor/Commands/keyMaps.ts diff --git a/src/Common/CodeMirror/Extensions/DiffMinimap.tsx b/src/Shared/Components/CodeEditor/Extensions/DiffMinimap.tsx similarity index 100% rename from src/Common/CodeMirror/Extensions/DiffMinimap.tsx rename to src/Shared/Components/CodeEditor/Extensions/DiffMinimap.tsx diff --git a/src/Common/CodeMirror/Extensions/findAndReplace.tsx b/src/Shared/Components/CodeEditor/Extensions/findAndReplace.tsx similarity index 100% rename from src/Common/CodeMirror/Extensions/findAndReplace.tsx rename to src/Shared/Components/CodeEditor/Extensions/findAndReplace.tsx diff --git a/src/Common/CodeMirror/Extensions/index.ts b/src/Shared/Components/CodeEditor/Extensions/index.ts similarity index 100% rename from src/Common/CodeMirror/Extensions/index.ts rename to src/Shared/Components/CodeEditor/Extensions/index.ts diff --git a/src/Common/CodeMirror/Extensions/readOnlyTooltip.ts b/src/Shared/Components/CodeEditor/Extensions/readOnlyTooltip.ts similarity index 100% rename from src/Common/CodeMirror/Extensions/readOnlyTooltip.ts rename to src/Shared/Components/CodeEditor/Extensions/readOnlyTooltip.ts diff --git a/src/Common/CodeMirror/Extensions/yamlHighlight.ts b/src/Shared/Components/CodeEditor/Extensions/yamlHighlight.ts similarity index 100% rename from src/Common/CodeMirror/Extensions/yamlHighlight.ts rename to src/Shared/Components/CodeEditor/Extensions/yamlHighlight.ts diff --git a/src/Common/CodeMirror/Extensions/yamlParseLinter.ts b/src/Shared/Components/CodeEditor/Extensions/yamlParseLinter.ts similarity index 100% rename from src/Common/CodeMirror/Extensions/yamlParseLinter.ts rename to src/Shared/Components/CodeEditor/Extensions/yamlParseLinter.ts diff --git a/src/Common/CodeMirror/codeEditor.scss b/src/Shared/Components/CodeEditor/codeEditor.scss similarity index 100% rename from src/Common/CodeMirror/codeEditor.scss rename to src/Shared/Components/CodeEditor/codeEditor.scss diff --git a/src/Common/CodeMirror/index.ts b/src/Shared/Components/CodeEditor/index.ts similarity index 100% rename from src/Common/CodeMirror/index.ts rename to src/Shared/Components/CodeEditor/index.ts diff --git a/src/Common/CodeMirror/types.ts b/src/Shared/Components/CodeEditor/types.ts similarity index 100% rename from src/Common/CodeMirror/types.ts rename to src/Shared/Components/CodeEditor/types.ts diff --git a/src/Common/CodeMirror/utils.tsx b/src/Shared/Components/CodeEditor/utils.tsx similarity index 100% rename from src/Common/CodeMirror/utils.tsx rename to src/Shared/Components/CodeEditor/utils.tsx diff --git a/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx b/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx deleted file mode 100644 index a00c91dcd..000000000 --- a/src/Shared/Components/CodeEditorWrapper/CodeEditorWrapper.tsx +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { CodeEditor as CodeMirror, CodeEditorHeaderProps, CodeEditorStatusBarProps } from '@Common/CodeMirror' - -import { CodeEditorWrapperProps } from './types' - -export const CodeEditorWrapper = ({ - /* eslint-disable @typescript-eslint/no-unused-vars */ - codeEditorProps, - codeMirrorProps, - children, - ...restProps -}: CodeEditorWrapperProps) => ( - {...(codeMirrorProps as any)} {...restProps}> - {children} - -) - -const CodeEditorClipboardWrapper = () => - -const CodeEditorHeaderWrapper = (props: CodeEditorHeaderProps) => - -const CodeEditorWarningWrapper = (props: CodeEditorStatusBarProps) => - -const CodeEditorErrorBarWrapper = (props: CodeEditorStatusBarProps) => - -const CodeEditorInformationWrapper = (props: CodeEditorStatusBarProps) => - -const CodeEditorContainerWrapper = ({ - children, - flexExpand, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - overflowHidden, -}: { - children: React.ReactNode - flexExpand?: boolean - /** @deprecated this prop does not have any effect on codeEditor */ - overflowHidden?: boolean -}) => {children} - -CodeEditorWrapper.Clipboard = CodeEditorClipboardWrapper -CodeEditorWrapper.Header = CodeEditorHeaderWrapper -CodeEditorWrapper.Warning = CodeEditorWarningWrapper -CodeEditorWrapper.ErrorBar = CodeEditorErrorBarWrapper -CodeEditorWrapper.Information = CodeEditorInformationWrapper -CodeEditorWrapper.Container = CodeEditorContainerWrapper diff --git a/src/Shared/Components/CodeEditorWrapper/index.ts b/src/Shared/Components/CodeEditorWrapper/index.ts deleted file mode 100644 index 55dd23db1..000000000 --- a/src/Shared/Components/CodeEditorWrapper/index.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -export { CodeEditorWrapper as CodeEditor } from './CodeEditorWrapper' diff --git a/src/Shared/Components/CodeEditorWrapper/types.ts b/src/Shared/Components/CodeEditorWrapper/types.ts deleted file mode 100644 index a01a5a3c7..000000000 --- a/src/Shared/Components/CodeEditorWrapper/types.ts +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2024. Devtron Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { CodeEditorProps } from '@Common/CodeMirror' - -export type CodeEditorWrapperProps = Pick< - CodeEditorProps, - | 'mode' - | 'tabSize' - | 'readOnly' - | 'placeholder' - | 'noParsing' - | 'loading' - | 'customLoader' - | 'cleanData' - | 'disableSearch' - | 'children' -> & { - diffView?: DiffView - /** - * @deprecated - * Monaco editor has been removed. \ - * This prop is no longer required and will be removed in future releases. - */ - codeEditorProps?: any - codeMirrorProps: Omit< - CodeEditorProps, - | 'mode' - | 'tabSize' - | 'readOnly' - | 'placeholder' - | 'noParsing' - | 'loading' - | 'customLoader' - | 'cleanData' - | 'disableSearch' - | 'children' - > -} diff --git a/src/Shared/Components/index.ts b/src/Shared/Components/index.ts index 75d7f961e..3254f2f7c 100644 --- a/src/Shared/Components/index.ts +++ b/src/Shared/Components/index.ts @@ -30,7 +30,7 @@ export * from './ButtonWithLoader' export * from './ButtonWithSelector' export * from './CICDHistory' export * from './CMCS' -export * from './CodeEditorWrapper' +export * from './CodeEditor' export * from './Collapse' export * from './CollapsibleList' export * from './CommitChipCell' From 67492ffe966891a92f1926fd2e9788d06f62ee3f Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 15:31:35 +0530 Subject: [PATCH 68/80] chore(version): bump to 1.12.0-pre-4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2d20a4174..a16f71080 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 628bbfa5f..458893b3a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From a013fbfd1be1733b9fdf548515dcbca6aa78ce64 Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 15:41:46 +0530 Subject: [PATCH 69/80] refactor: rename email prop to identifier in UserIdentifier component --- .../UserIdentifier/UserIdentifier.tsx | 18 ++++++++++-------- src/Shared/Components/UserIdentifier/types.ts | 2 +- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx index 70cd6663c..8e9318cc2 100644 --- a/src/Shared/Components/UserIdentifier/UserIdentifier.tsx +++ b/src/Shared/Components/UserIdentifier/UserIdentifier.tsx @@ -16,7 +16,7 @@ const UserIdentifierTooltip = ({ ) export const UserIdentifier = ({ - email, + identifier, children, rootClassName, tooltipContent, @@ -25,13 +25,13 @@ export const UserIdentifier = ({ // HOOKS const { email: currentUserEmail } = useUserEmail() - if (!email) { + if (!identifier) { return null } // CONSTANTS - const isCurrentUser = email === currentUserEmail - const isApiToken = email.startsWith(API_TOKEN_PREFIX) + const isCurrentUser = identifier === currentUserEmail + const isApiToken = identifier.startsWith(API_TOKEN_PREFIX) const renderIcon = () => { if (isApiToken) { @@ -41,7 +41,7 @@ export const UserIdentifier = ({ return isUserGroup ? ( ) : ( - getAlphabetIcon(email, 'dc__no-shrink m-0-imp') + getAlphabetIcon(identifier, 'dc__no-shrink m-0-imp') ) } @@ -51,10 +51,10 @@ export const UserIdentifier = ({ } if (isApiToken) { - return email.split(':')?.[1] || '-' + return identifier.split(':')?.[1] || '-' } - return email + return identifier } return ( @@ -63,7 +63,9 @@ export const UserIdentifier = ({ {renderIcon()}
    {renderText()} diff --git a/src/Shared/Components/UserIdentifier/types.ts b/src/Shared/Components/UserIdentifier/types.ts index 17de36d4d..7a2e3b8dc 100644 --- a/src/Shared/Components/UserIdentifier/types.ts +++ b/src/Shared/Components/UserIdentifier/types.ts @@ -1,7 +1,7 @@ import { ReactNode } from 'react' export interface UserIdentifierProps { - email: string + identifier: string children?: ReactNode isUserGroup?: boolean rootClassName?: string From 2989e777bb97fc6628c036976b0d285f94a0fd28 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 5 May 2025 15:41:48 +0530 Subject: [PATCH 70/80] fix: tab group underline layout --- src/Assets/IconV2/ic-info-filled.svg | 2 +- src/Shared/Components/TabGroup/TabGroup.component.tsx | 3 +-- src/Shared/Components/TabGroup/TabGroup.scss | 1 + src/Shared/Components/TabGroup/TabGroup.utils.ts | 9 ++++----- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Assets/IconV2/ic-info-filled.svg b/src/Assets/IconV2/ic-info-filled.svg index 8f79e556b..f9f02f2b0 100644 --- a/src/Assets/IconV2/ic-info-filled.svg +++ b/src/Assets/IconV2/ic-info-filled.svg @@ -16,5 +16,5 @@ - + diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 1d79f4f00..a9ea67803 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -35,7 +35,7 @@ const MotionLayoutUnderline = ({ layoutId }: { layoutId: string }) => ( generatedTransform.replace(/translate3d\(([^,]+),\s*[^,]+,\s*([^)]+)\)/, 'translate3d($1, 0px, $2)') } layoutId={layoutId} - className="underline bcb-5" + className="underline bcb-5 w-100 dc__position-abs" /> ) @@ -67,7 +67,6 @@ const Tab = ({ const { tabClassName, iconClassName, badgeClassName } = getClassNameBySizeMap({ hideTopPadding, - isTabActive, })[size] const onClickHandler = ( diff --git a/src/Shared/Components/TabGroup/TabGroup.scss b/src/Shared/Components/TabGroup/TabGroup.scss index ac743f2ee..02f5e7967 100644 --- a/src/Shared/Components/TabGroup/TabGroup.scss +++ b/src/Shared/Components/TabGroup/TabGroup.scss @@ -37,6 +37,7 @@ height: 2px !important; border-top-left-radius: 2px; border-top-right-radius: 2px; + bottom: -1px; } &--active { diff --git a/src/Shared/Components/TabGroup/TabGroup.utils.ts b/src/Shared/Components/TabGroup/TabGroup.utils.ts index 5bc8aeb6f..5682c1651 100644 --- a/src/Shared/Components/TabGroup/TabGroup.utils.ts +++ b/src/Shared/Components/TabGroup/TabGroup.utils.ts @@ -21,8 +21,7 @@ import { TabGroupProps } from './TabGroup.types' export const getClassNameBySizeMap = ({ hideTopPadding, - isTabActive, -}: Pick & { isTabActive: boolean }): Record< +}: Pick): Record< TabGroupProps['size'], { tabClassName: string @@ -31,17 +30,17 @@ export const getClassNameBySizeMap = ({ } > => ({ [ComponentSizeType.medium]: { - tabClassName: `fs-12 ${!hideTopPadding ? 'pt-6' : ''} ${isTabActive ? 'pb-3' : 'pb-5'}`, + tabClassName: `fs-12 ${!hideTopPadding ? 'pt-6' : ''} pb-5`, iconClassName: 'icon-dim-14', badgeClassName: 'fs-11 lh-18 tab-group__tab__badge--medium', }, [ComponentSizeType.large]: { - tabClassName: `fs-13 ${!hideTopPadding ? 'pt-8' : ''} ${isTabActive ? 'pb-5' : 'pb-7'}`, + tabClassName: `fs-13 ${!hideTopPadding ? 'pt-8' : ''} pb-7`, iconClassName: 'icon-dim-16', badgeClassName: 'fs-12 lh-20', }, [ComponentSizeType.xl]: { - tabClassName: `min-w-200 fs-13 ${!hideTopPadding ? 'pt-10' : ''} ${isTabActive ? 'pb-7' : 'pb-9'}`, + tabClassName: `min-w-200 fs-13 ${!hideTopPadding ? 'pt-10' : ''} pb-9`, iconClassName: 'icon-dim-16', badgeClassName: 'fs-12 lh-20', }, From afd87c80373ed0fc55ffdf8891ff1ea74b986aaa Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 15:42:07 +0530 Subject: [PATCH 71/80] chore(version): bump to 1.12.0-pre-4 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 386347e6d..b3f206a49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 77e914d22..a6af9db1f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-3", + "version": "1.12.0-pre-4", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 774f8f1ec8f067c4ec402b121ea0e1f38a04914f Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 5 May 2025 16:13:29 +0530 Subject: [PATCH 72/80] feat: update getTimeDiff function --- src/Shared/Helpers.tsx | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/Shared/Helpers.tsx b/src/Shared/Helpers.tsx index eda31ea24..77e50337d 100644 --- a/src/Shared/Helpers.tsx +++ b/src/Shared/Helpers.tsx @@ -790,19 +790,24 @@ export const getTimeDifference = ({ return fallbackString } - const seconds = moment(endTime).diff(moment(startTime), 'seconds') - const minutes = moment(endTime).diff(moment(startTime), 'minutes') - const hours = moment(endTime).diff(moment(startTime), 'hours') + const duration = moment.duration(moment(endTime).diff(moment(startTime))) - if (seconds < 60) { - return `${seconds}s` - } - if (minutes < 60) { - return `${minutes}m ${seconds % 60}s` + const units = [ + { label: 'd', value: duration.days() }, + { label: 'h', value: duration.hours() }, + { label: 'm', value: duration.minutes() }, + { label: 's', value: duration.seconds() }, + ] + + // Filter out zero values and take the first two non-zero units + const nonZeroUnits = units.filter((unit) => unit.value > 0).slice(0, 2) + + // If all units are zero, show "0s" + if (nonZeroUnits.length === 0) { + return '0s' } - const leftOverMinutes = minutes - hours * 60 - const leftOverSeconds = seconds - minutes * 60 - return `${hours}h ${leftOverMinutes}m ${leftOverSeconds}s` + + return nonZeroUnits.map((unit) => `${unit.value}${unit.label}`).join(' ') } export const getFileNameFromHeaders = (headers: Headers) => From b867eaf4e06276d6ebe4a60454789dd94d58be9a Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 5 May 2025 16:42:35 +0530 Subject: [PATCH 73/80] fix: time diff helper --- src/Shared/Helpers.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Shared/Helpers.tsx b/src/Shared/Helpers.tsx index 77e50337d..b73a459ad 100644 --- a/src/Shared/Helpers.tsx +++ b/src/Shared/Helpers.tsx @@ -790,7 +790,14 @@ export const getTimeDifference = ({ return fallbackString } - const duration = moment.duration(moment(endTime).diff(moment(startTime))) + const start = moment(startTime) + const end = moment(endTime) + if (!start.isValid() || !end.isValid()) { + return fallbackString + } + + const diff = Math.abs(end.diff(start)) + const duration = moment.duration(diff) const units = [ { label: 'd', value: duration.days() }, From adb3fb201b6f32e5844b98436d0e8cecd24a1a59 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Mon, 5 May 2025 16:53:16 +0530 Subject: [PATCH 74/80] chore: feature flag for ai integration --- src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.ts b/src/index.ts index f582c59a3..f598dd3d3 100644 --- a/src/index.ts +++ b/src/index.ts @@ -155,6 +155,7 @@ export interface customEnv { */ FEATURE_APPLICATION_TEMPLATES_ENABLE?: boolean GATEKEEPER_URL?: string + FEATURE_AI_INTEGRATION_ENABLE?: boolean } declare global { interface Window { From c258f16c444b950507ed482ab062a095332f02ef Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Mon, 5 May 2025 17:15:25 +0530 Subject: [PATCH 75/80] chore(version): bump to 1.12.0-pre-6 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 81aec7c0a..99503cd04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-5", + "version": "1.12.0-pre-6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-5", + "version": "1.12.0-pre-6", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index a1ab5ed4d..5e737b1ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-5", + "version": "1.12.0-pre-6", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 44f1f607215a87199252ee41443cd7dd8bbc8f82 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Tue, 6 May 2025 12:46:59 +0530 Subject: [PATCH 76/80] feat: add component for snow confetti --- package-lock.json | 4 ++-- package.json | 2 +- .../Components/Confetti/Confetti.component.tsx | 18 ++++++++++++++++++ src/Shared/Components/Confetti/index.ts | 2 +- src/index.ts | 1 + 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index d759c8afc..9ae5ee249 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.2", + "version": "1.11.2-patch-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.2", + "version": "1.11.2-patch-1", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 3f8212f81..310b26a9b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.11.2", + "version": "1.11.2-patch-1", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Shared/Components/Confetti/Confetti.component.tsx b/src/Shared/Components/Confetti/Confetti.component.tsx index 6a68f734e..5ecff9e66 100644 --- a/src/Shared/Components/Confetti/Confetti.component.tsx +++ b/src/Shared/Components/Confetti/Confetti.component.tsx @@ -15,8 +15,26 @@ */ import { ComponentProps } from 'react' +import Snow from 'react-canvas-confetti/dist/presets/snow' import Pride from 'react-canvas-confetti/dist/presets/pride' +export const SnowConfetti = () => { + const decorateOptions: ComponentProps['decorateOptions'] = (options) => ({ + ...options, + colors: ['#a864fd'], + }) + + return ( + + ) +} + const Confetti = () => { const decorateOptions: ComponentProps['decorateOptions'] = (options) => ({ ...options, diff --git a/src/Shared/Components/Confetti/index.ts b/src/Shared/Components/Confetti/index.ts index d6af234ed..e7445ee8e 100644 --- a/src/Shared/Components/Confetti/index.ts +++ b/src/Shared/Components/Confetti/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export { default as Confetti } from './Confetti.component' +export { SnowConfetti, default as Confetti } from './Confetti.component' diff --git a/src/index.ts b/src/index.ts index b101a0807..050a20a77 100644 --- a/src/index.ts +++ b/src/index.ts @@ -155,6 +155,7 @@ export interface customEnv { */ FEATURE_APPLICATION_TEMPLATES_ENABLE?: boolean GATEKEEPER_URL?: string + LOGIN_PAGE_IMAGE?: string } declare global { interface Window { From f8aaa6d828240624ab50791a1d57c68cd6a2ff36 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Tue, 6 May 2025 17:25:29 +0530 Subject: [PATCH 77/80] feat: update logic for isActive in tab group --- .../TabGroup/TabGroup.component.tsx | 25 +++++++++++-------- .../Components/TabGroup/TabGroup.helpers.tsx | 13 ---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/src/Shared/Components/TabGroup/TabGroup.component.tsx b/src/Shared/Components/TabGroup/TabGroup.component.tsx index 2d1d8a10b..63b3a54b1 100644 --- a/src/Shared/Components/TabGroup/TabGroup.component.tsx +++ b/src/Shared/Components/TabGroup/TabGroup.component.tsx @@ -14,14 +14,14 @@ * limitations under the License. */ -import { useMemo } from 'react' -import { Link, NavLink, useRouteMatch } from 'react-router-dom' +import { useEffect, useMemo, useRef, useState } from 'react' +import { Link, NavLink, useLocation } from 'react-router-dom' import { motion } from 'framer-motion' import { Tooltip } from '@Common/Tooltip' import { ComponentSizeType } from '@Shared/constants' -import { getPathnameToMatch, getTabBadge, getTabDescription, getTabIcon, getTabIndicator } from './TabGroup.helpers' +import { getTabBadge, getTabDescription, getTabIcon, getTabIndicator } from './TabGroup.helpers' import { AdditionalTabProps, TabGroupProps, TabProps } from './TabGroup.types' import { getClassNameBySizeMap, tabGroupClassMap } from './TabGroup.utils' @@ -57,13 +57,17 @@ const Tab = ({ tooltipProps, uniqueGroupId, }: TabProps & Pick & AdditionalTabProps) => { - const { path } = useRouteMatch() - const pathToMatch = tabType === 'navLink' || tabType === 'link' ? getPathnameToMatch(props.to, path) : '' - - // using match to define if tab is active as useRouteMatch return an object if path is matched otherwise return null/undefined - const match = useRouteMatch(pathToMatch) - - const isTabActive = tabType === 'button' ? active : !!match + const { pathname, search } = useLocation() + const ref = useRef(null) + const [isTabActive, setIsTabActive] = useState(tabType === 'button' && active) + + useEffect(() => { + if (tabType === 'navLink') { + setIsTabActive(ref.current?.classList.contains('active') || false) + return + } + setIsTabActive(active) + }, [active, tabType, pathname, search]) const { tabClassName, iconClassName, badgeClassName } = getClassNameBySizeMap({ hideTopPadding, @@ -110,6 +114,7 @@ const Tab = ({ case 'navLink': return ( : description} ) - -const replaceTrailingSlash = (pathname: string) => pathname.replace(/\/+$/, '') - -export const getPathnameToMatch = (to: NavLinkProps['to'] | LinkProps['to'], currentPathname: string): string => { - if (typeof to === 'string' || (to && typeof to === 'object' && 'pathname' in to)) { - const pathname = typeof to === 'string' ? to : to.pathname || '' - // handling absolute and relative paths - return pathname.startsWith('/') ? pathname : `${replaceTrailingSlash(currentPathname)}/${pathname}` - } - return '' -} From d9ea5c194d5ada95f973975e903c64d983e62eb6 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Tue, 6 May 2025 17:26:38 +0530 Subject: [PATCH 78/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6e7eb0d65..457ceb0fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-7", + "version": "1.12.0-pre-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-7", + "version": "1.12.0-pre-8", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index 4e67a8f7f..c0b8c17ef 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-7", + "version": "1.12.0-pre-8", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From bf5397875c6d613c4cb4364767329966eb041078 Mon Sep 17 00:00:00 2001 From: Arun Jain Date: Tue, 6 May 2025 18:06:54 +0530 Subject: [PATCH 79/80] chore: version bump --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 457ceb0fd..51f54834c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-8", + "version": "1.12.0-pre-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-8", + "version": "1.12.0-pre-9", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index c0b8c17ef..f08782d6a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-8", + "version": "1.12.0-pre-9", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", From 809ade753767536c495019331d5c861f7664642c Mon Sep 17 00:00:00 2001 From: Rohit Raj Date: Wed, 7 May 2025 18:50:51 +0530 Subject: [PATCH 80/80] chore(version): bump to 1.13.0 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 51f54834c..01938014c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-9", + "version": "1.13.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-9", + "version": "1.13.0", "hasInstallScript": true, "license": "ISC", "dependencies": { diff --git a/package.json b/package.json index f08782d6a..a10088e67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.12.0-pre-9", + "version": "1.13.0", "description": "Supporting common component library", "type": "module", "main": "dist/index.js",