@red-hat-developer-hub/backstage-plugin-global-header 1.11.2 → 1.13.0

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.
Files changed (26) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/app-config.dynamic.yaml +11 -1
  3. package/config.d.ts +7 -0
  4. package/dist/components/CompanyLogo/CompanyLogo.esm.js +11 -5
  5. package/dist/components/CompanyLogo/CompanyLogo.esm.js.map +1 -1
  6. package/dist/components/HeaderDropdownComponent/HelpDropdown.esm.js +45 -0
  7. package/dist/components/HeaderDropdownComponent/HelpDropdown.esm.js.map +1 -0
  8. package/dist/components/HeaderDropdownComponent/ProfileDropdown.esm.js +35 -11
  9. package/dist/components/HeaderDropdownComponent/ProfileDropdown.esm.js.map +1 -1
  10. package/dist/components/QuickstartButton/QuickstartButton.esm.js +34 -0
  11. package/dist/components/QuickstartButton/QuickstartButton.esm.js.map +1 -0
  12. package/dist/components/QuickstartButton/const.esm.js +4 -0
  13. package/dist/components/QuickstartButton/const.esm.js.map +1 -0
  14. package/dist/components/QuickstartButton/useQuickstartButtonPermission.esm.js +27 -0
  15. package/dist/components/QuickstartButton/useQuickstartButtonPermission.esm.js.map +1 -0
  16. package/dist/components/SupportButton/SupportButton.esm.js +19 -23
  17. package/dist/components/SupportButton/SupportButton.esm.js.map +1 -1
  18. package/dist/defaultMountPoints/defaultMountPoints.esm.js +28 -2
  19. package/dist/defaultMountPoints/defaultMountPoints.esm.js.map +1 -1
  20. package/dist/hooks/useHelpDropdownMountPoints.esm.js +14 -0
  21. package/dist/hooks/useHelpDropdownMountPoints.esm.js.map +1 -0
  22. package/dist/index.d.ts +128 -110
  23. package/dist/index.esm.js +1 -1
  24. package/dist/plugin.esm.js +14 -3
  25. package/dist/plugin.esm.js.map +1 -1
  26. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @red-hat-developer-hub/backstage-plugin-global-header
2
2
 
3
+ ## 1.13.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ba5e13c: Add dynamic profile link support to ProfileDropdown based on current user identity.
8
+
9
+ ## 1.12.0
10
+
11
+ ### Minor Changes
12
+
13
+ - 667e8c2: **BREAKING**: The `CompanyLogo` prop `logoWidth` has been renamed to `width`.
14
+
15
+ Allow configuring `width` and `height` for `CompanyLogo` via configuration. When `width` is not specified, `CompanyLogo` will now fall back to using the value from `app.branding.fullLogoWidth`.
16
+
17
+ - 5000863: **BREAKING**: `SupportButton` is now a `MenuItem` and `style` config prop can be used to update color, size and other required css properties.
18
+
19
+ Add `HelpDropdown` in global header plugin.
20
+
21
+ - 5638ede: Add QuickstartButton to global header plugin
22
+
3
23
  ## 1.11.2
4
24
 
5
25
  ### Patch Changes
@@ -67,10 +67,20 @@ dynamicPlugins:
67
67
  link: https://github.com/redhat-developer/rhdh-local
68
68
 
69
69
  - mountPoint: global.header/component
70
- importName: SupportButton
70
+ importName: HelpDropdown
71
71
  config:
72
72
  priority: 80
73
73
 
74
+ - mountPoint: global.header/help
75
+ importName: QuickstartButton
76
+ config:
77
+ priority: 100
78
+
79
+ - mountPoint: global.header/help
80
+ importName: SupportButton
81
+ config:
82
+ priority: 10
83
+
74
84
  - mountPoint: global.header/component
75
85
  importName: NotificationButton
76
86
  config:
package/config.d.ts CHANGED
@@ -38,6 +38,13 @@ declare module '@backstage/config' {
38
38
  */
39
39
  dark: string;
40
40
  };
41
+ /**
42
+ * Fallback width for the full logo in the global header.
43
+ * Accepts any valid CSS length (e.g. `'200px'`, `'12rem'`).
44
+ * Used only when a `width` prop isn’t supplied through the extension configuration.
45
+ * @visibility frontend
46
+ */
47
+ fullLogoWidth?: string | number;
41
48
  };
42
49
  };
43
50
  }
