Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add workflow for discount function settings #5096

Draft
wants to merge 3 commits into
base: nw-hackdays37-extension-workflow-registry
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions packages/app/src/cli/prompts/generate/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
return templateSpecChoices.sort(compareChoices)
}

const generateExtensionPrompts = async (
export const generateExtensionPrompts = async (

Check failure on line 76 in packages/app/src/cli/prompts/generate/extension.ts

View workflow job for this annotation

GitHub Actions / knip-reporter-annotations-check

packages/app/src/cli/prompts/generate/extension.ts#L76

'generateExtensionPrompts' is a duplicate of 'default'
options: GenerateExtensionPromptOptions,
): Promise<GenerateExtensionPromptOutput> => {
let extensionTemplates = options.extensionTemplates
Expand All @@ -90,25 +90,26 @@
throw new AbortError('You have reached the limit for the number of extensions you can create.')
}

// eslint-disable-next-line require-atomic-updates
templateType = await renderAutocompletePrompt({
message: 'Type of extension?',
choices: buildChoices(extensionTemplates, options.unavailableExtensions),
})
if (extensionTemplates.length === 1) {
templateType = extensionTemplates[0]?.identifier
} else {
// eslint-disable-next-line require-atomic-updates
templateType = await renderAutocompletePrompt({
message: 'Type of extension?',
choices: buildChoices(extensionTemplates, options.unavailableExtensions),
})
}
}

// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const extensionTemplate = extensionTemplates.find((template) => template.identifier === templateType)!

const name = options.name || (await promptName(options.directory, extensionTemplate.defaultName))

Check warning on line 107 in packages/app/src/cli/prompts/generate/extension.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/prompts/generate/extension.ts#L107

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
const flavor = options.extensionFlavor ?? (await promptFlavor(extensionTemplate))
const extensionContent = {
name,
flavor,
// extensionChildren [identifiers]
extensionChildren: extensionTemplate.relatedExtensions?.map((elem) => elem.name) ?? [],
}
// TODO: here perhaps return a flag, that lets us know that there are possible next steps

return {extensionTemplate, extensionContent}
}
Expand Down Expand Up @@ -155,5 +156,5 @@
})
}

export default generateExtensionPrompts

Check failure on line 159 in packages/app/src/cli/prompts/generate/extension.ts

View workflow job for this annotation

GitHub Actions / knip-reporter-annotations-check

packages/app/src/cli/prompts/generate/extension.ts#L159

'default' is a duplicate of 'generateExtensionPrompts'
export {promptAddExtensionConfirmation}

Check failure on line 160 in packages/app/src/cli/prompts/generate/extension.ts

View workflow job for this annotation

GitHub Actions / knip-reporter-annotations-check

packages/app/src/cli/prompts/generate/extension.ts#L160

'promptAddExtensionConfirmation' is an unused export
21 changes: 14 additions & 7 deletions packages/app/src/cli/services/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,8 @@
const promptOptions = await buildPromptOptions(extensionTemplates, specifications, app, options)
const promptAnswers = await generateExtensionPrompts(promptOptions)

// Call module related to that child extension
await saveAnalyticsMetadata(promptAnswers, template)

// We can add an extra generated extension here.
const generateExtensionOptions = buildGenerateOptions(promptAnswers, app, options, developerPlatformClient)
const generatedExtension = await generateExtensionTemplate(generateExtensionOptions)

Expand All @@ -60,18 +58,19 @@

const workflowResult = await workflow?.afterGenerate({
generateOptions: options,
extensionTemplateOptions: generateExtensionOptions,
generatedExtension,
extensionTemplateOptions: generateExtensionOptions,
extensionTemplates,
})

if (!workflowResult?.success) {
//TODO: Cleanup extension?

Check failure on line 67 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L67

[no-warning-comments] Unexpected 'todo' comment: 'TODO: Cleanup extension?'.

Check failure on line 67 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L67

[spaced-comment] Expected space or tab after '//' in comment.
}

renderSuccessMessage(generatedExtension, app.packageManager, workflowResult)
}

