Skip to content

Commit

Permalink
feat: add status option flag
Browse files Browse the repository at this point in the history
  • Loading branch information
pviti committed Dec 13, 2024
1 parent 5fa7463 commit 7ca1d4e
Show file tree
Hide file tree
Showing 7 changed files with 1,089 additions and 856 deletions.
4 changes: 3 additions & 1 deletion gen/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ const SPECS_DIR = 'test/commands/orders'

const clean = () => {

const staticFiles = ['index.ts', 'noc.ts', 'history.ts']

// Clean commands dir
const files = fs.readdirSync(COMMANDS_DIR)
files.forEach(f => {
if (!['index.ts', 'noc.ts'].includes(f)) fs.unlinkSync(`${COMMANDS_DIR}/${f}`)
if (!staticFiles.includes(f)) fs.unlinkSync(`${COMMANDS_DIR}/${f}`)
})
console.log('Deleted command files')

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,22 +64,22 @@
"@types/inquirer": "^8.2.10",
"@types/lodash.snakecase": "^4.1.9",
"@types/mocha": "^10.0.10",
"@types/node": "^20.17.9",
"@types/node": "^20.17.10",
"chai": "^4.5.0",
"eslint": "^8.57.1",
"inflector-js": "^1.0.1",
"lodash.snakecase": "^4.1.1",
"mocha": "^10.8.2",
"nyc": "^15.1.0",
"oclif": "^4.16.0",
"oclif": "^4.16.2",
"semantic-release": "^23.1.1",
"tsx": "^4.19.2",
"typescript": "5.3.3"
},
"dependencies": {
"@commercelayer/cli-core": "^5.4.3",
"@commercelayer/cli-ux": "1.0.6",
"@commercelayer/sdk": "^6.25.2",
"@commercelayer/sdk": "^6.26.0",
"@oclif/core": "^3.27.0",
"inquirer": "^8.2.6",
"tslib": "^2.8.1"
Expand Down
1,705 changes: 882 additions & 823 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

21 changes: 11 additions & 10 deletions src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,39 @@ export default abstract class extends Command {
description: 'the slug of your organization',
required: true,
env: 'CL_CLI_ORGANIZATION',
hidden: true,
hidden: true
}),
domain: Flags.string({
char: 'd',
required: false,
hidden: true,
dependsOn: ['organization'],
env: 'CL_CLI_DOMAIN',
env: 'CL_CLI_DOMAIN'
}),
accessToken: Flags.string({
hidden: true,
required: true,
env: 'CL_CLI_ACCESS_TOKEN',
env: 'CL_CLI_ACCESS_TOKEN'
}),
print: Flags.boolean({
char: 'p',
description: 'print out the modified order',
description: 'print out the modified order'
}),
json: Flags.boolean({
char: 'j',
description: 'print result in JSON format',
dependsOn: ['print'],
dependsOn: ['print']
}),
unformatted: Flags.boolean({
char: 'u',
description: 'print JSON output without indentation',
dependsOn: ['json'],
}),
dependsOn: ['json']
})
}


static args = {
id: Args.string({ name: 'id', description: 'the unique id of the order', required: true }),
id: Args.string({ name: 'id', description: 'the unique id of the order', required: true })
}


Expand All @@ -60,8 +60,9 @@ export default abstract class extends Command {
}


