@red-hat-developer-hub/backstage-plugin-global-header 0.0.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +13 -0
  3. package/dist/components/GlobalHeader.esm.js +87 -0
  4. package/dist/components/GlobalHeader.esm.js.map +1 -0
  5. package/dist/components/HeaderDropdownComponent/CreateDropdown.esm.js +80 -0
  6. package/dist/components/HeaderDropdownComponent/CreateDropdown.esm.js.map +1 -0
  7. package/dist/components/HeaderDropdownComponent/HeaderDropdownComponent.esm.js +117 -0
  8. package/dist/components/HeaderDropdownComponent/HeaderDropdownComponent.esm.js.map +1 -0
  9. package/dist/components/HeaderDropdownComponent/MenuItemContent.esm.js +15 -0
  10. package/dist/components/HeaderDropdownComponent/MenuItemContent.esm.js.map +1 -0
  11. package/dist/components/HeaderDropdownComponent/MenuSection.esm.js +88 -0
  12. package/dist/components/HeaderDropdownComponent/MenuSection.esm.js.map +1 -0
  13. package/dist/components/HeaderDropdownComponent/ProfileDropdown.esm.js +78 -0
  14. package/dist/components/HeaderDropdownComponent/ProfileDropdown.esm.js.map +1 -0
  15. package/dist/components/HeaderIconButton/HeaderIconButton.esm.js +22 -0
  16. package/dist/components/HeaderIconButton/HeaderIconButton.esm.js.map +1 -0
  17. package/dist/components/HeaderIconButton/SmallIconWrapper.esm.js +11 -0
  18. package/dist/components/HeaderIconButton/SmallIconWrapper.esm.js.map +1 -0
  19. package/dist/components/SearchComponent/SearchBar.esm.js +72 -0
  20. package/dist/components/SearchComponent/SearchBar.esm.js.map +1 -0
  21. package/dist/components/SearchComponent/SearchComponent.esm.js +26 -0
  22. package/dist/components/SearchComponent/SearchComponent.esm.js.map +1 -0
  23. package/dist/components/SearchComponent/SearchInput.esm.js +32 -0
  24. package/dist/components/SearchComponent/SearchInput.esm.js.map +1 -0
  25. package/dist/components/SearchComponent/SearchOption.esm.js +44 -0
  26. package/dist/components/SearchComponent/SearchOption.esm.js.map +1 -0
  27. package/dist/components/SearchComponent/SearchResultItem.esm.js +16 -0
  28. package/dist/components/SearchComponent/SearchResultItem.esm.js.map +1 -0
  29. package/dist/hooks/useDropdownManager.esm.js +19 -0
  30. package/dist/hooks/useDropdownManager.esm.js.map +1 -0
  31. package/dist/index.d.ts +16 -0
  32. package/dist/index.esm.js +7 -0
  33. package/dist/index.esm.js.map +1 -0
  34. package/dist/plugin.esm.js +16 -0
  35. package/dist/plugin.esm.js.map +1 -0
  36. package/dist/utils/stringUtils.esm.js +35 -0
  37. package/dist/utils/stringUtils.esm.js.map +1 -0
  38. package/package.json +86 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @red-hat-developer-hub/backstage-plugin-global-header
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 086841f: First release of global-header plugin
package/README.md ADDED
@@ -0,0 +1,13 @@
1
+ # global-header
2
+
3
+ Welcome to the global-header plugin!
4
+
5
+ _This plugin was created through the Backstage CLI_
6
+
7
+ ## Getting started
8
+
9
+ Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/global-header](http://localhost:3000/global-header).
10
+
11
+ You can also serve the plugin in isolation by running `yarn start` in the plugin directory.
12
+ This method of serving the plugin provides quicker iteration speed and a faster startup and hot reloads.
13
+ It is only meant for local development, and the setup for it can be found inside the [/dev](./dev) directory.
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import AppBar from '@mui/material/AppBar';
3
+ import Toolbar from '@mui/material/Toolbar';
4
+ import { SearchComponent } from './SearchComponent/SearchComponent.esm.js';
5
+ import { HeaderIconButton } from './HeaderIconButton/HeaderIconButton.esm.js';
6
+ import CreateDropdown from './HeaderDropdownComponent/CreateDropdown.esm.js';
7
+ import ProfileDropdown from './HeaderDropdownComponent/ProfileDropdown.esm.js';
8
+ import Divider from '@mui/material/Divider';
9
+ import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineRounded';
10
+ import NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined';
11
+ import { useDropdownManager } from '../hooks/useDropdownManager.esm.js';
12
+
13
+ const iconButtons = [
14
+ {
15
+ key: "help",
16
+ Icon: HelpOutlineOutlinedIcon,
17
+ onClick: () => {
18
+ }
19
+ },
20
+ {
21
+ key: "notification",
22
+ Icon: NotificationsOutlinedIcon,
23
+ onClick: () => {
24
+ }
25
+ }
26
+ ];
27
+ const GlobalHeader = () => {
28
+ const { menuStates, handleOpen, handleClose } = useDropdownManager();
29
+ const dropdownConfigs = [
30
+ {
31
+ key: "create",
32
+ component: CreateDropdown,
33
+ buttonProps: {
34
+ handleMenu: handleOpen("create"),
35
+ anchorEl: menuStates.create,
36
+ setAnchorEl: handleClose("create")
37
+ }
38
+ },
39
+ {
40
+ key: "profile",
41
+ component: ProfileDropdown,
42
+ buttonProps: {
43
+ handleMenu: handleOpen("profile"),
44
+ anchorEl: menuStates.profile,
45
+ setAnchorEl: handleClose("profile")
46
+ }
47
+ }
48
+ ];
49
+ return /* @__PURE__ */ React.createElement(
50
+ AppBar,
51
+ {
52
+ position: "sticky",
53
+ component: "nav",
54
+ sx: { backgroundColor: "#212427" }
55
+ },
56
+ /* @__PURE__ */ React.createElement(Toolbar, null, /* @__PURE__ */ React.createElement(SearchComponent, null), /* @__PURE__ */ React.createElement(
57
+ CreateDropdown,
58
+ {
59
+ key: dropdownConfigs[0].key,
60
+ ...dropdownConfigs[0].buttonProps
61
+ }
62
+ ), iconButtons.map(({ key, Icon, onClick }) => /* @__PURE__ */ React.createElement(
63
+ HeaderIconButton,
64
+ {
65
+ key: `header-icon-button-${key}`,
66
+ Icon,
67
+ onClick
68
+ }
69
+ )), /* @__PURE__ */ React.createElement(
70
+ Divider,
71
+ {
72
+ orientation: "vertical",
73
+ flexItem: true,
74
+ sx: { borderColor: "#373A40" }
75
+ }
76
+ ), /* @__PURE__ */ React.createElement(
77
+ ProfileDropdown,
78
+ {
79
+ key: dropdownConfigs[1].key,
80
+ ...dropdownConfigs[1].buttonProps
81
+ }
82
+ ))
83
+ );
84
+ };
85
+
86
+ export { GlobalHeader };
87
+ //# sourceMappingURL=GlobalHeader.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GlobalHeader.esm.js","sources":["../../src/components/GlobalHeader.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 React from 'react';\nimport AppBar from '@mui/material/AppBar';\nimport Toolbar from '@mui/material/Toolbar';\nimport { SearchComponent } from './SearchComponent/SearchComponent';\nimport { HeaderIconButton } from './HeaderIconButton/HeaderIconButton';\nimport CreateDropdown from './HeaderDropdownComponent/CreateDropdown';\nimport ProfileDropdown from './HeaderDropdownComponent/ProfileDropdown';\nimport Divider from '@mui/material/Divider';\nimport HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineRounded';\nimport NotificationsOutlinedIcon from '@mui/icons-material/NotificationsOutlined';\nimport { useDropdownManager } from '../hooks';\n\nconst iconButtons = [\n {\n key: 'help',\n Icon: HelpOutlineOutlinedIcon,\n onClick: () => {},\n },\n {\n key: 'notification',\n Icon: NotificationsOutlinedIcon,\n onClick: () => {},\n },\n];\n\nexport const GlobalHeader = () => {\n const { menuStates, handleOpen, handleClose } = useDropdownManager();\n const dropdownConfigs = [\n {\n key: 'create',\n component: CreateDropdown,\n buttonProps: {\n handleMenu: handleOpen('create'),\n anchorEl: menuStates.create,\n setAnchorEl: handleClose('create'),\n },\n },\n {\n key: 'profile',\n component: ProfileDropdown,\n buttonProps: {\n handleMenu: handleOpen('profile'),\n anchorEl: menuStates.profile,\n setAnchorEl: handleClose('profile'),\n },\n },\n ];\n\n return (\n <AppBar\n position=\"sticky\"\n component=\"nav\"\n sx={{ backgroundColor: '#212427' }}\n >\n <Toolbar>\n <SearchComponent />\n <CreateDropdown\n key={dropdownConfigs[0].key}\n {...dropdownConfigs[0].buttonProps}\n />\n {iconButtons.map(({ key, Icon, onClick }) => (\n <HeaderIconButton\n key={`header-icon-button-${key}`}\n Icon={Icon}\n onClick={onClick}\n />\n ))}\n <Divider\n orientation=\"vertical\"\n flexItem\n sx={{ borderColor: '#373A40' }}\n />\n <ProfileDropdown\n key={dropdownConfigs[1].key}\n {...dropdownConfigs[1].buttonProps}\n />\n </Toolbar>\n </AppBar>\n );\n};\n"],"names":[],"mappings":";;;;;;;;;;;;AA4BA,MAAM,WAAc,GAAA;AAAA,EAClB;AAAA,IACE,GAAK,EAAA,MAAA;AAAA,IACL,IAAM,EAAA,uBAAA;AAAA,IACN,SAAS,MAAM;AAAA;AAAC,GAClB;AAAA,EACA;AAAA,IACE,GAAK,EAAA,cAAA;AAAA,IACL,IAAM,EAAA,yBAAA;AAAA,IACN,SAAS,MAAM;AAAA;AAAC;AAEpB,CAAA;AAEO,MAAM,eAAe,MAAM;AAChC,EAAA,MAAM,EAAE,UAAA,EAAY,UAAY,EAAA,WAAA,KAAgB,kBAAmB,EAAA;AACnE,EAAA,MAAM,eAAkB,GAAA;AAAA,IACtB;AAAA,MACE,GAAK,EAAA,QAAA;AAAA,MACL,SAAW,EAAA,cAAA;AAAA,MACX,WAAa,EAAA;AAAA,QACX,UAAA,EAAY,WAAW,QAAQ,CAAA;AAAA,QAC/B,UAAU,UAAW,CAAA,MAAA;AAAA,QACrB,WAAA,EAAa,YAAY,QAAQ;AAAA;AACnC,KACF;AAAA,IACA;AAAA,MACE,GAAK,EAAA,SAAA;AAAA,MACL,SAAW,EAAA,eAAA;AAAA,MACX,WAAa,EAAA;AAAA,QACX,UAAA,EAAY,WAAW,SAAS,CAAA;AAAA,QAChC,UAAU,UAAW,CAAA,OAAA;AAAA,QACrB,WAAA,EAAa,YAAY,SAAS;AAAA;AACpC;AACF,GACF;AAEA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,QAAS,EAAA,QAAA;AAAA,MACT,SAAU,EAAA,KAAA;AAAA,MACV,EAAA,EAAI,EAAE,eAAA,EAAiB,SAAU;AAAA,KAAA;AAAA,oBAEhC,KAAA,CAAA,aAAA,CAAA,OAAA,EAAA,IAAA,kBACE,KAAA,CAAA,aAAA,CAAA,eAAA,EAAA,IAAgB,CACjB,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,cAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,eAAgB,CAAA,CAAC,CAAE,CAAA,GAAA;AAAA,QACvB,GAAG,eAAgB,CAAA,CAAC,CAAE,CAAA;AAAA;AAAA,KACzB,EACC,YAAY,GAAI,CAAA,CAAC,EAAE,GAAK,EAAA,IAAA,EAAM,SAC7B,qBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,gBAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,sBAAsB,GAAG,CAAA,CAAA;AAAA,QAC9B,IAAA;AAAA,QACA;AAAA;AAAA,KAEH,CACD,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,OAAA;AAAA,MAAA;AAAA,QACC,WAAY,EAAA,UAAA;AAAA,QACZ,QAAQ,EAAA,IAAA;AAAA,QACR,EAAA,EAAI,EAAE,WAAA,EAAa,SAAU;AAAA;AAAA,KAE/B,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,eAAA;AAAA,MAAA;AAAA,QACC,GAAA,EAAK,eAAgB,CAAA,CAAC,CAAE,CAAA,GAAA;AAAA,QACvB,GAAG,eAAgB,CAAA,CAAC,CAAE,CAAA;AAAA;AAAA,KAE3B;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+ import HeaderDropdownComponent from './HeaderDropdownComponent.esm.js';
3
+ import ArrowDropDownOutlinedIcon from '@mui/icons-material/ArrowDropDownOutlined';
4
+ import CategoryOutlinedIcon from '@mui/icons-material/CategoryOutlined';
5
+
6
+ const models = [
7
+ {
8
+ key: "key-1",
9
+ value: "argocd-template",
10
+ label: "Add ArgoCD to an existing project"
11
+ },
12
+ {
13
+ key: "key-2",
14
+ value: "create-backend-plugin",
15
+ label: "Create Backend Plugin Template"
16
+ },
17
+ {
18
+ key: "key-3",
19
+ value: "create-frontend-plugin",
20
+ label: "Create Frontend Plugin Template"
21
+ },
22
+ {
23
+ key: "key-4",
24
+ value: "create-react-app-template-test-annotator",
25
+ label: "Create React App Template with annotations"
26
+ },
27
+ {
28
+ key: "key-5",
29
+ value: "define-ansible-job-template",
30
+ label: "Ansible Job Template"
31
+ }
32
+ ];
33
+ const menuBottomItems = [
34
+ {
35
+ itemKey: "custom",
36
+ icon: CategoryOutlinedIcon,
37
+ label: "Register a component",
38
+ subLabel: "Import it to the catalog page",
39
+ link: "/catalog-import"
40
+ }
41
+ ];
42
+ const CreateDropdown = ({
43
+ handleMenu,
44
+ anchorEl,
45
+ setAnchorEl
46
+ }) => {
47
+ const menuSections = [
48
+ {
49
+ sectionKey: "templates",
50
+ sectionLabel: "Use a template",
51
+ optionalLinkLabel: "All templates",
52
+ optionalLink: "/create",
53
+ items: models.map((m) => ({
54
+ itemKey: m.key,
55
+ label: m.label,
56
+ link: `/create/templates/default/${m.value}`
57
+ })),
58
+ handleClose: () => setAnchorEl(null)
59
+ }
60
+ ];
61
+ return /* @__PURE__ */ React.createElement(
62
+ HeaderDropdownComponent,
63
+ {
64
+ buttonContent: /* @__PURE__ */ React.createElement(React.Fragment, null, "Create ", /* @__PURE__ */ React.createElement(ArrowDropDownOutlinedIcon, { sx: { ml: 1 } })),
65
+ menuSections,
66
+ menuBottomItems,
67
+ buttonProps: {
68
+ color: "primary",
69
+ variant: "contained",
70
+ sx: { mr: 2 }
71
+ },
72
+ buttonClick: handleMenu,
73
+ anchorEl,
74
+ setAnchorEl
75
+ }
76
+ );
77
+ };
78
+
79
+ export { CreateDropdown as default };
80
+ //# sourceMappingURL=CreateDropdown.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CreateDropdown.esm.js","sources":["../../../src/components/HeaderDropdownComponent/CreateDropdown.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 React from 'react';\nimport HeaderDropdownComponent from './HeaderDropdownComponent';\nimport ArrowDropDownOutlinedIcon from '@mui/icons-material/ArrowDropDownOutlined';\nimport CategoryOutlinedIcon from '@mui/icons-material/CategoryOutlined';\nimport { MenuItemConfig } from './MenuSection';\n\ninterface CreateButtonProps {\n handleMenu: (event: React.MouseEvent<HTMLElement>) => void;\n anchorEl: HTMLElement | null;\n setAnchorEl: React.Dispatch<React.SetStateAction<HTMLElement | null>>;\n}\n\nconst models = [\n {\n key: 'key-1',\n value: 'argocd-template',\n label: 'Add ArgoCD to an existing project',\n },\n {\n key: 'key-2',\n value: 'create-backend-plugin',\n label: 'Create Backend Plugin Template',\n },\n {\n key: 'key-3',\n value: 'create-frontend-plugin',\n label: 'Create Frontend Plugin Template',\n },\n {\n key: 'key-4',\n value: 'create-react-app-template-test-annotator',\n label: 'Create React App Template with annotations',\n },\n {\n key: 'key-5',\n value: 'define-ansible-job-template',\n label: 'Ansible Job Template',\n },\n];\n\nconst menuBottomItems: MenuItemConfig[] = [\n {\n itemKey: 'custom',\n icon: CategoryOutlinedIcon,\n label: 'Register a component',\n subLabel: 'Import it to the catalog page',\n link: '/catalog-import',\n },\n];\nconst CreateDropdown: React.FC<CreateButtonProps> = ({\n handleMenu,\n anchorEl,\n setAnchorEl,\n}) => {\n const menuSections = [\n {\n sectionKey: 'templates',\n sectionLabel: 'Use a template',\n optionalLinkLabel: 'All templates',\n optionalLink: '/create',\n items: models.map(m => ({\n itemKey: m.key,\n label: m.label,\n link: `/create/templates/default/${m.value}`,\n })),\n handleClose: () => setAnchorEl(null),\n },\n ];\n return (\n <HeaderDropdownComponent\n buttonContent={\n <>\n Create <ArrowDropDownOutlinedIcon sx={{ ml: 1 }} />\n </>\n }\n menuSections={menuSections}\n menuBottomItems={menuBottomItems}\n buttonProps={{\n color: 'primary',\n variant: 'contained',\n sx: { mr: 2 },\n }}\n buttonClick={handleMenu}\n anchorEl={anchorEl}\n setAnchorEl={setAnchorEl}\n />\n );\n};\n\nexport default CreateDropdown;\n"],"names":[],"mappings":";;;;;AA4BA,MAAM,MAAS,GAAA;AAAA,EACb;AAAA,IACE,GAAK,EAAA,OAAA;AAAA,IACL,KAAO,EAAA,iBAAA;AAAA,IACP,KAAO,EAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,GAAK,EAAA,OAAA;AAAA,IACL,KAAO,EAAA,uBAAA;AAAA,IACP,KAAO,EAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,GAAK,EAAA,OAAA;AAAA,IACL,KAAO,EAAA,wBAAA;AAAA,IACP,KAAO,EAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,GAAK,EAAA,OAAA;AAAA,IACL,KAAO,EAAA,0CAAA;AAAA,IACP,KAAO,EAAA;AAAA,GACT;AAAA,EACA;AAAA,IACE,GAAK,EAAA,OAAA;AAAA,IACL,KAAO,EAAA,6BAAA;AAAA,IACP,KAAO,EAAA;AAAA;AAEX,CAAA;AAEA,MAAM,eAAoC,GAAA;AAAA,EACxC;AAAA,IACE,OAAS,EAAA,QAAA;AAAA,IACT,IAAM,EAAA,oBAAA;AAAA,IACN,KAAO,EAAA,sBAAA;AAAA,IACP,QAAU,EAAA,+BAAA;AAAA,IACV,IAAM,EAAA;AAAA;AAEV,CAAA;AACA,MAAM,iBAA8C,CAAC;AAAA,EACnD,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAM,KAAA;AACJ,EAAA,MAAM,YAAe,GAAA;AAAA,IACnB;AAAA,MACE,UAAY,EAAA,WAAA;AAAA,MACZ,YAAc,EAAA,gBAAA;AAAA,MACd,iBAAmB,EAAA,eAAA;AAAA,MACnB,YAAc,EAAA,SAAA;AAAA,MACd,KAAA,EAAO,MAAO,CAAA,GAAA,CAAI,CAAM,CAAA,MAAA;AAAA,QACtB,SAAS,CAAE,CAAA,GAAA;AAAA,QACX,OAAO,CAAE,CAAA,KAAA;AAAA,QACT,IAAA,EAAM,CAA6B,0BAAA,EAAA,CAAA,CAAE,KAAK,CAAA;AAAA,OAC1C,CAAA,CAAA;AAAA,MACF,WAAA,EAAa,MAAM,WAAA,CAAY,IAAI;AAAA;AACrC,GACF;AACA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,aAAA,kBACI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAA,SAAA,kBACQ,KAAA,CAAA,aAAA,CAAA,yBAAA,EAAA,EAA0B,IAAI,EAAE,EAAA,EAAI,CAAE,EAAA,EAAG,CACnD,CAAA;AAAA,MAEF,YAAA;AAAA,MACA,eAAA;AAAA,MACA,WAAa,EAAA;AAAA,QACX,KAAO,EAAA,SAAA;AAAA,QACP,OAAS,EAAA,WAAA;AAAA,QACT,EAAA,EAAI,EAAE,EAAA,EAAI,CAAE;AAAA,OACd;AAAA,MACA,WAAa,EAAA,UAAA;AAAA,MACb,QAAA;AAAA,MACA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,117 @@
1
+ import React from 'react';
2
+ import Menu from '@mui/material/Menu';
3
+ import MenuItem from '@mui/material/MenuItem';
4
+ import Button from '@mui/material/Button';
5
+ import Typography from '@mui/material/Typography';
6
+ import { Link } from '@backstage/core-components';
7
+ import { styled } from '@mui/material/styles';
8
+ import Box from '@mui/material/Box';
9
+ import MenuSection from './MenuSection.esm.js';
10
+
11
+ const Listbox = styled("ul")(
12
+ ({ theme }) => `
13
+ font-size: 0.875rem;
14
+ box-sizing: border-box;
15
+ padding: 0;
16
+ margin: 0;
17
+ min-width: 160px;
18
+ border-radius: 3px;
19
+ text-decoration: none;
20
+ list-style: none;
21
+ overflow: auto;
22
+ outline: 1;
23
+ background: ${theme.palette.mode === "dark" ? theme.palette.background.default : "#fff"};
24
+ border: 1px solid ${theme.palette.mode === "dark" ? theme.palette.divider : theme.palette.background.default};
25
+ color: ${theme.palette.mode === "dark" ? theme.palette.text.disabled : theme.palette.text.primary};
26
+ box-shadow: 0 4px 6px ${theme.palette.mode === "dark" ? "rgba(0,0,0, 0.50)" : "rgba(0,0,0, 0.05)"};
27
+ z-index: 1;
28
+ `
29
+ );
30
+ const HeaderDropdownComponent = ({
31
+ buttonContent,
32
+ menuSections = [],
33
+ menuBottomItems = [],
34
+ buttonProps,
35
+ buttonClick,
36
+ anchorEl,
37
+ setAnchorEl
38
+ }) => {
39
+ const shouldHideDivider = (index) => menuSections.length === 1 && index === menuSections.length - 1 && menuBottomItems.length === 0;
40
+ return /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(
41
+ Button,
42
+ {
43
+ disableRipple: true,
44
+ disableTouchRipple: true,
45
+ ...buttonProps,
46
+ onClick: buttonClick
47
+ },
48
+ buttonContent
49
+ ), /* @__PURE__ */ React.createElement(
50
+ Menu,
51
+ {
52
+ id: "menu-appbar",
53
+ anchorEl,
54
+ keepMounted: true,
55
+ open: Boolean(anchorEl),
56
+ onClose: () => setAnchorEl(null),
57
+ anchorOrigin: {
58
+ vertical: "bottom",
59
+ horizontal: "center"
60
+ },
61
+ transformOrigin: {
62
+ vertical: "top",
63
+ horizontal: "center"
64
+ },
65
+ sx: {
66
+ '& ul[class*="MuiMenu-list"]': {
67
+ py: 0
68
+ }
69
+ }
70
+ },
71
+ /* @__PURE__ */ React.createElement(Listbox, { role: "menu" }, menuSections.map((section, index) => /* @__PURE__ */ React.createElement(
72
+ MenuSection,
73
+ {
74
+ key: `menu-section-${section.sectionKey}`,
75
+ ...{ hideDivider: shouldHideDivider(index), ...section },
76
+ handleClose: section.handleClose
77
+ }
78
+ )), menuBottomItems.map(
79
+ ({ itemKey, icon: Icon, label, subLabel, link }) => /* @__PURE__ */ React.createElement(
80
+ MenuItem,
81
+ {
82
+ key: `menu-item-${itemKey}`,
83
+ sx: { my: "8px", "&:hover": { background: "transparent" } },
84
+ onClick: () => setAnchorEl(null),
85
+ disableRipple: true
86
+ },
87
+ link && /* @__PURE__ */ React.createElement(
88
+ Link,
89
+ {
90
+ to: link,
91
+ style: {
92
+ display: "flex",
93
+ color: "inherit",
94
+ alignItems: "center",
95
+ textDecoration: "none"
96
+ }
97
+ },
98
+ Icon && /* @__PURE__ */ React.createElement(
99
+ Icon,
100
+ {
101
+ fontSize: "small",
102
+ style: {
103
+ marginRight: "0.5rem",
104
+ flexShrink: 0,
105
+ color: "slategray"
106
+ }
107
+ }
108
+ ),
109
+ /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, label), subLabel && /* @__PURE__ */ React.createElement(Typography, { variant: "caption", color: "text.secondary" }, subLabel))
110
+ )
111
+ )
112
+ ))
113
+ ));
114
+ };
115
+
116
+ export { HeaderDropdownComponent as default };
117
+ //# sourceMappingURL=HeaderDropdownComponent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeaderDropdownComponent.esm.js","sources":["../../../src/components/HeaderDropdownComponent/HeaderDropdownComponent.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 React from 'react';\nimport Menu from '@mui/material/Menu';\nimport MenuItem from '@mui/material/MenuItem';\nimport Button from '@mui/material/Button';\nimport Typography from '@mui/material/Typography';\nimport { Link } from '@backstage/core-components';\nimport { styled } from '@mui/material/styles';\nimport Box from '@mui/material/Box';\nimport MenuSection, { MenuItemConfig, MenuSectionConfig } from './MenuSection';\n\ninterface HeaderDropdownProps {\n buttonContent: React.ReactNode;\n menuSections?: MenuSectionConfig[];\n menuBottomItems?: MenuItemConfig[];\n buttonProps?: React.ComponentProps<typeof Button>;\n buttonClick?: (event: React.MouseEvent<HTMLElement>) => void;\n anchorEl: HTMLElement | null;\n setAnchorEl: React.Dispatch<React.SetStateAction<HTMLElement | null>>;\n}\n\nconst Listbox = styled('ul')(\n ({ theme }) => `\n font-size: 0.875rem;\n box-sizing: border-box;\n padding: 0;\n margin: 0;\n min-width: 160px;\n border-radius: 3px;\n text-decoration: none;\n list-style: none;\n overflow: auto;\n outline: 1;\n background: ${\n theme.palette.mode === 'dark' ? theme.palette.background.default : '#fff'\n };\n border: 1px solid ${\n theme.palette.mode === 'dark'\n ? theme.palette.divider\n : theme.palette.background.default\n };\n color: ${\n theme.palette.mode === 'dark'\n ? theme.palette.text.disabled\n : theme.palette.text.primary\n };\n box-shadow: 0 4px 6px ${\n theme.palette.mode === 'dark' ? 'rgba(0,0,0, 0.50)' : 'rgba(0,0,0, 0.05)'\n };\n z-index: 1;\n `,\n);\n\nconst HeaderDropdownComponent: React.FC<HeaderDropdownProps> = ({\n buttonContent,\n menuSections = [],\n menuBottomItems = [],\n buttonProps,\n buttonClick,\n anchorEl,\n setAnchorEl,\n}) => {\n const shouldHideDivider = (index: number) =>\n menuSections.length === 1 &&\n index === menuSections.length - 1 &&\n menuBottomItems.length === 0;\n\n return (\n <Box>\n <Button\n disableRipple\n disableTouchRipple\n {...buttonProps}\n onClick={buttonClick}\n >\n {buttonContent}\n </Button>\n <Menu\n id=\"menu-appbar\"\n anchorEl={anchorEl}\n keepMounted\n open={Boolean(anchorEl)}\n onClose={() => setAnchorEl(null)}\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'center',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'center',\n }}\n sx={{\n '& ul[class*=\"MuiMenu-list\"]': {\n py: 0,\n },\n }}\n >\n <Listbox role=\"menu\">\n {menuSections.map((section, index) => (\n <MenuSection\n key={`menu-section-${section.sectionKey}`}\n {...{ hideDivider: shouldHideDivider(index), ...section }}\n handleClose={section.handleClose}\n />\n ))}\n {menuBottomItems.map(\n ({ itemKey, icon: Icon, label, subLabel, link }) => (\n <MenuItem\n key={`menu-item-${itemKey}`}\n sx={{ my: '8px', '&:hover': { background: 'transparent' } }}\n onClick={() => setAnchorEl(null)}\n disableRipple\n >\n {link && (\n <Link\n to={link}\n style={{\n display: 'flex',\n color: 'inherit',\n alignItems: 'center',\n textDecoration: 'none',\n }}\n >\n {Icon && (\n <Icon\n fontSize=\"small\"\n style={{\n marginRight: '0.5rem',\n flexShrink: 0,\n color: 'slategray',\n }}\n />\n )}\n <Box>\n <Typography variant=\"body2\">{label}</Typography>\n {subLabel && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {subLabel}\n </Typography>\n )}\n </Box>\n </Link>\n )}\n </MenuItem>\n ),\n )}\n </Listbox>\n </Menu>\n </Box>\n );\n};\n\nexport default HeaderDropdownComponent;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import Typography from '@mui/material/Typography';
3
+ import Box from '@mui/material/Box';
4
+ import SmallIconWrapper from '../HeaderIconButton/SmallIconWrapper.esm.js';
5
+
6
+ const MenuItemContent = ({ Icon, label, subLabel }) => /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex", alignItems: "center", margin: "8px 0" } }, Icon && /* @__PURE__ */ React.createElement(
7
+ SmallIconWrapper,
8
+ {
9
+ IconComponent: Icon,
10
+ sx: { marginRight: "0.5rem", flexShrink: 0 }
11
+ }
12
+ ), /* @__PURE__ */ React.createElement(Box, null, /* @__PURE__ */ React.createElement(Typography, { variant: "body2" }, label), subLabel && /* @__PURE__ */ React.createElement(Typography, { variant: "caption", color: "text.secondary" }, subLabel)));
13
+
14
+ export { MenuItemContent as default };
15
+ //# sourceMappingURL=MenuItemContent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuItemContent.esm.js","sources":["../../../src/components/HeaderDropdownComponent/MenuItemContent.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 React from 'react';\nimport Typography from '@mui/material/Typography';\nimport { SvgIconProps } from '@mui/material/SvgIcon';\nimport Box from '@mui/material/Box';\nimport SmallIconWrapper from '../HeaderIconButton/SmallIconWrapper';\n\nconst MenuItemContent: React.FC<{\n Icon?: React.ElementType<SvgIconProps>;\n label: string;\n subLabel?: string;\n}> = ({ Icon, label, subLabel }) => (\n <Box sx={{ display: 'flex', alignItems: 'center', margin: '8px 0' }}>\n {Icon && (\n <SmallIconWrapper\n IconComponent={Icon}\n sx={{ marginRight: '0.5rem', flexShrink: 0 }}\n />\n )}\n <Box>\n <Typography variant=\"body2\">{label}</Typography>\n {subLabel && (\n <Typography variant=\"caption\" color=\"text.secondary\">\n {subLabel}\n </Typography>\n )}\n </Box>\n </Box>\n);\n\nexport default MenuItemContent;\n"],"names":[],"mappings":";;;;;AAsBA,MAAM,kBAID,CAAC,EAAE,MAAM,KAAO,EAAA,QAAA,uBAClB,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,EAAI,EAAA,EAAE,SAAS,MAAQ,EAAA,UAAA,EAAY,UAAU,MAAQ,EAAA,OAAA,MACvD,IACC,oBAAA,KAAA,CAAA,aAAA;AAAA,EAAC,gBAAA;AAAA,EAAA;AAAA,IACC,aAAe,EAAA,IAAA;AAAA,IACf,EAAI,EAAA,EAAE,WAAa,EAAA,QAAA,EAAU,YAAY,CAAE;AAAA;AAC7C,CAAA,sCAED,GACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,WAAS,KAAM,CAAA,EAClC,QACC,oBAAA,KAAA,CAAA,aAAA,CAAC,cAAW,OAAQ,EAAA,SAAA,EAAU,OAAM,gBACjC,EAAA,EAAA,QACH,CAEJ,CACF;;;;"}
@@ -0,0 +1,88 @@
1
+ import React from 'react';
2
+ import Divider from '@mui/material/Divider';
3
+ import Box from '@mui/material/Box';
4
+ import Typography from '@mui/material/Typography';
5
+ import MenuItem from '@mui/material/MenuItem';
6
+ import { Link } from '@backstage/core-components';
7
+ import MenuItemContent from './MenuItemContent.esm.js';
8
+
9
+ const MenuSection = ({
10
+ sectionKey,
11
+ sectionLabel,
12
+ optionalLink,
13
+ optionalLinkLabel,
14
+ items,
15
+ hideDivider = false,
16
+ handleClose
17
+ }) => /* @__PURE__ */ React.createElement(Box, null, sectionLabel && sectionKey && /* @__PURE__ */ React.createElement(
18
+ Box,
19
+ {
20
+ sx: {
21
+ display: "flex",
22
+ justifyContent: "space-between",
23
+ alignItems: "center",
24
+ mx: 0,
25
+ mt: "0.5rem",
26
+ "&:hover": { background: "transparent" }
27
+ }
28
+ },
29
+ /* @__PURE__ */ React.createElement(
30
+ Typography,
31
+ {
32
+ variant: "body2",
33
+ sx: { ml: 2, fontSize: "0.875em", color: "text.disabled" }
34
+ },
35
+ sectionLabel
36
+ ),
37
+ /* @__PURE__ */ React.createElement(
38
+ MenuItem,
39
+ {
40
+ sx: {
41
+ "&:hover": { background: "transparent" }
42
+ },
43
+ disableRipple: true,
44
+ disableTouchRipple: true,
45
+ onClick: handleClose
46
+ },
47
+ optionalLink && optionalLinkLabel && /* @__PURE__ */ React.createElement(
48
+ Link,
49
+ {
50
+ to: optionalLink,
51
+ underline: "none",
52
+ style: { fontSize: "0.875em" }
53
+ },
54
+ optionalLinkLabel
55
+ )
56
+ )
57
+ ), /* @__PURE__ */ React.createElement("ul", { style: { padding: 0, listStyle: "none" } }, items.map(({ itemKey, icon: Icon, label, subLabel, link, onClick }) => /* @__PURE__ */ React.createElement(
58
+ MenuItem,
59
+ {
60
+ key: `menu-item-${itemKey}`,
61
+ disableRipple: true,
62
+ disableTouchRipple: true,
63
+ onClick: handleClose,
64
+ sx: { py: 0.5, "&:hover": { background: "transparent" } }
65
+ },
66
+ link ? /* @__PURE__ */ React.createElement(
67
+ Link,
68
+ {
69
+ to: link,
70
+ style: {
71
+ color: "inherit",
72
+ textDecoration: "none",
73
+ width: "100%"
74
+ }
75
+ },
76
+ /* @__PURE__ */ React.createElement(MenuItemContent, { Icon, label, subLabel })
77
+ ) : /* @__PURE__ */ React.createElement(
78
+ Box,
79
+ {
80
+ onClick,
81
+ sx: { cursor: "pointer", width: "100%", color: "inherit" }
82
+ },
83
+ /* @__PURE__ */ React.createElement(MenuItemContent, { Icon, label, subLabel })
84
+ )
85
+ ))), !hideDivider && /* @__PURE__ */ React.createElement(Divider, { sx: { margin: "8px 0" } }));
86
+
87
+ export { MenuSection as default };
88
+ //# sourceMappingURL=MenuSection.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MenuSection.esm.js","sources":["../../../src/components/HeaderDropdownComponent/MenuSection.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 React from 'react';\nimport { SvgIconProps } from '@mui/material/SvgIcon';\nimport Divider from '@mui/material/Divider';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport MenuItem from '@mui/material/MenuItem';\nimport { Link } from '@backstage/core-components';\nimport MenuItemContent from './MenuItemContent';\n\nexport interface MenuItemBase {\n itemKey: string;\n icon?: React.ElementType<SvgIconProps>;\n label: string;\n subLabel?: string;\n}\n\nexport interface MenuItemLink extends MenuItemBase {\n link: string;\n onClick?: never;\n}\n\nexport interface MenuItemAction extends MenuItemBase {\n onClick: () => void;\n link?: never;\n}\n\nexport type MenuItemConfig = MenuItemLink | MenuItemAction;\n\nexport interface MenuSectionConfig {\n sectionKey: string;\n sectionLabel?: string;\n optionalLink?: string;\n optionalLinkLabel?: string;\n items: MenuItemConfig[];\n hideDivider?: boolean;\n handleClose: () => void;\n}\n\nconst MenuSection: React.FC<MenuSectionConfig> = ({\n sectionKey,\n sectionLabel,\n optionalLink,\n optionalLinkLabel,\n items,\n hideDivider = false,\n handleClose,\n}) => (\n <Box>\n {sectionLabel && sectionKey && (\n <Box\n sx={{\n display: 'flex',\n justifyContent: 'space-between',\n alignItems: 'center',\n mx: 0,\n mt: '0.5rem',\n '&:hover': { background: 'transparent' },\n }}\n >\n <Typography\n variant=\"body2\"\n sx={{ ml: 2, fontSize: '0.875em', color: 'text.disabled' }}\n >\n {sectionLabel}\n </Typography>\n <MenuItem\n sx={{\n '&:hover': { background: 'transparent' },\n }}\n disableRipple\n disableTouchRipple\n onClick={handleClose}\n >\n {optionalLink && optionalLinkLabel && (\n <Link\n to={optionalLink}\n underline=\"none\"\n style={{ fontSize: '0.875em' }}\n >\n {optionalLinkLabel}\n </Link>\n )}\n </MenuItem>\n </Box>\n )}\n <ul style={{ padding: 0, listStyle: 'none' }}>\n {items.map(({ itemKey, icon: Icon, label, subLabel, link, onClick }) => (\n <MenuItem\n key={`menu-item-${itemKey}`}\n disableRipple\n disableTouchRipple\n onClick={handleClose}\n sx={{ py: 0.5, '&:hover': { background: 'transparent' } }}\n >\n {link ? (\n <Link\n to={link}\n style={{\n color: 'inherit',\n textDecoration: 'none',\n width: '100%',\n }}\n >\n <MenuItemContent Icon={Icon} label={label} subLabel={subLabel} />\n </Link>\n ) : (\n <Box\n onClick={onClick}\n sx={{ cursor: 'pointer', width: '100%', color: 'inherit' }}\n >\n <MenuItemContent Icon={Icon} label={label} subLabel={subLabel} />\n </Box>\n )}\n </MenuItem>\n ))}\n </ul>\n {!hideDivider && <Divider sx={{ margin: '8px 0' }} />}\n </Box>\n);\n\nexport default MenuSection;\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import React from 'react';
2
+ import HeaderDropdownComponent from './HeaderDropdownComponent.esm.js';
3
+ import AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';
4
+ import ManageAccountsOutlinedIcon from '@mui/icons-material/ManageAccountsOutlined';
5
+ import LogoutOutlinedIcon from '@mui/icons-material/LogoutOutlined';
6
+ import KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';
7
+ import Typography from '@mui/material/Typography';
8
+ import SmallIconWrapper from '../HeaderIconButton/SmallIconWrapper.esm.js';
9
+ import { useApi, errorApiRef, identityApiRef } from '@backstage/core-plugin-api';
10
+
11
+ const ProfileDropdown = ({
12
+ handleMenu,
13
+ anchorEl,
14
+ setAnchorEl
15
+ }) => {
16
+ const errorApi = useApi(errorApiRef);
17
+ const identityApi = useApi(identityApiRef);
18
+ const user = "Guest User";
19
+ const handleLogout = () => {
20
+ identityApi.signOut().catch((error) => errorApi.post(error));
21
+ };
22
+ const menuSections = [
23
+ {
24
+ sectionKey: "profile",
25
+ items: [
26
+ {
27
+ itemKey: "settings",
28
+ icon: ManageAccountsOutlinedIcon,
29
+ label: "Settings",
30
+ link: "/settings"
31
+ },
32
+ {
33
+ itemKey: "logout",
34
+ icon: LogoutOutlinedIcon,
35
+ label: "Log out",
36
+ onClick: handleLogout
37
+ }
38
+ ],
39
+ handleClose: () => setAnchorEl(null)
40
+ }
41
+ ];
42
+ return /* @__PURE__ */ React.createElement(
43
+ HeaderDropdownComponent,
44
+ {
45
+ buttonContent: /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
46
+ SmallIconWrapper,
47
+ {
48
+ IconComponent: AccountCircleOutlinedIcon,
49
+ sx: { mx: 1 }
50
+ }
51
+ ), /* @__PURE__ */ React.createElement(Typography, { variant: "body2", sx: { fontWeight: 500, mx: 1 } }, user), /* @__PURE__ */ React.createElement(
52
+ KeyboardArrowDownOutlinedIcon,
53
+ {
54
+ sx: {
55
+ marginLeft: "1rem",
56
+ bgcolor: "#383838",
57
+ borderRadius: "25%"
58
+ }
59
+ }
60
+ )),
61
+ menuSections,
62
+ buttonProps: {
63
+ color: "inherit",
64
+ sx: {
65
+ display: "flex",
66
+ alignItems: "center",
67
+ ml: 1
68
+ }
69
+ },
70
+ buttonClick: handleMenu,
71
+ anchorEl,
72
+ setAnchorEl
73
+ }
74
+ );
75
+ };
76
+
77
+ export { ProfileDropdown as default };
78
+ //# sourceMappingURL=ProfileDropdown.esm.js.map
@@ -0,0 +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 React from 'react';\nimport HeaderDropdownComponent from './HeaderDropdownComponent';\nimport AccountCircleOutlinedIcon from '@mui/icons-material/AccountCircleOutlined';\nimport ManageAccountsOutlinedIcon from '@mui/icons-material/ManageAccountsOutlined';\nimport LogoutOutlinedIcon from '@mui/icons-material/LogoutOutlined';\nimport KeyboardArrowDownOutlinedIcon from '@mui/icons-material/KeyboardArrowDownOutlined';\nimport Typography from '@mui/material/Typography';\nimport SmallIconWrapper from '../HeaderIconButton/SmallIconWrapper';\nimport {\n identityApiRef,\n errorApiRef,\n useApi,\n} from '@backstage/core-plugin-api';\n\ninterface ProfileDropdownProps {\n handleMenu: (event: React.MouseEvent<HTMLElement>) => void;\n anchorEl: HTMLElement | null;\n setAnchorEl: React.Dispatch<React.SetStateAction<HTMLElement | null>>;\n}\n\nconst ProfileDropdown: React.FC<ProfileDropdownProps> = ({\n handleMenu,\n anchorEl,\n setAnchorEl,\n}) => {\n const errorApi = useApi(errorApiRef);\n const identityApi = useApi(identityApiRef);\n const user = 'Guest User';\n\n const handleLogout = () => {\n identityApi.signOut().catch(error => errorApi.post(error));\n };\n const menuSections = [\n {\n sectionKey: 'profile',\n items: [\n {\n itemKey: 'settings',\n icon: ManageAccountsOutlinedIcon,\n label: 'Settings',\n link: '/settings',\n },\n {\n itemKey: 'logout',\n icon: LogoutOutlinedIcon,\n label: 'Log out',\n onClick: handleLogout,\n },\n ],\n handleClose: () => setAnchorEl(null),\n },\n ];\n return (\n <HeaderDropdownComponent\n buttonContent={\n <>\n <SmallIconWrapper\n IconComponent={AccountCircleOutlinedIcon}\n sx={{ mx: 1 }}\n />\n <Typography variant=\"body2\" sx={{ fontWeight: 500, mx: 1 }}>\n {user ?? 'Guest User'}\n </Typography>\n <KeyboardArrowDownOutlinedIcon\n sx={{\n marginLeft: '1rem',\n bgcolor: '#383838',\n borderRadius: '25%',\n }}\n />\n </>\n }\n menuSections={menuSections}\n buttonProps={{\n color: 'inherit',\n sx: {\n display: 'flex',\n alignItems: 'center',\n ml: 1,\n },\n }}\n buttonClick={handleMenu}\n anchorEl={anchorEl}\n setAnchorEl={setAnchorEl}\n />\n );\n};\n\nexport default ProfileDropdown;\n"],"names":[],"mappings":";;;;;;;;;;AAoCA,MAAM,kBAAkD,CAAC;AAAA,EACvD,UAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAM,KAAA;AACJ,EAAM,MAAA,QAAA,GAAW,OAAO,WAAW,CAAA;AACnC,EAAM,MAAA,WAAA,GAAc,OAAO,cAAc,CAAA;AACzC,EAAA,MAAM,IAAO,GAAA,YAAA;AAEb,EAAA,MAAM,eAAe,MAAM;AACzB,IAAA,WAAA,CAAY,SAAU,CAAA,KAAA,CAAM,WAAS,QAAS,CAAA,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,GAC3D;AACA,EAAA,MAAM,YAAe,GAAA;AAAA,IACnB;AAAA,MACE,UAAY,EAAA,SAAA;AAAA,MACZ,KAAO,EAAA;AAAA,QACL;AAAA,UACE,OAAS,EAAA,UAAA;AAAA,UACT,IAAM,EAAA,0BAAA;AAAA,UACN,KAAO,EAAA,UAAA;AAAA,UACP,IAAM,EAAA;AAAA,SACR;AAAA,QACA;AAAA,UACE,OAAS,EAAA,QAAA;AAAA,UACT,IAAM,EAAA,kBAAA;AAAA,UACN,KAAO,EAAA,SAAA;AAAA,UACP,OAAS,EAAA;AAAA;AACX,OACF;AAAA,MACA,WAAA,EAAa,MAAM,WAAA,CAAY,IAAI;AAAA;AACrC,GACF;AACA,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,uBAAA;AAAA,IAAA;AAAA,MACC,+BAEI,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,gBAAA;AAAA,QAAA;AAAA,UACC,aAAe,EAAA,yBAAA;AAAA,UACf,EAAA,EAAI,EAAE,EAAA,EAAI,CAAE;AAAA;AAAA,OAEd,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,OAAA,EAAQ,SAAQ,EAAI,EAAA,EAAE,UAAY,EAAA,GAAA,EAAK,EAAI,EAAA,CAAA,EACpD,EAAA,EAAA,IACH,CACA,kBAAA,KAAA,CAAA,aAAA;AAAA,QAAC,6BAAA;AAAA,QAAA;AAAA,UACC,EAAI,EAAA;AAAA,YACF,UAAY,EAAA,MAAA;AAAA,YACZ,OAAS,EAAA,SAAA;AAAA,YACT,YAAc,EAAA;AAAA;AAChB;AAAA,OAEJ,CAAA;AAAA,MAEF,YAAA;AAAA,MACA,WAAa,EAAA;AAAA,QACX,KAAO,EAAA,SAAA;AAAA,QACP,EAAI,EAAA;AAAA,UACF,OAAS,EAAA,MAAA;AAAA,UACT,UAAY,EAAA,QAAA;AAAA,UACZ,EAAI,EAAA;AAAA;AACN,OACF;AAAA,MACA,WAAa,EAAA,UAAA;AAAA,MACb,QAAA;AAAA,MACA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,22 @@
1
+ import React from 'react';
2
+ import IconButton from '@mui/material/IconButton';
3
+ import SmallIconWrapper from './SmallIconWrapper.esm.js';
4
+
5
+ const HeaderIconButton = ({
6
+ Icon,
7
+ onClick
8
+ }) => {
9
+ return /* @__PURE__ */ React.createElement(
10
+ IconButton,
11
+ {
12
+ color: "inherit",
13
+ "aria-label": "help",
14
+ sx: { mr: 1.5 },
15
+ onClick
16
+ },
17
+ /* @__PURE__ */ React.createElement(SmallIconWrapper, { IconComponent: Icon })
18
+ );
19
+ };
20
+
21
+ export { HeaderIconButton };
22
+ //# sourceMappingURL=HeaderIconButton.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"HeaderIconButton.esm.js","sources":["../../../src/components/HeaderIconButton/HeaderIconButton.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 React from 'react';\nimport IconButton from '@mui/material/IconButton';\nimport SmallIconWrapper, { IconComponentType } from './SmallIconWrapper';\n\ninterface HeaderIconButtonProps {\n Icon: IconComponentType;\n onClick: () => void;\n}\n\nexport const HeaderIconButton: React.FC<HeaderIconButtonProps> = ({\n Icon,\n onClick,\n}) => {\n return (\n <IconButton\n color=\"inherit\"\n aria-label=\"help\"\n sx={{ mr: 1.5 }}\n onClick={onClick}\n >\n <SmallIconWrapper IconComponent={Icon} />\n </IconButton>\n );\n};\n"],"names":[],"mappings":";;;;AAyBO,MAAM,mBAAoD,CAAC;AAAA,EAChE,IAAA;AAAA,EACA;AACF,CAAM,KAAA;AACJ,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,UAAA;AAAA,IAAA;AAAA,MACC,KAAM,EAAA,SAAA;AAAA,MACN,YAAW,EAAA,MAAA;AAAA,MACX,EAAA,EAAI,EAAE,EAAA,EAAI,GAAI,EAAA;AAAA,MACd;AAAA,KAAA;AAAA,oBAEA,KAAA,CAAA,aAAA,CAAC,gBAAiB,EAAA,EAAA,aAAA,EAAe,IAAM,EAAA;AAAA,GACzC;AAEJ;;;;"}
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+
3
+ const SmallIconWrapper = ({
4
+ IconComponent,
5
+ ...props
6
+ }) => {
7
+ return /* @__PURE__ */ React.createElement(IconComponent, { fontSize: "small", ...props });
8
+ };
9
+
10
+ export { SmallIconWrapper as default };
11
+ //# sourceMappingURL=SmallIconWrapper.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SmallIconWrapper.esm.js","sources":["../../../src/components/HeaderIconButton/SmallIconWrapper.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 React from 'react';\nimport { SvgIconProps } from '@mui/material/SvgIcon';\n\nexport type IconComponentType = React.ElementType<SvgIconProps>;\n\ninterface SmallIconWrapperProps extends SvgIconProps {\n IconComponent: IconComponentType;\n}\n\nconst SmallIconWrapper: React.FC<SmallIconWrapperProps> = ({\n IconComponent,\n ...props\n}) => {\n return <IconComponent fontSize=\"small\" {...props} />;\n};\n\nexport default SmallIconWrapper;\n"],"names":[],"mappings":";;AAyBA,MAAM,mBAAoD,CAAC;AAAA,EACzD,aAAA;AAAA,EACA,GAAG;AACL,CAAM,KAAA;AACJ,EAAA,uBAAQ,KAAA,CAAA,aAAA,CAAA,aAAA,EAAA,EAAc,QAAS,EAAA,OAAA,EAAS,GAAG,KAAO,EAAA,CAAA;AACpD;;;;"}
@@ -0,0 +1,72 @@
1
+ import React from 'react';
2
+ import { SearchResultState } from '@backstage/plugin-search-react';
3
+ import Autocomplete from '@mui/material/Autocomplete';
4
+ import { createSearchLink } from '../../utils/stringUtils.esm.js';
5
+ import { useNavigate } from 'react-router-dom';
6
+ import { SearchInput } from './SearchInput.esm.js';
7
+ import { SearchOption } from './SearchOption.esm.js';
8
+
9
+ const SearchBar = (props) => {
10
+ const { query, setSearchTerm } = props;
11
+ const navigate = useNavigate();
12
+ return /* @__PURE__ */ React.createElement(SearchResultState, { ...props }, ({ loading, error, value }) => {
13
+ const results = query?.term ? value?.results ?? [] : [];
14
+ let options = [];
15
+ if (results.length > 0) {
16
+ options = [
17
+ ...results.slice(0, 5).map((result) => result.document.title),
18
+ `${query?.term}`
19
+ ];
20
+ } else if (query?.term) {
21
+ options = ["No results found"];
22
+ }
23
+ const searchLink = createSearchLink(query?.term ?? "");
24
+ return /* @__PURE__ */ React.createElement(
25
+ Autocomplete,
26
+ {
27
+ freeSolo: true,
28
+ options,
29
+ loading,
30
+ getOptionLabel: (option) => option ?? "",
31
+ onInputChange: (_, inputValue) => setSearchTerm(inputValue),
32
+ sx: { width: "100%" },
33
+ filterOptions: (x) => x,
34
+ getOptionDisabled: (option) => option === "No results found",
35
+ onKeyDown: (event) => {
36
+ if (event.key === "Enter") {
37
+ event.preventDefault();
38
+ if (query?.term) {
39
+ navigate(searchLink);
40
+ }
41
+ }
42
+ },
43
+ renderInput: (params) => /* @__PURE__ */ React.createElement(
44
+ SearchInput,
45
+ {
46
+ params,
47
+ error: !!error,
48
+ helperText: error ? "Error fetching results" : ""
49
+ }
50
+ ),
51
+ renderOption: (renderProps, option, { index }) => /* @__PURE__ */ React.createElement(
52
+ SearchOption,
53
+ {
54
+ option,
55
+ index,
56
+ options,
57
+ query,
58
+ results,
59
+ renderProps,
60
+ searchLink
61
+ }
62
+ ),
63
+ ListboxProps: {
64
+ style: { maxHeight: 600 }
65
+ }
66
+ }
67
+ );
68
+ });
69
+ };
70
+
71
+ export { SearchBar };
72
+ //# sourceMappingURL=SearchBar.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchBar.esm.js","sources":["../../../src/components/SearchComponent/SearchBar.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 React from 'react';\nimport {\n SearchResultState,\n SearchResultProps,\n} from '@backstage/plugin-search-react';\nimport Autocomplete from '@mui/material/Autocomplete';\nimport { createSearchLink } from '../../utils/stringUtils';\nimport { useNavigate } from 'react-router-dom';\nimport { SearchInput } from './SearchInput';\nimport { SearchOption } from './SearchOption';\n\ninterface SearchBarProps {\n query: SearchResultProps['query'];\n setSearchTerm: (term: string) => void;\n}\nexport const SearchBar = (props: SearchBarProps) => {\n const { query, setSearchTerm } = props;\n const navigate = useNavigate();\n\n return (\n <SearchResultState {...props}>\n {({ loading, error, value }) => {\n const results = query?.term ? value?.results ?? [] : [];\n let options: string[] = [];\n if (results.length > 0) {\n options = [\n ...results.slice(0, 5).map(result => result.document.title),\n `${query?.term}`,\n ];\n } else if (query?.term) {\n options = ['No results found'];\n }\n const searchLink = createSearchLink(query?.term ?? '');\n\n return (\n <Autocomplete\n freeSolo\n options={options}\n loading={loading}\n getOptionLabel={option => option ?? ''}\n onInputChange={(_, inputValue) => setSearchTerm(inputValue)}\n sx={{ width: '100%' }}\n filterOptions={x => x}\n getOptionDisabled={option => option === 'No results found'}\n onKeyDown={event => {\n if (event.key === 'Enter') {\n event.preventDefault();\n if (query?.term) {\n navigate(searchLink);\n }\n }\n }}\n renderInput={params => (\n <SearchInput\n params={params}\n error={!!error}\n helperText={error ? 'Error fetching results' : ''}\n />\n )}\n renderOption={(renderProps, option, { index }) => (\n <SearchOption\n option={option}\n index={index}\n options={options}\n query={query}\n results={results}\n renderProps={renderProps}\n searchLink={searchLink}\n />\n )}\n ListboxProps={{\n style: { maxHeight: 600 },\n }}\n />\n );\n }}\n </SearchResultState>\n );\n};\n"],"names":[],"mappings":";;;;;;;;AA+Ba,MAAA,SAAA,GAAY,CAAC,KAA0B,KAAA;AAClD,EAAM,MAAA,EAAE,KAAO,EAAA,aAAA,EAAkB,GAAA,KAAA;AACjC,EAAA,MAAM,WAAW,WAAY,EAAA;AAE7B,EACE,uBAAA,KAAA,CAAA,aAAA,CAAC,qBAAmB,GAAG,KAAA,EAAA,EACpB,CAAC,EAAE,OAAA,EAAS,KAAO,EAAA,KAAA,EAAY,KAAA;AAC9B,IAAA,MAAM,UAAU,KAAO,EAAA,IAAA,GAAO,OAAO,OAAW,IAAA,KAAK,EAAC;AACtD,IAAA,IAAI,UAAoB,EAAC;AACzB,IAAI,IAAA,OAAA,CAAQ,SAAS,CAAG,EAAA;AACtB,MAAU,OAAA,GAAA;AAAA,QACR,GAAG,OAAQ,CAAA,KAAA,CAAM,CAAG,EAAA,CAAC,EAAE,GAAI,CAAA,CAAA,MAAA,KAAU,MAAO,CAAA,QAAA,CAAS,KAAK,CAAA;AAAA,QAC1D,CAAA,EAAG,OAAO,IAAI,CAAA;AAAA,OAChB;AAAA,KACF,MAAA,IAAW,OAAO,IAAM,EAAA;AACtB,MAAA,OAAA,GAAU,CAAC,kBAAkB,CAAA;AAAA;AAE/B,IAAA,MAAM,UAAa,GAAA,gBAAA,CAAiB,KAAO,EAAA,IAAA,IAAQ,EAAE,CAAA;AAErD,IACE,uBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,YAAA;AAAA,MAAA;AAAA,QACC,QAAQ,EAAA,IAAA;AAAA,QACR,OAAA;AAAA,QACA,OAAA;AAAA,QACA,cAAA,EAAgB,YAAU,MAAU,IAAA,EAAA;AAAA,QACpC,aAAe,EAAA,CAAC,CAAG,EAAA,UAAA,KAAe,cAAc,UAAU,CAAA;AAAA,QAC1D,EAAA,EAAI,EAAE,KAAA,EAAO,MAAO,EAAA;AAAA,QACpB,eAAe,CAAK,CAAA,KAAA,CAAA;AAAA,QACpB,iBAAA,EAAmB,YAAU,MAAW,KAAA,kBAAA;AAAA,QACxC,WAAW,CAAS,KAAA,KAAA;AAClB,UAAI,IAAA,KAAA,CAAM,QAAQ,OAAS,EAAA;AACzB,YAAA,KAAA,CAAM,cAAe,EAAA;AACrB,YAAA,IAAI,OAAO,IAAM,EAAA;AACf,cAAA,QAAA,CAAS,UAAU,CAAA;AAAA;AACrB;AACF,SACF;AAAA,QACA,aAAa,CACX,MAAA,qBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,WAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,KAAA,EAAO,CAAC,CAAC,KAAA;AAAA,YACT,UAAA,EAAY,QAAQ,wBAA2B,GAAA;AAAA;AAAA,SACjD;AAAA,QAEF,cAAc,CAAC,WAAA,EAAa,MAAQ,EAAA,EAAE,OACpC,qBAAA,KAAA,CAAA,aAAA;AAAA,UAAC,YAAA;AAAA,UAAA;AAAA,YACC,MAAA;AAAA,YACA,KAAA;AAAA,YACA,OAAA;AAAA,YACA,KAAA;AAAA,YACA,OAAA;AAAA,YACA,WAAA;AAAA,YACA;AAAA;AAAA,SACF;AAAA,QAEF,YAAc,EAAA;AAAA,UACZ,KAAA,EAAO,EAAE,SAAA,EAAW,GAAI;AAAA;AAC1B;AAAA,KACF;AAAA,GAGN,CAAA;AAEJ;;;;"}
@@ -0,0 +1,26 @@
1
+ import React, { useState } from 'react';
2
+ import Box from '@mui/material/Box';
3
+ import { SearchBar } from './SearchBar.esm.js';
4
+ import { SearchContextProvider } from '@backstage/plugin-search-react';
5
+
6
+ const SearchComponent = () => {
7
+ const [searchTerm, setSearchTerm] = useState("");
8
+ return /* @__PURE__ */ React.createElement(SearchContextProvider, null, /* @__PURE__ */ React.createElement(
9
+ Box,
10
+ {
11
+ sx: {
12
+ position: "relative",
13
+ flexGrow: 1,
14
+ display: "flex",
15
+ flexDirection: "row",
16
+ justifyContent: "start",
17
+ direction: "ltr",
18
+ mr: 4
19
+ }
20
+ },
21
+ /* @__PURE__ */ React.createElement(SearchBar, { query: { term: searchTerm }, setSearchTerm })
22
+ ));
23
+ };
24
+
25
+ export { SearchComponent };
26
+ //# sourceMappingURL=SearchComponent.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchComponent.esm.js","sources":["../../../src/components/SearchComponent/SearchComponent.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 React, { useState } from 'react';\nimport Box from '@mui/material/Box';\nimport { SearchBar } from './SearchBar';\nimport { SearchContextProvider } from '@backstage/plugin-search-react';\n\nexport const SearchComponent = () => {\n const [searchTerm, setSearchTerm] = useState<string>('');\n\n return (\n <SearchContextProvider>\n <Box\n sx={{\n position: 'relative',\n flexGrow: 1,\n display: 'flex',\n flexDirection: 'row',\n justifyContent: 'start',\n direction: 'ltr',\n mr: 4,\n }}\n >\n <SearchBar query={{ term: searchTerm }} setSearchTerm={setSearchTerm} />\n </Box>\n </SearchContextProvider>\n );\n};\n"],"names":[],"mappings":";;;;;AAqBO,MAAM,kBAAkB,MAAM;AACnC,EAAA,MAAM,CAAC,UAAA,EAAY,aAAa,CAAA,GAAI,SAAiB,EAAE,CAAA;AAEvD,EAAA,2CACG,qBACC,EAAA,IAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,GAAA;AAAA,IAAA;AAAA,MACC,EAAI,EAAA;AAAA,QACF,QAAU,EAAA,UAAA;AAAA,QACV,QAAU,EAAA,CAAA;AAAA,QACV,OAAS,EAAA,MAAA;AAAA,QACT,aAAe,EAAA,KAAA;AAAA,QACf,cAAgB,EAAA,OAAA;AAAA,QAChB,SAAW,EAAA,KAAA;AAAA,QACX,EAAI,EAAA;AAAA;AACN,KAAA;AAAA,wCAEC,SAAU,EAAA,EAAA,KAAA,EAAO,EAAE,IAAM,EAAA,UAAA,IAAc,aAA8B,EAAA;AAAA,GAE1E,CAAA;AAEJ;;;;"}
@@ -0,0 +1,32 @@
1
+ import React from 'react';
2
+ import TextField from '@mui/material/TextField';
3
+ import InputAdornment from '@mui/material/InputAdornment';
4
+ import SearchIcon from '@mui/icons-material/Search';
5
+
6
+ const SearchInput = ({
7
+ params,
8
+ error,
9
+ helperText
10
+ }) => /* @__PURE__ */ React.createElement(
11
+ TextField,
12
+ {
13
+ ...params,
14
+ placeholder: "Search...",
15
+ variant: "standard",
16
+ error,
17
+ helperText,
18
+ InputProps: {
19
+ ...params.InputProps,
20
+ disableUnderline: true,
21
+ startAdornment: /* @__PURE__ */ React.createElement(InputAdornment, { position: "start" }, /* @__PURE__ */ React.createElement(SearchIcon, { style: { color: "#fff" } }))
22
+ },
23
+ sx: {
24
+ pt: "6px",
25
+ input: { color: "#fff" },
26
+ button: { color: "#fff" }
27
+ }
28
+ }
29
+ );
30
+
31
+ export { SearchInput };
32
+ //# sourceMappingURL=SearchInput.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchInput.esm.js","sources":["../../../src/components/SearchComponent/SearchInput.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 React from 'react';\nimport TextField from '@mui/material/TextField';\nimport InputAdornment from '@mui/material/InputAdornment';\nimport SearchIcon from '@mui/icons-material/Search';\n\ninterface SearchInputProps {\n params: any;\n error: boolean;\n helperText: string;\n}\n\nexport const SearchInput = ({\n params,\n error,\n helperText,\n}: SearchInputProps) => (\n <TextField\n {...params}\n placeholder=\"Search...\"\n variant=\"standard\"\n error={error}\n helperText={helperText}\n InputProps={{\n ...params.InputProps,\n disableUnderline: true,\n startAdornment: (\n <InputAdornment position=\"start\">\n <SearchIcon style={{ color: '#fff' }} />\n </InputAdornment>\n ),\n }}\n sx={{\n pt: '6px',\n input: { color: '#fff' },\n button: { color: '#fff' },\n }}\n />\n);\n"],"names":[],"mappings":";;;;;AA2BO,MAAM,cAAc,CAAC;AAAA,EAC1B,MAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CACE,qBAAA,KAAA,CAAA,aAAA;AAAA,EAAC,SAAA;AAAA,EAAA;AAAA,IACE,GAAG,MAAA;AAAA,IACJ,WAAY,EAAA,WAAA;AAAA,IACZ,OAAQ,EAAA,UAAA;AAAA,IACR,KAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAY,EAAA;AAAA,MACV,GAAG,MAAO,CAAA,UAAA;AAAA,MACV,gBAAkB,EAAA,IAAA;AAAA,MAClB,cACE,kBAAA,KAAA,CAAA,aAAA,CAAC,cAAe,EAAA,EAAA,QAAA,EAAS,OACvB,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,KAAA,EAAO,EAAE,KAAA,EAAO,MAAO,EAAA,EAAG,CACxC;AAAA,KAEJ;AAAA,IACA,EAAI,EAAA;AAAA,MACF,EAAI,EAAA,KAAA;AAAA,MACJ,KAAA,EAAO,EAAE,KAAA,EAAO,MAAO,EAAA;AAAA,MACvB,MAAA,EAAQ,EAAE,KAAA,EAAO,MAAO;AAAA;AAC1B;AACF;;;;"}
@@ -0,0 +1,44 @@
1
+ import React from 'react';
2
+ import Box from '@mui/material/Box';
3
+ import Divider from '@mui/material/Divider';
4
+ import { Link } from '@backstage/core-components';
5
+ import ListItem from '@mui/material/ListItem';
6
+ import Typography from '@mui/material/Typography';
7
+ import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
8
+ import { SearchResultItem } from './SearchResultItem.esm.js';
9
+
10
+ const SearchOption = ({
11
+ option,
12
+ index,
13
+ options,
14
+ query,
15
+ results,
16
+ renderProps,
17
+ searchLink
18
+ }) => {
19
+ if (option === query?.term && index === options.length - 1) {
20
+ return /* @__PURE__ */ React.createElement(Box, { key: "all-results", id: "all-results" }, /* @__PURE__ */ React.createElement(Divider, { sx: { my: 0.5 } }), /* @__PURE__ */ React.createElement(Link, { to: searchLink, underline: "none" }, /* @__PURE__ */ React.createElement(
21
+ ListItem,
22
+ {
23
+ ...renderProps,
24
+ sx: { my: 0 },
25
+ className: "allResultsOption"
26
+ },
27
+ /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Typography, { sx: { flexGrow: 1, mr: 1 } }, "All results"), /* @__PURE__ */ React.createElement(ArrowForwardIcon, { fontSize: "small" }))
28
+ )));
29
+ }
30
+ const result = results.find((r) => r.document.title === option);
31
+ return /* @__PURE__ */ React.createElement(
32
+ SearchResultItem,
33
+ {
34
+ key: index,
35
+ option,
36
+ query,
37
+ result,
38
+ renderProps
39
+ }
40
+ );
41
+ };
42
+
43
+ export { SearchOption };
44
+ //# sourceMappingURL=SearchOption.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchOption.esm.js","sources":["../../../src/components/SearchComponent/SearchOption.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 React from 'react';\nimport Box from '@mui/material/Box';\nimport Divider from '@mui/material/Divider';\nimport { Link } from '@backstage/core-components';\nimport ListItem from '@mui/material/ListItem';\nimport Typography from '@mui/material/Typography';\nimport ArrowForwardIcon from '@mui/icons-material/ArrowForward';\nimport { SearchResultItem } from './SearchResultItem';\nimport { Result, SearchDocument } from '@backstage/plugin-search-common';\nimport { SearchResultProps } from '@backstage/plugin-search-react';\n\ninterface SearchOptionProps {\n option: string;\n index: number;\n options: string[];\n query: SearchResultProps['query'];\n results: Result<SearchDocument>[];\n renderProps: any;\n searchLink: string;\n}\n\nexport const SearchOption = ({\n option,\n index,\n options,\n query,\n results,\n renderProps,\n searchLink,\n}: SearchOptionProps) => {\n if (option === query?.term && index === options.length - 1) {\n return (\n <Box key=\"all-results\" id=\"all-results\">\n <Divider sx={{ my: 0.5 }} />\n <Link to={searchLink} underline=\"none\">\n <ListItem\n {...renderProps}\n sx={{ my: 0 }}\n className=\"allResultsOption\"\n >\n <Box sx={{ display: 'flex', alignItems: 'center' }}>\n <Typography sx={{ flexGrow: 1, mr: 1 }}>All results</Typography>\n <ArrowForwardIcon fontSize=\"small\" />\n </Box>\n </ListItem>\n </Link>\n </Box>\n );\n }\n\n const result = results.find(r => r.document.title === option);\n return (\n <SearchResultItem\n key={index}\n option={option}\n query={query}\n result={result}\n renderProps={renderProps}\n />\n );\n};\n"],"names":[],"mappings":";;;;;;;;;AAqCO,MAAM,eAAe,CAAC;AAAA,EAC3B,MAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAyB,KAAA;AACvB,EAAA,IAAI,WAAW,KAAO,EAAA,IAAA,IAAQ,KAAU,KAAA,OAAA,CAAQ,SAAS,CAAG,EAAA;AAC1D,IAAA,2CACG,GAAI,EAAA,EAAA,GAAA,EAAI,eAAc,EAAG,EAAA,aAAA,EAAA,sCACvB,OAAQ,EAAA,EAAA,EAAA,EAAI,EAAE,EAAI,EAAA,GAAA,IAAO,CAC1B,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAK,EAAI,EAAA,UAAA,EAAY,WAAU,MAC9B,EAAA,kBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACE,GAAG,WAAA;AAAA,QACJ,EAAA,EAAI,EAAE,EAAA,EAAI,CAAE,EAAA;AAAA,QACZ,SAAU,EAAA;AAAA,OAAA;AAAA,sBAEV,KAAA,CAAA,aAAA,CAAC,GAAI,EAAA,EAAA,EAAA,EAAI,EAAE,OAAA,EAAS,QAAQ,UAAY,EAAA,QAAA,EACtC,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,UAAW,EAAA,EAAA,EAAA,EAAI,EAAE,QAAU,EAAA,CAAA,EAAG,EAAI,EAAA,CAAA,EAAK,EAAA,EAAA,aAAW,mBAClD,KAAA,CAAA,aAAA,CAAA,gBAAA,EAAA,EAAiB,QAAS,EAAA,OAAA,EAAQ,CACrC;AAAA,KAEJ,CACF,CAAA;AAAA;AAIJ,EAAA,MAAM,SAAS,OAAQ,CAAA,IAAA,CAAK,OAAK,CAAE,CAAA,QAAA,CAAS,UAAU,MAAM,CAAA;AAC5D,EACE,uBAAA,KAAA,CAAA,aAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,GAAK,EAAA,KAAA;AAAA,MACL,MAAA;AAAA,MACA,KAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA;AAAA,GACF;AAEJ;;;;"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { Link } from '@backstage/core-components';
3
+ import ListItem from '@mui/material/ListItem';
4
+ import Box from '@mui/material/Box';
5
+ import Typography from '@mui/material/Typography';
6
+ import { highlightMatch } from '../../utils/stringUtils.esm.js';
7
+
8
+ const SearchResultItem = ({
9
+ option,
10
+ query,
11
+ result,
12
+ renderProps
13
+ }) => /* @__PURE__ */ React.createElement(Link, { to: result?.document.location ?? "#", underline: "none" }, /* @__PURE__ */ React.createElement(ListItem, { key: option, ...renderProps, sx: { cursor: "pointer", py: 2 } }, /* @__PURE__ */ React.createElement(Box, { sx: { display: "flex", width: "100%" } }, /* @__PURE__ */ React.createElement(Typography, { sx: { color: "text.primary", py: 0.5, flexGrow: 1 } }, option === "No results found" ? option : highlightMatch(option, query?.term ?? "")))));
14
+
15
+ export { SearchResultItem };
16
+ //# sourceMappingURL=SearchResultItem.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SearchResultItem.esm.js","sources":["../../../src/components/SearchComponent/SearchResultItem.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 React from 'react';\nimport { Link } from '@backstage/core-components';\nimport ListItem from '@mui/material/ListItem';\nimport Box from '@mui/material/Box';\nimport Typography from '@mui/material/Typography';\nimport { highlightMatch } from '../../utils/stringUtils';\nimport { SearchResultProps } from '@backstage/plugin-search-react';\nimport { Result, SearchDocument } from '@backstage/plugin-search-common';\n\ninterface SearchResultItemProps {\n option: string;\n query: SearchResultProps['query'];\n result: Result<SearchDocument> | undefined;\n renderProps: any;\n}\n\nexport const SearchResultItem = ({\n option,\n query,\n result,\n renderProps,\n}: SearchResultItemProps) => (\n <Link to={result?.document.location ?? '#'} underline=\"none\">\n <ListItem key={option} {...renderProps} sx={{ cursor: 'pointer', py: 2 }}>\n <Box sx={{ display: 'flex', width: '100%' }}>\n <Typography sx={{ color: 'text.primary', py: 0.5, flexGrow: 1 }}>\n {option === 'No results found'\n ? option\n : highlightMatch(option, query?.term ?? '')}\n </Typography>\n </Box>\n </ListItem>\n </Link>\n);\n"],"names":[],"mappings":";;;;;;;AAgCO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,MAAA;AAAA,EACA,KAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CACE,qBAAA,KAAA,CAAA,aAAA,CAAC,IAAK,EAAA,EAAA,EAAA,EAAI,MAAQ,EAAA,QAAA,CAAS,YAAY,GAAK,EAAA,SAAA,EAAU,MACpD,EAAA,kBAAA,KAAA,CAAA,aAAA,CAAC,QAAS,EAAA,EAAA,GAAA,EAAK,QAAS,GAAG,WAAA,EAAa,EAAI,EAAA,EAAE,MAAQ,EAAA,SAAA,EAAW,IAAI,CAAE,EAAA,EAAA,kBACpE,KAAA,CAAA,aAAA,CAAA,GAAA,EAAA,EAAI,EAAI,EAAA,EAAE,SAAS,MAAQ,EAAA,KAAA,EAAO,MAAO,EAAA,EAAA,kBACvC,KAAA,CAAA,aAAA,CAAA,UAAA,EAAA,EAAW,IAAI,EAAE,KAAA,EAAO,cAAgB,EAAA,EAAA,EAAI,GAAK,EAAA,QAAA,EAAU,GACzD,EAAA,EAAA,MAAA,KAAW,kBACR,GAAA,MAAA,GACA,cAAe,CAAA,MAAA,EAAQ,KAAO,EAAA,IAAA,IAAQ,EAAE,CAC9C,CACF,CACF,CACF;;;;"}
@@ -0,0 +1,19 @@
1
+ import React from 'react';
2
+
3
+ const useDropdownManager = () => {
4
+ const [menuStates, setMenuStates] = React.useState({});
5
+ const handleOpen = (key) => (event) => {
6
+ setMenuStates((prev) => ({ ...prev, [key]: event.currentTarget }));
7
+ };
8
+ const handleClose = (key) => () => {
9
+ setMenuStates((prev) => ({ ...prev, [key]: null }));
10
+ };
11
+ return {
12
+ menuStates,
13
+ handleOpen,
14
+ handleClose
15
+ };
16
+ };
17
+
18
+ export { useDropdownManager };
19
+ //# sourceMappingURL=useDropdownManager.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDropdownManager.esm.js","sources":["../../src/hooks/useDropdownManager.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\nimport React from 'react';\n\nexport const useDropdownManager = () => {\n const [menuStates, setMenuStates] = React.useState<\n Record<string, HTMLElement | null>\n >({});\n\n const handleOpen =\n (key: string) => (event: React.MouseEvent<HTMLElement>) => {\n setMenuStates(prev => ({ ...prev, [key]: event.currentTarget }));\n };\n\n const handleClose = (key: string) => () => {\n setMenuStates(prev => ({ ...prev, [key]: null }));\n };\n\n return {\n menuStates,\n handleOpen,\n handleClose,\n };\n};\n"],"names":[],"mappings":";;AAkBO,MAAM,qBAAqB,MAAM;AACtC,EAAA,MAAM,CAAC,UAAY,EAAA,aAAa,IAAI,KAAM,CAAA,QAAA,CAExC,EAAE,CAAA;AAEJ,EAAA,MAAM,UACJ,GAAA,CAAC,GAAgB,KAAA,CAAC,KAAyC,KAAA;AACzD,IAAc,aAAA,CAAA,CAAA,IAAA,MAAS,EAAE,GAAG,IAAA,EAAM,CAAC,GAAG,GAAG,KAAM,CAAA,aAAA,EAAgB,CAAA,CAAA;AAAA,GACjE;AAEF,EAAM,MAAA,WAAA,GAAc,CAAC,GAAA,KAAgB,MAAM;AACzC,IAAc,aAAA,CAAA,CAAA,IAAA,MAAS,EAAE,GAAG,IAAA,EAAM,CAAC,GAAG,GAAG,MAAO,CAAA,CAAA;AAAA,GAClD;AAEA,EAAO,OAAA;AAAA,IACL,UAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AACF;;;;"}
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import * as react from 'react';
3
+ import * as _backstage_core_plugin_api from '@backstage/core-plugin-api';
4
+
5
+ /**
6
+ * @public
7
+ * Global Header Plugin
8
+ */
9
+ declare const globalHeaderPlugin: _backstage_core_plugin_api.BackstagePlugin<{}, {}, {}>;
10
+ /**
11
+ * @public
12
+ * Global Header
13
+ */
14
+ declare const GlobalHeader: () => react.JSX.Element;
15
+
16
+ export { GlobalHeader, globalHeaderPlugin };
@@ -0,0 +1,7 @@
1
+ import { unstable_ClassNameGenerator } from '@mui/material/className';
2
+ export { GlobalHeader, globalHeaderPlugin } from './plugin.esm.js';
3
+
4
+ unstable_ClassNameGenerator.configure((componentName) => {
5
+ return componentName.startsWith("v5-") ? componentName : `v5-${componentName}`;
6
+ });
7
+ //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.esm.js","sources":["../src/index.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 */\nimport { unstable_ClassNameGenerator as ClassNameGenerator } from '@mui/material/className';\n\nClassNameGenerator.configure(componentName => {\n return componentName.startsWith('v5-')\n ? componentName\n : `v5-${componentName}`;\n});\n\nexport { globalHeaderPlugin, GlobalHeader } from './plugin';\n"],"names":["ClassNameGenerator"],"mappings":";;;AAiBAA,2BAAA,CAAmB,UAAU,CAAiB,aAAA,KAAA;AAC5C,EAAA,OAAO,cAAc,UAAW,CAAA,KAAK,CACjC,GAAA,aAAA,GACA,MAAM,aAAa,CAAA,CAAA;AACzB,CAAC,CAAA"}
@@ -0,0 +1,16 @@
1
+ import { createPlugin, createComponentExtension } from '@backstage/core-plugin-api';
2
+
3
+ const globalHeaderPlugin = createPlugin({
4
+ id: "global-header"
5
+ });
6
+ const GlobalHeader = globalHeaderPlugin.provide(
7
+ createComponentExtension({
8
+ name: "GlobalHeader",
9
+ component: {
10
+ lazy: () => import('./components/GlobalHeader.esm.js').then((m) => m.GlobalHeader)
11
+ }
12
+ })
13
+ );
14
+
15
+ export { GlobalHeader, globalHeaderPlugin };
16
+ //# sourceMappingURL=plugin.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.esm.js","sources":["../src/plugin.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\nimport {\n createPlugin,\n createComponentExtension,\n} from '@backstage/core-plugin-api';\n\n/**\n * @public\n * Global Header Plugin\n */\nexport const globalHeaderPlugin = createPlugin({\n id: 'global-header',\n});\n\n/**\n * @public\n * Global Header\n */\nexport const GlobalHeader = globalHeaderPlugin.provide(\n createComponentExtension({\n name: 'GlobalHeader',\n component: {\n lazy: () => import('./components/GlobalHeader').then(m => m.GlobalHeader),\n },\n }),\n);\n"],"names":[],"mappings":";;AAyBO,MAAM,qBAAqB,YAAa,CAAA;AAAA,EAC7C,EAAI,EAAA;AACN,CAAC;AAMM,MAAM,eAAe,kBAAmB,CAAA,OAAA;AAAA,EAC7C,wBAAyB,CAAA;AAAA,IACvB,IAAM,EAAA,cAAA;AAAA,IACN,SAAW,EAAA;AAAA,MACT,IAAA,EAAM,MAAM,OAAO,kCAA2B,EAAE,IAAK,CAAA,CAAA,CAAA,KAAK,EAAE,YAAY;AAAA;AAC1E,GACD;AACH;;;;"}
@@ -0,0 +1,35 @@
1
+ import React from 'react';
2
+ import Typography from '@mui/material/Typography';
3
+
4
+ const highlightMatch = (text, query) => {
5
+ if (!query) return /* @__PURE__ */ React.createElement(React.Fragment, null, text);
6
+ const escapeRegex = (input) => input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7
+ const escapedQuery = escapeRegex(query);
8
+ const regex = new RegExp(`(${escapedQuery})`, "i");
9
+ const parts = text.split(regex);
10
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, parts.map(
11
+ (part, index) => regex.test(part) ? /* @__PURE__ */ React.createElement(
12
+ Typography,
13
+ {
14
+ key: `${part}-${index}`,
15
+ component: "span",
16
+ sx: { fontWeight: "normal" }
17
+ },
18
+ part
19
+ ) : /* @__PURE__ */ React.createElement(
20
+ Typography,
21
+ {
22
+ key: `${part}-${index}`,
23
+ component: "span",
24
+ sx: { fontWeight: "bold" }
25
+ },
26
+ part
27
+ )
28
+ ));
29
+ };
30
+ const createSearchLink = (searchTerm) => {
31
+ return `/search?query=${encodeURIComponent(searchTerm)}`;
32
+ };
33
+
34
+ export { createSearchLink, highlightMatch };
35
+ //# sourceMappingURL=stringUtils.esm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stringUtils.esm.js","sources":["../../src/utils/stringUtils.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 React from 'react';\nimport Typography from '@mui/material/Typography';\n\n/**\n * Highlights the substring that matches the query term.\n * @param text The full text to render.\n * @param query The query term to highlight.\n * @returns JSX.Element with highlighted matching substring.\n */\nexport const highlightMatch = (text: string, query: string) => {\n if (!query) return <>{text}</>;\n\n const escapeRegex = (input: string) =>\n input.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n const escapedQuery = escapeRegex(query);\n\n const regex = new RegExp(`(${escapedQuery})`, 'i');\n const parts = text.split(regex);\n\n return (\n <>\n {parts.map((part, index) =>\n regex.test(part) ? (\n <Typography\n key={`${part}-${index}`}\n component=\"span\"\n sx={{ fontWeight: 'normal' }}\n >\n {part}\n </Typography>\n ) : (\n <Typography\n key={`${part}-${index}`}\n component=\"span\"\n sx={{ fontWeight: 'bold' }}\n >\n {part}\n </Typography>\n ),\n )}\n </>\n );\n};\n\nexport const createSearchLink = (searchTerm: string) => {\n return `/search?query=${encodeURIComponent(searchTerm)}`;\n};\n"],"names":[],"mappings":";;;AAyBa,MAAA,cAAA,GAAiB,CAAC,IAAA,EAAc,KAAkB,KAAA;AAC7D,EAAA,IAAI,CAAC,KAAA,EAAc,uBAAA,KAAA,CAAA,aAAA,CAAA,KAAA,CAAA,QAAA,EAAA,IAAA,EAAG,IAAK,CAAA;AAE3B,EAAA,MAAM,cAAc,CAAC,KAAA,KACnB,KAAM,CAAA,OAAA,CAAQ,uBAAuB,MAAM,CAAA;AAC7C,EAAM,MAAA,YAAA,GAAe,YAAY,KAAK,CAAA;AAEtC,EAAA,MAAM,QAAQ,IAAI,MAAA,CAAO,CAAI,CAAA,EAAA,YAAY,KAAK,GAAG,CAAA;AACjD,EAAM,MAAA,KAAA,GAAQ,IAAK,CAAA,KAAA,CAAM,KAAK,CAAA;AAE9B,EAAA,iEAEK,KAAM,CAAA,GAAA;AAAA,IAAI,CAAC,IAAM,EAAA,KAAA,KAChB,KAAM,CAAA,IAAA,CAAK,IAAI,CACb,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,QACrB,SAAU,EAAA,MAAA;AAAA,QACV,EAAA,EAAI,EAAE,UAAA,EAAY,QAAS;AAAA,OAAA;AAAA,MAE1B;AAAA,KAGH,mBAAA,KAAA,CAAA,aAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,GAAK,EAAA,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,QACrB,SAAU,EAAA,MAAA;AAAA,QACV,EAAA,EAAI,EAAE,UAAA,EAAY,MAAO;AAAA,OAAA;AAAA,MAExB;AAAA;AACH,GAGN,CAAA;AAEJ;AAEa,MAAA,gBAAA,GAAmB,CAAC,UAAuB,KAAA;AACtD,EAAO,OAAA,CAAA,cAAA,EAAiB,kBAAmB,CAAA,UAAU,CAAC,CAAA,CAAA;AACxD;;;;"}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@red-hat-developer-hub/backstage-plugin-global-header",
3
+ "version": "0.0.1",
4
+ "main": "dist/index.esm.js",
5
+ "types": "dist/index.d.ts",
6
+ "license": "Apache-2.0",
7
+ "publishConfig": {
8
+ "access": "public",
9
+ "main": "dist/index.esm.js",
10
+ "types": "dist/index.d.ts"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/redhat-developer/rhdh-plugins",
15
+ "directory": "workspaces/global-header/plugins/global-header"
16
+ },
17
+ "backstage": {
18
+ "role": "frontend-plugin",
19
+ "pluginId": "global-header",
20
+ "pluginPackages": [
21
+ "@red-hat-developer-hub/backstage-plugin-global-header"
22
+ ]
23
+ },
24
+ "sideEffects": false,
25
+ "scripts": {
26
+ "start": "backstage-cli package start",
27
+ "build": "backstage-cli package build",
28
+ "lint": "backstage-cli package lint",
29
+ "lint:fix": "backstage-cli package lint --fix",
30
+ "test": "backstage-cli package test",
31
+ "clean": "backstage-cli package clean",
32
+ "prepack": "backstage-cli package prepack",
33
+ "postpack": "backstage-cli package postpack"
34
+ },
35
+ "dependencies": {
36
+ "@backstage/core-components": "^0.16.1",
37
+ "@backstage/core-plugin-api": "^1.10.1",
38
+ "@backstage/plugin-search": "1.4.21",
39
+ "@backstage/plugin-search-backend": "^1.8.0",
40
+ "@backstage/plugin-search-backend-module-catalog": "^0.2.6",
41
+ "@backstage/plugin-search-backend-module-pg": "^0.5.39",
42
+ "@backstage/plugin-search-backend-module-techdocs": "^0.3.4",
43
+ "@backstage/plugin-search-common": "^1.2.16",
44
+ "@backstage/plugin-search-react": "1.8.4",
45
+ "@backstage/theme": "^0.6.2",
46
+ "@mui/icons-material": "5.16.13",
47
+ "@mui/material": "5.16.13",
48
+ "@mui/styled-engine": "5.16.13",
49
+ "react-dom": "16.13.1 || ^17.0.0 || ^18.0.0",
50
+ "react-router-dom": "^6.3.0",
51
+ "react-use": "^17.2.4"
52
+ },
53
+ "peerDependencies": {
54
+ "@backstage/core-components": "0.15.1",
55
+ "@backstage/core-plugin-api": "^1.10.0",
56
+ "@backstage/plugin-search": "1.4.18",
57
+ "@backstage/plugin-search-react": "1.8.1",
58
+ "@backstage/theme": "0.6.0",
59
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
60
+ "react-router-dom": "^6.0.0"
61
+ },
62
+ "devDependencies": {
63
+ "@backstage/cli": "^0.29.0",
64
+ "@backstage/core-app-api": "^1.15.2",
65
+ "@backstage/dev-utils": "^1.1.4",
66
+ "@backstage/plugin-search-common": "^1.2.16",
67
+ "@backstage/test-utils": "^1.7.2",
68
+ "@testing-library/jest-dom": "^6.0.0",
69
+ "@testing-library/react": "^14.0.0",
70
+ "@testing-library/user-event": "^14.0.0",
71
+ "msw": "^1.0.0",
72
+ "react": "^16.13.1 || ^17.0.0 || ^18.0.0",
73
+ "react-router-dom": "^6.0.0"
74
+ },
75
+ "files": [
76
+ "dist"
77
+ ],
78
+ "typesVersions": {
79
+ "*": {
80
+ "index": [
81
+ "dist/index.d.ts"
82
+ ]
83
+ }
84
+ },
85
+ "module": "./dist/index.esm.js"
86
+ }