コンテンツへスキップ
Pivotick
Main Navigation ホーム
はじめに
設定
生成された API ドキュメント
ギャラリープロジェクト試してみる!

日本語

English
简体中文
Français
Deutsch
Português
Nederlands
العربية
Español

日本語

English
简体中文
Français
Deutsch
Português
Nederlands
العربية
Español

外観

Sidebar Navigation

はじめに

Pivotick を使ったプロジェクト

設定

コールバック

エッジレイヤー

簡略化

レイアウト

描画

シミュレーション

UI のカスタマイズ

サイドバー

ツールチップ

コンテキストメニュー

フィルター

凡例

データ表

UI のスタイル

UI の翻訳

プラグイン

Pivotick API

ピボットとデータ拡充

ピボット結果の保存

元に戻す操作と履歴

セキュリティ

API ドキュメント

ギャラリー

基本

ノードのスタイル

エッジのスタイル

レイアウト

イベントとコールバック

UI のカスタマイズ

編集と作成

メモと注釈

フィルター・検索・階層

プログラムによる制御

テーマとパフォーマンス

ピボットとデータ拡充

注目のサンプル

拒否して再試行 ​

フェッチ後に何が起こるか。トリアージ カウントは 3 つの異なる理由で移動します。 プロバイダーに障害が発生しても、それは行き止まりではなく、回復できる状態です。

P を押し、mail.example をクリックして、相関 を取得します。

  • 5 行を拒否し、再実行します。 ヘッダーは 40 fetched · 5 rejected earlier となります。 拒否はセッション中に記憶され、ピボットごとにキー設定されるため、ルールを設定した行は 戻ってくるのをやめてください。セグメントをクリックして表示し、復元します。
  • 3 つ摂取して、再度実行します。 これで、次のようになります。 40 fetched · 3 already on canvas (skipped) · 5 rejected earlier。 3 つの理由を 1 行にまとめます。
  • プロバイダーを閉じても何も拒否されません。「レビュー」タブのその行には×が付いています。のみ 選択を拒否 および 残りすべてを拒否 は決定です。あなたが一度も支配したことのないものはすべて 再び提供されました。
  • 失敗した要約 には、パネルではなく 1 つのエントリがかかります: 評判検索 は、 Couldn't reach the source.、再試行。
  • 失敗したフェッチ がペインに表示されます: フィードからの強化 が開きます Couldn't fetch candidates. ステージには何もありません。

どちらのプロバイダーも、最初の Retry で回復します。スローはエラー プロトコル全体です。

js
// The other card is about getting a number *down* before you fetch it. This one is about
// everything after the fetch: a triage count moves for three different reasons, and a
// provider that fails is a state you can recover from rather than a dead end.

/**
 * Stable ids matter here. A rejection is remembered as (pivot, candidate id), so a
 * provider that renumbers its results on every call can never be usefully rejected:
 * the same row comes back wearing a new id, and the memory has nothing to match.
 */
const indicators = (count, prefix, type) =>
    Array.from({ length: count }, (_, i) => ({
        id: `${prefix}-${i}`,
        data: { label: `${prefix} ${String(i).padStart(2, '0')}`, type },
    }))

/** Fan a result set out from whichever node the pivot was run on. */
const fanOut = (nodes, found, fallback) => {
    const origin = nodes[0]?.id ?? fallback
    return { nodes: found, edges: found.map((node) => ({ from: origin, to: node.id })) }
}

// 1. The reliable one. Forty candidates, the same forty every time, so rejecting five
// and running again demonstrates something.
const correlations = {
    id: 'correlations',
    label: 'Correlations',
    appliesTo: (nodes) => nodes.every((node) => node.getData()?.type !== 'case'),
    // No facets: narrowing is the other card's subject, and forty rows need none.
    summarize: () => ({ total: 40 }),
    fetch: (nodes) => fanOut(nodes, indicators(40, 'ind', 'indicator'), 'mail.example'),
}

// Both providers below fail on their first call and work on every one after it. The
// failure is deterministic so the card can promise it.
let feedCalls = 0
let reputationCalls = 0

// 2. The fetch fails. `summarize` is fine, so the entry looks healthy and the failure
// only appears once you commit to the expensive call: the pane's own error state.
const feed = {
    id: 'feed',
    label: 'Enrich from feed',
    appliesTo: (nodes) => nodes.every((node) => node.getData()?.type !== 'case'),
    summarize: () => ({ total: 18 }),
    fetch: (nodes) => {
        if (++feedCalls === 1) throw new Error('feed.example timed out (504)')
        return fanOut(nodes, indicators(18, 'feed', 'feed'), 'mail.example')
    },
}

// 3. The summary fails. This one is broken before you touch it, so its entry carries the
// error the moment the mode opens. Retry re-asks, and nothing else on the panel cares.
const reputation = {
    id: 'reputation',
    label: 'Reputation lookup',
    appliesTo: (nodes) => nodes.every((node) => node.getData()?.type !== 'case'),
    summarize: () => {
        if (++reputationCalls === 1) throw new Error('reputation.example refused the connection')
        return { total: 6 }
    },
    fetch: (nodes) => fanOut(nodes, indicators(6, 'rep', 'reputation'), 'mail.example'),
}

const options = {
    pivots: [correlations, feed, reputation],
    UI: {
        mode: 'full',
        sidebar: { collapsed: true },
        // The dock is the subject of this card, but it still starts folded: a staged
        // set unfolds it by itself. Its height is set explicitly, because the default
        // share leaves the candidate table too short to read.
        minimap: false,
        table: { open: false },
        dock: { height: 380 },
    },
    render: {
        defaultNodeStyle: {
            size: 8,
            color: (node) => ({
                case: '#bf616a', domain: '#ebcb8b', ip: '#88c0d0', hash: '#b48ead',
                indicator: '#8fbcbb', feed: '#a3be8c', reputation: '#d08770',
            }[node.getData()?.type] ?? '#8f9aa8'),
        },
    },
}
js
// One case and the three indicators already attached to it. Everything else in this card
// arrives through a pivot, and most of it gets thrown away again.
const data = {
    nodes: [
        // Declared first because it is the one to pivot from. Every `appliesTo` below
        // excludes the case node, so an origin of `Case 77` finds nothing to offer.
        { id: 'mail.example', data: { label: 'mail.example', type: 'domain' } },
        { id: 'case-77', data: { label: 'Case 77', type: 'case' } },
        { id: '203.0.113.9', data: { label: '203.0.113.9', type: 'ip' } },
        { id: 'a1b2c3d4', data: { label: 'a1b2c3d4…', type: 'hash' } },
    ],
    edges: [
        { from: 'case-77', to: 'mail.example' },
        { from: 'case-77', to: '203.0.113.9' },
        { from: '203.0.113.9', to: 'a1b2c3d4' },
    ],
}

完全なリファレンス: ピボットとエンリッチメント。

Pager
次のページはじめに