Finish webhooks management POC
This commit is contained in:
parent
7efa970079
commit
bd757776f2
6 changed files with 293 additions and 0 deletions
|
@ -8,6 +8,7 @@ import { hideBin } from "yargs/helpers";
|
|||
import { installAppCommand } from "./commands/install-app-command";
|
||||
import { uninstallAppCommand } from "./commands/uninstall-app-command";
|
||||
import "dotenv/config";
|
||||
import { webhooksCommand } from "./commands/webhooks-command";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const pkg = require("../package.json");
|
||||
|
@ -117,6 +118,35 @@ const parser = yargs(hideBin(process.argv))
|
|||
});
|
||||
}
|
||||
)
|
||||
.command(
|
||||
"webhooks",
|
||||
"Print webhook details of installed app.",
|
||||
(yargs) => {
|
||||
return yargs
|
||||
.option("instanceUrl", {
|
||||
type: "string",
|
||||
desc: "URL to the Saleor GraphQL API. Example: https://example.com/graphql/",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("userEmail", {
|
||||
type: "string",
|
||||
desc: "Dashboard user email",
|
||||
demandOption: true,
|
||||
})
|
||||
.option("userPassword", {
|
||||
type: "string",
|
||||
desc: "Dashboard user password",
|
||||
demandOption: true,
|
||||
});
|
||||
},
|
||||
(argv) => {
|
||||
webhooksCommand({
|
||||
instanceUrl: argv.instanceUrl,
|
||||
userEmail: argv.userEmail,
|
||||
userPassword: argv.userPassword,
|
||||
});
|
||||
}
|
||||
)
|
||||
.demandCommand(1, "You need at least one command before moving on")
|
||||
.alias("h", "help")
|
||||
.wrap(null);
|
||||
|
|
|
@ -50,6 +50,11 @@ export const uninstallAppCommand = async ({
|
|||
|
||||
appListSpinner.succeed();
|
||||
|
||||
if (!installedApps.length) {
|
||||
console.log("No apps installed");
|
||||
return;
|
||||
}
|
||||
|
||||
// Display CLI interface with multiselect if none of the filters were provided
|
||||
if (appId || appName || manifestUrl) {
|
||||
const filteredApps = filterApps({
|
||||
|
|
120
apps/apps-cli/src/commands/webhooks-command.ts
Normal file
120
apps/apps-cli/src/commands/webhooks-command.ts
Normal file
|
@ -0,0 +1,120 @@
|
|||
import ora from "ora";
|
||||
import { getAccessTokenMutation } from "../saleor-api/operations/get-access-token-mutation";
|
||||
import { getAppsListQuery } from "../saleor-api/operations/get-apps-list-query";
|
||||
import { select } from "@inquirer/prompts";
|
||||
import { getAppWebhooksQuery } from "../saleor-api/operations/get-app-webhooks-query";
|
||||
import { removeWebhookMutation } from "../saleor-api/operations/remove-webhook-mutation";
|
||||
|
||||
interface DumpMetadataCommandArgs {
|
||||
instanceUrl: string;
|
||||
userEmail: string;
|
||||
userPassword: string;
|
||||
}
|
||||
|
||||
export const webhooksCommand = async ({
|
||||
instanceUrl,
|
||||
userEmail,
|
||||
userPassword,
|
||||
}: DumpMetadataCommandArgs) => {
|
||||
const loginSpinner = ora("Logging into Saleor instance").start();
|
||||
|
||||
const token = await getAccessTokenMutation({
|
||||
email: userEmail,
|
||||
password: userPassword,
|
||||
saleorApiUrl: instanceUrl,
|
||||
});
|
||||
|
||||
loginSpinner.succeed();
|
||||
|
||||
const appListSpinner = ora("Fetching installed apps").start();
|
||||
|
||||
const installedApps = await getAppsListQuery({
|
||||
saleorApiUrl: instanceUrl,
|
||||
token,
|
||||
});
|
||||
|
||||
appListSpinner.succeed();
|
||||
|
||||
if (!installedApps.length) {
|
||||
console.log("No apps installed");
|
||||
return;
|
||||
}
|
||||
|
||||
const appId = await select({
|
||||
message: "Select app",
|
||||
choices: installedApps.map((app) => ({
|
||||
name: app.name ? `${app.name} (${app.id})` : app.id,
|
||||
value: app.id,
|
||||
})),
|
||||
});
|
||||
|
||||
const webhooksData = await getAppWebhooksQuery({
|
||||
appId,
|
||||
saleorApiUrl: instanceUrl,
|
||||
token,
|
||||
});
|
||||
|
||||
if (!webhooksData.length) {
|
||||
console.log("Application has no webhooks configured");
|
||||
return;
|
||||
}
|
||||
|
||||
const webhook = await select({
|
||||
message: "Select webhook to investigate",
|
||||
choices: webhooksData.map((webhook) => ({
|
||||
name: `${webhook.name} (${[...webhook.syncEvents, ...webhook.asyncEvents]
|
||||
.map((e) => e.name)
|
||||
.join(", ")})`,
|
||||
value: webhook,
|
||||
description: `
|
||||
Target url: ${webhook.targetUrl}
|
||||
Active: ${webhook.isActive}
|
||||
Captured event deliveries count: ${webhook.eventDeliveries?.edges.length}
|
||||
`,
|
||||
})),
|
||||
});
|
||||
|
||||
const operation = await select({
|
||||
message: "Operation",
|
||||
choices: [
|
||||
{
|
||||
name: "List event deliveries",
|
||||
value: "list",
|
||||
},
|
||||
{
|
||||
name: "Remove webhook",
|
||||
value: "remove",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (operation === "list") {
|
||||
console.log("Number of entries: ", webhook.eventDeliveries?.edges.length);
|
||||
for (const deliveryEdge of webhook.eventDeliveries?.edges ?? []) {
|
||||
const delivery = deliveryEdge.node;
|
||||
|
||||
console.log(`
|
||||
Event type: ${delivery.eventType}
|
||||
Created at: ${delivery.createdAt}
|
||||
Status: ${delivery.status}`);
|
||||
const attempts = delivery.attempts?.edges ?? [];
|
||||
const lastAttempt = attempts[attempts.length - 1]?.node;
|
||||
|
||||
if (lastAttempt) {
|
||||
console.log(`
|
||||
Date of the last attempt: ${lastAttempt.createdAt}
|
||||
Status: ${lastAttempt.status}`);
|
||||
}
|
||||
}
|
||||
} else if (operation === "remove") {
|
||||
const removeSpinner = ora("Removing webhook...").start();
|
||||
|
||||
await removeWebhookMutation({
|
||||
saleorApiUrl: instanceUrl,
|
||||
token,
|
||||
webhookId: webhook.id,
|
||||
});
|
||||
|
||||
removeSpinner.succeed();
|
||||
}
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import request from "graphql-request";
|
||||
|
||||
import { graphql } from "../generated/gql";
|
||||
|
||||
const getAppMetadataQueryDocument = graphql(/* GraphQL */ `
|
||||
query GetAppMetadata {
|
||||
app(id: "QXBwOjE=") {
|
||||
metadata {
|
||||
key
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const getAppMetadataQuery = async ({
|
||||
saleorApiUrl,
|
||||
token,
|
||||
}: {
|
||||
saleorApiUrl: string;
|
||||
token: string;
|
||||
}) => {
|
||||
const { app } = await request(
|
||||
saleorApiUrl,
|
||||
getAppMetadataQueryDocument,
|
||||
{},
|
||||
{ "Authorization-Bearer": token }
|
||||
);
|
||||
|
||||
return app?.metadata ?? [];
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
import request from "graphql-request";
|
||||
|
||||
import { graphql } from "../generated/gql";
|
||||
|
||||
const getAppWebhooksQueryDocument = graphql(/* GraphQL */ `
|
||||
query GetAppWebhooks($id: ID!) {
|
||||
app(id: $id) {
|
||||
webhooks {
|
||||
id
|
||||
name
|
||||
isActive
|
||||
syncEvents {
|
||||
name
|
||||
eventType
|
||||
}
|
||||
asyncEvents {
|
||||
name
|
||||
eventType
|
||||
}
|
||||
targetUrl
|
||||
eventDeliveries(first: 10) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
createdAt
|
||||
status
|
||||
eventType
|
||||
attempts(first: 10) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
createdAt
|
||||
taskId
|
||||
duration
|
||||
response
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const getAppWebhooksQuery = async ({
|
||||
saleorApiUrl,
|
||||
token,
|
||||
appId,
|
||||
}: {
|
||||
saleorApiUrl: string;
|
||||
token: string;
|
||||
appId: string;
|
||||
}) => {
|
||||
const { app } = await request(
|
||||
saleorApiUrl,
|
||||
getAppWebhooksQueryDocument,
|
||||
{
|
||||
id: appId,
|
||||
},
|
||||
{ "Authorization-Bearer": token }
|
||||
);
|
||||
|
||||
return app?.webhooks ?? [];
|
||||
};
|
|
@ -0,0 +1,40 @@
|
|||
import request from "graphql-request";
|
||||
|
||||
import { graphql } from "../generated/gql";
|
||||
|
||||
const removeWebhookMutationDocument = graphql(/* GraphQL */ `
|
||||
mutation RemoveWebhook($webhookId: ID!) {
|
||||
webhookDelete(id: $webhookId) {
|
||||
errors {
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`);
|
||||
|
||||
export const removeWebhookMutation = async ({
|
||||
saleorApiUrl,
|
||||
token,
|
||||
webhookId,
|
||||
}: {
|
||||
saleorApiUrl: string;
|
||||
token: string;
|
||||
webhookId: string;
|
||||
}) => {
|
||||
const { webhookDelete } = await request(
|
||||
saleorApiUrl,
|
||||
removeWebhookMutationDocument,
|
||||
{
|
||||
webhookId,
|
||||
},
|
||||
{ "Authorization-Bearer": token }
|
||||
);
|
||||
|
||||
if (webhookDelete?.errors.length) {
|
||||
console.log("Sth went wrong", webhookDelete.errors);
|
||||
throw new Error(`Remove webhook mutation failed`);
|
||||
}
|
||||
|
||||
return;
|
||||
};
|
Loading…
Reference in a new issue