@@ -8,7 +8,8 @@ import { useAppBarBackgroundScheme } from '../../hooks/useAppBarBackgroundScheme
8
8
  const LogoRender = ({
9
9
  base64Logo,
10
10
  defaultLogo,
11
- width = 150
11
+ width = 150,
12
+ height = 40
12
13
  }) => {
13
14
  return base64Logo ? /* @__PURE__ */ jsx(
14
15
  "img",
@@ -19,8 +20,7 @@ const LogoRender = ({
19
20
  style: {
20
21
  objectFit: "contain",
21
22
  objectPosition: "left",
22
- maxHeight: "40px"
23
- // "kind of" aligns with PF's MastheadLogo height
23
+ maxHeight: height
24
24
  },
25
25
  width
26
26
  }
@@ -36,10 +36,15 @@ const useFullLogo = (logo) => {
36
36
  };
37
37
  const CompanyLogo = ({
38
38
  logo,
39
- logoWidth,
39
+ width,
40
+ height,
40
41
  to = "/"
41
42
  }) => {
42
43
  const logoURL = useFullLogo(logo);
44
+ const configApi = useApi(configApiRef);
45
+ const fullLogoWidth = configApi.getOptional(
46
+ "app.branding.fullLogoWidth"
47
+ );
43
48
  return /* @__PURE__ */ jsx(
44
49
  Box,
45
50
  {
@@ -68,7 +73,8 @@ const CompanyLogo = ({
68
73
  {
69
74
  base64Logo: logoURL,
70
75
  defaultLogo: /* @__PURE__ */ jsx(DefaultLogo, {}),
71
- width: logoWidth
76
+ width: width ?? fullLogoWidth,
77
+ height
72
78
  }
73
79
  )
74
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"CompanyLogo.esm.js","sources":["../../../src/components/CompanyLogo/CompanyLogo.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 */\nimport type { CSSProperties } from 'react';\nimport { Link } from '@backstage/core-components';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport DefaultLogo from './DefaultLogo';\nimport Box from '@mui/material/Box';\nimport { useAppBarBackgroundScheme } from '../../hooks/useAppBarBackgroundScheme';\n\nconst LogoRender = ({\n base64Logo,\n defaultLogo,\n width = 150,\n}: {\n base64Logo: string | undefined;\n defaultLogo: JSX.Element;\n width?: number;\n}) => {\n return base64Logo ? (\n <img\n data-testid=\"home-logo\"\n src={base64Logo}\n alt=\"Home logo\"\n style={{\n objectFit: 'contain',\n objectPosition: 'left',\n maxHeight: '40px', // \"kind of\" aligns with PF's MastheadLogo height\n }}\n width={width}\n />\n ) : (\n defaultLogo\n );\n};\n\n/**\n * An interface representing the URLs for light and dark variants of a logo.\n * @public\n */\nexport type LogoURLs =\n | {\n /** The logo that will be used in global headers with a light-coloured background */\n light: string;\n /** The logo that will be used in global headers with a dark-coloured background */\n dark: string;\n }\n | string\n | undefined;\n\n/**\n * @public\n */\nexport interface CompanyLogoProps {\n /** An object containing the logo URLs */\n logo?: LogoURLs;\n /** The route to link the logo to */\n to?: string;\n /**\n * The width of the logo in pixels (defaults to 150px). This prop fixes an\n * issue where encoded SVGs without an explicit width would not render.\n * You likely do not need to set this prop, but we recommend setting it\n * to a value under 200px.\n */\n logoWidth?: number;\n /** This prop is not used by this component. */\n layout?: CSSProperties;\n}\n\n/**\n * Gets a themed image based on the current theme.\n */\nconst useFullLogo = (logo: LogoURLs): string | undefined => {\n const appBarBackgroundScheme = useAppBarBackgroundScheme();\n\n const configApi = useApi(configApiRef);\n\n /** The fullLogo config specified by app.branding.fullLogo */\n const fullLogo = configApi.getOptional<LogoURLs>('app.branding.fullLogo');\n\n /** The URI of the logo specified by app.branding.fullLogo */\n const fullLogoURI =\n typeof fullLogo === 'string'\n ? fullLogo\n : fullLogo?.[appBarBackgroundScheme];\n\n /** The URI of the logo specified by CompanyLogo props */\n const propsLogoURI =\n typeof logo === 'string' ? logo : logo?.[appBarBackgroundScheme];\n\n return propsLogoURI ?? fullLogoURI ?? undefined;\n};\n\nexport const CompanyLogo = ({\n logo,\n logoWidth,\n to = '/',\n}: CompanyLogoProps) => {\n const logoURL = useFullLogo(logo);\n\n return (\n <Box\n data-testid=\"global-header-company-logo\"\n sx={{\n minWidth: '200px',\n marginRight: '13px', // align with BackstageContent\n display: 'flex',\n justifyContent: 'flex-start',\n alignItems: 'center',\n }}\n >\n <Link\n to={to}\n underline=\"none\"\n aria-label=\"Home\"\n style={{\n display: 'flex',\n justifyContent: 'flex-start',\n alignItems: 'center',\n }}\n >\n <LogoRender\n base64Logo={logoURL}\n defaultLogo={<DefaultLogo />}\n width={logoWidth}\n />\n </Link>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,aAAa,CAAC;AAAA,EAClB,UAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAQ,GAAA;AACV,CAIM,KAAA;AACJ,EAAA,OAAO,UACL,mBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAY,EAAA,WAAA;AAAA,MACZ,GAAK,EAAA,UAAA;AAAA,MACL,GAAI,EAAA,WAAA;AAAA,MACJ,KAAO,EAAA;AAAA,QACL,SAAW,EAAA,SAAA;AAAA,QACX,cAAgB,EAAA,MAAA;AAAA,QAChB,SAAW,EAAA;AAAA;AAAA,OACb;AAAA,MACA;AAAA;AAAA,GAGF,GAAA,WAAA;AAEJ,CAAA;AAsCA,MAAM,WAAA,GAAc,CAAC,IAAuC,KAAA;AAC1D,EAAA,MAAM,yBAAyB,yBAA0B,EAAA;AAEzD,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AAGrC,EAAM,MAAA,QAAA,GAAW,SAAU,CAAA,WAAA,CAAsB,uBAAuB,CAAA;AAGxE,EAAA,MAAM,cACJ,OAAO,QAAA,KAAa,QAChB,GAAA,QAAA,GACA,WAAW,sBAAsB,CAAA;AAGvC,EAAA,MAAM,eACJ,OAAO,IAAA,KAAS,QAAW,GAAA,IAAA,GAAO,OAAO,sBAAsB,CAAA;AAEjE,EAAA,OAAO,gBAAgB,WAAe,IAAA,KAAA,CAAA;AACxC,CAAA;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,IAAA;AAAA,EACA,SAAA;AAAA,EACA,EAAK,GAAA;AACP,CAAwB,KAAA;AACtB,EAAM,MAAA,OAAA,GAAU,YAAY,IAAI,CAAA;AAEhC,EACE,uBAAA,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,aAAY,EAAA,4BAAA;AAAA,MACZ,EAAI,EAAA;AAAA,QACF,QAAU,EAAA,OAAA;AAAA,QACV,WAAa,EAAA,MAAA;AAAA;AAAA,QACb,OAAS,EAAA,MAAA;AAAA,QACT,cAAgB,EAAA,YAAA;AAAA,QAChB,UAAY,EAAA;AAAA,OACd;AAAA,MAEA,QAAA,kBAAA,GAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,EAAA;AAAA,UACA,SAAU,EAAA,MAAA;AAAA,UACV,YAAW,EAAA,MAAA;AAAA,UACX,KAAO,EAAA;AAAA,YACL,OAAS,EAAA,MAAA;AAAA,YACT,cAAgB,EAAA,YAAA;AAAA,YAChB,UAAY,EAAA;AAAA,WACd;AAAA,UAEA,QAAA,kBAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,UAAY,EAAA,OAAA;AAAA,cACZ,WAAA,sBAAc,WAAY,EAAA,EAAA,CAAA;AAAA,cAC1B,KAAO,EAAA;AAAA;AAAA;AACT;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
1
+ {"version":3,"file":"CompanyLogo.esm.js","sources":["../../../src/components/CompanyLogo/CompanyLogo.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 */\nimport type { CSSProperties } from 'react';\nimport { Link } from '@backstage/core-components';\nimport { configApiRef, useApi } from '@backstage/core-plugin-api';\nimport DefaultLogo from './DefaultLogo';\nimport Box from '@mui/material/Box';\nimport { useAppBarBackgroundScheme } from '../../hooks/useAppBarBackgroundScheme';\n\nconst LogoRender = ({\n base64Logo,\n defaultLogo,\n width = 150,\n height = 40,\n}: {\n base64Logo: string | undefined;\n defaultLogo: JSX.Element;\n width?: number | string;\n height?: number | string;\n}) => {\n return base64Logo ? (\n <img\n data-testid=\"home-logo\"\n src={base64Logo}\n alt=\"Home logo\"\n style={{\n objectFit: 'contain',\n objectPosition: 'left',\n maxHeight: height,\n }}\n width={width}\n />\n ) : (\n defaultLogo\n );\n};\n\n/**\n * An interface representing the URLs for light and dark variants of a logo.\n * @public\n */\nexport type LogoURLs =\n | {\n /** The logo that will be used in global headers with a light-coloured background */\n light: string;\n /** The logo that will be used in global headers with a dark-coloured background */\n dark: string;\n }\n | string\n | undefined;\n\n/**\n * @public\n */\nexport interface CompanyLogoProps {\n /** An object containing the logo URLs */\n logo?: LogoURLs;\n /** The route to link the logo to */\n to?: string;\n /**\n * The width of the logo in pixels (defaults to 150px). This prop fixes an\n * issue where encoded SVGs without an explicit width would not render.\n * You likely do not need to set this prop, but we recommend setting it\n * to a value under 200px.\n */\n width?: string | number;\n /**\n * The maximum height of the logo in pixels (defaults to 40px).\n * Note that changing this value may result in changes in the height of the global header.\n **/\n height?: string | number;\n /** This prop is not used by this component. */\n layout?: CSSProperties;\n}\n\n/**\n * Gets a themed image based on the current theme.\n */\nconst useFullLogo = (logo: LogoURLs): string | undefined => {\n const appBarBackgroundScheme = useAppBarBackgroundScheme();\n\n const configApi = useApi(configApiRef);\n\n /** The fullLogo config specified by app.branding.fullLogo */\n const fullLogo = configApi.getOptional<LogoURLs>('app.branding.fullLogo');\n\n /** The URI of the logo specified by app.branding.fullLogo */\n const fullLogoURI =\n typeof fullLogo === 'string'\n ? fullLogo\n : fullLogo?.[appBarBackgroundScheme];\n\n /** The URI of the logo specified by CompanyLogo props */\n const propsLogoURI =\n typeof logo === 'string' ? logo : logo?.[appBarBackgroundScheme];\n\n return propsLogoURI ?? fullLogoURI ?? undefined;\n};\n\nexport const CompanyLogo = ({\n logo,\n width,\n height,\n to = '/',\n}: CompanyLogoProps) => {\n const logoURL = useFullLogo(logo);\n const configApi = useApi(configApiRef);\n const fullLogoWidth = configApi.getOptional<number | string>(\n 'app.branding.fullLogoWidth',\n );\n return (\n <Box\n data-testid=\"global-header-company-logo\"\n sx={{\n minWidth: '200px',\n marginRight: '13px', // align with BackstageContent\n display: 'flex',\n justifyContent: 'flex-start',\n alignItems: 'center',\n }}\n >\n <Link\n to={to}\n underline=\"none\"\n aria-label=\"Home\"\n style={{\n display: 'flex',\n justifyContent: 'flex-start',\n alignItems: 'center',\n }}\n >\n <LogoRender\n base64Logo={logoURL}\n defaultLogo={<DefaultLogo />}\n width={width ?? fullLogoWidth}\n height={height}\n />\n </Link>\n </Box>\n );\n};\n"],"names":[],"mappings":";;;;;;;AAsBA,MAAM,aAAa,CAAC;AAAA,EAClB,UAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAQ,GAAA,GAAA;AAAA,EACR,MAAS,GAAA;AACX,CAKM,KAAA;AACJ,EAAA,OAAO,UACL,mBAAA,GAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,aAAY,EAAA,WAAA;AAAA,MACZ,GAAK,EAAA,UAAA;AAAA,MACL,GAAI,EAAA,WAAA;AAAA,MACJ,KAAO,EAAA;AAAA,QACL,SAAW,EAAA,SAAA;AAAA,QACX,cAAgB,EAAA,MAAA;AAAA,QAChB,SAAW,EAAA;AAAA,OACb;AAAA,MACA;AAAA;AAAA,GAGF,GAAA,WAAA;AAEJ,CAAA;AA2CA,MAAM,WAAA,GAAc,CAAC,IAAuC,KAAA;AAC1D,EAAA,MAAM,yBAAyB,yBAA0B,EAAA;AAEzD,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AAGrC,EAAM,MAAA,QAAA,GAAW,SAAU,CAAA,WAAA,CAAsB,uBAAuB,CAAA;AAGxE,EAAA,MAAM,cACJ,OAAO,QAAA,KAAa,QAChB,GAAA,QAAA,GACA,WAAW,sBAAsB,CAAA;AAGvC,EAAA,MAAM,eACJ,OAAO,IAAA,KAAS,QAAW,GAAA,IAAA,GAAO,OAAO,sBAAsB,CAAA;AAEjE,EAAA,OAAO,gBAAgB,WAAe,IAAA,KAAA,CAAA;AACxC,CAAA;AAEO,MAAM,cAAc,CAAC;AAAA,EAC1B,IAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA,EAAK,GAAA;AACP,CAAwB,KAAA;AACtB,EAAM,MAAA,OAAA,GAAU,YAAY,IAAI,CAAA;AAChC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AACrC,EAAA,MAAM,gBAAgB,SAAU,CAAA,WAAA;AAAA,IAC9B;AAAA,GACF;AACA,EACE,uBAAA,GAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,aAAY,EAAA,4BAAA;AAAA,MACZ,EAAI,EAAA;AAAA,QACF,QAAU,EAAA,OAAA;AAAA,QACV,WAAa,EAAA,MAAA;AAAA;AAAA,QACb,OAAS,EAAA,MAAA;AAAA,QACT,cAAgB,EAAA,YAAA;AAAA,QAChB,UAAY,EAAA;AAAA,OACd;AAAA,MAEA,QAAA,kBAAA,GAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,EAAA;AAAA,UACA,SAAU,EAAA,MAAA;AAAA,UACV,YAAW,EAAA,MAAA;AAAA,UACX,KAAO,EAAA;AAAA,YACL,OAAS,EAAA,MAAA;AAAA,YACT,cAAgB,EAAA,YAAA;AAAA,YAChB,UAAY,EAAA;AAAA,WACd;AAAA,UAEA,QAAA,kBAAA,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,UAAY,EAAA,OAAA;AAAA,cACZ,WAAA,sBAAc,WAAY,EAAA,EAAA,CAAA;AAAA,cAC1B,OAAO,KAAS,IAAA,aAAA;AAAA,cAChB;AAAA;AAAA;AACF;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,45 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useMemo } from 'react';
3
+ import { HeaderDropdownComponent } from './HeaderDropdownComponent.esm.js';
4
+ import { useDropdownManager } from '../../hooks/useDropdownManager.esm.js';
5
+ import HelpOutlineIcon from '@mui/icons-material/HelpOutline';
6
+ import { useHelpDropdownMountPoints } from '../../hooks/useHelpDropdownMountPoints.esm.js';
7
+ import { MenuSection } from './MenuSection.esm.js';
8
+
9
+ const HelpDropdown = ({ layout }) => {
10
+ const { anchorEl, handleOpen, handleClose } = useDropdownManager();
11
+ const helpDropdownMountPoints = useHelpDropdownMountPoints();
12
+ const menuItems = useMemo(() => {
13
+ return (helpDropdownMountPoints ?? []).map((mp) => ({
14
+ Component: mp.Component,
15
+ icon: mp.config?.props?.icon,
16
+ label: mp.config?.props?.title,
17
+ link: mp.config?.props?.link,
18
+ tooltip: mp.config?.props?.tooltip,
19
+ style: mp.config?.style,
20
+ priority: mp.config?.priority ?? 0
21
+ })).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
22
+ }, [helpDropdownMountPoints]);
23
+ if (menuItems.length === 0) {
24
+ return null;
25
+ }
26
+ return /* @__PURE__ */ jsx(
27
+ HeaderDropdownComponent,
28
+ {
29
+ isIconButton: true,
30
+ tooltip: "Help",
31
+ buttonContent: /* @__PURE__ */ jsx(HelpOutlineIcon, {}),
32
+ buttonProps: {
33
+ color: "inherit",
34
+ sx: layout
35
+ },
36
+ onOpen: handleOpen,
37
+ onClose: handleClose,
38
+ anchorEl,
39
+ children: /* @__PURE__ */ jsx(MenuSection, { hideDivider: true, items: menuItems, handleClose })
40
+ }
41
+ );
42
+ };
43
+
44
+ export { HelpDropdown };
45
+ //# sourceMappingURL=HelpDropdown.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HelpDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/HelpDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useMemo } from 'react';\nimport type { CSSProperties } from 'react';\nimport { HeaderDropdownComponent } from './HeaderDropdownComponent';\nimport { useDropdownManager } from '../../hooks';\nimport HelpOutlineIcon from '@mui/icons-material/HelpOutline';\nimport { useHelpDropdownMountPoints } from '../../hooks/useHelpDropdownMountPoints';\nimport { MenuSection } from './MenuSection';\n\n/**\n * @public\n * Props for Help Dropdown\n */\nexport interface HelpDropdownProps {\n layout?: CSSProperties;\n}\n\nexport const HelpDropdown = ({ layout }: HelpDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n\n const helpDropdownMountPoints = useHelpDropdownMountPoints();\n\n const menuItems = useMemo(() => {\n return (helpDropdownMountPoints ?? [])\n .map(mp => ({\n Component: mp.Component,\n icon: mp.config?.props?.icon,\n label: mp.config?.props?.title,\n link: mp.config?.props?.link,\n tooltip: mp.config?.props?.tooltip,\n style: mp.config?.style,\n priority: mp.config?.priority ?? 0,\n }))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }, [helpDropdownMountPoints]);\n\n if (menuItems.length === 0) {\n return null;\n }\n\n return (\n <HeaderDropdownComponent\n isIconButton\n tooltip=\"Help\"\n buttonContent={<HelpOutlineIcon />}\n buttonProps={{\n color: 'inherit',\n sx: layout,\n }}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n >\n <MenuSection hideDivider items={menuItems} handleClose={handleClose} />\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AAgCO,MAAM,YAAe,GAAA,CAAC,EAAE,MAAA,EAAgC,KAAA;AAC7D,EAAA,MAAM,EAAE,QAAA,EAAU,UAAY,EAAA,WAAA,KAAgB,kBAAmB,EAAA;AAEjE,EAAA,MAAM,0BAA0B,0BAA2B,EAAA;AAE3D,EAAM,MAAA,SAAA,GAAY,QAAQ,MAAM;AAC9B,IAAA,OAAA,CAAQ,uBAA2B,IAAA,EAChC,EAAA,GAAA,CAAI,CAAO,EAAA,MAAA;AAAA,MACV,WAAW,EAAG,CAAA,SAAA;AAAA,MACd,IAAA,EAAM,EAAG,CAAA,MAAA,EAAQ,KAAO,EAAA,IAAA;AAAA,MACxB,KAAA,EAAO,EAAG,CAAA,MAAA,EAAQ,KAAO,EAAA,KAAA;AAAA,MACzB,IAAA,EAAM,EAAG,CAAA,MAAA,EAAQ,KAAO,EAAA,IAAA;AAAA,MACxB,OAAA,EAAS,EAAG,CAAA,MAAA,EAAQ,KAAO,EAAA,OAAA;AAAA,MAC3B,KAAA,EAAO,GAAG,MAAQ,EAAA,KAAA;AAAA,MAClB,QAAA,EAAU,EAAG,CAAA,MAAA,EAAQ,QAAY,IAAA;AAAA,KACnC,CAAE,CACD,CAAA,IAAA,CAAK,CAAC,CAAA,EAAG,CAAO,KAAA,CAAA,CAAA,CAAE,QAAY,IAAA,CAAA,KAAM,CAAE,CAAA,QAAA,IAAY,CAAE,CAAA,CAAA;AAAA,GACzD,EAAG,CAAC,uBAAuB,CAAC,CAAA;AAE5B,EAAI,IAAA,SAAA,CAAU,WAAW,CAAG,EAAA;AAC1B,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,YAAY,EAAA,IAAA;AAAA,MACZ,OAAQ,EAAA,MAAA;AAAA,MACR,aAAA,sBAAgB,eAAgB,EAAA,EAAA,CAAA;AAAA,MAChC,WAAa,EAAA;AAAA,QACX,KAAO,EAAA,SAAA;AAAA,QACP,EAAI,EAAA;AAAA,OACN;AAAA,MACA,MAAQ,EAAA,UAAA;AAAA,MACR,OAAS,EAAA,WAAA;AAAA,MACT,QAAA;AAAA,MAEA,8BAAC,WAAY,EAAA,EAAA,WAAA,EAAW,IAAC,EAAA,KAAA,EAAO,WAAW,WAA0B,EAAA;AAAA;AAAA,GACvE;AAEJ;;;;"}
@@ -3,6 +3,7 @@ import { useState, useRef, useEffect, useMemo } from 'react';
3
3
  import { useUserProfile } from '@backstage/plugin-user-settings';
4
4
  import { useApi } from '@backstage/core-plugin-api';
5
5
  import { catalogApiRef } from '@backstage/plugin-catalog-react';
6
+ import { parseEntityRef } from '@backstage/catalog-model';
6
7
  import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';
7
8
  import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
8
9
  import Avatar from '@mui/material/Avatar';
@@ -17,6 +18,7 @@ import { useDropdownManager } from '../../hooks/useDropdownManager.esm.js';
17
18
  const ProfileDropdown = ({ layout }) => {
18
19
  const { anchorEl, handleOpen, handleClose } = useDropdownManager();
19
20
  const [user, setUser] = useState();
21
+ const [profileLink, setProfileLink] = useState();
20
22
  const {
21
23
  displayName,
22
24
  backstageIdentity,
@@ -45,30 +47,52 @@ const ProfileDropdown = ({ layout }) => {
45
47
  useEffect(() => {
46
48
  const fetchUserEntity = async () => {
47
49
  let userProfile;
50
+ let profileUrl = null;
48
51
  try {
49
52
  if (backstageIdentity?.userEntityRef) {
53
+ const { namespace = "default", name } = parseEntityRef(
54
+ backstageIdentity.userEntityRef
55
+ );
56
+ profileUrl = `/catalog/${namespace}/user/${name}`;
50
57
  userProfile = await catalogApi.getEntityByRef(
51
58
  backstageIdentity.userEntityRef
52
59
  );
60
+ setUser(
61
+ userProfile?.spec?.profile?.displayName ?? userProfile?.metadata?.title
62
+ );
63
+ setProfileLink(profileUrl);
64
+ } else {
65
+ setUser(null);
66
+ setProfileLink(null);
53
67
  }
54
- setUser(
55
- userProfile?.spec?.profile?.displayName ?? userProfile?.metadata?.title
56
- );
57
68
  } catch (_err) {
58
69
  setUser(null);
70
+ setProfileLink(null);
59
71
  }
60
72
  };
61
73
  fetchUserEntity();
62
74
  }, [backstageIdentity, catalogApi]);
63
75
  const menuItems = useMemo(() => {
64
- return (profileDropdownMountPoints ?? []).map((mp) => ({
65
- Component: mp.Component,
66
- icon: mp.config?.props?.icon ?? "",
67
- label: mp.config?.props?.title ?? "",
68
- link: mp.config?.props?.link ?? "",
69
- priority: mp.config?.priority ?? 0
70
- })).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
71
- }, [profileDropdownMountPoints]);
76
+ return (profileDropdownMountPoints ?? []).map((mp) => {
77
+ const {
78
+ title = "",
79
+ icon = "",
80
+ link: staticLink = ""
81
+ } = mp.config?.props ?? {};
82
+ const isMyProfile = title.toLowerCase() === "my profile";
83
+ const link = isMyProfile ? profileLink ?? "" : staticLink;
84
+ if (!link && title) {
85
+ return null;
86
+ }
87
+ return {
88
+ Component: mp.Component,
89
+ label: title,
90
+ link,
91
+ priority: mp.config?.priority ?? 0,
92
+ ...icon && { icon }
93
+ };
94
+ }).filter((item) => item !== null).sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
95
+ }, [profileDropdownMountPoints, profileLink]);
72
96
  if (menuItems.length === 0) {
73
97
  return null;
74
98
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/ProfileDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useEffect, useMemo, useRef, useState } from 'react';\nimport type { CSSProperties } from 'react';\nimport { useUserProfile } from '@backstage/plugin-user-settings';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { UserEntity } from '@backstage/catalog-model';\nimport AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';\nimport KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';\nimport Avatar from '@mui/material/Avatar';\nimport Typography from '@mui/material/Typography';\nimport { lighten } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\n\nimport { MenuSection } from './MenuSection';\nimport { HeaderDropdownComponent } from './HeaderDropdownComponent';\nimport { useProfileDropdownMountPoints } from '../../hooks/useProfileDropdownMountPoints';\nimport { useDropdownManager } from '../../hooks';\n\n/**\n * @public\n * Props for Profile Dropdown\n */\nexport interface ProfileDropdownProps {\n layout?: CSSProperties;\n}\n\nexport const ProfileDropdown = ({ layout }: ProfileDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const [user, setUser] = useState<string | null>();\n const {\n displayName,\n backstageIdentity,\n profile,\n loading: profileLoading,\n } = useUserProfile();\n const catalogApi = useApi(catalogApiRef);\n\n const profileDropdownMountPoints = useProfileDropdownMountPoints();\n\n const headerRef = useRef<HTMLElement | null>(null);\n const [bgColor, setBgColor] = useState('#3C3F42');\n\n useEffect(() => {\n if (headerRef.current) {\n const computedStyle = window.getComputedStyle(headerRef.current);\n const baseColor = computedStyle.backgroundColor;\n setBgColor(lighten(baseColor, 0.2));\n }\n }, []);\n\n useEffect(() => {\n const container = document.getElementById('global-header');\n if (container) {\n const computedStyle = window.getComputedStyle(container);\n const baseColor = computedStyle.backgroundColor;\n setBgColor(lighten(baseColor, 0.2));\n }\n }, []);\n\n useEffect(() => {\n const fetchUserEntity = async () => {\n let userProfile;\n try {\n if (backstageIdentity?.userEntityRef) {\n userProfile = (await catalogApi.getEntityByRef(\n backstageIdentity.userEntityRef,\n )) as unknown as UserEntity;\n }\n setUser(\n userProfile?.spec?.profile?.displayName ??\n userProfile?.metadata?.title,\n );\n } catch (_err) {\n setUser(null);\n }\n };\n\n fetchUserEntity();\n }, [backstageIdentity, catalogApi]);\n\n const menuItems = useMemo(() => {\n return (profileDropdownMountPoints ?? [])\n .map(mp => ({\n Component: mp.Component,\n icon: mp.config?.props?.icon ?? '',\n label: mp.config?.props?.title ?? '',\n link: mp.config?.props?.link ?? '',\n priority: mp.config?.priority ?? 0,\n }))\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }, [profileDropdownMountPoints]);\n\n if (menuItems.length === 0) {\n return null;\n }\n\n const profileDisplayName = () => {\n const name = user ?? displayName;\n const regex = /^[^:/]+:[^/]+\\/[^/]+$/;\n if (regex.test(name)) {\n return name\n .charAt(name.indexOf('/') + 1)\n .toLocaleUpperCase('en-US')\n .concat(name.substring(name.indexOf('/') + 2));\n }\n return name;\n };\n\n return (\n <HeaderDropdownComponent\n buttonContent={\n <Box sx={{ display: 'flex', alignItems: 'center', ...layout }}>\n {!profileLoading && (\n <>\n {profile.picture ? (\n <Avatar\n src={profile.picture}\n sx={{ mr: 2, height: '32px', width: '32px' }}\n alt=\"Profile picture\"\n />\n ) : (\n <AccountCircleOutlinedIcon fontSize=\"small\" sx={{ mr: 1 }} />\n )}\n <Typography\n variant=\"body2\"\n sx={{\n display: { xs: 'none', md: 'block' },\n fontWeight: 500,\n mr: '1rem',\n }}\n >\n {profileDisplayName()}\n </Typography>\n </>\n )}\n <KeyboardArrowDownOutlinedIcon\n sx={{\n bgcolor: bgColor,\n borderRadius: '25%',\n }}\n />\n </Box>\n }\n buttonProps={{\n color: 'inherit',\n sx: {\n display: 'flex',\n alignItems: 'center',\n },\n }}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n >\n <MenuSection hideDivider items={menuItems} handleClose={handleClose} />\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ProfileDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/ProfileDropdown.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { useEffect, useMemo, useRef, useState } from 'react';\nimport type { CSSProperties } from 'react';\nimport { useUserProfile } from '@backstage/plugin-user-settings';\nimport { useApi } from '@backstage/core-plugin-api';\nimport { catalogApiRef } from '@backstage/plugin-catalog-react';\nimport { parseEntityRef, UserEntity } from '@backstage/catalog-model';\nimport AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';\nimport KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';\nimport Avatar from '@mui/material/Avatar';\nimport Typography from '@mui/material/Typography';\nimport { lighten } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\n\nimport { MenuItemConfig, MenuSection } from './MenuSection';\nimport { HeaderDropdownComponent } from './HeaderDropdownComponent';\nimport { useProfileDropdownMountPoints } from '../../hooks/useProfileDropdownMountPoints';\nimport { useDropdownManager } from '../../hooks';\n\n/**\n * @public\n * Props for Profile Dropdown\n */\nexport interface ProfileDropdownProps {\n layout?: CSSProperties;\n}\n\nexport const ProfileDropdown = ({ layout }: ProfileDropdownProps) => {\n const { anchorEl, handleOpen, handleClose } = useDropdownManager();\n const [user, setUser] = useState<string | null>();\n const [profileLink, setProfileLink] = useState<string | null>();\n const {\n displayName,\n backstageIdentity,\n profile,\n loading: profileLoading,\n } = useUserProfile();\n const catalogApi = useApi(catalogApiRef);\n\n const profileDropdownMountPoints = useProfileDropdownMountPoints();\n\n const headerRef = useRef<HTMLElement | null>(null);\n const [bgColor, setBgColor] = useState('#3C3F42');\n\n useEffect(() => {\n if (headerRef.current) {\n const computedStyle = window.getComputedStyle(headerRef.current);\n const baseColor = computedStyle.backgroundColor;\n setBgColor(lighten(baseColor, 0.2));\n }\n }, []);\n\n useEffect(() => {\n const container = document.getElementById('global-header');\n if (container) {\n const computedStyle = window.getComputedStyle(container);\n const baseColor = computedStyle.backgroundColor;\n setBgColor(lighten(baseColor, 0.2));\n }\n }, []);\n\n useEffect(() => {\n const fetchUserEntity = async () => {\n let userProfile;\n let profileUrl: string | null = null;\n\n try {\n if (backstageIdentity?.userEntityRef) {\n const { namespace = 'default', name } = parseEntityRef(\n backstageIdentity.userEntityRef,\n );\n profileUrl = `/catalog/${namespace}/user/${name}`;\n\n userProfile = (await catalogApi.getEntityByRef(\n backstageIdentity.userEntityRef,\n )) as unknown as UserEntity;\n setUser(\n userProfile?.spec?.profile?.displayName ??\n userProfile?.metadata?.title,\n );\n setProfileLink(profileUrl);\n } else {\n setUser(null);\n setProfileLink(null);\n }\n } catch (_err) {\n setUser(null);\n setProfileLink(null);\n }\n };\n\n fetchUserEntity();\n }, [backstageIdentity, catalogApi]);\n\n const menuItems = useMemo(() => {\n return (profileDropdownMountPoints ?? [])\n .map(mp => {\n const {\n title = '',\n icon = '',\n link: staticLink = '',\n } = mp.config?.props ?? {};\n const isMyProfile = title.toLowerCase() === 'my profile';\n const link = isMyProfile ? profileLink ?? '' : staticLink;\n\n if (!link && title) {\n return null;\n }\n\n return {\n Component: mp.Component,\n label: title,\n link,\n priority: mp.config?.priority ?? 0,\n ...(icon && { icon }),\n };\n })\n .filter((item: MenuItemConfig) => item !== null)\n .sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));\n }, [profileDropdownMountPoints, profileLink]);\n\n if (menuItems.length === 0) {\n return null;\n }\n\n const profileDisplayName = () => {\n const name = user ?? displayName;\n const regex = /^[^:/]+:[^/]+\\/[^/]+$/;\n if (regex.test(name)) {\n return name\n .charAt(name.indexOf('/') + 1)\n .toLocaleUpperCase('en-US')\n .concat(name.substring(name.indexOf('/') + 2));\n }\n return name;\n };\n\n return (\n <HeaderDropdownComponent\n buttonContent={\n <Box sx={{ display: 'flex', alignItems: 'center', ...layout }}>\n {!profileLoading && (\n <>\n {profile.picture ? (\n <Avatar\n src={profile.picture}\n sx={{ mr: 2, height: '32px', width: '32px' }}\n alt=\"Profile picture\"\n />\n ) : (\n <AccountCircleOutlinedIcon fontSize=\"small\" sx={{ mr: 1 }} />\n )}\n <Typography\n variant=\"body2\"\n sx={{\n display: { xs: 'none', md: 'block' },\n fontWeight: 500,\n mr: '1rem',\n }}\n >\n {profileDisplayName()}\n </Typography>\n </>\n )}\n <KeyboardArrowDownOutlinedIcon\n sx={{\n bgcolor: bgColor,\n borderRadius: '25%',\n }}\n />\n </Box>\n }\n buttonProps={{\n color: 'inherit',\n sx: {\n display: 'flex',\n alignItems: 'center',\n },\n }}\n onOpen={handleOpen}\n onClose={handleClose}\n anchorEl={anchorEl}\n >\n <MenuSection hideDivider items={menuItems} handleClose={handleClose} />\n </HeaderDropdownComponent>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AA0CO,MAAM,eAAkB,GAAA,CAAC,EAAE,MAAA,EAAmC,KAAA;AACnE,EAAA,MAAM,EAAE,QAAA,EAAU,UAAY,EAAA,WAAA,KAAgB,kBAAmB,EAAA;AACjE,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAI,QAAwB,EAAA;AAChD,EAAA,MAAM,CAAC,WAAA,EAAa,cAAc,CAAA,GAAI,QAAwB,EAAA;AAC9D,EAAM,MAAA;AAAA,IACJ,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,OAAA;AAAA,IACA,OAAS,EAAA;AAAA,MACP,cAAe,EAAA;AACnB,EAAM,MAAA,UAAA,GAAa,OAAO,aAAa,CAAA;AAEvC,EAAA,MAAM,6BAA6B,6BAA8B,EAAA;AAEjE,EAAM,MAAA,SAAA,GAAY,OAA2B,IAAI,CAAA;AACjD,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAI,SAAS,SAAS,CAAA;AAEhD,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,IAAI,UAAU,OAAS,EAAA;AACrB,MAAA,MAAM,aAAgB,GAAA,MAAA,CAAO,gBAAiB,CAAA,SAAA,CAAU,OAAO,CAAA;AAC/D,MAAA,MAAM,YAAY,aAAc,CAAA,eAAA;AAChC,MAAW,UAAA,CAAA,OAAA,CAAQ,SAAW,EAAA,GAAG,CAAC,CAAA;AAAA;AACpC,GACF,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAM,MAAA,SAAA,GAAY,QAAS,CAAA,cAAA,CAAe,eAAe,CAAA;AACzD,IAAA,IAAI,SAAW,EAAA;AACb,MAAM,MAAA,aAAA,GAAgB,MAAO,CAAA,gBAAA,CAAiB,SAAS,CAAA;AACvD,MAAA,MAAM,YAAY,aAAc,CAAA,eAAA;AAChC,MAAW,UAAA,CAAA,OAAA,CAAQ,SAAW,EAAA,GAAG,CAAC,CAAA;AAAA;AACpC,GACF,EAAG,EAAE,CAAA;AAEL,EAAA,SAAA,CAAU,MAAM;AACd,IAAA,MAAM,kBAAkB,YAAY;AAClC,MAAI,IAAA,WAAA;AACJ,MAAA,IAAI,UAA4B,GAAA,IAAA;AAEhC,MAAI,IAAA;AACF,QAAA,IAAI,mBAAmB,aAAe,EAAA;AACpC,UAAA,MAAM,EAAE,SAAA,GAAY,SAAW,EAAA,IAAA,EAAS,GAAA,cAAA;AAAA,YACtC,iBAAkB,CAAA;AAAA,WACpB;AACA,UAAa,UAAA,GAAA,CAAA,SAAA,EAAY,SAAS,CAAA,MAAA,EAAS,IAAI,CAAA,CAAA;AAE/C,UAAA,WAAA,GAAe,MAAM,UAAW,CAAA,cAAA;AAAA,YAC9B,iBAAkB,CAAA;AAAA,WACpB;AACA,UAAA,OAAA;AAAA,YACE,WAAa,EAAA,IAAA,EAAM,OAAS,EAAA,WAAA,IAC1B,aAAa,QAAU,EAAA;AAAA,WAC3B;AACA,UAAA,cAAA,CAAe,UAAU,CAAA;AAAA,SACpB,MAAA;AACL,UAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,UAAA,cAAA,CAAe,IAAI,CAAA;AAAA;AACrB,eACO,IAAM,EAAA;AACb,QAAA,OAAA,CAAQ,IAAI,CAAA;AACZ,QAAA,cAAA,CAAe,IAAI,CAAA;AAAA;AACrB,KACF;AAEA,IAAgB,eAAA,EAAA;AAAA,GACf,EAAA,CAAC,iBAAmB,EAAA,UAAU,CAAC,CAAA;AAElC,EAAM,MAAA,SAAA,GAAY,QAAQ,MAAM;AAC9B,IAAA,OAAA,CAAQ,0BAA8B,IAAA,EACnC,EAAA,GAAA,CAAI,CAAM,EAAA,KAAA;AACT,MAAM,MAAA;AAAA,QACJ,KAAQ,GAAA,EAAA;AAAA,QACR,IAAO,GAAA,EAAA;AAAA,QACP,MAAM,UAAa,GAAA;AAAA,OACjB,GAAA,EAAA,CAAG,MAAQ,EAAA,KAAA,IAAS,EAAC;AACzB,MAAM,MAAA,WAAA,GAAc,KAAM,CAAA,WAAA,EAAkB,KAAA,YAAA;AAC5C,MAAM,MAAA,IAAA,GAAO,WAAc,GAAA,WAAA,IAAe,EAAK,GAAA,UAAA;AAE/C,MAAI,IAAA,CAAC,QAAQ,KAAO,EAAA;AAClB,QAAO,OAAA,IAAA;AAAA;AAGT,MAAO,OAAA;AAAA,QACL,WAAW,EAAG,CAAA,SAAA;AAAA,QACd,KAAO,EAAA,KAAA;AAAA,QACP,IAAA;AAAA,QACA,QAAA,EAAU,EAAG,CAAA,MAAA,EAAQ,QAAY,IAAA,CAAA;AAAA,QACjC,GAAI,IAAQ,IAAA,EAAE,IAAK;AAAA,OACrB;AAAA,KACD,CACA,CAAA,MAAA,CAAO,CAAC,IAAA,KAAyB,SAAS,IAAI,CAAA,CAC9C,IAAK,CAAA,CAAC,GAAG,CAAO,KAAA,CAAA,CAAA,CAAE,YAAY,CAAM,KAAA,CAAA,CAAE,YAAY,CAAE,CAAA,CAAA;AAAA,GACtD,EAAA,CAAC,0BAA4B,EAAA,WAAW,CAAC,CAAA;AAE5C,EAAI,IAAA,SAAA,CAAU,WAAW,CAAG,EAAA;AAC1B,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,MAAM,qBAAqB,MAAM;AAC/B,IAAA,MAAM,OAAO,IAAQ,IAAA,WAAA;AACrB,IAAA,MAAM,KAAQ,GAAA,uBAAA;AACd,IAAI,IAAA,KAAA,CAAM,IAAK,CAAA,IAAI,CAAG,EAAA;AACpB,MAAA,OAAO,KACJ,MAAO,CAAA,IAAA,CAAK,QAAQ,GAAG,CAAA,GAAI,CAAC,CAC5B,CAAA,iBAAA,CAAkB,OAAO,CACzB,CAAA,MAAA,CAAO,KAAK,SAAU,CAAA,IAAA,CAAK,QAAQ,GAAG,CAAA,GAAI,CAAC,CAAC,CAAA;AAAA;AAEjD,IAAO,OAAA,IAAA;AAAA,GACT;AAEA,EACE,uBAAA,GAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,aAAA,kBACG,IAAA,CAAA,GAAA,EAAA,EAAI,EAAI,EAAA,EAAE,OAAS,EAAA,MAAA,EAAQ,UAAY,EAAA,QAAA,EAAU,GAAG,MAAA,EAClD,EAAA,QAAA,EAAA;AAAA,QAAA,CAAC,kCAEG,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,UAAA,OAAA,CAAQ,OACP,mBAAA,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,KAAK,OAAQ,CAAA,OAAA;AAAA,cACb,IAAI,EAAE,EAAA,EAAI,GAAG,MAAQ,EAAA,MAAA,EAAQ,OAAO,MAAO,EAAA;AAAA,cAC3C,GAAI,EAAA;AAAA;AAAA,WACN,uBAEC,yBAA0B,EAAA,EAAA,QAAA,EAAS,SAAQ,EAAI,EAAA,EAAE,EAAI,EAAA,CAAA,EAAK,EAAA,CAAA;AAAA,0BAE7D,GAAA;AAAA,YAAC,UAAA;AAAA,YAAA;AAAA,cACC,OAAQ,EAAA,OAAA;AAAA,cACR,EAAI,EAAA;AAAA,gBACF,OAAS,EAAA,EAAE,EAAI,EAAA,MAAA,EAAQ,IAAI,OAAQ,EAAA;AAAA,gBACnC,UAAY,EAAA,GAAA;AAAA,gBACZ,EAAI,EAAA;AAAA,eACN;AAAA,cAEC,QAAmB,EAAA,kBAAA;AAAA;AAAA;AACtB,SACF,EAAA,CAAA;AAAA,wBAEF,GAAA;AAAA,UAAC,6BAAA;AAAA,UAAA;AAAA,YACC,EAAI,EAAA;AAAA,cACF,OAAS,EAAA,OAAA;AAAA,cACT,YAAc,EAAA;AAAA;AAChB;AAAA;AACF,OACF,EAAA,CAAA;AAAA,MAEF,WAAa,EAAA;AAAA,QACX,KAAO,EAAA,SAAA;AAAA,QACP,EAAI,EAAA;AAAA,UACF,OAAS,EAAA,MAAA;AAAA,UACT,UAAY,EAAA;AAAA;AACd,OACF;AAAA,MACA,MAAQ,EAAA,UAAA;AAAA,MACR,OAAS,EAAA,WAAA;AAAA,MACT,QAAA;AAAA,MAEA,8BAAC,WAAY,EAAA,EAAA,WAAA,EAAW,IAAC,EAAA,KAAA,EAAO,WAAW,WAA0B,EAAA;AAAA;AAAA,GACvE;AAEJ;;;;"}
@@ -0,0 +1,34 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { useCallback } from 'react';
3
+ import MenuItem from '@mui/material/MenuItem';
4
+ import { MenuItemLink } from '../MenuItemLink/MenuItemLink.esm.js';
5
+ import { QUICKSTART_DRAWER_OPEN_KEY } from './const.esm.js';
6
+ import { useQuickstartButtonPermission } from './useQuickstartButtonPermission.esm.js';
7
+
8
+ const QuickstartButton = ({
9
+ icon = "quickstart",
10
+ title = "Quick start",
11
+ tooltip,
12
+ style
13
+ }) => {
14
+ const isAllowed = useQuickstartButtonPermission();
15
+ const toggleDrawer = useCallback(() => {
16
+ const isDrawerOpen = localStorage.getItem(QUICKSTART_DRAWER_OPEN_KEY) === "true";
17
+ localStorage.setItem(
18
+ QUICKSTART_DRAWER_OPEN_KEY,
19
+ (!isDrawerOpen).toString()
20
+ );
21
+ }, []);
22
+ return isAllowed ? /* @__PURE__ */ jsx(
23
+ MenuItem,
24
+ {
25
+ sx: { width: "100%", color: "inherit", ...style },
26
+ "data-testid": "quickstart-button",
27
+ onClick: toggleDrawer,
28
+ children: /* @__PURE__ */ jsx(MenuItemLink, { to: "", title, icon, tooltip })
29
+ }
30
+ ) : null;
31
+ };
32
+
33
+ export { QuickstartButton };
34
+ //# sourceMappingURL=QuickstartButton.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"QuickstartButton.esm.js","sources":["../../../src/components/QuickstartButton/QuickstartButton.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { CSSProperties, useCallback } from 'react';\nimport MenuItem from '@mui/material/MenuItem';\nimport { MenuItemLink } from '../MenuItemLink/MenuItemLink';\nimport { QUICKSTART_DRAWER_OPEN_KEY } from './const';\nimport { useQuickstartButtonPermission } from './useQuickstartButtonPermission';\n\n/**\n * @public\n */\nexport interface QuickstartButtonProps {\n icon?: string;\n title?: string;\n tooltip?: string;\n style?: CSSProperties;\n}\n\n/**\n * @public\n */\nexport const QuickstartButton = ({\n icon = 'quickstart',\n title = 'Quick start',\n tooltip,\n style,\n}: QuickstartButtonProps) => {\n const isAllowed = useQuickstartButtonPermission();\n const toggleDrawer = useCallback(() => {\n const isDrawerOpen =\n localStorage.getItem(QUICKSTART_DRAWER_OPEN_KEY) === 'true';\n localStorage.setItem(\n QUICKSTART_DRAWER_OPEN_KEY,\n (!isDrawerOpen).toString(),\n );\n }, []);\n\n return isAllowed ? (\n <MenuItem\n sx={{ width: '100%', color: 'inherit', ...style }}\n data-testid=\"quickstart-button\"\n onClick={toggleDrawer}\n >\n <MenuItemLink to=\"\" title={title} icon={icon} tooltip={tooltip} />\n </MenuItem>\n ) : null;\n};\n"],"names":[],"mappings":";;;;;;;AAmCO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,IAAO,GAAA,YAAA;AAAA,EACP,KAAQ,GAAA,aAAA;AAAA,EACR,OAAA;AAAA,EACA;AACF,CAA6B,KAAA;AAC3B,EAAA,MAAM,YAAY,6BAA8B,EAAA;AAChD,EAAM,MAAA,YAAA,GAAe,YAAY,MAAM;AACrC,IAAA,MAAM,YACJ,GAAA,YAAA,CAAa,OAAQ,CAAA,0BAA0B,CAAM,KAAA,MAAA;AACvD,IAAa,YAAA,CAAA,OAAA;AAAA,MACX,0BAAA;AAAA,MACC,CAAA,CAAC,cAAc,QAAS;AAAA,KAC3B;AAAA,GACF,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,SACL,mBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAI,EAAE,KAAA,EAAO,QAAQ,KAAO,EAAA,SAAA,EAAW,GAAG,KAAM,EAAA;AAAA,MAChD,aAAY,EAAA,mBAAA;AAAA,MACZ,OAAS,EAAA,YAAA;AAAA,MAET,8BAAC,YAAa,EAAA,EAAA,EAAA,EAAG,EAAG,EAAA,KAAA,EAAc,MAAY,OAAkB,EAAA;AAAA;AAAA,GAEhE,GAAA,IAAA;AACN;;;;"}
@@ -0,0 +1,4 @@
1
+ const QUICKSTART_DRAWER_OPEN_KEY = "quickstart-drawer-open";
2
+
3
+ export { QUICKSTART_DRAWER_OPEN_KEY };
4
+ //# sourceMappingURL=const.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"const.esm.js","sources":["../../../src/components/QuickstartButton/const.ts"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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\nexport const QUICKSTART_DRAWER_OPEN_KEY = 'quickstart-drawer-open';\n"],"names":[],"mappings":"AAgBO,MAAM,0BAA6B,GAAA;;;;"}
@@ -0,0 +1,27 @@
1
+ import { useApi, identityApiRef, configApiRef } from '@backstage/core-plugin-api';
2
+ import { useAsync } from 'react-use';
3
+
4
+ const useQuickstartButtonPermission = () => {
5
+ const identityApi = useApi(identityApiRef);
6
+ const configApi = useApi(configApiRef);
7
+ const getUserAuthorization = async () => {
8
+ const { token: idToken } = await identityApi.getCredentials();
9
+ const backendUrl = configApi.getString("backend.baseUrl");
10
+ const jsonResponse = await fetch(`${backendUrl}/api/permission/`, {
11
+ headers: {
12
+ ...idToken && { Authorization: `Bearer ${idToken}` }
13
+ }
14
+ });
15
+ return jsonResponse.json();
16
+ };
17
+ const { loading: isUserLoading, value: result } = useAsync(
18
+ async () => await getUserAuthorization(),
19
+ []
20
+ );
21
+ const isRBACPluginEnabled = configApi.getOptionalBoolean("permission.enabled");
22
+ if (!isRBACPluginEnabled) return true;
23
+ return !isUserLoading && result.status === "Authorized";
24
+ };
25
+
26
+ export { useQuickstartButtonPermission };
27
+ //# sourceMappingURL=useQuickstartButtonPermission.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useQuickstartButtonPermission.esm.js","sources":["../../../src/components/QuickstartButton/useQuickstartButtonPermission.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 {\n configApiRef,\n identityApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\nimport { useAsync } from 'react-use';\n\nexport const useQuickstartButtonPermission = () => {\n const identityApi = useApi(identityApiRef);\n const configApi = useApi(configApiRef);\n\n const getUserAuthorization = async () => {\n const { token: idToken } = await identityApi.getCredentials();\n const backendUrl = configApi.getString('backend.baseUrl');\n const jsonResponse = await fetch(`${backendUrl}/api/permission/`, {\n headers: {\n ...(idToken && { Authorization: `Bearer ${idToken}` }),\n },\n });\n return jsonResponse.json();\n };\n const { loading: isUserLoading, value: result } = useAsync(\n async () => await getUserAuthorization(),\n [],\n );\n\n const isRBACPluginEnabled =\n configApi.getOptionalBoolean('permission.enabled');\n\n if (!isRBACPluginEnabled) return true;\n\n return !isUserLoading && result.status === 'Authorized';\n};\n"],"names":[],"mappings":";;;AAuBO,MAAM,gCAAgC,MAAM;AACjD,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAM,MAAA,SAAA,GAAY,OAAO,YAAY,CAAA;AAErC,EAAA,MAAM,uBAAuB,YAAY;AACvC,IAAA,MAAM,EAAE,KAAO,EAAA,OAAA,EAAY,GAAA,MAAM,YAAY,cAAe,EAAA;AAC5D,IAAM,MAAA,UAAA,GAAa,SAAU,CAAA,SAAA,CAAU,iBAAiB,CAAA;AACxD,IAAA,MAAM,YAAe,GAAA,MAAM,KAAM,CAAA,CAAA,EAAG,UAAU,CAAoB,gBAAA,CAAA,EAAA;AAAA,MAChE,OAAS,EAAA;AAAA,QACP,GAAI,OAAW,IAAA,EAAE,aAAe,EAAA,CAAA,OAAA,EAAU,OAAO,CAAG,CAAA;AAAA;AACtD,KACD,CAAA;AACD,IAAA,OAAO,aAAa,IAAK,EAAA;AAAA,GAC3B;AACA,EAAA,MAAM,EAAE,OAAA,EAAS,aAAe,EAAA,KAAA,EAAO,QAAW,GAAA,QAAA;AAAA,IAChD,YAAY,MAAM,oBAAqB,EAAA;AAAA,IACvC;AAAC,GACH;AAEA,EAAM,MAAA,mBAAA,GACJ,SAAU,CAAA,kBAAA,CAAmB,oBAAoB,CAAA;AAEnD,EAAI,IAAA,CAAC,qBAA4B,OAAA,IAAA;AAEjC,EAAO,OAAA,CAAC,aAAiB,IAAA,MAAA,CAAO,MAAW,KAAA,YAAA;AAC7C;;;;"}
@@ -1,19 +1,15 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import { useApiHolder, configApiRef } from '@backstage/core-plugin-api';
3
- import { Link as Link$1 } from '@backstage/core-components';
4
- import Box from '@mui/material/Box';
5
- import IconButton from '@mui/material/IconButton';
6
- import Tooltip from '@mui/material/Tooltip';
7
- import HelpIcon from '@mui/icons-material/HelpOutline';
3
+ import { Link } from '@backstage/core-components';
4
+ import MenuItem from '@mui/material/MenuItem';
5
+ import { MenuItemLink } from '../MenuItemLink/MenuItemLink.esm.js';
8
6
 
9
- const Link = (props) => /* @__PURE__ */ jsx(Link$1, { ...props, color: "inherit", externalLinkIcon: false });
10
7
  const SupportButton = ({
11
8
  title = "Support",
12
- tooltip,
13
- color = "inherit",
14
- size = "small",
15
9
  to,
16
- layout
10
+ icon = "support",
11
+ tooltip,
12
+ style
17
13
  }) => {
18
14
  const apiHolder = useApiHolder();
19
15
  const config = apiHolder.get(configApiRef);
@@ -21,24 +17,24 @@ const SupportButton = ({
21
17
  if (!supportUrl) {
22
18
  return null;
23
19
  }
24
- const isExternalLink = supportUrl.startsWith("http://") || supportUrl.startsWith("https://");
25
- return /* @__PURE__ */ jsx(Box, { sx: layout, children: /* @__PURE__ */ jsx(
26
- Tooltip,
20
+ return /* @__PURE__ */ jsx(
21
+ MenuItem,
27
22
  {
28
- title: tooltip ?? `${title}${isExternalLink ? " (external link)" : ""}`,
29
- children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
30
- IconButton,
23
+ to: supportUrl,
24
+ component: Link,
25
+ sx: { width: "100%", color: "inherit", ...style },
26
+ "data-testid": "support-button",
27
+ children: /* @__PURE__ */ jsx(
28
+ MenuItemLink,
31
29
  {
32
- component: Link,
33
- color,
34
- size,
35
30
  to: supportUrl,
36
- "aria-label": title,
37
- children: /* @__PURE__ */ jsx(HelpIcon, { fontSize: size })
31
+ title,
32
+ icon,
33
+ tooltip
38
34
  }
39
- ) })
35
+ )
40
36
  }
41
- ) });
37
+ );
42
38
  };
43
39
 
44
40
  export { SupportButton };
@@ -1 +1 @@
1
- {"version":3,"file":"SupportButton.esm.js","sources":["../../../src/components/SupportButton/SupportButton.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 type { CSSProperties } from 'react';\nimport { configApiRef, useApiHolder } from '@backstage/core-plugin-api';\nimport { Link as BackstageLink } from '@backstage/core-components';\n\nimport Box from '@mui/material/Box';\nimport IconButton from '@mui/material/IconButton';\nimport Tooltip from '@mui/material/Tooltip';\nimport HelpIcon from '@mui/icons-material/HelpOutline';\n\n/**\n * @public\n */\nexport interface SupportButtonProps {\n title?: string;\n tooltip?: string;\n color?:\n | 'inherit'\n | 'default'\n | 'primary'\n | 'secondary'\n | 'error'\n | 'info'\n | 'success'\n | 'warning';\n size?: 'small' | 'medium' | 'large';\n to?: string;\n layout?: CSSProperties;\n}\n\n// Backstage Link automatically detects external links and emits analytic events.\nconst Link = (props: any) => (\n <BackstageLink {...props} color=\"inherit\" externalLinkIcon={false} />\n);\n\n/**\n * @public\n */\nexport const SupportButton = ({\n title = 'Support',\n tooltip,\n color = 'inherit',\n size = 'small',\n to,\n layout,\n}: SupportButtonProps) => {\n const apiHolder = useApiHolder();\n const config = apiHolder.get(configApiRef);\n const supportUrl = to ?? config?.getOptionalString('app.support.url');\n\n if (!supportUrl) {\n return null;\n }\n\n const isExternalLink =\n supportUrl.startsWith('http://') || supportUrl.startsWith('https://');\n\n return (\n <Box sx={layout}>\n <Tooltip\n title={tooltip ?? `${title}${isExternalLink ? ' (external link)' : ''}`}\n >\n <div>\n <IconButton\n component={Link}\n color={color}\n size={size}\n to={supportUrl}\n aria-label={title}\n >\n <HelpIcon fontSize={size} />\n </IconButton>\n </div>\n </Tooltip>\n </Box>\n );\n};\n"],"names":["BackstageLink"],"mappings":";;;;;;;;AA8CA,MAAM,IAAA,GAAO,CAAC,KAAA,qBACX,GAAA,CAAAA,MAAA,EAAA,EAAe,GAAG,KAAO,EAAA,KAAA,EAAM,SAAU,EAAA,gBAAA,EAAkB,KAAO,EAAA,CAAA;AAM9D,MAAM,gBAAgB,CAAC;AAAA,EAC5B,KAAQ,GAAA,SAAA;AAAA,EACR,OAAA;AAAA,EACA,KAAQ,GAAA,SAAA;AAAA,EACR,IAAO,GAAA,OAAA;AAAA,EACP,EAAA;AAAA,EACA;AACF,CAA0B,KAAA;AACxB,EAAA,MAAM,YAAY,YAAa,EAAA;AAC/B,EAAM,MAAA,MAAA,GAAS,SAAU,CAAA,GAAA,CAAI,YAAY,CAAA;AACzC,EAAA,MAAM,UAAa,GAAA,EAAA,IAAM,MAAQ,EAAA,iBAAA,CAAkB,iBAAiB,CAAA;AAEpE,EAAA,IAAI,CAAC,UAAY,EAAA;AACf,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,MAAM,iBACJ,UAAW,CAAA,UAAA,CAAW,SAAS,CAAK,IAAA,UAAA,CAAW,WAAW,UAAU,CAAA;AAEtE,EACE,uBAAA,GAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,MACP,EAAA,QAAA,kBAAA,GAAA;AAAA,IAAC,OAAA;AAAA,IAAA;AAAA,MACC,OAAO,OAAW,IAAA,CAAA,EAAG,KAAK,CAAG,EAAA,cAAA,GAAiB,qBAAqB,EAAE,CAAA,CAAA;AAAA,MAErE,8BAAC,KACC,EAAA,EAAA,QAAA,kBAAA,GAAA;AAAA,QAAC,UAAA;AAAA,QAAA;AAAA,UACC,SAAW,EAAA,IAAA;AAAA,UACX,KAAA;AAAA,UACA,IAAA;AAAA,UACA,EAAI,EAAA,UAAA;AAAA,UACJ,YAAY,EAAA,KAAA;AAAA,UAEZ,QAAA,kBAAA,GAAA,CAAC,QAAS,EAAA,EAAA,QAAA,EAAU,IAAM,EAAA;AAAA;AAAA,OAE9B,EAAA;AAAA;AAAA,GAEJ,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"SupportButton.esm.js","sources":["../../../src/components/SupportButton/SupportButton.tsx"],"sourcesContent":["/*\n * Copyright Red Hat, Inc.\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 { configApiRef, useApiHolder } from '@backstage/core-plugin-api';\nimport { Link } from '@backstage/core-components';\nimport MenuItem from '@mui/material/MenuItem';\nimport { MenuItemLink } from '../MenuItemLink/MenuItemLink';\nimport { CSSProperties } from 'react';\n\n/**\n * @public\n */\nexport interface SupportButtonProps {\n icon?: string;\n title?: string;\n to?: string;\n tooltip?: string;\n style?: CSSProperties;\n}\n/**\n * @public\n */\nexport const SupportButton = ({\n title = 'Support',\n to,\n icon = 'support',\n tooltip,\n style,\n}: SupportButtonProps) => {\n const apiHolder = useApiHolder();\n const config = apiHolder.get(configApiRef);\n const supportUrl = to ?? config?.getOptionalString('app.support.url');\n\n if (!supportUrl) {\n return null;\n }\n\n return (\n <MenuItem\n to={supportUrl}\n component={Link}\n sx={{ width: '100%', color: 'inherit', ...style }}\n data-testid=\"support-button\"\n >\n <MenuItemLink\n to={supportUrl}\n title={title}\n icon={icon}\n tooltip={tooltip}\n />\n </MenuItem>\n );\n};\n"],"names":[],"mappings":";;;;;;AAmCO,MAAM,gBAAgB,CAAC;AAAA,EAC5B,KAAQ,GAAA,SAAA;AAAA,EACR,EAAA;AAAA,EACA,IAAO,GAAA,SAAA;AAAA,EACP,OAAA;AAAA,EACA;AACF,CAA0B,KAAA;AACxB,EAAA,MAAM,YAAY,YAAa,EAAA;AAC/B,EAAM,MAAA,MAAA,GAAS,SAAU,CAAA,GAAA,CAAI,YAAY,CAAA;AACzC,EAAA,MAAM,UAAa,GAAA,EAAA,IAAM,MAAQ,EAAA,iBAAA,CAAkB,iBAAiB,CAAA;AAEpE,EAAA,IAAI,CAAC,UAAY,EAAA;AACf,IAAO,OAAA,IAAA;AAAA;AAGT,EACE,uBAAA,GAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,EAAI,EAAA,UAAA;AAAA,MACJ,SAAW,EAAA,IAAA;AAAA,MACX,IAAI,EAAE,KAAA,EAAO,QAAQ,KAAO,EAAA,SAAA,EAAW,GAAG,KAAM,EAAA;AAAA,MAChD,aAAY,EAAA,gBAAA;AAAA,MAEZ,QAAA,kBAAA,GAAA;AAAA,QAAC,YAAA;AAAA,QAAA;AAAA,UACC,EAAI,EAAA,UAAA;AAAA,UACJ,KAAA;AAAA,UACA,IAAA;AAAA,UACA;AAAA;AAAA;AACF;AAAA,GACF;AAEJ;;;;"}
@@ -12,6 +12,8 @@ import { Spacer } from '../components/Spacer/Spacer.esm.js';
12
12
  import { StarredDropdown } from '../components/HeaderDropdownComponent/StarredDropdown.esm.js';
13
13
  import { ApplicationLauncherDropdown } from '../components/HeaderDropdownComponent/ApplicationLauncherDropdown.esm.js';
14
14
  import { CompanyLogo } from '../components/CompanyLogo/CompanyLogo.esm.js';
15
+ import { HelpDropdown } from '../components/HeaderDropdownComponent/HelpDropdown.esm.js';
16
+ import { QuickstartButton } from '../components/QuickstartButton/QuickstartButton.esm.js';
15
17
 
16
18
  const defaultGlobalHeaderComponentsMountPoints = [
17
19
  {
@@ -72,7 +74,7 @@ const defaultGlobalHeaderComponentsMountPoints = [
72
74
  }
73
75
  },
74
76
  {
75
- Component: SupportButton,
77
+ Component: HelpDropdown,
76
78
  config: {
77
79
  priority: 80
78
80
  }
@@ -123,6 +125,16 @@ const defaultProfileDropdownMountPoints = [
123
125
  }
124
126
  }
125
127
  },
128
+ {
129
+ Component: MenuItemLink,
130
+ config: {
131
+ priority: 150,
132
+ props: {
133
+ title: "My profile",
134
+ icon: "account"
135
+ }
136
+ }
137
+ },
126
138
  {
127
139
  Component: LogoutButton,
128
140
  config: {
@@ -130,6 +142,20 @@ const defaultProfileDropdownMountPoints = [
130
142
  }
131
143
  }
132
144
  ];
145
+ const defaultHelpDropdownMountPoints = [
146
+ {
147
+ Component: QuickstartButton,
148
+ config: {
149
+ priority: 100
150
+ }
151
+ },
152
+ {
153
+ Component: SupportButton,
154
+ config: {
155
+ priority: 10
156
+ }
157
+ }
158
+ ];
133
159
  const defaultApplicationLauncherDropdownMountPoints = [
134
160
  {
135
161
  Component: MenuItemLink,
@@ -157,5 +183,5 @@ const defaultApplicationLauncherDropdownMountPoints = [
157
183
  }
158
184
  ];
159
185
 
160
- export { defaultApplicationLauncherDropdownMountPoints, defaultCreateDropdownMountPoints, defaultGlobalHeaderComponentsMountPoints, defaultProfileDropdownMountPoints };
186
+ export { defaultApplicationLauncherDropdownMountPoints, defaultCreateDropdownMountPoints, defaultGlobalHeaderComponentsMountPoints, defaultHelpDropdownMountPoints, defaultProfileDropdownMountPoints };
161
187
  //# sourceMappingURL=defaultMountPoints.esm.js.map