mirror of https://github.com/harness/drone.git
feat: [code-2337] add support for webhook execution logs (#2681)
* fix: [code-2337] address comments * fix: [code-2337] increase drawer width to 50% * fix: [code-2337] editor to scroll beyond last line * fix: [code-2337] event title * fix: [code-2337] remove commented code * feat: [code-2337] add support for webhook execution logsCODE-2402
parent
bdc01e85f7
commit
55c6cacbde
|
@ -108,9 +108,9 @@ const BranchProtectionForm = (props: {
|
|||
const { data: statuses } = useGet<string[]>({
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/checks/recent`,
|
||||
queryParams: {
|
||||
query: searchStatusTerm,
|
||||
debounce: 500
|
||||
}
|
||||
query: searchStatusTerm
|
||||
},
|
||||
debounce: 500
|
||||
})
|
||||
const statusOptions: SelectOption[] = useMemo(
|
||||
() =>
|
||||
|
|
|
@ -41,6 +41,7 @@ export interface StringsMap {
|
|||
ascending: string
|
||||
assignPeople: string
|
||||
at: string
|
||||
atSubTitle: string
|
||||
attachText: string
|
||||
basedOn: string
|
||||
behindDivergence: string
|
||||
|
@ -358,6 +359,9 @@ export interface StringsMap {
|
|||
enterUser: string
|
||||
error: string
|
||||
error404Text: string
|
||||
event: string
|
||||
executionHistory: string
|
||||
executionId: string
|
||||
'executions.canceledTime': string
|
||||
'executions.completedTime': string
|
||||
'executions.description': string
|
||||
|
@ -565,6 +569,7 @@ export interface StringsMap {
|
|||
'labels.updateLabel': string
|
||||
'labels.updated': string
|
||||
language: string
|
||||
lastTriggeredAt: string
|
||||
leaveAComment: string
|
||||
license: string
|
||||
lineBreaks: string
|
||||
|
@ -626,6 +631,8 @@ export interface StringsMap {
|
|||
noCommits: string
|
||||
noCommitsMessage: string
|
||||
noCommitsPR: string
|
||||
noExecutionsFound: string
|
||||
noExecutionsFoundForWebhook: string
|
||||
noExpiration: string
|
||||
noExpirationDate: string
|
||||
noFilterResultMessage: string
|
||||
|
@ -637,6 +644,7 @@ export interface StringsMap {
|
|||
noWebHooks: string
|
||||
none: string
|
||||
noneYet: string
|
||||
notRetriggerableMessage: string
|
||||
off: string
|
||||
ok: string
|
||||
on: string
|
||||
|
@ -855,6 +863,7 @@ export interface StringsMap {
|
|||
pullRequestalreadyExists: string
|
||||
pullRequests: string
|
||||
quote: string
|
||||
reTriggeredExecution: string
|
||||
reactivate: string
|
||||
readMe: string
|
||||
reader: string
|
||||
|
@ -903,6 +912,7 @@ export interface StringsMap {
|
|||
repositoryName: string
|
||||
reqChanges: string
|
||||
requestChanges: string
|
||||
requestPayload: string
|
||||
required: string
|
||||
resetZoom: string
|
||||
resolve: string
|
||||
|
@ -911,6 +921,7 @@ export interface StringsMap {
|
|||
resolvedComments: string
|
||||
restoreBranch: string
|
||||
results: string
|
||||
retriggerExecution: string
|
||||
reviewProjectSettings: string
|
||||
reviewerNotFound: string
|
||||
reviewers: string
|
||||
|
@ -973,6 +984,7 @@ export interface StringsMap {
|
|||
selectToViewMore: string
|
||||
selectUsers: string
|
||||
'semanticSearch.sampleQueries': string
|
||||
serverResponse: string
|
||||
setAsAdmin: string
|
||||
setting: string
|
||||
settings: string
|
||||
|
@ -1048,6 +1060,7 @@ export interface StringsMap {
|
|||
token: string
|
||||
tooltipRepoEdit: string
|
||||
top: string
|
||||
triggeredEvent: string
|
||||
'triggers.actions': string
|
||||
'triggers.createSuccess': string
|
||||
'triggers.createTrigger': string
|
||||
|
@ -1142,9 +1155,11 @@ export interface StringsMap {
|
|||
webhookPRMerged: string
|
||||
webhookPRReopened: string
|
||||
webhookPRUpdated: string
|
||||
webhookPage: string
|
||||
webhookSelectAllEvents: string
|
||||
webhookSelectIndividualEvents: string
|
||||
webhookSelectPushEvents: string
|
||||
webhookTabs: string
|
||||
webhookTagCreated: string
|
||||
webhookTagDeleted: string
|
||||
webhookTagUpdated: string
|
||||
|
|
|
@ -420,7 +420,22 @@ webhookPRClosed: PR closed
|
|||
webhookPRCommentCreated: PR comment created
|
||||
webhookPRMerged: PR merged
|
||||
nameYourWebhook: Name your webhook
|
||||
noExecutionsFound: No Executions found
|
||||
noExecutionsFoundForWebhook: No executions found for the given webhook
|
||||
executionHistory: Execution History
|
||||
serverResponse: Server Response
|
||||
requestPayload: Request Payload
|
||||
triggeredEvent: Triggered Event
|
||||
event: Event
|
||||
lastTriggeredAt: Last Triggered At
|
||||
executionId: Execution ID
|
||||
submitReview: Submit Review
|
||||
webhookPage: Webhook page
|
||||
webhookTabs: WebhookTabs
|
||||
reTriggeredExecution: Re-triggered Execution
|
||||
retriggerExecution: Re-trigger Execution
|
||||
atSubTitle: At
|
||||
notRetriggerableMessage: This webhook execution cannot be re-triggered
|
||||
approve: Approve
|
||||
requestChanges: Changes Requested
|
||||
repoEmptyMarkdown: |
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
.main {
|
||||
min-height: calc(var(--page-height) - 160px);
|
||||
background-color: var(--primary-bg) !important;
|
||||
width: 100%;
|
||||
margin: var(--spacing-small);
|
||||
:global {
|
||||
.bp3-tab {
|
||||
width: fit-content !important;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.bp3-tab-panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bp3-tab {
|
||||
margin-top: 20px;
|
||||
margin-bottom: unset !important;
|
||||
}
|
||||
|
||||
.bp3-tab-list .bp3-tab[aria-selected='true'] {
|
||||
background-color: var(--grey-0);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-bottom: 2px solid var(--primary-7);
|
||||
border-bottom-left-radius: 0px !important;
|
||||
border-bottom-right-radius: 0px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabsContainer {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
background-color: var(--primary-bg) !important;
|
||||
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
> div > div[role='tablist'] {
|
||||
background-color: var(--white) !important;
|
||||
padding-left: var(--spacing-large) !important;
|
||||
padding-right: var(--spacing-xlarge) !important;
|
||||
border-bottom: 1px solid var(--grey-200) !important;
|
||||
}
|
||||
|
||||
> div > div[role='tabpanel'] {
|
||||
margin-top: 0;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
[aria-selected='true'] {
|
||||
.tabTitle,
|
||||
.tabTitle:hover {
|
||||
color: var(--grey-900) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle {
|
||||
font-weight: 500;
|
||||
color: var(--grey-700);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin-top: var(--spacing-8);
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle:not:first-child {
|
||||
margin-left: var(--spacing-8) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.headerContainer {
|
||||
border-bottom: unset !important;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const headerContainer: string
|
||||
export declare const main: string
|
||||
export declare const tabsContainer: string
|
||||
export declare const tabTitle: string
|
|
@ -14,52 +14,75 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react'
|
||||
import { Container, PageBody } from '@harnessio/uicore'
|
||||
import { useGet } from 'restful-react'
|
||||
import React, { useEffect } from 'react'
|
||||
import cx from 'classnames'
|
||||
import { PageBody, Container, Tabs } from '@harnessio/uicore'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import type { OpenapiWebhookType } from 'services/code'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { RepositoryPageHeader } from 'components/RepositoryPageHeader/RepositoryPageHeader'
|
||||
import { WehookForm } from 'pages/WebhookNew/WehookForm'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { PageBrowserProps, getErrorMessage, voidFn } from 'utils/Utils'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { WebhookTabs } from 'utils/GitUtils'
|
||||
import WebhookDetailsTab from 'pages/WebhookDetailsTab/WebhookDetailsTab'
|
||||
import WebhookExecutions from 'pages/WebhookExecutions/WebhookExecutions'
|
||||
import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams'
|
||||
import { useQueryParams } from 'hooks/useQueryParams'
|
||||
import css from './Webhook.module.scss'
|
||||
|
||||
export default function WebhookDetails() {
|
||||
const { repoMetadata, error, loading, refetch, webhookId } = useGetRepositoryMetadata()
|
||||
const queryParams = useQueryParams<PageBrowserProps>()
|
||||
const { replaceQueryParams } = useUpdateQueryParams()
|
||||
const { getString } = useStrings()
|
||||
const { routes } = useAppContext()
|
||||
const { repoMetadata, error, loading, webhookId, refetch: refreshMetadata } = useGetRepositoryMetadata()
|
||||
const {
|
||||
data,
|
||||
loading: webhookLoading,
|
||||
error: webhookError,
|
||||
refetch: refetchWebhook
|
||||
} = useGet<OpenapiWebhookType>({
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/webhooks/${webhookId}`,
|
||||
lazy: !repoMetadata
|
||||
|
||||
useEffect(() => {
|
||||
if (!queryParams.tab) {
|
||||
replaceQueryParams({ ...queryParams, tab: WebhookTabs.DETAILS })
|
||||
}
|
||||
})
|
||||
|
||||
const tabListArray = [
|
||||
{
|
||||
id: WebhookTabs.DETAILS,
|
||||
title: getString('details'),
|
||||
panel: (
|
||||
<Container padding={'large'}>
|
||||
<WebhookDetailsTab />
|
||||
</Container>
|
||||
)
|
||||
},
|
||||
{
|
||||
id: WebhookTabs.EXECUTIONS,
|
||||
title: getString('pageTitle.executions'),
|
||||
panel: <WebhookExecutions />
|
||||
}
|
||||
]
|
||||
return (
|
||||
<Container>
|
||||
<Container className={css.main}>
|
||||
<RepositoryPageHeader
|
||||
className={css.headerContainer}
|
||||
repoMetadata={repoMetadata}
|
||||
title={getString('webhookDetails')}
|
||||
dataTooltipId="webhookDetails"
|
||||
extraBreadcrumbLinks={
|
||||
repoMetadata && [
|
||||
{
|
||||
label: getString('webhooks'),
|
||||
url: routes.toCODEWebhooks({ repoPath: repoMetadata.path as string })
|
||||
}
|
||||
]
|
||||
}
|
||||
title={`${getString('webhook')} : ${webhookId}`}
|
||||
dataTooltipId={getString('webhookPage')}
|
||||
/>
|
||||
<PageBody
|
||||
error={error || webhookError}
|
||||
retryOnError={() => (repoMetadata ? refetchWebhook() : refreshMetadata())}>
|
||||
<LoadingSpinner visible={loading || webhookLoading} withBorder={!!data && webhookLoading} />
|
||||
|
||||
{repoMetadata && data && <WehookForm isEdit webhook={data} repoMetadata={repoMetadata} />}
|
||||
<PageBody error={getErrorMessage(error)} retryOnError={voidFn(refetch)}>
|
||||
<LoadingSpinner visible={loading} />
|
||||
{repoMetadata && (
|
||||
<Container className={cx(css.main, css.tabsContainer)}>
|
||||
<Tabs
|
||||
id={getString('webhookTabs')}
|
||||
large={false}
|
||||
selectedTabId={queryParams.tab}
|
||||
animate={false}
|
||||
onChange={(id: WebhookTabs) => {
|
||||
if (id === WebhookTabs.DETAILS) {
|
||||
delete queryParams.page
|
||||
}
|
||||
replaceQueryParams({ ...queryParams, tab: id })
|
||||
}}
|
||||
tabList={tabListArray}></Tabs>
|
||||
</Container>
|
||||
)}
|
||||
</PageBody>
|
||||
</Container>
|
||||
)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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 from 'react'
|
||||
import { Container, PageBody } from '@harnessio/uicore'
|
||||
import { useGet } from 'restful-react'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import type { OpenapiWebhookType } from 'services/code'
|
||||
import { WehookForm } from 'pages/WebhookNew/WehookForm'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
|
||||
export default function WebhookDetails() {
|
||||
const { repoMetadata, error, loading, webhookId, refetch: refreshMetadata } = useGetRepositoryMetadata()
|
||||
const {
|
||||
data,
|
||||
loading: webhookLoading,
|
||||
error: webhookError,
|
||||
refetch: refetchWebhook
|
||||
} = useGet<OpenapiWebhookType>({
|
||||
path: `/api/v1/repos/${repoMetadata?.path}/+/webhooks/${webhookId}`,
|
||||
lazy: !repoMetadata
|
||||
})
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<PageBody
|
||||
error={error || webhookError}
|
||||
retryOnError={() => (repoMetadata ? refetchWebhook() : refreshMetadata())}>
|
||||
<LoadingSpinner visible={loading || webhookLoading} withBorder={!!data && webhookLoading} />
|
||||
{repoMetadata && data && <WehookForm isEdit webhook={data} repoMetadata={repoMetadata} />}
|
||||
</PageBody>
|
||||
</Container>
|
||||
)
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
.main {
|
||||
min-height: calc(var(--page-height) - 160px);
|
||||
width: 100%;
|
||||
:global {
|
||||
.bp3-tab {
|
||||
width: fit-content !important;
|
||||
height: 34px;
|
||||
}
|
||||
|
||||
.bp3-tab-panel {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bp3-tab {
|
||||
margin-top: 20px;
|
||||
margin-bottom: unset !important;
|
||||
}
|
||||
|
||||
.bp3-tab-list .bp3-tab[aria-selected='true'] {
|
||||
background-color: var(--grey-0);
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
border-bottom: 2px solid var(--primary-7);
|
||||
border-bottom-left-radius: 0px !important;
|
||||
border-bottom-right-radius: 0px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tabsContainer {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
> div > div[role='tablist'] {
|
||||
background-color: var(--white) !important;
|
||||
padding-left: var(--spacing-large) !important;
|
||||
padding-right: var(--spacing-xlarge) !important;
|
||||
border-bottom: 1px solid var(--grey-200) !important;
|
||||
}
|
||||
|
||||
> div > div[role='tabpanel'] {
|
||||
margin-top: 0;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
[aria-selected='true'] {
|
||||
.tabTitle,
|
||||
.tabTitle:hover {
|
||||
color: var(--grey-900) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle {
|
||||
font-weight: 500;
|
||||
color: var(--grey-700);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
margin-top: var(--spacing-8);
|
||||
|
||||
> svg {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.tabTitle:not:first-child {
|
||||
margin-left: var(--spacing-8) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.pageBody {
|
||||
min-height: 100% !important;
|
||||
}
|
||||
|
||||
.executionContext {
|
||||
padding: 2rem 1.8rem 1rem 1.8rem !important;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.errorMessage {
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.editor {
|
||||
height: 100% !important;
|
||||
:global(.bp3-drawer-header) {
|
||||
margin: 0 !important;
|
||||
padding-top: var(--spacing-5) !important;
|
||||
padding-bottom: var(--spacing-5) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.logsContainer {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.copyButton {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
z-index: 34;
|
||||
}
|
27
web/src/pages/WebhookExecutions/WebhookExecutionLogs/useWebhookLogDrawer.module.scss.d.ts
vendored
Normal file
27
web/src/pages/WebhookExecutions/WebhookExecutionLogs/useWebhookLogDrawer.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const copyButton: string
|
||||
export declare const editor: string
|
||||
export declare const errorMessage: string
|
||||
export declare const executionContext: string
|
||||
export declare const logsContainer: string
|
||||
export declare const main: string
|
||||
export declare const pageBody: string
|
||||
export declare const tabsContainer: string
|
||||
export declare const tabTitle: string
|
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copyright 2024 Harness, 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, { useMemo, useState } from 'react'
|
||||
import { Drawer, Position } from '@blueprintjs/core'
|
||||
import cx from 'classnames'
|
||||
import {
|
||||
Button,
|
||||
ButtonVariation,
|
||||
Container,
|
||||
Layout,
|
||||
PageBody,
|
||||
PageHeader,
|
||||
Tabs,
|
||||
Text,
|
||||
useToaster
|
||||
} from '@harnessio/uicore'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import MonacoEditor from 'react-monaco-editor'
|
||||
import { defaultTo, isEmpty } from 'lodash-es'
|
||||
import { useMutate } from 'restful-react'
|
||||
import moment from 'moment'
|
||||
import { Render } from 'react-jsx-match'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { CopyButton } from 'components/CopyButton/CopyButton'
|
||||
import { getErrorMessage } from 'utils/Utils'
|
||||
import { getConfig } from 'services/config'
|
||||
import { DateTimeWithLocalContentInline } from 'utils/timePopoverLocal/TimePopoverWithLocal'
|
||||
import { CodeIcon, ExecutionTabs, WebhookIndividualEvent, getEventDescription } from 'utils/GitUtils'
|
||||
import type { RepoRepositoryOutput, TypesWebhookExecution, TypesWebhookExecutionResponse } from 'services/code'
|
||||
import { useModalHook } from 'hooks/useModalHook'
|
||||
import css from './useWebhookLogDrawer.module.scss'
|
||||
|
||||
interface LogViewerProps {
|
||||
data?: string | TypesWebhookExecutionResponse
|
||||
}
|
||||
|
||||
export function useWeebhookLogDrawer(refetchExecutionList: () => Promise<void>) {
|
||||
const [executionData, setExecutionData] = useState<TypesWebhookExecution>()
|
||||
const [activeTab, setActiveTab] = useState<string>(ExecutionTabs.PAYLOAD)
|
||||
const [path, setPath] = useState('')
|
||||
const { mutate: retriggerExection } = useMutate({
|
||||
verb: 'POST',
|
||||
base: getConfig('code/api/v1'),
|
||||
path
|
||||
})
|
||||
const { getString } = useStrings()
|
||||
|
||||
const LogViewer = (props: LogViewerProps) => {
|
||||
const { data } = props
|
||||
return (
|
||||
<Container padding={'medium'} className={css.logsContainer}>
|
||||
<CopyButton
|
||||
content={JSON.stringify(data, null, 2)}
|
||||
className={css.copyButton}
|
||||
icon={CodeIcon.Copy}
|
||||
color={Color.PRIMARY_7}
|
||||
iconProps={{ size: 20 }}
|
||||
/>
|
||||
<MonacoEditor
|
||||
className={css.editor}
|
||||
height={'100vh'}
|
||||
language="json"
|
||||
value={JSON.stringify(data, null, 2)}
|
||||
data-testid="monaco-editor"
|
||||
theme="vs-dark"
|
||||
options={{
|
||||
fontFamily: "'Roboto Mono', monospace",
|
||||
fontSize: 13,
|
||||
scrollBeyondLastLine: true,
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
unicodeHighlight: {
|
||||
ambiguousCharacters: false
|
||||
},
|
||||
lineNumbers: 'on',
|
||||
glyphMargin: true,
|
||||
folding: false,
|
||||
lineDecorationsWidth: 60,
|
||||
wordWrap: 'on',
|
||||
scrollbar: {
|
||||
verticalScrollbarSize: 0
|
||||
},
|
||||
renderLineHighlight: 'none',
|
||||
wordWrapBreakBeforeCharacters: '',
|
||||
lineNumbersMinChars: 0,
|
||||
wordBasedSuggestions: 'off',
|
||||
readOnly: true
|
||||
}}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
const tabListArray = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: ExecutionTabs.PAYLOAD,
|
||||
title: ExecutionTabs.PAYLOAD,
|
||||
panel: <LogViewer data={JSON.parse(executionData?.request?.body ?? '{}')} />
|
||||
},
|
||||
{
|
||||
id: ExecutionTabs.SERVER_RESPONSE,
|
||||
title: ExecutionTabs.SERVER_RESPONSE,
|
||||
panel: <LogViewer data={executionData?.response} />
|
||||
}
|
||||
],
|
||||
[activeTab, executionData]
|
||||
)
|
||||
const { showSuccess, showError } = useToaster()
|
||||
const [openModal, hideModal] = useModalHook(
|
||||
() => (
|
||||
<Drawer position={Position.RIGHT} isOpen={true} isCloseButtonShown={true} size={'50%'} onClose={hideModal}>
|
||||
<PageHeader
|
||||
title={
|
||||
<Text icon={'execution'} iconProps={{ size: 24 }} font={{ variation: FontVariation.H4 }}>
|
||||
{executionData?.id}
|
||||
</Text>
|
||||
}
|
||||
content={
|
||||
<Button
|
||||
disabled={!executionData?.retriggerable}
|
||||
tooltipProps={{
|
||||
disabled: executionData?.retriggerable,
|
||||
position: Position.TOP,
|
||||
interactionKind: 'hover'
|
||||
}}
|
||||
tooltip={getString('notRetriggerableMessage')}
|
||||
variation={ButtonVariation.SECONDARY}
|
||||
onClick={() =>
|
||||
retriggerExection({})
|
||||
.then(() => {
|
||||
showSuccess(getString('reTriggeredExecution'))
|
||||
refetchExecutionList()
|
||||
})
|
||||
.catch(err => {
|
||||
showError(getErrorMessage(err))
|
||||
})
|
||||
}>
|
||||
{getString('retriggerExecution')}
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
<PageBody className={cx(css.pageBody)}>
|
||||
<Layout.Vertical className={css.executionContext}>
|
||||
<Layout.Horizontal spacing={'small'} flex={{ alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<Text font={{ variation: FontVariation.H6 }}>{getString('triggeredEvent')}: </Text>
|
||||
<Text color={Color.GREY_600}>
|
||||
{getEventDescription(executionData?.trigger_type as WebhookIndividualEvent)}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal spacing={'small'} flex={{ alignItems: 'center', justifyContent: 'flex-start' }}>
|
||||
<Text font={{ variation: FontVariation.H6 }}>{getString('atSubTitle')}: </Text>
|
||||
<Container>
|
||||
<DateTimeWithLocalContentInline time={defaultTo(executionData?.created as number, 0)} />
|
||||
</Container>
|
||||
</Layout.Horizontal>
|
||||
<Layout.Horizontal spacing={'small'}>
|
||||
<Text font={{ variation: FontVariation.H6 }}>Duration:</Text>
|
||||
<Text color={Color.GREY_600}>
|
||||
{Math.ceil(
|
||||
moment
|
||||
.duration((executionData?.duration ? executionData?.duration / 1_000_000 : 0) as number)
|
||||
.asSeconds()
|
||||
)}
|
||||
{'s'}
|
||||
</Text>
|
||||
</Layout.Horizontal>
|
||||
</Layout.Vertical>
|
||||
<Render when={!isEmpty(executionData?.error)}>
|
||||
<Container
|
||||
intent="danger"
|
||||
background="red100"
|
||||
border={{
|
||||
color: 'red500'
|
||||
}}
|
||||
margin={{ top: 'small', right: 'medium', left: 'medium' }}>
|
||||
<Text
|
||||
className={css.errorMessage}
|
||||
icon="error-outline"
|
||||
iconProps={{ size: 16, margin: { right: 'small' } }}
|
||||
padding={{ left: 'large', right: 'large', top: 'small', bottom: 'small' }}
|
||||
color={Color.ERROR}>
|
||||
{executionData?.error}
|
||||
</Text>
|
||||
</Container>
|
||||
</Render>
|
||||
<Container className={cx(css.main, css.tabsContainer)}>
|
||||
<Tabs
|
||||
id="WebhookExecutionLogs"
|
||||
large={false}
|
||||
defaultSelectedTabId={activeTab}
|
||||
animate={false}
|
||||
onChange={(id: string) => {
|
||||
setActiveTab(id)
|
||||
}}
|
||||
tabList={tabListArray}></Tabs>
|
||||
</Container>
|
||||
</PageBody>
|
||||
</Drawer>
|
||||
),
|
||||
[executionData, activeTab, path]
|
||||
)
|
||||
|
||||
const openExecutionLogs = (
|
||||
webhookExecution: TypesWebhookExecution,
|
||||
logTab: ExecutionTabs,
|
||||
repoMetadata?: RepoRepositoryOutput
|
||||
) => {
|
||||
setExecutionData(webhookExecution)
|
||||
setActiveTab(logTab)
|
||||
setPath(
|
||||
`/repos/${repoMetadata?.path}/+/webhooks/${webhookExecution.webhook_id}/executions/${webhookExecution.id}/retrigger`
|
||||
)
|
||||
openModal()
|
||||
}
|
||||
|
||||
return { openModal, hideModal, openExecutionLogs }
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
.main {
|
||||
.table {
|
||||
.row {
|
||||
height: fit-content !important;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
div[class*='TableV2--row'] {
|
||||
padding: 3px var(--spacing-medium);
|
||||
justify-content: center;
|
||||
min-height: 48px;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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.
|
||||
*/
|
||||
|
||||
/* eslint-disable */
|
||||
// This is an auto-generated file
|
||||
export declare const main: string
|
||||
export declare const row: string
|
||||
export declare const table: string
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2023 Harness, 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 } from 'react'
|
||||
import { Container, TableV2, Text, Button, ButtonVariation, useToaster } from '@harnessio/uicore'
|
||||
|
||||
import type { CellProps, Column } from 'react-table'
|
||||
import { useGet } from 'restful-react'
|
||||
import { Color, FontVariation } from '@harnessio/design-system'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { defaultTo, isEmpty } from 'lodash-es'
|
||||
import { useQueryParams } from 'hooks/useQueryParams'
|
||||
import { usePageIndex } from 'hooks/usePageIndex'
|
||||
import { LIST_FETCHING_LIMIT, type PageBrowserProps } from 'utils/Utils'
|
||||
import { ExecutionTabs, WebhookIndividualEvent, getEventDescription } from 'utils/GitUtils'
|
||||
import { ResourceListingPagination } from 'components/ResourceListingPagination/ResourceListingPagination'
|
||||
import { NoResultCard } from 'components/NoResultCard/NoResultCard'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import { useUpdateQueryParams } from 'hooks/useUpdateQueryParams'
|
||||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { getConfig } from 'services/config'
|
||||
import { useGetRepositoryMetadata } from 'hooks/useGetRepositoryMetadata'
|
||||
import type { TypesWebhookExecution } from 'services/code'
|
||||
import { TimePopoverWithLocal } from 'utils/timePopoverLocal/TimePopoverWithLocal'
|
||||
import { useWeebhookLogDrawer } from 'pages/WebhookExecutions/WebhookExecutionLogs/useWeebhookLogDrawer'
|
||||
import { ExecutionStatusLabel } from 'components/ExecutionStatusLabel/ExecutionStatusLabel'
|
||||
import css from './WebhookExecutions.module.scss'
|
||||
|
||||
const WebhookExecutions = () => {
|
||||
const { repoMetadata, webhookId } = useGetRepositoryMetadata()
|
||||
const { getString } = useStrings()
|
||||
const { showError, showSuccess } = useToaster()
|
||||
const history = useHistory()
|
||||
const pageBrowser = useQueryParams<PageBrowserProps>()
|
||||
const { updateQueryParams, replaceQueryParams } = useUpdateQueryParams()
|
||||
const pageInit = pageBrowser.page ? parseInt(pageBrowser.page) : 1
|
||||
const [page, setPage] = usePageIndex(pageInit)
|
||||
|
||||
useEffect(() => {
|
||||
const params = {
|
||||
...pageBrowser,
|
||||
...(page > 1 && { page: page.toString() })
|
||||
}
|
||||
updateQueryParams(params, undefined, true)
|
||||
|
||||
if (page <= 1) {
|
||||
const updateParams = { ...params }
|
||||
delete updateParams.page
|
||||
replaceQueryParams(updateParams, undefined, true)
|
||||
}
|
||||
}, [page]) // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
useEffect(() => {
|
||||
if (parseInt(pageBrowser.page ?? '1') !== page) {
|
||||
setPage(parseInt(pageBrowser.page ?? '1'))
|
||||
}
|
||||
}, [pageBrowser])
|
||||
|
||||
const {
|
||||
data: executionList,
|
||||
loading: executionListLoading,
|
||||
refetch: refetchExecutionList,
|
||||
response
|
||||
} = useGet<TypesWebhookExecution[]>({
|
||||
base: getConfig('code/api/v1'),
|
||||
path: `/repos/${repoMetadata?.path}/+/webhooks/${webhookId}/executions`,
|
||||
queryParams: {
|
||||
limit: LIST_FETCHING_LIMIT,
|
||||
page: page
|
||||
}
|
||||
})
|
||||
|
||||
const { openExecutionLogs } = useWeebhookLogDrawer(refetchExecutionList)
|
||||
|
||||
const columns: Column<TypesWebhookExecution>[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: getString('executionId'),
|
||||
id: getString('executionId'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return (
|
||||
<Text color={Color.GREY_900} icon={'execution'}>
|
||||
{row.original.id}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: getString('lastTriggeredAt'),
|
||||
id: getString('lastTriggeredAt'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return (
|
||||
<Text>
|
||||
<TimePopoverWithLocal
|
||||
time={defaultTo(row.original.created as number, 0)}
|
||||
inline={false}
|
||||
font={{ variation: FontVariation.BODY2_SEMI }}
|
||||
color={Color.GREY_400}
|
||||
/>
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: getString('event'),
|
||||
id: getString('event'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return <Text>{getEventDescription(row.original.trigger_type as WebhookIndividualEvent)}</Text>
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: getString('requestPayload'),
|
||||
id: getString('requestPayload'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return (
|
||||
<Button
|
||||
variation={ButtonVariation.LINK}
|
||||
font={{ variation: FontVariation.FORM_LABEL }}
|
||||
text={'View'}
|
||||
iconProps={{ size: 16 }}
|
||||
icon={'file'}
|
||||
onClick={() => openExecutionLogs(row.original, ExecutionTabs.PAYLOAD, repoMetadata)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: getString('serverResponse'),
|
||||
id: getString('serverResponse'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return (
|
||||
<Button
|
||||
variation={ButtonVariation.LINK}
|
||||
font={{ variation: FontVariation.FORM_LABEL }}
|
||||
text={'View'}
|
||||
iconProps={{ size: 18 }}
|
||||
icon={'sto-dast'}
|
||||
onClick={() => openExecutionLogs(row.original, ExecutionTabs.SERVER_RESPONSE, repoMetadata)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
},
|
||||
{
|
||||
Header: getString('status'),
|
||||
id: getString('status'),
|
||||
sort: 'true',
|
||||
width: '16.66%',
|
||||
Cell: ({ row }: CellProps<TypesWebhookExecution>) => {
|
||||
return (
|
||||
<ExecutionStatusLabel
|
||||
data={row.original.result === 'success' ? { state: 'success' } : { state: 'failed' }}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
], // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[history, getString, repoMetadata?.path, setPage, showError, showSuccess]
|
||||
)
|
||||
|
||||
return (
|
||||
<Container>
|
||||
<Container className={css.main} padding={{ bottom: 'large', right: 'xlarge', left: 'xlarge' }}>
|
||||
{executionList && !executionListLoading && executionList.length && (
|
||||
<TableV2<TypesWebhookExecution>
|
||||
className={css.table}
|
||||
columns={columns}
|
||||
data={executionList}
|
||||
sortable
|
||||
autoResetExpanded={true}
|
||||
getRowClassName={() => css.row}
|
||||
/>
|
||||
)}
|
||||
<LoadingSpinner visible={executionListLoading} />
|
||||
<ResourceListingPagination response={response} page={page} setPage={setPage} />
|
||||
</Container>
|
||||
<NoResultCard
|
||||
showWhen={() => !executionListLoading && isEmpty(executionList)}
|
||||
forSearch={true}
|
||||
title={getString('noExecutionsFound')}
|
||||
emptySearchMessage={getString('noExecutionsFoundForWebhook')}
|
||||
/>
|
||||
</Container>
|
||||
)
|
||||
}
|
||||
|
||||
export default WebhookExecutions
|
|
@ -35,33 +35,11 @@ import React from 'react'
|
|||
import type { OpenapiUpdateWebhookRequest, EnumWebhookTrigger, OpenapiWebhookType } from 'services/code'
|
||||
import { getErrorMessage, permissionProps } from 'utils/Utils'
|
||||
import { useStrings } from 'framework/strings'
|
||||
import type { GitInfoProps } from 'utils/GitUtils'
|
||||
import { WebhookIndividualEvent, type GitInfoProps, WebhookEventType } from 'utils/GitUtils'
|
||||
import { useAppContext } from 'AppContext'
|
||||
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
||||
import css from './WehookForm.module.scss'
|
||||
|
||||
enum WebhookEventType {
|
||||
PUSH = 'push',
|
||||
ALL = 'all',
|
||||
INDIVIDUAL = 'individual'
|
||||
}
|
||||
|
||||
enum WebhookIndividualEvent {
|
||||
BRANCH_CREATED = 'branch_created',
|
||||
BRANCH_UPDATED = 'branch_updated',
|
||||
BRANCH_DELETED = 'branch_deleted',
|
||||
TAG_CREATED = 'tag_created',
|
||||
TAG_UPDATED = 'tag_updated',
|
||||
TAG_DELETED = 'tag_deleted',
|
||||
PR_CREATED = 'pullreq_created',
|
||||
PR_UPDATED = 'pullreq_updated',
|
||||
PR_REOPENED = 'pullreq_reopened',
|
||||
PR_BRANCH_UPDATED = 'pullreq_branch_updated',
|
||||
PR_CLOSED = 'pullreq_closed',
|
||||
PR_COMMENT_CREATED = 'pullreq_comment_created',
|
||||
PR_MERGED = 'pullreq_merged'
|
||||
}
|
||||
|
||||
const SECRET_MASK = '********'
|
||||
|
||||
interface FormData {
|
||||
|
|
|
@ -50,7 +50,7 @@ import { ResourceListingPagination } from 'components/ResourceListingPagination/
|
|||
import { LoadingSpinner } from 'components/LoadingSpinner/LoadingSpinner'
|
||||
import { NoResultCard } from 'components/NoResultCard/NoResultCard'
|
||||
import type { OpenapiWebhookType } from 'services/code'
|
||||
import { formatTriggers } from 'utils/GitUtils'
|
||||
import { WebhookTabs, formatTriggers } from 'utils/GitUtils'
|
||||
import { useGetSpaceParam } from 'hooks/useGetSpaceParam'
|
||||
import { WebhooksHeader } from './WebhooksHeader/WebhooksHeader'
|
||||
import css from './Webhooks.module.scss'
|
||||
|
@ -256,6 +256,20 @@ export default function Webhooks() {
|
|||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
hasIcon: true,
|
||||
iconName: 'execution',
|
||||
iconSize: 16,
|
||||
text: getString('executionHistory'),
|
||||
onClick: () => {
|
||||
history.push(
|
||||
`${routes.toCODEWebhookDetails({
|
||||
repoPath: repoMetadata?.path as string,
|
||||
webhookId: String(row.original?.identifier)
|
||||
})}?tab=${WebhookTabs.EXECUTIONS}`
|
||||
)
|
||||
}
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
|
|
@ -133,6 +133,16 @@ export enum SpaceSettingsTab {
|
|||
labels = 'labels'
|
||||
}
|
||||
|
||||
export enum WebhookTabs {
|
||||
DETAILS = 'details',
|
||||
EXECUTIONS = 'executions'
|
||||
}
|
||||
|
||||
export enum ExecutionTabs {
|
||||
PAYLOAD = 'Payload',
|
||||
SERVER_RESPONSE = 'Server Response'
|
||||
}
|
||||
|
||||
export enum VulnerabilityScanningType {
|
||||
DETECT = 'detect',
|
||||
BLOCK = 'block',
|
||||
|
@ -579,3 +589,61 @@ export const dryMerge = (
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
export enum WebhookEventType {
|
||||
PUSH = 'push',
|
||||
ALL = 'all',
|
||||
INDIVIDUAL = 'individual'
|
||||
}
|
||||
|
||||
export enum WebhookIndividualEvent {
|
||||
BRANCH_CREATED = 'branch_created',
|
||||
BRANCH_UPDATED = 'branch_updated',
|
||||
BRANCH_DELETED = 'branch_deleted',
|
||||
TAG_CREATED = 'tag_created',
|
||||
TAG_UPDATED = 'tag_updated',
|
||||
TAG_DELETED = 'tag_deleted',
|
||||
PR_CREATED = 'pullreq_created',
|
||||
PR_UPDATED = 'pullreq_updated',
|
||||
PR_REOPENED = 'pullreq_reopened',
|
||||
PR_BRANCH_UPDATED = 'pullreq_branch_updated',
|
||||
PR_CLOSED = 'pullreq_closed',
|
||||
PR_COMMENT_CREATED = 'pullreq_comment_created',
|
||||
PR_MERGED = 'pullreq_merged'
|
||||
}
|
||||
|
||||
export enum WebhookEventMap {
|
||||
BRANCH_CREATED = 'Branch created',
|
||||
BRANCH_UPDATED = 'Branch updated',
|
||||
BRANCH_DELETED = 'Branch deleted',
|
||||
TAG_CREATED = 'Tag created',
|
||||
TAG_UPDATED = 'Tag updated',
|
||||
TAG_DELETED = 'Tag deleted',
|
||||
PR_CREATED = 'PR created',
|
||||
PR_UPDATED = 'PR updated',
|
||||
PR_REOPENED = 'PR reopened',
|
||||
PR_BRANCH_UPDATED = 'PR updated',
|
||||
PR_CLOSED = 'PR closed',
|
||||
PR_COMMENT_CREATED = 'PR created',
|
||||
PR_MERGED = 'PR merged'
|
||||
}
|
||||
|
||||
export const eventMapping: Record<WebhookIndividualEvent, WebhookEventMap> = {
|
||||
[WebhookIndividualEvent.BRANCH_CREATED]: WebhookEventMap.BRANCH_CREATED,
|
||||
[WebhookIndividualEvent.BRANCH_UPDATED]: WebhookEventMap.BRANCH_UPDATED,
|
||||
[WebhookIndividualEvent.BRANCH_DELETED]: WebhookEventMap.BRANCH_DELETED,
|
||||
[WebhookIndividualEvent.TAG_CREATED]: WebhookEventMap.TAG_CREATED,
|
||||
[WebhookIndividualEvent.TAG_UPDATED]: WebhookEventMap.TAG_UPDATED,
|
||||
[WebhookIndividualEvent.TAG_DELETED]: WebhookEventMap.TAG_DELETED,
|
||||
[WebhookIndividualEvent.PR_CREATED]: WebhookEventMap.PR_CREATED,
|
||||
[WebhookIndividualEvent.PR_UPDATED]: WebhookEventMap.PR_UPDATED,
|
||||
[WebhookIndividualEvent.PR_REOPENED]: WebhookEventMap.PR_REOPENED,
|
||||
[WebhookIndividualEvent.PR_BRANCH_UPDATED]: WebhookEventMap.PR_BRANCH_UPDATED,
|
||||
[WebhookIndividualEvent.PR_CLOSED]: WebhookEventMap.PR_CLOSED,
|
||||
[WebhookIndividualEvent.PR_COMMENT_CREATED]: WebhookEventMap.PR_COMMENT_CREATED,
|
||||
[WebhookIndividualEvent.PR_MERGED]: WebhookEventMap.PR_MERGED
|
||||
}
|
||||
|
||||
export function getEventDescription(event: WebhookIndividualEvent): string {
|
||||
return eventMapping[event]
|
||||
}
|
||||
|
|
|
@ -98,6 +98,7 @@ export const getErrorMessage = (error: Unknown): string | undefined =>
|
|||
export interface PageBrowserProps {
|
||||
page?: string
|
||||
state?: string
|
||||
tab?: string
|
||||
}
|
||||
|
||||
export const extractInfoFromRuleViolationArr = (ruleViolationArr: TypesRuleViolations[]) => {
|
||||
|
|
|
@ -40,7 +40,7 @@ enum TimeZone {
|
|||
export function DateTimeWithLocalContentInline({ time }: { time: number }): JSX.Element {
|
||||
const { getString } = useStrings()
|
||||
return (
|
||||
<Layout.Vertical>
|
||||
<Layout.Vertical margin={{ right: '4px' }}>
|
||||
<Layout.Horizontal className={css.timeWrapper}>
|
||||
<Text color={Color.GREY_600} className={css.time}>
|
||||
{moment(time).format(DATE_PARSE_FORMAT)}
|
||||
|
|
Loading…
Reference in New Issue