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.
@@ -1,408 +1,53 @@
1
- import type {
2
- ConfigRepository,
3
- TrelloRepository,
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
- AuthenticateUserUseCase,
8
- CreateCardUseCase,
9
- DeleteCardUseCase,
10
- GetBoardsUseCase,
11
- GetCardsUseCase,
12
- GetListsUseCase,
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 authenticateUseCase: AuthenticateUserUseCase;
21
- private getBoardsUseCase?: GetBoardsUseCase;
22
- private getListsUseCase?: GetListsUseCase;
23
- private getCardsUseCase?: GetCardsUseCase;
24
- private createCardUseCase?: CreateCardUseCase;
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.authenticateUseCase = new AuthenticateUserUseCase(configRepository);
20
+ this.initializeControllers();
31
21
  }
32
22
 
33
- async initializeTrelloUseCases(): Promise<void> {
34
- const config = await this.authenticateUseCase.getConfig();
23
+ private async initializeControllers(): Promise<void> {
24
+ this.authController = new AuthController(this.configRepository);
35
25
 
36
- if (!config.hasValidToken()) {
37
- throw new Error('Token não configurado');
38
- }
26
+ // Ensure we have a valid token before creating TrelloRepository
27
+ await this.authController.ensureAuthenticated();
39
28
 
40
- const trelloRepository: TrelloRepository = new TrelloApiRepository(
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.getBoardsUseCase = new GetBoardsUseCase(trelloRepository);
46
- this.getListsUseCase = new GetListsUseCase(trelloRepository);
47
- this.getCardsUseCase = new GetCardsUseCase(trelloRepository);
48
- this.createCardUseCase = new CreateCardUseCase(trelloRepository);
49
- this.updateCardUseCase = new UpdateCardUseCase(trelloRepository);
50
- this.deleteCardUseCase = new DeleteCardUseCase(trelloRepository);
51
- this.moveCardUseCase = new MoveCardUseCase(trelloRepository);
52
- }
53
-
54
- async ensureAuthenticated(): Promise<void> {
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
- private async showConfigMenu(): Promise<void> {
358
- while (true) {
359
- const { configAction } = await inquirer.prompt([
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
  }
@@ -1,2 +1,7 @@
1
+ export * from './AuthController';
2
+ export * from './BoardController';
3
+ export * from './CardController';
1
4
  export * from './CommandController';
5
+ export * from './ConfigController';
6
+ export * from './MainMenuController';
2
7
  export * from './TrelloCliController';
@@ -0,0 +1,3 @@
1
+ # Test comment to trigger CI
2
+ # Another test comment
3
+ test
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