Toolbox logo

Backstage Toolbox Plugin

Created by drodil

Toolbox is a collection of everyday developer tools that live inside Backstage. It brings common utilities into one place so your team can work without switching between random web apps.

The plugin ships with practical tools for daily work. You can convert data between JSON YAML CSV. Encode or decode strings including Base64 and HTML entities. Parse and inspect URLs. Generate and scan QR and barcode content. Decode JWTs. Compare text with a diff view. Work with colors. Calculate CIDR ranges and SLA uptime. Validate Backstage entities with the catalog. Check IBANs. Explore strings with analyzers. Create CSRs for certificates. It covers a lot of small but frequent tasks.

You can tailor it for your company. Add your own tools with simple React components or the provided blueprint. Group tools by category. Add aliases for better search. Mark favorites. Open a tool in a new window. Bookmark a specific tool. Translate labels to your language when needed.

Some tools run fully in the browser. Others can use an optional backend for tasks that need a server such as whois. There is also a home page card so teams can pin a preferred tool on the Backstage start view.

If you want fewer tabs and fewer context switches, Toolbox helps keep the basics close at hand.

Installation Instructions

These instructions apply to self-hosted Backstage only.

Run these from your Backstage root

Copy
yarn --cwd packages/app add @drodil/backstage-plugin-toolbox

Expose the page in your app

Copy
// packages/app/src/App.tsx
import React, { PropsWithChildren } from 'react';
import { FlatRoutes } from '@backstage/core-app-api';
import { Route } from 'react-router';
import { ToolboxPage } from '@drodil/backstage-plugin-toolbox';

const AppRoutes = () => (
  <FlatRoutes>
    {/* other routes */}
    <Route path="/toolbox" element={<ToolboxPage />} />
  </FlatRoutes>
);

export default AppRoutes;

Add a link in the sidebar

Copy
// packages/app/src/components/Root/Root.tsx
import React, { PropsWithChildren } from 'react';
import CardTravel from '@mui/icons-material/CardTravel';
import {
  SidebarPage,
  SidebarItem,
} from '@backstage/core-components';

export const Root = ({ children }: PropsWithChildren<{}>) => (
  <SidebarPage>
    {/* your other sidebar items */}
    <SidebarItem icon={CardTravel} to="toolbox" text="ToolBox" />
    {children}
  </SidebarPage>
);

Add optional tools to the page if you want to extend it

Copy
// packages/app/src/App.tsx
import React from 'react';
import { ToolboxPage, Tool } from '@drodil/backstage-plugin-toolbox';

const MyExtraTool: Tool = {
  name: 'Extra',
  component: <div>Extra tool</div>,
};

export const AppRoutes = () => (
  <FlatRoutes>
    <Route
      path="/toolbox"
      element={<ToolboxPage extraTools={[MyExtraTool]} />}
    />
  </FlatRoutes>
);

Lazy load your own tool for better load time

Copy
// packages/app/src/components/tools/MyTool.tsx
import React from 'react';

export default function MyTool() {
  return <div>My lazy tool</div>;
}

// packages/app/src/App.tsx
import React, { lazy } from 'react';
import { ToolboxPage, Tool } from '@drodil/backstage-plugin-toolbox';

const MyTool = lazy(() => import('./components/tools/MyTool'));

const extraTool: Tool = {
  name: 'Extra',
  component: <MyTool />,
};

<FlatRoutes>
  <Route path="/toolbox" element={<ToolboxPage extraTools={[extraTool]} />} />
</FlatRoutes>;

Use the new frontend system if your app uses the new plugin API

Copy
// an app module file in packages/app for example packages/app/src/plugins/toolbox.ts
import React from 'react';
import { createFrontendModule } from '@backstage/frontend-plugin-api';
import { ToolboxToolBlueprint } from '@drodil/backstage-plugin-toolbox/alpha';

// small helper because examples in docs wrap lazies this way
const compatWrapper = (node: React.ReactNode) => <>{node}</>;

const base64EncodeTool = ToolboxToolBlueprint.make({
  name: 'base64-encode',
  params: {
    id: 'base64-encode',
    displayName: 'Base64',
    description: 'Encode and decode base64 strings',
    category: 'Encode/Decode',
    async loader() {
      const m = await import('./components/Encoders/Base64Encode');
      return compatWrapper(<m.default />);
    },
  },
});

export default createFrontendModule({
  pluginId: 'toolbox',
  extensions: [base64EncodeTool],
});

Add the toolbox card to a custom home page if you use the home plugin

