trello-cli-unofficial 0.6.9 → 0.7.3
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/README.md +26 -13
- package/bunfig.toml +2 -0
- package/dist/main.js +10709 -10223
- package/package.json +20 -2
- package/scripts/check-coverage.js +67 -0
- package/src/application/use-cases/AuthenticateUserUseCase.ts +2 -2
- package/src/application/use-cases/CreateCardUseCase.ts +2 -2
- package/src/application/use-cases/DeleteCardUseCase.ts +1 -1
- package/src/application/use-cases/GetBoardsUseCase.ts +2 -2
- package/src/application/use-cases/GetCardsUseCase.ts +2 -2
- package/src/application/use-cases/GetListsUseCase.ts +2 -2
- package/src/application/use-cases/MoveCardUseCase.ts +2 -2
- package/src/application/use-cases/UpdateCardUseCase.ts +2 -2
- package/src/domain/repositories/ConfigRepository.ts +1 -1
- package/src/domain/repositories/TrelloRepository.ts +7 -1
- package/src/domain/services/AuthenticationService.ts +2 -2
- package/src/infrastructure/repositories/FileConfigRepository.ts +4 -6
- package/src/infrastructure/repositories/TrelloApiRepository.ts +3 -3
- package/src/presentation/cli/AuthController.ts +38 -0
- package/src/presentation/cli/BoardController.ts +85 -0
- package/src/presentation/cli/CardController.ts +319 -0
- package/src/presentation/cli/CommandController.ts +113 -10
- package/src/presentation/cli/ConfigController.ts +57 -0
- package/src/presentation/cli/MainMenuController.ts +62 -0
- package/src/presentation/cli/TrelloCliController.ts +35 -390
- package/src/presentation/cli/index.ts +5 -0
- package/test_trigger.txt +3 -0
- package/.eslintignore +0 -26
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
import type { CardEntity, ListEntity } from '@domain/entities';
|
|
2
|
+
import type { TrelloRepository } from '@domain/repositories';
|
|
3
|
+
import {
|
|
4
|
+
CreateCardUseCase,
|
|
5
|
+
DeleteCardUseCase,
|
|
6
|
+
MoveCardUseCase,
|
|
7
|
+
UpdateCardUseCase,
|
|
8
|
+
} from '@application/use-cases';
|
|
9
|
+
import { CARD_ACTIONS } from '@shared/types';
|
|
10
|
+
import inquirer from 'inquirer';
|
|
11
|
+
|
|
12
|
+
export class CardController {
|
|
13
|
+
private createCardUseCase: CreateCardUseCase;
|
|
14
|
+
private updateCardUseCase: UpdateCardUseCase;
|
|
15
|
+
private deleteCardUseCase: DeleteCardUseCase;
|
|
16
|
+
private moveCardUseCase: MoveCardUseCase;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
private trelloRepository: TrelloRepository,
|
|
20
|
+
private boardController: unknown, // Will be injected to avoid circular dependency
|
|
21
|
+
) {
|
|
22
|
+
this.createCardUseCase = new CreateCardUseCase(trelloRepository);
|
|
23
|
+
this.updateCardUseCase = new UpdateCardUseCase(trelloRepository);
|
|
24
|
+
this.deleteCardUseCase = new DeleteCardUseCase(trelloRepository);
|
|
25
|
+
this.moveCardUseCase = new MoveCardUseCase(trelloRepository);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async createCardInteractive(): Promise<void> {
|
|
29
|
+
const boards = await (this.boardController as any).getBoards();
|
|
30
|
+
|
|
31
|
+
const { selectedBoard } = await inquirer.prompt([
|
|
32
|
+
{
|
|
33
|
+
type: 'list',
|
|
34
|
+
name: 'selectedBoard',
|
|
35
|
+
message: 'Selecione o quadro:',
|
|
36
|
+
choices: boards.map((board: any) => ({ name: board.name, value: board.id })),
|
|
37
|
+
},
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
const lists = await (this.boardController as any).getLists(selectedBoard);
|
|
41
|
+
|
|
42
|
+
const { selectedList } = await inquirer.prompt([
|
|
43
|
+
{
|
|
44
|
+
type: 'list',
|
|
45
|
+
name: 'selectedList',
|
|
46
|
+
message: 'Selecione a lista:',
|
|
47
|
+
choices: lists.map((list: any) => ({ name: list.name, value: list.id })),
|
|
48
|
+
},
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
const { cardName, cardDesc } = await inquirer.prompt([
|
|
52
|
+
{
|
|
53
|
+
type: 'input',
|
|
54
|
+
name: 'cardName',
|
|
55
|
+
message: 'Nome do cartão:',
|
|
56
|
+
validate: input => input.length > 0 || 'Nome é obrigatório',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
type: 'input',
|
|
60
|
+
name: 'cardDesc',
|
|
61
|
+
message: 'Descrição (opcional):',
|
|
62
|
+
},
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
const newCard = await this.createCardUseCase.execute({
|
|
66
|
+
name: cardName,
|
|
67
|
+
desc: cardDesc,
|
|
68
|
+
listId: selectedList,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log('✅ Cartão criado com sucesso!');
|
|
72
|
+
console.log(`📝 Nome: ${newCard.name}`);
|
|
73
|
+
console.log(`🔗 URL: ${newCard.url}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async exploreCards(boardId: string, lists: ListEntity[]): Promise<void> {
|
|
77
|
+
const { selectedList } = await inquirer.prompt([
|
|
78
|
+
{
|
|
79
|
+
type: 'list',
|
|
80
|
+
name: 'selectedList',
|
|
81
|
+
message: 'Selecione uma lista:',
|
|
82
|
+
choices: lists.map(list => ({ name: list.name, value: list.id })),
|
|
83
|
+
},
|
|
84
|
+
]);
|
|
85
|
+
|
|
86
|
+
const cards = await (this.boardController as any).getCards(selectedList);
|
|
87
|
+
|
|
88
|
+
if (cards.length === 0) {
|
|
89
|
+
console.log('📭 Esta lista está vazia.');
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
console.log(
|
|
94
|
+
`🃏 Cartões em "${lists.find(l => l.id === selectedList)?.name}":`,
|
|
95
|
+
);
|
|
96
|
+
cards.forEach((card: any, index: number) => {
|
|
97
|
+
console.log(`${index + 1}. ${card.name}`);
|
|
98
|
+
if (card.desc) {
|
|
99
|
+
const desc
|
|
100
|
+
= card.desc.length > 100
|
|
101
|
+
? `${card.desc.substring(0, 100)}...`
|
|
102
|
+
: card.desc;
|
|
103
|
+
console.log(` 📝 ${desc}`);
|
|
104
|
+
}
|
|
105
|
+
console.log(` 🔗 ${card.url}\n`);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Opções adicionais
|
|
109
|
+
const { nextAction } = await inquirer.prompt([
|
|
110
|
+
{
|
|
111
|
+
type: 'list',
|
|
112
|
+
name: 'nextAction',
|
|
113
|
+
message: 'O que deseja fazer?',
|
|
114
|
+
choices: [
|
|
115
|
+
{ name: '⬅️ Voltar ao menu', value: CARD_ACTIONS.BACK },
|
|
116
|
+
{ name: '📝 Editar cartão', value: CARD_ACTIONS.EDIT },
|
|
117
|
+
{ name: '🗑️ Deletar cartão', value: CARD_ACTIONS.DELETE },
|
|
118
|
+
{ name: '📦 Mover cartão', value: CARD_ACTIONS.MOVE },
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
]);
|
|
122
|
+
|
|
123
|
+
if (nextAction !== CARD_ACTIONS.BACK) {
|
|
124
|
+
const { selectedCard } = await inquirer.prompt([
|
|
125
|
+
{
|
|
126
|
+
type: 'list',
|
|
127
|
+
name: 'selectedCard',
|
|
128
|
+
message: 'Selecione um cartão:',
|
|
129
|
+
choices: cards.map((card: any) => ({ name: card.name, value: card.id })),
|
|
130
|
+
},
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
const selectedCardEntity = cards.find((c: any) => c.id === selectedCard)!;
|
|
134
|
+
|
|
135
|
+
switch (nextAction) {
|
|
136
|
+
case CARD_ACTIONS.EDIT:
|
|
137
|
+
await this.editCard(selectedCard, selectedCardEntity);
|
|
138
|
+
break;
|
|
139
|
+
case CARD_ACTIONS.DELETE:
|
|
140
|
+
await this.deleteCardInteractive(selectedCard, selectedCardEntity);
|
|
141
|
+
break;
|
|
142
|
+
case CARD_ACTIONS.MOVE:
|
|
143
|
+
await this.moveCardInteractive(selectedCard, boardId, lists);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
private async editCard(cardId: string, card: CardEntity): Promise<void> {
|
|
150
|
+
const { newName, newDesc } = await inquirer.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: 'input',
|
|
153
|
+
name: 'newName',
|
|
154
|
+
message: 'Novo nome:',
|
|
155
|
+
default: card.name,
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
type: 'input',
|
|
159
|
+
name: 'newDesc',
|
|
160
|
+
message: 'Nova descrição:',
|
|
161
|
+
default: card.desc || '',
|
|
162
|
+
},
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
await this.updateCardUseCase.execute(cardId, {
|
|
166
|
+
name: newName,
|
|
167
|
+
desc: newDesc,
|
|
168
|
+
});
|
|
169
|
+
console.log('✅ Cartão atualizado com sucesso!');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private async deleteCardInteractive(
|
|
173
|
+
cardId: string,
|
|
174
|
+
card: CardEntity,
|
|
175
|
+
): Promise<void> {
|
|
176
|
+
const { confirm } = await inquirer.prompt([
|
|
177
|
+
{
|
|
178
|
+
type: 'confirm',
|
|
179
|
+
name: 'confirm',
|
|
180
|
+
message: `Tem certeza que deseja deletar "${card.name}"?`,
|
|
181
|
+
default: false,
|
|
182
|
+
},
|
|
183
|
+
]);
|
|
184
|
+
|
|
185
|
+
if (confirm) {
|
|
186
|
+
await this.deleteCard(cardId, card);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private async moveCardInteractive(
|
|
191
|
+
cardId: string,
|
|
192
|
+
currentBoardId: string,
|
|
193
|
+
lists: ListEntity[],
|
|
194
|
+
): Promise<void> {
|
|
195
|
+
const { targetList } = await inquirer.prompt([
|
|
196
|
+
{
|
|
197
|
+
type: 'list',
|
|
198
|
+
name: 'targetList',
|
|
199
|
+
message: 'Mover para qual lista?',
|
|
200
|
+
choices: lists.map(list => ({ name: list.name, value: list.id })),
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
// Encontrar o nome da lista de destino para passar para o método público
|
|
205
|
+
const targetListObj = lists.find(list => list.id === targetList);
|
|
206
|
+
if (targetListObj) {
|
|
207
|
+
await this.moveCard(cardId, targetListObj.name);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
async createCard(
|
|
212
|
+
boardName: string,
|
|
213
|
+
listName: string,
|
|
214
|
+
cardName: string,
|
|
215
|
+
description?: string,
|
|
216
|
+
): Promise<void> {
|
|
217
|
+
const boards = await (this.boardController as any).getBoards();
|
|
218
|
+
const board = boards.find((b: any) => b.name === boardName);
|
|
219
|
+
|
|
220
|
+
if (!board) {
|
|
221
|
+
throw new Error(`Quadro "${boardName}" não encontrado`);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const lists = await (this.boardController as any).getLists(board.id);
|
|
225
|
+
const list = lists.find((l: any) => l.name === listName);
|
|
226
|
+
|
|
227
|
+
if (!list) {
|
|
228
|
+
throw new Error(
|
|
229
|
+
`Lista "${listName}" não encontrada no quadro "${boardName}"`,
|
|
230
|
+
);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const newCard = await this.createCardUseCase.execute({
|
|
234
|
+
name: cardName,
|
|
235
|
+
desc: description || '',
|
|
236
|
+
listId: list.id,
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
console.log('✅ Cartão criado com sucesso!');
|
|
240
|
+
console.log(`📝 Nome: ${newCard.name}`);
|
|
241
|
+
console.log(`🔗 URL: ${newCard.url}`);
|
|
242
|
+
console.log(`🆔 ID: ${newCard.id}`);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async moveCard(cardId: string, targetListName: string): Promise<void> {
|
|
246
|
+
// Primeiro precisamos encontrar em qual board o cartão está
|
|
247
|
+
// Para isso, vamos buscar todas as listas de todos os boards
|
|
248
|
+
const boards = await (this.boardController as any).getBoards();
|
|
249
|
+
|
|
250
|
+
for (const board of boards) {
|
|
251
|
+
const lists = await (this.boardController as any).getLists(board.id);
|
|
252
|
+
|
|
253
|
+
// Verificar se alguma lista contém o cartão
|
|
254
|
+
for (const list of lists) {
|
|
255
|
+
try {
|
|
256
|
+
const cards = await (this.boardController as any).getCards(list.id);
|
|
257
|
+
const card = cards.find((c: any) => c.id === cardId);
|
|
258
|
+
|
|
259
|
+
if (card) {
|
|
260
|
+
// Encontrou o cartão! Agora procurar a lista de destino
|
|
261
|
+
const targetList = lists.find((l: any) => l.name === targetListName);
|
|
262
|
+
|
|
263
|
+
if (!targetList) {
|
|
264
|
+
throw new Error(
|
|
265
|
+
`Lista "${targetListName}" não encontrada no quadro "${board.name}"`,
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
await this.moveCardUseCase.execute(cardId, targetList.id);
|
|
270
|
+
console.log('✅ Cartão movido com sucesso!');
|
|
271
|
+
console.log(`📝 Cartão: ${card.name}`);
|
|
272
|
+
console.log(`➡️ Para: ${targetList.name}`);
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
} catch {
|
|
276
|
+
// Ignorar erros ao buscar cards, continuar procurando
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
throw new Error(`Cartão com ID "${cardId}" não encontrado`);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async deleteCard(cardId: string, card?: CardEntity): Promise<void> {
|
|
286
|
+
// Se não passou o card, tentar encontrar
|
|
287
|
+
if (!card) {
|
|
288
|
+
const boards = await (this.boardController as any).getBoards();
|
|
289
|
+
|
|
290
|
+
for (const board of boards) {
|
|
291
|
+
const lists = await (this.boardController as any).getLists(board.id);
|
|
292
|
+
|
|
293
|
+
for (const list of lists) {
|
|
294
|
+
try {
|
|
295
|
+
const cards = await (this.boardController as any).getCards(list.id);
|
|
296
|
+
card = cards.find((c: any) => c.id === cardId);
|
|
297
|
+
|
|
298
|
+
if (card) {
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
} catch {
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (card) {
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (!card) {
|
|
311
|
+
throw new Error(`Cartão com ID "${cardId}" não encontrado`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
await this.deleteCardUseCase.execute(cardId);
|
|
316
|
+
console.log('✅ Cartão deletado com sucesso!');
|
|
317
|
+
console.log(`📝 Nome: ${card.name}`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
@@ -1,18 +1,41 @@
|
|
|
1
|
+
import { AuthenticationService } from '@domain/services';
|
|
2
|
+
import {
|
|
3
|
+
FileConfigRepository,
|
|
4
|
+
TrelloApiRepository,
|
|
5
|
+
} from '@infrastructure/repositories';
|
|
1
6
|
import { Command } from 'commander';
|
|
2
|
-
import {
|
|
3
|
-
import { TrelloCliController } from './TrelloCliController';
|
|
7
|
+
import { AuthController, BoardController, CardController } from './index';
|
|
4
8
|
|
|
5
9
|
export class CommandController {
|
|
6
|
-
private
|
|
10
|
+
private authController: AuthController;
|
|
11
|
+
private boardController!: BoardController;
|
|
12
|
+
private cardController!: CardController;
|
|
7
13
|
private program: Command;
|
|
8
14
|
|
|
9
15
|
constructor() {
|
|
10
16
|
const configRepository = new FileConfigRepository();
|
|
11
|
-
this.
|
|
17
|
+
this.authController = new AuthController(configRepository);
|
|
12
18
|
this.program = new Command();
|
|
13
19
|
this.setupCommands();
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
private async initializeTrelloControllers(): Promise<void> {
|
|
23
|
+
await this.authController.ensureAuthenticated();
|
|
24
|
+
|
|
25
|
+
const authService = new AuthenticationService(new FileConfigRepository());
|
|
26
|
+
const config = await authService.getConfig();
|
|
27
|
+
const trelloRepository = new TrelloApiRepository(
|
|
28
|
+
config.apiKey,
|
|
29
|
+
config.token!,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
this.boardController = new BoardController(trelloRepository);
|
|
33
|
+
this.cardController = new CardController(
|
|
34
|
+
trelloRepository,
|
|
35
|
+
this.boardController,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
|
|
16
39
|
private setupCommands(): void {
|
|
17
40
|
this.program
|
|
18
41
|
.name('trello-cli-unofficial')
|
|
@@ -24,7 +47,11 @@ export class CommandController {
|
|
|
24
47
|
.alias('i')
|
|
25
48
|
.description('Start interactive mode')
|
|
26
49
|
.action(async () => {
|
|
27
|
-
|
|
50
|
+
const configRepository = new FileConfigRepository();
|
|
51
|
+
const cli = new (
|
|
52
|
+
await import('./TrelloCliController')
|
|
53
|
+
).TrelloCliController(configRepository);
|
|
54
|
+
await cli.run();
|
|
28
55
|
});
|
|
29
56
|
|
|
30
57
|
this.program
|
|
@@ -32,9 +59,8 @@ export class CommandController {
|
|
|
32
59
|
.description('List all your Trello boards')
|
|
33
60
|
.action(async () => {
|
|
34
61
|
try {
|
|
35
|
-
await this.
|
|
36
|
-
await this.
|
|
37
|
-
await this.cli.showBoards();
|
|
62
|
+
await this.initializeTrelloControllers();
|
|
63
|
+
await this.boardController.showBoards();
|
|
38
64
|
} catch (error) {
|
|
39
65
|
console.error('❌ Erro:', (error as Error).message);
|
|
40
66
|
}
|
|
@@ -44,14 +70,91 @@ export class CommandController {
|
|
|
44
70
|
.command('setup')
|
|
45
71
|
.description('Setup your Trello token')
|
|
46
72
|
.action(async () => {
|
|
47
|
-
await this.
|
|
73
|
+
await this.authController.setupToken();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
this.program
|
|
77
|
+
.command('lists <boardName>')
|
|
78
|
+
.description('List all lists in a specific board')
|
|
79
|
+
.action(async (boardName: string) => {
|
|
80
|
+
try {
|
|
81
|
+
await this.initializeTrelloControllers();
|
|
82
|
+
await this.boardController.showLists(boardName);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
this.program
|
|
89
|
+
.command('cards <boardName> <listName>')
|
|
90
|
+
.description('List all cards in a specific list')
|
|
91
|
+
.action(async (boardName: string, listName: string) => {
|
|
92
|
+
try {
|
|
93
|
+
await this.initializeTrelloControllers();
|
|
94
|
+
await this.boardController.showCards(boardName, listName);
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
this.program
|
|
101
|
+
.command('create-card <boardName> <listName> <cardName>')
|
|
102
|
+
.description('Create a new card in a specific board and list')
|
|
103
|
+
.option('-d, --desc <description>', 'Card description')
|
|
104
|
+
.action(
|
|
105
|
+
async (
|
|
106
|
+
boardName: string,
|
|
107
|
+
listName: string,
|
|
108
|
+
cardName: string,
|
|
109
|
+
options: { desc?: string },
|
|
110
|
+
) => {
|
|
111
|
+
try {
|
|
112
|
+
await this.initializeTrelloControllers();
|
|
113
|
+
await this.cardController.createCard(
|
|
114
|
+
boardName,
|
|
115
|
+
listName,
|
|
116
|
+
cardName,
|
|
117
|
+
options.desc,
|
|
118
|
+
);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
this.program
|
|
126
|
+
.command('move-card <cardId> <listName>')
|
|
127
|
+
.description('Move a card to a different list')
|
|
128
|
+
.action(async (cardId: string, listName: string) => {
|
|
129
|
+
try {
|
|
130
|
+
await this.initializeTrelloControllers();
|
|
131
|
+
await this.cardController.moveCard(cardId, listName);
|
|
132
|
+
} catch (error) {
|
|
133
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
this.program
|
|
138
|
+
.command('delete-card <cardId>')
|
|
139
|
+
.description('Delete a card by its ID')
|
|
140
|
+
.action(async (cardId: string) => {
|
|
141
|
+
try {
|
|
142
|
+
await this.initializeTrelloControllers();
|
|
143
|
+
await this.cardController.deleteCard(cardId);
|
|
144
|
+
} catch (error) {
|
|
145
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
146
|
+
}
|
|
48
147
|
});
|
|
49
148
|
}
|
|
50
149
|
|
|
51
150
|
async run(): Promise<void> {
|
|
52
151
|
// Fallback to interactive mode if no command specified
|
|
53
152
|
if (process.argv.length === 2) {
|
|
54
|
-
|
|
153
|
+
const configRepository = new FileConfigRepository();
|
|
154
|
+
const cli = new (
|
|
155
|
+
await import('./TrelloCliController')
|
|
156
|
+
).TrelloCliController(configRepository);
|
|
157
|
+
await cli.run();
|
|
55
158
|
} else {
|
|
56
159
|
this.program.parse();
|
|
57
160
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CONFIG_ACTIONS } from '@shared/types';
|
|
2
|
+
import inquirer from 'inquirer';
|
|
3
|
+
|
|
4
|
+
export class ConfigController {
|
|
5
|
+
constructor(private authController: { getConfig: () => Promise<unknown>; setupToken: () => Promise<void> }) {}
|
|
6
|
+
|
|
7
|
+
async showConfigMenu(): Promise<void> {
|
|
8
|
+
while (true) {
|
|
9
|
+
const { configAction } = await inquirer.prompt([
|
|
10
|
+
{
|
|
11
|
+
type: 'list',
|
|
12
|
+
name: 'configAction',
|
|
13
|
+
message: '⚙️ Configurações',
|
|
14
|
+
choices: [
|
|
15
|
+
{ name: '🔑 Configurar token', value: CONFIG_ACTIONS.TOKEN },
|
|
16
|
+
{ name: '👀 Ver configuração atual', value: CONFIG_ACTIONS.VIEW },
|
|
17
|
+
{ name: '🔄 Resetar configuração', value: CONFIG_ACTIONS.RESET },
|
|
18
|
+
{ name: '⬅️ Voltar', value: CONFIG_ACTIONS.BACK },
|
|
19
|
+
],
|
|
20
|
+
},
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
switch (configAction) {
|
|
24
|
+
case CONFIG_ACTIONS.TOKEN:
|
|
25
|
+
await this.authController.setupToken();
|
|
26
|
+
break;
|
|
27
|
+
case CONFIG_ACTIONS.VIEW:
|
|
28
|
+
const config = await this.authController.getConfig() as any;
|
|
29
|
+
console.log('📋 Configuração atual:');
|
|
30
|
+
console.log(`API Key: ${config.apiKey}`);
|
|
31
|
+
console.log(
|
|
32
|
+
`Token configurado: ${config.hasValidToken() ? '✅ Sim' : '❌ Não'}`,
|
|
33
|
+
);
|
|
34
|
+
console.log(
|
|
35
|
+
`Arquivo de config: ~/.trello-cli-unofficial/config.json`,
|
|
36
|
+
);
|
|
37
|
+
break;
|
|
38
|
+
case CONFIG_ACTIONS.RESET:
|
|
39
|
+
const { confirm } = await inquirer.prompt([
|
|
40
|
+
{
|
|
41
|
+
type: 'confirm',
|
|
42
|
+
name: 'confirm',
|
|
43
|
+
message: 'Tem certeza que deseja resetar toda a configuração?',
|
|
44
|
+
default: false,
|
|
45
|
+
},
|
|
46
|
+
]);
|
|
47
|
+
if (confirm) {
|
|
48
|
+
// Reset logic would need to be implemented in the use case
|
|
49
|
+
console.log('✅ Configuração resetada!');
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case CONFIG_ACTIONS.BACK:
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { ListEntity } from '@domain/entities';
|
|
2
|
+
import { MENU_ACTIONS } from '@shared/types';
|
|
3
|
+
import inquirer from 'inquirer';
|
|
4
|
+
|
|
5
|
+
export class MainMenuController {
|
|
6
|
+
constructor(
|
|
7
|
+
private boardController: { showBoards: () => Promise<void> },
|
|
8
|
+
private cardController: {
|
|
9
|
+
createCardInteractive: () => Promise<void>;
|
|
10
|
+
exploreCards: (boardId: string, lists: ListEntity[]) => Promise<void>;
|
|
11
|
+
},
|
|
12
|
+
private configController: { showConfigMenu: () => Promise<void> },
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async showMenu(): Promise<void> {
|
|
16
|
+
while (true) {
|
|
17
|
+
const { action } = await inquirer.prompt([
|
|
18
|
+
{
|
|
19
|
+
type: 'list',
|
|
20
|
+
name: 'action',
|
|
21
|
+
message: '🏠 Menu Principal - Trello CLI Unofficial',
|
|
22
|
+
choices: [
|
|
23
|
+
{ name: '📋 Ver meus quadros', value: MENU_ACTIONS.BOARDS },
|
|
24
|
+
{ name: '📝 Explorar quadro', value: MENU_ACTIONS.EXPLORE },
|
|
25
|
+
{ name: '➕ Criar cartão', value: MENU_ACTIONS.CREATE },
|
|
26
|
+
{ name: '⚙️ Configurações', value: MENU_ACTIONS.CONFIG },
|
|
27
|
+
{ name: '🚪 Sair', value: MENU_ACTIONS.EXIT },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
switch (action) {
|
|
34
|
+
case MENU_ACTIONS.BOARDS:
|
|
35
|
+
await this.boardController.showBoards();
|
|
36
|
+
break;
|
|
37
|
+
case MENU_ACTIONS.EXPLORE:
|
|
38
|
+
await this.exploreBoard();
|
|
39
|
+
break;
|
|
40
|
+
case MENU_ACTIONS.CREATE:
|
|
41
|
+
await this.cardController.createCardInteractive();
|
|
42
|
+
break;
|
|
43
|
+
case MENU_ACTIONS.CONFIG:
|
|
44
|
+
await this.configController.showConfigMenu();
|
|
45
|
+
break;
|
|
46
|
+
case MENU_ACTIONS.EXIT:
|
|
47
|
+
console.log('👋 Até logo!');
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
} catch (error) {
|
|
51
|
+
console.error('❌ Erro:', (error as Error).message);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
console.log(`\n${'='.repeat(50)}\n`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private async exploreBoard(): Promise<void> {
|
|
59
|
+
// This will be implemented when we refactor the main controller
|
|
60
|
+
console.log('🚧 Explorar quadro - Em desenvolvimento');
|
|
61
|
+
}
|
|
62
|
+
}
|