チャプター2:ダッシュボードを作成

このチュートリアルの最初の部分では、ほとんどのフクロウのアイデアを紹介しました。 Web クライアントで使用されているように Odoo JavaScript フレームワーク全体について学ぶ時が来ました。

../../../_images/previously_learned.svg

始めるには、実行中の Odoo サーバーと開発環境のセットアップが必要です。 練習問題に入る前に、この tutorial <tutorials/discover_js_framework/setup>`で説明されているすべてのステップに従っていることを確認してください。 この章では、`awesome_dashboard addonが提供する空のダッシュボードから始めます。 Odoo JavaScriptフレームワークを使用して、機能を徐々に追加します。

目標

../../../_images/overview_02.png

章の各演習の解決策は、 official Odoo tutorials repository にホストされています。

1. 新しいレイアウト

Odoo ウェブクライアントのほとんどの画面は、共通のレイアウト:コントロールパネルを上に使用します。 ボタンの下にメインゾーンがあります これは Layout コンポーネント を使用して行われ、@web/search/layout で利用できます。

  1. Update the AwesomeDashboard component located in awesome_dashboard/static/src/ to use the Layout component. You can use {controlPanel: {} } for the display props of the Layout component.

  2. Layout`に`className`プロパティを追加する: `className 'o_dashboard h-100'"`

  3. .o_dashboard の背景色をグレー(または好きな色)に設定する dashboard.scss ファイルを追加します

http://localhost:8069/webを開き、 Awesome Dashboard アプリを開き、結果を確認します。

../../../_images/new_layout.png

理論: サービス

実際には、すべてのコンポーネント(ルートコンポーネントを除く)はいつでも破壊され、別のコンポーネントに置き換えられる(またはそうでない)ことがあります。 これは、各コンポーネントの内部状態が持続しないことを意味します。 これは多くの場合は問題ありませんが、データを保持したい場合は確かにあります。 たとえば、チャンネルを表示するたびにすべてのディスカッションメッセージが再読み込みされることはありません。

また、コンポーネントではないコードを書く必要がある場合もあります。 多分、すべてのバーコードを処理する何か、またはユーザー構成(コンテキストなど)を管理する何か。

Odoo フレームワークは、 :ref:`service <frontend/services>`のアイデアを定義します。 これは状態や関数をエクスポートする永続的なコードです 各サービスは他のサービスに依存し、コンポーネントはサービスをインポートすることができます。

以下の例では、5秒ごとに通知を表示するシンプルなサービスを登録します。

import { registry } from "@web/core/registry";

const myService = {
    dependencies: ["notification"],
    start(env, { notification }) {
        let counter = 1;
        setInterval(() => {
            notification.add(`Tick Tock ${counter++}`);
        }, 5000);
    },
};

registry.category("services").add("myService", myService);

サービスは、任意のコンポーネントからアクセスできます。共有状態を維持するためのサービスがあるとします。

import { registry } from "@web/core/registry";

const sharedStateService = {
    start(env) {
        let state = {};
        return {
            getValue(key) {
                return state[key];
            },
            setValue(key, value) {
                state[key] = value;
            },
        };
    },
};

registry.category("services").add("shared_state", sharedStateService);

次に、任意のコンポーネントが次のように実行できます。

import { useService } from "@web/core/utils/hooks";

setup() {
   this.sharedState = useService("shared_state");
   const value = this.sharedState.getValue("somekey");
   // do something with value
}

2. クイックナビゲーションのボタンを追加する

Odoo が提供する重要なサービスは action サービスです。Odoo が定義するすべての標準的なアクションを実行できます。 例えば、あるコンポーネントが xml id でアクションを実行する方法は次のとおりです。

import { useService } from "@web/core/utils/hooks";
...
setup() {
      this.action = useService("action");
}
openSettings() {
      this.action.doAction("base_setup.action_general_configuration");
}
...

次に、コントロールパネルに 2 つのボタンを追加します。

  1. すべての顧客とのカンバン ビューを開くボタン Customers (このアクションは既に存在するため、its xml id) を使用する必要があります。

  2. Leads`ボタン。`crm.lead`モデルでは、リストとフォームビューを持つ動的なアクションを開きます。 `action service のこの使用例に従ってください。

../../../_images/navigation_buttons.png

3. ダッシュボード項目を追加

では、コンテンツを改善しましょう。

  1. デフォルトのスロットを素敵なカードレイアウトで表示する汎用の DashboardItem コンポーネントを作成します。 デフォルトは 1 で、オプションの size 数値プロパティを使用します。幅は (18*size)rem にハードコードする必要があります。

  2. ダッシュボードに2枚のカードを追加します。1枚はサイズがなく、もう1枚は2枚です。

../../../_images/dashboard_item.png

4. サーバーを呼び出し、統計情報を追加します

ダッシュボードにいくつかのダッシュボード項目を追加して、*実際の*ビジネスデータを表示することでダッシュボードを改善しましょう。 awesome_dashboard addon は、興味深い情報を返すための /awesome_dashboard/statistics ルートを提供します。

