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 で動作を確認しています。