Documentation
Open app

Artifact surfaces

An artifact surface owns the body of a durable side-panel view. Declare a stable app-namespaced artifactKind; Core uses it to resolve the current native module in that app lane when the app opens the artifact.

YAML
contributes:
  ui:
    - id: report-viewer
      kind: nativeModule
      surface: artifact
      slot: artifact.slot.reports-viewer
      artifactKind: reports.viewer
      module:
        entry: dist/ui/app.js
        export: ReportViewer
        styles: dist/ui/app.css
TSX
import { useAppContext } from '@sota/platform';

type ArtifactProps = {
  artifact: { artifactKind: string; context?: Record<string, unknown> };
};

export function ReportViewer({ artifact }: ArtifactProps) {
  const { ui } = useAppContext();
  const title = typeof artifact.context?.title === 'string'
    ? artifact.context.title
    : 'Report';
  return (
    <article>
      <h1>{title}</h1>
      <button type="button" onClick={ui.closeArtifact}>Close</button>
    </article>
  );
}

Open it from any surface in the same app lane with useAppContext().ui.openArtifact('reports.viewer', context). The lane's current app renders the opaque artifact.context; apps own compatibility with payloads created by earlier releases. Artifact kinds must be unique for the resolved workspace; the core.* namespace is reserved.

TSX
import { useAppContext } from '@sota/platform';

export function OpenReportButton({ reportId }: { reportId: string }) {
  const { ui } = useAppContext();
  return (
    <button type="button" onClick={() => ui.openArtifact('reports.viewer', {
      reportId,
      title: 'Quarterly report',
    })}>
      Open report
    </button>
  );
}

Validate artifact.context before using it; it is structural transport data, not a substitute for loading authoritative records from the app backend.

Contents

Esc

Search titles and body text across every chapter.