useChart.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. import yaml from "js-yaml";
  2. import { useContext, useEffect, useState } from "react";
  3. import { useRouteMatch } from "react-router";
  4. import api from "shared/api";
  5. import { onlyInLeft } from "shared/array_utils";
  6. import { Context } from "shared/Context";
  7. import { useRouting } from "shared/routing";
  8. import { ChartType, ChartTypeWithExtendedConfig } from "shared/types";
  9. export const useChart = (oldChart: ChartType, closeChart: () => void) => {
  10. const { currentProject, currentCluster, setCurrentError } = useContext(
  11. Context
  12. );
  13. const [chart, setChart] = useState<ChartTypeWithExtendedConfig>(null);
  14. const { url: matchUrl } = useRouteMatch();
  15. const [status, setStatus] = useState<"ready" | "loading" | "deleting">(
  16. "loading"
  17. );
  18. const [saveStatus, setSaveStatus] = useState<
  19. "loading" | "successful" | string
  20. >("");
  21. const { pushFiltered, getQueryParam, pushQueryParams } = useRouting();
  22. useEffect(() => {
  23. const { namespace, name: chartName } = oldChart;
  24. setStatus("loading");
  25. const revision = getQueryParam("chart_revision");
  26. api
  27. .getChart<ChartTypeWithExtendedConfig>(
  28. "token",
  29. {},
  30. {
  31. id: currentProject?.id,
  32. cluster_id: currentCluster?.id,
  33. namespace,
  34. name: chartName,
  35. revision: Number(revision) ? Number(revision) : 0,
  36. }
  37. )
  38. .then((res) => {
  39. if (res?.data) {
  40. setChart(res.data);
  41. }
  42. })
  43. .finally(() => {
  44. setStatus("ready");
  45. });
  46. }, [oldChart, currentCluster, currentProject]);
  47. /**
  48. * Upgrade chart version
  49. */
  50. const upgradeChart = async () => {
  51. // convert current values to yaml
  52. let valuesYaml = yaml.dump({
  53. ...(chart.config as Object),
  54. });
  55. try {
  56. await api.upgradeChartValues(
  57. "<token>",
  58. {
  59. values: valuesYaml,
  60. version: chart.latest_version,
  61. },
  62. {
  63. id: currentProject.id,
  64. name: chart.name,
  65. namespace: chart.namespace,
  66. cluster_id: currentCluster.id,
  67. }
  68. );
  69. window.analytics?.track("Chart Upgraded", {
  70. chart: chart.name,
  71. values: valuesYaml,
  72. });
  73. } catch (err) {
  74. let parsedErr = err?.response?.data?.error;
  75. if (parsedErr) {
  76. err = parsedErr;
  77. }
  78. setCurrentError(parsedErr);
  79. window.analytics?.track("Failed to Upgrade Chart", {
  80. chart: chart.name,
  81. values: valuesYaml,
  82. error: err,
  83. });
  84. }
  85. };
  86. /**
  87. * Delete/Uninstall chart
  88. */
  89. const deleteChart = async () => {
  90. try {
  91. const syncedEnvGroups = chart.config?.container?.env?.synced || [];
  92. const removeApplicationToEnvGroupPromises = syncedEnvGroups.map(
  93. (envGroup: any) => {
  94. return api.removeApplicationFromEnvGroup(
  95. "<token>",
  96. {
  97. name: envGroup?.name,
  98. app_name: chart.name,
  99. },
  100. {
  101. project_id: currentProject.id,
  102. cluster_id: currentCluster.id,
  103. namespace: chart.namespace,
  104. }
  105. );
  106. }
  107. );
  108. try {
  109. await Promise.all(removeApplicationToEnvGroupPromises);
  110. } catch (error) {
  111. setCurrentError(
  112. "We coudln't remove the synced env group from the application, please remove it manually before uninstalling the chart, or try again."
  113. );
  114. return;
  115. }
  116. await api.uninstallTemplate(
  117. "<token>",
  118. {},
  119. {
  120. namespace: chart.namespace,
  121. name: chart.name,
  122. id: currentProject.id,
  123. cluster_id: currentCluster.id,
  124. }
  125. );
  126. setStatus("ready");
  127. closeChart();
  128. return;
  129. } catch (error) {
  130. console.log(error);
  131. throw new Error("Couldn't uninstall the chart");
  132. }
  133. };
  134. /**
  135. * Update chart values
  136. */
  137. const updateChart = async (
  138. processValues: (
  139. chart: ChartType,
  140. oldChart?: ChartType
  141. ) => { yaml: string; metadata: any }
  142. ) => {
  143. setSaveStatus("loading");
  144. const { yaml: values, metadata } = processValues(chart, oldChart);
  145. const syncEnvGroups = metadata ? metadata["container.env"] : {};
  146. const addedEnvGroups = syncEnvGroups?.added || [];
  147. const deletedEnvGroups = syncEnvGroups?.deleted || [];
  148. const addApplicationToEnvGroupPromises = addedEnvGroups.map(
  149. (envGroup: any) => {
  150. return api.addApplicationToEnvGroup(
  151. "<token>",
  152. {
  153. name: envGroup?.name,
  154. app_name: chart.name,
  155. },
  156. {
  157. project_id: currentProject.id,
  158. cluster_id: currentCluster.id,
  159. namespace: chart.namespace,
  160. }
  161. );
  162. }
  163. );
  164. try {
  165. await Promise.all(addApplicationToEnvGroupPromises);
  166. } catch (error) {
  167. setCurrentError(
  168. "We coudln't sync the env group to the application, please try again."
  169. );
  170. }
  171. const removeApplicationToEnvGroupPromises = deletedEnvGroups.map(
  172. (envGroup: any) => {
  173. return api.removeApplicationFromEnvGroup(
  174. "<token>",
  175. {
  176. name: envGroup?.name,
  177. app_name: chart.name,
  178. },
  179. {
  180. project_id: currentProject.id,
  181. cluster_id: currentCluster.id,
  182. namespace: chart.namespace,
  183. }
  184. );
  185. }
  186. );
  187. try {
  188. await Promise.all(removeApplicationToEnvGroupPromises);
  189. } catch (error) {
  190. setCurrentError(
  191. "We coudln't remove the synced env group from the application, please try again."
  192. );
  193. }
  194. try {
  195. await api.upgradeChartValues(
  196. "<token>",
  197. {
  198. values,
  199. },
  200. {
  201. id: currentProject.id,
  202. name: chart.name,
  203. namespace: chart.namespace,
  204. cluster_id: currentCluster.id,
  205. }
  206. );
  207. setSaveStatus("successful");
  208. setTimeout(() => setSaveStatus(""), 500);
  209. } catch (err) {
  210. let parsedErr = err?.response?.data?.error;
  211. if (!parsedErr) {
  212. parsedErr = err;
  213. }
  214. setCurrentError(parsedErr);
  215. setSaveStatus("Couldn't process the request.");
  216. // throw new Error(parsedErr);
  217. }
  218. };
  219. /**
  220. * Refresh the chart data
  221. */
  222. const refreshChart = async () => {
  223. try {
  224. const newChart = await api
  225. .getChart(
  226. "<token>",
  227. {},
  228. {
  229. name: chart.name,
  230. revision: 0,
  231. namespace: chart.namespace,
  232. cluster_id: currentCluster.id,
  233. id: currentProject.id,
  234. }
  235. )
  236. .then((res) => res.data);
  237. pushQueryParams({
  238. chart_version: newChart.version,
  239. });
  240. setChart(newChart);
  241. } catch (error) {}
  242. };
  243. const loadChartWithSpecificRevision = async (revision: number) => {
  244. try {
  245. const newChart = await api
  246. .getChart(
  247. "<token>",
  248. {},
  249. {
  250. name: chart.name,
  251. revision: revision,
  252. namespace: chart.namespace,
  253. cluster_id: currentCluster.id,
  254. id: currentProject.id,
  255. }
  256. )
  257. .then((res) => res.data);
  258. pushQueryParams({
  259. chart_revision: newChart.version,
  260. });
  261. setChart(newChart);
  262. } catch (error) {}
  263. };
  264. return {
  265. chart,
  266. status,
  267. saveStatus,
  268. upgradeChart,
  269. deleteChart,
  270. updateChart,
  271. refreshChart,
  272. loadChartWithSpecificRevision,
  273. };
  274. };