Skip to content

Commit

Permalink
feat: migrates webhooks to RTK (#5087)
Browse files Browse the repository at this point in the history
  • Loading branch information
tiagoapolo authored Feb 17, 2025
1 parent 76c2f5f commit 965ea96
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 78 deletions.
70 changes: 0 additions & 70 deletions frontend/common/providers/withWebhooks.js

This file was deleted.

102 changes: 102 additions & 0 deletions frontend/common/services/useWebhooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { service } from 'common/service'
import { Res } from 'common/types/responses'
import { Req } from 'common/types/requests'

export const webhookService = service
.enhanceEndpoints({ addTagTypes: ['Webhooks'] })
.injectEndpoints({
endpoints: (builder) => ({
createWebhook: builder.mutation<Res['webhook'], Req['createWebhook']>({
invalidatesTags: [{ id: 'LIST', type: 'Webhooks' }],
query: ({ environmentId, ...rest }) => ({
body: {
...rest,
},
method: 'POST',
url: `environments/${environmentId}/webhooks/`,
}),
}),

deleteWebhook: builder.mutation<void, Req['deleteWebhook']>({
invalidatesTags: [{ id: 'LIST', type: 'Webhooks' }],
query: (query) => ({
method: 'DELETE',
url: `environments/${query.environmentId}/webhooks/${query.id}/`,
}),
}),

getWebhooks: builder.query<Res['webhooks'], Req['getWebhooks']>({
providesTags: [{ id: 'LIST', type: 'Webhooks' }],
query: (query) => ({
url: `environments/${query.environmentId}/webhooks/`,
}),
}),

updateWebhook: builder.mutation<Res['webhook'], Req['updateWebhook']>({
invalidatesTags: [{ id: 'LIST', type: 'Webhooks' }],
query: ({ environmentId, ...rest }) => ({
body: {
...rest,
},
method: 'PUT',
url: `environments/${environmentId}/webhooks/${rest.id}/`,
}),
}),
}),
})

export async function createWebhook(
store: any,
data: Req['createWebhook'],
options?: Parameters<
typeof webhookService.endpoints.createWebhook.initiate
>[1],
) {
return store.dispatch(
webhookService.endpoints.createWebhook.initiate(data, options),
)
}
export async function getWebhooks(
store: any,
data: Req['getWebhooks'],
options?: Parameters<typeof webhookService.endpoints.getWebhooks.initiate>[1],
) {
return store.dispatch(
webhookService.endpoints.getWebhooks.initiate(data, options),
)
}
export async function updateWebhook(
store: any,
data: Req['updateWebhook'],
options?: Parameters<
typeof webhookService.endpoints.updateWebhook.initiate
>[1],
) {
return store.dispatch(
webhookService.endpoints.deleteWebhook.initiate(data, options),
)
}
export async function deleteWebhook(
store: any,
data: Req['deleteWebhook'],
options?: Parameters<
typeof webhookService.endpoints.deleteWebhook.initiate
>[1],
) {
return store.dispatch(
webhookService.endpoints.deleteWebhook.initiate(data, options),
)
}

export const {
useCreateWebhookMutation,
useDeleteWebhookMutation,
useGetWebhooksQuery,
useUpdateWebhookMutation,
} = webhookService

/* Usage examples:
const { data, isLoading } = useGetWebhooksQuery({ environmentId: 1 }) //get hook
const [createWebhook, { isLoading, data, isSuccess }] = useCreateWebhookMutation() //create hook
webhookService.endpoints.getWebhooks.select({id: 2})(store.getState()) //access data from any function
*/
20 changes: 20 additions & 0 deletions frontend/common/types/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,26 @@ export type Req = {
| 'previous_billing_period'
| '90_day_period'
}
getWebhooks: {
environmentId: string
}
createWebhook: {
environmentId: string
enabled: boolean
secret: string
url: string
}
updateWebhook: {
id: number
environmentId: string
enabled: boolean
secret: string
url: string
}
deleteWebhook: {
id: number
environmentId: string
}
deleteIdentity: {
id: string
environmentId: string
Expand Down
11 changes: 11 additions & 0 deletions frontend/common/types/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,15 @@ export type HealthProvider = {
webhook_url: number
}

export type Webhook = {
id: number
url: string
secret: string
enabled: boolean
created_at: string
updated_at: string
}

export type Res = {
segments: PagedResponse<Segment>
segment: Segment
Expand All @@ -667,6 +676,8 @@ export type Res = {
projects: ProjectSummary[]
project: Project
environments: PagedResponse<Environment>
webhook: Webhook
webhooks: Webhook[]
organisationUsage: {
totals: {
flags: number
Expand Down
68 changes: 60 additions & 8 deletions frontend/web/components/pages/EnvironmentSettingsPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { Component } from 'react'
import ConfirmRemoveEnvironment from 'components/modals/ConfirmRemoveEnvironment'
import ProjectStore from 'common/stores/project-store'
import ConfigProvider from 'common/providers/ConfigProvider'
import withWebhooks from 'common/providers/withWebhooks'
import CreateWebhookModal from 'components/modals/CreateWebhook'
import ConfirmRemoveWebhook from 'components/modals/ConfirmRemoveWebhook'
import ConfirmToggleEnvFeature from 'components/modals/ConfirmToggleEnvFeature'
Expand All @@ -26,6 +25,12 @@ import { getSupportedContentType } from 'common/services/useSupportedContentType
import EnvironmentVersioningListener from 'components/EnvironmentVersioningListener'
import Format from 'common/utils/format'
import Setting from 'components/Setting'
import {
createWebhook,
deleteWebhook,
getWebhooks,
updateWebhook,
} from 'common/services/useWebhooks'

const showDisabledFlagOptions = [
{ label: 'Inherit from Project', value: null },
Expand All @@ -47,14 +52,31 @@ const EnvironmentSettingsPage = class extends Component {
environmentContentType: {},
roles: [],
showMetadataList: false,
webhooks: [],
webhooksLoading: true,
}
AppActions.getProject(this.props.match.params.projectId)
}

componentDidMount = () => {
API.trackPage(Constants.pages.ENVIRONMENT_SETTINGS)
this.getEnvironment()
this.props.getWebhooks()
this.fetchWebhooks(this.props.match.params.environmentId)
}

fetchWebhooks = (environmentId) => {
if (!environmentId) return

this.setState({ webhooksLoading: true })
getWebhooks(getStore(), { environmentId })
.then((res) => {
this.setState({
webhooks: res.data,
})
})
.finally(() => {
this.setState({ webhooksLoading: false })
})
}

getEnvironment = () => {
Expand Down Expand Up @@ -97,7 +119,7 @@ const EnvironmentSettingsPage = class extends Component {
this.setState({ environmentContentType: environmentContentType })
})
}
this.props.getWebhooks()
this.fetchWebhooks(this.props.match.params.environmentId)
}

onSave = () => {
Expand Down Expand Up @@ -200,7 +222,16 @@ const EnvironmentSettingsPage = class extends Component {
router={this.context.router}
environmentId={this.props.match.params.environmentId}
projectId={this.props.match.params.projectId}
save={this.props.createWebhook}
save={(webhook) =>
createWebhook(getStore(), {
environmentId: this.props.match.params.environmentId,
...webhook,
}).then((res) => {
this.setState({
webhooks: this.state.webhooks.concat(res.data),
})
})
}
/>,
'side-modal',
)
Expand All @@ -215,7 +246,18 @@ const EnvironmentSettingsPage = class extends Component {
isEdit
environmentId={this.props.match.params.environmentId}
projectId={this.props.match.params.projectId}
save={this.props.saveWebhook}
save={(webhook) =>
updateWebhook(getStore(), {
environmentId: this.props.match.params.environmentId,
...webhook,
}).then(() => {
this.setState({
webhooks: this.state.webhooks.map((w) =>
w.id === webhook.id ? webhook : w,
),
})
})
}
/>,
'side-modal',
)
Expand All @@ -228,7 +270,16 @@ const EnvironmentSettingsPage = class extends Component {
environmentId={this.props.match.params.environmentId}
projectId={this.props.match.params.projectId}
url={webhook.url}
cb={() => this.props.deleteWebhook(webhook)}
cb={() =>
deleteWebhook(getStore(), {
environmentId: this.props.match.params.environmentId,
id: webhook.id,
}).then(() => {
this.setState({
webhooks: this.state.webhooks.filter((w) => w.id !== webhook.id),
})
})
}
/>,
'p-0',
)
Expand All @@ -255,14 +306,15 @@ const EnvironmentSettingsPage = class extends Component {

render() {
const {
props: { webhooks, webhooksLoading },
state: {
allow_client_traits,
hide_sensitive_data,
name,
use_identity_composite_key_for_hashing,
use_identity_overrides_in_local_eval,
use_v2_feature_versioning,
webhooks,
webhooksLoading,
},
} = this
const has4EyesPermission = Utils.getPlansPermission('4_EYES')
Expand Down Expand Up @@ -917,4 +969,4 @@ const EnvironmentSettingsPage = class extends Component {

EnvironmentSettingsPage.propTypes = {}

module.exports = ConfigProvider(withWebhooks(EnvironmentSettingsPage))
module.exports = ConfigProvider(EnvironmentSettingsPage)

0 comments on commit 965ea96

Please sign in to comment.