To call a specific controller, we need to use the rpc function. It only exports a single function that perform the request: rpc(route, params, settings). A basic request could look like this:

import { rpc } from "@web/core/network/rpc";
// ...

setup() {
   onWillStart(async () => {
      const result = await rpc("/my/controller", {a: 1, b: 2});
   })
   // ...
}
  1. ダッシュボード`を更新して、`rpc`関数を使用し、統計ルート/awesome_dashboard/statistics`を呼び出します。

  2. ダッシュボードにいくつかのカードを表示します。

    • Number of new orders this month

    • 今月の新規注文合計

    • 今月の平均Tシャツの注文数

    • キャンセルされた注文の月数

    • 「新規」から「送信」または「キャンセル」への注文の平均時間

../../../_images/statistics.png

関連項目

コード: rpc

5. ネットワーク通話のキャッシュ、サービスの作成

ブラウザの開発ツールの Network タブを開くと、 クライアントアクションが表示されるたびに、/awesome_dashboard/statistics の呼び出しが行われます。 これは、Dashboard コンポーネントがマウントされるたびに、onWillStart フックが呼び出されるためです。 しかし、この場合、私たちは最初にそれを行うことを好むでしょう。 ですから、実際には`ダッシュボード`コンポーネントの外側にある状態を維持する必要があります。 これはサービスのための素敵なユースケースです!

  1. awesome_dashboard.statistics サービスを登録してインポートします。

  2. 呼び出された関数`loadStatistics`を提供し、実際のrpcを実行し、常に同じ情報を返す必要があります。

  3. 統計をキャッシュすることを可能にする`@web/core/utils/functions`の`memoize <https://github.com/odoo/odoo/blob/1f4e583ba20a01f4c44b0a4ada42c4d3bb074273/ addons/web/static/src/core/utils/functions.js#L11>`_ utility関数`@web/core/utils/functions`を使います。

  4. ダッシュボード コンポーネントでこのサービスを使用します。

  5. 期待どおりに動作することを確認してください。

6. 円グラフを表示

誰もがチャート(!)が好きなので、私たちのダッシュボードで円グラフを追加しましょう。 S/M/L/XL/XXLというサイズごとに販売されているTシャツの比率が表示されます。

この課題では、Chart.js を使用します。グラフビューで使用されているチャートライブラリです。 ただし、デフォルトではロードされていないため、アセットバンドルに追加するか、遅延ロードする必要があります。 ユーザーがチャートjsコードを必要としない場合は、毎回チャートjsコードをロードする必要がないため、遅延ロードは通常より良いです。

  1. PieChart コンポーネントを作成します。

  2. onWillStart メソッドでチャートをロードします。loadJs 関数を使用して、 /web/static/lib/Chart/Chart.js をロードできます。

  3. DashboardItem 内の PieChart コンポーネントを使用して、販売されている各Tシャツの枚数をそれぞれのサイズで表示する 円グラフ を表示します(この情報は /statistics ルートで利用可能です)。 size プロパティを使うと、大きく見えるようになります。

  4. `PieChart`コンポーネントはキャンバスを描画し、`chart.js`を使用して描画する必要があります。

  5. うまくいくようにしよう!

../../../_images/pie_chart.png

7. 実際の耐用年数の更新

データの読み込みをキャッシュに移動したので、更新はありません。 しかし、私たちは速い移動データを見ているので、定期的に(例えば、10分ごとに)新鮮なデータをリロードしたいと思います。

これは統計サービスに`setTimeout`または`setInterval`を使って実装するのはとても簡単です。 ただし、ここでは難しい部分です:ダッシュボードが現在表示されている場合は、すぐに更新する必要があります。

これを行うには、 reactive オブジェクトを使用できます。これは、 useState が返すプロキシと同じですが、どのコンポーネントにもリンクされていません。 コンポーネントはその変更を受け取るために useState を実行できます。

  1. 統計情報サービスを更新して、10分ごとにデータを再読み込みします(テストするには10秒を代わりに使用してください)

  2. reactive オブジェクトを返すように修正します。データをリロードする場合は、その場所でリアクティブオブジェクトを更新する必要があります。

  3. Dashboard コンポーネントが useState で使用できるようになりました。

関連項目

8. ダッシュボードを読み込んでいます

私たちのダッシュボードはかなり大きくなってきており、一部のユーザーにとってのみ関心があると考えてみましょう。 その場合、私たちのダッシュボードと関連するすべての資産を遅延ロードすることは意味があります。 コードを読み込むのにかかる費用は実際に見たいときだけです

これを行う一つの方法は、 LazyComponent (`@web/core/assets`から) をコンポーネントを表示する前にアセットバンドルをロードする中間として使用することです。

Example

example_action.js:

export class ExampleComponentLoader extends Component {
    static components = { LazyComponent };
    static template = xml`
        <LazyComponent bundle="'example_module.example_assets'" Component="'ExampleComponent'" />
    `;
}

