diff --git a/.changeset/swift-bugs-appear.md b/.changeset/swift-bugs-appear.md
new file mode 100644
index 0000000..b4d8674
--- /dev/null
+++ b/.changeset/swift-bugs-appear.md
@@ -0,0 +1,6 @@
+---
+"@dandori/cli": patch
+"@dandori/ui": patch
+---
+
+Add trello
diff --git a/README.md b/README.md
index 04622b5..2d11c3f 100644
--- a/README.md
+++ b/README.md
@@ -38,6 +38,21 @@ Today's My Tasks
+## Example 3
+
+### Input
+
+```text
+Today's My Tasks
+* [todo] Send Email to John
+* [doing] Write a blog
+* [done] Report to Boss
+```
+
+### Output(Trello)
+
+
+
## Usage
This project is monorepo. You can choose the following ways to use it.
diff --git a/media/trello_example.png b/media/trello_example.png
new file mode 100644
index 0000000..dc50d7b
Binary files /dev/null and b/media/trello_example.png differ
diff --git a/packages/cli/README.md b/packages/cli/README.md
index ce9c6cd..86393bc 100644
--- a/packages/cli/README.md
+++ b/packages/cli/README.md
@@ -114,4 +114,31 @@ Options:
```bash
pnpm --package=@dandori/cli dlx dandori-miro your_tasks.txt -d your_database_id -o status --status 'Status' --status-todo 'ToDo' --status-doing 'Doing' --status-done 'Done 🙌'
+```
+
+### dandori-trello
+
+This command is to execute `generateDandoriTrelloCards` of `@dandori/ui`.
+
+```bash
+% pnpm --package=@dandori/cli dlx dandori-trello -h
+
+Usage: @dandori/cli [options]
+
+Options:
+ -V, --version output the version number
+ -e, --env-file env file path
+ -m, --model Chat GPT model which supports function_calling
+ -o, --optional-task-props optional output task props which delimiter is a comma
+ -b, --board-id trello board id
+ --status-todo trello list status todo name
+ --status-doing trello list status doing name
+ --status-done trello list status done name
+ -h, --help display help for command
+```
+
+#### Example of the command
+
+```bash
+pnpm --package=@dandori/cli dlx dandori-trello your_tasks.txt -d your_board_id -o status --status-todo 'Todo' --status-doing 'Doing' --status-done 'Done'
```
\ No newline at end of file
diff --git a/packages/cli/package.json b/packages/cli/package.json
index a4b9ab2..68462b4 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -34,13 +34,15 @@
"build": "tsup --config ../../tsup.config.ts",
"test": "vitest run",
"dev:core": "tsx src/core/cli.ts",
- "dev:miro": "tsx src/miro/cli.ts ./tmp/tmp.txt",
- "dev:notion": "tsx src/notion/cli.ts"
+ "dev:miro": "tsx src/miro/cli.ts",
+ "dev:notion": "tsx src/notion/cli.ts",
+ "dev:trello": "tsx src/trello/cli.ts -h"
},
"bin": {
"dandori-core": "./dist/core/cli.js",
"dandori-miro": "./dist/miro/cli.js",
- "dandori-notion": "./dist/notion/cli.js"
+ "dandori-notion": "./dist/notion/cli.js",
+ "dandori-trello": "./dist/trello/cli.js"
},
"keywords": [],
"author": "Hiroki Miyaji",
diff --git a/packages/cli/src/notion/__tests__/index.test.ts b/packages/cli/src/notion/__tests__/index.test.ts
index 59d02b8..40d23a0 100644
--- a/packages/cli/src/notion/__tests__/index.test.ts
+++ b/packages/cli/src/notion/__tests__/index.test.ts
@@ -11,7 +11,7 @@ import {
} from "vitest";
import { DandoriTask } from "@dandori/core";
import { generateDandoriNotionPages } from "@dandori/ui";
-import DandoriMiroCli from "../index";
+import DandoriNotionCli from "../index";
import { rm, writeFile } from "fs/promises";
const tasks: DandoriTask[] = [
@@ -60,7 +60,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["-d", databaseId]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with database id", () => {
@@ -75,7 +75,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--name", name]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.name", () => {
@@ -92,7 +92,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--deadline", deadline]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.deadline", () => {
@@ -109,7 +109,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--status", status]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.status", () => {
@@ -126,7 +126,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--status-todo", statusTodo]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.status.todo", () => {
@@ -143,7 +143,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--status-doing", statusDoing]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.status.doing", () => {
@@ -160,7 +160,7 @@ describe("DandoriNotionCli", () => {
beforeEach(async () => {
loadProcessArgv(["--status-done", statusDone]);
- await new DandoriMiroCli().run();
+ await new DandoriNotionCli().run();
});
it("call generateDandoriNotionPages with databasePropertiesMap.status.done", () => {
diff --git a/packages/cli/src/trello/__tests__/index.test.ts b/packages/cli/src/trello/__tests__/index.test.ts
new file mode 100644
index 0000000..64af7b9
--- /dev/null
+++ b/packages/cli/src/trello/__tests__/index.test.ts
@@ -0,0 +1,123 @@
+import {
+ describe,
+ beforeEach,
+ afterEach,
+ vi,
+ expect,
+ it,
+ beforeAll,
+ afterAll,
+ Mock,
+} from "vitest";
+import { DandoriTask } from "@dandori/core";
+import { generateDandoriTrelloCards } from "@dandori/ui";
+import DandoriTrelloCli from "../index";
+import { rm, writeFile } from "fs/promises";
+
+const tasks: DandoriTask[] = [
+ {
+ id: "1",
+ name: "task1",
+ deadline: "2021-01-01",
+ description: "task1-description",
+ fromTaskIdList: [],
+ status: "todo",
+ },
+];
+
+vi.mock("@dandori/core", () => ({
+ default: vi.fn(() => tasks),
+}));
+
+vi.mock("@dandori/ui", () => ({
+ generateDandoriTrelloCards: vi.fn(),
+}));
+
+const mockGenerateDandoriTrelloCards = generateDandoriTrelloCards as Mock;
+
+describe("DandoriTrelloCli", () => {
+ const inputFileName = "DandoriTrelloCli.txt";
+ const inputFileText = "DandoriTrelloCli";
+ const loadProcessArgv = (options: string[]) => {
+ process.argv = ["node", "cli.js", inputFileName, ...options];
+ };
+
+ beforeAll(async () => {
+ await writeFile(inputFileName, inputFileText);
+ });
+
+ afterAll(async () => {
+ await rm(inputFileName);
+ });
+
+ afterEach(() => {
+ process.argv = [];
+ vi.clearAllMocks();
+ });
+
+ describe("with -b option", () => {
+ const boardId = "boardId";
+
+ beforeEach(async () => {
+ loadProcessArgv(["-b", boardId]);
+ await new DandoriTrelloCli().run();
+ });
+
+ it("call generateDandoriTrelloCards with board id", () => {
+ expect(mockGenerateDandoriTrelloCards.mock.lastCall[1]).toMatchObject({
+ boardId,
+ });
+ });
+ });
+
+ describe("with --status-todo option", () => {
+ const statusTodo = "ToDo";
+
+ beforeEach(async () => {
+ loadProcessArgv(["--status-todo", statusTodo]);
+ await new DandoriTrelloCli().run();
+ });
+
+ it("call generateDandoriTrelloCards with trelloListPropertiesMap.status.todo", () => {
+ expect(
+ mockGenerateDandoriTrelloCards.mock.lastCall[1].trelloListPropertiesMap,
+ ).toMatchObject({
+ "status.todo": statusTodo,
+ });
+ });
+ });
+
+ describe("with --status-doing option", () => {
+ const statusDoing = "Doing";
+
+ beforeEach(async () => {
+ loadProcessArgv(["--status-doing", statusDoing]);
+ await new DandoriTrelloCli().run();
+ });
+
+ it("call generateDandoriTrelloCards with trelloListPropertiesMap.status.doing", () => {
+ expect(
+ mockGenerateDandoriTrelloCards.mock.lastCall[1].trelloListPropertiesMap,
+ ).toMatchObject({
+ "status.doing": statusDoing,
+ });
+ });
+ });
+
+ describe("with --status-done option", () => {
+ const statusDone = "Done";
+
+ beforeEach(async () => {
+ loadProcessArgv(["--status-done", statusDone]);
+ await new DandoriTrelloCli().run();
+ });
+
+ it("call generateDandoriTrelloCards with trelloListPropertiesMap.status.done", () => {
+ expect(
+ mockGenerateDandoriTrelloCards.mock.lastCall[1].trelloListPropertiesMap,
+ ).toMatchObject({
+ "status.done": statusDone,
+ });
+ });
+ });
+});
diff --git a/packages/cli/src/trello/cli.ts b/packages/cli/src/trello/cli.ts
new file mode 100644
index 0000000..e672ca6
--- /dev/null
+++ b/packages/cli/src/trello/cli.ts
@@ -0,0 +1,6 @@
+#!/usr/bin/env node
+
+import DandoriTrelloCli from "./index";
+
+const cli = new DandoriTrelloCli();
+void cli.run();
diff --git a/packages/cli/src/trello/index.ts b/packages/cli/src/trello/index.ts
new file mode 100644
index 0000000..f9c8b6c
--- /dev/null
+++ b/packages/cli/src/trello/index.ts
@@ -0,0 +1,26 @@
+import { generateDandoriTrelloCards } from "@dandori/ui";
+import DandoriCoreCli from "../core";
+
+export default class DandoriTrelloCli extends DandoriCoreCli {
+ override async run(): Promise {
+ const tasks = await this.generateDandoriTasks();
+ const opts = this.program.opts();
+ await generateDandoriTrelloCards(tasks, {
+ boardId: opts.boardId,
+ trelloListPropertiesMap: {
+ "status.todo": opts.statusTodo,
+ "status.doing": opts.statusDoing,
+ "status.done": opts.statusDone,
+ },
+ });
+ }
+
+ protected override buildCommand() {
+ return super
+ .buildCommand()
+ .option("-b, --board-id ", "trello board id")
+ .option("--status-todo ", "trello list status todo name")
+ .option("--status-doing ", "trello list status doing name")
+ .option("--status-done ", "trello list status done name");
+ }
+}
diff --git a/packages/ui/README.md b/packages/ui/README.md
index a45dc66..0a4e834 100644
--- a/packages/ui/README.md
+++ b/packages/ui/README.md
@@ -39,6 +39,7 @@ await generateDandoriMiroCards(tasks, {
* [Miro](https://miro.com/)
* [Notion](https://www.notion.so/)
+* [Trello](https://trello.com/)
## API
@@ -116,7 +117,7 @@ The tasks which are generated by `generateDandoriTasks` of `@dandori/core`.
interface GenerateDandoriNotionPagesOptions {
databaseId: string;
databasePropertiesMap?: DatabasePropertiesMap;
- apuKey?: string;
+ apiKey?: string;
}
```
@@ -181,4 +182,94 @@ For more details about database properties, please see [Notion API](https://deve
* apiKey
-The api key of miro. You can also set `NOTION_API_KEY` environment variable instead of this option.
\ No newline at end of file
+The api key of notion. You can also set `NOTION_API_KEY` environment variable instead of this option.
+
+### generateDandoriTrelloCards
+
+```ts
+async function generateDandoriTrelloCards(
+ tasks: DandoriTask[],
+ options?: GenerateDandoriTrelloCardsOptions,
+): Promise {}
+```
+
+`generateDandoriTrelloCards` creates trello cards from `generateDandoriTasks` result.
+
+
+
+#### Parameters
+
+##### tasks
+
+The tasks which are generated by `generateDandoriTasks` of `@dandori/core`.
+
+##### options
+
+```ts
+interface GenerateDandoriTrelloCardsOptions {
+ boardId: string;
+ trelloListPropertiesMap?: TrelloListPropertiesMap;
+ apiKey?: string;
+ apiToken?: string;
+}
+```
+
+* boardId
+
+The existing board id of trello.
+
+You can get the board id from your trello url.
+
+For example, if the url is `https://trello.com/b/ABCDE/boardTitle`, the board id is `ABCDE`.
+
+* trelloListPropertiesMap
+
+The map which key is defined by dandori and value is your trello list properties.
+
+You can set the key like belows.
+
+```ts
+const trelloListPropertiesMap = {
+ "status.todo": "",
+ "status.doing": "",
+ "status.done": "",
+};
+```
+
+```ts
+import generateDandoriTasks from '@dandori/core';
+import { generateDandoriTrelloCards } from "@dandori/ui";
+
+const text = `
+Today's My Tasks
+* Send Email to John
+* Send Email to Mary
+* Report to Boss after sending emails
+`;
+
+const trelloListPropertiesMap = {
+ "status.todo": "Todo",
+ "status.doing": "Doing",
+ "status.done": "Done",
+};
+
+const tasks = await generateDandoriTasks(text);
+await generateDandoriNotionPages(tasks, {
+ boardId: 'ABCDE',
+ trelloListPropertiesMap,
+});
+```
+
+This is an example. In this case, the output is like belows.
+
+
+
+For more details about database properties, please see [Notion API](https://developers.notion.com/reference/page#page-property-value).
+
+* apiKey
+
+The api key of trello. You can also set `TRELLO_API_KEY` environment variable instead of this option.
+
+* apiToken
+
+The api token of trello which you can get through OAuth. You can also set `TRELLO_API_TOKEN` environment variable instead of this option.
\ No newline at end of file
diff --git a/packages/ui/src/trello/client.ts b/packages/ui/src/trello/client.ts
index 84f07e1..ff2454c 100644
--- a/packages/ui/src/trello/client.ts
+++ b/packages/ui/src/trello/client.ts
@@ -22,18 +22,20 @@ export class TrelloClient {
this.apiToken = apiToken;
}
- getLists(boardId: string): Promise {
- return fetch(
+ async getLists(boardId: string): Promise {
+ const res = await fetch(
`https://api.trello.com/1/boards/${boardId}/lists?key=${this.apiKey}&token=${this.apiToken}`,
- ).then((res) => res.json());
+ );
+ return res.json();
}
- createCard(param: { listId: string; name: string }): Promise {
- return fetch(
+ async createCard(param: { listId: string; name: string }): Promise {
+ const res = await fetch(
`https://api.trello.com/1/cards?key=${this.apiKey}&token=${this.apiToken}&idList=${param.listId}&name=${param.name}`,
{
method: "POST",
},
- ).then((res) => res.json());
+ );
+ return res.json();
}
}