PageHeader.tsx 4.4 KB

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