@backstage/frontend-plugin-api 0.15.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @backstage/frontend-plugin-api
2
2
 
3
+ ## 0.15.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 5783b63: Added `titleLink` prop to `PageLayoutProps` so the plugin header title can link back to the plugin root.
8
+
3
9
  ## 0.15.0
4
10
 
5
11
  ### Minor Changes
@@ -21,7 +21,7 @@ import '../apis/definitions/IconsApi.esm.js';
21
21
  import '../apis/definitions/IdentityApi.esm.js';
22
22
  import '../apis/definitions/DialogApi.esm.js';
23
23
  import '../apis/definitions/OAuthRequestApi.esm.js';
24
- import '../apis/definitions/RouteResolutionApi.esm.js';
24
+ import { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi.esm.js';
25
25
  import '../apis/definitions/StorageApi.esm.js';
26
26
  import '../apis/definitions/AnalyticsApi.esm.js';
27
27
  import '../apis/definitions/ToastApi.esm.js';
@@ -34,6 +34,16 @@ import '../components/AppNodeProvider.esm.js';
34
34
  import '../components/DefaultSwappableComponents.esm.js';
35
35
  import { PageLayout } from '../components/PageLayout.esm.js';
36
36
 
37
+ function resolveTitleLink(routeResolutionApi, routeRef) {
38
+ if (!routeRef) {
39
+ return void 0;
40
+ }
41
+ try {
42
+ return routeResolutionApi.resolve(routeRef)?.();
43
+ } catch {
44
+ return void 0;
45
+ }
46
+ }
37
47
  const PageBlueprint = createExtensionBlueprint({
38
48
  kind: "page",
39
49
  attachTo: { id: "app/routes", input: "routes" },
@@ -66,10 +76,13 @@ const PageBlueprint = createExtensionBlueprint({
66
76
  const noHeader = params.noHeader ?? false;
67
77
  const resolvedTitle = title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;
68
78
  const resolvedIcon = icon ?? node.spec.plugin.icon;
79
+ const titleRouteRef = node.spec.plugin.routes.root ?? params.routeRef;
69
80
  yield coreExtensionData.routePath(config.path ?? params.path);
70
81
  if (params.loader) {
71
82
  const loader = params.loader;
72
83
  const PageContent = () => {
84
+ const routeResolutionApi = useApi(routeResolutionApiRef);
85
+ const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);
73
86
  const headerActionsApi = useApi(pluginHeaderActionsApiRef);
74
87
  const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);
75
88
  return /* @__PURE__ */ jsx(
@@ -78,6 +91,7 @@ const PageBlueprint = createExtensionBlueprint({
78
91
  title: resolvedTitle,
79
92
  icon: resolvedIcon,
80
93
  noHeader,
94
+ titleLink,
81
95
  headerActions,
82
96
  children: ExtensionBoundary.lazy(node, loader)
83
97
  }
@@ -98,6 +112,8 @@ const PageBlueprint = createExtensionBlueprint({
98
112
  });
99
113
  const PageContent = () => {
100
114
  const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);
115
+ const routeResolutionApi = useApi(routeResolutionApiRef);
116
+ const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);
101
117
  const headerActionsApi = useApi(pluginHeaderActionsApiRef);
102
118
  const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);
103
119
  return /* @__PURE__ */ jsx(
@@ -106,6 +122,7 @@ const PageBlueprint = createExtensionBlueprint({
106
122
  title: resolvedTitle,
107
123
  icon: resolvedIcon,
108
124
  tabs,
125
+ titleLink,
109
126
  headerActions,
110
127
  children: /* @__PURE__ */ jsxs(Routes, { children: [
111
128
  firstPagePath && /* @__PURE__ */ jsx(
@@ -127,6 +144,8 @@ const PageBlueprint = createExtensionBlueprint({
127
144
  yield coreExtensionData.reactElement(/* @__PURE__ */ jsx(PageContent, {}));
128
145
  } else {
129
146
  const PageContent = () => {
147
+ const routeResolutionApi = useApi(routeResolutionApiRef);
148
+ const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);
130
149
  const headerActionsApi = useApi(pluginHeaderActionsApiRef);
131
150
  const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);
132
151
  return /* @__PURE__ */ jsx(
@@ -134,6 +153,7 @@ const PageBlueprint = createExtensionBlueprint({
134
153
  {
135
154
  title: resolvedTitle,
136
155
  icon: resolvedIcon,
156
+ titleLink,
137
157
  headerActions
138
158
  }
139
159
  );
@@ -1 +1 @@
1
- {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PageBlueprint.esm.js","sources":["../../src/blueprints/PageBlueprint.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { JSX } from 'react';\nimport { Routes, Route, Navigate } from 'react-router-dom';\nimport { IconElement } from '../icons/types';\nimport { RouteRef } from '../routing';\nimport {\n coreExtensionData,\n createExtensionBlueprint,\n createExtensionInput,\n} from '../wiring';\nimport { ExtensionBoundary, PageLayout, PageLayoutTab } from '../components';\nimport { useApi } from '../apis/system';\nimport { routeResolutionApiRef } from '../apis/definitions/RouteResolutionApi';\nimport { pluginHeaderActionsApiRef } from '../apis/definitions/PluginHeaderActionsApi';\nimport { RouteResolutionApi } from '../apis/definitions/RouteResolutionApi';\n\nfunction resolveTitleLink(\n routeResolutionApi: RouteResolutionApi,\n routeRef: RouteRef | undefined,\n): string | undefined {\n if (!routeRef) {\n return undefined;\n }\n try {\n return routeResolutionApi.resolve(routeRef)?.();\n } catch {\n // Route ref may require params not available in the current context\n return undefined;\n }\n}\n\n/**\n * Creates extensions that are routable React page components.\n *\n * @public\n */\nexport const PageBlueprint = createExtensionBlueprint({\n kind: 'page',\n attachTo: { id: 'app/routes', input: 'routes' },\n inputs: {\n pages: createExtensionInput([\n coreExtensionData.routePath,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.reactElement,\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ]),\n },\n output: [\n coreExtensionData.routePath,\n coreExtensionData.reactElement,\n coreExtensionData.routeRef.optional(),\n coreExtensionData.title.optional(),\n coreExtensionData.icon.optional(),\n ],\n config: {\n schema: {\n path: z => z.string().optional(),\n title: z => z.string().optional(),\n },\n },\n *factory(\n params: {\n path: string;\n title?: string;\n icon?: IconElement;\n loader?: () => Promise<JSX.Element>;\n routeRef?: RouteRef;\n /**\n * Hide the default plugin page header, making the page fill up all available space.\n */\n noHeader?: boolean;\n },\n { config, node, inputs },\n ) {\n const title = config.title ?? params.title;\n const icon = params.icon;\n const pluginId = node.spec.plugin.pluginId;\n const noHeader = params.noHeader ?? false;\n const resolvedTitle =\n title ?? node.spec.plugin.title ?? node.spec.plugin.pluginId;\n const resolvedIcon = icon ?? node.spec.plugin.icon;\n const titleRouteRef =\n (node.spec.plugin.routes as { root?: RouteRef }).root ?? params.routeRef;\n\n yield coreExtensionData.routePath(config.path ?? params.path);\n if (params.loader) {\n const loader = params.loader;\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n noHeader={noHeader}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n {ExtensionBoundary.lazy(node, loader)}\n </PageLayout>\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n } else if (inputs.pages.length > 0) {\n // Parent page with sub-pages - render header with tabs\n const tabs: PageLayoutTab[] = inputs.pages.map(page => {\n const path = page.get(coreExtensionData.routePath);\n const tabTitle = page.get(coreExtensionData.title);\n const tabIcon = page.get(coreExtensionData.icon);\n return {\n id: path,\n label: tabTitle || path,\n icon: tabIcon,\n href: path,\n };\n });\n\n const PageContent = () => {\n const firstPagePath = inputs.pages[0]?.get(coreExtensionData.routePath);\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n tabs={tabs}\n titleLink={titleLink}\n headerActions={headerActions}\n >\n <Routes>\n {firstPagePath && (\n <Route\n index\n element={<Navigate to={firstPagePath} replace />}\n />\n )}\n {inputs.pages.map((page, index) => {\n const path = page.get(coreExtensionData.routePath);\n const element = page.get(coreExtensionData.reactElement);\n return (\n <Route key={index} path={`${path}/*`} element={element} />\n );\n })}\n </Routes>\n </PageLayout>\n );\n };\n\n yield coreExtensionData.reactElement(<PageContent />);\n } else {\n const PageContent = () => {\n const routeResolutionApi = useApi(routeResolutionApiRef);\n const titleLink = resolveTitleLink(routeResolutionApi, titleRouteRef);\n const headerActionsApi = useApi(pluginHeaderActionsApiRef);\n const headerActions = headerActionsApi.getPluginHeaderActions(pluginId);\n return (\n <PageLayout\n title={resolvedTitle}\n icon={resolvedIcon}\n titleLink={titleLink}\n headerActions={headerActions}\n />\n );\n };\n yield coreExtensionData.reactElement(<PageContent />);\n }\n if (params.routeRef) {\n yield coreExtensionData.routeRef(params.routeRef);\n }\n if (title) {\n yield coreExtensionData.title(title);\n }\n if (icon) {\n yield coreExtensionData.icon(icon);\n }\n },\n});\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PageLayout.esm.js","sources":["../../src/components/PageLayout.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReactNode } from 'react';\nimport { IconElement } from '../icons/types';\nimport { createSwappableComponent } from './createSwappableComponent';\n\n/**\n * Tab configuration for page navigation\n * @public\n */\nexport interface PageLayoutTab {\n id: string;\n label: string;\n icon?: IconElement;\n href: string;\n}\n\n/**\n * @deprecated Use {@link PageLayoutTab} instead\n * @public\n */\nexport type PageTab = PageLayoutTab;\n\n/**\n * Props for the PageLayout component\n * @public\n */\nexport interface PageLayoutProps {\n title?: string;\n icon?: IconElement;\n noHeader?: boolean;\n headerActions?: Array<JSX.Element | null>;\n tabs?: PageLayoutTab[];\n children?: ReactNode;\n}\n\n/**\n * Default implementation of PageLayout using plain HTML elements\n */\nfunction DefaultPageLayout(props: PageLayoutProps): JSX.Element {\n const { title, icon, headerActions, tabs, children } = props;\n\n return (\n <div\n data-component=\"page-layout\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n minHeight: 0,\n }}\n >\n {(title || tabs) && (\n <header\n style={{\n borderBottom: '1px solid #ddd',\n backgroundColor: '#fff',\n flexShrink: 0,\n }}\n >\n {title && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 24px 8px',\n fontSize: '18px',\n fontWeight: 500,\n }}\n >\n {icon}\n {title}\n {headerActions && (\n <div style={{ marginLeft: 'auto' }}>{headerActions}</div>\n )}\n </div>\n )}\n {tabs && tabs.length > 0 && (\n <nav\n style={{\n display: 'flex',\n gap: '4px',\n padding: '0 24px',\n }}\n >\n {tabs.map(tab => (\n <a\n key={tab.id}\n href={tab.href}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n padding: '8px 12px',\n textDecoration: 'none',\n color: '#333',\n borderBottom: '2px solid transparent',\n }}\n >\n {tab.icon}\n {tab.label}\n </a>\n ))}\n </nav>\n )}\n </header>\n )}\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n minHeight: 0,\n }}\n >\n {children}\n </div>\n </div>\n );\n}\n\n/**\n * Swappable component for laying out page content with header and navigation.\n * The default implementation uses plain HTML elements.\n * Apps can override this with a custom implementation (e.g., using \\@backstage/ui).\n *\n * @public\n */\nexport const PageLayout = createSwappableComponent<PageLayoutProps>({\n id: 'core.page-layout',\n loader: () => DefaultPageLayout,\n});\n"],"names":[],"mappings":";;;AAqDA,SAAS,kBAAkB,KAAA,EAAqC;AAC9D,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,UAAS,GAAI,KAAA;AAEvD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,gBAAA,EAAe,aAAA;AAAA,MACf,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,QAAA,EAAU,CAAA;AAAA,QACV,SAAA,EAAW;AAAA,OACb;AAAA,MAEE,QAAA,EAAA;AAAA,QAAA,CAAA,KAAA,IAAS,IAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,YAAA,EAAc,gBAAA;AAAA,cACd,eAAA,EAAiB,MAAA;AAAA,cACjB,UAAA,EAAY;AAAA,aACd;AAAA,YAEC,QAAA,EAAA;AAAA,cAAA,KAAA,oBACC,IAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAO;AAAA,oBACL,OAAA,EAAS,MAAA;AAAA,oBACT,UAAA,EAAY,QAAA;AAAA,oBACZ,GAAA,EAAK,KAAA;AAAA,oBACL,OAAA,EAAS,eAAA;AAAA,oBACT,QAAA,EAAU,MAAA;AAAA,oBACV,UAAA,EAAY;AAAA,mBACd;AAAA,kBAEC,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,oBACA,KAAA;AAAA,oBACA,aAAA,wBACE,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,UAAA,EAAY,MAAA,IAAW,QAAA,EAAA,aAAA,EAAc;AAAA;AAAA;AAAA,eAEvD;AAAA,cAED,IAAA,IAAQ,IAAA,CAAK,MAAA,GAAS,CAAA,oBACrB,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAO;AAAA,oBACL,OAAA,EAAS,MAAA;AAAA,oBACT,GAAA,EAAK,KAAA;AAAA,oBACL,OAAA,EAAS;AAAA,mBACX;AAAA,kBAEC,QAAA,EAAA,IAAA,CAAK,IAAI,CAAA,GAAA,qBACR,IAAA;AAAA,oBAAC,GAAA;AAAA,oBAAA;AAAA,sBAEC,MAAM,GAAA,CAAI,IAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,OAAA,EAAS,MAAA;AAAA,wBACT,UAAA,EAAY,QAAA;AAAA,wBACZ,GAAA,EAAK,KAAA;AAAA,wBACL,OAAA,EAAS,UAAA;AAAA,wBACT,cAAA,EAAgB,MAAA;AAAA,wBAChB,KAAA,EAAO,MAAA;AAAA,wBACP,YAAA,EAAc;AAAA,uBAChB;AAAA,sBAEC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAI,IAAA;AAAA,wBACJ,GAAA,CAAI;AAAA;AAAA,qBAAA;AAAA,oBAbA,GAAA,CAAI;AAAA,mBAeZ;AAAA;AAAA;AACH;AAAA;AAAA,SAEJ;AAAA,wBAEF,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,OAAA,EAAS,MAAA;AAAA,cACT,aAAA,EAAe,QAAA;AAAA,cACf,QAAA,EAAU,CAAA;AAAA,cACV,SAAA,EAAW;AAAA,aACb;AAAA,YAEC;AAAA;AAAA;AACH;AAAA;AAAA,GACF;AAEJ;AASO,MAAM,aAAa,wBAAA,CAA0C;AAAA,EAClE,EAAA,EAAI,kBAAA;AAAA,EACJ,QAAQ,MAAM;AAChB,CAAC;;;;"}
1
+ {"version":3,"file":"PageLayout.esm.js","sources":["../../src/components/PageLayout.tsx"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { ReactNode } from 'react';\nimport { IconElement } from '../icons/types';\nimport { createSwappableComponent } from './createSwappableComponent';\n\n/**\n * Tab configuration for page navigation\n * @public\n */\nexport interface PageLayoutTab {\n id: string;\n label: string;\n icon?: IconElement;\n href: string;\n}\n\n/**\n * @deprecated Use {@link PageLayoutTab} instead\n * @public\n */\nexport type PageTab = PageLayoutTab;\n\n/**\n * Props for the PageLayout component\n * @public\n */\nexport interface PageLayoutProps {\n title?: string;\n icon?: IconElement;\n noHeader?: boolean;\n titleLink?: string;\n headerActions?: Array<JSX.Element | null>;\n tabs?: PageLayoutTab[];\n children?: ReactNode;\n}\n\n/**\n * Default implementation of PageLayout using plain HTML elements\n */\nfunction DefaultPageLayout(props: PageLayoutProps): JSX.Element {\n const { title, icon, headerActions, tabs, children } = props;\n\n return (\n <div\n data-component=\"page-layout\"\n style={{\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n minHeight: 0,\n }}\n >\n {(title || tabs) && (\n <header\n style={{\n borderBottom: '1px solid #ddd',\n backgroundColor: '#fff',\n flexShrink: 0,\n }}\n >\n {title && (\n <div\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '12px 24px 8px',\n fontSize: '18px',\n fontWeight: 500,\n }}\n >\n {icon}\n {title}\n {headerActions && (\n <div style={{ marginLeft: 'auto' }}>{headerActions}</div>\n )}\n </div>\n )}\n {tabs && tabs.length > 0 && (\n <nav\n style={{\n display: 'flex',\n gap: '4px',\n padding: '0 24px',\n }}\n >\n {tabs.map(tab => (\n <a\n key={tab.id}\n href={tab.href}\n style={{\n display: 'flex',\n alignItems: 'center',\n gap: '4px',\n padding: '8px 12px',\n textDecoration: 'none',\n color: '#333',\n borderBottom: '2px solid transparent',\n }}\n >\n {tab.icon}\n {tab.label}\n </a>\n ))}\n </nav>\n )}\n </header>\n )}\n <div\n style={{\n display: 'flex',\n flexDirection: 'column',\n flexGrow: 1,\n minHeight: 0,\n }}\n >\n {children}\n </div>\n </div>\n );\n}\n\n/**\n * Swappable component for laying out page content with header and navigation.\n * The default implementation uses plain HTML elements.\n * Apps can override this with a custom implementation (e.g., using \\@backstage/ui).\n *\n * @public\n */\nexport const PageLayout = createSwappableComponent<PageLayoutProps>({\n id: 'core.page-layout',\n loader: () => DefaultPageLayout,\n});\n"],"names":[],"mappings":";;;AAsDA,SAAS,kBAAkB,KAAA,EAAqC;AAC9D,EAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,UAAS,GAAI,KAAA;AAEvD,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,gBAAA,EAAe,aAAA;AAAA,MACf,KAAA,EAAO;AAAA,QACL,OAAA,EAAS,MAAA;AAAA,QACT,aAAA,EAAe,QAAA;AAAA,QACf,QAAA,EAAU,CAAA;AAAA,QACV,SAAA,EAAW;AAAA,OACb;AAAA,MAEE,QAAA,EAAA;AAAA,QAAA,CAAA,KAAA,IAAS,IAAA,qBACT,IAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,YAAA,EAAc,gBAAA;AAAA,cACd,eAAA,EAAiB,MAAA;AAAA,cACjB,UAAA,EAAY;AAAA,aACd;AAAA,YAEC,QAAA,EAAA;AAAA,cAAA,KAAA,oBACC,IAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAO;AAAA,oBACL,OAAA,EAAS,MAAA;AAAA,oBACT,UAAA,EAAY,QAAA;AAAA,oBACZ,GAAA,EAAK,KAAA;AAAA,oBACL,OAAA,EAAS,eAAA;AAAA,oBACT,QAAA,EAAU,MAAA;AAAA,oBACV,UAAA,EAAY;AAAA,mBACd;AAAA,kBAEC,QAAA,EAAA;AAAA,oBAAA,IAAA;AAAA,oBACA,KAAA;AAAA,oBACA,aAAA,wBACE,KAAA,EAAA,EAAI,KAAA,EAAO,EAAE,UAAA,EAAY,MAAA,IAAW,QAAA,EAAA,aAAA,EAAc;AAAA;AAAA;AAAA,eAEvD;AAAA,cAED,IAAA,IAAQ,IAAA,CAAK,MAAA,GAAS,CAAA,oBACrB,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBACC,KAAA,EAAO;AAAA,oBACL,OAAA,EAAS,MAAA;AAAA,oBACT,GAAA,EAAK,KAAA;AAAA,oBACL,OAAA,EAAS;AAAA,mBACX;AAAA,kBAEC,QAAA,EAAA,IAAA,CAAK,IAAI,CAAA,GAAA,qBACR,IAAA;AAAA,oBAAC,GAAA;AAAA,oBAAA;AAAA,sBAEC,MAAM,GAAA,CAAI,IAAA;AAAA,sBACV,KAAA,EAAO;AAAA,wBACL,OAAA,EAAS,MAAA;AAAA,wBACT,UAAA,EAAY,QAAA;AAAA,wBACZ,GAAA,EAAK,KAAA;AAAA,wBACL,OAAA,EAAS,UAAA;AAAA,wBACT,cAAA,EAAgB,MAAA;AAAA,wBAChB,KAAA,EAAO,MAAA;AAAA,wBACP,YAAA,EAAc;AAAA,uBAChB;AAAA,sBAEC,QAAA,EAAA;AAAA,wBAAA,GAAA,CAAI,IAAA;AAAA,wBACJ,GAAA,CAAI;AAAA;AAAA,qBAAA;AAAA,oBAbA,GAAA,CAAI;AAAA,mBAeZ;AAAA;AAAA;AACH;AAAA;AAAA,SAEJ;AAAA,wBAEF,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAA,EAAO;AAAA,cACL,OAAA,EAAS,MAAA;AAAA,cACT,aAAA,EAAe,QAAA;AAAA,cACf,QAAA,EAAU,CAAA;AAAA,cACV,SAAA,EAAW;AAAA,aACb;AAAA,YAEC;AAAA;AAAA;AACH;AAAA;AAAA,GACF;AAEJ;AASO,MAAM,aAAa,wBAAA,CAA0C;AAAA,EAClE,EAAA,EAAI,kBAAA;AAAA,EACJ,QAAQ,MAAM;AAChB,CAAC;;;;"}
package/dist/index.d.ts CHANGED
@@ -753,6 +753,7 @@ interface PageLayoutProps {
753
753
  title?: string;
754
754
  icon?: IconElement;
755
755
  noHeader?: boolean;
756
+ titleLink?: string;
756
757
  headerActions?: Array<JSX.Element | null>;
757
758
  tabs?: PageLayoutTab[];
758
759
  children?: ReactNode;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backstage/frontend-plugin-api",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "backstage": {
5
5
  "role": "web-library"
6
6
  },
@@ -62,7 +62,7 @@
62
62
  "devDependencies": {
63
63
  "@backstage/cli": "^0.36.0",
64
64
  "@backstage/config": "^1.3.6",
65
- "@backstage/frontend-app-api": "^0.16.0",
65
+ "@backstage/frontend-app-api": "^0.16.1",
66
66
  "@backstage/frontend-test-utils": "^0.5.1",
67
67
  "@backstage/test-utils": "^1.7.16",
68
68
  "@testing-library/jest-dom": "^6.0.0",