async function buildPromptOptions(
export async function buildPromptOptions(
extensionTemplates: ExtensionTemplate[],
specifications: ExtensionSpecification[],
app: AppInterface,
Expand Down Expand Up @@ -111,7 +110,7 @@
const type = template.type
const specification = specifications.find((spec) => spec.identifier === type || spec.externalIdentifier === type)
const existingExtensions = app.extensionsForType({identifier: type, externalIdentifier: type})
return existingExtensions.length >= (specification?.registrationLimit || 1)

Check warning on line 113 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L113

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
}

async function saveAnalyticsMetadata(promptAnswers: GenerateExtensionPromptOutput, typeFlag: string | undefined) {
Expand All @@ -123,7 +122,7 @@
}))
}

function buildGenerateOptions(
export function buildGenerateOptions(
promptAnswers: GenerateExtensionPromptOutput,
app: AppInterface,
options: GenerateOptions,
Expand All @@ -138,7 +137,11 @@
}
}

function renderSuccessMessage(extension: GeneratedExtension, packageManager: AppInterface['packageManager'], workflowResult?: WorkflowResult) {
function renderSuccessMessage(
extension: GeneratedExtension,
packageManager: AppInterface['packageManager'],
workflowResult?: WorkflowResult,
) {
const formattedSuccessfulMessage = formatSuccessfulRunMessage(
extension.extensionTemplate,
extension.directory,
Expand Down Expand Up @@ -169,9 +172,13 @@
): RenderAlertOptions {
const workflowMessage = workflowResult?.message
const options: RenderAlertOptions = {
headline: workflowMessage?.headline || ['Your extension was created in', {filePath: extensionDirectory}, {char: '.'}],
headline: workflowMessage?.headline || [

Check warning on line 175 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L175

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
'Your extension was created in',
{filePath: extensionDirectory},
{char: '.'},
],
nextSteps: workflowMessage?.nextSteps || [],

Check warning on line 180 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L180

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
reference: workflowMessage?.reference || [],

Check warning on line 181 in packages/app/src/cli/services/generate.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate.ts#L181

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
}

if (extensionTemplate.type !== 'function') {
Expand Down
9 changes: 6 additions & 3 deletions packages/app/src/cli/services/generate/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
export interface GeneratedExtension {
directory: string
extensionTemplate: ExtensionTemplate
handle: string
}

interface ExtensionInitOptions {
Expand All @@ -81,9 +82,8 @@
const extensionFlavor = options.extensionTemplate.supportedFlavors.find(
(flavor) => flavor.value === extensionFlavorValue,
)
// TODO For grouping we might want to setup directories/groups for extensions
const directory = await ensureExtensionDirectoryExists({app: options.app, name: extensionName})
const url = options.cloneUrl || options.extensionTemplate.url

Check warning on line 86 in packages/app/src/cli/services/generate/extension.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/extension.ts#L86

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
const uid = options.developerPlatformClient.supportsAtomicDeployments ? randomUUID() : undefined
const initOptions: ExtensionInitOptions = {
directory,
Expand All @@ -100,7 +100,11 @@
}),
}
await extensionInit(initOptions)
return {directory: relativizePath(directory), extensionTemplate: options.extensionTemplate}
return {
directory: relativizePath(directory),
extensionTemplate: options.extensionTemplate,
handle: slugify(extensionName),
}
}

async function extensionInit(options: ExtensionInitOptions) {
Expand Down Expand Up @@ -170,7 +174,7 @@
await recursiveLiquidTemplateCopy(templateDirectory, directory, {
name,
handle: slugify(name),
// TODO: This is where we'd want to write the ui extension handle in the function toml

Check failure on line 177 in packages/app/src/cli/services/generate/extension.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/extension.ts#L177

[no-warning-comments] Unexpected 'todo' comment: 'TODO: This is where we'd want to write...'.
uiExtensionHandle: slugify(name),
flavor: extensionFlavor?.value,
uid,
Expand All @@ -178,7 +182,7 @@
})

if (templateLanguage === 'javascript') {
const srcFileExtension = getSrcFileExtension(extensionFlavor?.value || 'rust')

Check warning on line 185 in packages/app/src/cli/services/generate/extension.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/extension.ts#L185

[@typescript-eslint/prefer-nullish-coalescing] Prefer using nullish coalescing operator (`??`) instead of a logical or (`||`), as it is a safer operator.
await changeIndexFileExtension(directory, srcFileExtension, '!(*.graphql)')
}
},
Expand Down Expand Up @@ -225,7 +229,6 @@
onGetTemplateRepository,
}: ExtensionInitOptions) {
const templateLanguage = getTemplateLanguage(extensionFlavor?.value)

const tasks = [
{
title: `Generating extension`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {renderConfirmationPrompt} from '@shopify/cli-kit/node/ui'

Check failure on line 1 in packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts#L1

[import/order] `@shopify/cli-kit/node/ui` import should occur after import of `../../generate.js`
import {Workflow} from './registry.js'
import {generateExtensionTemplate} from '../extension.js'
import {generateExtensionPrompts} from '../../../prompts/generate/extension.js'
import {buildGenerateOptions, buildPromptOptions} from '../../generate.js'

export const discountDetailsFunctionSettingsCollection: Workflow = {
afterGenerate: async (options) => {
const {app, developerPlatformClient, specifications} = options.generateOptions

const shouldCreateFunction = await renderConfirmationPrompt({
message: 'Would you like to create a function for this extension?',
defaultValue: true,
})

if (shouldCreateFunction) {
// create a function extension
const extensionTemplates = options.extensionTemplates.filter(
(template) =>
template.identifier === 'shipping_discounts' ||
template.identifier === 'product_discounts' ||
template.identifier === 'order_discounts' ||
template.identifier == 'discounts_allocator',

Check failure on line 23 in packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts#L23

[eqeqeq] Expected '===' and instead saw '=='.
)

const promptOptions = await buildPromptOptions(extensionTemplates, specifications, app, options.generateOptions)
const promptAnswers = await generateExtensionPrompts(promptOptions)

const generateExtensionOptions = buildGenerateOptions(
promptAnswers,
app,
options.generateOptions,
developerPlatformClient,
)
const generatedExtension = await generateExtensionTemplate(generateExtensionOptions)

Check failure on line 35 in packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/discount-details-function-settings-collection.ts#L35

[@typescript-eslint/no-unused-vars] 'generatedExtension' is assigned a value but never used. Allowed unused vars must match /^_/u.
}

return {
success: true,
}
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import {renderConfirmationPrompt} from '@shopify/cli-kit/node/ui'

Check failure on line 1 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L1

[import/order] `@shopify/cli-kit/node/ui` import should occur after import of `./patch-configuration-file.js`
import {Workflow} from './registry.js'
import {generateExtensionTemplate} from '../extension.js'

Check failure on line 3 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L3

[import/order] `../extension.js` import should occur after import of `./patch-configuration-file.js`
import {generateExtensionPrompts} from '../../../prompts/generate/extension.js'

Check failure on line 4 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L4

[import/order] `../../../prompts/generate/extension.js` import should occur after import of `./patch-configuration-file.js`

Check failure on line 4 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L4

[import/no-duplicates] '../../../prompts/generate/extension.js' imported multiple times.
import {buildGenerateOptions, buildPromptOptions} from '../../generate.js'

Check failure on line 5 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L5

[import/order] `../../generate.js` import should occur after import of `./patch-configuration-file.js`
import {GenerateExtensionPromptOutput} from '../../../prompts/generate/extension.js'

Check failure on line 6 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L6

[import/order] `../../../prompts/generate/extension.js` import should occur after import of `./patch-configuration-file.js`

Check failure on line 6 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L6

[unused-imports/no-unused-imports] 'GenerateExtensionPromptOutput' is defined but never used.

Check failure on line 6 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L6

[@typescript-eslint/no-unused-vars] 'GenerateExtensionPromptOutput' is defined but never used. Allowed unused vars must match /^_/u.

Check failure on line 6 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L6

[import/no-duplicates] '../../../prompts/generate/extension.js' imported multiple times.
import {patchConfigurationFile} from './patch-configuration-file.js'

export const productDiscountFunctionCollection: Workflow = {
afterGenerate: async (options) => {
const {app, developerPlatformClient, specifications} = options.generateOptions
const functionTomlFilePath = `${options.generatedExtension.directory}/shopify.extension.toml`

const shouldLinkExtension = await renderConfirmationPrompt({
message: 'Would you like to create an Admin UI for configuring your function?',
confirmationMessage: 'Yes (recommended)',
cancellationMessage: 'No',
defaultValue: true,
})

if (!shouldLinkExtension) {
return {
success: true,
}
}

// create a UI extension
const extensionTemplates = options.extensionTemplates.filter(
(template) => template.identifier === 'discount_details_function_settings',
)

const promptOptions = await buildPromptOptions(extensionTemplates, specifications, app, options.generateOptions)
// TODO: What if it's larger than the limit?

Check failure on line 33 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L33

[no-warning-comments] Unexpected 'todo' comment: 'TODO: What if it's larger than the...'.
promptOptions.name = `${options.generatedExtension.handle}-ui`
const promptAnswers = await generateExtensionPrompts(promptOptions)
const generateExtensionOptions = buildGenerateOptions(
promptAnswers,
app,
options.generateOptions,
developerPlatformClient,
)
const generatedExtension = await generateExtensionTemplate(generateExtensionOptions)

const patch = {
extensions: [
{
ui: {
handle: generatedExtension.handle,
},
},
],
}
await patchConfigurationFile({
path: functionTomlFilePath,
patch,
})

return {
success: true,
message: {
headline: [
'Your extensions were created in',
{filePath: options.generatedExtension.directory},
'and',
{filePath: generatedExtension.directory},
{char: '.'},
],
}

Check failure on line 68 in packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/product-discount-function-collection.ts#L68

[prettier/prettier] Insert `,`
}
},
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import {editorExtensionCollection} from './editor-extension-collection.js'
import {GenerateOptions} from '../../generate.js'
import {GeneratedExtension, GenerateExtensionTemplateOptions} from '../../generate/extension.js'
import { RenderAlertOptions } from '@shopify/cli-kit/node/ui'
import {RenderAlertOptions} from '@shopify/cli-kit/node/ui'
import {discountDetailsFunctionSettingsCollection} from './discount-details-function-settings-collection.js'

Check failure on line 5 in packages/app/src/cli/services/generate/workflows/registry.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/registry.ts#L5

[import/order] `./discount-details-function-settings-collection.js` import should occur before import of `../../generate.js`
import {productDiscountFunctionCollection} from './product-discount-function-collection.js'

Check failure on line 6 in packages/app/src/cli/services/generate/workflows/registry.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/registry.ts#L6

[import/order] `./product-discount-function-collection.js` import should occur before import of `../../generate.js`
import {ExtensionTemplate} from '../../../models/app/template.js'

Check failure on line 7 in packages/app/src/cli/services/generate/workflows/registry.ts

View workflow job for this annotation

GitHub Actions / ESLint Report Analysis

packages/app/src/cli/services/generate/workflows/registry.ts#L7

[import/order] `../../../models/app/template.js` import should occur before import of `@shopify/cli-kit/node/ui`

interface AfterGenerateOptions {
generateOptions: GenerateOptions
extensionTemplateOptions: GenerateExtensionTemplateOptions
extensionTemplates: ExtensionTemplate[]
generatedExtension: GeneratedExtension
}

Expand All @@ -24,4 +28,6 @@

export const workflowRegistry: WorkflowRegistry = {
editor_extension_collection: editorExtensionCollection,
discount_details_function_settings: discountDetailsFunctionSettingsCollection,
product_discounts: productDiscountFunctionCollection,
}
Loading