kintone のアプリが 50 を超えたあたりから、「目的のアプリの、目的の設定画面にたどり着くまで」がいちばんの手間になりました。
アクセス権を付けてほしいと頼まれたら、アプリ一覧から探して、歯車を押して、設定タブを開いて、アクセス権を開く。JavaScript を直したら、また同じ道をたどってカスタマイズ画面へ降りていく。1回は数秒でも、1日に何十回もあると手が止まります。
そこで、kintone のどの画面からでも Ctrl+/ でパレットを開き、名前を数文字打って Enter で目的の画面に飛べる Chrome 拡張を作りました。この記事では、何に困って、Manifest V3 でどう作って、半年使って何が残ったかを書きます。
困っていたこと
海外の工場で、kintone をひとりで作って運用しています。アプリは 50 を超えました。
困りごとは大きく3つでした。
1つ目はアプリ間の移動です。アプリ一覧から探すより、名前を打つほうが早い数になっていました。
2つ目は設定画面の深さです。アクセス権・通知・JavaScript / CSS カスタマイズ・プラグイン設定は、どれもアプリの設定の奥にあります。開発中はコードを直してアップロードして確かめる往復のたびに、ここを降りていきます。
3つ目はフィールドコードです。最近はカスタマイズのコードを AI に書いてもらうことが増えましたが、フィールドコードを1つ間違えられると動かないコードが返ってきます。毎回フォームの設定画面を開いてコードを書き写すのは、移動以上に面倒でした。
作ったもの
Ctrl+/(Mac は Cmd+/)でパレットが開きます。
アプリ名の一部を打てばアプリに移動します。設定画面は英語の短い言葉で呼べるようにしました。アクセス権は acl、JavaScript / CSS カスタマイズは js、通知は notify、今開いているレコードの再利用は dup です。日本語だと変換を挟むので、半角のまま3文字打って Enter のほうが手が止まりません。
AI に相談するときは、パレットの「フィールドコード一覧をコピー」を使います。1行目にアプリ ID、続けてフィールドコード・フィールド名・種類がタブ区切りで入るので、そのまま会話に貼れます。込み入った相談のときは「フォーム定義を JSON で取得」で、選択肢やルックアップの設定まで含めたフォームの定義を丸ごと貼ります。
Manifest V3 での作り方
Chrome 拡張から kintone を触るときに引っかかった点を、実装の順に書きます。
content script からは kintone.api が見えない
最初に詰まったのがここでした。content script は「isolated world」という、ページとは別の JavaScript の世界で動きます。DOM は共有されますが、ページ側の window.kintone は見えません。
kintone.api が使えればログイン中のセッションのまま REST API を呼べるので、API トークンを発行してもらう必要がなくなります。そこで、chrome.scripting.executeScript に world: 'MAIN' を指定して、ページ側の世界で関数を実行しています。
// service_worker.js(フィールドコード一覧を取る部分を簡略化)
const [{ result }] = await chrome.scripting.executeScript({
target: { tabId },
world: 'MAIN',
func: async () => {
const sdk = window.kintone;
if (!sdk?.app || !sdk?.api) return { ok: false, reason: 'not_kintone_page' };
const appId = sdk.app.getId();
const resp = await sdk.api(
sdk.api.url('/k/v1/app/form/fields', true), 'GET', { app: appId }
);
return { ok: true, appId, properties: resp.properties };
},
});
func に渡した関数はシリアライズされてページに送られるので、外側の変数は参照できません。必要な値は args で渡します。
何度も呼ぶ処理は、web_accessible_resources に置いた小さなスクリプト(page-bridge)をページに差し込み、content script と window.postMessage でやり取りする形にしました。メッセージは location.origin を相手先に指定し、受け取る側でも自分の印が付いたメッセージだけを処理します。
権限は「許可したドメインだけ」にする
kintone のドメインは *.cybozu.com・*.kintone.com・*.kintone-dev.com と複数あり、会社ごとにサブドメインが違います。最初から全部に権限を取ると、ストアの審査でもインストールする人にとっても重くなります。
そこで host_permissions は空にして、optional_host_permissions に候補を並べ、使う人が自分の kintone のドメインを設定画面で許可したときだけ動くようにしました。
"permissions": ["storage", "scripting", "tabs", "alarms", "contextMenus", "sidePanel"],
"host_permissions": [],
"optional_host_permissions": [
"https://*.kintone.com/*",
"https://*.cybozu.com/*",
"https://*.kintone-dev.com/*"
]
// 許可済みならそのまま、未許可ならダイアログを出す
async function ensureOrigin(pattern) {
if (await chrome.permissions.contains({ origins: [pattern] })) return true;
return await chrome.permissions.request({ origins: [pattern] });
}
chrome.permissions.request はユーザーの操作(クリック)の中からしか呼べないので、設定画面のボタンから呼んでいます。
状態は service worker に置かない
Manifest V3 の background は service worker で、しばらく操作がないと止まります。変数に持たせた状態は、止まった時点で消えます。
なので、残したいものはすべて chrome.storage に置いています。お気に入りのアプリ・ピン留め・ショートカットのような、量が少なく PC をまたいで同じであってほしいものは chrome.storage.sync。アプリ一覧のキャッシュや件数の前回値のような、その PC だけで持てばよいものは chrome.storage.local です。
sync は容量の上限が小さい(全体で約 100KB、1項目あたり約 8KB)ので、キャッシュを入れるとすぐに溢れます。どちらに置くかは「別の PC でも同じであってほしいか」で決めました。
設定はすべてブラウザの中に保存され、外部のサーバーには送っていません。
サイドパネル
よく使うアプリや、見ておきたい一覧の件数を並べるサイドパネルも付けました。sidePanel 権限を取り、拡張のアイコンを押したら開くようにしています。
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });
件数の更新は2段に分けました。パネルが開いている間は、パネルのページ側のタイマーで数分おきに取り直します(ページなので、開いている間は止まりません)。パネルを閉じている間の「件数がしきい値を超えたら通知する」確認は、service worker 側で chrome.alarms を使って 10 分おきに起こしています。service worker は止まるので、こちらは setInterval では続きません。
// service_worker.js
chrome.alarms.create('pb-watchlist-threshold-check', { periodInMinutes: 10 });
chrome.alarms.onAlarm.addListener((alarm) => {
if (alarm.name === 'pb-watchlist-threshold-check') checkWatchlistThresholds();
});
半年使って、残ったもの
作った本人がいちばん使っているのは、結局パレットのアプリ移動と、acl・js での設定画面への直行です。それに、AI に渡すフィールドコード一覧のコピーが加わりました。
一方で、いちばん手をかけたサイドパネルは、朝に件数を確かめる1日1回くらいしか開いていません。
パレットを開くときは、「権限を付けたい」「JS を直したい」と行き先がもう決まっています。サイドパネルは、用事がまだ無いときに何かあるかを見に行く画面です。人は用事があるときにしか画面を開かない、というのが、自分で使ってみて分かったことでした。
使ってみたい方へ
ここに書いた機能は、すべて無料で使えます。設定はブラウザの中だけに保存され、kintone へのアクセスも自分で許可したドメインでだけ動きます。
Chrome ウェブストア:
https://plugbits.app/launcher/go/qiita/
説明ページ: https://plugbits.app/launcher
一覧を Excel のような表で直接編集できる有料の Pro 版(買い切り ¥1,980・14日間の無料お試しあり・月額なし)もありますが、この記事の機能には関係ありません。
「この画面にも一発で飛びたい」というものがあれば、コメントで教えてください。次に足すものの参考にします。
