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
yarn --cwd packages/app add @drodil/backstage-plugin-toolbox
Expose the page in your app
// 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
// 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
// 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
// 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
// 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
// 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
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
// 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
yarn --cwd packages/backend add @drodil/backstage-plugin-toolbox-backend
Create a plugin wiring file
// 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
// 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
/api/toolboxPlugin/health
Add optional translations if you need them
// 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
// 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
// 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
Breaking changes
- None
Set up Backstage in minutes with Roadie
Focus on using Backstage, rather than building and maintaining it.