kintone のスペースを API を使ってカスタマイズしてみよう

目次

はじめに

kintoneのスペーストップ画面は、「お知らせ」欄にスペースの説明を表示したり、アプリを貼り付けてレコードの一覧を表示するなど、使用用途に合わせて自由に設定できます。
さらにスペースをカスタマイズするAPIを使うと、ポータルカスタマイズのように文字を表示したり、ボタンを設置したりできます。
本記事では、kintone JavaScript APIのスペースAPIを使った簡単なkintoneカスタマイズを紹介します。

スペース API でできること

スペースAPIを使うことで、ボタンを設置したり、リンクを動的に設置するなどのカスタマイズができます。

スペース系 API

スペースに関するJavaScript APIは2021年10月現在、以下のものがあります。

完成イメージ

スペースの上側部分に出勤・退勤ボタンを設置します。
それぞれのボタンを押すと、タイムカードアプリにレコードが追加・更新されます。

JavaScript を利用したスペースのカスタマイズ方法

このTipsのカスタマイズは、kintone全体にカスタマイズを適用します。
そのため、kintoneシステム管理者の権限が必要です。

下準備

  1. kintoneのポータル画面からスペースを作成します。

    • 作成するスペースは、「スペースのポータルと複数にスレッドを使用する」を有効にしてください。
    • JavaScriptカスタマイズで使用するため、作成したスペースIDを控えておきます。
      スペースIDは、ブラウザーでスペースを表示した際のURLで確認できます。
      以下のURLの場合、スペースIDは8です。
      https://{subdomain}.cubozu.com/k/#/space/8
  2. 1. で作成したスペース内にタイムカードアプリを作成します。

    • タイムカードアプリ (External link) は、kintoneアプリストアから追加してください。
    • タイムカードアプリのフィールド「承認者」を次のように設定します。
      • 「必須項目にする」のチェックを外す。
    • JavaScriptカスタマイズで使用するため、作成したアプリIDを控えておきます。
      アプリIDは、ブラウザーでアプリを表示した際のURLで確認できます。
      以下のURLの場合、アプリIDは245です。
      https://{subdomain}.cybozu.com/k/245/

ライブラリの入手

カスタマイズ例:スペースの上部に出勤・退勤ボタンを設置する

それではさっそく、スペースの上側に出勤・退勤ボタンを設置し、タイムカードアプリに登録するカスタマイズをしていきましょう。

kintone へのカスタマイズ適用

スペースのカスタマイズは、kintoneシステム管理画面から行います。
詳しい設定方法については、kintoneヘルプ「 JavaScript / CSS ファイルを取り込む (External link) 」を確認してください。
設定は以下のようになります。

  • PC用のJavaScriptファイル

    • https://js.cybozu.com/luxon/2.0.2/luxon.min.js
    • sweetalert2.min.js
    • kuc.min.js
    • sample.js
  • PC用のCSSファイル

    • sweetalert2.min.css
    • sample.css

サンプルコード
sample.js

出勤・退勤ボタンを設置し、ボタンを押したときにタイムカードアプリへレコードを追加・更新するためのスクリプトファイルです。
ご自身の環境に応じてつぎのとおり内容を変更してください。

  • 12行目{YOUR_CUSTOM_SPACE_ID}:「下準備1.」で控えたスペースIDに変更
  • 13行目{TIMECARD_APP_ID}:「下準備2.」で控えたタイムカードアプリのIDに変更
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * sample.js
 * Copyright (c) 2021 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

