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
|
@@ -1,408 +1,53 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from '../../domain/repositories';
|
|
5
|
-
import inquirer from 'inquirer';
|
|
1
|
+
import type { ConfigRepository } from '@domain/repositories';
|
|
2
|
+
import { AuthenticationService } from '@domain/services';
|
|
3
|
+
import { TrelloApiRepository } from '@infrastructure/repositories';
|
|
6
4
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
MoveCardUseCase,
|
|
14
|
-
UpdateCardUseCase,
|
|
15
|
-
} from '../../application';
|
|
16
|
-
import { TrelloApiRepository } from '../../infrastructure/repositories';
|
|
17
|
-
import { CARD_ACTIONS, CONFIG_ACTIONS, MENU_ACTIONS } from '../../shared';
|
|
5
|
+
AuthController,
|
|
6
|
+
BoardController,
|
|
7
|
+
CardController,
|
|
8
|
+
ConfigController,
|
|
9
|
+
MainMenuController,
|
|
10
|
+
} from './index';
|
|
18
11
|
|
|
19
12
|
export class TrelloCliController {
|
|
20
|
-
private
|
|
21
|
-
private
|
|
22
|
-
private
|
|
23
|
-
private
|
|
24
|
-
private
|
|
25
|
-
private updateCardUseCase?: UpdateCardUseCase;
|
|
26
|
-
private deleteCardUseCase?: DeleteCardUseCase;
|
|
27
|
-
private moveCardUseCase?: MoveCardUseCase;
|
|
13
|
+
private authController!: AuthController;
|
|
14
|
+
private boardController!: BoardController;
|
|
15
|
+
private cardController!: CardController;
|
|
16
|
+
private configController!: ConfigController;
|
|
17
|
+
private mainMenuController!: MainMenuController;
|
|
28
18
|
|
|
29
19
|
constructor(private configRepository: ConfigRepository) {
|
|
30
|
-
this.
|
|
20
|
+
this.initializeControllers();
|
|
31
21
|
}
|
|
32
22
|
|
|
33
|
-
async
|
|
34
|
-
|
|
23
|
+
private async initializeControllers(): Promise<void> {
|
|
24
|
+
this.authController = new AuthController(this.configRepository);
|
|
35
25
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
}
|
|
26
|
+
// Ensure we have a valid token before creating TrelloRepository
|
|
27
|
+
await this.authController.ensureAuthenticated();
|
|
39
28
|
|
|
40
|
-
const
|
|
29
|
+
const authService = new AuthenticationService(this.configRepository);
|
|
30
|
+
const config = await authService.getConfig();
|
|
31
|
+
const trelloRepository = new TrelloApiRepository(
|
|
41
32
|
config.apiKey,
|
|
42
33
|
config.token!,
|
|
43
34
|
);
|
|
44
35
|
|
|
45
|
-
this.
|
|
46
|
-
this.
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
this.
|
|
51
|
-
this.
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const result = await this.authenticateUseCase.execute();
|
|
56
|
-
if (!result.success) {
|
|
57
|
-
console.log(result.message);
|
|
58
|
-
await this.setupToken();
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
async setupToken(): Promise<void> {
|
|
63
|
-
const { token } = await inquirer.prompt([
|
|
64
|
-
{
|
|
65
|
-
type: 'input',
|
|
66
|
-
name: 'token',
|
|
67
|
-
message: 'Digite seu token do Trello (ATTA...):',
|
|
68
|
-
validate: input =>
|
|
69
|
-
input.startsWith('ATTA') || 'Token deve começar com ATTA',
|
|
70
|
-
},
|
|
71
|
-
]);
|
|
72
|
-
|
|
73
|
-
const result = await this.authenticateUseCase.execute(token);
|
|
74
|
-
console.log(result.message);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
async showMenu(): Promise<void> {
|
|
78
|
-
await this.ensureAuthenticated();
|
|
79
|
-
await this.initializeTrelloUseCases();
|
|
80
|
-
|
|
81
|
-
while (true) {
|
|
82
|
-
const { action } = await inquirer.prompt([
|
|
83
|
-
{
|
|
84
|
-
type: 'list',
|
|
85
|
-
name: 'action',
|
|
86
|
-
message: '🏠 Menu Principal - Trello CLI Unofficial',
|
|
87
|
-
choices: [
|
|
88
|
-
{ name: '📋 Ver meus quadros', value: MENU_ACTIONS.BOARDS },
|
|
89
|
-
{ name: '📝 Explorar quadro', value: MENU_ACTIONS.EXPLORE },
|
|
90
|
-
{ name: '➕ Criar cartão', value: MENU_ACTIONS.CREATE },
|
|
91
|
-
{ name: '⚙️ Configurações', value: MENU_ACTIONS.CONFIG },
|
|
92
|
-
{ name: '🚪 Sair', value: MENU_ACTIONS.EXIT },
|
|
93
|
-
],
|
|
94
|
-
},
|
|
95
|
-
]);
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
switch (action) {
|
|
99
|
-
case MENU_ACTIONS.BOARDS:
|
|
100
|
-
await this.showBoards();
|
|
101
|
-
break;
|
|
102
|
-
case MENU_ACTIONS.EXPLORE:
|
|
103
|
-
await this.exploreBoard();
|
|
104
|
-
break;
|
|
105
|
-
case MENU_ACTIONS.CREATE:
|
|
106
|
-
await this.createCardInteractive();
|
|
107
|
-
break;
|
|
108
|
-
case MENU_ACTIONS.CONFIG:
|
|
109
|
-
await this.showConfigMenu();
|
|
110
|
-
break;
|
|
111
|
-
case MENU_ACTIONS.EXIT:
|
|
112
|
-
console.log('👋 Até logo!');
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
115
|
-
} catch (error) {
|
|
116
|
-
console.error('❌ Erro:', (error as Error).message);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
console.log(`\n${'='.repeat(50)}\n`);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
async showBoards(): Promise<void> {
|
|
124
|
-
if (!this.getBoardsUseCase) {
|
|
125
|
-
throw new Error('Use cases não inicializados');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const boards = await this.getBoardsUseCase.execute();
|
|
129
|
-
|
|
130
|
-
console.log('📋 Seus Quadros do Trello:');
|
|
131
|
-
boards.forEach((board, index) => {
|
|
132
|
-
console.log(`${index + 1}. ${board.name}`);
|
|
133
|
-
console.log(` 🔗 ${board.url}`);
|
|
134
|
-
console.log(` 🆔 ${board.id}\n`);
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private async exploreBoard(): Promise<void> {
|
|
139
|
-
if (
|
|
140
|
-
!this.getBoardsUseCase
|
|
141
|
-
|| !this.getListsUseCase
|
|
142
|
-
|| !this.getCardsUseCase
|
|
143
|
-
) {
|
|
144
|
-
throw new Error('Use cases não inicializados');
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const boards = await this.getBoardsUseCase.execute();
|
|
148
|
-
|
|
149
|
-
const { selectedBoard } = await inquirer.prompt([
|
|
150
|
-
{
|
|
151
|
-
type: 'list',
|
|
152
|
-
name: 'selectedBoard',
|
|
153
|
-
message: 'Selecione um quadro:',
|
|
154
|
-
choices: boards.map(board => ({ name: board.name, value: board.id })),
|
|
155
|
-
},
|
|
156
|
-
]);
|
|
157
|
-
|
|
158
|
-
const lists = await this.getListsUseCase.execute(selectedBoard);
|
|
159
|
-
|
|
160
|
-
const { selectedList } = await inquirer.prompt([
|
|
161
|
-
{
|
|
162
|
-
type: 'list',
|
|
163
|
-
name: 'selectedList',
|
|
164
|
-
message: 'Selecione uma lista:',
|
|
165
|
-
choices: lists.map(list => ({ name: list.name, value: list.id })),
|
|
166
|
-
},
|
|
167
|
-
]);
|
|
168
|
-
|
|
169
|
-
const cards = await this.getCardsUseCase.execute(selectedList);
|
|
170
|
-
|
|
171
|
-
if (cards.length === 0) {
|
|
172
|
-
console.log('📭 Esta lista está vazia.');
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
console.log(
|
|
177
|
-
`🃏 Cartões em "${lists.find(l => l.id === selectedList)?.name}":`,
|
|
36
|
+
this.boardController = new BoardController(trelloRepository);
|
|
37
|
+
this.cardController = new CardController(
|
|
38
|
+
trelloRepository,
|
|
39
|
+
this.boardController,
|
|
40
|
+
);
|
|
41
|
+
this.configController = new ConfigController(this.authController);
|
|
42
|
+
this.mainMenuController = new MainMenuController(
|
|
43
|
+
this.boardController,
|
|
44
|
+
this.cardController,
|
|
45
|
+
this.configController,
|
|
178
46
|
);
|
|
179
|
-
cards.forEach((card, index) => {
|
|
180
|
-
console.log(`${index + 1}. ${card.name}`);
|
|
181
|
-
if (card.desc) {
|
|
182
|
-
const desc
|
|
183
|
-
= card.desc.length > 100
|
|
184
|
-
? `${card.desc.substring(0, 100)}...`
|
|
185
|
-
: card.desc;
|
|
186
|
-
console.log(` 📝 ${desc}`);
|
|
187
|
-
}
|
|
188
|
-
console.log(` 🔗 ${card.url}\n`);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// Opções adicionais
|
|
192
|
-
const { nextAction } = await inquirer.prompt([
|
|
193
|
-
{
|
|
194
|
-
type: 'list',
|
|
195
|
-
name: 'nextAction',
|
|
196
|
-
message: 'O que deseja fazer?',
|
|
197
|
-
choices: [
|
|
198
|
-
{ name: '⬅️ Voltar ao menu', value: CARD_ACTIONS.BACK },
|
|
199
|
-
{ name: '📝 Editar cartão', value: CARD_ACTIONS.EDIT },
|
|
200
|
-
{ name: '🗑️ Deletar cartão', value: CARD_ACTIONS.DELETE },
|
|
201
|
-
{ name: '📦 Mover cartão', value: CARD_ACTIONS.MOVE },
|
|
202
|
-
],
|
|
203
|
-
},
|
|
204
|
-
]);
|
|
205
|
-
|
|
206
|
-
if (nextAction !== CARD_ACTIONS.BACK) {
|
|
207
|
-
const { selectedCard } = await inquirer.prompt([
|
|
208
|
-
{
|
|
209
|
-
type: 'list',
|
|
210
|
-
name: 'selectedCard',
|
|
211
|
-
message: 'Selecione um cartão:',
|
|
212
|
-
choices: cards.map(card => ({ name: card.name, value: card.id })),
|
|
213
|
-
},
|
|
214
|
-
]);
|
|
215
|
-
|
|
216
|
-
const selectedCardEntity = cards.find(c => c.id === selectedCard)!;
|
|
217
|
-
|
|
218
|
-
switch (nextAction) {
|
|
219
|
-
case CARD_ACTIONS.EDIT:
|
|
220
|
-
await this.editCard(selectedCard, selectedCardEntity);
|
|
221
|
-
break;
|
|
222
|
-
case CARD_ACTIONS.DELETE:
|
|
223
|
-
await this.deleteCard(selectedCard, selectedCardEntity);
|
|
224
|
-
break;
|
|
225
|
-
case CARD_ACTIONS.MOVE:
|
|
226
|
-
await this.moveCard(selectedCard, selectedBoard, lists);
|
|
227
|
-
break;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
private async createCardInteractive(): Promise<void> {
|
|
233
|
-
if (
|
|
234
|
-
!this.getBoardsUseCase
|
|
235
|
-
|| !this.getListsUseCase
|
|
236
|
-
|| !this.createCardUseCase
|
|
237
|
-
) {
|
|
238
|
-
throw new Error('Use cases não inicializados');
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
const boards = await this.getBoardsUseCase.execute();
|
|
242
|
-
|
|
243
|
-
const { selectedBoard } = await inquirer.prompt([
|
|
244
|
-
{
|
|
245
|
-
type: 'list',
|
|
246
|
-
name: 'selectedBoard',
|
|
247
|
-
message: 'Selecione o quadro:',
|
|
248
|
-
choices: boards.map(board => ({ name: board.name, value: board.id })),
|
|
249
|
-
},
|
|
250
|
-
]);
|
|
251
|
-
|
|
252
|
-
const lists = await this.getListsUseCase.execute(selectedBoard);
|
|
253
|
-
|
|
254
|
-
const { selectedList } = await inquirer.prompt([
|
|
255
|
-
{
|
|
256
|
-
type: 'list',
|
|
257
|
-
name: 'selectedList',
|
|
258
|
-
message: 'Selecione a lista:',
|
|
259
|
-
choices: lists.map(list => ({ name: list.name, value: list.id })),
|
|
260
|
-
},
|
|
261
|
-
]);
|
|
262
|
-
|
|
263
|
-
const { cardName, cardDesc } = await inquirer.prompt([
|
|
264
|
-
{
|
|
265
|
-
type: 'input',
|
|
266
|
-
name: 'cardName',
|
|
267
|
-
message: 'Nome do cartão:',
|
|
268
|
-
validate: input => input.length > 0 || 'Nome é obrigatório',
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
type: 'input',
|
|
272
|
-
name: 'cardDesc',
|
|
273
|
-
message: 'Descrição (opcional):',
|
|
274
|
-
},
|
|
275
|
-
]);
|
|
276
|
-
|
|
277
|
-
const newCard = await this.createCardUseCase.execute({
|
|
278
|
-
name: cardName,
|
|
279
|
-
desc: cardDesc,
|
|
280
|
-
listId: selectedList,
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
console.log('✅ Cartão criado com sucesso!');
|
|
284
|
-
console.log(`📝 Nome: ${newCard.name}`);
|
|
285
|
-
console.log(`🔗 URL: ${newCard.url}`);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
private async editCard(cardId: string, card: any): Promise<void> {
|
|
289
|
-
if (!this.updateCardUseCase) {
|
|
290
|
-
throw new Error('Use cases não inicializados');
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const { newName, newDesc } = await inquirer.prompt([
|
|
294
|
-
{
|
|
295
|
-
type: 'input',
|
|
296
|
-
name: 'newName',
|
|
297
|
-
message: 'Novo nome:',
|
|
298
|
-
default: card.name,
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
type: 'input',
|
|
302
|
-
name: 'newDesc',
|
|
303
|
-
message: 'Nova descrição:',
|
|
304
|
-
default: card.desc || '',
|
|
305
|
-
},
|
|
306
|
-
]);
|
|
307
|
-
|
|
308
|
-
await this.updateCardUseCase.execute(cardId, {
|
|
309
|
-
name: newName,
|
|
310
|
-
desc: newDesc,
|
|
311
|
-
});
|
|
312
|
-
console.log('✅ Cartão atualizado com sucesso!');
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
private async deleteCard(cardId: string, card: any): Promise<void> {
|
|
316
|
-
if (!this.deleteCardUseCase) {
|
|
317
|
-
throw new Error('Use cases não inicializados');
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
const { confirm } = await inquirer.prompt([
|
|
321
|
-
{
|
|
322
|
-
type: 'confirm',
|
|
323
|
-
name: 'confirm',
|
|
324
|
-
message: `Tem certeza que deseja deletar "${card.name}"?`,
|
|
325
|
-
default: false,
|
|
326
|
-
},
|
|
327
|
-
]);
|
|
328
|
-
|
|
329
|
-
if (confirm) {
|
|
330
|
-
await this.deleteCardUseCase.execute(cardId);
|
|
331
|
-
console.log('✅ Cartão deletado com sucesso!');
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
private async moveCard(
|
|
336
|
-
cardId: string,
|
|
337
|
-
currentBoardId: string,
|
|
338
|
-
lists: any[],
|
|
339
|
-
): Promise<void> {
|
|
340
|
-
if (!this.moveCardUseCase) {
|
|
341
|
-
throw new Error('Use cases não inicializados');
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
const { targetList } = await inquirer.prompt([
|
|
345
|
-
{
|
|
346
|
-
type: 'list',
|
|
347
|
-
name: 'targetList',
|
|
348
|
-
message: 'Mover para qual lista?',
|
|
349
|
-
choices: lists.map(list => ({ name: list.name, value: list.id })),
|
|
350
|
-
},
|
|
351
|
-
]);
|
|
352
|
-
|
|
353
|
-
await this.moveCardUseCase.execute(cardId, targetList);
|
|
354
|
-
console.log('✅ Cartão movido com sucesso!');
|
|
355
47
|
}
|
|
356
48
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
{
|
|
361
|
-
type: 'list',
|
|
362
|
-
name: 'configAction',
|
|
363
|
-
message: '⚙️ Configurações',
|
|
364
|
-
choices: [
|
|
365
|
-
{ name: '🔑 Configurar token', value: CONFIG_ACTIONS.TOKEN },
|
|
366
|
-
{ name: '👀 Ver configuração atual', value: CONFIG_ACTIONS.VIEW },
|
|
367
|
-
{ name: '🔄 Resetar configuração', value: CONFIG_ACTIONS.RESET },
|
|
368
|
-
{ name: '⬅️ Voltar', value: CONFIG_ACTIONS.BACK },
|
|
369
|
-
],
|
|
370
|
-
},
|
|
371
|
-
]);
|
|
372
|
-
|
|
373
|
-
switch (configAction) {
|
|
374
|
-
case CONFIG_ACTIONS.TOKEN:
|
|
375
|
-
await this.setupToken();
|
|
376
|
-
await this.initializeTrelloUseCases(); // Re-initialize with new token
|
|
377
|
-
break;
|
|
378
|
-
case CONFIG_ACTIONS.VIEW:
|
|
379
|
-
const config = await this.authenticateUseCase.getConfig();
|
|
380
|
-
console.log('📋 Configuração atual:');
|
|
381
|
-
console.log(`API Key: ${config.apiKey}`);
|
|
382
|
-
console.log(
|
|
383
|
-
`Token configurado: ${config.hasValidToken() ? '✅ Sim' : '❌ Não'}`,
|
|
384
|
-
);
|
|
385
|
-
console.log(
|
|
386
|
-
`Arquivo de config: ~/.trello-cli-unofficial/config.json`,
|
|
387
|
-
);
|
|
388
|
-
break;
|
|
389
|
-
case CONFIG_ACTIONS.RESET:
|
|
390
|
-
const { confirm } = await inquirer.prompt([
|
|
391
|
-
{
|
|
392
|
-
type: 'confirm',
|
|
393
|
-
name: 'confirm',
|
|
394
|
-
message: 'Tem certeza que deseja resetar toda a configuração?',
|
|
395
|
-
default: false,
|
|
396
|
-
},
|
|
397
|
-
]);
|
|
398
|
-
if (confirm) {
|
|
399
|
-
// Reset logic would need to be implemented in the use case
|
|
400
|
-
console.log('✅ Configuração resetada!');
|
|
401
|
-
}
|
|
402
|
-
break;
|
|
403
|
-
case CONFIG_ACTIONS.BACK:
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
}
|
|
49
|
+
async run(): Promise<void> {
|
|
50
|
+
await this.initializeControllers();
|
|
51
|
+
await this.mainMenuController.showMenu();
|
|
407
52
|
}
|
|
408
53
|
}
|
package/test_trigger.txt
ADDED
package/.eslintignore
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
# Dependencies
|
|
2
|
-
node_modules/
|
|
3
|
-
bun.lock
|
|
4
|
-
|
|
5
|
-
# Build outputs
|
|
6
|
-
dist/
|
|
7
|
-
*.tsbuildinfo
|
|
8
|
-
|
|
9
|
-
# Config files backup
|
|
10
|
-
*.backup
|
|
11
|
-
|
|
12
|
-
# Environment
|
|
13
|
-
.env
|
|
14
|
-
.env.*
|
|
15
|
-
|
|
16
|
-
# IDE
|
|
17
|
-
.vscode/
|
|
18
|
-
.idea/
|
|
19
|
-
|
|
20
|
-
# OS
|
|
21
|
-
.DS_Store
|
|
22
|
-
Thumbs.db
|
|
23
|
-
|
|
24
|
-
# Coverage
|
|
25
|
-
coverage/
|
|
26
|
-
*.lcov
|