Files
plugin-legal-ai/src/ui/types.ts
Chaim Marcus f70023fccc feat(ui): Phase 2 — issue detail tab + dashboard widget
Plugin now mounts two React components inside Paperclip via the
SDK's UI slot mechanism. Both are read-only views over data the
plugin worker fetches from legal-ai on demand.

## Slots

* **LegalCaseTab** (type: detailTab, entityTypes: ["issue"])
  Mounted as a "ערר" tab on every issue page. Shows case summary
  (status / practice_area / appeal_subtype), legal_arguments
  grouped by party (עוררים/ועדה/משיבה/מבקשי היתר), attached
  precedents, and open missing_precedents.

* **LegalCasesWidget** (type: dashboardWidget)
  Dashboard tile with case counts by status + 7-day activity.

## Worker handlers (ctx.data.register)

Five handlers added at the end of setup() — all read-only over the
existing legal-ai HTTP API, all wrapped in try/catch so a transient
failure shows a placeholder instead of crashing the host:

- legal-case-summary           → /api/cases/{n}/details
- legal-case-arguments         → /api/cases/{n}/legal-arguments
- legal-case-precedents        → /api/cases/{n}/precedents
- legal-case-missing-precedents → /api/missing-precedents?case_number=&status=open
- legal-dashboard-stats        → in-memory aggregation over /api/cases

case_number is resolved from plugin state (scopeKind=issue,
stateKey=legal-case-number) — populated by legal_case_create.

## Build pipeline

- esbuild.ui.config.mjs uses createPluginBundlerPresets from the SDK
  to build src/ui/index.tsx → dist/ui/index.js (13.5kb, react +
  @paperclipai/plugin-sdk/ui externalized)
- package.json: build = "build:worker" (tsc) + "build:ui" (esbuild)
- tsconfig.json: jsx=react-jsx, lib += DOM
- New deps: react@19, @types/react, esbuild

## Manifest

- capabilities += ui.detailTab.register, ui.dashboardWidget.register
- entrypoints.ui = "dist/ui"
- ui.slots declared with entityTypes (not "entities" — fixed against
  PluginUiSlotDeclaration validator)

## Verified

- tsc + esbuild + biome clean
- Plugin re-installs (20 capabilities) and activates with worker
  + 8 tools + 3 jobs + 1 webhook + 2 event subs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 14:04:40 +00:00

73 lines
1.6 KiB
TypeScript

/**
* Shared types for the legal-ai plugin UI bundle.
*
* Mirrors a minimal subset of the legal-ai backend response shapes so the UI
* components can type their props/data without pulling the full LegalApi
* client (which is a worker-side dependency).
*/
export interface LegalCaseSummary {
case_number: string;
title: string;
status: string;
practice_area?: string | null;
appeal_subtype?: string | null;
proceeding_type?: string | null;
updated_at?: string | null;
archived_at?: string | null;
}
export interface LegalCaseDetails {
id: string;
case_number: string;
title: string;
status: string;
practice_area?: string | null;
appeal_subtype?: string | null;
appellants?: string[];
respondents?: string[];
subject?: string;
property_address?: string;
expected_outcome?: string;
[key: string]: unknown;
}
export interface LegalArgument {
id?: string;
party: string;
argument_title?: string;
argument_body?: string;
claim_index?: number;
[key: string]: unknown;
}
export interface LegalArgumentsResponse {
case_number: string;
total: number;
by_party: Record<string, LegalArgument[]>;
arguments: LegalArgument[];
}
export interface PrecedentRow {
id: string;
citation: string;
section_id?: string | null;
practice_area?: string | null;
[key: string]: unknown;
}
export interface MissingPrecedentRow {
id: string;
citation: string;
status: string;
legal_topic?: string | null;
cited_by_party?: string | null;
[key: string]: unknown;
}
export interface DashboardStats {
byStatus: Record<string, number>;
weekActivity: number;
totalCases: number;
}