CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-backstage--plugin-catalog-react

A frontend library that helps other Backstage plugins interact with the catalog through React components, hooks, and utilities.

Pending
Overview
Eval results
Files

alpha-features.mddocs/

Alpha Features

Extension system functions for creating custom entity cards and content extensions in the new Backstage frontend system. These features are experimental and subject to change.

Capabilities

Extension Data References

Alpha features define extension data references for the new frontend system.

/**
 * Extension data reference for entity content titles
 * @alpha
 */
const entityContentTitleExtensionDataRef: ExtensionDataRef<string>;

/**
 * Extension data reference for entity filters  
 * @alpha
 */
const entityFilterExtensionDataRef: ExtensionDataRef<
  (ctx: { entity: Entity }) => boolean
>;

Entity Card Extensions

Function for creating custom entity card extensions that can be displayed in entity overviews.

/**
 * Creates an entity card extension for the new frontend system
 * @param options - Configuration for the entity card extension
 * @returns Extension instance for the card
 * @alpha
 */
function createEntityCardExtension<TInputs extends AnyExtensionInputMap>(
  options: EntityCardExtensionOptions<TInputs>
): Extension<any>;

interface EntityCardExtensionOptions<TInputs extends AnyExtensionInputMap> {
  /** Unique identifier for the extension */
  id: string;
  
  /** Where to attach this extension (default: entity.content.overview cards) */
  attachTo?: { id: string; input: string };
  
  /** Whether the extension is disabled by default */
  disabled?: boolean;
  
  /** Extension inputs for dependency injection */
  inputs?: TInputs;
  
  /** Filter function to determine when card should be shown */
  filter?: (ctx: { entity: Entity }) => boolean;
  
  /** Loader function that returns the card component */
  loader: (options: {
    inputs: Expand<ExtensionInputValues<TInputs>>;
  }) => Promise<JSX.Element>;
}

Usage Examples:

import { createEntityCardExtension } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';

// Basic entity card extension
const myEntityCardExtension = createEntityCardExtension({
  id: 'my-entity-card',
  filter: ({ entity }: { entity: Entity }) => entity.kind === 'component',
  loader: async () => {
    // Dynamically import your card component
    const { MyEntityCard } = await import('./MyEntityCard');
    return <MyEntityCard />;
  },
});

// Card with custom filter and attachment
const apiDocumentationCardExtension = createEntityCardExtension({
  id: 'api-documentation-card',
  attachTo: {
    id: 'entity.content.overview',
    input: 'cards'
  },
  filter: ({ entity }: { entity: Entity }) => 
    entity.kind === 'api' && entity.spec?.definition,
  loader: async ({ inputs }) => {
    const { ApiDocumentationCard } = await import('./ApiDocumentationCard');
    return <ApiDocumentationCard inputs={inputs} />;
  },
});

// Card with inputs for dependency injection
const metricsCardExtension = createEntityCardExtension({
  id: 'metrics-card',
  inputs: {
    metricsApi: metricsApiRef,
  },
  filter: ({ entity }: { entity: Entity }) => 
    entity.kind === 'component' && entity.spec?.type === 'service',
  loader: async ({ inputs }) => {
    const { MetricsCard } = await import('./MetricsCard');
    return <MetricsCard metricsApi={inputs.metricsApi} />;
  },
});

Entity Content Extensions

Function for creating custom entity content pages that appear as tabs in entity views.

/**
 * Creates an entity content extension for the new frontend system
 * @param options - Configuration for the entity content extension
 * @returns Extension instance for the content page
 * @alpha
 */
function createEntityContentExtension<TInputs extends AnyExtensionInputMap>(
  options: EntityContentExtensionOptions<TInputs>
): Extension<any>;

interface EntityContentExtensionOptions<TInputs extends AnyExtensionInputMap> {
  /** Unique identifier for the extension */
  id: string;
  
  /** Where to attach this extension (default: plugin.catalog.page.entity contents) */
  attachTo?: { id: string; input: string };
  
  /** Whether the extension is disabled by default */
  disabled?: boolean;
  
  /** Extension inputs for dependency injection */
  inputs?: TInputs;
  
  /** Route reference for the content page */
  routeRef?: RouteRef;
  
  /** Default path for the content tab */
  defaultPath: string;
  
  /** Default title for the content tab */
  defaultTitle: string;
  
  /** Filter function to determine when content should be shown */
  filter?: (ctx: { entity: Entity }) => boolean;
  
  /** Loader function that returns the content component */
  loader: (options: {
    inputs: Expand<ExtensionInputValues<TInputs>>;
  }) => Promise<JSX.Element>;
}

Usage Examples:

import { createEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
import { Entity } from '@backstage/catalog-model';

// Basic entity content extension
const deploymentContentExtension = createEntityContentExtension({
  id: 'deployment-content',
  defaultPath: '/deployments',
  defaultTitle: 'Deployments',
  filter: ({ entity }: { entity: Entity }) => 
    entity.kind === 'component' && entity.spec?.type === 'service',
  loader: async () => {
    const { DeploymentContent } = await import('./DeploymentContent');
    return <DeploymentContent />;
  },
});

// Content extension with custom route and inputs
const monitoringContentExtension = createEntityContentExtension({
  id: 'monitoring-content',
  defaultPath: '/monitoring',
  defaultTitle: 'Monitoring',
  routeRef: monitoringRouteRef,
  inputs: {
    monitoringApi: monitoringApiRef,
  },
  filter: ({ entity }: { entity: Entity }) => 
    entity.kind === 'component' && 
    entity.metadata.annotations?.['monitoring.io/dashboard'],
  loader: async ({ inputs }) => {
    const { MonitoringContent } = await import('./MonitoringContent');
    return <MonitoringContent monitoringApi={inputs.monitoringApi} />;
  },
});

// API-specific content extension
const apiSpecContentExtension = createEntityContentExtension({
  id: 'api-spec-content',
  defaultPath: '/spec',
  defaultTitle: 'API Spec',
  filter: ({ entity }: { entity: Entity }) => 
    entity.kind === 'api' && entity.spec?.definition,
  loader: async () => {
    const { ApiSpecContent } = await import('./ApiSpecContent');
    return <ApiSpecContent />;
  },
});

Re-exported Utilities

Alpha features also re-export some utility functions for convenience.

/**
 * Re-exported from utils module
 * @alpha
 */
function isOwnerOf(owner: Entity, entity: Entity): boolean;

/**
 * Re-exported from hooks module  
 * Hook for checking permissions on the current entity in context
 * @alpha
 */
function useEntityPermission(
  permission: ResourcePermission<'catalog-entity'>
): {
  loading: boolean;
  allowed: boolean;
  error?: Error;
};

Usage Examples:

import { 
  isOwnerOf, 
  useEntityPermission 
} from '@backstage/plugin-catalog-react/alpha';
import { catalogEntityDeletePermission } from '@backstage/plugin-catalog-common';

function EntityActionsCard() {
  const { entity } = useEntity();
  const currentUser = useCurrentUser();
  
  const canDelete = useEntityPermission(
    catalogEntityDeletePermission
  );
  
  const isOwner = isOwnerOf(currentUser, entity);
  
  return (
    <div>
      <h3>Actions</h3>
      {isOwner && <button>Edit</button>}
      {canDelete.allowed && !canDelete.loading && (
        <button>Delete</button>
      )}
    </div>
  );
}

Extension Registration

Extensions need to be registered with the Backstage app:

// In your app-config or plugin configuration
import { 
  myEntityCardExtension,
  deploymentContentExtension 
} from './extensions';

const app = createApp({
  extensions: [
    myEntityCardExtension,
    deploymentContentExtension,
    // ... other extensions
  ],
});

Configuration Schema

Extensions support configuration through the app-config system:

// Extension with configuration
const configurableCardExtension = createEntityCardExtension({
  id: 'configurable-card',
  // Configuration is automatically generated with filters
  loader: async () => {
    const { ConfigurableCard } = await import('./ConfigurableCard');
    return <ConfigurableCard />;
  },
});

Configuration in app-config.yaml:

extensions:
  - entity.cards.configurable-card:
      filter:
        - isKind: component
        - isType: service
      disabled: false

Migration from Legacy System

Alpha extensions provide a migration path from the legacy plugin system:

// Legacy approach (deprecated)
export const EntityPage = () => (
  <EntityLayout>
    <EntityLayout.Route path="/" title="Overview">
      <Grid container spacing={3}>
        <Grid item xs={12} md={6}>
          <EntityAboutCard />
        </Grid>
        <Grid item xs={12} md={6}>
          <MyCustomCard />
        </Grid>
      </Grid>
    </EntityLayout.Route>
  </EntityLayout>
);

// New alpha approach
const myCustomCardExtension = createEntityCardExtension({
  id: 'my-custom-card',
  loader: async () => {
    const { MyCustomCard } = await import('./MyCustomCard');
    return <MyCustomCard />;
  },
});

Important Notes

  • Alpha Status: These features are experimental and may change
  • Performance: Extensions are lazy-loaded for better performance
  • Filtering: Both configuration-based and code-based filtering supported
  • Dependencies: Use inputs for dependency injection
  • Testing: Extensions can be tested using the standard Backstage testing utilities

Install with Tessl CLI

npx tessl i tessl/npm-backstage--plugin-catalog-react

docs

alpha-features.md

api-integration.md

entity-display.md

entity-filters.md

entity-hooks.md

index.md

picker-components.md

utilities.md

tile.json