From 23472c092e64673de6796529851e3b9a7a32695a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morel=20Se=CC=81bastien?= Date: Fri, 1 Aug 2025 13:27:34 +0200 Subject: [PATCH] feat(cli): add code to the feedback to improve ui --- components/cli/.gitignore | 1 + components/cli/CHANGELOG.md | 4 ++++ components/cli/package.json | 2 +- components/cli/src/command/serve.ts | 5 ++++ .../src/domain/contracts/feedback-piper.ts | 5 ++-- .../cli/src/domain/contracts/message-codes.ts | 23 +++++++++++++++++++ .../src/domain/contracts/tenant-enroller.ts | 4 ++-- .../src/domain/core/create-feedback-piper.ts | 6 +++-- .../src/domain/core/create-tenant-enroller.ts | 21 +++++++++-------- .../domain/use-cases/create-clean-tenant.ts | 9 ++++---- .../enroll-tenant-with-boilerplate-package.ts | 8 +++---- 11 files changed, 63 insertions(+), 25 deletions(-) create mode 100644 components/cli/src/domain/contracts/message-codes.ts diff --git a/components/cli/.gitignore b/components/cli/.gitignore index c66a58a..74b22a7 100644 --- a/components/cli/.gitignore +++ b/components/cli/.gitignore @@ -1,2 +1,3 @@ node_modules/ crystallize +.idea/ \ No newline at end of file diff --git a/components/cli/CHANGELOG.md b/components/cli/CHANGELOG.md index 93cb182..73f0678 100644 --- a/components/cli/CHANGELOG.md +++ b/components/cli/CHANGELOG.md @@ -2,6 +2,10 @@ All notable changes to this project will be documented in this file. +## [5.7.6] + +- adds codes to messages that are streamed to FE while tenant is being updated with selected template + ## [5.7.5] - schema 4.0.0 diff --git a/components/cli/package.json b/components/cli/package.json index eb3734c..058055a 100644 --- a/components/cli/package.json +++ b/components/cli/package.json @@ -1,6 +1,6 @@ { "name": "@crystallize/cli", - "version": "5.7.5", + "version": "5.7.6", "description": "Crystallize CLI", "module": "src/index.ts", "repository": "https://github.com/CrystallizeAPI/crystallize-cli", diff --git a/components/cli/src/command/serve.ts b/components/cli/src/command/serve.ts index 88ae8a1..3adfe04 100644 --- a/components/cli/src/command/serve.ts +++ b/components/cli/src/command/serve.ts @@ -4,6 +4,7 @@ import { Command } from 'commander'; import type { Boilerplate } from '../domain/contracts/models/boilerplate'; import { boilerplates } from '../content/boilerplates'; import type { FeedbackMessage, FeedbackPiper } from '../domain/contracts/feedback-piper'; +import { MessageCode } from '../domain/contracts/message-codes'; import packageJson from '../../package.json'; import pc from 'picocolors'; @@ -91,6 +92,7 @@ export const createServeCommand = ({ logger, commandBus, feedbackPiper, crystall send({ level: 'info', message: `Enrolling tenant ${tenantIdentifier} with boilerplate ${boilerplate.name} started.`, + code: MessageCode.ENROLLMENT_STARTED, }); try { const intent = commandBus.createCommand('EnrollTenantWithBoilerplatePackage', { @@ -112,17 +114,20 @@ export const createServeCommand = ({ logger, commandBus, feedbackPiper, crystall send({ level: 'error', message: `Enrolling tenant ${tenantIdentifier} with boilerplate ${boilerplate.name} failed.`, + code: MessageCode.ENROLLMENT_FAILED, }); } send({ level: 'info', message: `Enrolling tenant ${tenantIdentifier} with boilerplate ${boilerplate.name} done!`, + code: MessageCode.ENROLLMENT_COMPLETED, }); } catch (err) { send({ level: 'error', message: `${(err as Error).message}`, + code: MessageCode.ENROLLMENT_ERROR, }); } finally { clearInterval(pingInterval); diff --git a/components/cli/src/domain/contracts/feedback-piper.ts b/components/cli/src/domain/contracts/feedback-piper.ts index 0ea8026..d5b945e 100644 --- a/components/cli/src/domain/contracts/feedback-piper.ts +++ b/components/cli/src/domain/contracts/feedback-piper.ts @@ -2,12 +2,13 @@ type FeedbackLevel = 'info' | 'error'; export type FeedbackMessage = { level: FeedbackLevel; message: string; + code: number; }; export type FeedbackListener = (feedback: FeedbackMessage) => void; export type FeedbackPiper = { subscribe: (listener: FeedbackListener) => () => void; unsubscribe: (listener: FeedbackListener) => void; clear: () => void; - info: (message: string) => void; - error: (message: string) => void; + info: (message: string, code: number) => void; + error: (message: string, code: number) => void; }; diff --git a/components/cli/src/domain/contracts/message-codes.ts b/components/cli/src/domain/contracts/message-codes.ts new file mode 100644 index 0000000..29967a9 --- /dev/null +++ b/components/cli/src/domain/contracts/message-codes.ts @@ -0,0 +1,23 @@ +export const MessageCode = { + ENROLLMENT_STARTED: 1000, + ENROLLMENT_FAILED: 1001, + ENROLLMENT_COMPLETED: 1002, + ENROLLMENT_ERROR: 1003, + + TENANT_CREATED: 1100, + SHAPE_CLEANED: 1101, + + MASS_OPERATION_CREATED: 1200, + MASS_OPERATION_COMPLETED: 1201, + MASS_OPERATION_FAILED: 1202, + + DISCOVERY_API_START: 1300, + DISCOVERY_API_IGNITED: 1301, + + ASSET_UPLOAD_STARTED: 1400, + ASSET_UPLOAD_COMPLETED: 1401, + ASSET_UPLOAD_FAILED: 1402, + + MUTATIONS_EXECUTED: 1500, + MUTATIONS_FAILED: 1501, +} as const; diff --git a/components/cli/src/domain/contracts/tenant-enroller.ts b/components/cli/src/domain/contracts/tenant-enroller.ts index 6e4acb9..dd2d1a8 100644 --- a/components/cli/src/domain/contracts/tenant-enroller.ts +++ b/components/cli/src/domain/contracts/tenant-enroller.ts @@ -3,8 +3,8 @@ import type { PimCredentials } from './models/credentials'; import type { Tenant } from './models/tenant'; type Deps = { - addTraceLog: (log: string) => void; - addTraceError: (log: string) => void; + addTraceLog: (log: string, code: number) => void; + addTraceError: (log: string, code: number) => void; }; type Args = { diff --git a/components/cli/src/domain/core/create-feedback-piper.ts b/components/cli/src/domain/core/create-feedback-piper.ts index 9b1cad5..52cb909 100644 --- a/components/cli/src/domain/core/create-feedback-piper.ts +++ b/components/cli/src/domain/core/create-feedback-piper.ts @@ -23,16 +23,18 @@ export const createFeedbackPiper = (): FeedbackPiper => { clear: (): void => { listeners.clear(); }, - info: (message: string): void => { + info: (message: string, code: number): void => { dispatch({ level: 'info', message, + code, }); }, - error: (message: string): void => { + error: (message: string, code: number): void => { dispatch({ level: 'error', message, + code, }); }, }; diff --git a/components/cli/src/domain/core/create-tenant-enroller.ts b/components/cli/src/domain/core/create-tenant-enroller.ts index 09c5a52..1810846 100644 --- a/components/cli/src/domain/core/create-tenant-enroller.ts +++ b/components/cli/src/domain/core/create-tenant-enroller.ts @@ -13,6 +13,7 @@ import type { } from '../use-cases/download-boilerplate-archive'; import type { TenantEnrollerBuilder } from '../contracts/tenant-enroller'; import type { Boilerplate } from '../contracts/models/boilerplate'; +import { MessageCode } from '../contracts/message-codes'; type Deps = { credentialsRetriever: CredentialRetriever; @@ -70,7 +71,7 @@ export const createTenantEnrollerBuilder = ({ }, } as Envelope); logger.debug('Mass operation task created', startedTask); - addTraceLog(`Mass operation task created: ${startedTask?.id}`); + addTraceLog(`Mass operation task created: ${startedTask?.id}`, MessageCode.MASS_OPERATION_CREATED); await sleep(10); // we have an easy 10 sec sleep here to let the task start while (startedTask?.status !== 'complete') { const get = await cClient.nextPimApi(getMassOperationBulkTask, { id: startedTask?.id }); @@ -81,10 +82,10 @@ export const createTenantEnrollerBuilder = ({ await sleep(3); // then we check every 3 seconds } } catch (e) { - addTraceError(`Failed to run mass operation.`); + addTraceError(`Failed to run mass operation.`, MessageCode.MASS_OPERATION_FAILED); logger.error('Failed to run mass operation', e); } - addTraceLog(`Mass operation completed.`); + addTraceLog(`Mass operation completed.`, MessageCode.MASS_OPERATION_COMPLETED); }; const uploadAssets = async () => { @@ -95,7 +96,7 @@ export const createTenantEnrollerBuilder = ({ } try { - addTraceLog(`Uploading ${images.length} images.`); + addTraceLog(`Uploading ${images.length} images.`, MessageCode.ASSET_UPLOAD_STARTED); const imagResults = await uploadImages({ message: { paths: images, @@ -105,9 +106,9 @@ export const createTenantEnrollerBuilder = ({ } as Envelope); imageMapping = imagResults.keys; - addTraceLog(`${Object.keys(imageMapping).length} images Uploaded.`); + addTraceLog(`${Object.keys(imageMapping).length} images Uploaded.`, MessageCode.ASSET_UPLOAD_COMPLETED); } catch (e) { - addTraceError(`Failed to upload images..`); + addTraceError(`Failed to upload images..`, MessageCode.ASSET_UPLOAD_FAILED); logger.error('Failed to upload images'); } return imageMapping; @@ -126,14 +127,14 @@ export const createTenantEnrollerBuilder = ({ }, } as unknown as Envelope); } catch (e) { - addTraceError(`Failed to run extra mutations.`); + addTraceError(`Failed to run extra mutations.`, MessageCode.MUTATIONS_FAILED); logger.error('Failed to run extra mutations', e); } - addTraceLog(`Extra Mutations executed.`); + addTraceLog(`Extra Mutations executed.`, MessageCode.MUTATIONS_EXECUTED); }; const ignite = async () => { - addTraceLog(`Starting the index for Discovery API.`); + addTraceLog(`Starting the index for Discovery API.`, MessageCode.DISCOVERY_API_START); await cClient.nextPimApi(`mutation { igniteTenant }`); // check the 404 @@ -147,7 +148,7 @@ export const createTenantEnrollerBuilder = ({ discoApiPingResponseCode = discoApiPingResponse.status; sleep(5); // then every 5 seconds } while (discoApiPingResponseCode === 404); - addTraceLog(`Tenant ignited in Discovery API.`); + addTraceLog(`Tenant ignited in Discovery API.`, MessageCode.DISCOVERY_API_IGNITED); }; return { diff --git a/components/cli/src/domain/use-cases/create-clean-tenant.ts b/components/cli/src/domain/use-cases/create-clean-tenant.ts index 2cb8d6b..10bb0b3 100644 --- a/components/cli/src/domain/use-cases/create-clean-tenant.ts +++ b/components/cli/src/domain/use-cases/create-clean-tenant.ts @@ -7,6 +7,7 @@ import type { FlySystem } from '../contracts/fly-system'; import type { Logger } from '../contracts/logger'; import type { InstallBoilerplateStore } from '../../ui/journeys/install-boilerplate/create-store'; import type { TenantEnrollerBuilder } from '../contracts/tenant-enroller'; +import { MessageCode } from '../contracts/message-codes'; type Deps = { createCrystallizeClient: AsyncCreateClient; @@ -37,8 +38,8 @@ const handler = async ( identifier: string; }> => { const { storage, atoms } = installBoilerplateCommandStore; - const addTraceLog = (log: string) => storage.set(atoms.addTraceLogAtom, log); - const addTraceError = (log: string) => storage.set(atoms.addTraceErrorAtom, log); + const addTraceLog = (log: string, _: number) => storage.set(atoms.addTraceLogAtom, log); + const addTraceError = (log: string, _: number) => storage.set(atoms.addTraceErrorAtom, log); const { tenant, credentials } = envelope.message; const finalCredentials = credentials || (await credentialsRetriever.getCredentials()); @@ -72,7 +73,7 @@ const handler = async ( }, ); const { id, identifier } = createResult.tenant.create; - addTraceLog(`Tenant created with id: ${id}.`); + addTraceLog(`Tenant created with id: ${id}.`, MessageCode.TENANT_CREATED); const shapeIdentifiers = ['default-product', 'default-folder', 'default-document']; const mutation = { shape: shapeIdentifiers.reduce((memo: Record, shapeIdentifier: string) => { @@ -91,7 +92,7 @@ const handler = async ( }; const query = jsonToGraphQLQuery({ mutation }); await client.pimApi(query); - addTraceLog(`Shape cleaned.`); + addTraceLog(`Shape cleaned.`, MessageCode.SHAPE_CLEANED); // if we have a folder, we check that folder for .crystallize folder and convention const { folder } = envelope.message; diff --git a/components/cli/src/domain/use-cases/enroll-tenant-with-boilerplate-package.ts b/components/cli/src/domain/use-cases/enroll-tenant-with-boilerplate-package.ts index 4c1f5b9..21ed78e 100644 --- a/components/cli/src/domain/use-cases/enroll-tenant-with-boilerplate-package.ts +++ b/components/cli/src/domain/use-cases/enroll-tenant-with-boilerplate-package.ts @@ -41,13 +41,13 @@ const handler = async (envelope: Envelope, deps: Deps) => { folder, }, { - addTraceLog: (log: string) => { + addTraceLog: (log: string, code: number) => { logger.info(log); - feedbackPiper.info(log); + feedbackPiper.info(log, code); }, - addTraceError: (log: string) => { + addTraceError: (log: string, code: number) => { logger.error(log); - feedbackPiper.error(log); + feedbackPiper.error(log, code); }, }, );