async catch(error: any): Promise<any> {
this.handleError(error as Error)
async catch(error: CommandError): Promise<any> {
if (error.message?.includes('quit')) this.exit()
else this.handleError(error as Error)
}


Expand Down
159 changes: 159 additions & 0 deletions src/commands/orders/history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import { clColor, clConfig, clOutput } from '@commercelayer/cli-core'
import Command, { Flags } from '../../base'
import { commercelayerInit } from '../../init'
import type { QueryPageSize, QuerySort, Version } from '@commercelayer/sdk'
import inquirer from 'inquirer'
import * as cliux from '@commercelayer/cli-ux'
import { checkOrder } from '../../exec'


const VERSIONS_TO_SHOW = clConfig.api.page_max_size as QueryPageSize


type VersionChoice = {
value: string,
name: string,
short?: string
}



export default class OrdersIndex extends Command {

static description = 'show history of specific order'

static flags = {
status: Flags.boolean({
char: 'S',
description: 'show only status changes'
})
}

static args = {
...Command.args
}



async run(): Promise<any> {

const { args, flags } = await this.parse(OrdersIndex)

const id = args.id

const cl = commercelayerInit(flags, this.config)

console.log()
cliux.action.start(`Fetching latest ${VERSIONS_TO_SHOW} versions of order ${clColor.yellowBright(id)}`)

await checkOrder(cl, id)

const filters = { resource_type_eq: 'orders', resource_id_eq: id }
const pageSize = VERSIONS_TO_SHOW
const sort: QuerySort<Version> = ['-updated_at']
const versions = await cl.versions.list({ filters, pageSize, sort })
// If the versions page is full and the user wants to show only status changes, retrieve page 2 too
if (flags.status && (versions.length === VERSIONS_TO_SHOW)) {
const page2 = await cl.versions.list({ filters, pageSize, sort, pageNumber: 2 })
versions.push(...page2)
}
cliux.action.stop()

if (versions.length === 0) {
this.log(clColor.dim.italic('\nNo versions found\n'))
this.exit()
}

do {

console.log()
const versionId = await this.showHistory(id, versions, flags.status)

const version = versions.find(v => v.id === versionId)

console.clear()
console.log()
console.log(clOutput.printObject(version))

console.log()
const k = await cliux.anykey(`Press any key to return to versions history or ${clColor.yellowBright('q')} to exit`)
if (k !== 'q') console.clear()

} while (true)

}


private timestamp(version: Version): string {
return version.updated_at.substring(0, 19).replace('T', ' ')
}


private author(version: Version): string {
let author: string = ''
const who = version.who
if (who && (Object.keys(who).length > 0)) {
if (who.worker) author = `Worker: ${who.worker.type}`
else
if (who.owner) author = `User: ${who.owner.email}`
else
if (who.application) author = `Application: ${who.application.kind}`
}
return author
}


private fields(version: Version): string[] {
return version.changes ? Object.keys(version.changes) : []
}


private changeChoice(version: Version): VersionChoice {
const timestamp = this.timestamp(version)
const fields = this.fields(version)
const author = this.author(version)
return {
value: version.id,
name: `${timestamp} ${fields.join(', ')}${author? ` ${clColor.dim(`[${author}]`)}` : ''}`,
short: timestamp
}
}


private changeChoiceStatus(version: Version): VersionChoice {
const timestamp = this.timestamp(version)
const statusFields = this.fields(version).filter(k => k.endsWith('status'))
const status = []
if (statusFields.length > 0) {
for (const sf of statusFields) {
const change = version.changes? version.changes[sf] : []
if (change.length === 2) status.push(`${sf}: ${clColor.italic(change[0])} \u2500\u2500\u25b6 ${clColor.italic(change[1])}`)
}
}
const author = this.author(version)
return {
value: version.id,
name: `${timestamp} ${status.join(', ')}${author? ` ${clColor.dim(`[${author}]`)}` : ''}`,
short: timestamp
}
}


private async showHistory(orderId: string, versions: Version[], status?: boolean): Promise<string> {
let filteredVersions = versions.filter(v => (v.changes && (Object.keys(v.changes).length > 0)))
if (status) {
filteredVersions = filteredVersions.filter(v => Object.keys(v.changes || {}).some(k => k.endsWith('status')))
filteredVersions.splice(VERSIONS_TO_SHOW)
}
const answers = await inquirer.prompt([{
type: 'list',
name: 'version',
message: `Versions history for order ${clColor.yellowBright(orderId)}${status? ` (${clColor.cyanBright('status only')})` : ''}:`,
choices: filteredVersions.map(v => status? this.changeChoiceStatus(v) : this.changeChoice(v)),
loop: false,
pageSize: VERSIONS_TO_SHOW
}])
return answers.version
}

}
29 changes: 10 additions & 19 deletions src/exec.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,28 @@
import commercelayer from '@commercelayer/sdk'
import type { CommerceLayerClient, Order, OrderUpdate, QueryParamsRetrieve } from '@commercelayer/sdk'
import type { ActionType } from './triggers'
import type { Config } from '@oclif/core/lib/interfaces'
import { clColor, clUtil } from '@commercelayer/cli-core'
import { clColor } from '@commercelayer/cli-core'
import { CLIError } from '@oclif/core/lib/errors'
import { commercelayerInit } from './init'



const commercelayerInit = (flags: any, config?: Config): CommerceLayerClient => {

const organization = flags.organization
const domain = flags.domain
const accessToken = flags.accessToken

const userAgent = config? clUtil.userAgent(config) : undefined

return commercelayer({
organization,
domain,
accessToken,
userAgent
export const checkOrder = async (cl: CommerceLayerClient, id: string): Promise<Order> => {
const order = await cl.orders.retrieve(id).catch((err: Error) => {
if (cl.isApiError(err) && (err.status === 404)) throw new CLIError(`Invalid order or order not found: ${clColor.msg.error(id)}`)
else throw err
})

return order
}




const exec = async (id: string, action: ActionType, flags: any, fields?: string[], config?: Config): Promise<Order> => {

const cl = commercelayerInit(flags, config)

await cl.orders.retrieve(id).catch(err => {
if (cl.isApiError(err) && (err.status === 404)) throw new CLIError(`Invalid order or order not found: ${clColor.msg.error(id)}`)
})
await checkOrder(cl, id)

const res: OrderUpdate = { id, [`_${action}`]: flags.value || true }
const params: QueryParamsRetrieve<Order> = {}
Expand Down
21 changes: 21 additions & 0 deletions src/init.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { clUtil } from '@commercelayer/cli-core'
import commercelayer, { type CommerceLayerClient } from '@commercelayer/sdk'
import type { Config } from '@oclif/core/lib/interfaces'


export const commercelayerInit = (flags: any, config?: Config): CommerceLayerClient => {

const organization = flags.organization
const domain = flags.domain
const accessToken = flags.accessToken

const userAgent = config? clUtil.userAgent(config) : undefined

return commercelayer({
organization,
domain,
accessToken,
userAgent
})

}

0 comments on commit 7ca1d4e

Please sign in to comment.