mirror of
https://github.com/harness/drone.git
synced 2025-05-07 03:31:24 +08:00
feat: [AH-883]: Implement edit webhook page (#3291)
* feat: [AH-883]: refetch webhook after update and fix route to webhook details page from webhook list page * feat: [AH-883]: fix breaking css for inline inputs * feat: [AH-883]: implement Edit flow with enterprise secret input * feat: [AH-883]: Implement edit webhook page
This commit is contained in:
parent
b6c214b9ee
commit
b00a8f16b4
@ -28,6 +28,7 @@ import upstreamProxyDetails from '@ar/pages/upstream-proxy-details/strings/strin
|
||||
import versionDetails from '@ar/pages/version-details/strings/strings.en.yaml'
|
||||
import versionList from '@ar/pages/version-list/strings/strings.en.yaml'
|
||||
import webhookList from '@ar/pages/webhook-list/strings/strings.en.yaml'
|
||||
import webhookDetails from '@ar/pages/webhook-details/strings/strings.en.yaml'
|
||||
|
||||
export default function languageLoader() {
|
||||
return {
|
||||
@ -39,6 +40,7 @@ export default function languageLoader() {
|
||||
upstreamProxyDetails,
|
||||
versionDetails,
|
||||
versionList,
|
||||
webhookList
|
||||
webhookList,
|
||||
webhookDetails
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,8 @@ export default function getARRouteDefinitions(routeParams: Record<string, string
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
|
||||
// anything random, as this route will not be used in gitness
|
||||
toARVersionDetailsTab: params =>
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`
|
||||
`/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}`,
|
||||
toARRepositoryWebhookDetailsTab: params =>
|
||||
`/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}/${params?.tab}`
|
||||
}
|
||||
}
|
||||
|
@ -123,7 +123,7 @@ export function getFormattedFormDataForAuthType(
|
||||
})
|
||||
}
|
||||
|
||||
function getSecretScopeDetailsByIdentifier(identifier: string, secretSpacePath: string) {
|
||||
export function getSecretScopeDetailsByIdentifier(identifier: string, secretSpacePath: string) {
|
||||
const referenceString = getReferenceStringFromSecretSpacePath(identifier, secretSpacePath)
|
||||
const [, orgIdentifier, projectIdentifier] = secretSpacePath.split('/')
|
||||
return {
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.tabsContainer {
|
||||
position: relative !important;
|
||||
& > :global(.bp3-tabs > .bp3-tab-list) {
|
||||
border-bottom: 1px solid var(--grey-200);
|
||||
}
|
||||
:global {
|
||||
.bp3-tab-panel {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.bp3-tab-list {
|
||||
background-color: var(--white);
|
||||
width: 100%;
|
||||
border-bottom: 0;
|
||||
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.13);
|
||||
align-items: center;
|
||||
padding: 0 var(--spacing-xlarge);
|
||||
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 2;
|
||||
}
|
||||
}
|
||||
}
|
19
web/src/ar/pages/webhook-details/WebhookDetailsPage.module.scss.d.ts
vendored
Normal file
19
web/src/ar/pages/webhook-details/WebhookDetailsPage.module.scss.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 tabsContainer: string
|
128
web/src/ar/pages/webhook-details/WebhookDetailsPage.tsx
Normal file
128
web/src/ar/pages/webhook-details/WebhookDetailsPage.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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, { useState } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { Expander } from '@blueprintjs/core'
|
||||
import { useGetWebhookQuery, type WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
import { Redirect, Switch, useHistory, useParams } from 'react-router-dom'
|
||||
import { Button, ButtonVariation, Container, Layout, Page, Tab, Tabs } from '@harnessio/uicore'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import RouteProvider from '@ar/components/RouteProvider/RouteProvider'
|
||||
import type { RepositoryWebhookDetailsPathParams } from '@ar/routes/types'
|
||||
import { useGetSpaceRef, useParentComponents, useRoutes } from '@ar/hooks'
|
||||
import { PermissionIdentifier, ResourceType } from '@ar/common/permissionTypes'
|
||||
import { repositoryWebhookDetailsPathParams, repositoryWebhookDetailsTabPathParams } from '@ar/routes/RouteDestinations'
|
||||
|
||||
import { WebhookDetailsTab } from './constants'
|
||||
import WebhookDetailsTabPage from './WebhookDetailsTabPage'
|
||||
// import { MOCK_WEBHOK_LIST_TABLE } from '../webhook-list/mockData'
|
||||
import { WebhookDetailsContext } from './context/WebhookDetailsContext'
|
||||
import { WebhookDetailsPageHeader } from './components/WebhookDetailsPageHeader/WebhookDetailsPageHeader'
|
||||
|
||||
import css from './WebhookDetailsPage.module.scss'
|
||||
|
||||
export default function WebhookDetailsPage() {
|
||||
const params = useParams<RepositoryWebhookDetailsPathParams>()
|
||||
const { repositoryIdentifier, webhookIdentifier } = params
|
||||
const history = useHistory()
|
||||
const routes = useRoutes()
|
||||
const routeDefinitions = useRoutes(true)
|
||||
const { RbacButton } = useParentComponents()
|
||||
|
||||
const registryRef = useGetSpaceRef()
|
||||
const { getString } = useStrings()
|
||||
const stepRef = React.useRef<FormikProps<WebhookRequest> | null>(null)
|
||||
|
||||
const [activeTab, setActiveTab] = useState(WebhookDetailsTab.Configuration)
|
||||
const [isDirty, setIsDirty] = useState(false)
|
||||
const [isUpdating, setUpdating] = useState(false)
|
||||
|
||||
const { isFetching, error, data, refetch } = useGetWebhookQuery({
|
||||
registry_ref: registryRef,
|
||||
webhook_identifier: webhookIdentifier
|
||||
})
|
||||
|
||||
const handleChangeTab = (nextTab: WebhookDetailsTab): void => {
|
||||
setActiveTab(nextTab)
|
||||
history.push(routes.toARRepositoryWebhookDetailsTab({ ...params, tab: nextTab }))
|
||||
}
|
||||
|
||||
const renderActionBtns = (): JSX.Element => (
|
||||
<Layout.Horizontal spacing="medium">
|
||||
<RbacButton
|
||||
text={getString('save')}
|
||||
variation={ButtonVariation.PRIMARY}
|
||||
onClick={stepRef.current?.submitForm}
|
||||
disabled={!isDirty || isUpdating}
|
||||
permission={{
|
||||
permission: PermissionIdentifier.EDIT_ARTIFACT_REGISTRY,
|
||||
resource: {
|
||||
resourceType: ResourceType.ARTIFACT_REGISTRY,
|
||||
resourceIdentifier: repositoryIdentifier
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
variation={ButtonVariation.SECONDARY}
|
||||
text={getString('discard')}
|
||||
onClick={() => stepRef.current?.resetForm()}
|
||||
disabled={!isDirty}
|
||||
/>
|
||||
</Layout.Horizontal>
|
||||
)
|
||||
|
||||
const response = data?.content.data
|
||||
// const response = MOCK_WEBHOK_LIST_TABLE.webhooks[0]
|
||||
|
||||
return (
|
||||
<WebhookDetailsContext.Provider value={{ data: response, loading: isFetching, setDirty: setIsDirty, setUpdating }}>
|
||||
<Page.Body loading={isFetching} error={error} retryOnError={() => refetch()}>
|
||||
{response && !isFetching && (
|
||||
<Container>
|
||||
<WebhookDetailsPageHeader data={response} repositoryIdentifier={repositoryIdentifier} />
|
||||
<Container className={css.tabsContainer}>
|
||||
<Tabs id="webhookDetailsTabs" selectedTabId={activeTab} onChange={handleChangeTab}>
|
||||
<Tab id={WebhookDetailsTab.Configuration} title={getString('webhookDetails.tabs.configuration')} />
|
||||
<Tab id={WebhookDetailsTab.Executions} title={getString('webhookDetails.tabs.executions')} />
|
||||
<Expander />
|
||||
{activeTab === WebhookDetailsTab.Configuration && renderActionBtns()}
|
||||
</Tabs>
|
||||
</Container>
|
||||
<Switch>
|
||||
<RouteProvider
|
||||
exact
|
||||
path={routeDefinitions.toARRepositoryWebhookDetails({ ...repositoryWebhookDetailsPathParams })}>
|
||||
<Redirect
|
||||
to={routes.toARRepositoryWebhookDetailsTab({
|
||||
...params,
|
||||
tab: WebhookDetailsTab.Configuration
|
||||
})}
|
||||
/>
|
||||
</RouteProvider>
|
||||
<RouteProvider
|
||||
exact
|
||||
path={routeDefinitions.toARRepositoryWebhookDetailsTab({ ...repositoryWebhookDetailsTabPathParams })}>
|
||||
<WebhookDetailsTabPage onInit={setActiveTab} formRef={stepRef} />
|
||||
</RouteProvider>
|
||||
</Switch>
|
||||
</Container>
|
||||
)}
|
||||
</Page.Body>
|
||||
</WebhookDetailsContext.Provider>
|
||||
)
|
||||
}
|
49
web/src/ar/pages/webhook-details/WebhookDetailsTabPage.tsx
Normal file
49
web/src/ar/pages/webhook-details/WebhookDetailsTabPage.tsx
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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, { useEffect } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import type { WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
|
||||
import type { RepositoryWebhookDetailsTabPathParams } from '@ar/routes/types'
|
||||
|
||||
import { WebhookDetailsTab } from './constants'
|
||||
import WebhookConfigurationForm from './components/WebhookConfigurationForm/WebhookConfigurationForm'
|
||||
|
||||
interface WebhookDetailsTabPageProps {
|
||||
onInit: (tab: WebhookDetailsTab) => void
|
||||
formRef: React.RefObject<FormikProps<WebhookRequest>>
|
||||
}
|
||||
|
||||
export default function WebhookDetailsTabPage(props: WebhookDetailsTabPageProps): JSX.Element {
|
||||
const { onInit, formRef } = props
|
||||
const params = useParams<RepositoryWebhookDetailsTabPathParams>()
|
||||
const { tab } = params
|
||||
|
||||
useEffect(() => {
|
||||
onInit(tab)
|
||||
}, [tab])
|
||||
|
||||
switch (tab) {
|
||||
case WebhookDetailsTab.Configuration:
|
||||
return <WebhookConfigurationForm formRef={formRef} />
|
||||
case WebhookDetailsTab.Executions:
|
||||
return <>Executions Page</>
|
||||
default:
|
||||
return <>Not Found</>
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
.formContainer {
|
||||
:global(.bp3-form-group .bp3-input),
|
||||
:global(.bp3-form-group .bp3-input-group),
|
||||
:global(.bp3-form-group .bp3-select-popover) {
|
||||
width: var(--input-element-width);
|
||||
}
|
||||
|
||||
:global(.bp3-form-group.bp3-inline .bp3-input),
|
||||
:global(.bp3-form-group.bp3-inline .bp3-input-group),
|
||||
:global(.bp3-form-group.bp3-inline .bp3-select-popover) {
|
||||
width: unset;
|
||||
}
|
||||
|
||||
div[class*='InputWithIdentifier--txtNameContainer-'] {
|
||||
width: var(--input-element-width);
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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 formContainer: string
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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, { useContext } from 'react'
|
||||
import type { FormikProps } from 'formik'
|
||||
import { useParams } from 'react-router-dom'
|
||||
import { updateWebhook, WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
import { Container, getErrorInfoFromErrorObject, useToaster } from '@harnessio/uicore'
|
||||
|
||||
import { useGetSpaceRef } from '@ar/hooks'
|
||||
import { queryClient } from '@ar/utils/queryClient'
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import WebhookForm from '@ar/pages/webhook-list/components/Forms/WebhookForm'
|
||||
import type { RepositoryWebhookDetailsTabPathParams } from '@ar/routes/types'
|
||||
|
||||
import { WebhookDetailsContext } from '../../context/WebhookDetailsContext'
|
||||
import css from './WebhookConfigurationForm.module.scss'
|
||||
|
||||
interface WebhookConfigurationFormProps {
|
||||
formRef: React.RefObject<FormikProps<WebhookRequest>>
|
||||
}
|
||||
|
||||
export default function WebhookConfigurationForm(props: WebhookConfigurationFormProps): JSX.Element {
|
||||
const { formRef } = props
|
||||
const { showError, showSuccess, clear } = useToaster()
|
||||
const { getString } = useStrings()
|
||||
|
||||
const { data, setDirty, setUpdating } = useContext(WebhookDetailsContext)
|
||||
const registryRef = useGetSpaceRef()
|
||||
const { webhookIdentifier } = useParams<RepositoryWebhookDetailsTabPathParams>()
|
||||
|
||||
const handleUpdateWebhook = async (values: WebhookRequest) => {
|
||||
try {
|
||||
setUpdating?.(true)
|
||||
await updateWebhook({
|
||||
registry_ref: registryRef,
|
||||
webhook_identifier: webhookIdentifier,
|
||||
body: values
|
||||
})
|
||||
showSuccess(getString('webhookList.webhookUpdated'))
|
||||
queryClient.invalidateQueries(['GetWebhook'])
|
||||
} catch (e) {
|
||||
clear()
|
||||
showError(getErrorInfoFromErrorObject(e as Error))
|
||||
} finally {
|
||||
setUpdating?.(false)
|
||||
}
|
||||
}
|
||||
|
||||
if (!data) return <></>
|
||||
return (
|
||||
<Container className={css.formContainer} padding="xlarge">
|
||||
<WebhookForm data={data} ref={formRef} isEdit onSubmit={handleUpdateWebhook} setDirty={setDirty} />
|
||||
</Container>
|
||||
)
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 from 'react'
|
||||
import { Page, Text } from '@harnessio/uicore'
|
||||
import { FontVariation } from '@harnessio/design-system'
|
||||
import type { Webhook } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { useParentComponents, useRoutes } from '@ar/hooks'
|
||||
import { getIdentifierStringForBreadcrumb } from '@ar/common/utils'
|
||||
import { RepositoryDetailsTab } from '@ar/pages/repository-details/constants'
|
||||
|
||||
interface WebhookDetailsPageHeaderProps {
|
||||
data: Webhook
|
||||
repositoryIdentifier: string
|
||||
}
|
||||
|
||||
export function WebhookDetailsPageHeader(props: WebhookDetailsPageHeaderProps) {
|
||||
const { data, repositoryIdentifier } = props
|
||||
const { NGBreadcrumbs } = useParentComponents()
|
||||
const routes = useRoutes()
|
||||
const { getString } = useStrings()
|
||||
return (
|
||||
<Page.Header
|
||||
title={
|
||||
<Text font={{ variation: FontVariation.H4 }} lineClamp={1}>
|
||||
{data.name}
|
||||
</Text>
|
||||
}
|
||||
size="large"
|
||||
breadcrumbs={
|
||||
<NGBreadcrumbs
|
||||
links={[
|
||||
{
|
||||
url: routes.toARRepositories(),
|
||||
label: getString('breadcrumbs.repositories')
|
||||
},
|
||||
{
|
||||
url: routes.toARRepositoryDetailsTab({
|
||||
repositoryIdentifier,
|
||||
tab: RepositoryDetailsTab.WEBHOOKS
|
||||
}),
|
||||
label: getIdentifierStringForBreadcrumb(getString('breadcrumbs.repositories'), repositoryIdentifier)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
20
web/src/ar/pages/webhook-details/constants.tsx
Normal file
20
web/src/ar/pages/webhook-details/constants.tsx
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export enum WebhookDetailsTab {
|
||||
Configuration = 'configuration',
|
||||
Executions = 'executions'
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* 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 { createContext } from 'react'
|
||||
import type { Webhook } from '@harnessio/react-har-service-client'
|
||||
|
||||
interface WebhookDetailsContextSpec {
|
||||
data?: Webhook
|
||||
loading?: boolean
|
||||
setDirty?: (dirty: boolean) => void
|
||||
setUpdating?: (updating: boolean) => void
|
||||
}
|
||||
|
||||
export const WebhookDetailsContext = createContext<WebhookDetailsContextSpec>({
|
||||
data: {} as Webhook,
|
||||
loading: false
|
||||
})
|
3
web/src/ar/pages/webhook-details/strings/strings.en.yaml
Normal file
3
web/src/ar/pages/webhook-details/strings/strings.en.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
tabs:
|
||||
configuration: Configuration
|
||||
executions: Executions
|
@ -17,7 +17,7 @@
|
||||
import React, { forwardRef, useMemo } from 'react'
|
||||
import * as Yup from 'yup'
|
||||
import { Formik } from '@harnessio/uicore'
|
||||
import type { WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
import type { Webhook, WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useAppStore } from '@ar/hooks'
|
||||
import { GENERIC_URL_REGEX } from '@ar/constants'
|
||||
@ -27,19 +27,24 @@ import type { FormikFowardRef } from '@ar/common/types'
|
||||
|
||||
import type { WebhookRequestUI } from './types'
|
||||
import WebhookFormContent from './WebhookFormContent'
|
||||
import { transformFormValuesToSubmitValues } from './utils'
|
||||
import { transformFormValuesToSubmitValues, transformWebhookDataToFormValues } from './utils'
|
||||
|
||||
interface CreateWebhookFormProps {
|
||||
data?: Webhook
|
||||
onSubmit: (values: WebhookRequest) => void
|
||||
setDirty?: (dirty: boolean) => void
|
||||
readonly?: boolean
|
||||
isEdit?: boolean
|
||||
}
|
||||
|
||||
function WebhookForm(props: CreateWebhookFormProps, formikRef: FormikFowardRef<WebhookRequestUI>) {
|
||||
const { onSubmit, readonly, isEdit } = props
|
||||
const { onSubmit, readonly, isEdit, data, setDirty } = props
|
||||
const { getString } = useStrings()
|
||||
const { parent, scope } = useAppStore()
|
||||
const initialValues: WebhookRequestUI = useMemo(() => {
|
||||
if (isEdit && data) {
|
||||
return transformWebhookDataToFormValues(data, parent)
|
||||
}
|
||||
return {
|
||||
identifier: '',
|
||||
name: '',
|
||||
@ -74,6 +79,7 @@ function WebhookForm(props: CreateWebhookFormProps, formikRef: FormikFowardRef<W
|
||||
onSubmit={handleSubmit}
|
||||
initialValues={initialValues}>
|
||||
{formik => {
|
||||
setDirty?.(formik.dirty)
|
||||
setFormikRef(formikRef, formik)
|
||||
return <WebhookFormContent formikProps={formik} isEdit={isEdit} readonly={readonly} />
|
||||
}}
|
||||
|
@ -16,11 +16,14 @@
|
||||
|
||||
import produce from 'immer'
|
||||
import { get, set } from 'lodash-es'
|
||||
import type { WebhookRequest } from '@harnessio/react-har-service-client'
|
||||
import type { WebhookRequest, Webhook } from '@harnessio/react-har-service-client'
|
||||
|
||||
import type { Scope } from '@ar/MFEAppTypes'
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { getSecretSpacePath } from '@ar/pages/upstream-proxy-details/components/Forms/utils'
|
||||
import {
|
||||
getSecretScopeDetailsByIdentifier,
|
||||
getSecretSpacePath
|
||||
} from '@ar/pages/upstream-proxy-details/components/Forms/utils'
|
||||
|
||||
import type { WebhookRequestUI } from './types'
|
||||
|
||||
@ -54,3 +57,26 @@ export function transformFormValuesToSubmitValues(
|
||||
return draft
|
||||
})
|
||||
}
|
||||
|
||||
function convertFormFieldsToSecreteInput(formData: Webhook, secretField: string, secretSpacePathField: string) {
|
||||
const secretIdentifier = get(formData, secretField, '')
|
||||
const secretSpacePath = get(formData, secretSpacePathField, '')
|
||||
set(formData, secretField, getSecretScopeDetailsByIdentifier(secretIdentifier, secretSpacePath))
|
||||
}
|
||||
|
||||
export function transformWebhookDataToFormValues(data: Webhook, parent: Parent): WebhookRequestUI {
|
||||
return produce(data, draft => {
|
||||
if (draft.triggers?.length) {
|
||||
set(draft, 'triggerType', 'custom')
|
||||
} else {
|
||||
set(draft, 'triggerType', 'all')
|
||||
}
|
||||
if (!draft.extraHeaders?.length) {
|
||||
set(draft, 'extraHeaders', [{ key: '', value: '' }])
|
||||
}
|
||||
if (parent === Parent.Enterprise) {
|
||||
convertFormFieldsToSecreteInput(draft, 'secretIdentifier', 'secretSpacePath')
|
||||
}
|
||||
return draft
|
||||
}) as WebhookRequestUI
|
||||
}
|
||||
|
@ -17,12 +17,13 @@
|
||||
import React from 'react'
|
||||
import classNames from 'classnames'
|
||||
import type { Column } from 'react-table'
|
||||
import { useHistory } from 'react-router-dom'
|
||||
import { useHistory, useParams } from 'react-router-dom'
|
||||
import { type PaginationProps, TableV2 } from '@harnessio/uicore'
|
||||
import type { ListWebhooks, Webhook } from '@harnessio/react-har-service-client'
|
||||
|
||||
import { useStrings } from '@ar/frameworks/strings'
|
||||
import { useParentHooks, useRoutes } from '@ar/hooks'
|
||||
import type { RepositoryDetailsTabPathParams } from '@ar/routes/types'
|
||||
|
||||
import {
|
||||
WebhookActionsCell,
|
||||
@ -50,6 +51,7 @@ export interface WebhookListTableProps extends WebhookListColumnActions {
|
||||
export default function WebhookListTable(props: WebhookListTableProps): JSX.Element {
|
||||
const { data, gotoPage, onPageSizeChange, readonly, sortBy, setSortBy } = props
|
||||
const { useDefaultPaginationProps } = useParentHooks()
|
||||
const { repositoryIdentifier } = useParams<RepositoryDetailsTabPathParams>()
|
||||
const { getString } = useStrings()
|
||||
const history = useHistory()
|
||||
const routes = useRoutes()
|
||||
@ -116,7 +118,7 @@ export default function WebhookListTable(props: WebhookListTableProps): JSX.Elem
|
||||
onRowClick={rowDetails => {
|
||||
history.push(
|
||||
routes.toARRepositoryWebhookDetails({
|
||||
repositoryIdentifier: rowDetails.identifier,
|
||||
repositoryIdentifier,
|
||||
webhookIdentifier: rowDetails.identifier
|
||||
})
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
newWebhook: New Webhook
|
||||
webhookCreated: Webhook created successfully
|
||||
webhookUpdated: Webhook updated successfully
|
||||
triggers:
|
||||
artifactCreation: 'Artifact Creation'
|
||||
artifactDeletion: 'Artifact Deletion'
|
||||
|
@ -21,6 +21,7 @@ import type {
|
||||
RepositoryDetailsPathParams,
|
||||
RepositoryDetailsTabPathParams,
|
||||
RepositoryWebhookDetailsPathParams,
|
||||
RepositoryWebhookDetailsTabPathParams,
|
||||
VersionDetailsPathParams,
|
||||
VersionDetailsTabPathParams
|
||||
} from './types'
|
||||
@ -36,6 +37,7 @@ export interface ARRouteDefinitionsReturn {
|
||||
toARVersionDetails: (params: VersionDetailsPathParams) => string
|
||||
toARVersionDetailsTab: (params: VersionDetailsTabPathParams) => string
|
||||
toARRepositoryWebhookDetails: (params: RepositoryWebhookDetailsPathParams) => string
|
||||
toARRepositoryWebhookDetailsTab: (params: RepositoryWebhookDetailsTabPathParams) => string
|
||||
}
|
||||
|
||||
export const routeDefinitions: ARRouteDefinitionsReturn = {
|
||||
@ -70,5 +72,7 @@ export const routeDefinitions: ARRouteDefinitionsReturn = {
|
||||
return `/registries/${params?.repositoryIdentifier}/artifacts/${params?.artifactIdentifier}/versions/${params?.versionIdentifier}/${params.versionTab}`
|
||||
},
|
||||
toARRepositoryWebhookDetails: params =>
|
||||
`/registries/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`
|
||||
`/registries/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}`,
|
||||
toARRepositoryWebhookDetailsTab: params =>
|
||||
`/registries/${params?.repositoryIdentifier}/webhooks/${params?.webhookIdentifier}/${params.tab}`
|
||||
}
|
||||
|
@ -20,12 +20,15 @@ import { Redirect, Switch } from 'react-router-dom'
|
||||
import { Parent } from '@ar/common/types'
|
||||
import { useAppStore, useRoutes } from '@ar/hooks'
|
||||
import RedirectPage from '@ar/pages/redirect-page/RedirectPage'
|
||||
import type { WebhookDetailsTab } from '@ar/pages/webhook-details/constants'
|
||||
import type { RepositoryDetailsTab } from '@ar/pages/repository-details/constants'
|
||||
|
||||
import type {
|
||||
ArtifactDetailsPathParams,
|
||||
RepositoryDetailsPathParams,
|
||||
RepositoryDetailsTabPathParams,
|
||||
RepositoryWebhookDetailsPathParams,
|
||||
RepositoryWebhookDetailsTabPathParams,
|
||||
VersionDetailsPathParams,
|
||||
VersionDetailsTabPathParams
|
||||
} from './types'
|
||||
@ -37,6 +40,7 @@ const ArtifactDetailsPage = React.lazy(() => import('@ar/pages/artifact-details/
|
||||
const VersionDetailsPage = React.lazy(() => import('@ar/pages/version-details/VersionDetailsPage'))
|
||||
const OSSVersionDetailsPage = React.lazy(() => import('@ar/pages/version-details/OSSVersionDetailsPage'))
|
||||
const RouteProvider = React.lazy(() => import('@ar/components/RouteProvider/RouteProvider'))
|
||||
const WebhookDetailsPage = React.lazy(() => import('@ar/pages/webhook-details/WebhookDetailsPage'))
|
||||
|
||||
export const repositoryDetailsPathProps: RepositoryDetailsPathParams = {
|
||||
repositoryIdentifier: ':repositoryIdentifier'
|
||||
@ -74,6 +78,16 @@ export const versionDetailsTabWithSSCADetailsPathParams: VersionDetailsTabPathPa
|
||||
artifactId: ':artifactId'
|
||||
}
|
||||
|
||||
export const repositoryWebhookDetailsPathParams: RepositoryWebhookDetailsPathParams = {
|
||||
...repositoryDetailsPathProps,
|
||||
webhookIdentifier: ':webhookIdentifier'
|
||||
}
|
||||
|
||||
export const repositoryWebhookDetailsTabPathParams: RepositoryWebhookDetailsTabPathParams = {
|
||||
...repositoryWebhookDetailsPathParams,
|
||||
tab: ':tab' as WebhookDetailsTab
|
||||
}
|
||||
|
||||
const RouteDestinations = (): JSX.Element => {
|
||||
const routes = useRoutes(true)
|
||||
const { parent } = useAppStore()
|
||||
@ -110,6 +124,9 @@ const RouteDestinations = (): JSX.Element => {
|
||||
<VersionDetailsPage />
|
||||
</RouteProvider>
|
||||
)}
|
||||
<RouteProvider path={routes.toARRepositoryWebhookDetails({ ...repositoryWebhookDetailsPathParams })}>
|
||||
<WebhookDetailsPage />
|
||||
</RouteProvider>
|
||||
<RouteProvider path={routes.toARRepositoryDetails({ ...repositoryDetailsPathProps })}>
|
||||
<RepositoryDetailsPage />
|
||||
</RouteProvider>
|
||||
|
@ -17,6 +17,7 @@
|
||||
import type { RepositoryPackageType } from '@ar/common/types'
|
||||
import type { RepositoryDetailsTab } from '@ar/pages/repository-details/constants'
|
||||
import type { VersionDetailsTab } from '@ar/pages/version-details/components/VersionDetailsTabs/constants'
|
||||
import type { WebhookDetailsTab } from '@ar/pages/webhook-details/constants'
|
||||
|
||||
export interface RepositoryDetailsPathParams {
|
||||
repositoryIdentifier: string
|
||||
@ -56,3 +57,7 @@ export interface RedirectPageQueryParams {
|
||||
export interface RepositoryWebhookDetailsPathParams extends RepositoryDetailsPathParams {
|
||||
webhookIdentifier: string
|
||||
}
|
||||
|
||||
export interface RepositoryWebhookDetailsTabPathParams extends RepositoryWebhookDetailsPathParams {
|
||||
tab: WebhookDetailsTab
|
||||
}
|
||||
|
@ -229,6 +229,8 @@ export interface StringsMap {
|
||||
'versionList.table.columns.size': string
|
||||
'versionList.table.columns.version': string
|
||||
'versionList.table.noVersionsTitle': string
|
||||
'webhookDetails.tabs.configuration': string
|
||||
'webhookDetails.tabs.executions': string
|
||||
'webhookList.formFields.SSLVerification': string
|
||||
'webhookList.formFields.addNewKeyValuePair': string
|
||||
'webhookList.formFields.advanced': string
|
||||
@ -254,6 +256,7 @@ export interface StringsMap {
|
||||
'webhookList.triggers.artifactDeletion': string
|
||||
'webhookList.triggers.artifactModification': string
|
||||
'webhookList.webhookCreated': string
|
||||
'webhookList.webhookUpdated': string
|
||||
'actions.delete': string
|
||||
'actions.edit': string
|
||||
'actions.quarantine': string
|
||||
|
Loading…
Reference in New Issue
Block a user