2021-12-13 14:43:30 +00:00
|
|
|
import {
|
2021-12-23 12:42:10 +00:00
|
|
|
WebhookEventTypeAsyncEnum,
|
2022-06-21 09:36:55 +00:00
|
|
|
WebhookEventTypeSyncEnum,
|
2023-01-16 09:45:12 +00:00
|
|
|
} from "@dashboard/graphql";
|
|
|
|
import { ChangeEvent } from "@dashboard/hooks/useForm";
|
2023-01-24 13:59:14 +00:00
|
|
|
import { capitalize } from "@dashboard/misc";
|
2023-01-16 09:45:12 +00:00
|
|
|
import { toggle } from "@dashboard/utils/lists";
|
2023-01-24 13:59:14 +00:00
|
|
|
import {
|
2023-03-23 15:31:04 +00:00
|
|
|
DocumentNode,
|
|
|
|
FieldNode,
|
2023-01-24 13:59:14 +00:00
|
|
|
InlineFragmentNode,
|
|
|
|
ObjectFieldNode,
|
2023-03-23 15:31:04 +00:00
|
|
|
OperationDefinitionNode,
|
2023-01-24 13:59:14 +00:00
|
|
|
parse,
|
|
|
|
print,
|
2023-03-23 15:31:04 +00:00
|
|
|
SelectionNode,
|
2023-01-24 13:59:14 +00:00
|
|
|
visit,
|
|
|
|
} from "graphql";
|
2023-02-23 09:03:41 +00:00
|
|
|
import isEmpty from "lodash/isEmpty";
|
|
|
|
import React, { Dispatch, SetStateAction } from "react";
|
2021-12-13 14:43:30 +00:00
|
|
|
|
2023-02-23 09:03:41 +00:00
|
|
|
import { WebhookFormData } from "./components/WebhookDetailsPage";
|
2023-03-23 15:31:04 +00:00
|
|
|
import { filterSelectedAsyncEvents, IntrospectionNode } from "./utils";
|
2021-12-13 14:43:30 +00:00
|
|
|
|
2023-02-23 09:03:41 +00:00
|
|
|
interface CreateSyncEventsSelectHandler {
|
|
|
|
change: (event: ChangeEvent, cb?: () => void) => void;
|
|
|
|
data: WebhookFormData;
|
|
|
|
query: string;
|
|
|
|
setQuery: Dispatch<SetStateAction<string>>;
|
2023-03-23 15:31:04 +00:00
|
|
|
availableEvents: IntrospectionNode[];
|
2023-02-23 09:03:41 +00:00
|
|
|
}
|
|
|
|
|
2023-01-24 13:59:14 +00:00
|
|
|
export const createSyncEventsSelectHandler =
|
2023-03-23 15:31:04 +00:00
|
|
|
({
|
|
|
|
change,
|
|
|
|
data,
|
|
|
|
query,
|
|
|
|
setQuery,
|
|
|
|
availableEvents,
|
|
|
|
}: CreateSyncEventsSelectHandler) =>
|
2023-01-24 13:59:14 +00:00
|
|
|
(event: ChangeEvent) => {
|
2023-02-23 09:03:41 +00:00
|
|
|
const { syncEvents, asyncEvents } = data;
|
2023-01-24 13:59:14 +00:00
|
|
|
const events = toggle(event.target.value, syncEvents, (a, b) => a === b);
|
|
|
|
|
|
|
|
// Clear asyncEvents
|
2023-02-23 09:03:41 +00:00
|
|
|
if (!isEmpty(asyncEvents)) {
|
|
|
|
setQuery("");
|
|
|
|
|
|
|
|
change({
|
|
|
|
target: {
|
|
|
|
name: "asyncEvents",
|
|
|
|
value: [],
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2023-01-24 13:59:14 +00:00
|
|
|
|
|
|
|
change({
|
|
|
|
target: {
|
|
|
|
name: "syncEvents",
|
|
|
|
value: events,
|
|
|
|
},
|
|
|
|
});
|
2023-02-23 09:03:41 +00:00
|
|
|
|
2023-03-23 15:31:04 +00:00
|
|
|
handleQuery({ events, query, setQuery, availableEvents });
|
2023-01-24 13:59:14 +00:00
|
|
|
};
|
|
|
|
|
2023-02-23 09:03:41 +00:00
|
|
|
interface CreateAsyncEventsSelectHandler {
|
|
|
|
change: (event: ChangeEvent, cb?: () => void) => void;
|
|
|
|
data: WebhookFormData;
|
|
|
|
query: string;
|
|
|
|
setQuery: Dispatch<SetStateAction<string>>;
|
2023-03-23 15:31:04 +00:00
|
|
|
availableEvents: IntrospectionNode[];
|
2023-02-23 09:03:41 +00:00
|
|
|
}
|
|
|
|
|
2023-01-24 13:59:14 +00:00
|
|
|
export const createAsyncEventsSelectHandler =
|
2023-03-23 15:31:04 +00:00
|
|
|
({
|
|
|
|
change,
|
|
|
|
data,
|
|
|
|
query,
|
|
|
|
setQuery,
|
|
|
|
availableEvents,
|
|
|
|
}: CreateAsyncEventsSelectHandler) =>
|
2023-01-24 13:59:14 +00:00
|
|
|
(event: ChangeEvent) => {
|
2023-02-23 09:03:41 +00:00
|
|
|
const { syncEvents, asyncEvents } = data;
|
2023-01-24 13:59:14 +00:00
|
|
|
const events = toggle(event.target.value, asyncEvents, (a, b) => a === b);
|
|
|
|
const filteredEvents = filterSelectedAsyncEvents(events);
|
|
|
|
|
|
|
|
// Clear syncEvents
|
2023-02-23 09:03:41 +00:00
|
|
|
if (!isEmpty(syncEvents)) {
|
|
|
|
setQuery("");
|
|
|
|
|
|
|
|
change({
|
|
|
|
target: {
|
|
|
|
name: "syncEvents",
|
|
|
|
value: [],
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2023-01-24 13:59:14 +00:00
|
|
|
|
|
|
|
change({
|
|
|
|
target: {
|
|
|
|
name: "asyncEvents",
|
|
|
|
value: filteredEvents,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2023-03-23 15:31:04 +00:00
|
|
|
handleQuery({ events: filteredEvents, query, setQuery, availableEvents });
|
2023-01-24 13:59:14 +00:00
|
|
|
};
|
|
|
|
|
2023-03-23 15:31:04 +00:00
|
|
|
const enumToEventName = (value: string) =>
|
|
|
|
value
|
|
|
|
.toLowerCase()
|
|
|
|
.split("_")
|
|
|
|
.map(chunk => capitalize(chunk))
|
|
|
|
.join("");
|
2023-02-21 11:38:28 +00:00
|
|
|
|
2023-03-23 15:31:04 +00:00
|
|
|
interface HandleQuery {
|
|
|
|
events: WebhookEventTypeAsyncEnum[] | WebhookEventTypeSyncEnum[];
|
|
|
|
query: string;
|
|
|
|
setQuery: React.Dispatch<React.SetStateAction<string>>;
|
|
|
|
availableEvents: IntrospectionNode[];
|
|
|
|
}
|
|
|
|
|
|
|
|
const handleQuery = ({
|
|
|
|
events,
|
|
|
|
query,
|
|
|
|
setQuery,
|
|
|
|
availableEvents,
|
|
|
|
}: HandleQuery) => {
|
|
|
|
const availableEventNames = availableEvents.map(({ name }) => name);
|
|
|
|
const eventsNames: string[] = events
|
|
|
|
.map(enumToEventName)
|
|
|
|
.filter(eventName => availableEventNames.includes(eventName));
|
|
|
|
|
|
|
|
if (eventsNames.length > 0 && query.length === 0) {
|
2023-01-24 13:59:14 +00:00
|
|
|
setQuery(
|
2023-03-23 15:31:04 +00:00
|
|
|
print(
|
|
|
|
parse(
|
|
|
|
`subscription { event { ... on ${eventsNames[0]} { __typename } } }`,
|
|
|
|
),
|
|
|
|
),
|
2023-01-24 13:59:14 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (query.length > 0) {
|
2023-03-23 15:31:04 +00:00
|
|
|
try {
|
|
|
|
const ast = parse(query);
|
|
|
|
|
|
|
|
const editedAst: DocumentNode = visit(ast, {
|
|
|
|
SelectionSet(node, _key, parent) {
|
|
|
|
if ((parent as ObjectFieldNode).name?.value === "event") {
|
|
|
|
const queryEvents = node.selections.map(
|
|
|
|
selection =>
|
|
|
|
(selection as InlineFragmentNode).typeCondition.name.value,
|
|
|
|
);
|
|
|
|
|
|
|
|
const eventsToRemove = queryEvents.filter(
|
|
|
|
event => !eventsNames.includes(event),
|
2023-01-24 13:59:14 +00:00
|
|
|
);
|
2023-03-23 15:31:04 +00:00
|
|
|
|
|
|
|
const selections = [...node.selections].filter(
|
|
|
|
selection =>
|
|
|
|
!eventsToRemove.includes(
|
|
|
|
(selection as InlineFragmentNode).typeCondition.name.value,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
eventsNames.forEach(event => {
|
|
|
|
if (!queryEvents.includes(event)) {
|
|
|
|
const eventFragment = createEventInlineFragment(event);
|
|
|
|
selections.push(eventFragment);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
if (!selections.length) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
...node,
|
|
|
|
selections,
|
|
|
|
};
|
2023-01-24 13:59:14 +00:00
|
|
|
}
|
2023-03-23 15:31:04 +00:00
|
|
|
},
|
|
|
|
});
|
2021-12-13 14:43:30 +00:00
|
|
|
|
2023-03-23 15:31:04 +00:00
|
|
|
setQuery(isEmptyQuery(editedAst) ? "" : print(editedAst));
|
|
|
|
} catch (e) {
|
|
|
|
console.error(e);
|
|
|
|
}
|
2023-01-24 13:59:14 +00:00
|
|
|
}
|
2021-12-13 14:43:30 +00:00
|
|
|
};
|
2023-03-23 15:31:04 +00:00
|
|
|
|
|
|
|
const createEventInlineFragment = (event: string): SelectionNode => ({
|
|
|
|
kind: "InlineFragment",
|
|
|
|
typeCondition: {
|
|
|
|
kind: "NamedType",
|
|
|
|
name: {
|
|
|
|
kind: "Name",
|
|
|
|
value: event,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
selectionSet: {
|
|
|
|
kind: "SelectionSet",
|
|
|
|
selections: [
|
|
|
|
{ kind: "Field", name: { kind: "Name", value: "__typename" } },
|
|
|
|
],
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
const isEmptyQuery = (ast: DocumentNode): boolean => {
|
|
|
|
let empty = false;
|
|
|
|
|
|
|
|
visit(ast, {
|
|
|
|
SelectionSet(node, _key, parent) {
|
|
|
|
if ((parent as OperationDefinitionNode).operation === "subscription") {
|
|
|
|
const event = node.selections.filter(
|
|
|
|
selection => (selection as FieldNode).name?.value === "event",
|
|
|
|
)[0] as FieldNode;
|
|
|
|
if (!event.selectionSet) {
|
|
|
|
empty = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
return empty;
|
|
|
|
};
|