@wavyx/pdcli 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +36 -1
- package/README.md +60 -11
- package/oclif.manifest.json +7101 -354
- package/package.json +4 -1
- package/src/base-command.js +65 -7
- package/src/commands/activity/create.js +63 -0
- package/src/commands/activity/delete.js +39 -0
- package/src/commands/activity/get.js +2 -17
- package/src/commands/activity/update.js +89 -0
- package/src/commands/api.js +6 -2
- package/src/commands/auth/login.js +102 -7
- package/src/commands/auth/logout.js +2 -1
- package/src/commands/auth/status.js +61 -13
- package/src/commands/backup.js +53 -0
- package/src/commands/deal/create.js +65 -0
- package/src/commands/deal/delete.js +39 -0
- package/src/commands/deal/get.js +2 -19
- package/src/commands/deal/update.js +79 -0
- package/src/commands/file/download.js +35 -0
- package/src/commands/file/get.js +26 -0
- package/src/commands/file/list.js +40 -0
- package/src/commands/file/upload.js +42 -0
- package/src/commands/filter/get.js +26 -0
- package/src/commands/filter/list.js +43 -0
- package/src/commands/goal/list.js +37 -0
- package/src/commands/lead/create.js +58 -0
- package/src/commands/lead/delete.js +39 -0
- package/src/commands/lead/get.js +26 -0
- package/src/commands/lead/list.js +50 -0
- package/src/commands/lead/update.js +71 -0
- package/src/commands/note/create.js +42 -0
- package/src/commands/note/delete.js +39 -0
- package/src/commands/note/get.js +26 -0
- package/src/commands/note/list.js +49 -0
- package/src/commands/note/update.js +45 -0
- package/src/commands/org/create.js +42 -0
- package/src/commands/org/delete.js +39 -0
- package/src/commands/org/get.js +2 -17
- package/src/commands/org/update.js +57 -0
- package/src/commands/person/create.js +54 -0
- package/src/commands/person/delete.js +39 -0
- package/src/commands/person/get.js +2 -17
- package/src/commands/person/update.js +69 -0
- package/src/commands/pipeline/get.js +26 -0
- package/src/commands/pipeline/list.js +37 -0
- package/src/commands/product/create.js +62 -0
- package/src/commands/product/delete.js +39 -0
- package/src/commands/product/get.js +26 -0
- package/src/commands/product/list.js +45 -0
- package/src/commands/product/update.js +77 -0
- package/src/commands/project/create.js +48 -0
- package/src/commands/project/delete.js +39 -0
- package/src/commands/project/get.js +26 -0
- package/src/commands/project/list.js +39 -0
- package/src/commands/project/update.js +63 -0
- package/src/commands/stage/get.js +26 -0
- package/src/commands/stage/list.js +41 -0
- package/src/commands/webhook/create.js +75 -0
- package/src/commands/webhook/delete.js +39 -0
- package/src/commands/webhook/list.js +33 -0
- package/src/lib/auth.js +227 -3
- package/src/lib/backup.js +122 -0
- package/src/lib/client.js +96 -6
- package/src/lib/confirm.js +10 -0
- package/src/lib/entity-view.js +42 -0
- package/src/lib/input.js +110 -0
- package/src/lib/keychain.js +47 -0
- package/src/lib/output/csv.js +26 -0
- package/src/lib/output/index.js +9 -1
- package/src/lib/output/yaml.js +9 -0
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import ora from 'ora'
|
|
4
|
+
import BaseCommand from '../base-command.js'
|
|
5
|
+
import { runBackup } from '../lib/backup.js'
|
|
6
|
+
|
|
7
|
+
export default class BackupCommand extends BaseCommand {
|
|
8
|
+
static description =
|
|
9
|
+
'Export the whole account to a JSON tree (resumable, one file per resource)'
|
|
10
|
+
|
|
11
|
+
static examples = [
|
|
12
|
+
'<%= config.bin %> backup',
|
|
13
|
+
'<%= config.bin %> backup --dir ./my-backup',
|
|
14
|
+
'<%= config.bin %> backup --dir ./my-backup --resume',
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
static flags = {
|
|
18
|
+
...BaseCommand.baseFlags,
|
|
19
|
+
dir: Flags.string({
|
|
20
|
+
description: 'Target directory for the export',
|
|
21
|
+
default: 'pipedrive-backup',
|
|
22
|
+
}),
|
|
23
|
+
resume: Flags.boolean({
|
|
24
|
+
description: 'Skip resources already completed in a previous run',
|
|
25
|
+
default: false,
|
|
26
|
+
}),
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async run() {
|
|
30
|
+
const { flags } = await this.parse(BackupCommand)
|
|
31
|
+
|
|
32
|
+
const spinner = ora('Starting backup...').start()
|
|
33
|
+
let summary
|
|
34
|
+
try {
|
|
35
|
+
summary = await runBackup(this.apiClient, flags.dir, {
|
|
36
|
+
resume: flags.resume,
|
|
37
|
+
onProgress: (resource, count) => {
|
|
38
|
+
spinner.text = `Exported ${resource} (${count})`
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
} finally {
|
|
42
|
+
spinner.stop()
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
this.log(
|
|
46
|
+
chalk.green(
|
|
47
|
+
`Backup complete: ${summary.exported}/${summary.total} resources ` +
|
|
48
|
+
`exported to ${chalk.cyan(flags.dir)}` +
|
|
49
|
+
(summary.skipped ? chalk.dim(` (${summary.skipped} skipped)`) : ''),
|
|
50
|
+
),
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { buildWriteBody } from '../../lib/input.js'
|
|
4
|
+
import { defsForFields, outputRecord } from '../../lib/entity-view.js'
|
|
5
|
+
|
|
6
|
+
export default class DealCreateCommand extends BaseCommand {
|
|
7
|
+
static description = 'Create a deal'
|
|
8
|
+
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> deal create --title "Acme renewal" --value 5000 --currency EUR',
|
|
11
|
+
'<%= config.bin %> deal create --title "Sized" --field "Deal Size=Large"',
|
|
12
|
+
'<%= config.bin %> deal create --title "Raw" --body \'{"probability":75}\'',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
static flags = {
|
|
16
|
+
...BaseCommand.baseFlags,
|
|
17
|
+
title: Flags.string({ required: true, description: 'Deal title' }),
|
|
18
|
+
value: Flags.integer({ description: 'Deal value' }),
|
|
19
|
+
currency: Flags.string({ description: 'Deal currency (e.g. EUR)' }),
|
|
20
|
+
status: Flags.string({
|
|
21
|
+
description: 'Deal status',
|
|
22
|
+
options: ['open', 'won', 'lost'],
|
|
23
|
+
}),
|
|
24
|
+
stage: Flags.integer({ description: 'Stage ID' }),
|
|
25
|
+
pipeline: Flags.integer({ description: 'Pipeline ID' }),
|
|
26
|
+
person: Flags.integer({ description: 'Linked person ID' }),
|
|
27
|
+
org: Flags.integer({ description: 'Linked organization ID' }),
|
|
28
|
+
owner: Flags.integer({ description: 'Owner (user) ID' }),
|
|
29
|
+
probability: Flags.integer({ description: 'Success probability (0-100)' }),
|
|
30
|
+
'expected-close-date': Flags.string({
|
|
31
|
+
description: 'Expected close date (YYYY-MM-DD)',
|
|
32
|
+
}),
|
|
33
|
+
field: Flags.string({
|
|
34
|
+
multiple: true,
|
|
35
|
+
description: 'Custom/standard field as "Name=Value" (repeatable)',
|
|
36
|
+
}),
|
|
37
|
+
body: Flags.string({ description: 'Raw JSON body to merge (flags win)' }),
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async run() {
|
|
41
|
+
const { flags } = await this.parse(DealCreateCommand)
|
|
42
|
+
|
|
43
|
+
const body = buildWriteBody({
|
|
44
|
+
typed: {
|
|
45
|
+
title: flags.title,
|
|
46
|
+
value: flags.value,
|
|
47
|
+
currency: flags.currency,
|
|
48
|
+
status: flags.status,
|
|
49
|
+
stage_id: flags.stage,
|
|
50
|
+
pipeline_id: flags.pipeline,
|
|
51
|
+
person_id: flags.person,
|
|
52
|
+
org_id: flags.org,
|
|
53
|
+
owner_id: flags.owner,
|
|
54
|
+
probability: flags.probability,
|
|
55
|
+
expected_close_date: flags['expected-close-date'],
|
|
56
|
+
},
|
|
57
|
+
fields: flags.field,
|
|
58
|
+
rawBody: flags.body,
|
|
59
|
+
defs: await defsForFields(this, 'deal', flags.field),
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
const res = await this.apiClient.post('/api/v2/deals', { body })
|
|
63
|
+
await outputRecord(this, res.data, 'deal')
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import BaseCommand from '../../base-command.js'
|
|
4
|
+
import { confirmAction } from '../../lib/confirm.js'
|
|
5
|
+
import { CliError } from '../../lib/errors.js'
|
|
6
|
+
|
|
7
|
+
export default class DealDeleteCommand extends BaseCommand {
|
|
8
|
+
static description = 'Delete a deal'
|
|
9
|
+
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> deal delete 42',
|
|
12
|
+
'<%= config.bin %> deal delete 42 --yes',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
static args = {
|
|
16
|
+
id: Args.integer({ required: true, description: 'Deal ID' }),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static flags = {
|
|
20
|
+
...BaseCommand.baseFlags,
|
|
21
|
+
yes: Flags.boolean({
|
|
22
|
+
char: 'y',
|
|
23
|
+
description: 'Skip the confirmation prompt',
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async run() {
|
|
29
|
+
const { args, flags } = await this.parse(DealDeleteCommand)
|
|
30
|
+
|
|
31
|
+
const ok = await confirmAction(`Delete deal ${args.id}?`, flags.yes)
|
|
32
|
+
if (!ok) {
|
|
33
|
+
throw new CliError('Aborted', { exitCode: 1 })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await this.apiClient.del(`/api/v2/deals/${args.id}`)
|
|
37
|
+
this.log(chalk.green(`Deleted deal ${args.id}`))
|
|
38
|
+
}
|
|
39
|
+
}
|
package/src/commands/deal/get.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Args } from '@oclif/core'
|
|
2
2
|
import BaseCommand from '../../base-command.js'
|
|
3
|
-
import {
|
|
4
|
-
import { flattenRecord } from '../../lib/output/record.js'
|
|
3
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
5
4
|
|
|
6
5
|
export default class DealGetCommand extends BaseCommand {
|
|
7
6
|
static description = 'Get a deal by ID'
|
|
@@ -22,22 +21,6 @@ export default class DealGetCommand extends BaseCommand {
|
|
|
22
21
|
async run() {
|
|
23
22
|
const { args } = await this.parse(DealGetCommand)
|
|
24
23
|
const body = await this.apiClient.get(`/api/v2/deals/${args.id}`)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
if (this.resolveFormat() === 'table') {
|
|
28
|
-
// Table view resolves custom-field hash keys to names and option IDs
|
|
29
|
-
// to labels; JSON output stays raw for scripting.
|
|
30
|
-
if (record.custom_fields && Object.keys(record.custom_fields).length) {
|
|
31
|
-
const defs = await getFields(this.apiClient, 'deal')
|
|
32
|
-
record = makeResolver(defs).resolveCustomFields(record)
|
|
33
|
-
}
|
|
34
|
-
await this.outputResults(flattenRecord(record), {
|
|
35
|
-
field: { header: 'Field' },
|
|
36
|
-
value: { header: 'Value' },
|
|
37
|
-
})
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
await this.outputResults(record, {})
|
|
24
|
+
await outputRecord(this, body.data, 'deal')
|
|
42
25
|
}
|
|
43
26
|
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { buildWriteBody } from '../../lib/input.js'
|
|
4
|
+
import { defsForFields, outputRecord } from '../../lib/entity-view.js'
|
|
5
|
+
import { CliError } from '../../lib/errors.js'
|
|
6
|
+
|
|
7
|
+
export default class DealUpdateCommand extends BaseCommand {
|
|
8
|
+
static description = 'Update a deal (v2 PATCH — only provided fields change)'
|
|
9
|
+
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> deal update 42 --stage 5',
|
|
12
|
+
'<%= config.bin %> deal update 42 --status won',
|
|
13
|
+
'<%= config.bin %> deal update 42 --field "Deal Size=Large"',
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
static args = {
|
|
17
|
+
id: Args.integer({ required: true, description: 'Deal ID' }),
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
static flags = {
|
|
21
|
+
...BaseCommand.baseFlags,
|
|
22
|
+
title: Flags.string({ description: 'Deal title' }),
|
|
23
|
+
value: Flags.integer({ description: 'Deal value' }),
|
|
24
|
+
currency: Flags.string({ description: 'Deal currency (e.g. EUR)' }),
|
|
25
|
+
status: Flags.string({
|
|
26
|
+
description: 'Deal status',
|
|
27
|
+
options: ['open', 'won', 'lost'],
|
|
28
|
+
}),
|
|
29
|
+
stage: Flags.integer({ description: 'Stage ID' }),
|
|
30
|
+
pipeline: Flags.integer({ description: 'Pipeline ID' }),
|
|
31
|
+
person: Flags.integer({ description: 'Linked person ID' }),
|
|
32
|
+
org: Flags.integer({ description: 'Linked organization ID' }),
|
|
33
|
+
owner: Flags.integer({ description: 'Owner (user) ID' }),
|
|
34
|
+
probability: Flags.integer({ description: 'Success probability (0-100)' }),
|
|
35
|
+
'expected-close-date': Flags.string({
|
|
36
|
+
description: 'Expected close date (YYYY-MM-DD)',
|
|
37
|
+
}),
|
|
38
|
+
field: Flags.string({
|
|
39
|
+
multiple: true,
|
|
40
|
+
description: 'Custom/standard field as "Name=Value" (repeatable)',
|
|
41
|
+
}),
|
|
42
|
+
body: Flags.string({ description: 'Raw JSON body to merge (flags win)' }),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async run() {
|
|
46
|
+
const { args, flags } = await this.parse(DealUpdateCommand)
|
|
47
|
+
|
|
48
|
+
const body = buildWriteBody({
|
|
49
|
+
typed: {
|
|
50
|
+
title: flags.title,
|
|
51
|
+
value: flags.value,
|
|
52
|
+
currency: flags.currency,
|
|
53
|
+
status: flags.status,
|
|
54
|
+
stage_id: flags.stage,
|
|
55
|
+
pipeline_id: flags.pipeline,
|
|
56
|
+
person_id: flags.person,
|
|
57
|
+
org_id: flags.org,
|
|
58
|
+
owner_id: flags.owner,
|
|
59
|
+
probability: flags.probability,
|
|
60
|
+
expected_close_date: flags['expected-close-date'],
|
|
61
|
+
},
|
|
62
|
+
fields: flags.field,
|
|
63
|
+
rawBody: flags.body,
|
|
64
|
+
defs: await defsForFields(this, 'deal', flags.field),
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
if (Object.keys(body).length === 0) {
|
|
68
|
+
throw new CliError(
|
|
69
|
+
'Nothing to update — pass at least one field flag, --field, or --body',
|
|
70
|
+
{ exitCode: 64 },
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const res = await this.apiClient.patch(`/api/v2/deals/${args.id}`, {
|
|
75
|
+
body,
|
|
76
|
+
})
|
|
77
|
+
await outputRecord(this, res.data, 'deal')
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs'
|
|
2
|
+
import { Args, Flags } from '@oclif/core'
|
|
3
|
+
import chalk from 'chalk'
|
|
4
|
+
import BaseCommand from '../../base-command.js'
|
|
5
|
+
|
|
6
|
+
export default class FileDownloadCommand extends BaseCommand {
|
|
7
|
+
static description = 'Download a file by ID'
|
|
8
|
+
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> file download 5',
|
|
11
|
+
'<%= config.bin %> file download 5 --out ./report.pdf',
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
static args = {
|
|
15
|
+
id: Args.integer({ required: true, description: 'File ID' }),
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
static flags = {
|
|
19
|
+
...BaseCommand.baseFlags,
|
|
20
|
+
out: Flags.string({ description: 'Path to write to (default: file name)' }),
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async run() {
|
|
24
|
+
const { args, flags } = await this.parse(FileDownloadCommand)
|
|
25
|
+
|
|
26
|
+
const body = await this.apiClient.get(`/api/v1/files/${args.id}`)
|
|
27
|
+
const { buffer } = await this.apiClient.download(
|
|
28
|
+
`/api/v1/files/${args.id}/download`,
|
|
29
|
+
)
|
|
30
|
+
const bytes = Buffer.from(buffer)
|
|
31
|
+
const out = flags.out ?? body.data.name
|
|
32
|
+
writeFileSync(out, bytes)
|
|
33
|
+
this.log(chalk.green(`Saved ${out} (${bytes.length} bytes)`))
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Args } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
4
|
+
|
|
5
|
+
export default class FileGetCommand extends BaseCommand {
|
|
6
|
+
static description = 'Get a file by ID'
|
|
7
|
+
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> file get 5',
|
|
10
|
+
'<%= config.bin %> file get 5 --output json',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static args = {
|
|
18
|
+
id: Args.integer({ required: true, description: 'File ID' }),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run() {
|
|
22
|
+
const { args } = await this.parse(FileGetCommand)
|
|
23
|
+
const body = await this.apiClient.get(`/api/v1/files/${args.id}`)
|
|
24
|
+
await outputRecord(this, body.data)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import BaseCommand from '../../base-command.js'
|
|
2
|
+
import { collectPages } from '../../lib/pagination.js'
|
|
3
|
+
|
|
4
|
+
const columns = {
|
|
5
|
+
id: { header: 'ID' },
|
|
6
|
+
name: { header: 'Name' },
|
|
7
|
+
file_type: { header: 'Type' },
|
|
8
|
+
file_size: { header: 'Size' },
|
|
9
|
+
deal_id: { header: 'Deal' },
|
|
10
|
+
person_id: { header: 'Person' },
|
|
11
|
+
add_time: { header: 'Created' },
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default class FileListCommand extends BaseCommand {
|
|
15
|
+
static description = 'List files'
|
|
16
|
+
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> file list',
|
|
19
|
+
'<%= config.bin %> file list --limit 50 --output json',
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
static flags = {
|
|
23
|
+
...BaseCommand.baseFlags,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(FileListCommand)
|
|
28
|
+
const limit = flags.limit ?? 100
|
|
29
|
+
|
|
30
|
+
const query = {
|
|
31
|
+
limit: Math.min(limit, 100),
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const items = await collectPages(
|
|
35
|
+
this.apiClient.pageV1('/api/v1/files', query),
|
|
36
|
+
limit,
|
|
37
|
+
)
|
|
38
|
+
await this.outputResults(items, columns)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { basename } from 'node:path'
|
|
3
|
+
import { Args, Flags } from '@oclif/core'
|
|
4
|
+
import BaseCommand from '../../base-command.js'
|
|
5
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
6
|
+
|
|
7
|
+
export default class FileUploadCommand extends BaseCommand {
|
|
8
|
+
static description = 'Upload a file'
|
|
9
|
+
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> file upload ./report.pdf',
|
|
12
|
+
'<%= config.bin %> file upload ./report.pdf --deal 42',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
static args = {
|
|
16
|
+
path: Args.string({ required: true, description: 'Path to the file' }),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static flags = {
|
|
20
|
+
...BaseCommand.baseFlags,
|
|
21
|
+
deal: Flags.integer({ description: 'Associate with a deal ID' }),
|
|
22
|
+
person: Flags.integer({ description: 'Associate with a person ID' }),
|
|
23
|
+
org: Flags.integer({ description: 'Associate with an organization ID' }),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async run() {
|
|
27
|
+
const { args, flags } = await this.parse(FileUploadCommand)
|
|
28
|
+
|
|
29
|
+
const data = readFileSync(args.path)
|
|
30
|
+
const name = basename(args.path)
|
|
31
|
+
|
|
32
|
+
const res = await this.apiClient.postMultipart('/api/v1/files', {
|
|
33
|
+
file: { name, data },
|
|
34
|
+
fields: {
|
|
35
|
+
deal_id: flags.deal,
|
|
36
|
+
person_id: flags.person,
|
|
37
|
+
org_id: flags.org,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
await outputRecord(this, res.data)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Args } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
4
|
+
|
|
5
|
+
export default class FilterGetCommand extends BaseCommand {
|
|
6
|
+
static description = 'Get a filter by ID'
|
|
7
|
+
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> filter get 5',
|
|
10
|
+
'<%= config.bin %> filter get 5 --output json',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static args = {
|
|
18
|
+
id: Args.integer({ required: true, description: 'Filter ID' }),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run() {
|
|
22
|
+
const { args } = await this.parse(FilterGetCommand)
|
|
23
|
+
const body = await this.apiClient.get(`/api/v1/filters/${args.id}`)
|
|
24
|
+
await outputRecord(this, body.data)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
|
|
4
|
+
const columns = {
|
|
5
|
+
id: { header: 'ID' },
|
|
6
|
+
name: { header: 'Name' },
|
|
7
|
+
type: { header: 'Type' },
|
|
8
|
+
active_flag: { header: 'Active' },
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default class FilterListCommand extends BaseCommand {
|
|
12
|
+
static description = 'List filters'
|
|
13
|
+
|
|
14
|
+
static examples = [
|
|
15
|
+
'<%= config.bin %> filter list',
|
|
16
|
+
'<%= config.bin %> filter list --type deals --output json',
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
static flags = {
|
|
20
|
+
...BaseCommand.baseFlags,
|
|
21
|
+
type: Flags.string({
|
|
22
|
+
description: 'Filter by type',
|
|
23
|
+
options: [
|
|
24
|
+
'deals',
|
|
25
|
+
'leads',
|
|
26
|
+
'org',
|
|
27
|
+
'people',
|
|
28
|
+
'products',
|
|
29
|
+
'activity',
|
|
30
|
+
'projects',
|
|
31
|
+
],
|
|
32
|
+
}),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async run() {
|
|
36
|
+
const { flags } = await this.parse(FilterListCommand)
|
|
37
|
+
|
|
38
|
+
const body = await this.apiClient.get('/api/v1/filters', {
|
|
39
|
+
query: { type: flags.type },
|
|
40
|
+
})
|
|
41
|
+
await this.outputResults(body.data, columns)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
|
|
4
|
+
const columns = {
|
|
5
|
+
id: { header: 'ID' },
|
|
6
|
+
title: { header: 'Title', get: (row) => row.title ?? '' },
|
|
7
|
+
type: { header: 'Type', get: (row) => row.type?.name ?? '' },
|
|
8
|
+
interval: { header: 'Interval', get: (row) => row.interval ?? '' },
|
|
9
|
+
owner_id: { header: 'Owner' },
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default class GoalListCommand extends BaseCommand {
|
|
13
|
+
static description = 'List goals'
|
|
14
|
+
|
|
15
|
+
static examples = [
|
|
16
|
+
'<%= config.bin %> goal list',
|
|
17
|
+
'<%= config.bin %> goal list --assignee 7 --type deals_won --output json',
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
static flags = {
|
|
21
|
+
...BaseCommand.baseFlags,
|
|
22
|
+
assignee: Flags.integer({ description: 'Filter by assignee (user) ID' }),
|
|
23
|
+
type: Flags.string({ description: 'Filter by goal type name' }),
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(GoalListCommand)
|
|
28
|
+
|
|
29
|
+
const body = await this.apiClient.get('/api/v1/goals/find', {
|
|
30
|
+
query: {
|
|
31
|
+
'assignee.id': flags.assignee,
|
|
32
|
+
'type.name': flags.type,
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
await this.outputResults(body.data?.goals ?? [], columns)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { buildWriteBody } from '../../lib/input.js'
|
|
4
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
5
|
+
|
|
6
|
+
export default class LeadCreateCommand extends BaseCommand {
|
|
7
|
+
static description = 'Create a lead'
|
|
8
|
+
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> lead create --title "Acme renewal" --value 5000 --currency EUR',
|
|
11
|
+
'<%= config.bin %> lead create --title "Linked" --person 4 --org 5',
|
|
12
|
+
'<%= config.bin %> lead create --title "Raw" --body \'{"visible_to":"3"}\'',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
static flags = {
|
|
16
|
+
...BaseCommand.baseFlags,
|
|
17
|
+
title: Flags.string({ required: true, description: 'Lead title' }),
|
|
18
|
+
person: Flags.integer({ description: 'Linked person ID' }),
|
|
19
|
+
org: Flags.integer({ description: 'Linked organization ID' }),
|
|
20
|
+
owner: Flags.integer({ description: 'Owner (user) ID' }),
|
|
21
|
+
value: Flags.string({
|
|
22
|
+
description: 'Lead value amount (requires --currency)',
|
|
23
|
+
dependsOn: ['currency'],
|
|
24
|
+
}),
|
|
25
|
+
currency: Flags.string({
|
|
26
|
+
description: 'Lead value currency (requires --value)',
|
|
27
|
+
dependsOn: ['value'],
|
|
28
|
+
}),
|
|
29
|
+
'expected-close-date': Flags.string({
|
|
30
|
+
description: 'Expected close date (YYYY-MM-DD)',
|
|
31
|
+
}),
|
|
32
|
+
body: Flags.string({ description: 'Raw JSON body to merge (flags win)' }),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async run() {
|
|
36
|
+
const { flags } = await this.parse(LeadCreateCommand)
|
|
37
|
+
|
|
38
|
+
const value =
|
|
39
|
+
flags.value !== undefined && flags.currency !== undefined
|
|
40
|
+
? { amount: Number(flags.value), currency: flags.currency }
|
|
41
|
+
: undefined
|
|
42
|
+
|
|
43
|
+
const body = buildWriteBody({
|
|
44
|
+
typed: {
|
|
45
|
+
title: flags.title,
|
|
46
|
+
person_id: flags.person,
|
|
47
|
+
organization_id: flags.org,
|
|
48
|
+
owner_id: flags.owner,
|
|
49
|
+
value,
|
|
50
|
+
expected_close_date: flags['expected-close-date'],
|
|
51
|
+
},
|
|
52
|
+
rawBody: flags.body,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const res = await this.apiClient.post('/api/v1/leads', { body })
|
|
56
|
+
await outputRecord(this, res.data, 'deal')
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core'
|
|
2
|
+
import chalk from 'chalk'
|
|
3
|
+
import BaseCommand from '../../base-command.js'
|
|
4
|
+
import { confirmAction } from '../../lib/confirm.js'
|
|
5
|
+
import { CliError } from '../../lib/errors.js'
|
|
6
|
+
|
|
7
|
+
export default class LeadDeleteCommand extends BaseCommand {
|
|
8
|
+
static description = 'Delete a lead'
|
|
9
|
+
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> lead delete adf21080-0e10-11eb-879b-05d71fb426ec',
|
|
12
|
+
'<%= config.bin %> lead delete adf21080-0e10-11eb-879b-05d71fb426ec --yes',
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
static args = {
|
|
16
|
+
id: Args.string({ required: true, description: 'Lead ID (UUID)' }),
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static flags = {
|
|
20
|
+
...BaseCommand.baseFlags,
|
|
21
|
+
yes: Flags.boolean({
|
|
22
|
+
char: 'y',
|
|
23
|
+
description: 'Skip the confirmation prompt',
|
|
24
|
+
default: false,
|
|
25
|
+
}),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async run() {
|
|
29
|
+
const { args, flags } = await this.parse(LeadDeleteCommand)
|
|
30
|
+
|
|
31
|
+
const ok = await confirmAction(`Delete lead ${args.id}?`, flags.yes)
|
|
32
|
+
if (!ok) {
|
|
33
|
+
throw new CliError('Aborted', { exitCode: 1 })
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
await this.apiClient.del(`/api/v1/leads/${args.id}`)
|
|
37
|
+
this.log(chalk.green(`Deleted lead ${args.id}`))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Args } from '@oclif/core'
|
|
2
|
+
import BaseCommand from '../../base-command.js'
|
|
3
|
+
import { outputRecord } from '../../lib/entity-view.js'
|
|
4
|
+
|
|
5
|
+
export default class LeadGetCommand extends BaseCommand {
|
|
6
|
+
static description = 'Get a lead by ID'
|
|
7
|
+
|
|
8
|
+
static examples = [
|
|
9
|
+
'<%= config.bin %> lead get adf21080-0e10-11eb-879b-05d71fb426ec',
|
|
10
|
+
'<%= config.bin %> lead get adf21080-0e10-11eb-879b-05d71fb426ec --output json',
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
static flags = {
|
|
14
|
+
...BaseCommand.baseFlags,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
static args = {
|
|
18
|
+
id: Args.string({ required: true, description: 'Lead ID (UUID)' }),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async run() {
|
|
22
|
+
const { args } = await this.parse(LeadGetCommand)
|
|
23
|
+
const body = await this.apiClient.get(`/api/v1/leads/${args.id}`)
|
|
24
|
+
await outputRecord(this, body.data, 'deal')
|
|
25
|
+
}
|
|
26
|
+
}
|