StatusSection.tsx 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. import React, { useContext, useEffect, useState } from "react";
  2. import styled from "styled-components";
  3. import api from "shared/api";
  4. import { Context } from "shared/Context";
  5. import { ChartType } from "shared/types";
  6. import Loading from "components/Loading";
  7. import Logs from "./Logs";
  8. import ControllerTab from "./ControllerTab";
  9. type Props = {
  10. selectors?: string[];
  11. currentChart: ChartType;
  12. fullscreen?: boolean;
  13. setFullScreenLogs?: any;
  14. };
  15. const StatusSectionFC: React.FunctionComponent<Props> = ({
  16. currentChart,
  17. fullscreen,
  18. setFullScreenLogs,
  19. selectors,
  20. }) => {
  21. const [selectedPod, setSelectedPod] = useState<any>({});
  22. const [controllers, setControllers] = useState<any[]>([]);
  23. const [isLoading, setIsLoading] = useState<boolean>(true);
  24. const [podError, setPodError] = useState<string>("");
  25. const { currentProject, currentCluster, setCurrentError } = useContext(
  26. Context
  27. );
  28. useEffect(() => {
  29. let isSubscribed = true;
  30. api
  31. .getChartControllers(
  32. "<token>",
  33. {},
  34. {
  35. namespace: currentChart.namespace,
  36. cluster_id: currentCluster.id,
  37. id: currentProject.id,
  38. name: currentChart.name,
  39. revision: currentChart.version,
  40. }
  41. )
  42. .then((res: any) => {
  43. if (!isSubscribed) {
  44. return;
  45. }
  46. let controllers =
  47. currentChart.chart.metadata.name == "job"
  48. ? res.data[0]?.status.active
  49. : res.data;
  50. setControllers(controllers);
  51. setIsLoading(false);
  52. })
  53. .catch((err) => {
  54. if (!isSubscribed) {
  55. return;
  56. }
  57. setCurrentError(JSON.stringify(err));
  58. setControllers([]);
  59. setIsLoading(false);
  60. });
  61. return () => {
  62. isSubscribed = false;
  63. };
  64. }, [currentProject, currentCluster, setCurrentError, currentChart]);
  65. const renderLogs = () => {
  66. return (
  67. <Logs
  68. podError={podError}
  69. key={selectedPod?.metadata?.name}
  70. selectedPod={selectedPod}
  71. />
  72. );
  73. };
  74. const renderTabs = () => {
  75. return controllers.map((c, i) => {
  76. return (
  77. <ControllerTab
  78. // handle CronJob case
  79. key={c.metadata?.uid || c.uid}
  80. selectedPod={selectedPod}
  81. selectPod={setSelectedPod}
  82. selectors={selectors ? [selectors[i]] : null}
  83. controller={c}
  84. isLast={i === controllers?.length - 1}
  85. isFirst={i === 0}
  86. setPodError={(x: string) => setPodError(x)}
  87. />
  88. );
  89. });
  90. };
  91. const renderStatusSection = () => {
  92. if (isLoading) {
  93. return (
  94. <NoControllers>
  95. <Loading />
  96. </NoControllers>
  97. );
  98. }
  99. if (controllers?.length > 0) {
  100. return (
  101. <Wrapper>
  102. <TabWrapper>{renderTabs()}</TabWrapper>
  103. {renderLogs()}
  104. </Wrapper>
  105. );
  106. }
  107. if (currentChart?.chart?.metadata?.name === "job") {
  108. return (
  109. <NoControllers>
  110. <i className="material-icons">category</i>
  111. There are no jobs currently running.
  112. </NoControllers>
  113. );
  114. }
  115. return (
  116. <NoControllers>
  117. <i className="material-icons">category</i>
  118. No objects to display. This might happen while your app is still
  119. deploying.
  120. </NoControllers>
  121. );
  122. };
  123. return (
  124. <>
  125. {fullscreen ? (
  126. <FullScreen>
  127. <AbsoluteTitle>
  128. <BackButton onClick={setFullScreenLogs}>
  129. <i className="material-icons">navigate_before</i>
  130. </BackButton>
  131. Status ({currentChart.name})
  132. </AbsoluteTitle>
  133. <FullScreenButton top="70px" onClick={setFullScreenLogs}>
  134. <i className="material-icons">close_fullscreen</i>
  135. </FullScreenButton>
  136. {renderStatusSection()}
  137. </FullScreen>
  138. ) : (
  139. <StyledStatusSection>
  140. <FullScreenButton onClick={setFullScreenLogs}>
  141. <i className="material-icons">open_in_full</i>
  142. </FullScreenButton>
  143. {renderStatusSection()}
  144. </StyledStatusSection>
  145. )}
  146. </>
  147. );
  148. };
  149. export default StatusSectionFC;
  150. const FullScreenButton = styled.div<{ top?: string }>`
  151. position: absolute;
  152. top: ${(props) => props.top || "10px"};
  153. right: 10px;
  154. width: 24px;
  155. height: 24px;
  156. cursor: pointer;
  157. display: flex;
  158. justify-content: center;
  159. align-items: center;
  160. border-radius: 5px;
  161. background: #ffffff11;
  162. border: 1px solid #aaaabb;
  163. :hover {
  164. background: #ffffff22;
  165. }
  166. > i {
  167. font-size: 14px;
  168. }
  169. `;
  170. const BackButton = styled.div`
  171. display: flex;
  172. width: 30px;
  173. z-index: 999;
  174. cursor: pointer;
  175. height: 30px;
  176. align-items: center;
  177. margin-right: 15px;
  178. justify-content: center;
  179. cursor: pointer;
  180. border: 1px solid #ffffff55;
  181. border-radius: 100px;
  182. background: #ffffff11;
  183. > i {
  184. font-size: 18px;
  185. }
  186. :hover {
  187. background: #ffffff22;
  188. > img {
  189. opacity: 1;
  190. }
  191. }
  192. `;
  193. const AbsoluteTitle = styled.div`
  194. position: absolute;
  195. top: 0px;
  196. left: 0px;
  197. width: 100%;
  198. height: 60px;
  199. display: flex;
  200. align-items: center;
  201. padding-left: 20px;
  202. font-size: 18px;
  203. font-weight: 500;
  204. user-select: text;
  205. `;
  206. const TabWrapper = styled.div`
  207. width: 35%;
  208. min-width: 250px;
  209. height: 100%;
  210. overflow-y: auto;
  211. `;
  212. const StyledStatusSection = styled.div`
  213. padding: 0px;
  214. user-select: text;
  215. overflow: hidden;
  216. width: 100%;
  217. min-height: 400px;
  218. height: calc(100vh - 400px);
  219. font-size: 13px;
  220. overflow: hidden;
  221. border-radius: 8px;
  222. animation: floatIn 0.3s;
  223. animation-timing-function: ease-out;
  224. animation-fill-mode: forwards;
  225. @keyframes floatIn {
  226. from {
  227. opacity: 0;
  228. transform: translateY(10px);
  229. }
  230. to {
  231. opacity: 1;
  232. transform: translateY(0px);
  233. }
  234. }
  235. `;
  236. const FullScreen = styled.div`
  237. position: absolute;
  238. top: 0;
  239. left: 0;
  240. width: 100%;
  241. height: 100%;
  242. padding-top: 60px;
  243. `;
  244. const Wrapper = styled.div`
  245. width: 100%;
  246. height: 100%;
  247. display: flex;
  248. `;
  249. const NoControllers = styled.div`
  250. padding-top: 20%;
  251. position: relative;
  252. width: 100%;
  253. display: flex;
  254. justify-content: center;
  255. align-items: center;
  256. color: #ffffff44;
  257. font-size: 14px;
  258. > i {
  259. font-size: 18px;
  260. margin-right: 12px;
  261. }
  262. `;