index.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // The index file for the spa running on the summary page
  2. const React = require('react');
  3. const ReactDOM = require('react-dom');
  4. const SummaryTableHeader = require('./summaryTableHeader');
  5. const SummaryTableLine = require('./summaryTableLine');
  6. const SummaryHeader = require('./summaryHeader');
  7. const getChildData = require('./getChildData');
  8. const FlattenToggle = require('./flattenToggle');
  9. const FilterToggle = require('./filterToggle');
  10. const FileBreadcrumbs = require('./fileBreadcrumbs');
  11. const { setLocation, decodeLocation } = require('./routing');
  12. const { useState, useMemo, useEffect } = React;
  13. const sourceData = window.data;
  14. const metricsToShow = {};
  15. for (let i = 0; i < window.metricsToShow.length; i++) {
  16. metricsToShow[window.metricsToShow[i]] = true;
  17. }
  18. let firstMount = true;
  19. function App() {
  20. const routingDefaults = decodeLocation();
  21. const [activeSort, setSort] = useState(
  22. (routingDefaults && routingDefaults.activeSort) || {
  23. sortKey: 'file',
  24. order: 'desc'
  25. }
  26. );
  27. const [isFlat, setIsFlat] = useState(
  28. (routingDefaults && routingDefaults.isFlat) || false
  29. );
  30. const [activeFilters, setFilters] = useState(
  31. (routingDefaults && routingDefaults.activeFilters) || {
  32. low: true,
  33. medium: true,
  34. high: true
  35. }
  36. );
  37. const [expandedLines, setExpandedLines] = useState(
  38. (routingDefaults && routingDefaults.expandedLines) || []
  39. );
  40. const [fileFilter, setFileFilter] = useState(
  41. (routingDefaults && routingDefaults.fileFilter) || ''
  42. );
  43. const childData = useMemo(
  44. () =>
  45. getChildData(
  46. sourceData,
  47. metricsToShow,
  48. activeSort,
  49. isFlat,
  50. activeFilters,
  51. fileFilter
  52. ),
  53. [activeSort, isFlat, activeFilters, fileFilter]
  54. );
  55. const overallMetrics = sourceData.metrics;
  56. useEffect(() => {
  57. setLocation(
  58. firstMount,
  59. activeSort,
  60. isFlat,
  61. activeFilters,
  62. fileFilter,
  63. expandedLines
  64. );
  65. firstMount = false;
  66. }, [activeSort, isFlat, activeFilters, fileFilter, expandedLines]);
  67. useEffect(() => {
  68. window.onpopstate = () => {
  69. const routingState = decodeLocation();
  70. if (routingState) {
  71. // make sure all the state is set before rendering to avoid url updates
  72. // alternative is to merge all the states into one so it can be set in one go
  73. // https://github.com/facebook/react/issues/14259
  74. ReactDOM.unstable_batchedUpdates(() => {
  75. setFilters(routingState.activeFilters);
  76. setSort(routingState.activeSort);
  77. setIsFlat(routingState.isFlat);
  78. setExpandedLines(routingState.expandedLines);
  79. setFileFilter(routingState.fileFilter);
  80. });
  81. }
  82. };
  83. }, []);
  84. return (
  85. <div className="layout">
  86. <div className="layout__section">
  87. <SummaryHeader
  88. metrics={overallMetrics}
  89. metricsToShow={metricsToShow}
  90. />
  91. </div>
  92. <div className="layout__section">
  93. <div className="toolbar">
  94. <div className="toolbar__item">
  95. <FlattenToggle setIsFlat={setIsFlat} isFlat={isFlat} />
  96. </div>
  97. <div className="toolbar__item">
  98. <FilterToggle
  99. activeFilters={activeFilters}
  100. setFilters={setFilters}
  101. />
  102. </div>
  103. </div>
  104. </div>
  105. <div className="layout__section">
  106. <h1>
  107. <FileBreadcrumbs
  108. fileFilter={fileFilter}
  109. setFileFilter={setFileFilter}
  110. />
  111. </h1>
  112. </div>
  113. <div className="layout__section layout__section--fill">
  114. <table className="coverage-summary">
  115. <SummaryTableHeader
  116. onSort={newSort => {
  117. setSort(newSort);
  118. }}
  119. activeSort={activeSort}
  120. metricsToShow={metricsToShow}
  121. />
  122. <tbody>
  123. {childData.map(child => (
  124. <SummaryTableLine
  125. {...child}
  126. key={child.file}
  127. metricsToShow={metricsToShow}
  128. expandedLines={expandedLines}
  129. setExpandedLines={setExpandedLines}
  130. fileFilter={fileFilter}
  131. setFileFilter={setFileFilter}
  132. />
  133. ))}
  134. </tbody>
  135. </table>
  136. </div>
  137. <div className="layout__section center small quiet">
  138. Code coverage generated by{' '}
  139. <a
  140. href="https://istanbul.js.org/"
  141. target="_blank"
  142. rel="noopener noreferrer"
  143. >
  144. istanbul
  145. </a>{' '}
  146. at {window.generatedDatetime}
  147. </div>
  148. </div>
  149. );
  150. }
  151. ReactDOM.render(<App />, document.getElementById('app'));