Merge pull request #29760 from csuich2/techdocs-entity-path

feat: add techdocs-entity-path annotation for techdocs deep linking
This commit is contained in:
Fredrik Adelöw
2025-05-27 14:46:39 +02:00
committed by GitHub
18 changed files with 294 additions and 38 deletions
+1
View File
@@ -63,6 +63,7 @@
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/frontend-plugin-api": "workspace:^",
"@backstage/plugin-techdocs-common": "workspace:^",
"@backstage/version-bridge": "workspace:^",
"@material-ui/core": "^4.12.2",
"@material-ui/styles": "^4.11.0",
+16
View File
@@ -15,8 +15,21 @@ import { JSX as JSX_2 } from 'react/jsx-runtime';
import { MemoExoticComponent } from 'react';
import { PropsWithChildren } from 'react';
import { ReactNode } from 'react';
import { RouteFunc } from '@backstage/core-plugin-api';
import { SetStateAction } from 'react';
// @public
export const buildTechDocsURL: (
entity: Entity,
routeFunc:
| RouteFunc<{
namespace: string;
kind: string;
name: string;
}>
| undefined,
) => string | undefined;
// @public
export function createTechDocsAddonExtension(
options: TechDocsAddonOptions,
@@ -27,6 +40,9 @@ export function createTechDocsAddonExtension<TComponentProps>(
options: TechDocsAddonOptions<TComponentProps>,
): Extension<(props: TComponentProps) => JSX.Element | null>;
// @public
export function getEntityRootTechDocsPath(entity: Entity): string;
// @public
export const SHADOW_DOM_STYLE_LOAD_EVENT = 'TECH_DOCS_SHADOW_DOM_STYLE_LOAD';
+75 -1
View File
@@ -15,7 +15,17 @@
*/
import { Config } from '@backstage/config';
import { CompoundEntityRef } from '@backstage/catalog-model';
import {
CompoundEntityRef,
Entity,
getCompoundEntityRef,
parseEntityRef,
} from '@backstage/catalog-model';
import {
TECHDOCS_EXTERNAL_ANNOTATION,
TECHDOCS_EXTERNAL_PATH_ANNOTATION,
} from '@backstage/plugin-techdocs-common';
import { RouteFunc } from '@backstage/core-plugin-api';
/**
* Lower-case entity triplets by default, but allow override.
@@ -35,3 +45,67 @@ export function toLowercaseEntityRefMaybe(
return entityRef;
}
/**
* Get the entity path annotation from the given entity and ensure it starts with a slash.
*
* @public
*/
export function getEntityRootTechDocsPath(entity: Entity): string {
let path = entity.metadata.annotations?.[TECHDOCS_EXTERNAL_PATH_ANNOTATION];
if (!path) {
return '';
}
if (!path.startsWith('/')) {
path = `/${path}`;
}
return path;
}
/**
* Build the TechDocs URL for the given entity. This helper should be used anywhere there
* is a link to an entities TechDocs.
*
* @public
*/
export const buildTechDocsURL = (
entity: Entity,
routeFunc:
| RouteFunc<{
namespace: string;
kind: string;
name: string;
}>
| undefined,
) => {
if (!routeFunc) {
return undefined;
}
let { namespace, kind, name } = getCompoundEntityRef(entity);
if (entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION]) {
try {
const techdocsRef = parseEntityRef(
entity.metadata.annotations?.[TECHDOCS_EXTERNAL_ANNOTATION],
);
namespace = techdocsRef.namespace;
kind = techdocsRef.kind;
name = techdocsRef.name;
} catch {
// not a fan of this but we don't care if the parseEntityRef fails
}
}
const url = routeFunc({
namespace,
kind,
name,
});
// Add on the external entity path to the url if one exists. This allows deep linking into another
// entities TechDocs.
const path = getEntityRootTechDocsPath(entity);
return `${url}${path}`;
};
+5 -1
View File
@@ -52,4 +52,8 @@ export {
useShadowRootElements,
useShadowRootSelection,
} from './hooks';
export { toLowercaseEntityRefMaybe } from './helpers';
export {
toLowercaseEntityRefMaybe,
getEntityRootTechDocsPath,
buildTechDocsURL,
} from './helpers';