From 51d210cd94a9d11e10737e6867c7cd1955e70491 Mon Sep 17 00:00:00 2001 From: Robert Field Date: Sat, 24 Aug 2024 11:24:54 +0100 Subject: [PATCH] feat: add klevu int to generate (#242) * feat: support klevu config during generate command * chore: add changeset --- .changeset/lovely-dragons-listen.md | 5 + .../src/commands/generate/d2c/d2c-command.tsx | 219 ++---------------- .../src/commands/generate/d2c/prompts.ts | 162 +++++++++++++ .../src/commands/generate/d2c/tasks/types.ts | 3 +- .../generate/utils/resolve-source-input.ts | 33 +++ .../src/commands/generate/utils/types.ts | 40 ++++ .../algolia/algolia-integration-command.tsx | 14 +- .../setup-klevu-custom-api-entry-tasks.ts | 2 +- 8 files changed, 264 insertions(+), 214 deletions(-) create mode 100644 .changeset/lovely-dragons-listen.md create mode 100644 packages/composable-cli/src/commands/generate/d2c/prompts.ts create mode 100644 packages/composable-cli/src/commands/generate/utils/resolve-source-input.ts create mode 100644 packages/composable-cli/src/commands/generate/utils/types.ts diff --git a/.changeset/lovely-dragons-listen.md b/.changeset/lovely-dragons-listen.md new file mode 100644 index 00000000..e0b0e95f --- /dev/null +++ b/.changeset/lovely-dragons-listen.md @@ -0,0 +1,5 @@ +--- +"composable-cli": minor +--- + +Support Klevu integration auto config during generate command diff --git a/packages/composable-cli/src/commands/generate/d2c/d2c-command.tsx b/packages/composable-cli/src/commands/generate/d2c/d2c-command.tsx index 1843c2e2..998435f6 100644 --- a/packages/composable-cli/src/commands/generate/d2c/d2c-command.tsx +++ b/packages/composable-cli/src/commands/generate/d2c/d2c-command.tsx @@ -51,7 +51,6 @@ import { createEPPaymentTasks } from "../../payments/manual/tasks/ep-payment" import { D2CSetupTaskContext } from "./tasks/types" import { createAlgoliaTask } from "../../integration/algolia/tasks/algolia-task" import { resolveConfStoreData } from "../../integration/algolia/algolia-integration-command" -import { AlgoliaIntegrationSetup } from "../../integration/algolia/utility/integration-hub/setup-algolia-schema" import { renderError, renderInfo, renderSuccess, renderWarning } from "../../ui" import { formatPackageManagerCommand, @@ -61,6 +60,10 @@ import { import chalk from "chalk" import { basename, resolvePath } from "../../path" import { SchematicEngineHost } from "../utils/schematic-engine-host" +import { createKlevuTask } from "../../integration/klevu/tasks/klevu-task" +import { resolveSourceInput } from "../utils/resolve-source-input" +import { GatheredOptions } from "../utils/types" +import { schematicOptionPrompts } from "./prompts" export function createD2CCommand( ctx: CommandContext, @@ -234,22 +237,7 @@ export function createD2CCommandHandler( const skipInstall = !!cliOptions["skip-install"] const skipConfig = !!cliOptions["skip-config"] - let gatheredOptions: { - epccClientId?: string - epccClientSecret?: string - location?: string | null - name?: string - directory?: string - epccEndpointUrl?: string - plpType?: "Algolia" | "Simple" | "Klevu" - algoliaApplicationId?: string - algoliaAdminApiKey?: string - klevuApiKey?: string - klevuSearchURL?: string - paymentGatewayType?: PaymentTypeOptions["paymentGatewayType"] - epPaymentsStripeAccountId?: string - epPaymentsStripePublishableKey?: string - } = { + let gatheredOptions: GatheredOptions = { location, } @@ -558,6 +546,13 @@ export function createD2CCommandHandler( task: createAlgoliaTask({ unsubscribe }) as any, }, ]) + } else if (gatheredOptions.plpType === "Klevu") { + d2cSetupTasks.add([ + { + title: "Klevu configuration", + task: createKlevuTask({ unsubscribe }) as any, + }, + ]) } if (gatheredOptions.paymentGatewayType === "Manual") { @@ -590,16 +585,6 @@ export function createD2CCommandHandler( } } - const options: AlgoliaIntegrationSetup | undefined = - gatheredOptions.plpType === "Algolia" - ? ({ - appId: gatheredOptions.algoliaApplicationId, - adminApiKey: gatheredOptions.algoliaAdminApiKey, - host: new URL(resolveHostFromRegion(confData.data.region)).host, - accessToken: confData.data.token, - } as AlgoliaIntegrationSetup) - : undefined - if (skipConfig) { renderWarning({ body: "You skipped configuration", @@ -618,7 +603,7 @@ export function createD2CCommandHandler( workspaceRoot: updatedCtx.workspaceRoot, accountId: gatheredOptions.epPaymentsStripeAccountId, publishableKey: gatheredOptions.epPaymentsStripePublishableKey, - sourceInput: options, + sourceInput: resolveSourceInput(gatheredOptions, confData.data), config: confData.data, requester: ctx.requester, skipGit, @@ -712,184 +697,6 @@ function processResultNotes(result: D2CSetupTaskContext): Note[] { return notes } -type PaymentTypeOptions = - | { - paymentGatewayType: "EP Payments" - epPaymentsStripeAccountId: string - epPaymentsStripePublishableKey: string - } - | { paymentGatewayType: "Manual" } - -type PlpTypeOptions = - | { - plpType: "Algolia" - algoliaApplicationId: string - algoliaAdminApiKey: string - algoliaSearchOnlyApiKey: string - } - | - { - plpType: "Klevu" - klevuApiKey: string - klevuSearchURL: string - } - | { plpType: "Simple" } - -async function schematicOptionPrompts(): Promise<{ - plp: PlpTypeOptions - paymentGateway: PaymentTypeOptions -}> { - const { plpType } = await inquirer.prompt([ - { - type: "list", - name: "plpType", - message: "What type of PLP do you want to create?", - choices: [ - { - name: "Simple", - value: "Simple", - }, - { - name: "Algolia", - value: "Algolia", - }, - { - name: "Klevu", - value: "Klevu", - }, - ], - }, - ]) - - let plp: PlpTypeOptions; - switch(plpType){ - case "Algolia": - plp = await algoliaSchematicPrompts() - break; - case "Klevu": - plp = await klevuSchematicPrompts(); - break; - case "Simple": - default: - plp = { plpType: "Simple" as const } - } - - // const plp = - // plpType === "Algolia" - // ? await algoliaSchematicPrompts() - // : { plpType: "Simple" as const } - - const { paymentGatewayType } = await inquirer.prompt([ - { - type: "list", - name: "paymentGatewayType", - message: "What type of payment gateway do you want to use?", - choices: [ - { - name: "Simple (quick start)", - value: "Manual", - }, - { - name: "EP Payments (powered by Stripe)", - value: "EP Payments", - }, - ], - }, - ]) - - const paymentGateway = - paymentGatewayType === "EP Payments" - ? await epPaymentsSchematicPrompts() - : { paymentGatewayType: "Manual" as const } - - return { - plp, - paymentGateway, - } -} - -async function epPaymentsSchematicPrompts(): Promise { - const { epPaymentsStripeAccountId } = await inquirer.prompt([ - { - type: "string", - name: "epPaymentsStripeAccountId", - message: "What is your Elastic Path Payments Account ID?", - }, - ]) - - const { epPaymentsStripePublishableKey } = await inquirer.prompt([ - { - type: "string", - name: "epPaymentsStripePublishableKey", - message: "What is your Elastic Path Payments Publishable Key?", - }, - ]) - - return { - paymentGatewayType: "EP Payments", - epPaymentsStripeAccountId, - epPaymentsStripePublishableKey, - } -} - -async function algoliaSchematicPrompts(): Promise { - const { algoliaApplicationId } = await inquirer.prompt([ - { - type: "string", - name: "algoliaApplicationId", - message: "What is your Algolia App ID?", - }, - ]) - - const { algoliaSearchOnlyApiKey } = await inquirer.prompt([ - { - type: "string", - name: "algoliaSearchOnlyApiKey", - message: "What is your Algolia Search Only API Key?", - }, - ]) - - const { algoliaAdminApiKey } = await inquirer.prompt([ - { - type: "password", - name: "algoliaAdminApiKey", - message: "What is your Algolia Admin API Key?", - mask: "*", - }, - ]) - - return { - plpType: "Algolia", - algoliaApplicationId, - algoliaAdminApiKey, - algoliaSearchOnlyApiKey, - } -} - -async function klevuSchematicPrompts(): Promise { - const { klevuApiKey } = await inquirer.prompt([ - { - type: "string", - name: "klevuApiKey", - message: "What is your Klevu API Key?", - }, - ]) - - const { klevuSearchURL } = await inquirer.prompt([ - { - type: "string", - name: "klevuSearchURL", - message: "What is your Klevu Search URL?", - }, - ]) - - return { - plpType: "Klevu", - klevuApiKey, - klevuSearchURL, - } -} - /** Parse the command line. */ const booleanArgs = [ "allow-private", diff --git a/packages/composable-cli/src/commands/generate/d2c/prompts.ts b/packages/composable-cli/src/commands/generate/d2c/prompts.ts new file mode 100644 index 00000000..564e4946 --- /dev/null +++ b/packages/composable-cli/src/commands/generate/d2c/prompts.ts @@ -0,0 +1,162 @@ +import * as inquirer from "inquirer" +import { PaymentTypeOptions, PlpTypeOptions } from "../utils/types" + +export async function klevuSchematicPrompts(): Promise { + const { klevuApiKey } = await inquirer.prompt([ + { + type: "string", + name: "klevuApiKey", + message: "What is your Klevu API Key?", + }, + ]) + + const { klevuSearchURL } = await inquirer.prompt([ + { + type: "string", + name: "klevuSearchURL", + message: "What is your Klevu Search URL?", + }, + ]) + + const { klevuRestAuthKey } = await inquirer.prompt([ + { + type: "password", + mask: "*", + name: "klevuRestAuthKey", + message: "What is your Klevu rest auth key?", + }, + ]) + + return { + plpType: "Klevu", + klevuApiKey, + klevuSearchURL, + klevuRestAuthKey, + } +} + +export async function schematicOptionPrompts(): Promise<{ + plp: PlpTypeOptions + paymentGateway: PaymentTypeOptions +}> { + const { plpType } = await inquirer.prompt([ + { + type: "list", + name: "plpType", + message: "What type of PLP do you want to create?", + choices: [ + { + name: "Simple", + value: "Simple", + }, + { + name: "Algolia", + value: "Algolia", + }, + { + name: "Klevu", + value: "Klevu", + }, + ], + }, + ]) + + let plp: PlpTypeOptions + switch (plpType) { + case "Algolia": + plp = await algoliaSchematicPrompts() + break + case "Klevu": + plp = await klevuSchematicPrompts() + break + case "Simple": + default: + plp = { plpType: "Simple" as const } + } + + const { paymentGatewayType } = await inquirer.prompt([ + { + type: "list", + name: "paymentGatewayType", + message: "What type of payment gateway do you want to use?", + choices: [ + { + name: "Simple (quick start)", + value: "Manual", + }, + { + name: "EP Payments (powered by Stripe)", + value: "EP Payments", + }, + ], + }, + ]) + + const paymentGateway = + paymentGatewayType === "EP Payments" + ? await epPaymentsSchematicPrompts() + : { paymentGatewayType: "Manual" as const } + + return { + plp, + paymentGateway, + } +} + +export async function epPaymentsSchematicPrompts(): Promise { + const { epPaymentsStripeAccountId } = await inquirer.prompt([ + { + type: "string", + name: "epPaymentsStripeAccountId", + message: "What is your Elastic Path Payments Account ID?", + }, + ]) + + const { epPaymentsStripePublishableKey } = await inquirer.prompt([ + { + type: "string", + name: "epPaymentsStripePublishableKey", + message: "What is your Elastic Path Payments Publishable Key?", + }, + ]) + + return { + paymentGatewayType: "EP Payments", + epPaymentsStripeAccountId, + epPaymentsStripePublishableKey, + } +} + +export async function algoliaSchematicPrompts(): Promise { + const { algoliaApplicationId } = await inquirer.prompt([ + { + type: "string", + name: "algoliaApplicationId", + message: "What is your Algolia App ID?", + }, + ]) + + const { algoliaSearchOnlyApiKey } = await inquirer.prompt([ + { + type: "string", + name: "algoliaSearchOnlyApiKey", + message: "What is your Algolia Search Only API Key?", + }, + ]) + + const { algoliaAdminApiKey } = await inquirer.prompt([ + { + type: "password", + name: "algoliaAdminApiKey", + message: "What is your Algolia Admin API Key?", + mask: "*", + }, + ]) + + return { + plpType: "Algolia", + algoliaApplicationId, + algoliaAdminApiKey, + algoliaSearchOnlyApiKey, + } +} diff --git a/packages/composable-cli/src/commands/generate/d2c/tasks/types.ts b/packages/composable-cli/src/commands/generate/d2c/tasks/types.ts index 6c5b878f..65a360f9 100644 --- a/packages/composable-cli/src/commands/generate/d2c/tasks/types.ts +++ b/packages/composable-cli/src/commands/generate/d2c/tasks/types.ts @@ -3,6 +3,7 @@ import { AlgoliaIntegrationSetup } from "../../../integration/algolia/utility/in import { UserStore } from "../../../../lib/stores/stores-schema" import { Region } from "../../../../lib/stores/region-schema" import fetch from "node-fetch" +import { KlevuIntegrationSetup } from "../../../integration/klevu/utility/integration-hub/setup-klevu-schema" export type D2CSetupTaskContext = { client: Moltin @@ -11,7 +12,7 @@ export type D2CSetupTaskContext = { epPaymentGatewaySetup?: boolean accountId?: string publishableKey?: string - sourceInput?: AlgoliaIntegrationSetup + sourceInput?: AlgoliaIntegrationSetup | KlevuIntegrationSetup config?: { activeStore: UserStore apiUrl: string diff --git a/packages/composable-cli/src/commands/generate/utils/resolve-source-input.ts b/packages/composable-cli/src/commands/generate/utils/resolve-source-input.ts new file mode 100644 index 00000000..8fe95144 --- /dev/null +++ b/packages/composable-cli/src/commands/generate/utils/resolve-source-input.ts @@ -0,0 +1,33 @@ +import { ConfStoreData } from "../../integration/algolia/algolia-integration-command" +import { AlgoliaIntegrationSetup } from "../../integration/algolia/utility/integration-hub/setup-algolia-schema" +import { KlevuIntegrationSetup } from "../../integration/klevu/utility/integration-hub/setup-klevu-schema" +import { resolveHostFromRegion } from "../../../util/resolve-region" +import { GatheredOptions } from "./types" + +export function resolveSourceInput( + gatheredOptions: GatheredOptions, + confData: ConfStoreData, +) { + let options: AlgoliaIntegrationSetup | KlevuIntegrationSetup | undefined + if (gatheredOptions.plpType === "Algolia") { + options = { + appId: gatheredOptions.algoliaApplicationId!, + adminApiKey: gatheredOptions.algoliaAdminApiKey!, + host: hostFromConfData(confData), + accessToken: confData.token, + } as AlgoliaIntegrationSetup + } else if (gatheredOptions.plpType === "Klevu") { + options = { + apiKey: gatheredOptions.klevuApiKey!, + searchUrl: gatheredOptions.klevuSearchURL!, + restAuthKey: gatheredOptions.klevuRestAuthKey!, + host: hostFromConfData(confData), + accessToken: confData.token, + } as KlevuIntegrationSetup + } + return options +} + +function hostFromConfData(confData: ConfStoreData) { + return new URL(resolveHostFromRegion(confData.region)).host +} diff --git a/packages/composable-cli/src/commands/generate/utils/types.ts b/packages/composable-cli/src/commands/generate/utils/types.ts new file mode 100644 index 00000000..28a83d70 --- /dev/null +++ b/packages/composable-cli/src/commands/generate/utils/types.ts @@ -0,0 +1,40 @@ +export type GatheredOptions = { + epccClientId?: string + epccClientSecret?: string + location?: string | null + name?: string + directory?: string + epccEndpointUrl?: string + plpType?: "Algolia" | "Simple" | "Klevu" + algoliaApplicationId?: string + algoliaAdminApiKey?: string + klevuApiKey?: string + klevuSearchURL?: string + klevuRestAuthKey?: string + paymentGatewayType?: PaymentTypeOptions["paymentGatewayType"] + epPaymentsStripeAccountId?: string + epPaymentsStripePublishableKey?: string +} + +export type PaymentTypeOptions = + | { + paymentGatewayType: "EP Payments" + epPaymentsStripeAccountId: string + epPaymentsStripePublishableKey: string + } + | { paymentGatewayType: "Manual" } + +export type PlpTypeOptions = + | { + plpType: "Algolia" + algoliaApplicationId: string + algoliaAdminApiKey: string + algoliaSearchOnlyApiKey: string + } + | { + plpType: "Klevu" + klevuApiKey: string + klevuSearchURL: string + klevuRestAuthKey: string + } + | { plpType: "Simple" } diff --git a/packages/composable-cli/src/commands/integration/algolia/algolia-integration-command.tsx b/packages/composable-cli/src/commands/integration/algolia/algolia-integration-command.tsx index cfd99bbe..43c2c571 100644 --- a/packages/composable-cli/src/commands/integration/algolia/algolia-integration-command.tsx +++ b/packages/composable-cli/src/commands/integration/algolia/algolia-integration-command.tsx @@ -163,14 +163,16 @@ export function createAlgoliaIntegrationCommandHandler( } } +export type ConfStoreData = { + activeStore: UserStore + apiUrl: string + token: string + region: Region +} + export async function resolveConfStoreData( store: Conf, -): Promise< - Result< - { activeStore: UserStore; apiUrl: string; token: string; region: Region }, - AlgoliaIntegrationCommandError - > -> { +): Promise> { const activeStoreResult = await getStore(store) if (!activeStoreResult.success) { diff --git a/packages/composable-cli/src/commands/integration/klevu/tasks/setup-klevu-custom-api-entry-tasks.ts b/packages/composable-cli/src/commands/integration/klevu/tasks/setup-klevu-custom-api-entry-tasks.ts index 00162e5f..0354677b 100644 --- a/packages/composable-cli/src/commands/integration/klevu/tasks/setup-klevu-custom-api-entry-tasks.ts +++ b/packages/composable-cli/src/commands/integration/klevu/tasks/setup-klevu-custom-api-entry-tasks.ts @@ -63,7 +63,7 @@ export async function setupKlevuCustomApiEntryTasks( if (catalogs.length < 1) { throw new Error( - "The Algolia integration will only work correctly if you have a published catalog in your store. We were not able to find any catalogs in your store to publish. Please add a catalog and then rerun the `int algolia` command.\n\nLearn more about catalogs and publishing https://elasticpath.dev/docs/pxm/catalogs/catalogs", + "The Klevu integration will only work correctly if you have a published catalog in your store. We were not able to find any catalogs in your store to publish. Please add a catalog and then rerun the `int algolia` command.\n\nLearn more about catalogs and publishing https://elasticpath.dev/docs/pxm/catalogs/catalogs", ) }