ExpandedStack.tsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import Loading from "components/Loading";
  2. import Placeholder from "components/Placeholder";
  3. import TabSelector from "components/TabSelector";
  4. import TitleSection from "components/TitleSection";
  5. import React, { useContext, useEffect, useState } from "react";
  6. import { useParams } from "react-router";
  7. import api from "shared/api";
  8. import { Context } from "shared/Context";
  9. import { useRouting } from "shared/routing";
  10. import { readableDate } from "shared/string_utils";
  11. import styled from "styled-components";
  12. import ChartList from "../../chart/ChartList";
  13. import SortSelector from "../../SortSelector";
  14. import Status from "../components/Status";
  15. import {
  16. Br,
  17. InfoWrapper,
  18. LastDeployed,
  19. LineBreak,
  20. SepDot,
  21. Text,
  22. } from "../components/styles";
  23. import { getStackStatus, getStackStatusMessage } from "../shared";
  24. import { FullStackRevision, Stack, StackRevision } from "../types";
  25. import RevisionList from "./_RevisionList";
  26. import SourceConfig from "./_SourceConfig";
  27. const ExpandedStack = () => {
  28. const { namespace, stack_id } = useParams<{
  29. namespace: string;
  30. stack_id: string;
  31. }>();
  32. const { pushFiltered } = useRouting();
  33. const { currentProject, currentCluster, setCurrentError } = useContext(
  34. Context
  35. );
  36. const [stack, setStack] = useState<Stack>();
  37. const [sortType, setSortType] = useState("Alphabetical");
  38. const [isLoading, setIsLoading] = useState(true);
  39. const [currentTab, setCurrentTab] = useState("apps");
  40. const [currentRevision, setCurrentRevision] = useState<FullStackRevision>();
  41. const getStack = async () => {
  42. setIsLoading(true);
  43. try {
  44. const newStack = await api
  45. .getStack<Stack>(
  46. "<token>",
  47. {},
  48. {
  49. project_id: currentProject.id,
  50. cluster_id: currentCluster.id,
  51. stack_id: stack_id,
  52. namespace,
  53. }
  54. )
  55. .then((res) => res.data);
  56. setStack(newStack);
  57. setCurrentRevision(newStack.latest_revision);
  58. setIsLoading(false);
  59. } catch (error) {
  60. setCurrentError(error);
  61. pushFiltered("/stacks", []);
  62. }
  63. };
  64. useEffect(() => {
  65. getStack();
  66. }, [stack_id]);
  67. if (isLoading) {
  68. return <Loading />;
  69. }
  70. return (
  71. <div>
  72. <TitleSection
  73. materialIconClass="material-icons-outlined"
  74. icon={"lan"}
  75. capitalize
  76. >
  77. {stack.name}
  78. </TitleSection>
  79. <RevisionList
  80. revisions={stack.revisions}
  81. currentRevision={currentRevision}
  82. latestRevision={stack.latest_revision}
  83. stackId={stack.id}
  84. stackNamespace={namespace}
  85. onRevisionClick={(revision) => setCurrentRevision(revision)}
  86. onRollback={() => getStack()}
  87. ></RevisionList>
  88. <Br />
  89. <InfoWrapper>
  90. <LastDeployed>
  91. <Status
  92. status={getStackStatus(stack)}
  93. message={getStackStatusMessage(stack)}
  94. />
  95. <SepDot>•</SepDot>
  96. <Text color="#aaaabb">
  97. {!stack.latest_revision?.id
  98. ? `No version found`
  99. : `v${stack.latest_revision.id}`}
  100. </Text>
  101. <SepDot>•</SepDot>
  102. Last updated {readableDate(stack.updated_at)}
  103. </LastDeployed>
  104. </InfoWrapper>
  105. {/* Stack error message */}
  106. {stack.latest_revision &&
  107. stack.latest_revision.status === "failed" &&
  108. stack.latest_revision.message?.length > 0 ? (
  109. <StackErrorMessageStyles.Wrapper>
  110. <StackErrorMessageStyles.Title color="#b7b7c9">
  111. Error reason:
  112. </StackErrorMessageStyles.Title>
  113. <StackErrorMessageStyles.Text color="#aaaabb">
  114. {stack.latest_revision.message}
  115. </StackErrorMessageStyles.Text>
  116. </StackErrorMessageStyles.Wrapper>
  117. ) : null}
  118. <TabSelector
  119. currentTab={currentTab}
  120. options={[
  121. {
  122. label: "Apps",
  123. value: "apps",
  124. component: (
  125. <>
  126. <Gap></Gap>
  127. {currentRevision.id !== stack.latest_revision.id ? (
  128. <ChartListWrapper>
  129. <Placeholder>
  130. Not available when previewing versions
  131. </Placeholder>
  132. </ChartListWrapper>
  133. ) : (
  134. <>
  135. <SortSelector
  136. setSortType={setSortType}
  137. sortType={sortType}
  138. currentView="stacks"
  139. />
  140. <ChartListWrapper>
  141. <ChartList
  142. currentCluster={currentCluster}
  143. currentView="stacks"
  144. namespace={namespace}
  145. sortType="Alphabetical"
  146. appFilters={
  147. stack?.latest_revision?.resources?.map(
  148. (res) => res.name
  149. ) || []
  150. }
  151. closeChartRedirectUrl={`${window.location.pathname}${window.location.search}`}
  152. />
  153. </ChartListWrapper>
  154. </>
  155. )}
  156. </>
  157. ),
  158. },
  159. {
  160. label: "Source Config",
  161. value: "source_config",
  162. component: (
  163. <>
  164. <SourceConfig revision={currentRevision}></SourceConfig>
  165. </>
  166. ),
  167. },
  168. ]}
  169. setCurrentTab={(tab) => {
  170. setCurrentTab(tab);
  171. }}
  172. ></TabSelector>
  173. </div>
  174. );
  175. };
  176. export default ExpandedStack;
  177. const ChartListWrapper = styled.div`
  178. width: 100%;
  179. margin: auto;
  180. margin-top: 20px;
  181. padding-bottom: 125px;
  182. `;
  183. const Gap = styled.div`
  184. width: 100%;
  185. background: none;
  186. height: 30px;
  187. `;
  188. const StackErrorMessageStyles = {
  189. Text: styled(Text)`
  190. font-size: 14px;
  191. margin-bottom: 10px;
  192. `,
  193. Wrapper: styled.div`
  194. display: flex;
  195. flex-direction: column;
  196. margin-top: 5px;
  197. `,
  198. Title: styled(Text)`
  199. font-size: 16px;
  200. font-weight: bold;
  201. `,
  202. };