(function() {
  'use strict';
  kintone.events.on('space.portal.show', (event) => {
    const SPACE_ID = '{YOUR_CUSTOM_SPACE_ID}'; // ボタンを設置するスペース ID に変更してください
    const TIMECARD_APP_ID = '{TIMECARD_APP_ID}'; // タイムカードアプリのアプリID に変更してください
    if (event.spaceId !== SPACE_ID) {
      return event;
    }

    const toastObj = Swal.mixin({
      toast: true,
      position: 'top',
      showConfirmButton: false,
      timer: 3000,
      timerProgressBar: true,
      didOpen: function(toast) {
        toast.addEventListener('mouseenter', Swal.stopTimer);
        toast.addEventListener('mouseleave', Swal.resumeTimer);
      }
    });

    // スペース上側の要素を取得
    const el = kintone.space.portal.getContentSpaceElement();

    // 出勤・退勤ボタンの設定
    const startButton = new Kuc.Button({
      text: '出勤',
      type: 'submit',
      id: 'startButton'
    });

    const endButton = new Kuc.Button({
      text: '退勤',
      type: 'alert',
      id: 'endButton'
    });

    // 日付表示の設定
    const today = luxon.DateTime.local();
    const todayStr = today.setLocale('ja').toFormat('yyyy 年 M 月 d 日(EEE)');
    const displayDateDiv = document.createElement('div');
    displayDateDiv.id = 'displayDate';
    displayDateDiv.innerText = todayStr;

    // 今日の日付と出勤・退勤ボタンを設置
    el.appendChild(displayDateDiv);
    el.appendChild(startButton);
    el.appendChild(endButton);

    // 出勤ボタンを押したときの関数
    startButton.addEventListener('click', () => {
      // 現在時刻を取得
      const currentDate = luxon.DateTime.local();
      const currentTimeStr = currentDate.toFormat('HH:mm');

      // ログインユーザーがすでに今日の日付でレコードを登録していないかチェック
      const query = '申請者 in (" USER", LOGINUSER()) and 申請日時 = TODAY() order by 申請日時 desc limit 1';
      const paramsForGet = {
        app: TIMECARD_APP_ID,
        query: query
      };
      return kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', paramsForGet).then((resp) => {
        if (resp.records.length !== 0) {
          // すでに今日の日付のレコードがあった場合、レコードの出勤時刻を更新
          const recordId = resp.records[0].$id.value;
          const paramsForUpdate = {
            app: TIMECARD_APP_ID,
            id: recordId,
            record: {
              出勤時刻: {
                value: currentTimeStr
              }
            }
          };
          return kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', paramsForUpdate).then((resp2) => {
            toastObj.fire({
              icon: 'success',
              title: '出勤時刻を更新しました!'
            });
          }).catch((error) => {
            toastObj.fire({
              icon: 'error',
              title: '出勤時刻の更新に失敗しました。'
            });
          });
        }
        // 今日の日付のレコードがなかった場合、レコードを登録
        const paramsForAdd = {
          app: TIMECARD_APP_ID,
          record: {
            出勤時刻: {
              value: currentTimeStr
            },
            退勤時刻: {
              value: ''
            }
          }
        };
        return kintone.api(kintone.api.url('/k/v1/record.json', true), 'POST', paramsForAdd, (resp3) => {
          toastObj.fire({
            icon: 'success',
            title: '出勤時刻を登録しました!'
          });
        }, (error) => {
          toastObj.fire({
            icon: 'error',
            title: '出勤時刻の登録に失敗しました。'
          });
        });
      });
    });

    // 退勤ボタンを押したときの関数
    endButton.addEventListener('click', () => {
      // 現在時刻を取得
      const currentDate = luxon.DateTime.local();
      const currentTimeStr = currentDate.toFormat('HH:mm');

      // ログインユーザーが登録したレコードを取得
      const query = '申請者 in (" USER", LOGINUSER()) and 申請日時 = TODAY() order by 申請日時 desc limit 1';
      const paramsForGet = {
        app: TIMECARD_APP_ID,
        query: query
      };

      return kintone.api(kintone.api.url('/k/v1/records.json', true), 'GET', paramsForGet).then((resp) => {
        if (resp.records.length === 0) {
          // 今日の日付のレコードがない場合、レコードを登録
          const paramsForAdd = {
            app: TIMECARD_APP_ID,
            record: {
              出勤時刻: {
                value: ''
              },
              退勤時刻: {
                value: currentTimeStr
              }
            }
          };

          return kintone.api(kintone.api.url('/k/v1/record.json', true), 'POST', paramsForAdd).then((resp2) => {
            toastObj.fire({
              icon: 'info',
              title: '退勤時刻を登録しました!レコードから出勤時刻を忘れずに入力してください。'
            });
          }).catch((error) => {
            toastObj.fire({
              icon: 'error',
              title: '退勤時刻の登録に失敗しました。'
            });
          });
        }
        const recordId = resp.records[0].$id.value;
        const paramsForUpdate = {
          app: TIMECARD_APP_ID,
          id: recordId,
          record: {
            退勤時刻: {
              value: currentTimeStr
            }
          }
        };

        return kintone.api(kintone.api.url('/k/v1/record.json', true), 'PUT', paramsForUpdate).then((resp3) => {
          toastObj.fire({
            icon: 'success',
            title: '退勤時刻を更新しました!'
          });
        }).catch((error) => {
          toastObj.fire({
            icon: 'error',
            title: '退勤時刻の更新に失敗しました。'
          });
        });
      });
    });

    return event;
  });
})();
sample.css

出勤・退勤ボタンの表示位置を調整するためのCSSです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/*
 * sample.css
 * Copyright (c) 2021 Cybozu
 *
 * Licensed under the MIT License
 * https://opensource.org/license/mit/
 */

#displayDate {
  padding: 10px 20px 0px 30px;
  font-size: 20pt;
  font-weight: 500;
}

#startButton {
  padding: 10px 20px 20px 30px;
}

#endButton {
  padding: 10px 20px 20px 10px;
}
JavaScript カスタマイズのポイント
11 〜 14 行目

スペース表示イベントが実行されたときに、ボタンを表示したいスペースかどうかをスペースIDで判断します。
スペースカスタマイズではkintone全体にカスタマイズを適用しているため、if文を使ってボタンの表示/非表示を切り替えています。

30 〜 56 行目

スペースの上側の空白要素を取得し、今日の日付と出勤・退勤ボタンをセットしています。
出勤・退勤ボタンは、kintone UI Component v1を利用してkintoneライクなボタンを設置しています。

61 〜 62 行目

Luxonを使って、出勤ボタンを押したときの時間を時刻フィールドの書式にフォーマットしています。

135 〜 153 行目

出勤ボタンを押し忘れて退勤ボタンだけを押した場合、退勤時刻のみ登録されます。
ユーザーに出勤時刻を登録してもらうようにメッセージを追加しています。
ボタンを押したあとに表示されるメッセージはSweetAlert2を使用して表示しています。

おわりに

スペースAPIを使って、出退勤のボタンを設置するカスタマイズを紹介しました。
部署やグループごとでスペースを使い分けて、出退勤を管理したいシーンにおすすめです。
cybozu developer networkでは ポータルの上部に出勤・退勤ボタンを設置するカスタマイズも紹介しています。
スペースAPIを活用して、お好みのスペースカスタマイズをお試しください。

information

このTipsは、2021年10月版kintoneで動作を確認しています。