# ComponentInstaller

`ComponentInstaller` は、他の Blocklet に依存する機能のゲートキーパーとして機能するユーティリティコンポーネントです。指定されたコンポーネントの依存関係がインストールされているかどうかを検証します。インストールされていない場合、管理者（デフォルトでは `owner` または `admin` ロール）が直接インストールするためのユーザーフレンドリーなインターフェースを提供します。ユーザーが必要な権限を持っていない場合は、管理者に連絡するよう促すメッセージを表示します。

このコンポーネントは、不足しているオプションの依存関係を適切に処理できる堅牢なアプリケーションを作成するために不可欠であり、管理者をインストールプロセスを通じてガイドすることでユーザーエクスペリエンスを向上させます。

## 仕組み

このコンポーネントのロジックは、子コンポーネントをレンダリングする前に依存関係が満たされていることを確認するため、明確で順次的なプロセスに従います。

<!-- DIAGRAM_IMAGE_START:flowchart:4:3:1765962229 -->
![ComponentInstaller](assets/diagram/component-installer-diagram-0.ja.jpg)
<!-- DIAGRAM_IMAGE_END -->

1.  **依存関係のチェック**: `did` プロパティを読み取り、Blocklet のメタデータ（`window.blocklet.optionalComponents`）と照合して、必要なコンポーネントがインストールされているかどうかを判断します。
2.  **権限チェック**: 不足しているコンポーネントがある場合、`SessionPermission` コンポーネントを使用して、現在のユーザーのロールが `roles` プロパティで指定されたものと一致するかどうかを検証します。
3.  **条件付きレンダリング**:
    *   すべての依存関係がインストールされている場合、その `children` をレンダリングします。
    *   依存関係が不足しており、ユーザーに権限がある場合、ポップアップのインストールパネルを表示します。
    *   依存関係が不足しており、ユーザーに権限がない場合、管理者に連絡するよう提案を表示するか、`noPermissionMute` が有効な場合は `fallback` コンポーネントをレンダリングします。

## 基本的な使い方

オプションの Blocklet に依存するコンポーネントや機能を `ComponentInstaller` でラップします。必要なコンポーネントの DID を提供してください。

```jsx "MyFeature.jsx" icon=logos:react
import ComponentInstaller from '@arcblock/blocklet-ui-react/lib/ComponentInstaller';
import MyDependentComponent from './MyDependentComponent';

export default function MyFeature() {
  // 必要なコンポーネントの実際の DID に置き換えてください
  const requiredComponentDid = 'z8ia2427634f1e909a304e2b963715a18';

  return (
    <ComponentInstaller did={requiredComponentDid}>
      {/* このコンポーネントは依存関係が満たされている場合にのみレンダリングされます */}
      <MyDependentComponent />
    </ComponentInstaller>
  );
}
```

## Props

`ComponentInstaller` は、その動作をカスタマイズするために以下の props を受け入れます。

<x-field-group>
  <x-field data-name="did" data-type="string | string[]" data-required="true">
    <x-field-desc markdown>チェックするコンポーネントの依存関係の DID（または DID の配列）。これは、必要な Blocklet の主要な識別子です。</x-field-desc>
  </x-field>
  <x-field data-name="children" data-type="any" data-required="true">
    <x-field-desc markdown>すべての依存関係がインストールされていることを確認した後にレンダリングするコンテンツ。標準の React ノードまたはレンダー関数を指定できます。</x-field-desc>
  </x-field>
  <x-field data-name="roles" data-type="string[]" data-default='["owner", "admin"]'>
    <x-field-desc markdown>インストール UI を表示し、不足しているコンポーネントをインストールすることが許可されているユーザーロールの配列。</x-field-desc>
  </x-field>
  <x-field data-name="fallback" data-type="React.ReactNode" data-required="false">
    <x-field-desc markdown>依存関係をチェックしている間、またはインストール権限のないユーザーに対して `noPermissionMute` が有効な場合に表示するフォールバックコンポーネント。</x-field-desc>
  </x-field>
  <x-field data-name="noPermissionMute" data-type="boolean" data-default="false">
    <x-field-desc markdown>`true` の場合、権限のないユーザーには「管理者に連絡」メッセージの代わりに `fallback` コンポーネント（または何も表示しない）が表示されます。</x-field-desc>
  </x-field>
  <x-field data-name="disabled" data-type="boolean" data-default="false">
    <x-field-desc markdown>`true` の場合、コンポーネントはすべてのチェックをバイパスし、即座にその `children` をレンダリングします。</x-field-desc>
  </x-field>
  <x-field data-name="onInstalled" data-type="function" data-required="false">
    <x-field-desc markdown>依存関係のチェックが完了した後にトリガーされるコールバック関数。インストール済みのコンポーネントのリストを受け取ります。</x-field-desc>
  </x-field>
  <x-field data-name="onError" data-type="function" data-required="false">
    <x-field-desc markdown>依存関係のチェック中にエラーが発生した場合にトリガーされるコールバック関数。エラーの原因となったコンポーネントのリストを受け取ります。</x-field-desc>
  </x-field>
  <x-field data-name="onClose" data-type="function" data-required="false">
    <x-field-desc markdown>インストールのポップアップが閉じられたときに呼び出されるコールバック関数。</x-field-desc>
  </x-field>
  <x-field data-name="closeByOutSize" data-type="boolean" data-default="false">
    <x-field-desc markdown>`true` の場合、ユーザーがポップアップの外側をクリックすると、インストールのポップアップが閉じます。</x-field-desc>
  </x-field>
  <x-field data-name="warnIcon" data-type="React.ReactNode" data-required="false">
    <x-field-desc markdown>インストールのポップアップのデフォルトの警告アイコンを置き換えるためのカスタム React ノード。</x-field-desc>
  </x-field>
