mcpField
I
integrate-file-viewer

integrate-file-viewer

github.com/cognitedata開発337 回インストール
リポジトリ

integrate-file-viewer について

Dune アプリに CogniteFileViewer を追加し、CDF ファイルをプレビューするためのスキルです。依存関係や Vite、PDF.js worker の設定と、対応形式や操作方法を説明します。

主な機能

  1. 01ビューアー依存関係の導入
  2. 02PDF.js worker の設定
  3. 03Vite の pdfjs-dist 事前バンドル除外
  4. 04PDF、Office、画像、テキストのプレビュー
  5. 05ズーム、パン、注釈への対応

活用シーン

  1. 01Dune アプリへのファイルプレビュー追加
  2. 02CDF Document Preview API による Office 文書の表示
  3. 03注釈から関連ファイルへの移動

MCP 対応

ビューアーは Dune SDK を使って CDF ファイルにアクセスします。Office 文書は CDF Document Preview API で変換されます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/cognitedata/dune-skills --skill integrate-file-viewer

インストール後、Claude Code で/integrate-file-viewerを入力して読み込まれたか確認します。

詳細

CogniteFileViewer の統合

この Dune アプリに CogniteFileViewer を追加し、CDF ファイル(PDF、画像、テキスト)をプレビューできるようにします。

作業内容

以下の手順を順番に実施してください。変更を加える前に、各ファイルを読み込んでください。


手順 1 — アプリを理解する

作業に取りかかる前に、以下のファイルを読み込んでください。

  • package.json — パッケージマネージャー(packageManager フィールドまたはロックファイル)と既存の依存関係を確認します
  • vite.config.ts — 現在の Vite 設定を確認します
  • ビューアーを追加するコンポーネント

手順 2 — 依存関係をインストールする

  • pnpm → pnpm add "github:cognitedata/dune-industrial-components#semver:*" react-pdf
  • npm → npm install "github:cognitedata/dune-industrial-components#semver:*" react-pdf
  • yarn → yarn add "github:cognitedata/dune-industrial-components#semver:*" react-pdf

pdfjs-dist は適切なバージョンが react-pdf の依存関係として含まれています。別途インストールしないでください。


手順 3 — PDF.js ワーカーを設定する

利用側のアプリで PDF.js ワーカーを設定する必要があります。これにより、ワーカーのバージョンが、インストールした react-pdf に含まれる pdfjs-dist のバージョンと一致します。

CogniteFileViewer を使用するファイルと同じファイルに、次の設定を追加してください(モジュールの実行順序が重要です)。

import { pdfjs } from 'react-pdf';

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
  'pdfjs-dist/build/pdf.worker.min.mjs',
  import.meta.url,
).toString();

pnpm を使用する場合: pnpm の厳密なリンク設定により、ブラウザーから pdfjs-dist を解決できないことがあります。その場合は、pdfjs-dist を直接の依存関係として追加する(pnpm add pdfjs-dist)か、.npmrc に public-hoist-pattern[]=pdfjs-dist を追加してください。


手順 4 — Vite を設定する

Vite が pdfjs-dist を事前バンドルしないように(ワーカーが正常に動作しなくなるため)、vite.config.ts に optimizeDeps.exclude: ['pdfjs-dist'] を追加してください。

export default defineConfig({
  // ... existing config ...
  optimizeDeps: {
    exclude: ['pdfjs-dist'],
  },
});

手順 5 — コンポーネントを使用する

ファイルのプレビューが必要な箇所で、CogniteFileViewer をインポートしてレンダリングしてください。

import { CogniteFileViewer } from '@cognite/dune-industrial-components/file-viewer';

sdk は、すべての Dune アプリで使用できる useDune() フックから取得します。

import { useDune } from '@cognite/dune';
const { sdk } = useDune();
サポートされているファイル形式
種類形式
PDF.pdf — ページ移動、ズーム、パン、図面への注釈オーバーレイ
Office ドキュメントWord、PowerPoint、Excel、ODS、ODP、ODT、RTF、TSV — CDF Document Preview API を介して PDF に変換され、PDF と同様にレンダリングされます
画像JPEG、PNG、WebP、SVG、TIFF — ズーム、パン、回転
テキスト.txt、.csv、.json — 書式を保持したテキストとしてレンダリングされます
その他renderUnsupported にフォールバックします
最小限の使用例

必要な設定はこれだけです。ズーム、パン、タッチ操作は内部で処理されます。

<CogniteFileViewer
  source={{ type: 'internalId', id: file.id }}
  client={sdk}
  style={{ width: '100%', height: '600px' }}
/>

コンポーネントには高さの設定が必要です。 親要素に明示的な高さがない場合、ビューアーの高さは 0 になります。必ず style、className、または親コンテナーで height を設定してください。

ファイルソース

以下の 3 種類のソースのいずれかを渡してください。

// By instance ID (data-modelled file — enables annotations)
<CogniteFileViewer
  source={{ type: 'instanceId', space: 'my-space', externalId: 'my-file' }}
  client={sdk}
/>

// By CDF internal ID
<CogniteFileViewer
  source={{ type: 'internalId', id: 12345 }}
  client={sdk}
/>

// By direct URL
<CogniteFileViewer
  source={{ type: 'url', url: 'https://...', mimeType: 'application/pdf' }}
/>

可能であれば instanceId を使用してください。 図面への注釈オーバーレイを有効にできるのは、このソースタイプだけです。sdk.files.list() でファイルを一覧表示する際は、まず file.instanceId を確認してください。

