Skip to content

Commit

Permalink
Merge pull request #14 from Ho-Wan/develop
Browse files Browse the repository at this point in the history
v0.2.0
  • Loading branch information
ho-wan authored Jan 20, 2019
2 parents 9ab8abe + b437cd3 commit 6e8cfe0
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 28 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Change Log

## 0.2.0 (20 Jan 2019)
- Prefix card number to card names.
- Show comments on card.
- Show initials of users assigned to card.
- Enable auto line breaks for markdown new lines.
- Fixed checklist ordering.
- Improve visual format of card.

## 0.1.1 (19 Jan 2019)
- Minor documentation update. Improved api tests.

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Name of Setting | Default | Description
- The markdown file contains parsed content of the Trello card and can be saved locally.
- Hover over any board, list or card to see the Trello ID.
- The API token is stored using AES 256 encryption with IV.
- The setting "markdown.preview.breaks" is automatically set to true in only to see new lines correctly formatted.

## Unsupported Features

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "vscode-trello-viewer",
"displayName": "Trello Viewer",
"description": "View Trello cards in VS Code, browse user's boards and lists.",
"version": "0.1.1",
"version": "0.2.0",
"publisher": "Ho-Wan",
"author": {
"name": "Ho-Wan To",
Expand Down
6 changes: 6 additions & 0 deletions src/common/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export function prependToLabel(label: string, prefix?: string): string {
if (!prefix) {
return label;
}
return `${prefix}-${label}`;
}
2 changes: 2 additions & 0 deletions src/test/TrelloUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ suite("TrelloUtils", () => {
const data = new Promise(r =>
r({
id: CARD_ID,
idShort: 1,
name: "test_card",
attachments: [
{
Expand All @@ -95,6 +96,7 @@ suite("TrelloUtils", () => {
const trelloCard: TrelloCard = await trello.getCardById(CARD_ID, false);

assert.equal(trelloCard.id, CARD_ID);
assert.equal(trelloCard.idShort, '1');
assert.equal(trelloCard.attachments[0].url, "test_attachment_url");
assert.equal(trelloCard.name, "test_card");
assert.equal(trelloCard.url, "test_url");
Expand Down
17 changes: 17 additions & 0 deletions src/test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as assert from "assert";
import { prependToLabel } from "../common/utils";

suite("TrelloUtils", () => {
const label = "test_label";

test("should return label if prefix undefined", () => {
const resultLabel = prependToLabel(label, undefined);
assert.equal(resultLabel, "test_label");
});

test("should prepend text to label", () => {
const prefix = '12';
const resultLabel = prependToLabel(label, prefix);
assert.equal(resultLabel, "12-test_label");
});
});
4 changes: 3 additions & 1 deletion src/trello/TrelloTreeView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import * as vscode from "vscode";
import { TrelloUtils } from "./TrelloUtils";
import { TrelloItem } from "./TrelloItem";
import { TrelloObject, TrelloBoard, TrelloList, TrelloCard } from "./trelloComponents";

import { TRELLO_ITEM_TYPE, SETTING_PREFIX, SETTING_CONFIG } from "./constants";
import { prependToLabel } from "../common/utils";

export class TrelloTreeView implements vscode.TreeDataProvider<TrelloItem> {
private _onDidChangeTreeData: vscode.EventEmitter<TrelloItem | undefined> = new vscode.EventEmitter<
Expand Down Expand Up @@ -138,7 +140,7 @@ export class TrelloTreeView implements vscode.TreeDataProvider<TrelloItem> {
): TrelloItem[] {
return trelloObjects.map(obj => {
return new TrelloItem(
obj.name,
prependToLabel(obj.name, obj.idShort),
collapsed,
obj.id,
trelloItemType,
Expand Down
116 changes: 91 additions & 25 deletions src/trello/TrelloUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,15 @@ import { writeFile, unlink } from "fs";
import { UserDataFolder } from "../common/UserDataFolder";
import { encrypt, decrypt } from "../common/encrypt";
import { TrelloItem } from "./TrelloItem";
import { TrelloBoard, TrelloList, TrelloCard, TrelloChecklist, CheckItem } from "./trelloComponents";
import {
TrelloBoard,
TrelloList,
TrelloCard,
TrelloChecklist,
TrelloActionComment,
CheckItem,
TrelloMember,
} from "./trelloComponents";
import {
VSCODE_VIEW_COLUMN,
TEMP_TRELLO_FILE_NAME,
Expand All @@ -20,13 +28,25 @@ export class TrelloUtils {
private API_KEY: string | undefined;
private API_TOKEN: string | undefined;
private FAVORITE_LIST_ID: string | undefined;
private tempTrelloFile: string;

constructor(context?: vscode.ExtensionContext) {
this.globalState = context ? context.globalState : {};
axios.defaults.baseURL = TRELLO_API_BASE_URL;
this.tempTrelloFile = new UserDataFolder().getPathCodeSettings() + TEMP_TRELLO_FILE_NAME || "";

this.getCredentials();
this.getFavoriteList();
this.setMarkdownPreviewBreaks();
}

setMarkdownPreviewBreaks(): void {
try {
const config = vscode.workspace.getConfiguration();
config.update("markdown.preview.breaks", true, true);
} catch (error) {
console.error(error);
}
}

isCredentialsProvided(): boolean {
Expand Down Expand Up @@ -188,6 +208,9 @@ export class TrelloUtils {
key: this.API_KEY,
token: this.API_TOKEN,
attachments: "cover",
actions: "commentCard",
actions_limit: 20,
members: true,
},
credentialsRequired
);
Expand Down Expand Up @@ -250,49 +273,92 @@ export class TrelloUtils {
vscode.commands.executeCommand("trelloViewer.refreshFavoriteList");
}

showChecklistsAsMarkdown(checklists: any): string | undefined {
if (!checklists) {
return;
} else if (checklists.length == 0) {
return;
showCardMembersAsString(members: TrelloMember[]): string {
if (!members || members.length == 0) {
return "";
}
return members.map(member => member.initials).join(', ');
};

showChecklistsAsMarkdown(checklists: TrelloChecklist[]): string {
if (!checklists || checklists.length == 0) {
return "";
}

let checklistMarkdown: string = "";
Object.keys(checklists).forEach(id => {
const trelloChecklist: TrelloChecklist = checklists[id];
checklistMarkdown += `\n### ${trelloChecklist.name} \n`;
trelloChecklist.checkItems.map((checkItem: CheckItem) => {
checklistMarkdown +=
checkItem.state === "complete" ? `✅ ~~${checkItem.name}~~ \n` : `❌ ${checkItem.name} \n`;
});
checklists.map(checklist => {
checklistMarkdown += `\n> ${checklist.name} \n`;
checklist.checkItems
.sort((checkItem1: CheckItem, checkItem2: CheckItem) => checkItem1.pos - checkItem2.pos)
.map((checkItem: CheckItem) => {
checklistMarkdown +=
checkItem.state === "complete" ? `✅ ~~${checkItem.name}~~ \n` : `🔳 ${checkItem.name} \n`;
});
});

return checklistMarkdown;
}

showCommentsAsMarkdown(comments: TrelloActionComment[]): string {
if (!comments || comments.length == 0) {
return "";
}

let commentsMarkdown: string = "";
comments.map((comment: TrelloActionComment) => {
const date = new Date(comment.date);
const dateString = `${date.toLocaleString("en-GB", { day: "2-digit", month: "short", year: "numeric" })}`;
const timeString = `${date.toLocaleString("en-GB", {
hour: "2-digit",
minute: "2-digit",
hour12: true,
})}`;
commentsMarkdown += `\n> ${comment.memberCreator.fullName} - ${dateString} at ${timeString} ${
comment.data.dateLastEdited ? "(edited)" : ""
} \n`;
commentsMarkdown += `\n~~~ \n${comment.data.text} \n~~~ \n`;
});
return commentsMarkdown;
}

showMarkdownDecorated(header: string, content: string | undefined): string {
if (!content) {
return "";
}
return `## **\`${header}\`** \n${content}\n\n--- \n`;
};

async showCard(card: TrelloCard): Promise<void> {
if (!card) {
vscode.window.showErrorMessage("No card selected or invalid card.");
return;
}

let checklistItems: string | undefined = this.showChecklistsAsMarkdown(card.trelloChecklists);
const cardCoverImageUrl = card.attachments.length > 0 ? card.attachments[0].url : "";
const cardMembers: string = this.showCardMembersAsString(card.members);
const checklistItems: string = this.showChecklistsAsMarkdown(card.trelloChecklists);
const commentItems: string = this.showCommentsAsMarkdown(card.actions);
const cardCoverImageUrl = (!!card.attachments && card.attachments.length > 0) ? card.attachments[0].url : "";

const cardContentAndHeaders = [
{ header: "URL", content: card.url },
{ header: "Title", content: card.name },
{ header: "Members", content: cardMembers },
{ header: "Description", content: card.desc },
{ header: "Checklists", content: checklistItems },
{ header: "Comments", content: commentItems },
];

let cardContent: string = "";
cardContent += card.url ? `${card.url}\n\n---\n` : "";
cardContent += card.name ? `## ===TITLE===\n${card.name}\n\n---\n` : "";
cardContent += card.desc ? `## ===DESCRIPTION===\n${card.desc}\n\n---\n` : "";
cardContent += checklistItems ? `## ===CHECKLISTS===\n${checklistItems}\n\n---\n` : "";
cardContentAndHeaders.map(({header, content}) => {
cardContent += this.showMarkdownDecorated(header, content);
});
cardContent += cardCoverImageUrl ? `<img src="${cardCoverImageUrl}" alt="Image not found" />` : "";

// Get location of user's vs code folder to save temp markdown file
const tempTrelloFile = new UserDataFolder().getPathCodeSettings() + TEMP_TRELLO_FILE_NAME;
writeFile(tempTrelloFile, cardContent, err => {
// Write temp markdown file at user's vs code default settings directory
writeFile(this.tempTrelloFile, cardContent, err => {
if (err) {
vscode.window.showErrorMessage(`Error writing to temp file: ${err}`);
}
console.info(`✍ Writing to file: ${tempTrelloFile}`);
console.info(`✍ Writing to file: ${this.tempTrelloFile}`);
});

// open markdown file and preview view
Expand All @@ -304,7 +370,7 @@ export class TrelloUtils {
viewColumn = SETTING_CONFIG.DEFAULT_VIEW_COLUMN;
}
vscode.workspace
.openTextDocument(tempTrelloFile)
.openTextDocument(this.tempTrelloFile)
.then(doc => vscode.window.showTextDocument(doc, viewColumn, false))
.then(() => vscode.commands.executeCommand("markdown.showPreview"))
.then(() => vscode.commands.executeCommand("markdown.preview.toggleLock"));
Expand Down
4 changes: 3 additions & 1 deletion src/trello/TrelloViewFavoriteList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import * as vscode from "vscode";
import { TrelloUtils } from "./TrelloUtils";
import { TrelloItem } from "./TrelloItem";
import { TrelloObject, TrelloBoard, TrelloList, TrelloCard } from "./trelloComponents";

import { TRELLO_ITEM_TYPE } from "./constants";
import { prependToLabel } from "../common/utils";

export class TrelloViewFavoriteList implements vscode.TreeDataProvider<TrelloItem> {
private _onDidChangeTreeData: vscode.EventEmitter<TrelloItem | undefined> = new vscode.EventEmitter<
Expand Down Expand Up @@ -113,7 +115,7 @@ export class TrelloViewFavoriteList implements vscode.TreeDataProvider<TrelloIte
): TrelloItem[] {
return trelloObjects.map(obj => {
return new TrelloItem(
obj.name,
prependToLabel(obj.name, obj.idShort),
collapsed,
obj.id,
trelloItemType,
Expand Down
27 changes: 27 additions & 0 deletions src/trello/trelloComponents.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,20 @@ export interface TrelloBoard {
id: string;
name: string;
trelloLists: TrelloList[];
[key: string]: any;
}

export interface TrelloList {
id: string;
name: string;
idBoard: string;
trelloCards: TrelloCard[];
[key: string]: any;
}

export interface TrelloCard {
id: string;
idShort: string;
name: string;
attachments: Array<{
url: string;
Expand All @@ -25,18 +28,42 @@ export interface TrelloCard {
desc: string;
idChecklists: string[];
trelloChecklists: TrelloChecklist[];
actions: TrelloActionComment[];
members: TrelloMember[];
[key: string]: any;
}

export interface TrelloMember {
id: string;
initials: string;
}

export interface TrelloActionComment {
id: string;
date: string;
data: {
text: string;
dateLastEdited: string;
};
memberCreator: {
fullName: string;
};
[key: string]: any;
}

export interface TrelloChecklist {
id: string;
name: string;
checkItems: CheckItem[];
[key: string]: any;
}

export interface CheckItem {
id: string;
state: string;
name: string;
pos: number;
[key: string]: any;
}

export interface GlobalStateConfig {
Expand Down

0 comments on commit 6e8cfe0

Please sign in to comment.