Merge pull request #31055 from secustor/feat/add-devtools-extension
feat(devtools): support custom tabs using extensions
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
---
|
||||
'@backstage/plugin-catalog-unprocessed-entities': patch
|
||||
'@backstage/plugin-devtools-react': minor
|
||||
'@backstage/plugin-devtools': patch
|
||||
'@backstage/plugin-devtools-backend': patch
|
||||
'@backstage/plugin-devtools-common': patch
|
||||
---
|
||||
|
||||
Add support for adding `unprocessed-entities` and other tabs to `devtools` when using the New Frontend system
|
||||
@@ -114,6 +114,11 @@ app:
|
||||
# - entity-content:azure-devops/pull-requests
|
||||
# - entity-content:azure-devops/git-tags
|
||||
|
||||
# Enable the catalog-unprocessed-entities tab in devtools
|
||||
- devtools-content:catalog-unprocessed-entities: true
|
||||
# Disable the catalog-unprocessed-entities element outside devtools
|
||||
- page:catalog-unprocessed-entities: false
|
||||
|
||||
# scmAuthExtension: >-
|
||||
# createScmAuthExtension({
|
||||
# id: 'apis.scmAuth.addons.ghe',
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
"@backstage/plugin-catalog-import": "workspace:^",
|
||||
"@backstage/plugin-catalog-react": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^",
|
||||
"@backstage/plugin-devtools": "workspace:^",
|
||||
"@backstage/plugin-home": "workspace:^",
|
||||
"@backstage/plugin-kubernetes": "workspace:^",
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^",
|
||||
|
||||
@@ -45,6 +45,8 @@ import { convertLegacyPageExtension } from '@backstage/core-compat-api';
|
||||
import { convertLegacyEntityContentExtension } from '@backstage/plugin-catalog-react/alpha';
|
||||
import { pluginInfoResolver } from './pluginInfoResolver';
|
||||
import { appModuleNav } from './modules/appModuleNav';
|
||||
import devtoolsPlugin from '@backstage/plugin-devtools/alpha';
|
||||
import { unprocessedEntitiesDevToolsContent } from '@backstage/plugin-catalog-unprocessed-entities/alpha';
|
||||
|
||||
/*
|
||||
|
||||
@@ -116,6 +118,11 @@ const notFoundErrorPageModule = createFrontendModule({
|
||||
extensions: [notFoundErrorPage],
|
||||
});
|
||||
|
||||
const devtoolsPluginUnprocessed = createFrontendModule({
|
||||
pluginId: 'catalog-unprocessed-entities',
|
||||
extensions: [unprocessedEntitiesDevToolsContent],
|
||||
});
|
||||
|
||||
const collectedLegacyPlugins = convertLegacyAppRoot(
|
||||
<FlatRoutes>
|
||||
<Route path="/catalog-import" element={<CatalogImportPage />} />
|
||||
@@ -133,6 +140,8 @@ const app = createApp({
|
||||
notFoundErrorPageModule,
|
||||
appModuleNav,
|
||||
customHomePageModule,
|
||||
devtoolsPlugin,
|
||||
devtoolsPluginUnprocessed,
|
||||
...collectedLegacyPlugins,
|
||||
],
|
||||
advanced: {
|
||||
|
||||
@@ -52,18 +52,36 @@ Import `catalogUnprocessedEntitiesPlugin` in your `App.tsx` and add it to your a
|
||||
|
||||
```typescript
|
||||
import catalogUnprocessedEntitiesPlugin from '@backstage/plugin-catalog-unprocessed-entities';
|
||||
import { unprocessedEntitiesDevToolsContent } from '@backstage/plugin-catalog-unprocessed-entities/alpha';
|
||||
|
||||
// ...
|
||||
// Optionally add unprocessed entities route to devtools
|
||||
const devtoolsPluginUnprocessed = createFrontendModule({
|
||||
pluginId: 'catalog-unprocessed-entities',
|
||||
extensions: [unprocessedEntitiesDevToolsContent],
|
||||
});
|
||||
|
||||
export const app = createApp({
|
||||
features: [
|
||||
// ...
|
||||
catalogUnprocessedEntitiesPlugin,
|
||||
|
||||
// Optionally add unprocessed entities route to devtools
|
||||
devtoolsPluginUnprocessed,
|
||||
devtoolsPlugin, // devtools plugin needs to be added too, if autodiscover is disabled
|
||||
// ...
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
```yaml
|
||||
app:
|
||||
extensions:
|
||||
# Enable the catalog-unprocessed-entities tab in devtools
|
||||
- devtools-content:catalog-unprocessed-entities: true
|
||||
# Disable the catalog-unprocessed-entities element outside devtools including the sidebar
|
||||
- page:catalog-unprocessed-entities: false
|
||||
```
|
||||
|
||||
## Customization
|
||||
|
||||
If you want to use the provided endpoints in a different way, you can use the ApiRef doing the following:
|
||||
|
||||
@@ -50,11 +50,13 @@
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-compat-api": "workspace:^",
|
||||
"@backstage/core-components": "workspace:^",
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-catalog-unprocessed-entities-common": "workspace:^",
|
||||
"@backstage/plugin-devtools-react": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.60",
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
|
||||
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
|
||||
import { ApiFactory } from '@backstage/frontend-plugin-api';
|
||||
import { DevToolsContentBlueprintParams } from '@backstage/plugin-devtools-react';
|
||||
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { IconComponent } from '@backstage/frontend-plugin-api';
|
||||
@@ -89,5 +90,32 @@ const _default: OverridableFrontendPlugin<
|
||||
>;
|
||||
export default _default;
|
||||
|
||||
// @alpha
|
||||
export const unprocessedEntitiesDevToolsContent: OverridableExtensionDefinition<{
|
||||
kind: 'devtools-content';
|
||||
name: undefined;
|
||||
config: {
|
||||
path: string | undefined;
|
||||
title: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
};
|
||||
output:
|
||||
| ExtensionDataRef<string, 'core.routing.path', {}>
|
||||
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
|
||||
| ExtensionDataRef<
|
||||
RouteRef_2<AnyRouteRefParams>,
|
||||
'core.routing.ref',
|
||||
{
|
||||
optional: true;
|
||||
}
|
||||
>
|
||||
| ExtensionDataRef<string, 'core.title', {}>;
|
||||
inputs: {};
|
||||
params: DevToolsContentBlueprintParams;
|
||||
}>;
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
```
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DevToolsContentBlueprint } from '@backstage/plugin-devtools-react';
|
||||
|
||||
/**
|
||||
* DevTools content for catalog unprocessed entities.
|
||||
*
|
||||
* @alpha
|
||||
*/
|
||||
export const unprocessedEntitiesDevToolsContent = DevToolsContentBlueprint.make(
|
||||
{
|
||||
disabled: true,
|
||||
params: {
|
||||
path: 'unprocessed-entities',
|
||||
title: 'Unprocessed Entities',
|
||||
loader: () =>
|
||||
import('../components/UnprocessedEntities').then(m => (
|
||||
<m.UnprocessedEntitiesContent />
|
||||
)),
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -15,3 +15,4 @@
|
||||
*/
|
||||
|
||||
export { default } from './plugin';
|
||||
export { unprocessedEntitiesDevToolsContent } from './devToolsContent';
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
"pluginPackages": [
|
||||
"@backstage/plugin-devtools",
|
||||
"@backstage/plugin-devtools-backend",
|
||||
"@backstage/plugin-devtools-common"
|
||||
"@backstage/plugin-devtools-common",
|
||||
"@backstage/plugin-devtools-react"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"pluginPackages": [
|
||||
"@backstage/plugin-devtools",
|
||||
"@backstage/plugin-devtools-backend",
|
||||
"@backstage/plugin-devtools-common"
|
||||
"@backstage/plugin-devtools-common",
|
||||
"@backstage/plugin-devtools-react"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
|
||||
@@ -0,0 +1,5 @@
|
||||
# @backstage/plugin-devtools-react
|
||||
|
||||
Welcome to the web library package for the `devtools` plugin!
|
||||
|
||||
_This plugin was created through the Backstage CLI_
|
||||
@@ -0,0 +1,10 @@
|
||||
apiVersion: backstage.io/v1alpha1
|
||||
kind: Component
|
||||
metadata:
|
||||
name: backstage-plugin-devtools-react
|
||||
title: '@backstage/plugin-devtools-react'
|
||||
description: Web library for the devtools plugin
|
||||
spec:
|
||||
lifecycle: experimental
|
||||
type: backstage-web-library
|
||||
owner: maintainers
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "@backstage/plugin-devtools-react",
|
||||
"version": "0.0.0",
|
||||
"description": "Web library for the devtools plugin",
|
||||
"backstage": {
|
||||
"role": "web-library",
|
||||
"pluginId": "devtools",
|
||||
"pluginPackages": [
|
||||
"@backstage/plugin-devtools",
|
||||
"@backstage/plugin-devtools-backend",
|
||||
"@backstage/plugin-devtools-common",
|
||||
"@backstage/plugin-devtools-react"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"main": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/backstage/backstage",
|
||||
"directory": "plugins/devtools-react"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"sideEffects": false,
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "backstage-cli package build",
|
||||
"clean": "backstage-cli package clean",
|
||||
"lint": "backstage-cli package lint",
|
||||
"prepack": "backstage-cli package prepack",
|
||||
"postpack": "backstage-cli package postpack",
|
||||
"start": "backstage-cli package start",
|
||||
"test": "backstage-cli package test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@backstage/core-plugin-api": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
"@backstage/test-utils": "workspace:^",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@types/react": "^18.0.0",
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.0 || ^18.0.0",
|
||||
"react": "^17.0.0 || ^18.0.0",
|
||||
"react-dom": "^17.0.0 || ^18.0.0",
|
||||
"react-router-dom": "^6.3.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
## API Report File for "@backstage/plugin-devtools-react"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { RouteRef } from '@backstage/frontend-plugin-api';
|
||||
|
||||
// @public
|
||||
export const DevToolsContentBlueprint: ExtensionBlueprint<{
|
||||
kind: 'devtools-content';
|
||||
params: DevToolsContentBlueprintParams;
|
||||
output:
|
||||
| ExtensionDataRef<string, 'core.routing.path', {}>
|
||||
| ExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
|
||||
| ExtensionDataRef<
|
||||
RouteRef<AnyRouteRefParams>,
|
||||
'core.routing.ref',
|
||||
{
|
||||
optional: true;
|
||||
}
|
||||
>
|
||||
| ExtensionDataRef<string, 'core.title', {}>;
|
||||
inputs: {};
|
||||
config: {
|
||||
path: string | undefined;
|
||||
title: string | undefined;
|
||||
};
|
||||
configInput: {
|
||||
title?: string | undefined;
|
||||
path?: string | undefined;
|
||||
};
|
||||
dataRefs: never;
|
||||
}>;
|
||||
|
||||
// @public
|
||||
export interface DevToolsContentBlueprintParams {
|
||||
// (undocumented)
|
||||
loader: () => Promise<JSX_2.Element>;
|
||||
// (undocumented)
|
||||
path: string;
|
||||
// (undocumented)
|
||||
routeRef?: RouteRef;
|
||||
// (undocumented)
|
||||
title: string;
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2024 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
coreExtensionData,
|
||||
createExtensionBlueprint,
|
||||
ExtensionBoundary,
|
||||
RouteRef,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
import { JSX } from 'react';
|
||||
|
||||
/**
|
||||
* Parameters for creating a DevTools route extension
|
||||
* @public
|
||||
*/
|
||||
export interface DevToolsContentBlueprintParams {
|
||||
path: string;
|
||||
title: string;
|
||||
loader: () => Promise<JSX.Element>;
|
||||
routeRef?: RouteRef;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension blueprint for creating DevTools content pages (appearing as tabs)
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* const myDevToolsContent = DevToolsContentBlueprint.make({
|
||||
* {
|
||||
* params: {
|
||||
* path: 'my-dev-tools',
|
||||
* title: 'My DevTools',
|
||||
* loader: () =>
|
||||
* import('../components/MyDevTools').then(m =>
|
||||
* compatWrapper(<m.MyDevTools />),
|
||||
* ),
|
||||
* },
|
||||
* },
|
||||
* });
|
||||
* ```
|
||||
* @public
|
||||
*/
|
||||
export const DevToolsContentBlueprint = createExtensionBlueprint({
|
||||
kind: 'devtools-content',
|
||||
attachTo: { id: 'page:devtools', input: 'contents' },
|
||||
output: [
|
||||
coreExtensionData.reactElement,
|
||||
coreExtensionData.routePath,
|
||||
coreExtensionData.routeRef.optional(),
|
||||
coreExtensionData.title,
|
||||
],
|
||||
config: {
|
||||
schema: {
|
||||
path: z => z.string().optional(),
|
||||
title: z => z.string().optional(),
|
||||
},
|
||||
},
|
||||
*factory(params: DevToolsContentBlueprintParams, { node, config }) {
|
||||
const path = config.path ?? params.path;
|
||||
const title = config.title ?? params.title;
|
||||
|
||||
yield coreExtensionData.reactElement(
|
||||
ExtensionBoundary.lazy(node, params.loader),
|
||||
);
|
||||
|
||||
yield coreExtensionData.routePath(path);
|
||||
|
||||
yield coreExtensionData.title(title);
|
||||
|
||||
if (params.routeRef) {
|
||||
yield coreExtensionData.routeRef(params.routeRef);
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2025 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Web library for the devtools plugin.
|
||||
*
|
||||
* @packageDocumentation
|
||||
*/
|
||||
export {
|
||||
type DevToolsContentBlueprintParams,
|
||||
DevToolsContentBlueprint,
|
||||
} from './devToolsContentBlueprint';
|
||||
@@ -166,6 +166,39 @@ You can also add tabs to show content from other plugins that fit well with the
|
||||
|
||||
#### Catalog Unprocessed Entities Tab
|
||||
|
||||
##### New Frontend System
|
||||
|
||||
Create an extension and/or load a 3rd party extension to add additional tabs.
|
||||
|
||||
```shell
|
||||
yarn --cwd plugins/<your-plugin> add @backstage/plugin-devtools-react
|
||||
```
|
||||
|
||||
```tsx
|
||||
import { DevToolsContentBlueprint } from '@backstage/plugin-devtools-react';
|
||||
|
||||
export const unprocessedEntitiesDevToolsContent = DevToolsContentBlueprint.make(
|
||||
{
|
||||
disabled: true,
|
||||
params: {
|
||||
path: 'unprocessed-entities',
|
||||
title: 'Unprocessed Entities',
|
||||
loader: () =>
|
||||
import('../components/UnprocessedEntities').then(m => (
|
||||
<m.UnprocessedEntitiesContent />
|
||||
)),
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const appFeature = createFrontendModule({
|
||||
pluginId: 'catalog-unprocessed-entities',
|
||||
extensions: [unprocessedEntitiesDevToolsContent],
|
||||
});
|
||||
```
|
||||
|
||||
##### Old System
|
||||
|
||||
Here's how to add the Catalog Unprocessed Entities tab:
|
||||
|
||||
1. Install and setup the [Catalog Unprocessed Entities plugin](https://github.com/backstage/backstage/tree/master/plugins/catalog-unprocessed-entities) as per its documentation
|
||||
|
||||
@@ -7,7 +7,8 @@
|
||||
"pluginPackages": [
|
||||
"@backstage/plugin-devtools",
|
||||
"@backstage/plugin-devtools-backend",
|
||||
"@backstage/plugin-devtools-common"
|
||||
"@backstage/plugin-devtools-common",
|
||||
"@backstage/plugin-devtools-react"
|
||||
]
|
||||
},
|
||||
"publishConfig": {
|
||||
@@ -58,6 +59,7 @@
|
||||
"@backstage/errors": "workspace:^",
|
||||
"@backstage/frontend-plugin-api": "workspace:^",
|
||||
"@backstage/plugin-devtools-common": "workspace:^",
|
||||
"@backstage/plugin-devtools-react": "workspace:^",
|
||||
"@backstage/plugin-permission-react": "workspace:^",
|
||||
"@material-ui/core": "^4.9.13",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
import { AnyApiFactory } from '@backstage/frontend-plugin-api';
|
||||
import { AnyRouteRefParams } from '@backstage/frontend-plugin-api';
|
||||
import { ApiFactory } from '@backstage/frontend-plugin-api';
|
||||
import { ConfigurableExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionBlueprintParams } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionDataRef } from '@backstage/frontend-plugin-api';
|
||||
import { ExtensionInput } from '@backstage/frontend-plugin-api';
|
||||
import { IconComponent } from '@backstage/frontend-plugin-api';
|
||||
import { JSX as JSX_2 } from 'react';
|
||||
import { OverridableExtensionDefinition } from '@backstage/frontend-plugin-api';
|
||||
@@ -59,8 +61,6 @@ const _default: OverridableFrontendPlugin<
|
||||
};
|
||||
}>;
|
||||
'page:devtools': OverridableExtensionDefinition<{
|
||||
kind: 'page';
|
||||
name: undefined;
|
||||
config: {
|
||||
path: string | undefined;
|
||||
};
|
||||
@@ -77,7 +77,26 @@ const _default: OverridableFrontendPlugin<
|
||||
optional: true;
|
||||
}
|
||||
>;
|
||||
inputs: {};
|
||||
inputs: {
|
||||
contents: ExtensionInput<
|
||||
| ConfigurableExtensionDataRef<string, 'core.title', {}>
|
||||
| ConfigurableExtensionDataRef<JSX_2.Element, 'core.reactElement', {}>
|
||||
| ConfigurableExtensionDataRef<string, 'core.routing.path', {}>
|
||||
| ConfigurableExtensionDataRef<
|
||||
RouteRef_2<AnyRouteRefParams>,
|
||||
'core.routing.ref',
|
||||
{
|
||||
optional: true;
|
||||
}
|
||||
>,
|
||||
{
|
||||
singleton: false;
|
||||
optional: true;
|
||||
}
|
||||
>;
|
||||
};
|
||||
kind: 'page';
|
||||
name: undefined;
|
||||
params: {
|
||||
defaultPath?: [Error: `Use the 'path' param instead`];
|
||||
path: string;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
import { BackstagePlugin } from '@backstage/core-plugin-api';
|
||||
import { ElementType } from 'react';
|
||||
import { JSX as JSX_2 } from 'react/jsx-runtime';
|
||||
import { ReactElement } from 'react';
|
||||
import { ReactNode } from 'react';
|
||||
import { RouteRef } from '@backstage/core-plugin-api';
|
||||
import { TabProps } from '@material-ui/core/Tab';
|
||||
@@ -28,7 +29,23 @@ export type DevToolsLayoutProps = {
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const DevToolsPage: () => JSX_2.Element;
|
||||
export const DevToolsPage: ({ contents }: DevToolsPageProps) => JSX_2.Element;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface DevToolsPageContent {
|
||||
// (undocumented)
|
||||
children: ReactElement;
|
||||
// (undocumented)
|
||||
path: string;
|
||||
// (undocumented)
|
||||
title: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface DevToolsPageProps {
|
||||
// (undocumented)
|
||||
contents?: DevToolsPageContent[];
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const devToolsPlugin: BackstagePlugin<
|
||||
|
||||
@@ -21,6 +21,8 @@ import {
|
||||
ApiBlueprint,
|
||||
PageBlueprint,
|
||||
NavItemBlueprint,
|
||||
createExtensionInput,
|
||||
coreExtensionData,
|
||||
} from '@backstage/frontend-plugin-api';
|
||||
|
||||
import { devToolsApiRef, DevToolsClient } from '../api';
|
||||
@@ -42,12 +44,35 @@ export const devToolsApi = ApiBlueprint.make({
|
||||
});
|
||||
|
||||
/** @alpha */
|
||||
export const devToolsPage = PageBlueprint.make({
|
||||
params: {
|
||||
path: '/devtools',
|
||||
routeRef: rootRouteRef,
|
||||
loader: () =>
|
||||
import('../components/DevToolsPage').then(m => <m.DevToolsPage />),
|
||||
export const devToolsPage = PageBlueprint.makeWithOverrides({
|
||||
inputs: {
|
||||
contents: createExtensionInput(
|
||||
[
|
||||
coreExtensionData.reactElement,
|
||||
coreExtensionData.routePath,
|
||||
coreExtensionData.routeRef.optional(),
|
||||
coreExtensionData.title,
|
||||
],
|
||||
{
|
||||
optional: true,
|
||||
},
|
||||
),
|
||||
},
|
||||
factory(originalFactory, { inputs }) {
|
||||
return originalFactory({
|
||||
path: '/devtools',
|
||||
routeRef: rootRouteRef,
|
||||
loader: () => {
|
||||
const contents = inputs.contents.map(content => ({
|
||||
path: content.get(coreExtensionData.routePath),
|
||||
title: content.get(coreExtensionData.title),
|
||||
children: content.get(coreExtensionData.reactElement),
|
||||
}));
|
||||
return import('../components/DevToolsPage').then(m => (
|
||||
<m.DevToolsPage contents={contents} />
|
||||
));
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -18,15 +18,17 @@ import {
|
||||
devToolsConfigReadPermission,
|
||||
devToolsInfoReadPermission,
|
||||
} from '@backstage/plugin-devtools-common';
|
||||
|
||||
import { ConfigContent } from '../Content';
|
||||
import { devToolsTaskSchedulerReadPermission } from '@backstage/plugin-devtools-common/alpha';
|
||||
import { ConfigContent } from '../Content/ConfigContent';
|
||||
import { DevToolsLayout } from '../DevToolsLayout';
|
||||
import { InfoContent } from '../Content/InfoContent';
|
||||
import { InfoContent } from '../Content';
|
||||
import { RequirePermission } from '@backstage/plugin-permission-react';
|
||||
import { ScheduledTasksContent } from '../Content/ScheduledTasksContent';
|
||||
import { DevToolsPageProps } from '../DevToolsPage';
|
||||
|
||||
/** @public */
|
||||
export const DefaultDevToolsPage = () => (
|
||||
export const DefaultDevToolsPage = ({ contents }: DevToolsPageProps) => (
|
||||
<DevToolsLayout>
|
||||
<DevToolsLayout.Route path="info" title="Info">
|
||||
<RequirePermission permission={devToolsInfoReadPermission}>
|
||||
@@ -43,5 +45,14 @@ export const DefaultDevToolsPage = () => (
|
||||
<ScheduledTasksContent />
|
||||
</RequirePermission>
|
||||
</DevToolsLayout.Route>
|
||||
{contents?.map((content, index) => (
|
||||
<DevToolsLayout.Route
|
||||
key={`extension-${index}`}
|
||||
path={content.path}
|
||||
title={content.title}
|
||||
>
|
||||
{content.children}
|
||||
</DevToolsLayout.Route>
|
||||
))}
|
||||
</DevToolsLayout>
|
||||
);
|
||||
|
||||
@@ -16,9 +16,26 @@
|
||||
|
||||
import { useOutlet } from 'react-router-dom';
|
||||
import { DefaultDevToolsPage } from '../DefaultDevToolsPage';
|
||||
import { ReactElement } from 'react';
|
||||
|
||||
export const DevToolsPage = () => {
|
||||
/**
|
||||
@public
|
||||
*/
|
||||
export interface DevToolsPageProps {
|
||||
contents?: DevToolsPageContent[];
|
||||
}
|
||||
|
||||
/**
|
||||
@public
|
||||
*/
|
||||
export interface DevToolsPageContent {
|
||||
title: string;
|
||||
path: string;
|
||||
children: ReactElement;
|
||||
}
|
||||
|
||||
export const DevToolsPage = ({ contents }: DevToolsPageProps) => {
|
||||
const outlet = useOutlet();
|
||||
|
||||
return <>{outlet || <DefaultDevToolsPage />}</>;
|
||||
return <>{outlet || <DefaultDevToolsPage contents={contents} />}</>;
|
||||
};
|
||||
|
||||
@@ -14,4 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export { DevToolsPage } from './DevToolsPage';
|
||||
export {
|
||||
DevToolsPage,
|
||||
type DevToolsPageProps,
|
||||
type DevToolsPageContent,
|
||||
} from './DevToolsPage';
|
||||
|
||||
@@ -16,3 +16,7 @@
|
||||
|
||||
export * from './Content';
|
||||
export * from './DevToolsLayout';
|
||||
export {
|
||||
type DevToolsPageProps,
|
||||
type DevToolsPageContent,
|
||||
} from './DevToolsPage';
|
||||
|
||||
@@ -5444,12 +5444,14 @@ __metadata:
|
||||
resolution: "@backstage/plugin-catalog-unprocessed-entities@workspace:plugins/catalog-unprocessed-entities"
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/core-compat-api": "workspace:^"
|
||||
"@backstage/core-components": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/dev-utils": "workspace:^"
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/plugin-catalog-unprocessed-entities-common": "workspace:^"
|
||||
"@backstage/plugin-devtools-react": "workspace:^"
|
||||
"@material-ui/core": "npm:^4.9.13"
|
||||
"@material-ui/icons": "npm:^4.9.1"
|
||||
"@material-ui/lab": "npm:^4.0.0-alpha.60"
|
||||
@@ -5611,6 +5613,32 @@ __metadata:
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/plugin-devtools-react@workspace:^, @backstage/plugin-devtools-react@workspace:plugins/devtools-react":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/plugin-devtools-react@workspace:plugins/devtools-react"
|
||||
dependencies:
|
||||
"@backstage/cli": "workspace:^"
|
||||
"@backstage/core-plugin-api": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/test-utils": "workspace:^"
|
||||
"@material-ui/core": "npm:^4.9.13"
|
||||
"@testing-library/jest-dom": "npm:^6.0.0"
|
||||
"@testing-library/react": "npm:^14.0.0"
|
||||
"@types/react": "npm:^18.0.0"
|
||||
react: "npm:^18.0.2"
|
||||
react-dom: "npm:^18.0.2"
|
||||
react-router-dom: "npm:^6.3.0"
|
||||
peerDependencies:
|
||||
"@types/react": ^17.0.0 || ^18.0.0
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
react-dom: ^17.0.0 || ^18.0.0
|
||||
react-router-dom: ^6.3.0
|
||||
peerDependenciesMeta:
|
||||
"@types/react":
|
||||
optional: true
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@backstage/plugin-devtools@workspace:^, @backstage/plugin-devtools@workspace:plugins/devtools":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@backstage/plugin-devtools@workspace:plugins/devtools"
|
||||
@@ -5623,6 +5651,7 @@ __metadata:
|
||||
"@backstage/errors": "workspace:^"
|
||||
"@backstage/frontend-plugin-api": "workspace:^"
|
||||
"@backstage/plugin-devtools-common": "workspace:^"
|
||||
"@backstage/plugin-devtools-react": "workspace:^"
|
||||
"@backstage/plugin-permission-react": "workspace:^"
|
||||
"@material-ui/core": "npm:^4.9.13"
|
||||
"@material-ui/icons": "npm:^4.9.1"
|
||||
@@ -20169,6 +20198,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/dom@npm:^9.0.0":
|
||||
version: 9.3.4
|
||||
resolution: "@testing-library/dom@npm:9.3.4"
|
||||
dependencies:
|
||||
"@babel/code-frame": "npm:^7.10.4"
|
||||
"@babel/runtime": "npm:^7.12.5"
|
||||
"@types/aria-query": "npm:^5.0.1"
|
||||
aria-query: "npm:5.1.3"
|
||||
chalk: "npm:^4.1.0"
|
||||
dom-accessibility-api: "npm:^0.5.9"
|
||||
lz-string: "npm:^1.5.0"
|
||||
pretty-format: "npm:^27.0.2"
|
||||
checksum: 10/510da752ea76f4a10a0a4e3a77917b0302cf03effe576cd3534cab7e796533ee2b0e9fb6fb11b911a1ebd7c70a0bb6f235bf4f816c9b82b95b8fe0cddfd10975
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/jest-dom@npm:^6.0.0, @testing-library/jest-dom@npm:^6.6.3":
|
||||
version: 6.9.1
|
||||
resolution: "@testing-library/jest-dom@npm:6.9.1"
|
||||
@@ -20205,6 +20250,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react@npm:^14.0.0":
|
||||
version: 14.3.1
|
||||
resolution: "@testing-library/react@npm:14.3.1"
|
||||
dependencies:
|
||||
"@babel/runtime": "npm:^7.12.5"
|
||||
"@testing-library/dom": "npm:^9.0.0"
|
||||
"@types/react-dom": "npm:^18.0.0"
|
||||
peerDependencies:
|
||||
react: ^18.0.0
|
||||
react-dom: ^18.0.0
|
||||
checksum: 10/83359dcdf9eaf067839f34604e1a181cbc14fc09f3a07672403700fcc6a900c4b8054ad1114fc24b4b9f89d84e2a09e1b7c9afce2306b1d4b4c9e30eb1cb12de
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@testing-library/react@npm:^16.0.0":
|
||||
version: 16.3.1
|
||||
resolution: "@testing-library/react@npm:16.3.1"
|
||||
@@ -24713,6 +24772,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aria-query@npm:5.1.3":
|
||||
version: 5.1.3
|
||||
resolution: "aria-query@npm:5.1.3"
|
||||
dependencies:
|
||||
deep-equal: "npm:^2.0.5"
|
||||
checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"aria-query@npm:5.3.0":
|
||||
version: 5.3.0
|
||||
resolution: "aria-query@npm:5.3.0"
|
||||
@@ -24729,7 +24797,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2":
|
||||
"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "array-buffer-byte-length@npm:1.0.2"
|
||||
dependencies:
|
||||
@@ -25013,6 +25081,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"async-function@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "async-function@npm:1.0.0"
|
||||
checksum: 10/1a09379937d846f0ce7614e75071c12826945d4e417db634156bf0e4673c495989302f52186dfa9767a1d9181794554717badd193ca2bbab046ef1da741d8efd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"async-generator-function@npm:^1.0.0":
|
||||
version: 1.0.0
|
||||
resolution: "async-generator-function@npm:1.0.0"
|
||||
checksum: 10/3d49e7acbeee9e84537f4cb0e0f91893df8eba976759875ae8ee9e3d3c82f6ecdebdb347c2fad9926b92596d93cdfc78ecc988bcdf407e40433e8e8e6fe5d78e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"async-lock@npm:^1.4.1":
|
||||
version: 1.4.1
|
||||
resolution: "async-lock@npm:1.4.1"
|
||||
@@ -28491,6 +28573,32 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"deep-equal@npm:^2.0.5":
|
||||
version: 2.2.3
|
||||
resolution: "deep-equal@npm:2.2.3"
|
||||
dependencies:
|
||||
array-buffer-byte-length: "npm:^1.0.0"
|
||||
call-bind: "npm:^1.0.5"
|
||||
es-get-iterator: "npm:^1.1.3"
|
||||
get-intrinsic: "npm:^1.2.2"
|
||||
is-arguments: "npm:^1.1.1"
|
||||
is-array-buffer: "npm:^3.0.2"
|
||||
is-date-object: "npm:^1.0.5"
|
||||
is-regex: "npm:^1.1.4"
|
||||
is-shared-array-buffer: "npm:^1.0.2"
|
||||
isarray: "npm:^2.0.5"
|
||||
object-is: "npm:^1.1.5"
|
||||
object-keys: "npm:^1.1.1"
|
||||
object.assign: "npm:^4.1.4"
|
||||
regexp.prototype.flags: "npm:^1.5.1"
|
||||
side-channel: "npm:^1.0.4"
|
||||
which-boxed-primitive: "npm:^1.0.2"
|
||||
which-collection: "npm:^1.0.1"
|
||||
which-typed-array: "npm:^1.1.13"
|
||||
checksum: 10/1ce49d0b71d0f14d8ef991a742665eccd488dfc9b3cada069d4d7a86291e591c92d2589c832811dea182b4015736b210acaaebce6184be356c1060d176f5a05f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"deep-equal@npm:~1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "deep-equal@npm:1.0.1"
|
||||
@@ -29686,7 +29794,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"es-get-iterator@npm:^1.0.2":
|
||||
"es-get-iterator@npm:^1.0.2, es-get-iterator@npm:^1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "es-get-iterator@npm:1.1.3"
|
||||
dependencies:
|
||||
@@ -30700,6 +30808,7 @@ __metadata:
|
||||
"@backstage/plugin-catalog-import": "workspace:^"
|
||||
"@backstage/plugin-catalog-react": "workspace:^"
|
||||
"@backstage/plugin-catalog-unprocessed-entities": "workspace:^"
|
||||
"@backstage/plugin-devtools": "workspace:^"
|
||||
"@backstage/plugin-home": "workspace:^"
|
||||
"@backstage/plugin-kubernetes": "workspace:^"
|
||||
"@backstage/plugin-kubernetes-cluster": "workspace:^"
|
||||
@@ -32256,6 +32365,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"generator-function@npm:^2.0.0":
|
||||
version: 2.0.1
|
||||
resolution: "generator-function@npm:2.0.1"
|
||||
checksum: 10/eb7e7eb896c5433f3d40982b2ccacdb3dd990dd3499f14040e002b5d54572476513be8a2e6f9609f6e41ab29f2c4469307611ddbfc37ff4e46b765c326663805
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"generic-names@npm:^2.0.1":
|
||||
version: 2.0.1
|
||||
resolution: "generic-names@npm:2.0.1"
|
||||
@@ -32303,21 +32419,24 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "get-intrinsic@npm:1.3.0"
|
||||
"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.3.0":
|
||||
version: 1.3.1
|
||||
resolution: "get-intrinsic@npm:1.3.1"
|
||||
dependencies:
|
||||
async-function: "npm:^1.0.0"
|
||||
async-generator-function: "npm:^1.0.0"
|
||||
call-bind-apply-helpers: "npm:^1.0.2"
|
||||
es-define-property: "npm:^1.0.1"
|
||||
es-errors: "npm:^1.3.0"
|
||||
es-object-atoms: "npm:^1.1.1"
|
||||
function-bind: "npm:^1.1.2"
|
||||
generator-function: "npm:^2.0.0"
|
||||
get-proto: "npm:^1.0.1"
|
||||
gopd: "npm:^1.2.0"
|
||||
has-symbols: "npm:^1.1.0"
|
||||
hasown: "npm:^2.0.2"
|
||||
math-intrinsics: "npm:^1.1.0"
|
||||
checksum: 10/6e9dd920ff054147b6f44cb98104330e87caafae051b6d37b13384a45ba15e71af33c3baeac7cb630a0aaa23142718dcf25b45cfdd86c184c5dcb4e56d953a10
|
||||
checksum: 10/bb579dda84caa4a3a41611bdd483dade7f00f246f2a7992eb143c5861155290df3fdb48a8406efa3dfb0b434e2c8fafa4eebd469e409d0439247f85fc3fa2cc1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@@ -34407,7 +34526,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5":
|
||||
"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5":
|
||||
version: 3.0.5
|
||||
resolution: "is-array-buffer@npm:3.0.5"
|
||||
dependencies:
|
||||
@@ -34880,7 +34999,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-regex@npm:^1.2.1":
|
||||
"is-regex@npm:^1.1.4, is-regex@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "is-regex@npm:1.2.1"
|
||||
dependencies:
|
||||
@@ -34929,7 +35048,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"is-shared-array-buffer@npm:^1.0.4":
|
||||
"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "is-shared-array-buffer@npm:1.0.4"
|
||||
dependencies:
|
||||
@@ -44711,7 +44830,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4":
|
||||
"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4":
|
||||
version: 1.5.4
|
||||
resolution: "regexp.prototype.flags@npm:1.5.4"
|
||||
dependencies:
|
||||
@@ -46279,7 +46398,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"side-channel@npm:^1.1.0":
|
||||
"side-channel@npm:^1.0.4, side-channel@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "side-channel@npm:1.1.0"
|
||||
dependencies:
|
||||
@@ -50503,7 +50622,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1":
|
||||
"which-boxed-primitive@npm:^1.0.2, which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "which-boxed-primitive@npm:1.1.1"
|
||||
dependencies:
|
||||
@@ -50537,7 +50656,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-collection@npm:^1.0.2":
|
||||
"which-collection@npm:^1.0.1, which-collection@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "which-collection@npm:1.0.2"
|
||||
dependencies:
|
||||
@@ -50559,7 +50678,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2":
|
||||
"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19, which-typed-array@npm:^1.1.2":
|
||||
version: 1.1.19
|
||||
resolution: "which-typed-array@npm:1.1.19"
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user