サイボウズさん主催の kintone devCamp Boost! のセッションで提供したハンズオンの内容を記事にしました。
LINE WORKS の WOFF を利用した入力画面から kintone アプリにデータを入力します。
WOFF とは
WORKS Front-end Framework(以下、WOFF)は、「LINE WORKS」上で動くWeb アプリを実装できる開発プラットフォームです。このWOFFで作られた Web アプリ(以下、WOFFアプリ)は、トークメッセージなどからシームレスに立ち上がるミニアプリとして、幅広い連携を実現します。
WOFFアプリは HTML と JavaScript をベースとした Web アプリです。WOFF アプリを実行したユーザーの情報の取得や、WOFF アプリを呼び出したトークルームへのメッセージの送信などができるようになります。
Power Automate で WOFF を作成
トリガー作成
フローのトリガーとして [HTTP 要求の受信時] を用います。
一覧から探すか、または検索して "要求" を選択してください。
アクション作成
"Http 要求の受信時" で受けた Get のリクエストに応じて WOFF を表示するために、[応答] のアクションを追加します。
一覧から探すか、または検索して [要求] を選択し、[応答] のアクションを指定してください。
各項目を以下のとおり指定します。
ヘッダーは以下のとおりです。
キー:
Content-Type
値:
text/html; charset=UTF-8
本文は以下をコピー、ペーストしてください。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<title>devCamp Boost ハンズオン</title>
<script>
// WOFF ID を書き換えてください
const WOFF_ID = "i658h0DFhT-mSlGssQa6_Q";
// HTTP POST の URL を書き換えてください
const url = "https://prod-13.japaneast.logic.azure.com:443/workflows/4f8b1e46a6df44e1b48b0939a1e62f35/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=lrPlc5_GGqRmHuux_XVD7VU8TsnKss2yr7N2zmTOmwc";
</script>
<script charset="utf-8" src="https://static.worksmobile.net/static/wm/woff/edge/3.6/sdk.js"></script>
<style>
/* Global Styles */
body {
font-family: 'Arial', sans-serif;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
h1 {
margin-bottom: 15px;
}
input, select, button {
width: 100%;
margin-bottom: 15px;
padding: 10px;
box-sizing: border-box;
font-size: 16px;
}
/* Toggle Switch CSS */
.switch {
position: relative;
width: 60px;
height: 34px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
}
.slider:before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
}
input:checked + .slider {
background-color: #2196F3;
}
input:checked + .slider:before {
transform: translateX(26px);
}
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}
/* Label for Toggle */
label {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}
</style>
</head>
<body>
<h1>devCamp Boost</h1>
<label for="displayNameInput">表示名:</label>
<input type="text" id="displayNameInput" placeholder="名前を入力" required>
<label for="dateInput">日付:</label>
<input type="date" id="dateInput" required>
<label for="timeInput">開始時刻:</label>
<input type="time" id="timeInput" required>
<label for="workTypeSelect">作業種別:</label>
<select id="workTypeSelect">
<option value="組み立て">組み立て</option>
<option value="検査">検査</option>
<option value="洗浄">洗浄</option>
<option value="塗装">塗装</option>
</select>
<label>
位置情報を送信:
<div class="switch">
<input type="checkbox" id="locationToggle">
<span class="slider round"></span>
</div>
</label>
<button onclick="sendData()">送信</button>
<script>
document.addEventListener("DOMContentLoaded", function() {
woff.init({
woffId: WOFF_ID
})
.then(() => {
return woff.getProfile();
})
.then(profile => {
const input = document.getElementById("displayNameInput");
input.value = profile.displayName;
})
.catch(err => {
console.log(err.code, err.message);
});
});
function getLocation() {
return new Promise((resolve, reject) => {
if (!navigator.geolocation) {
reject(new Error("Geolocation is not supported by your browser."));
} else {
navigator.geolocation.getCurrentPosition(
position => {
resolve({
lat: position.coords.latitude,
lng: position.coords.longitude
});
},
error => {
reject(new Error("Unable to retrieve your location."));
}
);
}
});
}
async function sendData() {
const displayNameValue = document.getElementById("displayNameInput").value;
const dateValue = document.getElementById("dateInput").value;
const timeValue = document.getElementById("timeInput").value;
const workTypeValue = document.getElementById("workTypeSelect").value;
const locationToggle = document.getElementById("locationToggle").checked;
let locationData = null;
if (locationToggle) {
try {
locationData = await getLocation();
} catch (err) {
console.error(err.message);
return;
}
}
const data = {
displayName: displayNameValue,
date: dateValue,
time: timeValue,
workType: workTypeValue,
location: locationData
};
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => {
if (response.ok) {
woff.closeWindow();
} else {
return response.json();
}
})
.then(dataResponse => {
if (dataResponse) {
console.log(dataResponse);
}
})
.catch(error => {
console.error('Error:', error);
});
}
</script>
</body>
</html>
WOFF ID と HTTP POST の URL
以下の部分は後ほど書き換えます。
// WOFF ID を書き換えてください
const WOFF_ID = "i658h0DFhT-mSlGssQa6_Q";
// HTTP POST の URL を書き換えてください
const url = "https://prod-13.japaneast.logic.azure.com:443/workflows/4f8b1e46a6df44e1b48b0939a1e62f35/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=lrPlc5_GGqRmHuux_XVD7VU8TsnKss2yr7N2zmTOmwc";
"HTTP 要求の受信時" の "HTTP POST の URL" が生成されているので、コピーボタンをクリックし、いずれかの場所にメモしてください。
LINE WORKS Developer Console で WOFF アプリ登録
LINE WORKS Developer Console にアクセスします。
https://dev.worksmobile.com/jp/console/openapi/v2/app/list/view
WOFF アプリを登録します。
https://developers.worksmobile.com/jp/docs/woff-guide#create-woff-app
WOFF名: 任意の名前を指定
Endpoint URL を PowerAutomate で生成された HTTP 要求の受信時の URL を指定
サイズ: [Tall] を選択
[応答] アクションの本文の WOFF ID を書き換えてください。
動作確認
WOFF アプリの [URL] コピー ボタンをクリックします。
コピーした URL を LINE WORKS のトークで自分に送ります。
トークルームで URL をタップすると WOFF アプリが表示されます。
モバイルアプリで実行すると、[表示名] に WOFF SDK で取得されたログイン中の LINE WORKS ID の表示名が既定値として入力された状態になります。
この時点では [送信ボタン] は、まだ正しく動作しません。タップしないでください。
Power Automate で WOFF アプリからのデータを受信するフローを作成
Kintone アプリの APIトークンの設定
Kintone アプリの APIトークンを設定します。
該当のヘルプ記事は以下です。
https://jp.cybozu.help/k/ja/user/app_settings/api_token.html
アプリの画面の右側の歯車アイコン横の下向き矢印をクリックするとプルダウン メニュが表示されます。
[カスタマイズ/サービス連携] の [APIトークン] をクリックします。
APIトークンの設定画面で [生成する] をクリックします。
生成された APIトークンはメモしてください。また、アクセス権で [レコード追加] を選択してください。
[保存] します。
トリガー作成
Power Automate のフローのトリガーとして [HTTP 要求の受信時] を用います。
これにより、WOFF のフォームから送信されたメッセージを受信します。
一覧から探すか、または検索して "要求" を選択してください。
{
"type": "object",
"properties": {
"displayName": {
"type": "string"
},
"date": {
"type": "string"
},
"time": {
"type": "string"
},
"workType": {
"type": "string"
},
"location": {
"type": "object",
"properties": {
"lat": {
"type": "number"
},
"lng": {
"type": "number"
}
}
}
}
}
アクション作成
"Http 要求の受信時" で受けた内容を基に kintone の API リクエストを送信するために[HTTP] のアクションを追加します。
一覧から探すか、または検索して "HTTP" を選択し、[HTTP] のアクションを指定してください。
以下のとおり、各入力項目の値を登録します。
方法: プルダウンから "POST" を選択
https://sample.cybozu.com/k/v1/record.json
cybozu developer network の以下の記事を参照してください。
https://cybozu.dev/ja/kintone/docs/rest-api/records/get-record/
ヘッダーは以下のとおりです。
キー:
X-Cybozu-API-Token
値:
kintone アプリの設定で生成したトークン値
キー:
Content-Type
値:
application/json
本文は以下をコピー、ペーストしたうえで、
{
"app": <アプリ ID を記入>,
"record": {
"worker": {
"type": "SINGLE_LINE_TEXT",
"value": "@{triggerBody()?['displayName']}"
},
"日付": {
"type": "DATE",
"value": "@{triggerBody()?['date']}"
},
"時刻": {
"type": "TIME",
"value": "@{triggerBody()?['time']}"
},
"workType": {
"type": "SINGLE_LINE_TEXT",
"value": "@{triggerBody()?['workType']}"
},
"lng": {
"type": "SINGLE_LINE_TEXT",
"value": "@{triggerBody()?['location']?['lng']}"
},
"lat": {
"type": "SINGLE_LINE_TEXT",
"value": "@{triggerBody()?['location']?['lat']}"
}
}
}
app の id は対象のアプリの id に書き換えてください。
URL 末尾の数字が ID です。
kintone アプリのレコード登録完了を LINE WORKS の Bot で通知するため [HTTP] のアクションを追加します。
一覧から探すか、または検索して "HTTP" を選択し、[HTTP] のアクションを指定してください。
以下のとおり、各入力項目の値を登録します。
方法: プルダウンから "POST" を選択
URI: Bot ID は LINE WORKS Developer Console で登録した自分の Bot の Bot ID を記述します。先ほどメモしたものです。
https://www.worksapis.com/v1.0/bots/{botId}/users/{userId}/messages
userID は、自分の LINE WORKS ID を指定します。
ヘッダーは以下のとおりです。
キー:
Content-Type
値:
application/json
キー:
Authorization
値:
Bearer <token>
本文は以下をコピー、ペーストします。
{
"content": {
"type": "text",
"text": "kintone アプリに登録したよ!\nレコード番号 @{outputs('HTTP')?['body']?['id']} \nお疲れ様でした☺"
}
}
"HTTP 要求の受信時" の "HTTP POST の URL" が生成されているので、コピーボタンをクリックし、いずれかの場所にメモしてください。
この URL を以下の記事のスクリプト内に記述します。
https://qiita.com/iwaohig/private/5273a52bad121449403f#woff-id-%E3%81%A8-http-post-%E3%81%AE-url
動作確認
前の手順で自分に送信した WOFF URL から WOFF の画面を表示します。
各項目を入力します。
モバイルアプリから実行すると表示名が WOFF SDK の woff.getProfile() で取得した値が初期値として示されます。
https://developers.worksmobile.com/jp/docs/woff-api#woff-getprofile
日付、時刻、リストボックスなどは Bot のテキストより直感的な UI を提供できます。
[位置情報を送信] のトグル スイッチを有効にすると、位置情報を取得して送信されます。
送信ボタンをタップまたはクリックし、正しくデータ送信されると WOFF SDK の woff.closeWindow() メソッドでアプリが終了します。
https://developers.worksmobile.com/jp/docs/woff-api#close-woff-app
WOFF を固定メニューから起動できるようにする
LINE WORKS の Bot の固定メニューから WOFF を起動できるように登録します。
トリガー作成
フローのトリガーとして [手動でフローをトリガーします] を選択します。
アクション作成
[HTTP] のアクションを追加します。
一覧から探すか、または検索して "HTTP" を選択し、[HTTP] のアクションを指定してください。
以下のとおり、各入力項目の値を登録します。
方法: プルダウンから "POST" を選択
URI: 以下の URI を使います。
https://www.worksapis.com/v1.0/bots/{botId}/persistentmenu
{BotID} は書き換えてください。
ヘッダーは以下のとおりです。
キー:
Content-Type
値:
application/json
キー:
Authorization
値:
Bearer <token>
本文は以下です。
LINE WORKS Developer Console で生成されたものに書き換えてください。
{
"content": {
"actions": [
{
"type": "uri",
"label": "WOFF",
"uri": "<WOFF URL>"
}
]
}
}