</x-field-group>

## 高度な使い方

### 複数のコンポーネントのチェック

`did` プロパティに DID の配列を渡すことで、複数の依存関係を一度にチェックできます。指定されたすべてのコンポーネントがインストールされている場合にのみ、子はレンダリングされます。

```jsx "MyDashboard.jsx" icon=logos:react
import ComponentInstaller from '@arcblock/blocklet-ui-react/lib/ComponentInstaller';
import AnalyticsWidget from './AnalyticsWidget';
import CmsWidget from './CmsWidget';

export default function MyDashboard() {
  const requiredDids = [
    'z8ia2427634f1e909a304e2b963715a18', // 分析サービス
    'z8ia3c1f2e4b8e6a1b2c3d4e5f6a7b8c9', // CMS サービス
  ];

  return (
    <ComponentInstaller did={requiredDids}>
      <AnalyticsWidget />
      <CmsWidget />
    </ComponentInstaller>
  );
}
```

### ローディング状態のためのフォールバックの使用

依存関係のチェックが進行中の間、`fallback` コンポーネントを提供してユーザーエクスペリエンスを向上させます。これは、`noPermissionMute` と共に使用して、権限のないユーザーにプレースホルダーを表示する場合にも役立ちます。

```jsx "FeatureWithLoading.jsx" icon=logos:react
import ComponentInstaller from '@arcblock/blocklet-ui-react/lib/ComponentInstaller';
import CircularProgress from '@mui/material/CircularProgress';
import Box from '@mui/material/Box';
import MyDependentComponent from './MyDependentComponent';

export default function FeatureWithLoading() {
  const LoadingSpinner = (
    <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}>
      <CircularProgress />
    </Box>
  );

  return (
    <ComponentInstaller
      did="z8ia2427634f1e909a304e2b963715a18"
      fallback={LoadingSpinner}
      noPermissionMute={true}
    >
      <MyDependentComponent />
    </ComponentInstaller>
  );
}
```

### レンダープロップによるカスタム UI

UI を完全に制御するために、`children` として関数を渡すことができます。この関数は `hasPermission`、`optComponents`、および `installStatus` を含むオブジェクトを受け取り、完全にカスタムのインストールインターフェースを構築することができます。

```jsx "CustomInstallerButton.jsx" icon=logos:react
import ComponentInstaller from '@arcblock/blocklet-ui-react/lib/ComponentInstaller';
import Button from '@mui/material/Button';

export default function CustomInstallerButton() {
  const requiredDid = 'z8ia2427634f1e909a304e2b963715a18';

  return (
    <ComponentInstaller did={requiredDid}>
      {({ hasPermission, optComponents, installStatus }) => {
        const isMissing = optComponents.length > 0;
        const status = installStatus[requiredDid] || 'not_installed';

        if (!isMissing) {
          return <p>Feature is ready to use!</p>;
        }

        if (!hasPermission) {
          return <p>Please ask an admin to install the required component.</p>;
        }

        return (
          <Button
            variant="contained"
            disabled={status !== 'not_installed'}
            onClick={() => window.open(optComponents[0].installUrl, '_blank')}
          >
            {status === 'not_installed' ? `Install ${optComponents[0].meta.title}` : `Installing... (${status})`}
          </Button>
        );
      }}
    </ComponentInstaller>
  );
}
```

## まとめ

`ComponentInstaller` は、Blocklet アプリケーション内でオプションの依存関係を管理するための強力なコンポーネントです。必要なコンポーネントが利用可能であることを保証するための構造化されたユーザーフレンドリーな方法を提供し、必要に応じて管理者をインストールプロセスを通じてガイドします。このコンポーネントを使用することで、ユーザーの環境に適応する、より回復力があり機能豊富なアプリケーションを構築できます。

コンポーネントの管理に関する詳細については、リソースとコンポーネント管理のためのより包括的なインターフェースを提供する [BlockletStudio](./components-component-management-blocklet-studio.md) コンポーネントにも興味があるかもしれません。