registry.category("actions").add("example_module.example_action", ExampleComponentLoader);
  1. すべてのダッシュボードアセットをサブフォルダ /dashboard に移動して、バンドルに簡単に追加できます。

  2. /dashboard フォルダのすべての内容を含む awesome_dashboard.dashboard アセットバンドルを作成します。

  3. :file:の dashboard.js を変更して、 actions の代わりに lazy_components レジストリに登録します。

  4. :file:`src/dashboard_action.js`で、`LazyComponent`を使用して中間コンポーネントを作成し、それを`actions`レジストリに登録します。

9. ダッシュボードを一般的にする

これまでのところ、私たちは素晴らしい作業ダッシュボードを持っていますが、現在はダッシュボードテンプレートでハードコードされています。 ダッシュボードをカスタマイズしたい場合はどうなりますか? ユーザーによってはニーズが異なり、他のデータを見たいユーザーもいるかもしれません。

次のステップは、ダッシュボードを一般的にすることです。テンプレート内のコンテンツをハードコーディングする代わりに。 ダッシュボードの項目のリストを繰り返すだけです しかし、ダッシュボードアイテムの表示方法、登録方法、受信するデータなど、多くの質問が出てきます。 このようなシステムを設計するには、さまざまなトレードオフがあります。

このチュートリアルでは、ダッシュボード項目は以下の構造を持つオブジェクトであると言います。

const item = {
   id: "average_quantity",
   description: "Average amount of t-shirt",
   Component: StandardItem,
   // size and props are optionals
   size: 3,
   props: (data) => ({
      title: "Average amount of t-shirt by order this month",
      value: data.average_quantity
   }),
};

description の値は、ユーザーがダッシュボードに追加できる項目の名前を表示するために、後で練習するときに役立ちます。 size`番号は任意で、表示されるダッシュボードアイテムのサイズを簡単に説明します。 最後に、 `props 関数は任意です。指定しない場合は、 statistics オブジェクトをデータとして渡します。 しかし、定義されている場合は、コンポーネントの特定の props を計算するために使用されます。

目標は、ダッシュボードの内容を次のスニペットに置き換えることです。

<t t-foreach="items" t-as="item" t-key="item.id">
   <DashboardItem size="item.size || 1">
      <t t-set="itemProp" t-value="item.props ? item.props(statistics) : {'data': statistics}"/>
      <t t-component="item.Component" t-props="itemProp" />
   </DashboardItem>
</t>

上記の例では、動的コンポーネントと動的プロップの 2 つの高度な機能を備えています。

現在、アイテムコンポーネントには2種類あります:タイトルと数字のあるナンバーカード。 パイカードにラベルと円グラフが付いています

  1. NumberCardPieChartCard の 2 つのコンポーネントを作成し、実装します。

  2. dashboard_items.js ファイルを作成し、アイテムのリストを定義してエクスポートします。NumberCardPieChartCard を使用して現在のダッシュボードを再作成します。

  3. ダッシュボード コンポーネント内のアイテムのリストをインポートし、コンポーネントに追加し、テンプレートを更新して上記のように t-foreach を使用します。

    setup() {
       this.items = items;
    }
    

ダッシュボードテンプレートは一般的です!

10. ダッシュボードを拡張可能にする

ただし、アイテムリストの内容はまだハードコードされています。レジストリを使用して修正してみましょう:

  1. リストをエクスポートする代わりに、awesome_dashboard レジストリにすべてのダッシュボード項目を登録します

  2. `ダッシュボード`コンポーネントに`awesome_dashboard`レジストリのすべての項目をインポートします

ダッシュボードは簡単に拡張可能になりました。 ダッシュボードに新しいアイテムを登録したい他のOdooアドオンは、レジストリに追加するだけです。

11. ダッシュボードアイテムの追加と削除

ダッシュボードをカスタマイズ可能にする方法を見てみましょう。 簡単にするために、ユーザーダッシュボードの設定をローカルストレージに保存し、永続化します。 でも今のところはサーバーを扱う必要はない

ダッシュボードの設定は、削除されたアイテムIDのリストとして保存されます。

  1. コントロールパネルにギアアイコンを表示するボタンを追加し、設定ボタンであることを示します。

  2. そのボタンをクリックするとダイアログが開きます。

  3. このダイアログには、すべての既存のダッシュボードアイテムのリストが表示され、それぞれにチェックボックスが表示されます。

  4. フッターに`Apply`ボタンがあります。クリックすると、チェックされていない全てのアイテムIDのリストが作成されます。

  5. その値をローカルストレージに保存したいと考えています。

  6. また、構成からアイテムの id を削除することで、Dashboard コンポーネントを変更して、現在のアイテムをフィルタリングします。

../../../_images/items_configuration.png

12.さらに進む

以下は、時間があればやってみることができるいくつかの小さな改善点のリストです:

  1. アプリケーションが translated (env._t) であることを確認してください。

  2. 円グラフのセクションをクリックすると、対応するサイズの注文がすべてリスト表示されます。

  3. ダッシュボードの内容をユーザー設定のサーバーに保存します!

  4. モバイルモードでは、各カードの幅が100%かかる必要があります。