チームのコミュニケーションツールにSlackを、タスク管理ツールにTrelloを利用している開発者は多いと思います。
私もその1人で、2つのツールを活用しています。しかし、これらは便利なツールですが、それぞれのページ(アプリ)を行き来しながら作業するのはあまりスマートな気はしませんでした(Slack appはありますが、作成・検索はできても一覧の取得などはできません)
そこで、Web版SlackにTrelloのカードを表示させるchromeの拡張機能を作成しました。
Trelloの運用については会社やチームによって異なると思うので、ぜひカスタマイズしてお使いください。
(カスタマイズしやすいように、chromeウェブストアには公開せず、コードを公開しています)
#何ができるのか
Web版Slack上で、Trelloで自分がメンバーに設定されているカードの「カードタイトル」と「期限」が表示されます。(カスタマイズ次第でそれ以外の項目も取得できます)
#対象
・SlackとTrelloの両方を使っている方
・TrelloのSlack Appに物足りなさを感じている人
使い方
- Trelloのapiの設定
- コードの取得
- 拡張機能の読み込み
- 表示の確認
###Trelloのapiの設定
まずTrelloにログインした状態で以下にアクセスして、キーを取得します。次に、「手動でトークンを生成できます。」のリンクをクリックし、トークンを取得します。これらは後で使用するので、メモしておいてください。
次にユーザネームを確認します。ユーザ名はTrelloのプロフィールページに記載されています。(一番右側の項目の@に続く文字列です)
###拡張機能のコードの取得
以下で公開しているので、DLまたはcloneして取得してください。
###拡張機能の読み込み
chromeの拡張機能をデベロッパーモードにし、「パッケージ化されていない拡張機能を読み込む」から、取得したコードを読み込んでください。選択するのはプロジェクトのルートファイルを指定してください。
###拡張機能の設定
拡張機能のアイコンをクリックすると入力欄が表示されるので、先ほど取得したキーとトークンとユーザ名を入力し、saveをクリックします。
###表示の確認
web版のスラックにアクセスすると、チャンネルの上部にカードの一覧が表示されます。
表示するカードについては、Trelloの運用ルールに合わせて、ボードやリストを絞り込んでご利用ください(方法については本記事の後半で説明します)
#コードについての解説
ディレクトリ構成
一般的な拡張機能のディレクトリ構成と同じだと思います。
ライブラリとして、storageへのアクセスをラップしたwebextension-polyfillを利用しています
.
├── manifest.json
└── src
├── content.js
├── lib
│ └── browser-polyfill.js
└── popup
├── popup.html
└── popup.js
メインコードの解説
window.onload = async function () {
var slack_sidebar = document.getElementsByClassName("p-channel_sidebar")[0];
var trello_list = document.createElement("div");
trello_list.style.overflow = "auto";
trello_list.style.height = "20%";
const p = document.createElement("p");
p.appendChild(document.createTextNode("タスク一覧"));
trello_list.appendChild(p);
const list = document.createElement("ul");
list.className = "trello-list";
trello_list.appendChild(list);
slack_sidebar.insertBefore(trello_list, slack_sidebar.firstChild);
await this.setTrelloList();
// 30秒ごとにカードを更新するように定義
this.setInterval(async () => {
await this.setTrelloList();
}, 30000);
};
// カードを取得して、表示する
async function setTrelloList() {
const cards = await getTrelloList();
var list = document.getElementsByClassName("trello-list")[0];
while (list.lastChild) {
list.removeChild(list.lastChild);
}
for (let i = 0; i < cards.length; i++) {
const card_dom = document.createElement("li");
const card_due = new Date(cards[i].due);
card_dom.appendChild(
document.createTextNode(
cards[i].name + "[" + card_due.toLocaleString() + "]"
)
);
list.appendChild(card_dom);
}
}
// trelloからカード情報を取得
async function getTrelloList() {
const keys = await browser.storage.local.get([
"trello_key",
"trello_token",
"trello_user_name",
]);
const trelloKey = keys.trello_key,
trelloToken = keys.trello_token,
userName = keys.trello_user_name;
if (trelloKey === undefined) return new Array();
// IDからカードの一覧を取得
const getcards_url =
"https://trello.com/1/members/" +
userName +
"/cards?key=" +
trelloKey +
"&token=" +
trelloToken +
"&fields=name,due,idList";
const response = await fetch(getcards_url, {
method: "GET",
}).then((data) => data.json());
return response;
}
####1行目から22行目まで
既存のSlackのページに対して「カード表示部分の追加」と、定期的にカードを更新するを記述しています。
カードの表示部分については、高さがサイドバー全体の20%になるように調整し、カードが多い場合はスクロールする設定にしています。
カードの更新については、今回は30秒ごとにカードを更新しています。もし重い場合やそこまでリアルタイムに表示しなくてもいい場合は、間隔を長くしてもいいと思います。
####24行目から42行目まで
カードを表示する処理を記述しています。
今回は、カードタイトルと期限を表示していますが、追加・変更したい場合はここを変更します。
また項目を追加する場合は、以下のカードを取得する処理も併せて変更する必要があります。
####45行目から75行目まで
TrelloのAPIを使用し、カードを取得する処理を記述しています。
取得するカードの種類や項目を変更したい場合は、ここを変更します。
今回は、「指定したユーザがメンバーになっているカード」の、「タイトル」と「期限」を取得しています。
応用:特定のボード、リストに絞り込む
45行目から75行目を変更します。
まず指定するボードIDとリストIDを取得します。
取得方法については以下を参照して取得してください。
次に59行目から72行目を以下のように変更します。
変更後、拡張機能を再読み込みすることで、変更が適応されます。
//変更前
// const getcards_url =
// "https://trello.com/1/members/" +
// userName +
// "/cards?key=" +
// trelloKey +
// "&token=" +
// trelloToken +
// "&fields=name,due";
// const response = await fetch(getcards_url, {
// method: "GET",
// }).then((data) => data.json());
// 変更後
const boardId = "ここに取得したボードID"
const listId = "ここに取得したリストID"
const getcards_url =
"https://trello.com/1/members/" +
userName +
"/cards?key=" +
trelloKey +
"&token=" +
trelloToken +
"&fields=name,due,idBoard,idList";
const response = await fetch(getcards_url, {
method: "GET",
})
.then((data) => data.json())
.then((cards) => {
// console.log(cards);
let cardArray = [];
for (const card of cards) {
if (card.idBoard === boardId && card.idList === listId) {
cardArray.push(card);
}
}
return cardArray;
});
#参考文献
https://qiita.com/RyBB/items/32b2a7b879f21b3edefc