diff --git a/package-lock.json b/package-lock.json index 95e11a1a8..8ad42a9ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.0.6", + "version": "1.0.7", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.0.6", + "version": "1.0.7", "license": "ISC", "dependencies": { "@types/react-dates": "^21.8.6", diff --git a/package.json b/package.json index 8574dd78c..ac7d8a4bf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@devtron-labs/devtron-fe-common-lib", - "version": "1.0.6", + "version": "1.0.7", "description": "Supporting common component library", "type": "module", "main": "dist/index.js", diff --git a/src/Assets/Icon/ic-hash.svg b/src/Assets/Icon/ic-hash.svg new file mode 100644 index 000000000..8220a82ae --- /dev/null +++ b/src/Assets/Icon/ic-hash.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/Assets/Icon/ic-pull-request.svg b/src/Assets/Icon/ic-pull-request.svg index 9ba5cc629..695951ef5 100644 --- a/src/Assets/Icon/ic-pull-request.svg +++ b/src/Assets/Icon/ic-pull-request.svg @@ -14,6 +14,6 @@ - limitations under the License. --> - - + + \ No newline at end of file diff --git a/src/Assets/Icon/ic-tag.svg b/src/Assets/Icon/ic-tag.svg index f71d3f1f8..65b11a10d 100644 --- a/src/Assets/Icon/ic-tag.svg +++ b/src/Assets/Icon/ic-tag.svg @@ -14,7 +14,6 @@ - limitations under the License. --> - - - + + \ No newline at end of file diff --git a/src/Common/Common.service.ts b/src/Common/Common.service.ts index 99e28ff6c..a9a5559d9 100644 --- a/src/Common/Common.service.ts +++ b/src/Common/Common.service.ts @@ -18,7 +18,7 @@ import moment from 'moment' import { RuntimeParamsAPIResponseType, RuntimeParamsListItemType } from '@Shared/types' import { getIsManualApprovalSpecific, sanitizeUserApprovalConfig, stringComparatorBySortOrder } from '@Shared/Helpers' import { get, post } from './Api' -import { ROUTES } from './Constants' +import { GitProviderType, ROUTES } from './Constants' import { getUrlWithSearchParams, sortCallback } from './Helper' import { TeamList, @@ -250,7 +250,7 @@ const getImageApprovalPolicyDetailsFromMaterialResult = (cdMaterialsResult): Ima const validGroups = userApprovalConfig.userGroups.map((group) => group.identifier) // Have moved from Object.keys(imageApprovalUsersInfo) to approvalUsers since backend is not filtering out the users without approval - // TODO: This check should be on BE. Need to remove this once BE is updated + // TODO: This check should be on BE. Need to remove this once BE is updated const usersList = approvalUsers.filter((user) => user !== DefaultUserKey.system) const groupIdentifierToUsersMap = usersList.reduce( (acc, user) => { @@ -511,3 +511,19 @@ export function getWebhookEventsForEventId(eventId: string | number) { const URL = `${ROUTES.GIT_HOST_EVENT}/${eventId}` return get(URL) } + +/** + * + * @param gitUrl Git URL of the repository + * @param branchName Branch name + * @returns URL to the branch in the Git repository + */ +export const getGitBranchUrl = (gitUrl: string, branchName: string): string | null => { + if (!gitUrl) return null + const trimmedGitUrl = gitUrl.trim().replace(/\.git$/, '').replace(/\/$/, '') // Remove any trailing slash + if (trimmedGitUrl.includes(GitProviderType.GITLAB)) return `${trimmedGitUrl}/-/tree/${branchName}` + else if (trimmedGitUrl.includes(GitProviderType.GITHUB)) return `${trimmedGitUrl}/tree/${branchName}` + else if (trimmedGitUrl.includes(GitProviderType.BITBUCKET)) return `${trimmedGitUrl}/branch/${branchName}` + else if (trimmedGitUrl.includes(GitProviderType.AZURE)) return `${trimmedGitUrl}/src/branch/${branchName}` + return null +} diff --git a/src/Common/Constants.ts b/src/Common/Constants.ts index 8d147b6c5..1cb08f694 100644 --- a/src/Common/Constants.ts +++ b/src/Common/Constants.ts @@ -558,3 +558,20 @@ export const VULNERABILITIES_SORT_PRIORITY = { // TODO: might not work need to verify export const IS_PLATFORM_MAC_OS = window.navigator.userAgent.toUpperCase().includes('MAC') + +/** + * Git provider types + */ + +export enum GitProviderType { + GITHUB = 'github', + GITLAB = 'gitlab', + BITBUCKET = 'bitbucket', + AZURE = 'azure', + GITEA = 'gitea', +} + +/** + * Formats the schema removing any irregularity in the existing schema + */ +export const getFormattedSchema = (schema?: string) => JSON.stringify(JSON.parse(schema ?? '{}'), null, 2) diff --git a/src/Common/Helper.tsx b/src/Common/Helper.tsx index a2667d0cd..91a7dee66 100644 --- a/src/Common/Helper.tsx +++ b/src/Common/Helper.tsx @@ -40,8 +40,15 @@ import { ToastManager, ToastVariantType, versionComparatorBySortOrder, + WebhookEventNameType, } from '../Shared' -import { ReactComponent as ArrowDown } from '../Assets/Icon/ic-chevron-down.svg' +import { ReactComponent as ArrowDown } from '@Icons/ic-chevron-down.svg' +import webhookIcon from '@Icons/ic-webhook.svg' +import branchIcon from '@Icons/ic-branch.svg' +import regexIcon from '@Icons/ic-regex.svg' +import pullRequest from '@Icons/ic-pull-request.svg' +import tagIcon from '@Icons/ic-tag.svg' +import { SourceTypeMap } from '@Common/Common.service' export function showError(serverError, showToastOnUnknownError = true, hideAccessError = false) { if (serverError instanceof ServerErrors && Array.isArray(serverError.errors)) { @@ -956,6 +963,29 @@ export const throttle = unknown>( } } +/** + * + * @param sourceType - SourceTypeMap + * @param _isRegex - boolean + * @param webhookEventName - WebhookEventNameType + * @returns - Icon + */ +export const getBranchIcon = (sourceType, _isRegex?: boolean, webhookEventName?: string) => { + if (sourceType === SourceTypeMap.WEBHOOK) { + if (webhookEventName === WebhookEventNameType.PULL_REQUEST) { + return pullRequest + } + if (webhookEventName === WebhookEventNameType.TAG_CREATION) { + return tagIcon + } + return webhookIcon + } + if (sourceType === SourceTypeMap.BranchRegex || _isRegex) { + return regexIcon + } + return branchIcon +} + // TODO: Might need to expose sandbox and referrer policy export const getSanitizedIframe = (iframeString: string) => DOMPurify.sanitize(iframeString, { diff --git a/src/Shared/Components/CICDHistory/CiPipelineSourceConfig.tsx b/src/Shared/Components/CICDHistory/CiPipelineSourceConfig.tsx index da874cb0f..a5f42a03f 100644 --- a/src/Shared/Components/CICDHistory/CiPipelineSourceConfig.tsx +++ b/src/Shared/Components/CICDHistory/CiPipelineSourceConfig.tsx @@ -16,24 +16,11 @@ import { useState, useEffect, ReactNode } from 'react' import Tippy from '@tippyjs/react' -import { getWebhookEventsForEventId, SourceTypeMap } from '../../../Common' +import { ReactComponent as Info } from '@Icons/ic-info-outlined.svg' +import { getBranchIcon, getWebhookEventsForEventId, SourceTypeMap } from '../../../Common' import { GIT_BRANCH_NOT_CONFIGURED, DEFAULT_GIT_BRANCH_VALUE } from './constants' -import webhookIcon from '../../../Assets/Icon/ic-webhook.svg' -import branchIcon from '../../../Assets/Icon/ic-branch.svg' -import { ReactComponent as Info } from '../../../Assets/Icon/ic-info-outlined.svg' -import regexIcon from '../../../Assets/Icon/ic-regex.svg' import { buildHoverHtmlForWebhook } from './utils' - -export interface CIPipelineSourceConfigInterface { - sourceType - sourceValue - showTooltip?: boolean - showIcons?: boolean - baseText?: string - regex?: any - isRegex?: boolean - primaryBranchAfterRegex?: string -} +import { CIPipelineSourceConfigInterface } from './types' export const CiPipelineSourceConfig = ({ sourceType, @@ -44,11 +31,12 @@ export const CiPipelineSourceConfig = ({ regex, isRegex, primaryBranchAfterRegex, + rootClassName = '', }: CIPipelineSourceConfigInterface) => { const _isWebhook = sourceType === SourceTypeMap.WEBHOOK const _isRegex = sourceType === SourceTypeMap.BranchRegex || !!regex || isRegex - const [sourceValueBase, setSourceValueBase] = useState('') + const [sourceValueBase, setSourceValueBase] = useState('') const [sourceValueAdv, setSourceValueAdv] = useState('') const [loading, setLoading] = useState(!!_isWebhook) @@ -97,7 +85,7 @@ export const CiPipelineSourceConfig = ({ )} ) - // for non webhook case, data is already set in use state initialisation + // for non webhook case, data is already set in use state initialization function _init() { if (!_isWebhook) { return @@ -130,16 +118,14 @@ export const CiPipelineSourceConfig = ({ regexTippyContent() }, []) - const isRegexOrBranchIcon = _isRegex ? regexIcon : branchIcon - return ( -
+
{loading && showIcons && loading} {!loading && (
{showIcons && ( branch @@ -170,7 +156,7 @@ export const CiPipelineSourceConfig = ({ )} {baseText && ( - + {baseText} )} diff --git a/src/Shared/Components/CICDHistory/types.tsx b/src/Shared/Components/CICDHistory/types.tsx index 7c5963fe0..ea6bb5936 100644 --- a/src/Shared/Components/CICDHistory/types.tsx +++ b/src/Shared/Components/CICDHistory/types.tsx @@ -791,3 +791,15 @@ export type CreateMarkupPropsType = export type TriggerHistoryFilterCriteriaType = `${string}|${string}|${string}`[] export const terminalStatus = new Set(['error', 'healthy', 'succeeded', 'cancelled', 'failed', 'aborted']) export const statusSet = new Set(['starting', 'running', 'pending']) + +export interface CIPipelineSourceConfigInterface { + sourceType: string + sourceValue: any // TODO: need to make source value consistent + showTooltip?: boolean + showIcons?: boolean + baseText?: string + regex?: any + isRegex?: boolean + primaryBranchAfterRegex?: string + rootClassName?: string +} diff --git a/src/Shared/Components/CICDHistory/utils.tsx b/src/Shared/Components/CICDHistory/utils.tsx index ab92dab69..69cf27a64 100644 --- a/src/Shared/Components/CICDHistory/utils.tsx +++ b/src/Shared/Components/CICDHistory/utils.tsx @@ -16,6 +16,17 @@ import { TIMELINE_STATUS } from '@Shared/constants' import { ReactComponent as ICAborted } from '@Icons/ic-aborted.svg' import { ReactComponent as ICErrorCross } from '@Icons/ic-error-cross.svg' +import { ReactComponent as Close } from '@Icons/ic-close.svg' +import { ReactComponent as Check } from '@Icons/ic-check-grey.svg' +import { ReactComponent as ICHelpOutline } from '@Icons/ic-help-outline.svg' +import { ReactComponent as Error } from '@Icons/ic-error-exclamation.svg' +import { ReactComponent as Timer } from '@Icons/ic-timer.svg' +import { ReactComponent as Disconnect } from '@Icons/ic-disconnected.svg' +import { ReactComponent as TimeOut } from '@Icons/ic-timeout-red.svg' +import { ReactComponent as ICCheck } from '@Icons/ic-check.svg' +import { ReactComponent as ICInProgress } from '@Icons/ic-in-progress.svg' +import { TERMINAL_STATUS_MAP } from './constants' +import { ResourceKindType } from '../../types' import { TriggerHistoryFilterCriteriaProps, DeploymentHistoryResultObject, @@ -23,17 +34,6 @@ import { TriggerHistoryFilterCriteriaType, StageStatusType, } from './types' -import { ResourceKindType } from '../../types' -import { ReactComponent as Close } from '../../../Assets/Icon/ic-close.svg' -import { ReactComponent as Check } from '../../../Assets/Icon/ic-check-grey.svg' -import { ReactComponent as ICHelpOutline } from '../../../Assets/Icon/ic-help-outline.svg' -import { ReactComponent as Error } from '../../../Assets/Icon/ic-error-exclamation.svg' -import { ReactComponent as Timer } from '../../../Assets/Icon/ic-timer.svg' -import { ReactComponent as Disconnect } from '../../../Assets/Icon/ic-disconnected.svg' -import { ReactComponent as TimeOut } from '../../../Assets/Icon/ic-timeout-red.svg' -import { ReactComponent as ICCheck } from '../../../Assets/Icon/ic-check.svg' -import { ReactComponent as ICInProgress } from '../../../Assets/Icon/ic-in-progress.svg' -import { TERMINAL_STATUS_MAP } from './constants' export const getTriggerHistoryFilterCriteria = ({ appId, diff --git a/src/Shared/Components/GitCommitInfoGeneric/GitCommitInfoGeneric.tsx b/src/Shared/Components/GitCommitInfoGeneric/GitCommitInfoGeneric.tsx index 4da369fef..7f3e60dca 100644 --- a/src/Shared/Components/GitCommitInfoGeneric/GitCommitInfoGeneric.tsx +++ b/src/Shared/Components/GitCommitInfoGeneric/GitCommitInfoGeneric.tsx @@ -15,23 +15,23 @@ */ /* eslint-disable eqeqeq */ -import { useState } from 'react' import moment from 'moment' import Tippy from '@tippyjs/react' import ClipboardButton from '@Common/ClipboardButton/ClipboardButton' import { ReactComponent as Circle } from '@Icons/ic-circle.svg' import { ReactComponent as Commit } from '@Icons/ic-commit.svg' -import { ReactComponent as CommitIcon } from '@Icons/ic-code-commit.svg' import { ReactComponent as PersonIcon } from '@Icons/ic-person.svg' import { ReactComponent as CalendarIcon } from '@Icons/ic-calendar.svg' import { ReactComponent as MessageIcon } from '@Icons/ic-message.svg' -import { ReactComponent as BranchIcon } from '@Icons/ic-branch.svg' -import { ReactComponent as BranchMain } from '@Icons/ic-branch-main.svg' +import { ReactComponent as PullRequestIcon } from '@Icons/ic-pull-request.svg' import { ReactComponent as Check } from '@Icons/ic-check-circle.svg' import { ReactComponent as Abort } from '@Icons/ic-abort.svg' -import { SourceTypeMap, createGitCommitUrl } from '@Common/Common.service' +import { SourceTypeMap, createGitCommitUrl, getGitBranchUrl } from '@Common/Common.service' import { stopPropagation } from '@Common/Helper' -import { DATE_TIME_FORMATS } from '@Common/Constants' +import { DATE_TIME_FORMATS, GitProviderType } from '@Common/Constants' +import { ReactComponent as Tag } from '@Icons/ic-tag.svg' +import { getLowerCaseObject, getWebhookDate } from '@Shared/Helpers' +import { ReactComponent as Hash } from '@Icons/ic-hash.svg' import GitMaterialInfoHeader from './GitMaterialInfoHeader' import { MATERIAL_EXCLUDE_TIPPY_TEXT } from '../../constants' import { WEBHOOK_EVENT_ACTION_TYPE } from './constants' @@ -44,141 +44,67 @@ const GitCommitInfoGeneric = ({ selectedCommitInfo, materialUrl, showMaterialInfoHeader, - canTriggerBuild = false, index, isExcluded = false, }: GitCommitInfoGenericProps) => { - const [showSeeMore, setShowSeeMore] = useState(true) - - function _lowerCaseObject(input): any { - const _output = {} - if (!input) { - return _output - } - Object.keys(input).forEach((_key) => { - const _modifiedKey = _key.toLowerCase() - const _value = input[_key] - if (_value && typeof _value === 'object') { - _output[_modifiedKey] = _lowerCaseObject(_value) - } else { - _output[_modifiedKey] = _value - } - }) - return _output - } - - const _lowerCaseCommitInfo = _lowerCaseObject(commitInfo) + const lowerCaseCommitInfo = getLowerCaseObject(commitInfo) const _isWebhook = materialSourceType === SourceTypeMap.WEBHOOK || - (_lowerCaseCommitInfo && _lowerCaseCommitInfo.webhookdata && _lowerCaseCommitInfo.webhookdata.id !== 0) - const _webhookData = _isWebhook ? _lowerCaseCommitInfo.webhookdata : {} + (lowerCaseCommitInfo && lowerCaseCommitInfo.webhookdata && lowerCaseCommitInfo.webhookdata.id !== 0) + const _webhookData = _isWebhook ? lowerCaseCommitInfo.webhookdata : {} // eslint-disable-next-line no-nested-ternary const _commitUrl = _isWebhook ? null - : _lowerCaseCommitInfo.commiturl - ? _lowerCaseCommitInfo.commiturl - : createGitCommitUrl(materialUrl, _lowerCaseCommitInfo.commit) + : lowerCaseCommitInfo.commiturl + ? lowerCaseCommitInfo.commiturl + : createGitCommitUrl(materialUrl, lowerCaseCommitInfo.commit) - function renderBasicGitCommitInfoForWebhook() { - let _date - if (_webhookData.data.date) { - const _moment = moment(_webhookData.data.date, 'YYYY-MM-DDTHH:mm:ssZ') - _date = _moment.isValid() ? _moment.format(DATE_TIME_FORMATS.TWELVE_HOURS_FORMAT) : _webhookData.data.date - } + const renderBranchName = (branchName: string) => + branchName ? ( + + {branchName} + + ) : null + + function renderBasicGitCommitInfoForWebhook(isPRWebhook?: boolean) { + const _date = getWebhookDate(materialSourceType, commitInfo) return ( - <> +
+ {isPRWebhook ? ( +
+ +
+ Merge commit into  + {renderBranchName(_webhookData.data['target branch name'])} +  from  + {renderBranchName(_webhookData.data['source branch name'])} +
+
+ ) : null} {_webhookData.data.author ? ( -
+
{_webhookData.data.author}
) : null} {_date ? ( -
+
) : null} {_webhookData.data.message ? ( -
+
{_webhookData.data.message}
) : null} - - ) - } - - function renderMoreDataForWebhook(_moreData) { - return !showSeeMore ? ( -
-
- {Object.keys(_moreData).map((_key, idx) => { - let classes - if (idx % 2 == 0) { - classes = 'bcn-1' - } - return ( -
-
{_key}
-
{_moreData[_key]}
-
- ) - })} -
- ) : null - } - - function renderSeeMoreButtonForWebhook() { - return ( - - ) - } - - function handleMoreDataForWebhook() { - const _moreData = {} - if (_webhookData.eventactiontype === WEBHOOK_EVENT_ACTION_TYPE.MERGED) { - Object.keys(_webhookData.data).forEach((_key) => { - if ( - _key != 'author' && - _key != 'date' && - _key != 'git url' && - _key != 'source branch name' && - _key != 'source checkout' && - _key != 'target branch name' && - _key != 'target checkout' && - _key != 'title' - ) { - _moreData[_key] = _webhookData.data[_key] - } - }) - } else if (_webhookData.eventactiontype === WEBHOOK_EVENT_ACTION_TYPE.NON_MERGED) { - Object.keys(_webhookData.data).forEach((_key) => { - if (_key !== 'author' && _key !== 'date' && _key !== 'target checkout') { - _moreData[_key] = _webhookData.data[_key] - } - }) - } - - const _hasMoreData = Object.keys(_moreData).length > 0 - - return ( - <> - {_hasMoreData && renderMoreDataForWebhook(_moreData)} - {_hasMoreData && renderSeeMoreButtonForWebhook()} - ) } @@ -207,15 +133,89 @@ const GitCommitInfoGeneric = ({ } const renderCommitStatus = () => { - if (_lowerCaseCommitInfo.isselected) { + if (lowerCaseCommitInfo.isselected) { return } return matSelectionText() } + const renderWebhookTitle = () => + _webhookData.data.title ? {_webhookData.data.title} : null + + const renderPullRequestId = (pullRequestUrl: string) => { + const pullRequestId = pullRequestUrl?.split('/').pop() + + return ( + + ) + } + + const renderTagCreationId = (tagRequestUrl: string) => ( +
+ + {tagRequestUrl} +
+ ) + + const getCheckUncheckIcon = () => { + if (selectedCommitInfo) { + if (lowerCaseCommitInfo.isselected) { + return + } + return + } + return null + } + + const renderPRInfoCard = () => ( +
+
+ {renderPullRequestId(_webhookData.data['git url'])} + {getCheckUncheckIcon()} +
+ {renderWebhookTitle()} + {renderBasicGitCommitInfoForWebhook(true)} +
+ ) + + const renderTagInfoCard = () => ( + <> +
+ {renderTagCreationId(_webhookData.data['target checkout'])} + {getCheckUncheckIcon()} +
+ {renderBasicGitCommitInfoForWebhook()} + + ) + + const renderWebhookGitInfoCard = () => { + if (!_isWebhook) return null + + const isMerged = _webhookData.eventactiontype === WEBHOOK_EVENT_ACTION_TYPE.MERGED + + if (materialUrl.includes(GitProviderType.GITLAB)) { + // TODO: This is a temporary fix for the issue where the eventActionType data incorrect + return isMerged ? renderTagInfoCard() : renderPRInfoCard() + } + return isMerged ? renderPRInfoCard() : renderTagInfoCard() + } + return (
- {showMaterialInfoHeader && (_isWebhook || _lowerCaseCommitInfo.commit) && ( + {showMaterialInfoHeader && (_isWebhook || lowerCaseCommitInfo.commit) && ( {!_isWebhook && ( <> - {_lowerCaseCommitInfo.commit && ( + {lowerCaseCommitInfo.commit && (
{_commitUrl ? (
@@ -243,163 +243,49 @@ const GitCommitInfoGeneric = ({ data-testid={`git-commit-credential${index}`} > - {_lowerCaseCommitInfo.commit.slice(0, 7)} + {lowerCaseCommitInfo.commit.slice(0, 7)}
- +
) : null} {selectedCommitInfo ? renderCommitStatus() : null}
)} - {_lowerCaseCommitInfo.message ? ( + {lowerCaseCommitInfo.message ? (
- {_lowerCaseCommitInfo.message} + {lowerCaseCommitInfo.message}
) : null}
- {_lowerCaseCommitInfo.author ? ( + {lowerCaseCommitInfo.author ? (
- {_lowerCaseCommitInfo.author} + {lowerCaseCommitInfo.author}
) : null} - {_lowerCaseCommitInfo.date ? ( + {lowerCaseCommitInfo.date ? (
- {moment(_lowerCaseCommitInfo.date).format( - DATE_TIME_FORMATS.TWELVE_HOURS_FORMAT, - )} + {moment(lowerCaseCommitInfo.date).format(DATE_TIME_FORMATS.TWELVE_HOURS_FORMAT)}
) : null}
)} - - {_isWebhook && _webhookData.eventactiontype === WEBHOOK_EVENT_ACTION_TYPE.MERGED && ( - <> -
-
- {_webhookData.data.title ? ( -
{_webhookData.data.title}
- ) : null} - {_webhookData.data['git url'] ? ( - - View git url - - ) : null} -
- {selectedCommitInfo ? ( -
- {_lowerCaseCommitInfo.isselected ? ( - - ) : ( - - )} -
- ) : null} -
- -
-
- -
-
- {_webhookData.data['source branch name'] ? ( -
- {' '} - {_webhookData.data['source branch name']} -
- ) : null} - {_webhookData.data['source checkout'] ? ( - - ) : null} -
-
-
- {_webhookData.data['target branch name'] ? ( - <> - {' '} - {_webhookData.data['target branch name']}{' '} - - ) : null} -
-
- {canTriggerBuild && ( -
- - HEAD -
- )} - {!canTriggerBuild && ( - - - {_webhookData.data['target checkout']} - - )} -
-
-
-
-
- {renderBasicGitCommitInfoForWebhook()} - {handleMoreDataForWebhook()} - - )} - {_isWebhook && _webhookData.eventactiontype === WEBHOOK_EVENT_ACTION_TYPE.NON_MERGED && ( - <> -
-
{_webhookData.data['target checkout']}
- {selectedCommitInfo ? ( -
- {_lowerCaseCommitInfo.isselected ? : 'Select'} -
- ) : null} -
- {renderBasicGitCommitInfoForWebhook()} - {handleMoreDataForWebhook()} - - )} + {renderWebhookGitInfoCard()}
) diff --git a/src/Shared/Components/KeyValueTable/KeyValueTable.scss b/src/Shared/Components/KeyValueTable/KeyValueTable.scss index efe43bb85..2aaba811c 100644 --- a/src/Shared/Components/KeyValueTable/KeyValueTable.scss +++ b/src/Shared/Components/KeyValueTable/KeyValueTable.scss @@ -19,11 +19,11 @@ gap: 1px; &.two-columns-top-row { - grid-template-columns: 20% 1fr; + grid-template-columns: 30% 1fr; } &.two-columns { - grid-template-columns: 20% 1fr; + grid-template-columns: 30% 1fr; .key-value-table__row:last-of-type { .key-value-table__cell:first-child, @@ -41,7 +41,7 @@ } &.three-columns { - grid-template-columns: 20% 1fr 32px; + grid-template-columns: 30% 1fr 32px; .key-value-table__row:last-of-type { .key-value-table__cell:first-child, diff --git a/src/Shared/Components/MaterialHistory/MaterialHistory.component.tsx b/src/Shared/Components/MaterialHistory/MaterialHistory.component.tsx index a1b534ee9..3d7c84b2c 100644 --- a/src/Shared/Components/MaterialHistory/MaterialHistory.component.tsx +++ b/src/Shared/Components/MaterialHistory/MaterialHistory.component.tsx @@ -14,6 +14,9 @@ * limitations under the License. */ +import { getWebhookDate } from '@Shared/Helpers' +import { MaterialHistoryType } from '@Shared/Services' +import { useMemo } from 'react' import { SourceTypeMap } from '../../../Common' import { GitCommitInfoGeneric } from '../GitCommitInfoGeneric' import { MaterialHistoryProps } from './types' @@ -32,34 +35,35 @@ const MaterialHistory = ({ } } - const getMaterialHistoryMapWithTime = () => { - const historyTimeMap = {} - - material.history?.forEach((history) => { - const newDate = history.date.substring(0, 16) - - if (!historyTimeMap[newDate]) { - historyTimeMap[newDate] = [] - } - historyTimeMap[newDate].push(history) - }) + const materialHistoryMapWithTime = useMemo( + () => + material.history.reduce>((acc, historyElem: MaterialHistoryType) => { + const isWebhook = material.type === SourceTypeMap.WEBHOOK + const newDate = isWebhook + ? getWebhookDate(material.type, historyElem).substring(0, 16) + : historyElem.date.substring(0, 16) + if (!acc[newDate]) { + acc[newDate] = [] + } + acc[newDate].push(historyElem) + return acc + }, {}), + [material.history, material.type], + ) - return historyTimeMap - } // Retrieve the history map - const materialHistoryMapWithTime = getMaterialHistoryMapWithTime() // Retrieve the keys of the history map const dateKeys = Object.keys(materialHistoryMapWithTime) return ( // added for consistent typing // eslint-disable-next-line react/jsx-no-useless-fragment - <> +
{dateKeys.map((date) => { const historyList = materialHistoryMapWithTime[date] return ( <> - {!isCommitInfoModal && material.type !== SourceTypeMap.WEBHOOK && ( + {!isCommitInfoModal && (
{date}
@@ -87,7 +91,6 @@ const MaterialHistory = ({ materialSourceType={material.type} selectedCommitInfo={selectCommit} materialSourceValue={material.value} - canTriggerBuild={!history.excluded} isExcluded={history.excluded} />
@@ -96,7 +99,7 @@ const MaterialHistory = ({ ) })} - +
) } export default MaterialHistory diff --git a/src/Shared/Helpers.tsx b/src/Shared/Helpers.tsx index 5eaac04f8..8f5e8af10 100644 --- a/src/Shared/Helpers.tsx +++ b/src/Shared/Helpers.tsx @@ -19,6 +19,7 @@ import { useEffect, useRef, useState, ReactElement } from 'react' import Tippy from '@tippyjs/react' import { Pair } from 'yaml' import moment from 'moment' +import { MaterialHistoryType } from '@Shared/Services/app.types' import { handleUTCTime, ManualApprovalType, @@ -30,6 +31,8 @@ import { PATTERNS, ZERO_TIME_STRING, noop, + SourceTypeMap, + DATE_TIME_FORMATS, } from '../Common' import { AggregationKeys, @@ -852,3 +855,40 @@ export const groupArrayByObjectKey = , K extends k }, {} as Record, ) + +/** + * @description - Function to get the lower case object + * @param input - The input object + * @returns Record + */ +export const getLowerCaseObject = (input): Record => { + if (!input || typeof input !== 'object') { + return input + } + return Object.keys(input).reduce((acc, key) => { + const modifiedKey = key.toLowerCase() + const value = input[key] + if (value && typeof value === 'object') { + acc[modifiedKey] = getLowerCaseObject(value) + } else { + acc[modifiedKey] = value + } + return acc + }, {}) +} + +/** + * @description - Function to get the webhook date + * @param materialSourceType - The type of material source (e.g., WEBHOOK) + * @param history - The history object containing commit information + * @returns - Formatted webhook date if available, otherwise an empty string + */ + +export const getWebhookDate = (materialSourceType: string, history: MaterialHistoryType): string => { + const lowerCaseCommitInfo = getLowerCaseObject(history) + const isWebhook = materialSourceType === SourceTypeMap.WEBHOOK || lowerCaseCommitInfo?.webhookdata?.id !== 0 + const webhookData = isWebhook ? lowerCaseCommitInfo.webhookdata : {} + + const _moment = moment(webhookData.data.date, 'YYYY-MM-DDTHH:mm:ssZ') + return _moment.isValid() ? _moment.format(DATE_TIME_FORMATS.TWELVE_HOURS_FORMAT) : webhookData.data.date +} diff --git a/src/Shared/Services/app.types.ts b/src/Shared/Services/app.types.ts index a580762a2..e2192d00d 100644 --- a/src/Shared/Services/app.types.ts +++ b/src/Shared/Services/app.types.ts @@ -31,7 +31,7 @@ interface MaterialHistoryDTO { WebhookData: WebhookDataType } -interface MaterialHistoryType { +export interface MaterialHistoryType { commitURL: string commit: MaterialHistoryDTO['Commit'] author: MaterialHistoryDTO['Author'] @@ -84,6 +84,7 @@ export interface CIMaterialType gitURL: CIMaterialDTO['url'] history: MaterialHistoryType[] isSelected: boolean + gitMaterialUrl?: string } interface ImageCommentDTO {