Copy
// packages/app/src/components/home/HomePage.tsx
import React from 'react';
import { CustomHomepageGrid } from '@backstage/plugin-home';
import { ToolboxHomepageCard } from '@drodil/backstage-plugin-toolbox';
import { Content, Page } from '@backstage/core-components';

export const HomePage = () => (
  <Page themeId="home">
    <Content>
      <CustomHomepageGrid>
        <ToolboxHomepageCard />
      </CustomHomepageGrid>
    </Content>
  </Page>
);

Install the backend for tools that need server side work using the new backend system

Copy
yarn --cwd packages/backend add @drodil/backstage-plugin-toolbox-backend @drodil/backstage-plugin-toolbox-backend-module-whois

Wire it in with the new backend system

Copy
// packages/backend/src/index.ts
import { createBackend } from '@backstage/backend-defaults';

const backend = createBackend();

// other backend.add lines for your app
backend.add(import('@drodil/backstage-plugin-toolbox-backend'));

// optional extra module that adds whois lookups to the toolbox backend
backend.add(import('@drodil/backstage-plugin-toolbox-backend-module-whois'));

backend.start();

Install the backend using the old backend system if your app still uses the legacy backend

Copy
yarn --cwd packages/backend add @drodil/backstage-plugin-toolbox-backend

Create a plugin wiring file

Copy
// packages/backend/src/plugins/toolbox.ts
import { Router } from 'express';
import { Logger } from 'winston';
import { createRouter } from '@drodil/backstage-plugin-toolbox-backend';

// align this signature with your local PluginEnvironment type
type PluginEnv = {
  logger: Logger;
  // add other fields from your env if you have them
};

export default async function createPlugin(env: PluginEnv): Promise<Router> {
  // the toolbox backend only needs a logger in its default setup
  return await createRouter({ logger: env.logger });
}

Mount it under the api router

Copy
// packages/backend/src/index.ts
import toolbox from './plugins/toolbox';

// inside the main bootstrap where you build apiRouter
// apiRouter already mounts under /api
apiRouter.use('/toolboxPlugin', await toolbox(env));

The backend now serves a health endpoint at this path

Copy
/api/toolboxPlugin/health

Add optional translations if you need them

Copy
// packages/app/src/locales/toolbox-fi.ts
import { toolboxTranslationRef } from '@drodil/backstage-plugin-toolbox';
import { createTranslationMessages } from '@backstage/core-plugin-api/alpha';

const fi = createTranslationMessages({
  ref: toolboxTranslationRef,
  full: false,
  translations: {
    'toolsPage.title': 'Työkalut',
    'welcomePage.introText': 'Käytä työkaluja helposti',
  },
});

export default fi;

Register the translation resource in your app

Copy
// packages/app/src/App.tsx
import { createTranslationResource } from '@backstage/core-plugin-api/alpha';
import { toolboxTranslationRef } from '@drodil/backstage-plugin-toolbox';

const app = createApp({
  // other options
  __experimentalTranslations: {
    availableLanguages: ['en', 'fi'],
    resources: [
      createTranslationResource({
        ref: toolboxTranslationRef,
        translations: {
          fi: () => import('./locales/toolbox-fi'),
        },
      }),
    ],
  },
});

Use the predefined translations that ship with the plugin if they cover your language

Copy
// packages/app/src/App.tsx
import { toolboxTranslations } from '@drodil/backstage-plugin-toolbox';

const app = createApp({
  // other options
  __experimentalTranslations: {
    availableLanguages: ['en', 'fi'],
    resources: [toolboxTranslations],
  },
});

That is it for setup on both the frontend and the backend. The page path in the app is /toolbox. The backend health path is under api/toolboxPlugin/health when using the legacy backend. The new backend system handles the api path for you.

Changelog

This changelog is produced from commits made to the Toolbox plugin since a month ago, and based on the code located here. It may not contain information about all commits. Releases and version bumps are intentionally omitted. This changelog is generated by AI.

Features

  • CSR generator
    Add an alert that reminds you to download the key after you create a CSR. Add optional OU in the subject field. Add optional email address. Add RSA 2048 SHA2 as a new key type. #183 merged 1 month ago

Bug fixes

  • Fix an extra blank line before the footer in base64 output when the length is an exact multiple of 64. #183 merged 1 month ago

Dependencies

  • Bump sha.js to 2.4.12. #179 merged 1 month ago
  • Bump cipher base to 1.0.6. #180 merged 1 month ago

Breaking changes

  • None

Set up Backstage in minutes with Roadie