source={
  file.instanceId
    ? { type: 'instanceId', space: file.instanceId.space, externalId: file.instanceId.externalId }
    : { type: 'internalId', id: file.id }
}
props の全項目
<CogniteFileViewer
  // Required
  source={source}
  client={sdk}              // required for instanceId and internalId sources

  // PDF pagination
  page={page}               // controlled current page (1-indexed)
  onPageChange={setPage}
  onDocumentLoad={({ numPages }) => setNumPages(numPages)}

  // Zoom & pan (works on PDF and images)
  zoom={zoom}               // 1 = 100%; Ctrl/Cmd+wheel, pinch-to-zoom, and middle-click drag built in
  onZoomChange={setZoom}
  minZoom={0.25}            // default
  maxZoom={5}               // default
  panOffset={pan}           // controlled pan offset; resets on page change
  onPanChange={setPan}

  // Fit mode
  fitMode="width"           // 'width' fits to container width; 'page' fits entire page in container

  // Rotation (PDFs and images)
  rotation={rotation}       // 0 | 90 | 180 | 270

  // Diagram annotations (instanceId sources only)
  showAnnotations={true}    // default
  onAnnotationClick={(annotation) => { /* annotation.linkedResource has space + externalId */ }}
  onAnnotationHover={(annotation) => {}}

  // Custom annotation tooltip (replaces native <title> tooltip)
  renderAnnotationTooltip={(annotation, rect) => (
    <div style={{
      position: 'absolute',
      left: rect.x + rect.width,
      top: rect.y,
      zIndex: 11,
    }}>
      {annotation.text}
    </div>
  )}

  // Custom overlay (SVG paths, highlights, drawings — works on PDF and images)
  renderOverlay={({ width, height, originalWidth, originalHeight, pageNumber, rotation }) => (
    <svg
      width={width}
      height={height}
      viewBox={`0 0 ${originalWidth} ${originalHeight}`}
      preserveAspectRatio="none"
      style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'all' }}
    >
      <path d="..." stroke="cyan" fill="none" />
    </svg>
  )}

  // Custom renderers (all optional)
  renderLoading={() => <MySpinner />}
  renderError={(error) => <MyError message={error.message} />}
  renderUnsupported={(mimeType) => <div>Cannot preview {mimeType}</div>}

  // Layout
  className="..."
  style={{ width: '100%', height: '100%' }}
/>

ヒントとコツ

ソースが変わったら、ページ、ズーム、回転をリセットします。 ファイルを切り替えても、コンポーネントはこれらを自動的にリセットしません。手動で行ってください。

const navigateToFile = (file: FileInfo) => {
  setSelectedFile(file);
  setPage(1);
  setZoom(1);
  setRotation(0);
};

numPages > 0 の場合にページネーション UI を表示します。 onDocumentLoad は PDF の場合にのみ実行されます。ページ数がわかるまでは、ページネーションコントロールを表示しないでください。

{numPages > 0 && (
  <>
    <button disabled={page <= 1} onClick={() => setPage(p => p - 1)}>‹</button>
    <span>{page} / {numPages}</span>
    <button disabled={page >= numPages} onClick={() => setPage(p => p + 1)}>›</button>
  </>
)}

アノテーションのクリックから、リンク先のファイルに移動します。 annotation.linkedResource には、リンク先の CDF インスタンスの space と externalId が含まれています。これらを file.instanceId と照合して移動します。

onAnnotationClick={(annotation) => {
  if (!annotation.linkedResource) return;
  const { space, externalId } = annotation.linkedResource;
  const linked = files.find(
    f => f.instanceId?.space === space && f.instanceId?.externalId === externalId
  );
  if (linked) navigateToFile(linked);
}}

タッチ操作に標準対応しています。 タッチデバイスでは、2 本指でのピンチによるズームと、2 本指でのドラッグによるパンが自動的に機能します。設定は不要です。

デスクトップでは、パンは中クリックでドラッグして行います(ズームイン時)。左クリックはアノテーションのクリックやテキストの選択に使用できます。

Ctrl/Cmd + ホイールでカーソル位置に向かってズームします。こちらも標準機能です。プログラムによるズームボタンを追加したり、ズーム状態を保持したりする場合は、zoom/onZoomChange を接続してください。それ以外の場合は、完全に非制御で動作します。

renderOverlay には元のページ寸法(originalWidth、originalHeight)が渡されるため、元の座標空間で SVG の viewBox を設定できます。PDF ポイントまたは画像ピクセル単位で描画したパスは、ズームレベルにかかわらず、レンダリングされたページに正しく対応します。


よくある問題

問題原因解決方法
Failed to resolve module specifier 'pdf.worker.mjs'ワーカーが設定されていませんCogniteFileViewer を使用するファイルに、手順 3 のワーカー設定を追加します
API version does not match Worker versionアプリと react-pdf の間で pdfjs-dist のバージョンが一致していませんpdfjs-dist を個別にインストールせず、react-pdf が提供するものを使用します。すでにインストール済みの場合は削除してください
アノテーションがまったく表示されませんinstanceId が undefined です。指定されていない場合、アノテーションオーバーレイは無効になりますinstanceId のソースを使用するか、従来形式のファイルではアノテーションが表示されないことを許容して代替方法を使用します
アノテーションは表示されますが、中身が空ですファイルに CDF の CogniteDiagramAnnotation エッジがありません想定される動作です。アノテーションがあるのは、データモデルに同期された P&ID/図面ファイルのみです
ビューアーの高さがゼロになります親要素に明示的な高さがありませんstyle、className、または親要素の CSS で height を設定します

コメント