265
apps/console/src/__generated__/core/WebhooksSettingsPageQuery.graphql.ts
generated
Normal file
265
apps/console/src/__generated__/core/WebhooksSettingsPageQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,265 @@
|
||||
/**
|
||||
* @generated SignedSource<<ddaaa2d60cc045e841daaa3be6428cf2>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
|
||||
export type WebhooksSettingsPageQuery$variables = {
|
||||
organizationId: string;
|
||||
};
|
||||
export type WebhooksSettingsPageQuery$data = {
|
||||
readonly organization: {
|
||||
readonly __typename: "Organization";
|
||||
readonly id: string;
|
||||
readonly webhookConfigurations: {
|
||||
readonly edges: ReadonlyArray<{
|
||||
readonly node: {
|
||||
readonly endpointUrl: string;
|
||||
readonly id: string;
|
||||
readonly selectedEvents: ReadonlyArray<WebhookEventType>;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
} | {
|
||||
// This will never be '%other', but we need some
|
||||
// value in case none of the concrete values match.
|
||||
readonly __typename: "%other";
|
||||
};
|
||||
};
|
||||
export type WebhooksSettingsPageQuery = {
|
||||
response: WebhooksSettingsPageQuery$data;
|
||||
variables: WebhooksSettingsPageQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "organizationId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "organizationId"
|
||||
}
|
||||
],
|
||||
v2 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
v4 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfigurationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "edges",
|
||||
"plural": true,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfiguration",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endpointUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "selectedEvents",
|
||||
"storageKey": null
|
||||
},
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "cursor",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "PageInfo",
|
||||
"kind": "LinkedField",
|
||||
"name": "pageInfo",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endCursor",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "hasNextPage",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
v5 = [
|
||||
{
|
||||
"kind": "Literal",
|
||||
"name": "first",
|
||||
"value": 50
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "WebhooksSettingsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"kind": "RequiredField",
|
||||
"field": {
|
||||
"alias": "organization",
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": "webhookConfigurations",
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfigurationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "__WebhooksSettingsPage_webhookConfigurations_connection",
|
||||
"plural": false,
|
||||
"selections": (v4/*: any*/),
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
},
|
||||
"action": "THROW"
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "WebhooksSettingsPageQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": "organization",
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/),
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"concreteType": "WebhookConfigurationConnection",
|
||||
"kind": "LinkedField",
|
||||
"name": "webhookConfigurations",
|
||||
"plural": false,
|
||||
"selections": (v4/*: any*/),
|
||||
"storageKey": "webhookConfigurations(first:50)"
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v5/*: any*/),
|
||||
"filters": null,
|
||||
"handle": "connection",
|
||||
"key": "WebhooksSettingsPage_webhookConfigurations",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "webhookConfigurations"
|
||||
}
|
||||
],
|
||||
"type": "Organization",
|
||||
"abstractKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "e6aa5c6b8142b654e2a3b7bebec59f83",
|
||||
"id": null,
|
||||
"metadata": {
|
||||
"connection": [
|
||||
{
|
||||
"count": null,
|
||||
"cursor": null,
|
||||
"direction": "forward",
|
||||
"path": [
|
||||
"organization",
|
||||
"webhookConfigurations"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "WebhooksSettingsPageQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query WebhooksSettingsPageQuery(\n $organizationId: ID!\n) {\n organization: node(id: $organizationId) {\n __typename\n ... on Organization {\n id\n webhookConfigurations(first: 50) {\n edges {\n node {\n id\n endpointUrl\n selectedEvents\n __typename\n }\n cursor\n }\n pageInfo {\n endCursor\n hasNextPage\n }\n }\n }\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "2a68dcb3a875a982b7d8300aa72c012b";
|
||||
|
||||
export default node;
|
||||
177
apps/console/src/__generated__/core/WebhooksSettingsPage_createMutation.graphql.ts
generated
Normal file
177
apps/console/src/__generated__/core/WebhooksSettingsPage_createMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* @generated SignedSource<<56bfc2d1746edae72b0da44526fab12f>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
|
||||
export type CreateWebhookConfigurationInput = {
|
||||
endpointUrl: string;
|
||||
organizationId: string;
|
||||
selectedEvents: ReadonlyArray<WebhookEventType>;
|
||||
};
|
||||
export type WebhooksSettingsPage_createMutation$variables = {
|
||||
connections: ReadonlyArray<string>;
|
||||
input: CreateWebhookConfigurationInput;
|
||||
};
|
||||
export type WebhooksSettingsPage_createMutation$data = {
|
||||
readonly createWebhookConfiguration: {
|
||||
readonly webhookConfigurationEdge: {
|
||||
readonly node: {
|
||||
readonly endpointUrl: string;
|
||||
readonly id: string;
|
||||
readonly selectedEvents: ReadonlyArray<WebhookEventType>;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
export type WebhooksSettingsPage_createMutation = {
|
||||
response: WebhooksSettingsPage_createMutation$data;
|
||||
variables: WebhooksSettingsPage_createMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "connections"
|
||||
},
|
||||
v1 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
},
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfigurationEdge",
|
||||
"kind": "LinkedField",
|
||||
"name": "webhookConfigurationEdge",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfiguration",
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endpointUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "selectedEvents",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "WebhooksSettingsPage_createMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "CreateWebhookConfigurationPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "createWebhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": [
|
||||
(v1/*: any*/),
|
||||
(v0/*: any*/)
|
||||
],
|
||||
"kind": "Operation",
|
||||
"name": "WebhooksSettingsPage_createMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "CreateWebhookConfigurationPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "createWebhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"filters": null,
|
||||
"handle": "prependEdge",
|
||||
"key": "",
|
||||
"kind": "LinkedHandle",
|
||||
"name": "webhookConfigurationEdge",
|
||||
"handleArgs": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "connections",
|
||||
"variableName": "connections"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "0e88932f635b8f16e41f730abf9e05ff",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "WebhooksSettingsPage_createMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation WebhooksSettingsPage_createMutation(\n $input: CreateWebhookConfigurationInput!\n) {\n createWebhookConfiguration(input: $input) {\n webhookConfigurationEdge {\n node {\n id\n endpointUrl\n selectedEvents\n }\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "4e1a7692c83c4dda0c2fc557f15d669d";
|
||||
|
||||
export default node;
|
||||
132
apps/console/src/__generated__/core/WebhooksSettingsPage_deleteMutation.graphql.ts
generated
Normal file
132
apps/console/src/__generated__/core/WebhooksSettingsPage_deleteMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @generated SignedSource<<86d94ecf595a0048971276541e185905>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type DeleteWebhookConfigurationInput = {
|
||||
webhookConfigurationId: string;
|
||||
};
|
||||
export type WebhooksSettingsPage_deleteMutation$variables = {
|
||||
connections: ReadonlyArray<string>;
|
||||
input: DeleteWebhookConfigurationInput;
|
||||
};
|
||||
export type WebhooksSettingsPage_deleteMutation$data = {
|
||||
readonly deleteWebhookConfiguration: {
|
||||
readonly deletedWebhookConfigurationId: string;
|
||||
};
|
||||
};
|
||||
export type WebhooksSettingsPage_deleteMutation = {
|
||||
response: WebhooksSettingsPage_deleteMutation$data;
|
||||
variables: WebhooksSettingsPage_deleteMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "connections"
|
||||
},
|
||||
v1 = {
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
},
|
||||
v2 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
v3 = {
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "deletedWebhookConfigurationId",
|
||||
"storageKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": [
|
||||
(v0/*: any*/),
|
||||
(v1/*: any*/)
|
||||
],
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "WebhooksSettingsPage_deleteMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "DeleteWebhookConfigurationPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "deleteWebhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": [
|
||||
(v1/*: any*/),
|
||||
(v0/*: any*/)
|
||||
],
|
||||
"kind": "Operation",
|
||||
"name": "WebhooksSettingsPage_deleteMutation",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v2/*: any*/),
|
||||
"concreteType": "DeleteWebhookConfigurationPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "deleteWebhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v3/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"filters": null,
|
||||
"handle": "deleteEdge",
|
||||
"key": "",
|
||||
"kind": "ScalarHandle",
|
||||
"name": "deletedWebhookConfigurationId",
|
||||
"handleArgs": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "connections",
|
||||
"variableName": "connections"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "ae53fa4e16e4491720c1fdfc52301c09",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "WebhooksSettingsPage_deleteMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation WebhooksSettingsPage_deleteMutation(\n $input: DeleteWebhookConfigurationInput!\n) {\n deleteWebhookConfiguration(input: $input) {\n deletedWebhookConfigurationId\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "632fce2d89360bed2d857dd3feb90b9d";
|
||||
|
||||
export default node;
|
||||
124
apps/console/src/__generated__/core/WebhooksSettingsPage_signingSecretQuery.graphql.ts
generated
Normal file
124
apps/console/src/__generated__/core/WebhooksSettingsPage_signingSecretQuery.graphql.ts
generated
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* @generated SignedSource<<af555c91779a2fbceaae3666d5bae667>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type WebhooksSettingsPage_signingSecretQuery$variables = {
|
||||
webhookConfigurationId: string;
|
||||
};
|
||||
export type WebhooksSettingsPage_signingSecretQuery$data = {
|
||||
readonly node: {
|
||||
readonly signingSecret?: string;
|
||||
};
|
||||
};
|
||||
export type WebhooksSettingsPage_signingSecretQuery = {
|
||||
response: WebhooksSettingsPage_signingSecretQuery$data;
|
||||
variables: WebhooksSettingsPage_signingSecretQuery$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "webhookConfigurationId"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "id",
|
||||
"variableName": "webhookConfigurationId"
|
||||
}
|
||||
],
|
||||
v2 = {
|
||||
"kind": "InlineFragment",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "signingSecret",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "WebhookConfiguration",
|
||||
"abstractKey": null
|
||||
};
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "WebhooksSettingsPage_signingSecretQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
(v2/*: any*/)
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"type": "Query",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "WebhooksSettingsPage_signingSecretQuery",
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": (v1/*: any*/),
|
||||
"concreteType": null,
|
||||
"kind": "LinkedField",
|
||||
"name": "node",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "__typename",
|
||||
"storageKey": null
|
||||
},
|
||||
(v2/*: any*/),
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
]
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "266c1519da14eb09ed28e26cc6394f23",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "WebhooksSettingsPage_signingSecretQuery",
|
||||
"operationKind": "query",
|
||||
"text": "query WebhooksSettingsPage_signingSecretQuery(\n $webhookConfigurationId: ID!\n) {\n node(id: $webhookConfigurationId) {\n __typename\n ... on WebhookConfiguration {\n signingSecret\n }\n id\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "9d981d1a353a82f234e7ce79edb6d5d9";
|
||||
|
||||
export default node;
|
||||
132
apps/console/src/__generated__/core/WebhooksSettingsPage_updateMutation.graphql.ts
generated
Normal file
132
apps/console/src/__generated__/core/WebhooksSettingsPage_updateMutation.graphql.ts
generated
Normal file
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* @generated SignedSource<<3331839e2cc81d14ac1b2fcfe3fd84f1>>
|
||||
* @lightSyntaxTransform
|
||||
* @nogrep
|
||||
*/
|
||||
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { ConcreteRequest } from 'relay-runtime';
|
||||
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
|
||||
export type UpdateWebhookConfigurationInput = {
|
||||
endpointUrl?: string | null | undefined;
|
||||
id: string;
|
||||
selectedEvents?: ReadonlyArray<WebhookEventType> | null | undefined;
|
||||
};
|
||||
export type WebhooksSettingsPage_updateMutation$variables = {
|
||||
input: UpdateWebhookConfigurationInput;
|
||||
};
|
||||
export type WebhooksSettingsPage_updateMutation$data = {
|
||||
readonly updateWebhookConfiguration: {
|
||||
readonly webhookConfiguration: {
|
||||
readonly endpointUrl: string;
|
||||
readonly id: string;
|
||||
readonly selectedEvents: ReadonlyArray<WebhookEventType>;
|
||||
readonly updatedAt: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
export type WebhooksSettingsPage_updateMutation = {
|
||||
response: WebhooksSettingsPage_updateMutation$data;
|
||||
variables: WebhooksSettingsPage_updateMutation$variables;
|
||||
};
|
||||
|
||||
const node: ConcreteRequest = (function(){
|
||||
var v0 = [
|
||||
{
|
||||
"defaultValue": null,
|
||||
"kind": "LocalArgument",
|
||||
"name": "input"
|
||||
}
|
||||
],
|
||||
v1 = [
|
||||
{
|
||||
"alias": null,
|
||||
"args": [
|
||||
{
|
||||
"kind": "Variable",
|
||||
"name": "input",
|
||||
"variableName": "input"
|
||||
}
|
||||
],
|
||||
"concreteType": "UpdateWebhookConfigurationPayload",
|
||||
"kind": "LinkedField",
|
||||
"name": "updateWebhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"concreteType": "WebhookConfiguration",
|
||||
"kind": "LinkedField",
|
||||
"name": "webhookConfiguration",
|
||||
"plural": false,
|
||||
"selections": [
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "id",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "endpointUrl",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "selectedEvents",
|
||||
"storageKey": null
|
||||
},
|
||||
{
|
||||
"alias": null,
|
||||
"args": null,
|
||||
"kind": "ScalarField",
|
||||
"name": "updatedAt",
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
],
|
||||
"storageKey": null
|
||||
}
|
||||
];
|
||||
return {
|
||||
"fragment": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Fragment",
|
||||
"metadata": null,
|
||||
"name": "WebhooksSettingsPage_updateMutation",
|
||||
"selections": (v1/*: any*/),
|
||||
"type": "Mutation",
|
||||
"abstractKey": null
|
||||
},
|
||||
"kind": "Request",
|
||||
"operation": {
|
||||
"argumentDefinitions": (v0/*: any*/),
|
||||
"kind": "Operation",
|
||||
"name": "WebhooksSettingsPage_updateMutation",
|
||||
"selections": (v1/*: any*/)
|
||||
},
|
||||
"params": {
|
||||
"cacheID": "399a35c005f10dd321784a7533fb4f80",
|
||||
"id": null,
|
||||
"metadata": {},
|
||||
"name": "WebhooksSettingsPage_updateMutation",
|
||||
"operationKind": "mutation",
|
||||
"text": "mutation WebhooksSettingsPage_updateMutation(\n $input: UpdateWebhookConfigurationInput!\n) {\n updateWebhookConfiguration(input: $input) {\n webhookConfiguration {\n id\n endpointUrl\n selectedEvents\n updatedAt\n }\n }\n}\n"
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
(node as any).hash = "f974aae43d0ad8b5fe3cab60bd07a3ff";
|
||||
|
||||
export default node;
|
||||
@@ -2,6 +2,7 @@ import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
IconKey,
|
||||
IconLock,
|
||||
IconSend,
|
||||
IconSettingsGear2,
|
||||
PageHeader,
|
||||
TabLink,
|
||||
@@ -32,6 +33,10 @@ export default function SettingsLayout() {
|
||||
<IconKey size={20} />
|
||||
{__("SCIM")}
|
||||
</TabLink>
|
||||
<TabLink to={`/organizations/${organizationId}/settings/webhooks`}>
|
||||
<IconSend size={20} />
|
||||
{__("Webhooks")}
|
||||
</TabLink>
|
||||
</Tabs>
|
||||
|
||||
<Outlet />
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import { useEffect } from "react";
|
||||
import { useQueryLoader } from "react-relay";
|
||||
|
||||
import type { WebhooksSettingsPageQuery } from "#/__generated__/core/WebhooksSettingsPageQuery.graphql";
|
||||
import { useOrganizationId } from "#/hooks/useOrganizationId";
|
||||
import {
|
||||
WebhooksSettingsPage,
|
||||
webhooksSettingsPageQuery,
|
||||
} from "#/pages/organizations/settings/WebhooksSettingsPage";
|
||||
import { CoreRelayProvider } from "#/providers/CoreRelayProvider";
|
||||
|
||||
function WebhooksSettingsPageQueryLoader() {
|
||||
const organizationId = useOrganizationId();
|
||||
const [queryRef, loadQuery] = useQueryLoader<WebhooksSettingsPageQuery>(
|
||||
webhooksSettingsPageQuery,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
loadQuery({
|
||||
organizationId,
|
||||
});
|
||||
}, [loadQuery, organizationId]);
|
||||
|
||||
if (!queryRef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <WebhooksSettingsPage queryRef={queryRef} />;
|
||||
}
|
||||
|
||||
export default function WebhooksSettingsPageLoader() {
|
||||
return (
|
||||
<CoreRelayProvider>
|
||||
<WebhooksSettingsPageQueryLoader />
|
||||
</CoreRelayProvider>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,567 @@
|
||||
import { useTranslate } from "@probo/i18n";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Checkbox,
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
Field,
|
||||
IconPencil,
|
||||
IconPlusLarge,
|
||||
IconSquareBehindSquare2,
|
||||
IconTrashCan,
|
||||
Input,
|
||||
Label,
|
||||
Spinner,
|
||||
useDialogRef,
|
||||
useToast,
|
||||
} from "@probo/ui";
|
||||
import { useCallback, useState } from "react";
|
||||
import { type PreloadedQuery, usePreloadedQuery, useRelayEnvironment } from "react-relay";
|
||||
import { ConnectionHandler, fetchQuery, graphql } from "relay-runtime";
|
||||
import { z } from "zod";
|
||||
|
||||
import type { WebhooksSettingsPage_createMutation } from "#/__generated__/core/WebhooksSettingsPage_createMutation.graphql";
|
||||
import type { WebhooksSettingsPage_deleteMutation } from "#/__generated__/core/WebhooksSettingsPage_deleteMutation.graphql";
|
||||
import type { WebhooksSettingsPage_signingSecretQuery } from "#/__generated__/core/WebhooksSettingsPage_signingSecretQuery.graphql";
|
||||
import type { WebhooksSettingsPage_updateMutation } from "#/__generated__/core/WebhooksSettingsPage_updateMutation.graphql";
|
||||
import type { WebhooksSettingsPageQuery } from "#/__generated__/core/WebhooksSettingsPageQuery.graphql";
|
||||
import { useFormWithSchema } from "#/hooks/useFormWithSchema";
|
||||
import { useMutationWithToasts } from "#/hooks/useMutationWithToasts";
|
||||
|
||||
export const webhooksSettingsPageQuery = graphql`
|
||||
query WebhooksSettingsPageQuery($organizationId: ID!) {
|
||||
organization: node(id: $organizationId) @required(action: THROW) {
|
||||
__typename
|
||||
... on Organization {
|
||||
id
|
||||
webhookConfigurations(first: 50)
|
||||
@connection(key: "WebhooksSettingsPage_webhookConfigurations") {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
endpointUrl
|
||||
selectedEvents
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const createWebhookConfigurationMutation = graphql`
|
||||
mutation WebhooksSettingsPage_createMutation(
|
||||
$input: CreateWebhookConfigurationInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
createWebhookConfiguration(input: $input) {
|
||||
webhookConfigurationEdge @prependEdge(connections: $connections) {
|
||||
node {
|
||||
id
|
||||
endpointUrl
|
||||
selectedEvents
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const updateWebhookConfigurationMutation = graphql`
|
||||
mutation WebhooksSettingsPage_updateMutation(
|
||||
$input: UpdateWebhookConfigurationInput!
|
||||
) {
|
||||
updateWebhookConfiguration(input: $input) {
|
||||
webhookConfiguration {
|
||||
id
|
||||
endpointUrl
|
||||
selectedEvents
|
||||
updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const signingSecretQuery = graphql`
|
||||
query WebhooksSettingsPage_signingSecretQuery($webhookConfigurationId: ID!) {
|
||||
node(id: $webhookConfigurationId) {
|
||||
... on WebhookConfiguration {
|
||||
signingSecret
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const deleteWebhookConfigurationMutation = graphql`
|
||||
mutation WebhooksSettingsPage_deleteMutation(
|
||||
$input: DeleteWebhookConfigurationInput!
|
||||
$connections: [ID!]!
|
||||
) {
|
||||
deleteWebhookConfiguration(input: $input) {
|
||||
deletedWebhookConfigurationId @deleteEdge(connections: $connections)
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const EVENT_TYPES = [
|
||||
{ value: "MEETING_CREATED", label: "meeting:created" },
|
||||
{ value: "MEETING_UPDATED", label: "meeting:updated" },
|
||||
{ value: "MEETING_DELETED", label: "meeting:deleted" },
|
||||
{ value: "VENDOR_CREATED", label: "vendor:created" },
|
||||
{ value: "VENDOR_UPDATED", label: "vendor:updated" },
|
||||
{ value: "VENDOR_DELETED", label: "vendor:deleted" },
|
||||
] as const;
|
||||
|
||||
type WebhookEventType = (typeof EVENT_TYPES)[number]["value"];
|
||||
|
||||
const WEBHOOK_EVENT_VALUES = EVENT_TYPES.map(e => e.value) as [
|
||||
WebhookEventType,
|
||||
...WebhookEventType[],
|
||||
];
|
||||
|
||||
const webhookFormSchema = z.object({
|
||||
endpointUrl: z
|
||||
.string()
|
||||
.min(1, "Endpoint URL is required")
|
||||
.url("Please enter a valid URL")
|
||||
.refine(
|
||||
(val) => {
|
||||
try {
|
||||
const url = new URL(val);
|
||||
return url.protocol === "http:" || url.protocol === "https:";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
"URL must use http:// or https://",
|
||||
),
|
||||
selectedEvents: z
|
||||
.array(z.enum(WEBHOOK_EVENT_VALUES))
|
||||
.min(1, "At least one event must be selected"),
|
||||
});
|
||||
|
||||
type WebhookFormData = z.infer<typeof webhookFormSchema>;
|
||||
|
||||
function WebhookFormDialog({
|
||||
mode,
|
||||
initialValues,
|
||||
onSubmit,
|
||||
isSubmitting,
|
||||
trigger,
|
||||
}: {
|
||||
mode: "create" | "edit";
|
||||
initialValues?: WebhookFormData;
|
||||
onSubmit: (values: WebhookFormData) => void;
|
||||
isSubmitting: boolean;
|
||||
trigger: React.ReactNode;
|
||||
}) {
|
||||
const { __ } = useTranslate();
|
||||
const dialogRef = useDialogRef();
|
||||
const { register, handleSubmit, formState, setValue, watch, reset }
|
||||
= useFormWithSchema(webhookFormSchema, {
|
||||
defaultValues: {
|
||||
endpointUrl: initialValues?.endpointUrl ?? "",
|
||||
selectedEvents: initialValues?.selectedEvents ?? [],
|
||||
},
|
||||
});
|
||||
|
||||
const selectedEvents = watch("selectedEvents");
|
||||
|
||||
const handleToggleEvent = (event: WebhookEventType) => {
|
||||
const current = selectedEvents ?? [];
|
||||
const next = current.includes(event)
|
||||
? current.filter(e => e !== event)
|
||||
: [...current, event];
|
||||
setValue("selectedEvents", next, { shouldValidate: formState.isSubmitted });
|
||||
};
|
||||
|
||||
const onFormSubmit = (data: WebhookFormData) => {
|
||||
onSubmit(data);
|
||||
dialogRef.current?.close();
|
||||
reset(data);
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
ref={dialogRef}
|
||||
trigger={trigger}
|
||||
title={
|
||||
mode === "create"
|
||||
? __("Add Webhook Configuration")
|
||||
: __("Edit Webhook Configuration")
|
||||
}
|
||||
className="max-w-lg"
|
||||
>
|
||||
<form onSubmit={e => void handleSubmit(onFormSubmit)(e)}>
|
||||
<DialogContent padded>
|
||||
<div className="space-y-4">
|
||||
<Field
|
||||
label={__("Endpoint URL")}
|
||||
error={formState.errors.endpointUrl?.message}
|
||||
required
|
||||
>
|
||||
<Input
|
||||
{...register("endpointUrl")}
|
||||
type="url"
|
||||
placeholder={__("https://example.com/webhook")}
|
||||
/>
|
||||
</Field>
|
||||
<div>
|
||||
<Label>{__("Events")}</Label>
|
||||
<p className="text-sm text-txt-tertiary mb-2">
|
||||
{__("Select the events that will trigger this webhook.")}
|
||||
</p>
|
||||
<div className="space-y-2">
|
||||
{EVENT_TYPES.map(event => (
|
||||
<label
|
||||
key={event.value}
|
||||
className="flex items-center gap-2 cursor-pointer"
|
||||
>
|
||||
<Checkbox
|
||||
checked={selectedEvents?.includes(event.value) ?? false}
|
||||
onChange={() => handleToggleEvent(event.value)}
|
||||
/>
|
||||
<span className="text-sm font-mono">{event.label}</span>
|
||||
</label>
|
||||
))}
|
||||
</div>
|
||||
{formState.errors.selectedEvents?.message && (
|
||||
<p className="text-xs text-red-600 mt-1">
|
||||
{formState.errors.selectedEvents.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting
|
||||
? <Spinner size={16} />
|
||||
: mode === "create"
|
||||
? __("Create")
|
||||
: __("Save")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
export function WebhooksSettingsPage(props: {
|
||||
queryRef: PreloadedQuery<WebhooksSettingsPageQuery>;
|
||||
}) {
|
||||
const { queryRef } = props;
|
||||
const { __ } = useTranslate();
|
||||
const { toast } = useToast();
|
||||
const environment = useRelayEnvironment();
|
||||
const deleteDialogRef = useDialogRef();
|
||||
const [deletingId, setDeletingId] = useState<string | null>(null);
|
||||
const [revealedSecrets, setRevealedSecrets] = useState<Record<string, string>>({});
|
||||
const [loadingSecrets, setLoadingSecrets] = useState<Set<string>>(new Set());
|
||||
|
||||
const fetchSigningSecret = useCallback(
|
||||
async (webhookConfigurationId: string): Promise<string | null> => {
|
||||
// Return cached secret if already fetched
|
||||
if (revealedSecrets[webhookConfigurationId]) {
|
||||
return revealedSecrets[webhookConfigurationId];
|
||||
}
|
||||
|
||||
setLoadingSecrets(prev => new Set(prev).add(webhookConfigurationId));
|
||||
|
||||
try {
|
||||
const data = await fetchQuery<WebhooksSettingsPage_signingSecretQuery>(
|
||||
environment,
|
||||
signingSecretQuery,
|
||||
{ webhookConfigurationId },
|
||||
).toPromise();
|
||||
|
||||
const secret = data?.node?.signingSecret;
|
||||
if (secret) {
|
||||
setRevealedSecrets(prev => ({ ...prev, [webhookConfigurationId]: secret }));
|
||||
return secret;
|
||||
}
|
||||
return null;
|
||||
} catch {
|
||||
toast({
|
||||
title: __("Error"),
|
||||
description: __("Failed to load signing secret."),
|
||||
variant: "error",
|
||||
});
|
||||
return null;
|
||||
} finally {
|
||||
setLoadingSecrets((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.delete(webhookConfigurationId);
|
||||
return next;
|
||||
});
|
||||
}
|
||||
},
|
||||
[environment, revealedSecrets, toast, __],
|
||||
);
|
||||
|
||||
const toggleRevealSecret = (id: string) => {
|
||||
if (revealedSecrets[id]) {
|
||||
setRevealedSecrets((prev) => {
|
||||
const next = { ...prev };
|
||||
delete next[id];
|
||||
return next;
|
||||
});
|
||||
} else {
|
||||
void fetchSigningSecret(id);
|
||||
}
|
||||
};
|
||||
|
||||
const copyToClipboard = async (webhookConfigurationId: string, label: string) => {
|
||||
const secret = await fetchSigningSecret(webhookConfigurationId);
|
||||
if (secret) {
|
||||
void navigator.clipboard.writeText(secret);
|
||||
toast({
|
||||
title: __("Copied to clipboard"),
|
||||
description: label,
|
||||
variant: "success",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const { organization } = usePreloadedQuery<WebhooksSettingsPageQuery>(
|
||||
webhooksSettingsPageQuery,
|
||||
queryRef,
|
||||
);
|
||||
if (organization.__typename === "%other") {
|
||||
throw new Error("Relay node is not an organization");
|
||||
}
|
||||
|
||||
const [createWebhook, isCreating]
|
||||
= useMutationWithToasts<WebhooksSettingsPage_createMutation>(
|
||||
createWebhookConfigurationMutation,
|
||||
{
|
||||
successMessage: __("Webhook created successfully"),
|
||||
errorMessage: __("Failed to create webhook"),
|
||||
},
|
||||
);
|
||||
|
||||
const [updateWebhook, isUpdating]
|
||||
= useMutationWithToasts<WebhooksSettingsPage_updateMutation>(
|
||||
updateWebhookConfigurationMutation,
|
||||
{
|
||||
successMessage: __("Webhook updated successfully"),
|
||||
errorMessage: __("Failed to update webhook"),
|
||||
},
|
||||
);
|
||||
|
||||
const [deleteWebhook, isDeleting]
|
||||
= useMutationWithToasts<WebhooksSettingsPage_deleteMutation>(
|
||||
deleteWebhookConfigurationMutation,
|
||||
{
|
||||
successMessage: __("Webhook deleted successfully"),
|
||||
errorMessage: __("Failed to delete webhook"),
|
||||
},
|
||||
);
|
||||
|
||||
const webhooks = organization.webhookConfigurations?.edges ?? [];
|
||||
|
||||
const connectionId = ConnectionHandler.getConnectionID(
|
||||
organization.id,
|
||||
"WebhooksSettingsPage_webhookConfigurations",
|
||||
);
|
||||
|
||||
const handleCreate = (values: WebhookFormData) => {
|
||||
void createWebhook({
|
||||
variables: {
|
||||
input: {
|
||||
organizationId: organization.id,
|
||||
endpointUrl: values.endpointUrl,
|
||||
selectedEvents: values.selectedEvents,
|
||||
},
|
||||
connections: [connectionId],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleUpdate = (id: string, values: WebhookFormData) => {
|
||||
void updateWebhook({
|
||||
variables: {
|
||||
input: {
|
||||
id,
|
||||
endpointUrl: values.endpointUrl,
|
||||
selectedEvents: values.selectedEvents,
|
||||
},
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = (id: string) => {
|
||||
void deleteWebhook({
|
||||
variables: {
|
||||
input: {
|
||||
webhookConfigurationId: id,
|
||||
},
|
||||
connections: [connectionId],
|
||||
},
|
||||
onSuccess: () => {
|
||||
setDeletingId(null);
|
||||
deleteDialogRef.current?.close();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-base font-medium">{__("Webhook Configurations")}</h2>
|
||||
<p className="text-sm text-txt-tertiary">
|
||||
{__(
|
||||
"Configure webhooks to receive notifications when events occur in your organization.",
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
<WebhookFormDialog
|
||||
mode="create"
|
||||
onSubmit={handleCreate}
|
||||
isSubmitting={isCreating}
|
||||
trigger={(
|
||||
<Button icon={IconPlusLarge}>
|
||||
{__("Add Webhook Configuration")}
|
||||
</Button>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{webhooks.length === 0
|
||||
? (
|
||||
<Card padded>
|
||||
<div className="text-center py-8">
|
||||
<p className="text-sm text-txt-tertiary">
|
||||
{__("No webhook configurations yet. Add one to get started.")}
|
||||
</p>
|
||||
</div>
|
||||
</Card>
|
||||
)
|
||||
: (
|
||||
<div className="space-y-3">
|
||||
{webhooks.map(({ node: webhook }) => (
|
||||
<Card key={webhook.id} padded>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div className="flex-1 min-w-0 space-y-2">
|
||||
<div>
|
||||
<Label>{__("Endpoint URL")}</Label>
|
||||
<p className="text-sm font-mono text-txt-secondary truncate">
|
||||
{webhook.endpointUrl}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label>{__("Signing Secret")}</Label>
|
||||
<div className="flex items-center gap-2 mt-1">
|
||||
<code className="flex-1 bg-subtle p-2 rounded text-sm font-mono break-all">
|
||||
{revealedSecrets[webhook.id]
|
||||
? revealedSecrets[webhook.id]
|
||||
: "••••••••••••••••••••••••••••••••"}
|
||||
</code>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => toggleRevealSecret(webhook.id)}
|
||||
disabled={loadingSecrets.has(webhook.id)}
|
||||
>
|
||||
{loadingSecrets.has(webhook.id)
|
||||
? <Spinner size={16} />
|
||||
: revealedSecrets[webhook.id]
|
||||
? __("Hide")
|
||||
: __("Show")}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => void copyToClipboard(webhook.id, __("Signing Secret"))}
|
||||
disabled={loadingSecrets.has(webhook.id)}
|
||||
icon={IconSquareBehindSquare2}
|
||||
aria-label={__("Copy signing secret")}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label>{__("Events")}</Label>
|
||||
<div className="flex flex-wrap gap-1.5 mt-1">
|
||||
{webhook.selectedEvents.map((event) => {
|
||||
const eventLabel
|
||||
= EVENT_TYPES.find(e => e.value === event)?.label ?? event;
|
||||
return (
|
||||
<span
|
||||
key={event}
|
||||
className="inline-flex items-center rounded-md bg-surface-secondary px-2 py-0.5 text-xs font-mono text-txt-secondary border border-border-solid"
|
||||
>
|
||||
{eventLabel}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-1 shrink-0">
|
||||
<WebhookFormDialog
|
||||
mode="edit"
|
||||
initialValues={{
|
||||
endpointUrl: webhook.endpointUrl,
|
||||
selectedEvents: webhook.selectedEvents as WebhookEventType[],
|
||||
}}
|
||||
onSubmit={values => handleUpdate(webhook.id, values)}
|
||||
isSubmitting={isUpdating}
|
||||
trigger={(
|
||||
<Button
|
||||
variant="secondary"
|
||||
icon={IconPencil}
|
||||
aria-label={__("Edit webhook")}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
variant="quaternary"
|
||||
icon={IconTrashCan}
|
||||
aria-label={__("Delete webhook")}
|
||||
className="text-red-600 hover:text-red-700"
|
||||
onClick={() => {
|
||||
setDeletingId(webhook.id);
|
||||
deleteDialogRef.current?.open();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<Dialog
|
||||
ref={deleteDialogRef}
|
||||
title={__("Delete Webhook")}
|
||||
className="max-w-md"
|
||||
>
|
||||
<DialogContent padded>
|
||||
<p className="text-txt-secondary">
|
||||
{__(
|
||||
"Are you sure you want to delete this webhook configuration?",
|
||||
)}
|
||||
</p>
|
||||
<p className="text-txt-secondary mt-2">
|
||||
{__("This action cannot be undone.")}
|
||||
</p>
|
||||
</DialogContent>
|
||||
<DialogFooter>
|
||||
<Button
|
||||
variant="danger"
|
||||
onClick={() => deletingId && handleDelete(deletingId)}
|
||||
disabled={isDeleting}
|
||||
icon={isDeleting ? Spinner : IconTrashCan}
|
||||
>
|
||||
{isDeleting
|
||||
? __("Deleting...")
|
||||
: __("Delete")}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</Dialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -205,6 +205,13 @@ const routes = [
|
||||
import("./pages/iam/organizations/settings/SCIMSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
{
|
||||
path: "webhooks",
|
||||
Component: lazy(
|
||||
() =>
|
||||
import("./pages/iam/organizations/settings/WebhooksSettingsPageLoader"),
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
...peopleRoutes,
|
||||
|
||||
Reference in New Issue
Block a user