Skip to content

Commit 4a61afe

Browse files
committed
feat: support folder crud commands
1 parent 0b9141e commit 4a61afe

19 files changed

Lines changed: 629 additions & 20 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
},
88
"bugs": "https://github.com/hackmdio/hackmd-cli/issues",
99
"dependencies": {
10-
"@hackmd/api": "^2.5.0",
10+
"@hackmd/api": "2.5.0-beta.20260430192828.99a5117",
1111
"@hackmd/oclif-plugin-autocomplete": "^2.1.9-fish",
1212
"@oclif/core": "2.8.2",
1313
"@oclif/plugin-help": "5.2.9",

pnpm-lock.yaml

Lines changed: 8 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commands/folders/create.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
2+
import type {CreateUserFolderBody} from '@hackmd/api'
3+
4+
import {Flags, ux} from '@oclif/core'
5+
6+
import HackMDCommand from '../../command'
7+
import {
8+
folderColor,
9+
folderDescription,
10+
folderIcon,
11+
folderName,
12+
parentFolderId,
13+
} from '../../flags'
14+
15+
export default class Create extends HackMDCommand {
16+
static description = 'Create a folder'
17+
static flags = {
18+
color: folderColor,
19+
description: folderDescription,
20+
help: Flags.help({char: 'h'}),
21+
icon: folderIcon,
22+
name: folderName,
23+
parentFolderId,
24+
...ux.table.flags(),
25+
}
26+
27+
async run() {
28+
const {flags} = await this.parse(Create)
29+
const {color, description, icon, name, parentFolderId} = flags
30+
31+
if (!name) {
32+
this.error('Flag name could not be empty')
33+
}
34+
35+
const payload: CreateUserFolderBody = {
36+
color,
37+
description,
38+
icon,
39+
name,
40+
parentFolderId,
41+
}
42+
43+
try {
44+
const APIClient = await this.getAPIClient()
45+
const folder = await APIClient.createFolder(payload)
46+
47+
ux.table([folder], {
48+
color: {},
49+
description: {},
50+
icon: {},
51+
id: {
52+
header: 'ID',
53+
},
54+
name: {},
55+
parentFolderId: {
56+
header: 'Parent Folder ID',
57+
},
58+
}, {
59+
printLine: this.log.bind(this),
60+
...flags,
61+
})
62+
} catch (error) {
63+
this.log('Create folder failed')
64+
this.error(error as Error)
65+
}
66+
}
67+
}

src/commands/folders/delete.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import {Flags} from '@oclif/core'
2+
3+
import HackMDCommand from '../../command'
4+
import {folderId} from '../../flags'
5+
6+
export default class Delete extends HackMDCommand {
7+
static description = 'Delete a folder'
8+
static flags = {
9+
folderId,
10+
help: Flags.help({char: 'h'}),
11+
}
12+
13+
async run() {
14+
const {flags} = await this.parse(Delete)
15+
const {folderId} = flags
16+
17+
if (!folderId) {
18+
this.error('Flag folderId could not be empty')
19+
}
20+
21+
try {
22+
const APIClient = await this.getAPIClient()
23+
await APIClient.deleteFolder(folderId)
24+
} catch (error) {
25+
this.log('Delete folder failed')
26+
this.error(error as Error)
27+
}
28+
}
29+
}

src/commands/folders/index.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import {Flags, ux} from '@oclif/core'
2+
3+
import HackMDCommand from '../../command'
4+
import {folderId} from '../../flags'
5+
6+
export default class IndexCommand extends HackMDCommand {
7+
static description = 'HackMD folders commands'
8+
static flags = {
9+
folderId,
10+
help: Flags.help({char: 'h'}),
11+
...ux.table.flags(),
12+
}
13+
14+
async run() {
15+
const {flags} = await this.parse(IndexCommand)
16+
17+
try {
18+
const APIClient = await this.getAPIClient()
19+
const folders = flags.folderId ? [await APIClient.getFolder(flags.folderId)] : await APIClient.getFolderList()
20+
21+
ux.table(folders, {
22+
color: {},
23+
description: {},
24+
icon: {},
25+
id: {
26+
header: 'ID',
27+
},
28+
name: {},
29+
parentFolderId: {
30+
header: 'Parent Folder ID',
31+
},
32+
}, {
33+
printLine: this.log.bind(this),
34+
...flags,
35+
})
36+
} catch (error) {
37+
this.log('Fetch folders failed')
38+
this.error(error as Error)
39+
}
40+
}
41+
}

src/commands/folders/order.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import {Flags} from '@oclif/core'
2+
3+
import HackMDCommand from '../../command'
4+
import {folderOrder} from '../../flags'
5+
import {parseFolderOrder} from '../../utils'
6+
7+
export default class Order extends HackMDCommand {
8+
static description = 'Get or update folder order'
9+
static flags = {
10+
help: Flags.help({char: 'h'}),
11+
order: folderOrder,
12+
}
13+
14+
async run() {
15+
const {flags} = await this.parse(Order)
16+
17+
try {
18+
const APIClient = await this.getAPIClient()
19+
20+
if (flags.order) {
21+
await APIClient.updateFolderOrder({
22+
order: parseFolderOrder(flags.order),
23+
})
24+
this.log('Folder order updated')
25+
return
26+
}
27+
28+
const order = await APIClient.getFolderOrder()
29+
this.log(JSON.stringify(order, null, 2))
30+
} catch (error) {
31+
this.log('Update folder order failed')
32+
this.error(error as Error)
33+
}
34+
}
35+
}

src/commands/folders/update.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import type {UpdateUserFolderBody} from '@hackmd/api'
2+
3+
import {Flags, ux} from '@oclif/core'
4+
5+
import HackMDCommand from '../../command'
6+
import {
7+
folderColor,
8+
folderDescription,
9+
folderIcon,
10+
folderId,
11+
folderName,
12+
parentFolderId,
13+
} from '../../flags'
14+
15+
export default class Update extends HackMDCommand {
16+
static description = 'Update folder'
17+
static flags = {
18+
color: folderColor,
19+
description: folderDescription,
20+
folderId,
21+
help: Flags.help({char: 'h'}),
22+
icon: folderIcon,
23+
name: folderName,
24+
parentFolderId,
25+
...ux.table.flags(),
26+
}
27+
28+
async run() {
29+
const {flags} = await this.parse(Update)
30+
const {color, description, folderId, icon, name, parentFolderId} = flags
31+
32+
if (!folderId) {
33+
this.error('Flag folderId could not be empty')
34+
}
35+
36+
const payload: UpdateUserFolderBody = {
37+
color,
38+
description,
39+
icon,
40+
name,
41+
parentFolderId,
42+
}
43+
44+
try {
45+
const APIClient = await this.getAPIClient()
46+
const folder = await APIClient.updateFolder(folderId, payload)
47+
48+
ux.table([folder], {
49+
color: {},
50+
description: {},
51+
icon: {},
52+
id: {
53+
header: 'ID',
54+
},
55+
name: {},
56+
parentFolderId: {
57+
header: 'Parent Folder ID',
58+
},
59+
}, {
60+
printLine: this.log.bind(this),
61+
...flags,
62+
})
63+
} catch (error) {
64+
this.log('Update folder failed')
65+
this.error(error as Error)
66+
}
67+
}
68+
}

src/commands/notes/create.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
import {
1+
import type {
22
CommentPermissionType,
33
CreateNoteOptions,
44
NotePermissionRole,
5-
} from '@hackmd/api/dist/type'
5+
} from '@hackmd/api'
6+
67
import {Flags, ux} from '@oclif/core'
78
import * as fs from 'node:fs'
89

@@ -13,6 +14,7 @@ import {
1314
noteContent,
1415
notePermission,
1516
noteTitle,
17+
parentFolderId,
1618
} from '../../flags'
1719
import {openEditor} from '../../open-editor'
1820
import {safeStdinRead, temporaryMD} from '../../utils'
@@ -34,6 +36,7 @@ raUuSTetT5uQbqQfLnz9lA A new note gvfz2UB5THiKABQJQnLs6Q
3436
content: noteContent,
3537
editor,
3638
help: Flags.help({char: 'h'}),
39+
parentFolderId,
3740
readPermission: notePermission,
3841
title: noteTitle,
3942
writePermission: notePermission,
@@ -47,6 +50,7 @@ raUuSTetT5uQbqQfLnz9lA A new note gvfz2UB5THiKABQJQnLs6Q
4750
const options: CreateNoteOptions = {
4851
commentPermission: flags.commentPermission as CommentPermissionType,
4952
content: pipeString || flags.content,
53+
parentFolderId: flags.parentFolderId,
5054
readPermission: flags.readPermission as NotePermissionRole,
5155
title: flags.title,
5256
writePermission: flags.writePermission as NotePermissionRole,

src/commands/notes/update.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
import type {UpdateNoteOptions} from '@hackmd/api'
2+
13
import {Flags} from '@oclif/core'
24

35
import HackMDCommand from '../../command'
4-
import {noteContent, noteId} from '../../flags'
6+
import {noteContent, noteId, parentFolderId} from '../../flags'
57

68
export default class Update extends HackMDCommand {
79
static description = 'Update note content'
@@ -12,19 +14,25 @@ export default class Update extends HackMDCommand {
1214
content: noteContent,
1315
help: Flags.help({char: 'h'}),
1416
noteId,
17+
parentFolderId,
1518
}
1619

1720
async run() {
1821
const {flags} = await this.parse(Update)
19-
const {content, noteId} = flags
22+
const {content, noteId, parentFolderId} = flags
2023

2124
if (!noteId) {
2225
this.error('Flag noteId could not be empty')
2326
}
2427

28+
const payload: UpdateNoteOptions = {
29+
content,
30+
parentFolderId,
31+
}
32+
2533
try {
2634
const APIClient = await this.getAPIClient()
27-
await APIClient.updateNoteContent(noteId, content)
35+
await APIClient.updateNote(noteId, payload)
2836
} catch (error) {
2937
this.log('Update note content failed')
3038
this.error(error as Error)

0 commit comments

Comments
 (0)