PageHeader.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import React from 'react';
  2. import { observer } from 'mobx-react';
  3. import { NavModel, NavModelItem } from '../../nav_model_srv';
  4. import classNames from 'classnames';
  5. import appEvents from 'app/core/app_events';
  6. import { toJS } from 'mobx';
  7. export interface Props {
  8. model: NavModel;
  9. }
  10. const SelectNav = ({ main, customCss }: { main: NavModelItem; customCss: string }) => {
  11. const defaultSelectedItem = main.children.find(navItem => {
  12. return navItem.active === true;
  13. });
  14. const gotoUrl = evt => {
  15. var element = evt.target;
  16. var url = element.options[element.selectedIndex].value;
  17. appEvents.emit('location-change', { href: url });
  18. };
  19. return (
  20. <div className={`gf-form-select-wrapper width-20 ${customCss}`}>
  21. <label className={`gf-form-select-icon ${defaultSelectedItem.icon}`} htmlFor="page-header-select-nav" />
  22. {/* Label to make it clickable */}
  23. <select
  24. className="gf-select-nav gf-form-input"
  25. value={defaultSelectedItem.url}
  26. onChange={gotoUrl}
  27. id="page-header-select-nav"
  28. >
  29. {main.children.map((navItem: NavModelItem) => {
  30. if (navItem.hideFromTabs) {
  31. // TODO: Rename hideFromTabs => hideFromNav
  32. return null;
  33. }
  34. return (
  35. <option key={navItem.url} value={navItem.url}>
  36. {navItem.text}
  37. </option>
  38. );
  39. })}
  40. </select>
  41. </div>
  42. );
  43. };
  44. const Tabs = ({ main, customCss }: { main: NavModelItem; customCss: string }) => {
  45. return (
  46. <ul className={`gf-tabs ${customCss}`}>
  47. {main.children.map((tab, idx) => {
  48. if (tab.hideFromTabs) {
  49. return null;
  50. }
  51. const tabClasses = classNames({
  52. 'gf-tabs-link': true,
  53. active: tab.active,
  54. });
  55. return (
  56. <li className="gf-tabs-item" key={tab.url}>
  57. <a className={tabClasses} target={tab.target} href={tab.url}>
  58. <i className={tab.icon} />
  59. {tab.text}
  60. </a>
  61. </li>
  62. );
  63. })}
  64. </ul>
  65. );
  66. };
  67. const Navigation = ({ main }: { main: NavModelItem }) => {
  68. return (
  69. <nav>
  70. <SelectNav customCss="page-header__select-nav" main={main} />
  71. <Tabs customCss="page-header__tabs" main={main} />
  72. </nav>
  73. );
  74. };
  75. @observer
  76. export default class PageHeader extends React.Component<Props, any> {
  77. constructor(props) {
  78. super(props);
  79. }
  80. shouldComponentUpdate() {
  81. //Hack to re-render on changed props from angular with the @observer decorator
  82. return true;
  83. }
  84. renderTitle(title: string, breadcrumbs: any[]) {
  85. if (!title && (!breadcrumbs || breadcrumbs.length === 0)) {
  86. return null;
  87. }
  88. if (!breadcrumbs || breadcrumbs.length === 0) {
  89. return <h1 className="page-header__title">{title}</h1>;
  90. }
  91. const breadcrumbsResult = [];
  92. for (let i = 0; i < breadcrumbs.length; i++) {
  93. const bc = breadcrumbs[i];
  94. if (bc.url) {
  95. breadcrumbsResult.push(
  96. <a className="text-link" key={i} href={bc.url}>
  97. {bc.title}
  98. </a>
  99. );
  100. } else {
  101. breadcrumbsResult.push(<span key={i}> / {bc.title}</span>);
  102. }
  103. }
  104. breadcrumbsResult.push(<span key={breadcrumbs.length + 1}> / {title}</span>);
  105. return <h1 className="page-header__title">{breadcrumbsResult}</h1>;
  106. }
  107. renderHeaderTitle(main) {
  108. return (
  109. <div className="page-header__inner">
  110. <span className="page-header__logo">
  111. {main.icon && <i className={`page-header__icon ${main.icon}`} />}
  112. {main.img && <img className="page-header__img" src={main.img} />}
  113. </span>
  114. <div className="page-header__info-block">
  115. {this.renderTitle(main.text, main.breadcrumbs)}
  116. {main.subTitle && <div className="page-header__sub-title">{main.subTitle}</div>}
  117. {main.subType && (
  118. <div className="page-header__stamps">
  119. <i className={main.subType.icon} />
  120. {main.subType.text}
  121. </div>
  122. )}
  123. </div>
  124. </div>
  125. );
  126. }
  127. render() {
  128. const { model } = this.props;
  129. if (!model) {
  130. return null;
  131. }
  132. const main = toJS(model.main); // Convert to JS if its a mobx observable
  133. return (
  134. <div className="page-header-canvas">
  135. <div className="page-container">
  136. <div className="page-header">
  137. {this.renderHeaderTitle(main)}
  138. {main.children && <Navigation main={main} />}
  139. </div>
  140. </div>
  141. </div>
  142. );
  143. }
  144. }