Jelajahi Sumber

first half of deletions (#4669)

ianedwards 2 tahun lalu
induk
melakukan
b3bb5cbd93
49 mengubah file dengan 0 tambahan dan 4745 penghapusan
  1. 0 185
      dashboard/legacy/main/home/cluster-dashboard/DashboardRouter.tsx
  2. 0 24
      dashboard/src/assets/GithubIcon.tsx
  3. 0 15
      dashboard/src/assets/code-branch-icon.tsx
  4. 0 35
      dashboard/src/assets/command-line-icon.tsx
  5. 0 126
      dashboard/src/components/CheckboxList.tsx
  6. 0 157
      dashboard/src/components/Dropdown.tsx
  7. 0 0
      dashboard/src/components/Helper.tsx
  8. 0 45
      dashboard/src/components/InfoTooltip.tsx
  9. 0 0
      dashboard/src/components/LineGraph.tsx
  10. 0 54
      dashboard/src/components/NoClusterPlaceHolder.tsx
  11. 0 97
      dashboard/src/components/OptionsDropdown.tsx
  12. 0 188
      dashboard/src/components/PageNotFound.tsx
  13. 0 257
      dashboard/src/components/RadioFilter.tsx
  14. 0 247
      dashboard/src/components/SearchSelector.tsx
  15. 0 130
      dashboard/src/components/StatusIndicator.tsx
  16. 0 86
      dashboard/src/components/StatusSection.tsx
  17. 0 101
      dashboard/src/components/Table.tsx
  18. 0 117
      dashboard/src/components/TitleSectionStacks.tsx
  19. 0 70
      dashboard/src/components/TooltipParent.tsx
  20. 0 113
      dashboard/src/components/porter/ConfirmOverlay.tsx
  21. 0 123
      dashboard/src/legacy/assets/GoogleIcon.tsx
  22. 0 15
      dashboard/src/legacy/assets/code-branch-icon.tsx
  23. 0 126
      dashboard/src/legacy/components/CheckboxList.tsx
  24. 0 0
      dashboard/src/legacy/components/Helper.tsx
  25. 0 45
      dashboard/src/legacy/components/InfoTooltip.tsx
  26. 0 0
      dashboard/src/legacy/components/LineGraph.tsx
  27. 0 201
      dashboard/src/legacy/components/MultiSelectFilter.tsx
  28. 0 187
      dashboard/src/legacy/components/PageNotFound.tsx
  29. 0 117
      dashboard/src/legacy/components/TitleSectionStacks.tsx
  30. 0 70
      dashboard/src/legacy/components/TooltipParent.tsx
  31. 0 59
      dashboard/src/legacy/components/UnauthorizedPage.tsx
  32. 0 244
      dashboard/src/legacy/main/CurrentError.tsx
  33. 0 94
      dashboard/src/legacy/main/Main.tsx
  34. 0 39
      dashboard/src/legacy/main/MainWrapper.tsx
  35. 0 265
      dashboard/src/legacy/shared/Context.tsx
  36. 0 153
      dashboard/src/legacy/shared/DeploymentTargetContext.tsx
  37. 0 134
      dashboard/src/legacy/shared/ansiparser.tsx
  38. 0 1
      dashboard/src/legacy/shared/regex.tsx
  39. 0 17
      dashboard/src/legacy/utils/ip.ts
  40. 0 134
      dashboard/src/shared/ansiparser.tsx
  41. 0 10
      dashboard/src/shared/array_utils.ts
  42. 0 326
      dashboard/src/shared/hooks/useChart.ts
  43. 0 34
      dashboard/src/shared/hooks/useEffectDebugger.ts
  44. 0 103
      dashboard/src/shared/hooks/usePagination.ts
  45. 0 143
      dashboard/src/shared/hooks/usePods.ts
  46. 0 9
      dashboard/src/shared/hooks/usePrevious.ts
  47. 0 24
      dashboard/src/shared/icons/MoonBase.tsx
  48. 0 7
      dashboard/src/shared/release/utils.ts
  49. 0 18
      dashboard/src/shared/themes/opal.ts

+ 0 - 185
dashboard/legacy/main/home/cluster-dashboard/DashboardRouter.tsx

@@ -1,185 +0,0 @@
-import React, { useContext, useEffect, useState } from "react";
-import loadable from "@loadable/component";
-import { RouteComponentProps, withRouter } from "react-router";
-import { Route, Switch } from "react-router-dom";
-import styled from "styled-components";
-
-import Loading from "components/Loading";
-
-import api from "shared/api";
-import { withAuth, WithAuthProps } from "shared/auth/AuthorizationHoc";
-import GuardedRoute from "shared/auth/RouteGuard";
-import { Context } from "shared/Context";
-import { getQueryParam, PorterUrl, pushQueryParams } from "shared/routing";
-import { ClusterType } from "shared/types";
-
-import AppDashboard from "./apps/AppDashboard.ts";
-import DashboardRoutes from "./dashboard/Routes.ts";
-import EnvGroupDashboard from "./env-groups/EnvGroupDashboard.ts";
-import ExpandedEnvGroupDashboard from "./env-groups/ExpandedEnvGroupDashboard.ts";
-import ExpandedChartWrapper from "./expanded-chart/ExpandedChartWrapper.ts";
-import JobDashboard from "./jobs/JobDashboard.ts";
-
-const LazyPreviewEnvironmentsRoutes = loadable(
-  // @ts-ignore
-  () => import("./preview-environments/routes.tsx"),
-  {
-    fallback: <Loading />,
-  }
-);
-
-const LazyStackRoutes = loadable(
-  // @ts-ignore
-  () => import("./stacks/routes.tsx"),
-  {
-    fallback: <Loading />,
-  }
-);
-
-type Props = RouteComponentProps &
-  WithAuthProps & {
-    currentCluster: ClusterType;
-    setSidebar: (x: boolean) => void;
-    currentView: PorterUrl;
-  };
-
-// TODO: should try to maintain single source of truth b/w router and context/state (ex: namespace -> being managed in parallel right now so highly inextensible and routing is fragile)
-const DashboardRouter: React.FC<Props> = ({
-  setSidebar,
-  currentView,
-  ...props
-}) => {
-  const { currentProject, currentCluster } = useContext(Context);
-  const [namespace, setNamespace] = useState(null);
-  const [sortType, setSortType] = useState(
-    localStorage.getItem("SortType") || "Newest"
-  );
-  const [currentChart, setCurrentChart] = useState(null);
-  const [isMetricsInstalled, setIsMetricsInstalled] = useState(false);
-
-  useEffect(() => {
-    // Don't add cluster as query param if present in path
-    const { cluster } = props.match?.params as any;
-    if (!cluster) {
-      pushQueryParams(props, { cluster: currentCluster.name });
-    }
-    api
-      .getPrometheusIsInstalled(
-        "<token>",
-        {},
-        {
-          id: currentProject.id,
-          cluster_id: currentCluster.id,
-        }
-      )
-      .then((res) => {
-        setIsMetricsInstalled(true);
-      })
-      .catch(() => {
-        setIsMetricsInstalled(false);
-      });
-  }, []);
-
-  // Reset namespace filter and close expanded chart on cluster change
-  useEffect(() => {
-    let namespace = "default";
-    let localStorageNamespace = localStorage.getItem(
-      `${currentProject.id}-${currentCluster.id}-namespace`
-    );
-    if (localStorageNamespace) {
-      namespace = localStorageNamespace;
-    }
-    setNamespace(namespace);
-    setSortType(localStorage.getItem("SortType") || "Newest");
-    setCurrentChart(null);
-
-    // ret2
-    pushQueryParams(props, { namespace });
-  }, [currentCluster]);
-
-  useEffect(() => {
-    let { currentNamespace } =
-      currentProject?.simplified_view_enabled &&
-      currentProject?.capi_provisioner_enabled
-        ? "porter-env-group"
-        : (props.match?.params as any);
-    if (!currentNamespace) {
-      currentNamespace =
-        currentProject?.simplified_view_enabled &&
-        currentProject?.capi_provisioner_enabled
-          ? "porter-env-group"
-          : getQueryParam(props, "namespace");
-    }
-    setSortType("Newest");
-    setCurrentChart(null);
-    setNamespace(currentNamespace || "default");
-    pushQueryParams(props, { namespace: currentNamespace || "default" });
-  }, [currentView]);
-
-  return (
-    <Switch>
-      <Route path={"/stacks"}>
-        <LazyStackRoutes />
-      </Route>
-      <Route path={"/preview-environments"}>
-        <LazyPreviewEnvironmentsRoutes />
-      </Route>
-      <Route path="/:baseRoute/:clusterName+/:namespace/:chartName">
-        <ExpandedChartWrapper
-          setSidebar={setSidebar}
-          isMetricsInstalled={isMetricsInstalled}
-        />
-      </Route>
-      <GuardedRoute
-        path={"/applications"}
-        scope="application"
-        resource=""
-        verb={["get", "list"]}
-      >
-        <AppDashboard
-          currentView={currentView}
-          namespace={namespace}
-          setNamespace={setNamespace}
-          sortType={sortType}
-          setSortType={setSortType}
-        />
-      </GuardedRoute>
-      <GuardedRoute
-        path={"/jobs"}
-        scope="job"
-        resource=""
-        verb={["get", "list"]}
-      >
-        <JobDashboard
-          currentView={currentView}
-          namespace={namespace}
-          setNamespace={setNamespace}
-          sortType={sortType}
-        />
-      </GuardedRoute>
-      <GuardedRoute
-        path={"/env-groups/:name"}
-        scope="env_group"
-        resource=""
-        verb={["get", "list"]}
-      >
-        <ExpandedEnvGroupDashboard currentCluster={currentCluster} />
-      </GuardedRoute>
-      <GuardedRoute
-        path={"/env-groups"}
-        scope="env_group"
-        resource=""
-        verb={["get", "list"]}
-      >
-        <EnvGroupDashboard currentCluster={currentCluster} />
-      </GuardedRoute>
-      <Route path={["/cluster-dashboard"]}>
-        <DashboardRoutes />
-      </Route>
-    </Switch>
-  );
-};
-
-export default withRouter(withAuth(DashboardRouter));
-
-const StyledTemplateComponent = styled.div``;

+ 0 - 24
dashboard/src/assets/GithubIcon.tsx

@@ -1,24 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {};
-
-type StateType = {};
-
-export default class GHIcon extends Component<PropsType, StateType> {
-  render() {
-    return (
-      <Svg height="18" width="18" viewBox="0 0 16 16">
-        <path
-          fillRule="evenodd"
-          d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
-        />
-      </Svg>
-    );
-  }
-}
-
-const Svg = styled.svg`
-  fill: white;
-  margin-right: 6px;
-`;

+ 0 - 15
dashboard/src/assets/code-branch-icon.tsx

@@ -1,15 +0,0 @@
-import React, { SVGProps } from "react";
-
-function Icon(props: SVGProps<SVGElement>) {
-  return (
-    <svg
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 448 512"
-      className={props.className}
-    >
-      <path d="M160 80c0 32.8-19.7 60.1-48 73.3v87.8c18.8-10.9 40.7-17.1 64-17.1h96c35.3 0 64-28.7 64-64v-6.7c-28.3-13.2-48-40.5-48-73.3 0-44.18 35.8-80 80-80s80 35.82 80 80c0 32.8-19.7 60.1-48 73.3v6.7c0 70.7-57.3 128-128 128h-96c-35.3 0-64 28.7-64 64v6.7c28.3 12.3 48 40.5 48 73.3 0 44.2-35.8 80-80 80-44.18 0-80-35.8-80-80 0-32.8 19.75-61 48-73.3V153.3C19.75 140.1 0 112.8 0 80 0 35.82 35.82 0 80 0c44.2 0 80 35.82 80 80zm-80 24c13.25 0 24-10.75 24-24S93.25 56 80 56 56 66.75 56 80s10.75 24 24 24zm288-48c-13.3 0-24 10.75-24 24s10.7 24 24 24 24-10.75 24-24-10.7-24-24-24zM80 456c13.25 0 24-10.7 24-24s-10.75-24-24-24-24 10.7-24 24 10.75 24 24 24z"></path>
-    </svg>
-  );
-}
-
-export default Icon;

+ 0 - 35
dashboard/src/assets/command-line-icon.tsx

@@ -1,35 +0,0 @@
-import React, { SVGProps } from "react";
-import styled from "styled-components";
-
-function CommandLineIcon(props: SVGProps<SVGElement>) {
-  return (
-    <svg
-      xmlns="http://www.w3.org/2000/svg"
-      x="0"
-      y="0"
-      version="1.1"
-      viewBox="0 0 24 24"
-      xmlSpace="preserve"
-      className={props.className}
-      onClick={props.onClick}
-    >
-      <linearGradient
-        x1="825.344"
-        x2="825.344"
-        y1="-528.502"
-        y2="-529.502"
-        gradientUnits="userSpaceOnUse"
-      >
-        <stop offset="0" stopColor="#656565"></stop>
-        <stop offset="0.618" stopColor="#1b1b1b"></stop>
-        <stop offset="0.629" stopColor="#545454"></stop>
-        <stop offset="0.983" stopColor="#3e3e3e"></stop>
-      </linearGradient>
-      <path d="M3.2 17.3L2 15.9c-.2-.2-.2-.6.1-.7l5.4-4.5c.3-.2.3-.6 0-.8L2 5.4c-.2-.2-.2-.5 0-.8l1.2-1.5c.2-.1.5-.2.7 0l7.6 6.3c.5.4.5 1.3 0 1.7l-7.6 6.3c-.2.2-.5.2-.7-.1zM21.6 21H9.4c-.3 0-.6-.2-.6-.5v-1.9c0-.3.2-.5.6-.5h12.2c.3 0 .6.2.6.5v1.9c-.1.3-.3.5-.6.5z"></path>
-    </svg>
-  );
-}
-
-export default CommandLineIcon;
-
-const SVG = styled.svg``;

+ 0 - 126
dashboard/src/components/CheckboxList.tsx

@@ -1,126 +0,0 @@
-import React, { useEffect } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  label?: string;
-  options: { disabled?: boolean; value: any; label: string }[];
-  selected: { value: any; label: string }[];
-  setSelected: (x: { value: any; label: string }[]) => void;
-};
-
-const arraysEqual = (a: any, b: any) => {
-  if (a === b) return true;
-  if (a == null || b == null) return false;
-  if (a.length !== b.length) return false;
-
-  // If you don't care about the order of the elements inside
-  // the array, you should sort both arrays here.
-  // Please note that calling sort on an array will modify that array.
-  // you might want to clone your array first.
-
-  for (var i = 0; i < a.length; ++i) {
-    if (a[i] !== b[i]) return false;
-  }
-  return true;
-};
-
-const CheckboxList = ({ label, options, selected, setSelected }: PropsType) => {
-  let onSelectOption = (option: { value: any; label: string }) => {
-    const tmp = [...selected];
-    if (
-      tmp.filter(
-        (e) => e.value === option.value || arraysEqual(e.value, option.value)
-      ).length === 0
-    ) {
-      setSelected([...tmp, option]);
-    } else {
-      tmp.forEach((x, i) => {
-        if (x.value === option.value || arraysEqual(x.value, option.value)) {
-          tmp.splice(i, 1);
-        }
-      });
-      setSelected(tmp);
-    }
-  };
-
-  return (
-    <StyledCheckboxList>
-      {label && <Label>{label}</Label>}
-      {options.map((option: { value: any; label: string }, i: number) => {
-        return (
-          <CheckboxOption
-            isLast={i === options.length - 1}
-            onClick={() => onSelectOption(option)}
-            key={i}
-          >
-            <Checkbox
-              checked={
-                selected.filter(
-                  (e) =>
-                    e.value === option.value ||
-                    arraysEqual(e.value, option.value)
-                ).length > 0
-              }
-            >
-              <i className="material-icons">done</i>
-            </Checkbox>
-            <Text>{option.label}</Text>
-          </CheckboxOption>
-        );
-      })}
-    </StyledCheckboxList>
-  );
-};
-export default CheckboxList;
-
-const Text = styled.div`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  word-break: anywhere;
-  margin-right: 10px;
-`;
-
-const Checkbox = styled.div`
-  width: 14px;
-  height: 14px;
-  min-width: 14px;
-  border: 1px solid #ffffff55;
-  margin: 1px 10px 0px 1px;
-  border-radius: 3px;
-  background: ${(props: { checked: boolean }) =>
-    props.checked ? "#ffffff22" : "#ffffff11"};
-  display: flex;
-  align-items: center;
-  justify-content: center;
-
-  > i {
-    font-size: 12px;
-    padding-left: 0px;
-    display: ${(props: { checked: boolean }) => (props.checked ? "" : "none")};
-  }
-`;
-
-const CheckboxOption = styled.div<{ isLast: boolean }>`
-  width: 100%;
-  height: 35px;
-  padding-left: 10px;
-  display: flex;
-  cursor: pointer;
-  align-items: center;
-  font-size: 13px;
-
-  :hover {
-    background: #ffffff18;
-  }
-`;
-
-const Label = styled.div`
-  color: #ffffff;
-  margin-bottom: 10px;
-`;
-
-const StyledCheckboxList = styled.div`
-  border-radius: 3px;
-  padding: 0;
-`;

+ 0 - 157
dashboard/src/components/Dropdown.tsx

@@ -1,157 +0,0 @@
-import React, { useState } from "react";
-import styled from "styled-components";
-
-type Option = {
-  value: unknown;
-  label: string;
-};
-
-type DropdownProps = {
-  options: Array<Option>;
-  selectedOption: Option;
-  onSelect?: (selectedOption: Option) => unknown;
-  selectLabel?: (currentLabel: string) => void;
-  selectValue?: (currentValue: any) => void;
-};
-
-const Dropdown: React.FunctionComponent<DropdownProps> = ({
-  options,
-  selectedOption,
-  selectLabel,
-  selectValue,
-  onSelect,
-}) => {
-  const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
-
-  const handleSelectOption = (option: Option) => {
-    if (selectedOption.label === option.label) {
-      return;
-    }
-    onSelect(option);
-    typeof selectLabel === "function" && selectLabel(option.label);
-    typeof selectValue === "function" && selectValue(option.value);
-  };
-
-  const renderDropdown = () => {
-    if (isDropdownExpanded) {
-      return (
-        <>
-          <DropdownOverlay onClick={() => setIsDropdownExpanded(false)} />
-          <OptionWrapper
-            dropdownWidth="230px"
-            dropdownMaxHeight="200px"
-            onClick={() => setIsDropdownExpanded(false)}
-          >
-            {renderOptionList()}
-          </OptionWrapper>
-        </>
-      );
-    }
-  };
-
-  const renderOptionList = () => {
-    return options.map((option, i, originalArray) => {
-      return (
-        <Option
-          key={i}
-          selected={option.label === selectedOption.label}
-          onClick={() => handleSelectOption(option)}
-          lastItem={i === originalArray.length - 1}
-        >
-          {option.label}
-        </Option>
-      );
-    });
-  };
-
-  return (
-    <DropdownSelector
-      onClick={() => setIsDropdownExpanded(!isDropdownExpanded)}
-    >
-      <DropdownLabel>{selectedOption?.label}</DropdownLabel>
-      <i className="material-icons">arrow_drop_down</i>
-      {renderDropdown()}
-    </DropdownSelector>
-  );
-};
-
-export default Dropdown;
-
-const DropdownSelector = styled.div`
-  font-size: 13px;
-  font-weight: 500;
-  position: relative;
-  color: #ffffff;
-  display: flex;
-  align-items: center;
-  cursor: pointer;
-  border-radius: 5px;
-  :hover {
-    > i {
-      background: #ffffff22;
-    }
-  }
-
-  > i {
-    border-radius: 20px;
-    font-size: 20px;
-    margin-left: 10px;
-  }
-`;
-
-const DropdownLabel = styled.div`
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  overflow: hidden;
-  max-width: 200px;
-`;
-
-const DropdownOverlay = styled.div`
-  position: fixed;
-  width: 100%;
-  height: 100%;
-  z-index: 10;
-  left: 0px;
-  top: 0px;
-  cursor: default;
-`;
-
-const OptionWrapper = styled.div`
-  position: absolute;
-  left: 0;
-  top: calc(100% + 10px);
-  background: #26282f;
-  width: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
-    props.dropdownWidth};
-  max-height: ${(props: { dropdownWidth: string; dropdownMaxHeight: string }) =>
-    props.dropdownMaxHeight || "300px"};
-  border-radius: 3px;
-  z-index: 999;
-  overflow-y: auto;
-  margin-bottom: 20px;
-  box-shadow: 0px 4px 10px 0px #00000088;
-`;
-
-const Option = styled.div`
-  width: 100%;
-  border-top: 1px solid #00000000;
-  border-bottom: 1px solid
-    ${(props: { selected: boolean; lastItem: boolean }) =>
-      props.lastItem ? "#ffffff00" : "#ffffff15"};
-  height: 37px;
-  font-size: 13px;
-  padding-top: 9px;
-  align-items: center;
-  padding-left: 15px;
-  cursor: pointer;
-  padding-right: 10px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  background: ${(props: { selected: boolean; lastItem: boolean }) =>
-    props.selected ? "#ffffff11" : ""};
-
-  :hover {
-    background: #ffffff22;
-  }
-`;

+ 0 - 0
dashboard/src/components/Helper.tsx


+ 0 - 45
dashboard/src/components/InfoTooltip.tsx

@@ -1,45 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  text: string;
-};
-
-type StateType = {
-  showTooltip: boolean;
-};
-
-export default class InfoTooltip extends Component<PropsType, StateType> {
-  state = {
-    showTooltip: false,
-  };
-
-  render() {
-    return (
-      <StyledInfoTooltip>
-        <i className="material-icons">help_outline</i>
-      </StyledInfoTooltip>
-    );
-  }
-}
-
-const StyledInfoTooltip = styled.div`
-  display: inline-block;
-  position: relative;
-  width: 26px;
-  margin-right: 2px;
-
-  > i {
-    display: flex;
-    align-items: center;
-    position: absolute;
-    top: -14px;
-    font-size: 18px;
-    right: -1px;
-    color: #858faaaa;
-    cursor: pointer;
-    :hover {
-      color: #aaaabb;
-    }
-  }
-`;

+ 0 - 0
dashboard/src/components/LineGraph.tsx


+ 0 - 54
dashboard/src/components/NoClusterPlaceHolder.tsx

@@ -1,54 +0,0 @@
-import React, { useEffect, useState, useContext } from "react";
-import styled from "styled-components";
-import { RouteComponentProps, withRouter } from "react-router";
-import { pushFiltered } from "shared/routing";
-
-import loading from "assets/loading.gif";
-
-import { Context } from "shared/Context";
-import Heading from "components/form-components/Heading";
-import Helper from "components/form-components/Helper";
-import Text from "./porter/Text";
-import Spacer from "./porter/Spacer";
-
-type Props = {};
-
-const NoClusterPlaceholder: React.FC<RouteComponentProps> = (props) => {
-  const { currentCluster } = useContext(Context);
-
-  return (
-    <ClusterPlaceholder>
-      <Text size={16}>No Cluster Provisioned</Text>
-      <Spacer height="15px" />
-      <Text color="helper">Finish provisioning a cluster to continue</Text>
-    </ClusterPlaceholder>
-  );
-};
-
-export default withRouter(NoClusterPlaceholder);
-
-const Link = styled.a`
-  text-decoration: underline;
-  position: relative;
-  cursor: pointer;
-  > i {
-    color: #aaaabb;
-    font-size: 15px;
-    position: absolute;
-    right: -17px;
-    top: 1px;
-  }
-`;
-
-const Img = styled.img`
-  height: 15px;
-  margin-right: 15px;
-`;
-
-const ClusterPlaceholder = styled.div`
-  padding: 25px;
-  border-radius: 5px;
-  background: ${(props) => props.theme.fg};
-  border: 1px solid #494b4f;
-  padding-bottom: 35px;
-`;

+ 0 - 97
dashboard/src/components/OptionsDropdown.tsx

@@ -1,97 +0,0 @@
-import React, { useState } from "react";
-import styled from "styled-components";
-
-export const OptionsDropdown: React.FC<{
-  expandIcon?: string;
-  shrinkIcon?: string;
-}> = ({ children, expandIcon = "expand_more", shrinkIcon = "expand_less" }) => {
-  const [isOpen, setIsOpen] = useState(false);
-
-  const handleClick = (e: any) => {
-    e.stopPropagation();
-    e.preventDefault();
-    setIsOpen(!isOpen);
-  };
-
-  const handleOnBlur = () => {
-    setIsOpen(false);
-  };
-
-  return (
-    <OptionsButton onClick={handleClick} onBlur={handleOnBlur}>
-      <i className="material-icons">{isOpen ? shrinkIcon : expandIcon}</i>
-      {isOpen && <DropdownMenu>{children}</DropdownMenu>}
-    </OptionsButton>
-  );
-};
-
-const OptionsButton = styled.button`
-  position: relative;
-  border: none;
-  background: none;
-  color: white;
-  padding: 5px;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  border-radius: 50%;
-  color: #ffffff44;
-  :hover {
-    background: #32343a;
-    cursor: pointer;
-  }
-
-  > i {
-    font-size: 20px;
-  }
-`;
-
-const DropdownMenu = styled.div`
-  position: absolute;
-  right: 12px;
-  top: 30px;
-  overflow: hidden;
-  width: 120px;
-  height: auto;
-  background: #26282f;
-  box-shadow: 0 8px 20px 0px #00000088;
-  color: white;
-  overflow: hidden;
-  border-radius: 5px;
-`;
-
-const DropdownOption = styled.div`
-  width: 100%;
-  height: 37px;
-  font-size: 13px;
-  cursor: pointer;
-  padding-left: 10px;
-  padding-right: 10px;
-  font-weight: 500;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  :hover {
-    background: #ffffff22;
-  }
-  :not(:first-child) {
-    border-top: 1px solid #00000000;
-  }
-
-  :not(:last-child) {
-    border-bottom: 1px solid #ffffff15;
-  }
-
-  > i {
-    margin-right: 7px;
-    font-size: 16px;
-  }
-`;
-
-export default {
-  Dropdown: OptionsDropdown,
-  Option: DropdownOption,
-};

+ 0 - 188
dashboard/src/components/PageNotFound.tsx

@@ -1,188 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-import { RouteComponentProps, withRouter } from "react-router";
-
-import { pushFiltered } from "shared/routing";
-
-type PropsType = RouteComponentProps & {};
-
-type StateType = {};
-
-class PageNotFound extends Component<PropsType, StateType> {
-  state = {};
-
-  render() {
-    let { pathname } = this.props.location;
-    let params = this.props.match.params as any;
-    let { baseRoute } = params;
-    if (baseRoute === "applications") {
-      return (
-        <StyledPageNotFound>
-          <Mega>
-            404
-            <Inside>Application Not Found</Inside>
-          </Mega>
-          <Flex>
-            <BackButton
-              width="140px"
-              onClick={() =>
-                pushFiltered(this.props, "/applications", ["project_id"])
-              }
-            >
-              <i className="material-icons">arrow_back</i>
-              Applications
-            </BackButton>
-            {pathname && (
-              <>
-                <Splitter>|</Splitter>
-                <Helper>Could not find "{pathname}"</Helper>
-              </>
-            )}
-          </Flex>
-        </StyledPageNotFound>
-      );
-    } else if (baseRoute === "jobs") {
-      return (
-        <StyledPageNotFound>
-          <Mega>
-            404
-            <Inside>Job Not Found</Inside>
-          </Mega>
-          <Flex>
-            <BackButton
-              width="90px"
-              onClick={() => pushFiltered(this.props, "/jobs", ["project_id"])}
-            >
-              <i className="material-icons">arrow_back</i>
-              Jobs
-            </BackButton>
-            {pathname && (
-              <>
-                <Splitter>|</Splitter>
-                <Helper>Could not find "{pathname}"</Helper>
-              </>
-            )}
-          </Flex>
-        </StyledPageNotFound>
-      );
-    }
-    return (
-      <StyledPageNotFound>
-        <Mega>
-          404
-          <Inside>Page Not Found</Inside>
-        </Mega>
-        <Flex>
-          <BackButton
-            width="145px"
-            onClick={() =>
-              pushFiltered(this.props, "/dashboard", ["project_id"])
-            }
-          >
-            <i className="material-icons">home</i>
-            Return Home
-          </BackButton>
-          {pathname && (
-            <>
-              <Splitter>|</Splitter>
-              <Helper>Could not find "{pathname}"</Helper>
-            </>
-          )}
-        </Flex>
-      </StyledPageNotFound>
-    );
-  }
-}
-
-export default withRouter(PageNotFound);
-
-const Splitter = styled.div`
-  margin: 0 20px;
-  font-size: 27px;
-  font-weight: 200;
-  color: #ffffff15;
-`;
-
-const Flex = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Helper = styled.div`
-  font-size: 15px;
-  max-width: 550px;
-  margin-right: -50px;
-`;
-
-const BackButton = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  cursor: pointer;
-  font-size: 13px;
-  height: 35px;
-  padding: 5px 16px;
-  padding-right: 15px;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  width: ${(props: { width: string }) => props.width};
-  color: white;
-  background: #ffffff11;
-
-  :hover {
-    background: #ffffff22;
-  }
-
-  > i {
-    color: white;
-    font-size: 16px;
-    margin-right: 6px;
-    margin-left: -2px;
-  }
-`;
-
-const StyledPageNotFound = styled.div`
-  color: #6f6f6f;
-  font-size: 16px;
-  user-select: none;
-  margin-top: -80px;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Mega = styled.div`
-  font-size: 200px;
-  color: #ffffff06;
-  position: relative;
-  font-weight: bold;
-  text-align: center;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;
-
-const Inside = styled.div`
-  position: absolute;
-  color: #6f6f6f;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-weight: 400;
-  font-size: 20px;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;

+ 0 - 257
dashboard/src/components/RadioFilter.tsx

@@ -1,257 +0,0 @@
-import React, { useEffect, useState, useRef } from "react";
-
-import styled from "styled-components";
-import arrow from "assets/arrow-down.svg";
-
-type Props = {
-  name: string;
-  icon?: any;
-  options: { value: any; label: string }[];
-  selected: any;
-  setSelected: any;
-  noMargin?: boolean;
-  dropdownAlignRight?: boolean;
-};
-
-const RadioFilter: React.FC<Props> = (props) => {
-  const [expanded, setExpanded] = useState(false);
-
-  const wrapperRef = useRef<HTMLInputElement>(null);
-  const parentRef = useRef<HTMLInputElement>(null);
-
-  useEffect(() => {
-    document.addEventListener("mousedown", handleClickOutside.bind(this));
-    return () =>
-      document.removeEventListener("mousedown", handleClickOutside.bind(this));
-  }, []);
-
-  const handleClickOutside = (event: any) => {
-    if (
-      wrapperRef &&
-      wrapperRef.current &&
-      !wrapperRef.current.contains(event.target) &&
-      parentRef &&
-      parentRef.current &&
-      !parentRef.current.contains(event.target)
-    ) {
-      setExpanded(false);
-    }
-  };
-
-  const getLabel = (value: string): any => {
-    let tgt = props.options.find(
-      (element: { value: string; label: string }) => element.value === value
-    );
-    if (tgt) {
-      return tgt.label;
-    }
-  };
-
-  const renderDropdown = () => {
-    let { options } = props;
-    if (expanded) {
-      return (
-        <DropdownWrapper dropdownAlignRight={props.dropdownAlignRight}>
-          <Dropdown ref={wrapperRef}>
-            {options?.length > 0 ? (
-              <ScrollableWrapper>
-                {options.map(
-                  (option: { value: any; label: string }, i: number) => {
-                    return (
-                      <OptionRow
-                        isLast={i === options.length - 1}
-                        onClick={() => {
-                          props.setSelected(option.value);
-                          setExpanded(false);
-                        }}
-                        key={i}
-                        selected={props.selected === option.value}
-                      >
-                        <Text>{option.label}</Text>
-                      </OptionRow>
-                    );
-                  }
-                )}
-              </ScrollableWrapper>
-            ) : (
-              <Placeholder>No options found</Placeholder>
-            )}
-          </Dropdown>
-        </DropdownWrapper>
-      );
-    }
-  };
-
-  return (
-    <Relative>
-      <StyledRadioFilter
-        onClick={() => {
-          setExpanded(!expanded);
-        }}
-        ref={parentRef}
-        noMargin={props.noMargin}
-      >
-        {props.icon && <FilterIcon src={props.icon} />}
-        <TextAlt>{props.name}</TextAlt>
-        <Bar />
-        <Selected>
-          {props.selected != null
-            ? props.selected === ""
-              ? "All"
-              : getLabel(props.selected)
-            : ""}
-        </Selected>
-        <DropdownIcon src={arrow} />
-      </StyledRadioFilter>
-      {renderDropdown()}
-    </Relative>
-  );
-};
-
-export default RadioFilter;
-
-const Bar = styled.div`
-  width: 1px;
-  height: calc(18px);
-  background: #494b4f;
-  margin: 0 8px;
-  margin-left: 0;
-`;
-
-const Selected = styled.div`
-  color: #aaaaaa;
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  max-width: 120px;
-`;
-
-const DimmedText = styled.div`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  word-break: anywhere;
-  margin-right: 10px;
-  color: #999;
-`;
-
-const Text = styled.div`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  word-break: anywhere;
-  margin-right: 10px;
-`;
-
-const TextAlt = styled(Text)`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  word-break: anywhere;
-`;
-
-const OptionRow = styled.div<{ isLast: boolean; selected?: boolean }>`
-  width: 100%;
-  height: 35px;
-  padding-left: 10px;
-  display: flex;
-  cursor: pointer;
-  align-items: center;
-  font-size: 13px;
-  background: ${(props) => (props.selected ? "#ffffff11" : "")};
-
-  :hover {
-    background: #ffffff18;
-  }
-`;
-
-const Placeholder = styled.div`
-  color: #aaaabb88;
-  font-size: 12px;
-  width: 100%;
-  height: 50px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const ScrollableWrapper = styled.div`
-  overflow-y: auto;
-  max-height: 350px;
-
-  ::-webkit-scrollbar {
-    width: 5px;
-    :horizontal {
-      height: 8px;
-    }
-  }
-
-  ::-webkit-scrollbar-corner {
-    width: 10px;
-    background: #ffffff11;
-    color: white;
-  }
-
-  ::-webkit-scrollbar-track {
-    width: 10px;
-    -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
-    box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
-    border-radius: 5px;
-  }
-
-  ::-webkit-scrollbar-thumb {
-    background-color: darkgrey;
-    outline: 1px solid slategrey;
-    border-radius: 5px;
-  }
-`;
-
-const Relative = styled.div`
-  position: relative;
-`;
-
-const DropdownWrapper = styled.div<{ dropdownAlignRight?: boolean }>`
-  position: absolute;
-  left: ${(props) => (props.dropdownAlignRight ? "" : "0")};
-  right: ${(props) => (props.dropdownAlignRight ? "0" : "")};
-  z-index: 1;
-  top: calc(100% + 5px);
-`;
-
-const Dropdown = styled.div`
-  width: 260px;
-  border-radius: 3px;
-  z-index: 999;
-  overflow-y: auto;
-  background: #2f3135;
-  padding: 0;
-  border-radius: 5px;
-  border: 1px solid #aaaabb33;
-`;
-
-const DropdownIcon = styled.img`
-  width: 8px;
-  margin-left: 12px;
-`;
-
-const FilterIcon = styled.img`
-  width: 14px;
-  margin-right: 9px;
-`;
-
-const StyledRadioFilter = styled.div<{ noMargin?: boolean }>`
-  height: 30px;
-  font-size: 13px;
-  position: relative;
-  padding: 10px;
-  background: ${(props) => props.theme.fg};
-  border-radius: 5px;
-  display: flex;
-  align-items: center;
-  margin-right: ${(props) => (props.noMargin ? "" : "10px")};
-  cursor: pointer;
-  border: 1px solid #494b4f;
-  :hover {
-    border: 1px solid #7a7b80;
-  }
-`;

+ 0 - 247
dashboard/src/components/SearchSelector.tsx

@@ -1,247 +0,0 @@
-import _ from "lodash";
-import React, { useMemo, useState } from "react";
-import styled from "styled-components";
-import Loading from "./Loading";
-
-type Props<T = any> = {
-  options: T[];
-  onSelect: (option: T) => void;
-  label?: string;
-  dropdownLabel?: string;
-  getOptionLabel?: (option: T) => string;
-  filterBy?: ((option: T) => string) | string;
-  noOptionsText?: string;
-  dropdownMaxHeight?: string;
-  renderAddButton?: any;
-  className?: string;
-  renderOptionIcon?: (option: T) => React.ReactNode;
-  placeholder?: string;
-  showLoading?: boolean;
-};
-
-function SearchSelector<O = any>({
-  options,
-  onSelect,
-  label,
-  dropdownLabel,
-  getOptionLabel,
-  filterBy,
-  noOptionsText,
-  dropdownMaxHeight,
-  renderAddButton,
-  className,
-  renderOptionIcon,
-  placeholder = "Find or add a tag...", // legacy value to not break existing code
-  showLoading = false,
-}: Props<O>) {
-  const [isExpanded, setIsExpanded] = useState(false);
-  const [filter, setFilter] = useState("");
-
-  const handleOptionClick = (e: any, option: any) => {
-    setIsExpanded(false);
-    onSelect(option);
-    setFilter("");
-  };
-
-  const getLabel = (option: any) => {
-    if (typeof getOptionLabel === "function") {
-      return getOptionLabel(option);
-    }
-
-    return React.isValidElement(option) ? option : "";
-  };
-
-  const filteredOptions = useMemo(() => {
-    if (typeof filterBy === "function") {
-      return options.filter((option) => filterBy(option).includes(filter));
-    }
-
-    if (typeof filterBy === "string") {
-      return options.filter((option) =>
-        _.get(option, filterBy).includes(filter)
-      );
-    }
-
-    return options.filter((option) =>
-      typeof option === "string" ? option.includes(filter) : true
-    );
-  }, [filter, options]);
-
-  if (showLoading) {
-    return (
-      <>
-        {label?.length ? <Label>{label}</Label> : null}
-        <InputWrapper className={className}>
-          <Loading />
-        </InputWrapper>
-      </>
-    );
-  }
-
-  return (
-    <>
-      {label?.length ? <Label>{label}</Label> : null}
-      <InputWrapper
-        onBlur={() => {
-          setIsExpanded(false);
-        }}
-        className={className}
-      >
-        <Input
-          value={filter}
-          placeholder={placeholder}
-          onClick={(e) => {
-            setIsExpanded(false);
-            e.stopPropagation();
-            setIsExpanded(true);
-          }}
-          onChange={(e) => setFilter(e.target.value)}
-        />
-        {isExpanded ? (
-          <DropdownWrapper>
-            <Dropdown dropdownMaxHeight={dropdownMaxHeight}>
-              {!filteredOptions.length ? (
-                <>
-                  {!renderAddButton ? (
-                    <DropdownLabel>
-                      {noOptionsText || "No options available for this filter"}
-                    </DropdownLabel>
-                  ) : (
-                    <div
-                      onMouseDown={(e) => {
-                        e.stopPropagation();
-                        e.preventDefault();
-                        setFilter("");
-                      }}
-                    >
-                      {renderAddButton()}
-                    </div>
-                  )}
-                </>
-              ) : (
-                <>
-                  {renderAddButton && (
-                    <div
-                      onMouseDown={(e) => {
-                        e.stopPropagation();
-                        e.preventDefault();
-                        setFilter("");
-                      }}
-                    >
-                      {renderAddButton()}
-                    </div>
-                  )}
-                  {!renderAddButton && dropdownLabel && (
-                    <DropdownLabel>{dropdownLabel}</DropdownLabel>
-                  )}
-                  {filteredOptions.map((option, i) => (
-                    <Option
-                      key={i}
-                      onMouseDown={(e) => {
-                        e.stopPropagation();
-                        e.preventDefault();
-                      }}
-                      onClick={(e) => handleOptionClick(e, option)}
-                    >
-                      {typeof renderOptionIcon === "function"
-                        ? renderOptionIcon(option)
-                        : null}
-                      {getLabel(option)}
-                    </Option>
-                  ))}
-                </>
-              )}
-            </Dropdown>
-          </DropdownWrapper>
-        ) : null}
-      </InputWrapper>
-    </>
-  );
-}
-
-export default SearchSelector;
-
-const InputWrapper = styled.div`
-  display: flex;
-  margin-bottom: -1px;
-  align-items: center;
-  border: 1px solid #ffffff55;
-  border-radius: 3px;
-  background: #ffffff11;
-  position: relative;
-  width: 100%;
-  min-height: 37px;
-`;
-
-const Input = styled.input`
-  outline: none;
-  border: none;
-  font-size: 13px;
-  background: none;
-  color: #ffffff;
-  padding: 5px 10px;
-  min-height: 35px;
-  max-height: 45px;
-  width: 100%;
-`;
-
-const Label = styled.div`
-  color: #ffffff;
-  margin-bottom: 10px;
-  display: flex;
-  align-items: center;
-  font-size: 13px;
-  font-family: "Work Sans", sans-serif;
-`;
-
-const DropdownWrapper = styled.div`
-  position: absolute;
-  width: 100%;
-  right: 0;
-  z-index: 9999;
-  top: calc(100% + 5px);
-`;
-
-const Dropdown = styled.div`
-  background: #26282f;
-
-  max-height: ${(props: { dropdownMaxHeight: string }) =>
-    props.dropdownMaxHeight || "300px"};
-  border-radius: 3px;
-  z-index: 999;
-  overflow-y: auto;
-  margin-bottom: 20px;
-  box-shadow: 0 8px 20px 0px #00000088;
-`;
-
-const DropdownLabel = styled.div`
-  font-size: 13px;
-  color: #ffffff44;
-  font-weight: 500;
-  margin: 10px 13px;
-`;
-
-const Option = styled.div`
-  width: 100%;
-  border-top: 1px solid #00000000;
-  border-bottom: 1px solid #ffffff15;
-  min-height: 35px;
-  font-size: 13px;
-  align-items: center;
-  display: flex;
-  align-items: center;
-  padding-left: 15px;
-  cursor: pointer;
-  padding-right: 10px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-
-  :last-child {
-    border-bottom: 1px solid #ffffff00;
-  }
-
-  :hover {
-    background: #ffffff22;
-  }
-`;

+ 0 - 130
dashboard/src/components/StatusIndicator.tsx

@@ -1,130 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-import loading from "assets/loading.gif";
-
-type PropsType = {
-  status: string;
-  controllers: Record<string, Record<string, any>>;
-  margin_left: string;
-};
-
-type StateType = {};
-
-// Manages a tab selector and renders the associated view
-export default class StatusIndicator extends Component<PropsType, StateType> {
-  renderStatus = (status: string) => {
-    if (status == "loading") {
-      return (
-        <div>
-          <Spinner src={loading} />
-        </div>
-      );
-    }
-
-    return (
-      <div>
-        <StatusColor status={status} />
-      </div>
-    );
-  };
-
-  getChartStatus = (chartStatus: string) => {
-    if (chartStatus === "deployed") {
-      for (var uid in this.props.controllers) {
-        let value = this.props.controllers[uid];
-        let available = this.getAvailability(value.metadata.kind, value);
-        let progressing = true;
-
-        this.props.controllers[uid]?.status?.conditions?.forEach(
-          (condition: any) => {
-            if (
-              condition.type == "Progressing" &&
-              condition.status == "False" &&
-              condition.reason == "ProgressDeadlineExceeded"
-            ) {
-              progressing = false;
-            }
-          }
-        );
-
-        if (!available && progressing) {
-          return "loading";
-        } else if (!available && !progressing) {
-          return "failed";
-        }
-      }
-      return "deployed";
-    }
-    return chartStatus;
-  };
-
-  getAvailability = (kind: string, c: any) => {
-    switch (kind?.toLowerCase()) {
-      case "deployment":
-      case "replicaset":
-        return c.status.availableReplicas == c.status.replicas;
-      case "statefulset":
-        return c.status.readyReplicas == c.status.replicas;
-      case "daemonset":
-        return c.status.numberAvailable == c.status.desiredNumberScheduled;
-      case "cronjob":
-        return 1;
-    }
-  };
-
-  render() {
-    let status = this.getChartStatus(this.props.status);
-    return (
-      <Status margin_left={this.props.margin_left}>
-        {this.renderStatus(status)}
-        {status}
-      </Status>
-    );
-  }
-}
-
-const Spinner = styled.img`
-  width: 15px;
-  height: 15px;
-  margin-right: 15px;
-  margin-bottom: -3px;
-`;
-
-const StatusColor = styled.div`
-  margin-top: 1px;
-  width: 8px;
-  height: 8px;
-  background: ${(props: { status: string }) =>
-    props.status === "deployed"
-      ? "#4797ff"
-      : props.status === "failed"
-      ? "#ed5f85"
-      : props.status === "completed"
-      ? "#00d12a"
-      : "#f5cb42"};
-  border-radius: 20px;
-  margin-left: 3px;
-  margin-right: 16px;
-`;
-
-const Status = styled.div`
-  display: flex;
-  height: 20px;
-  font-size: 13px;
-  flex-direction: row;
-  text-transform: capitalize;
-  align-items: center;
-  font-family: "Work Sans", sans-serif;
-  color: #aaaabb;
-  animation: fadeIn 0.5s;
-  margin-left: ${(props: { margin_left: string }) => props.margin_left};
-
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;

+ 0 - 86
dashboard/src/components/StatusSection.tsx

@@ -1,86 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-import loading from "assets/loading.gif";
-
-type PropsType = {
-  status: string;
-};
-
-type StateType = {};
-
-// TODO: replace StatusIndicator
-export default class StatusSection extends Component<PropsType, StateType> {
-  renderIndicator = (status: string) => {
-    if (status == "loading") {
-      return (
-        <div>
-          <Spinner src={loading} />
-        </div>
-      );
-    }
-
-    return (
-      <div>
-        <StatusColor status={status} />
-      </div>
-    );
-  };
-
-  render() {
-    return (
-      <Status>
-        {this.renderIndicator(this.props.status)}
-        {this.props.status}
-      </Status>
-    );
-  }
-}
-
-const Spinner = styled.img`
-  width: 15px;
-  height: 15px;
-  margin-right: 15px;
-  margin-bottom: -3px;
-`;
-
-const StatusColor = styled.div`
-  margin-top: 1px;
-  max-width: 8px;
-  max-height: 8px;
-  min-width: 8px;
-  min-height: 8px;
-  width: 8px;
-  height: 8px;
-  background: ${(props: { status: string }) =>
-    props.status === "deployed" || props.status === "healthy"
-      ? "#4797ff"
-      : props.status === "failed"
-      ? "#ed5f85"
-      : props.status === "completed"
-      ? "#00d12a"
-      : "#f5cb42"};
-  border-radius: 4px;
-  margin-left: 3px;
-  margin-right: 16px;
-`;
-
-const Status = styled.div`
-  display: flex;
-  height: 20px;
-  font-size: 13px;
-  flex-direction: row;
-  text-transform: capitalize;
-  align-items: center;
-  font-family: "Work Sans", sans-serif;
-  color: #aaaabb;
-  animation: fadeIn 0.5s;
-
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;

+ 0 - 101
dashboard/src/components/Table.tsx

@@ -1,101 +0,0 @@
-import Placeholder from "components/Placeholder";
-import React from "react";
-import {
-  Column,
-  Row,
-  useGlobalFilter,
-  usePagination,
-  useTable,
-} from "react-table";
-import {
-  StyledTd,
-  StyledTable,
-  StyledTHead,
-  StyledTh,
-  StyledTBody,
-} from "../main/home/cluster-dashboard/expanded-chart/events/styles";
-
-export type TableProps = {
-  columns: Column<any>[];
-  data: any[];
-  onRowClick?: (row: Row) => void;
-  placeholder?: string;
-};
-
-const Table: React.FC<TableProps> = ({
-  columns: columnsData,
-  data,
-  onRowClick,
-  placeholder,
-}) => {
-  if (!data || data.length == 0) {
-    return <Placeholder>{placeholder}</Placeholder>;
-  }
-
-  const {
-    rows,
-    getTableProps,
-    getTableBodyProps,
-    prepareRow,
-    headerGroups,
-  } = useTable(
-    {
-      columns: columnsData,
-      data,
-    },
-    useGlobalFilter,
-    usePagination
-  );
-
-  const renderRows = () => {
-    return (
-      <>
-        {rows.map((row: any) => {
-          prepareRow(row);
-
-          return (
-            <tr
-              {...row.getRowProps()}
-              onClick={() => onRowClick && onRowClick(row)}
-              selected={false}
-            >
-              {row.cells.map((cell: any) => {
-                return (
-                  <StyledTd
-                    {...cell.getCellProps()}
-                    style={{
-                      width: cell.column.totalWidth,
-                    }}
-                  >
-                    {cell.render("Cell")}
-                  </StyledTd>
-                );
-              })}
-            </tr>
-          );
-        })}
-      </>
-    );
-  };
-
-  return (
-    <>
-      <StyledTable {...getTableProps()}>
-        <StyledTHead>
-          {headerGroups.map((headerGroup) => (
-            <tr {...headerGroup.getHeaderGroupProps()}>
-              {headerGroup.headers.map((column) => (
-                <StyledTh {...column.getHeaderProps()}>
-                  {column.render("Header")}
-                </StyledTh>
-              ))}
-            </tr>
-          ))}
-        </StyledTHead>
-        <StyledTBody {...getTableBodyProps()}>{renderRows()}</StyledTBody>
-      </StyledTable>
-    </>
-  );
-};
-
-export default Table;

+ 0 - 117
dashboard/src/components/TitleSectionStacks.tsx

@@ -1,117 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-interface Props {
-  children: React.ReactNode;
-  icon?: any;
-  iconWidth?: string;
-  capitalize?: boolean;
-  className?: string;
-  materialIconClass?: string;
-  handleNavBack?: () => void;
-  onClick?: any;
-}
-
-const TitleSectionStacks: React.FC<Props> = ({
-  children,
-  icon,
-  iconWidth,
-  capitalize,
-  handleNavBack,
-  className,
-  materialIconClass,
-  onClick,
-}) => {
-  return (
-    <StyledTitleSection className={className}>
-      {handleNavBack && (
-        <BackButton>
-          <i className="material-icons" onClick={handleNavBack}>
-            keyboard_backspace
-          </i>
-        </BackButton>
-      )}
-
-      {icon}
-
-      <StyledTitle capitalize={capitalize} onClick={onClick}>
-        {children}
-      </StyledTitle>
-    </StyledTitleSection>
-  );
-};
-
-export default TitleSectionStacks;
-
-const BackButton = styled.div`
-  > i {
-    cursor: pointer;
-    font-size: 24px;
-    color: #aaaabb;
-    margin-right: 10px;
-    padding: 3px;
-    margin-left: 0px;
-    border-radius: 100px;
-    :hover {
-      background: #ffffff11;
-    }
-  }
-`;
-
-const StyledTitleSection = styled.div`
-  display: flex;
-  align-items: center;
-`;
-
-const Icon = styled.span<{ disableMarginRight: boolean }>`
-  font-size: 24px;
-  margin-right: 10px;
-  ${(props) => {
-    if (!props.disableMarginRight) {
-      return "margin-right: 20px";
-    }
-  }}
-`;
-
-const StyledTitle = styled.div<{
-  capitalize: boolean;
-  onClick?: any;
-}>`
-  font-size: 21px;
-  user-select: text;
-  color: ${(props) => props.theme.text.primary};
-  text-transform: ${(props) => (props.capitalize ? "capitalize" : "")};
-  display: flex;
-  align-items: center;
-  cursor: ${(props) => (props.onClick ? "pointer" : "")};
-  :hover {
-    text-decoration: ${(props) => (props.onClick ? "underline" : "")};
-  }
-
-  > i {
-    margin-left: 10px;
-    cursor: pointer;
-    font-size: 18px;
-    color: #858faaaa;
-    padding: 5px;
-    border-radius: 100px;
-    :hover {
-      background: #ffffff11;
-    }
-    margin-bottom: -3px;
-  }
-
-  > a {
-    > i {
-      display: flex;
-      align-items: center;
-      margin-bottom: -2px;
-      font-size: 18px;
-      margin-left: 15px;
-      color: #858faaaa;
-      :hover {
-        color: #aaaabb;
-      }
-    }
-  }
-`;

+ 0 - 70
dashboard/src/components/TooltipParent.tsx

@@ -1,70 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  tooltipText: string;
-};
-
-type StateType = {
-  showTooltip: boolean;
-};
-
-export default class TooltipParent extends Component<PropsType, StateType> {
-  state = {
-    showTooltip: false,
-  };
-
-  renderTooltip = (): JSX.Element | undefined => {
-    if (this.state.showTooltip) {
-      return <Tooltip>{this.props.tooltipText}</Tooltip>;
-    }
-  };
-
-  render() {
-    return (
-      <StyledTooltipParent
-        onMouseOver={() => {
-          this.setState({ showTooltip: true });
-        }}
-        onMouseOut={() => {
-          this.setState({ showTooltip: false });
-        }}
-      >
-        {this.props.children}
-        {this.renderTooltip()}
-      </StyledTooltipParent>
-    );
-  }
-}
-
-const Tooltip = styled.div`
-  position: absolute;
-  left: 10px;
-  top: 20px;
-  height: 18px;
-  padding: 2px 5px;
-  background: #383842dd;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex: 1;
-  color: white;
-  font-size: 12px;
-  font-family: "Work Sans", sans-serif;
-  outline: 1px solid #ffffff55;
-  opacity: 0;
-  animation: faded-in 0.2s 0.15s;
-  animation-fill-mode: forwards;
-  @keyframes faded-in {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const StyledTooltipParent = styled.div`
-  position: relative;
-`;

+ 0 - 113
dashboard/src/components/porter/ConfirmOverlay.tsx

@@ -1,113 +0,0 @@
-import Loading from "components/Loading";
-import React from "react";
-import { createPortal } from "react-dom";
-import styled from "styled-components";
-
-type Props = {
-  message: string;
-  onYes: React.MouseEventHandler;
-  onNo: React.MouseEventHandler;
-  loading?: boolean;
-};
-
-const ConfirmOverlay: React.FC<Props> = ({
-  message,
-  onYes,
-  onNo,
-  loading,
-}) => {
-  return (
-    <>
-      {
-        createPortal(
-          <StyledConfirmOverlay>
-            {loading ? (
-              <Loading />
-            ) : (
-              <>
-                {message}
-                <ButtonRow>
-                  <ConfirmButton onClick={onYes}>Yes</ConfirmButton>
-                  <ConfirmButton onClick={onNo}>No</ConfirmButton>
-                </ButtonRow>
-              </>
-            )}
-          </StyledConfirmOverlay>,
-          document.body
-        )
-      }
-    </>
-  );
-};
-
-export default ConfirmOverlay;
-
-const StyledConfirmOverlay = styled.div`
-  position: absolute;
-  top: 0px;
-  opacity: 100%;
-  left: 0px;
-  width: 100%;
-  height: 100%;
-  z-index: 999;
-  display: flex;
-  padding-bottom: 30px;
-  align-items: center;
-  justify-content: center;
-  font-family: "Work Sans", sans-serif;
-  font-size: 18px;
-  color: white;
-  flex-direction: column;
-  background: rgb(0, 0, 0, 0.55);
-  backdrop-filter: blur(5px);
-  animation: lindEnter 0.2s;
-  animation-fill-mode: forwards;
-
-  @keyframes lindEnter {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const ButtonRow = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  width: 140px;
-  margin-top: 30px;
-`;
-
-const ConfirmButton = styled.div`
-  outline: none;
-  height: 40px;
-  border: 1px solid white;
-  border-radius: 5px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 60px;
-  cursor: pointer;
-  opacity: 0;
-  font-family: "Work Sans", sans-serif;
-  font-size: 15px;
-  animation: linEnter 0.3s 0.1s;
-  animation-fill-mode: forwards;
-  @keyframes linEnter {
-    from {
-      transform: translateY(20px);
-      opacity: 0;
-    }
-    to {
-      transform: translateY(0px);
-      opacity: 1;
-    }
-  }
-  :hover {
-    background: white;
-    color: #232323;
-  }
-`;

+ 0 - 123
dashboard/src/legacy/assets/GoogleIcon.tsx

@@ -1,123 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {};
-
-type StateType = {};
-
-export default class GHIcon extends Component<PropsType, StateType> {
-  render() {
-    return (
-      <Svg width="46px" height="46px" viewBox="0 0 46 46" {...this.props}>
-        <title>btn_google_light_normal_ios</title>
-        <desc>Created with Sketch.</desc>
-        <defs>
-          <filter
-            x="-50%"
-            y="-50%"
-            width="200%"
-            height="200%"
-            filterUnits="objectBoundingBox"
-            id="filter-1"
-          >
-            <feOffset
-              dx="0"
-              dy="1"
-              in="SourceAlpha"
-              result="shadowOffsetOuter1"
-            ></feOffset>
-            <feGaussianBlur
-              stdDeviation="0.5"
-              in="shadowOffsetOuter1"
-              result="shadowBlurOuter1"
-            ></feGaussianBlur>
-            <feColorMatrix
-              values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.168 0"
-              in="shadowBlurOuter1"
-              type="matrix"
-              result="shadowMatrixOuter1"
-            ></feColorMatrix>
-            <feOffset
-              dx="0"
-              dy="0"
-              in="SourceAlpha"
-              result="shadowOffsetOuter2"
-            ></feOffset>
-            <feGaussianBlur
-              stdDeviation="0.5"
-              in="shadowOffsetOuter2"
-              result="shadowBlurOuter2"
-            ></feGaussianBlur>
-            <feColorMatrix
-              values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.084 0"
-              in="shadowBlurOuter2"
-              type="matrix"
-              result="shadowMatrixOuter2"
-            ></feColorMatrix>
-            <feMerge>
-              <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
-              <feMergeNode in="shadowMatrixOuter2"></feMergeNode>
-              <feMergeNode in="SourceGraphic"></feMergeNode>
-            </feMerge>
-          </filter>
-          <rect id="path-2" x="0" y="0" width="40" height="40" rx="2"></rect>
-        </defs>
-        <g
-          id="Google-Button"
-          stroke="none"
-          stroke-width="1"
-          fill="none"
-          fill-rule="evenodd"
-        >
-          <g id="9-PATCH" transform="translate(-608.000000, -160.000000)"></g>
-          <g
-            id="btn_google_light_normal"
-            transform="translate(-1.000000, -1.000000)"
-          >
-            <g
-              id="button"
-              transform="translate(4.000000, 4.000000)"
-              filter="url(#filter-1)"
-            >
-              <g id="button-bg">
-                <use fill="#FFFFFF" fill-rule="evenodd"></use>
-                <use fill="none"></use>
-                <use fill="none"></use>
-                <use fill="none"></use>
-              </g>
-            </g>
-            <g
-              id="logo_googleg_48dp"
-              transform="translate(15.000000, 15.000000)"
-            >
-              <path
-                d="M17.64,9.20454545 C17.64,8.56636364 17.5827273,7.95272727 17.4763636,7.36363636 L9,7.36363636 L9,10.845 L13.8436364,10.845 C13.635,11.97 13.0009091,12.9231818 12.0477273,13.5613636 L12.0477273,15.8195455 L14.9563636,15.8195455 C16.6581818,14.2527273 17.64,11.9454545 17.64,9.20454545 L17.64,9.20454545 Z"
-                id="Shape"
-                fill="#4285F4"
-              ></path>
-              <path
-                d="M9,18 C11.43,18 13.4672727,17.1940909 14.9563636,15.8195455 L12.0477273,13.5613636 C11.2418182,14.1013636 10.2109091,14.4204545 9,14.4204545 C6.65590909,14.4204545 4.67181818,12.8372727 3.96409091,10.71 L0.957272727,10.71 L0.957272727,13.0418182 C2.43818182,15.9831818 5.48181818,18 9,18 L9,18 Z"
-                id="Shape"
-                fill="#34A853"
-              ></path>
-              <path
-                d="M3.96409091,10.71 C3.78409091,10.17 3.68181818,9.59318182 3.68181818,9 C3.68181818,8.40681818 3.78409091,7.83 3.96409091,7.29 L3.96409091,4.95818182 L0.957272727,4.95818182 C0.347727273,6.17318182 0,7.54772727 0,9 C0,10.4522727 0.347727273,11.8268182 0.957272727,13.0418182 L3.96409091,10.71 L3.96409091,10.71 Z"
-                id="Shape"
-                fill="#FBBC05"
-              ></path>
-              <path
-                d="M9,3.57954545 C10.3213636,3.57954545 11.5077273,4.03363636 12.4404545,4.92545455 L15.0218182,2.34409091 C13.4631818,0.891818182 11.4259091,0 9,0 C5.48181818,0 2.43818182,2.01681818 0.957272727,4.95818182 L3.96409091,7.29 C4.67181818,5.16272727 6.65590909,3.57954545 9,3.57954545 L9,3.57954545 Z"
-                id="Shape"
-                fill="#EA4335"
-              ></path>
-              <path d="M0,0 L18,0 L18,18 L0,18 L0,0 Z" id="Shape"></path>
-            </g>
-            <g id="handles_square"></g>
-          </g>
-        </g>
-      </Svg>
-    );
-  }
-}
-
-const Svg = styled.svg``;

+ 0 - 15
dashboard/src/legacy/assets/code-branch-icon.tsx

@@ -1,15 +0,0 @@
-import React, { SVGProps } from "react";
-
-function Icon(props: SVGProps<SVGElement>) {
-  return (
-    <svg
-      xmlns="http://www.w3.org/2000/svg"
-      viewBox="0 0 448 512"
-      className={props.className}
-    >
-      <path d="M160 80c0 32.8-19.7 60.1-48 73.3v87.8c18.8-10.9 40.7-17.1 64-17.1h96c35.3 0 64-28.7 64-64v-6.7c-28.3-13.2-48-40.5-48-73.3 0-44.18 35.8-80 80-80s80 35.82 80 80c0 32.8-19.7 60.1-48 73.3v6.7c0 70.7-57.3 128-128 128h-96c-35.3 0-64 28.7-64 64v6.7c28.3 12.3 48 40.5 48 73.3 0 44.2-35.8 80-80 80-44.18 0-80-35.8-80-80 0-32.8 19.75-61 48-73.3V153.3C19.75 140.1 0 112.8 0 80 0 35.82 35.82 0 80 0c44.2 0 80 35.82 80 80zm-80 24c13.25 0 24-10.75 24-24S93.25 56 80 56 56 66.75 56 80s10.75 24 24 24zm288-48c-13.3 0-24 10.75-24 24s10.7 24 24 24 24-10.75 24-24-10.7-24-24-24zM80 456c13.25 0 24-10.7 24-24s-10.75-24-24-24-24 10.7-24 24 10.75 24 24 24z"></path>
-    </svg>
-  );
-}
-
-export default Icon;

+ 0 - 126
dashboard/src/legacy/components/CheckboxList.tsx

@@ -1,126 +0,0 @@
-import React, { useEffect } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  label?: string;
-  options: { disabled?: boolean; value: any; label: string }[];
-  selected: { value: any; label: string }[];
-  setSelected: (x: { value: any; label: string }[]) => void;
-};
-
-const arraysEqual = (a: any, b: any) => {
-  if (a === b) return true;
-  if (a == null || b == null) return false;
-  if (a.length !== b.length) return false;
-
-  // If you don't care about the order of the elements inside
-  // the array, you should sort both arrays here.
-  // Please note that calling sort on an array will modify that array.
-  // you might want to clone your array first.
-
-  for (var i = 0; i < a.length; ++i) {
-    if (a[i] !== b[i]) return false;
-  }
-  return true;
-};
-
-const CheckboxList = ({ label, options, selected, setSelected }: PropsType) => {
-  let onSelectOption = (option: { value: any; label: string }) => {
-    const tmp = [...selected];
-    if (
-      tmp.filter(
-        (e) => e.value === option.value || arraysEqual(e.value, option.value)
-      ).length === 0
-    ) {
-      setSelected([...tmp, option]);
-    } else {
-      tmp.forEach((x, i) => {
-        if (x.value === option.value || arraysEqual(x.value, option.value)) {
-          tmp.splice(i, 1);
-        }
-      });
-      setSelected(tmp);
-    }
-  };
-
-  return (
-    <StyledCheckboxList>
-      {label && <Label>{label}</Label>}
-      {options.map((option: { value: any; label: string }, i: number) => {
-        return (
-          <CheckboxOption
-            isLast={i === options.length - 1}
-            onClick={() => onSelectOption(option)}
-            key={i}
-          >
-            <Checkbox
-              checked={
-                selected.filter(
-                  (e) =>
-                    e.value === option.value ||
-                    arraysEqual(e.value, option.value)
-                ).length > 0
-              }
-            >
-              <i className="material-icons">done</i>
-            </Checkbox>
-            <Text>{option.label}</Text>
-          </CheckboxOption>
-        );
-      })}
-    </StyledCheckboxList>
-  );
-};
-export default CheckboxList;
-
-const Text = styled.div`
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  word-break: anywhere;
-  margin-right: 10px;
-`;
-
-const Checkbox = styled.div`
-  width: 14px;
-  height: 14px;
-  min-width: 14px;
-  border: 1px solid #ffffff55;
-  margin: 1px 10px 0px 1px;
-  border-radius: 3px;
-  background: ${(props: { checked: boolean }) =>
-    props.checked ? "#ffffff22" : "#ffffff11"};
-  display: flex;
-  align-items: center;
-  justify-content: center;
-
-  > i {
-    font-size: 12px;
-    padding-left: 0px;
-    display: ${(props: { checked: boolean }) => (props.checked ? "" : "none")};
-  }
-`;
-
-const CheckboxOption = styled.div<{ isLast: boolean }>`
-  width: 100%;
-  height: 35px;
-  padding-left: 10px;
-  display: flex;
-  cursor: pointer;
-  align-items: center;
-  font-size: 13px;
-
-  :hover {
-    background: #ffffff18;
-  }
-`;
-
-const Label = styled.div`
-  color: #ffffff;
-  margin-bottom: 10px;
-`;
-
-const StyledCheckboxList = styled.div`
-  border-radius: 3px;
-  padding: 0;
-`;

+ 0 - 0
dashboard/src/legacy/components/Helper.tsx


+ 0 - 45
dashboard/src/legacy/components/InfoTooltip.tsx

@@ -1,45 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  text: string;
-};
-
-type StateType = {
-  showTooltip: boolean;
-};
-
-export default class InfoTooltip extends Component<PropsType, StateType> {
-  state = {
-    showTooltip: false,
-  };
-
-  render() {
-    return (
-      <StyledInfoTooltip>
-        <i className="material-icons">help_outline</i>
-      </StyledInfoTooltip>
-    );
-  }
-}
-
-const StyledInfoTooltip = styled.div`
-  display: inline-block;
-  position: relative;
-  width: 26px;
-  margin-right: 2px;
-
-  > i {
-    display: flex;
-    align-items: center;
-    position: absolute;
-    top: -14px;
-    font-size: 18px;
-    right: -1px;
-    color: #858faaaa;
-    cursor: pointer;
-    :hover {
-      color: #aaaabb;
-    }
-  }
-`;

+ 0 - 0
dashboard/src/legacy/components/LineGraph.tsx


+ 0 - 201
dashboard/src/legacy/components/MultiSelectFilter.tsx

@@ -1,201 +0,0 @@
-import React, { useEffect, useRef, useState } from "react";
-import arrow from "legacy/assets/arrow-down.svg";
-import styled from "styled-components";
-
-import CheckboxList from "./CheckboxList";
-
-type Props = {
-  name: string;
-  icon?: any;
-  options: { value: any; label: string }[];
-  selected: any[];
-  setSelected: any;
-};
-
-export const MultiSelectFilter: React.FC<Props> = (props) => {
-  const [expanded, setExpanded] = useState(false);
-
-  const wrapperRef = useRef<HTMLInputElement>(null);
-  const parentRef = useRef<HTMLInputElement>(null);
-
-  useEffect(() => {
-    document.addEventListener("mousedown", handleClickOutside.bind(this));
-    return () =>
-      document.removeEventListener("mousedown", handleClickOutside.bind(this));
-  }, []);
-
-  const handleClickOutside = (event: any) => {
-    if (
-      wrapperRef &&
-      wrapperRef.current &&
-      !wrapperRef.current.contains(event.target) &&
-      parentRef &&
-      parentRef.current &&
-      !parentRef.current.contains(event.target)
-    ) {
-      setExpanded(false);
-    }
-  };
-
-  const renderOptions = () => {
-    return props.options.map(
-      (option: { value: any; label: string }, i: number) => {
-        return (
-          <Option key={i} onClick={() => alert("choise")}>
-            {option.label}
-          </Option>
-        );
-      }
-    );
-  };
-
-  const renderDropdown = () => {
-    if (expanded) {
-      return (
-        <DropdownWrapper>
-          <Dropdown ref={wrapperRef}>
-            {props.options.length > 0 ? (
-              <ScrollableWrapper>
-                <CheckboxList
-                  options={props.options}
-                  selected={props.selected}
-                  setSelected={props.setSelected}
-                />
-              </ScrollableWrapper>
-            ) : (
-              <Placeholder>No options found</Placeholder>
-            )}
-          </Dropdown>
-        </DropdownWrapper>
-      );
-    }
-  };
-
-  return (
-    <Relative>
-      <StyledMultiSelectFilter
-        onClick={() => setExpanded(!expanded)}
-        ref={parentRef}
-      >
-        {props.icon && <FilterIcon src={props.icon} />}
-        {props.name}
-        {props.selected.length > 0 && (
-          <FilterCount>{props.selected.length}</FilterCount>
-        )}
-        <DropdownIcon src={arrow} />
-      </StyledMultiSelectFilter>
-      {renderDropdown()}
-    </Relative>
-  );
-};
-
-const FilterCount = styled.div`
-  padding: 5px;
-  color: #ffffff;
-  background: #ffffff11;
-  margin-left: 7px;
-  font-size: 12px;
-  border-radius: 50px;
-  margin-right: -5px;
-  height: 20px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  min-width: 20px;
-`;
-
-const Placeholder = styled.div`
-  color: #aaaabb88;
-  font-size: 12px;
-  width: 100%;
-  height: 50px;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const ScrollableWrapper = styled.div`
-  overflow-y: auto;
-  height: 100%;
-  max-height: 350px;
-`;
-
-const Label = styled.div`
-  height: 37px;
-  display: flex;
-  align-items: center;
-  margin-left: 10px;
-  font-size: 13px;
-`;
-
-const Option: any = styled.div`
-  width: 100%;
-  border-top: 1px solid #00000000;
-  height: 37px;
-  font-size: 13px;
-  align-items: center;
-  display: flex;
-  align-items: center;
-  padding-left: 15px;
-  cursor: pointer;
-  padding-right: 10px;
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  background: ${(props: any) => (props.selected ? "#ffffff11" : "")};
-
-  :hover {
-    background: #ffffff22;
-  }
-`;
-
-const Relative = styled.div`
-  position: relative;
-`;
-
-const DropdownWrapper = styled.div`
-  position: absolute;
-  width: 100%;
-  right: 0;
-  z-index: 1;
-  top: calc(100% + 5px);
-`;
-
-const Dropdown = styled.div`
-  width: 260px;
-  border-radius: 3px;
-  z-index: 999;
-  overflow-y: auto;
-  margin-bottom: 20px;
-  background: #2f3135;
-  padding: 0;
-  border-radius: 5px;
-  border: 1px solid #aaaabb33;
-`;
-
-const DropdownIcon = styled.img`
-  width: 8px;
-  margin-left: 12px;
-`;
-
-const FilterIcon = styled.img`
-  width: 14px;
-  margin-right: 7px;
-`;
-
-const StyledMultiSelectFilter = styled.div`
-  height: 30px;
-  font-size: 13px;
-  position: relative;
-  padding: 10px;
-  background: ${(props) => props.theme.fg};
-  border-radius: 5px;
-  border: 1px solid #aaaabb33;
-  display: flex;
-  align-items: center;
-  margin-right: 10px;
-  cursor: pointer;
-  :hover {
-    background: #ffffff11;
-  }
-`;

+ 0 - 187
dashboard/src/legacy/components/PageNotFound.tsx

@@ -1,187 +0,0 @@
-import React, { Component } from "react";
-import { pushFiltered } from "legacy/shared/routing";
-import { RouteComponentProps, withRouter } from "react-router";
-import styled from "styled-components";
-
-type PropsType = RouteComponentProps & {};
-
-type StateType = {};
-
-class PageNotFound extends Component<PropsType, StateType> {
-  state = {};
-
-  render() {
-    let { pathname } = this.props.location;
-    let params = this.props.match.params as any;
-    let { baseRoute } = params;
-    if (baseRoute === "applications") {
-      return (
-        <StyledPageNotFound>
-          <Mega>
-            404
-            <Inside>Application Not Found</Inside>
-          </Mega>
-          <Flex>
-            <BackButton
-              width="140px"
-              onClick={() =>
-                pushFiltered(this.props, "/applications", ["project_id"])
-              }
-            >
-              <i className="material-icons">arrow_back</i>
-              Applications
-            </BackButton>
-            {pathname && (
-              <>
-                <Splitter>|</Splitter>
-                <Helper>Could not find "{pathname}"</Helper>
-              </>
-            )}
-          </Flex>
-        </StyledPageNotFound>
-      );
-    } else if (baseRoute === "jobs") {
-      return (
-        <StyledPageNotFound>
-          <Mega>
-            404
-            <Inside>Job Not Found</Inside>
-          </Mega>
-          <Flex>
-            <BackButton
-              width="90px"
-              onClick={() => pushFiltered(this.props, "/jobs", ["project_id"])}
-            >
-              <i className="material-icons">arrow_back</i>
-              Jobs
-            </BackButton>
-            {pathname && (
-              <>
-                <Splitter>|</Splitter>
-                <Helper>Could not find "{pathname}"</Helper>
-              </>
-            )}
-          </Flex>
-        </StyledPageNotFound>
-      );
-    }
-    return (
-      <StyledPageNotFound>
-        <Mega>
-          404
-          <Inside>Page Not Found</Inside>
-        </Mega>
-        <Flex>
-          <BackButton
-            width="145px"
-            onClick={() =>
-              pushFiltered(this.props, "/dashboard", ["project_id"])
-            }
-          >
-            <i className="material-icons">home</i>
-            Return Home
-          </BackButton>
-          {pathname && (
-            <>
-              <Splitter>|</Splitter>
-              <Helper>Could not find "{pathname}"</Helper>
-            </>
-          )}
-        </Flex>
-      </StyledPageNotFound>
-    );
-  }
-}
-
-export default withRouter(PageNotFound);
-
-const Splitter = styled.div`
-  margin: 0 20px;
-  font-size: 27px;
-  font-weight: 200;
-  color: #ffffff15;
-`;
-
-const Flex = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Helper = styled.div`
-  font-size: 15px;
-  max-width: 550px;
-  margin-right: -50px;
-`;
-
-const BackButton = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  cursor: pointer;
-  font-size: 13px;
-  height: 35px;
-  padding: 5px 16px;
-  padding-right: 15px;
-  border: 1px solid #ffffff55;
-  border-radius: 100px;
-  width: ${(props: { width: string }) => props.width};
-  color: white;
-  background: #ffffff11;
-
-  :hover {
-    background: #ffffff22;
-  }
-
-  > i {
-    color: white;
-    font-size: 16px;
-    margin-right: 6px;
-    margin-left: -2px;
-  }
-`;
-
-const StyledPageNotFound = styled.div`
-  color: #6f6f6f;
-  font-size: 16px;
-  user-select: none;
-  margin-top: -80px;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Mega = styled.div`
-  font-size: 200px;
-  color: #ffffff06;
-  position: relative;
-  font-weight: bold;
-  text-align: center;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;
-
-const Inside = styled.div`
-  position: absolute;
-  color: #6f6f6f;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-weight: 400;
-  font-size: 20px;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;

+ 0 - 117
dashboard/src/legacy/components/TitleSectionStacks.tsx

@@ -1,117 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-interface Props {
-  children: React.ReactNode;
-  icon?: any;
-  iconWidth?: string;
-  capitalize?: boolean;
-  className?: string;
-  materialIconClass?: string;
-  handleNavBack?: () => void;
-  onClick?: any;
-}
-
-const TitleSectionStacks: React.FC<Props> = ({
-  children,
-  icon,
-  iconWidth,
-  capitalize,
-  handleNavBack,
-  className,
-  materialIconClass,
-  onClick,
-}) => {
-  return (
-    <StyledTitleSection className={className}>
-      {handleNavBack && (
-        <BackButton>
-          <i className="material-icons" onClick={handleNavBack}>
-            keyboard_backspace
-          </i>
-        </BackButton>
-      )}
-
-      {icon}
-
-      <StyledTitle capitalize={capitalize} onClick={onClick}>
-        {children}
-      </StyledTitle>
-    </StyledTitleSection>
-  );
-};
-
-export default TitleSectionStacks;
-
-const BackButton = styled.div`
-  > i {
-    cursor: pointer;
-    font-size: 24px;
-    color: #aaaabb;
-    margin-right: 10px;
-    padding: 3px;
-    margin-left: 0px;
-    border-radius: 100px;
-    :hover {
-      background: #ffffff11;
-    }
-  }
-`;
-
-const StyledTitleSection = styled.div`
-  display: flex;
-  align-items: center;
-`;
-
-const Icon = styled.span<{ disableMarginRight: boolean }>`
-  font-size: 24px;
-  margin-right: 10px;
-  ${(props) => {
-    if (!props.disableMarginRight) {
-      return "margin-right: 20px";
-    }
-  }}
-`;
-
-const StyledTitle = styled.div<{
-  capitalize: boolean;
-  onClick?: any;
-}>`
-  font-size: 21px;
-  user-select: text;
-  color: ${(props) => props.theme.text.primary};
-  text-transform: ${(props) => (props.capitalize ? "capitalize" : "")};
-  display: flex;
-  align-items: center;
-  cursor: ${(props) => (props.onClick ? "pointer" : "")};
-  :hover {
-    text-decoration: ${(props) => (props.onClick ? "underline" : "")};
-  }
-
-  > i {
-    margin-left: 10px;
-    cursor: pointer;
-    font-size: 18px;
-    color: #858faaaa;
-    padding: 5px;
-    border-radius: 100px;
-    :hover {
-      background: #ffffff11;
-    }
-    margin-bottom: -3px;
-  }
-
-  > a {
-    > i {
-      display: flex;
-      align-items: center;
-      margin-bottom: -2px;
-      font-size: 18px;
-      margin-left: 15px;
-      color: #858faaaa;
-      :hover {
-        color: #aaaabb;
-      }
-    }
-  }
-`;

+ 0 - 70
dashboard/src/legacy/components/TooltipParent.tsx

@@ -1,70 +0,0 @@
-import React, { Component } from "react";
-import styled from "styled-components";
-
-type PropsType = {
-  tooltipText: string;
-};
-
-type StateType = {
-  showTooltip: boolean;
-};
-
-export default class TooltipParent extends Component<PropsType, StateType> {
-  state = {
-    showTooltip: false,
-  };
-
-  renderTooltip = (): JSX.Element | undefined => {
-    if (this.state.showTooltip) {
-      return <Tooltip>{this.props.tooltipText}</Tooltip>;
-    }
-  };
-
-  render() {
-    return (
-      <StyledTooltipParent
-        onMouseOver={() => {
-          this.setState({ showTooltip: true });
-        }}
-        onMouseOut={() => {
-          this.setState({ showTooltip: false });
-        }}
-      >
-        {this.props.children}
-        {this.renderTooltip()}
-      </StyledTooltipParent>
-    );
-  }
-}
-
-const Tooltip = styled.div`
-  position: absolute;
-  left: 10px;
-  top: 20px;
-  height: 18px;
-  padding: 2px 5px;
-  background: #383842dd;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  flex: 1;
-  color: white;
-  font-size: 12px;
-  font-family: "Work Sans", sans-serif;
-  outline: 1px solid #ffffff55;
-  opacity: 0;
-  animation: faded-in 0.2s 0.15s;
-  animation-fill-mode: forwards;
-  @keyframes faded-in {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const StyledTooltipParent = styled.div`
-  position: relative;
-`;

+ 0 - 59
dashboard/src/legacy/components/UnauthorizedPage.tsx

@@ -1,59 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-const UnauthorizedPage: React.FunctionComponent = () => (
-  <StyledUnauthorizedPage>
-    <Mega>
-      401
-      <Inside>You're not authorized to access this page</Inside>
-    </Mega>
-  </StyledUnauthorizedPage>
-);
-
-export default UnauthorizedPage;
-
-const StyledUnauthorizedPage = styled.div`
-  font-family: "Work Sans", sans-serif;
-  color: #6f6f6f;
-  font-size: 16px;
-  user-select: none;
-  padding-bottom: 20px;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-`;
-
-const Mega = styled.div`
-  font-size: 200px;
-  color: #ffffff06;
-  position: relative;
-  font-weight: bold;
-  text-align: center;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;
-
-const Inside = styled.div`
-  position: absolute;
-  color: #6f6f6f;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  font-weight: 400;
-  font-size: 20px;
-
-  > i {
-    font-size: 23px;
-    margin-right: 12px;
-  }
-`;

+ 0 - 244
dashboard/src/legacy/main/CurrentError.tsx

@@ -1,244 +0,0 @@
-import React, { Component } from "react";
-import close from "legacy/assets/close.png";
-import styled from "styled-components";
-
-import { Context } from "shared/Context";
-
-type PropsType = {
-  currentError: any;
-};
-
-type StateType = {};
-
-export default class CurrentError extends Component<PropsType, StateType> {
-  state = {
-    expanded: false,
-  };
-
-  componentDidUpdate(prevProps: PropsType) {
-    if (
-      prevProps.currentError !== this.props.currentError &&
-      this.props.currentError ===
-        "Provisioning failed. Check your credentials and try again."
-    ) {
-      this.setState({ expanded: true });
-    }
-  }
-
-  render() {
-    if (!this.props.currentError) {
-      return null;
-    }
-
-    // Check if it's an error from the API then retrieve the error message that we get from the API
-    let currentError =
-      this.props.currentError?.response?.data?.error || this.props.currentError;
-    if (!React.isValidElement(currentError)) {
-      currentError = String(currentError);
-    }
-
-    if (
-      currentError &&
-      currentError !== "" &&
-      currentError !== "{}" &&
-      currentError !== undefined &&
-      currentError.length > 3
-    ) {
-      if (!this.state.expanded) {
-        return (
-          <StyledCurrentError>
-            <ErrorText>Error: {currentError}</ErrorText>
-            <ExpandButton
-              onClick={() => {
-                this.setState({ expanded: true });
-              }}
-            >
-              <i className="material-icons">launch</i>
-            </ExpandButton>
-            <CloseButton
-              onClick={(e) => {
-                e.stopPropagation();
-
-                this.setState({ expanded: false }, () => {
-                  this.context.setCurrentError(null);
-                });
-              }}
-            >
-              <CloseButtonImg src={close} />
-            </CloseButton>
-          </StyledCurrentError>
-        );
-      }
-
-      return (
-        <Overlay>
-          <ExpandedError>
-            Porter encountered an error. Full error log:
-            <CodeBlock>{currentError}</CodeBlock>
-            <ExpandButtonAlt
-              onClick={() => {
-                this.setState({ expanded: false });
-              }}
-            >
-              <i className="material-icons">remove</i>
-            </ExpandButtonAlt>
-            <CloseButtonAlt
-              onClick={(e) => {
-                e.stopPropagation();
-
-                this.setState({ expanded: false }, () => {
-                  this.context.setCurrentError(null);
-                });
-              }}
-            >
-              <CloseButtonImg src={close} />
-            </CloseButtonAlt>
-          </ExpandedError>
-        </Overlay>
-      );
-    }
-
-    return null;
-  }
-}
-
-CurrentError.contextType = Context;
-
-const CloseButton = styled.div`
-  display: flex;
-  align-items: center;
-  justify-content: center;
-  width: 30px;
-  height: 30px;
-  border-radius: 50%;
-  cursor: pointer;
-  :hover {
-    background-color: #ffffff11;
-  }
-`;
-
-const CloseButtonAlt = styled(CloseButton)`
-  position: absolute;
-  top: 5px;
-  right: 5px;
-`;
-
-const CloseButtonImg = styled.img`
-  width: 10px;
-`;
-
-const ErrorText = styled.div`
-  white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  width: calc(100% - 80px);
-`;
-
-const StyledCurrentError = styled.div`
-  position: fixed;
-  bottom: 22px;
-  width: 310px;
-  left: 20px;
-  padding: 15px;
-  padding-right: 0px;
-  font-family: "Work Sans", sans-serif;
-  height: 50px;
-  font-size: 13px;
-  border-radius: 3px;
-  background: #272731cc;
-  border: 1px solid #ffffff55;
-  display: flex;
-  align-items: center;
-  color: #ffffff;
-
-  > i {
-    font-size: 18px;
-    margin-right: 10px;
-  }
-
-  animation: floatIn 0.5s;
-  animation-fill-mode: forwards;
-
-  @keyframes floatIn {
-    from {
-      opacity: 0;
-      transform: translateY(20px);
-    }
-    to {
-      opacity: 1;
-      transform: translateY(0px);
-    }
-  }
-`;
-
-const ExpandButton = styled(CloseButton)`
-  display: flex;
-  width: 30px;
-  height: 30px;
-  border-radius: 50%;
-  cursor: pointer;
-
-  :hover {
-    background-color: #ffffff11;
-  }
-
-  > i {
-    font-size: 16px;
-  }
-`;
-
-const ExpandButtonAlt = styled(ExpandButton)`
-  position: absolute;
-  top: 5px;
-  right: 34px;
-`;
-
-const Overlay = styled.div`
-  position: fixed;
-  margin: 0;
-  padding: 0;
-  top: 0;
-  left: 0;
-  width: 100%;
-  height: 100%;
-  background-color: rgba(0, 0, 0, 0.6);
-  z-index: 3;
-  display: flex;
-  align-items: center;
-  justify-content: center;
-`;
-
-const ExpandedError = styled.div`
-  position: fixed;
-  display: block;
-  width: 700px;
-  left: calc(50% - 350px);
-  height: auto;
-  max-height: 500px;
-  top: 50%;
-  transform: translateY(-50%);
-  padding: 20px;
-  overflow-y: auto;
-  background: #272731;
-  border: 1px solid #ffffff55;
-  font-family: "Work Sans", sans-serif;
-  font-size: 13px;
-  border-radius: 12px;
-`;
-
-const CodeBlock = styled.span`
-  display: block;
-  background-color: #1b1d26;
-  color: white;
-  border-radius: 5px;
-  font-family: monospace;
-  user-select: text;
-  max-height: 400px;
-  width: 90%;
-  margin-left: 5%;
-  margin-top: 20px;
-  overflow-x: hidden;
-  overflow-y: auto;
-  padding: 10px;
-  overflow-wrap: break-word;
-`;

+ 0 - 94
dashboard/src/legacy/main/Main.tsx

@@ -1,94 +0,0 @@
-import React, { useContext, useEffect, useState } from "react";
-import Loading from "legacy/components/Loading";
-import api from "legacy/shared/api";
-import { PorterUrls, type PorterUrl } from "legacy/shared/routing";
-import { Redirect, Route, Switch } from "react-router-dom";
-
-import { Context } from "shared/Context";
-
-import { useAuthn } from "../shared/auth/AuthnContext";
-import CurrentError from "./CurrentError";
-import Home from "./home/Home";
-
-type PropsType = {};
-
-const Main: React.FC<PropsType> = () => {
-  const {
-    currentError,
-    setCurrentError,
-    setEdition,
-    setEnableGitlab,
-    currentProject,
-    currentCluster,
-  } = useContext(Context);
-  const { handleLogOut } = useAuthn();
-  const [version, setVersion] = useState("");
-
-  useEffect(() => {
-    // Get capabilities to case on user info requirements
-    api
-      .getMetadata("", {}, {})
-      .then((res) => {
-        setVersion(res.data?.version);
-      })
-      .catch(() => {});
-
-    const urlParams = new URLSearchParams(window.location.search);
-    const error = urlParams.get("error");
-    error && setCurrentError(error);
-
-    api
-      .getMetadata("", {}, {})
-      .then((res) => {
-        setEdition(res.data?.version);
-        setEnableGitlab(!!res.data?.gitlab);
-      })
-      .catch(() => {});
-  }, []);
-
-  const renderMain = (): JSX.Element => {
-    if (!version) {
-      return <Loading />;
-    }
-
-    return (
-      <Switch>
-        <Route
-          exact
-          path="/"
-          render={() => {
-            return <Redirect to="/dashboard" />;
-          }}
-        />
-        <Route
-          path={`/:baseRoute/:cluster?/:namespace?`}
-          render={(routeProps) => {
-            const baseRoute = routeProps.match.params.baseRoute;
-            if (PorterUrls.includes(baseRoute)) {
-              return (
-                <Home
-                  key="home"
-                  currentProject={currentProject}
-                  currentCluster={currentCluster}
-                  currentRoute={baseRoute as PorterUrl}
-                  logOut={handleLogOut}
-                />
-              );
-            } else {
-              return <Redirect to="/" />;
-            }
-          }}
-        />
-      </Switch>
-    );
-  };
-
-  return (
-    <>
-      {renderMain()}
-      <CurrentError currentError={currentError} />
-    </>
-  );
-};
-
-export default Main;

+ 0 - 39
dashboard/src/legacy/main/MainWrapper.tsx

@@ -1,39 +0,0 @@
-import React from "react";
-import { IntlProvider, ThemeProvider } from "@ory/elements";
-import MainWrapperErrorBoundary from "legacy/shared/error_handling/MainWrapperErrorBoundary";
-import { withRouter, type RouteComponentProps } from "react-router";
-
-import AuthzProvider from "shared/auth/AuthzContext";
-
-import AuthnProvider from "../shared/auth/AuthnContext";
-import { ContextProvider } from "shared/Context";
-import Main from "./Main";
-// required styles for Ory Elements
-import "@ory/elements/style.css";
-
-type PropsType = RouteComponentProps;
-
-const themeOverrides = {
-  fontFamily: '"Work Sans", sans-serif',
-  // other theme properties...
-};
-
-const MainWrapper: React.FC<PropsType> = ({ history, location }) => {
-  return (
-    <ContextProvider history={history} location={location}>
-      <ThemeProvider themeOverrides={themeOverrides}>
-        <IntlProvider locale="en" defaultLocale="en">
-          <AuthzProvider>
-            <AuthnProvider>
-              <MainWrapperErrorBoundary>
-                <Main />
-              </MainWrapperErrorBoundary>
-            </AuthnProvider>
-          </AuthzProvider>
-        </IntlProvider>
-      </ThemeProvider>
-    </ContextProvider>
-  );
-};
-
-export default withRouter(MainWrapper);

+ 0 - 265
dashboard/src/legacy/shared/Context.tsx

@@ -1,265 +0,0 @@
-import React, { Component } from "react";
-import { pushQueryParams } from "legacy/shared/routing";
-import {
-  NilCluster,
-  type CapabilityType,
-  type ClusterType,
-  type ContextProps,
-  type ProjectListType,
-  type ProjectType,
-  type UsageData,
-} from "legacy/shared/types";
-
-import api from "./api";
-
-const Context = React.createContext<Partial<ContextProps>>(null);
-
-const { Provider } = Context;
-const ContextConsumer = Context.Consumer;
-
-type PropsType = {
-  history: any;
-  location: any;
-};
-
-type StateType = GlobalContextType;
-
-export type GlobalContextType = {
-  currentModal: string;
-  currentModalData: any;
-  setCurrentModal: (currentModal: string, currentModalData?: any) => void;
-  currentOverlay: {
-    message: string;
-    onYes: any;
-    onNo: any;
-  };
-  setCurrentOverlay: (x: any) => void;
-  currentError: string | null;
-  setCurrentError: (currentError: string) => void;
-  currentCluster: ClusterType;
-  setCurrentCluster: (currentCluster: ClusterType, callback?: any) => void;
-  currentProject: ProjectType | null;
-  setCurrentProject: (
-    currentProject: ProjectType,
-    callback?: () => void
-  ) => void;
-  projects: ProjectListType[];
-  setProjects: (projects: ProjectListType[]) => void;
-  user: any;
-  setUser: (userId: number, email: string) => void;
-  devOpsMode: boolean;
-  setDevOpsMode: (devOpsMode: boolean) => void;
-  capabilities: CapabilityType;
-  setCapabilities: (capabilities: CapabilityType) => void;
-  clearContext: () => void;
-  edition: "ee" | "ce";
-  setEdition: (appVersion: string) => void;
-  hasBillingEnabled: boolean;
-  setHasBillingEnabled: (isBillingEnabled: boolean) => void;
-  usage: UsageData;
-  setUsage: (usage: UsageData) => void;
-  queryUsage: (retry?: number) => Promise<void>;
-  hasFinishedOnboarding: boolean;
-  setHasFinishedOnboarding: (onboardingStatus: boolean) => void;
-  canCreateProject: boolean;
-  setCanCreateProject: (canCreateProject: boolean) => void;
-  enableGitlab: boolean;
-  setEnableGitlab: (enableGitlab: boolean) => void;
-  shouldRefreshClusters: boolean;
-  setShouldRefreshClusters: (shouldRefreshClusters: boolean) => void;
-  featurePreview: boolean;
-  setFeaturePreview: (featurePreview: boolean) => void;
-  soc2Data: any;
-  setSoc2Data: (x: any) => void;
-};
-
-/**
- * Component managing a universal (application-wide) data store.
- *
- * Important Usage Notes:
- * 1) Each field must have an accompanying setter
- * 2) No function calls are allowed from within Context (not counting
- *    initialization)
- * 3) Context should be used as a last-resort (changes will re-render ALL
- *    components consuming Context)
- * 4) As a rule of thumb, Context should not be used for UI-related state
- */
-class ContextProvider extends Component<PropsType, StateType> {
-  state: GlobalContextType = {
-    currentModal: null,
-    currentModalData: null,
-    setCurrentModal: (currentModal: string, currentModalData?: any) => {
-      this.setState({ currentModal, currentModalData });
-    },
-    currentOverlay: null,
-    setCurrentOverlay: (x: any) => {
-      this.setState({ currentOverlay: x });
-    },
-    currentError: null,
-    setCurrentError: (currentError: string) => {
-      this.setState({ currentError });
-    },
-    currentCluster: NilCluster,
-    setCurrentCluster: (currentCluster: ClusterType, callback?: any) => {
-      localStorage.setItem(
-        this.state.currentProject.id + "-cluster",
-        JSON.stringify(currentCluster)
-      );
-      this.setState({ currentCluster }, () => {
-        callback?.();
-      });
-      if (window.intercomSettings) {
-        window.intercomSettings["Cluster ID"] = currentCluster.id;
-      }
-    },
-    currentProject: null,
-    setCurrentProject: (currentProject: ProjectType, callback?: any) => {
-      if (currentProject) {
-        localStorage.setItem("currentProject", currentProject.id.toString());
-        pushQueryParams(this.props, {
-          project_id: currentProject.id.toString(),
-        });
-      } else {
-        localStorage.removeItem("currentProject");
-      }
-      this.setState({ currentProject }, () => {
-        callback?.();
-      });
-      if (window.intercomSettings) {
-        window.intercomSettings["Project ID"] = currentProject.id;
-        window.intercomSettings.project_id = currentProject.id;
-      }
-    },
-    projects: [],
-    setProjects: (projects: ProjectListType[]) => {
-      projects.sort((a: any, b: any) => (a.name > b.name ? 1 : -1));
-      this.setState({ projects });
-    },
-    user: null,
-    setUser: (userId: number, email: string) => {
-      this.setState({
-        user: { userId, email, isPorterUser: email?.endsWith("@porter.run") },
-      });
-      if (window.intercomSettings) {
-        window.intercomSettings["Porter User ID"] = userId;
-        window.intercomSettings["Porter User Email"] = email;
-      }
-    },
-    devOpsMode: true,
-    setDevOpsMode: (devOpsMode: boolean) => {
-      this.setState({ devOpsMode });
-    },
-    capabilities: null,
-    setCapabilities: (capabilities: CapabilityType) => {
-      this.setState({ capabilities });
-    },
-    clearContext: () => {
-      this.setState({
-        currentModal: null,
-        currentModalData: null,
-        currentError: null,
-        currentCluster: null,
-        currentProject: null,
-        projects: [],
-        user: null,
-        devOpsMode: true,
-      });
-    },
-    edition: "ce",
-    setEdition: (version: string) => {
-      const [edition] = version.split("-").reverse();
-      // typesafe just in case we mess up something it will default to ce
-      if (edition === "ce" || edition === "ee") {
-        this.setState({ edition });
-      }
-    },
-    hasBillingEnabled: false,
-    setHasBillingEnabled: (isBillingEnabled: boolean) => {
-      this.setState({ hasBillingEnabled: isBillingEnabled });
-    },
-    usage: null,
-    setUsage: (usage: UsageData) => {
-      this.setState({ usage });
-    },
-    queryUsage: async (retry: number = 0) => {
-      api
-        .getUsage("<token>", {}, { project_id: this.state?.currentProject?.id })
-        .then((res) => {
-          if (JSON.stringify(res.data) !== JSON.stringify(this.state.usage)) {
-            this.state.setUsage(res.data);
-          } else {
-            if (retry < 10) {
-              setTimeout(() => {
-                this.state.queryUsage(retry + 1);
-              }, 1000);
-            }
-          }
-        });
-    },
-    hasFinishedOnboarding: false,
-    setHasFinishedOnboarding: (onboardingStatus) => {
-      this.setState({ hasFinishedOnboarding: onboardingStatus });
-    },
-    canCreateProject: false,
-    setCanCreateProject: (canCreateProject: boolean) => {
-      this.setState({ canCreateProject });
-    },
-    enableGitlab: false,
-    setEnableGitlab: (enableGitlab) => {
-      this.setState({ enableGitlab });
-    },
-    shouldRefreshClusters: false,
-    setShouldRefreshClusters: (shouldRefreshClusters) => {
-      this.setState({ shouldRefreshClusters });
-    },
-    featurePreview: false,
-    setFeaturePreview: (featurePreview) => {
-      this.setState({ featurePreview });
-    },
-    soc2Data: {
-      preflight_checks: {
-        "Public SSH Access": {
-          message:
-            "Porter-provisioned instances do not allow remote SSH access. Users are not allowed to invoke commands directly on the host, and all commands are invoked via the EKS Control Plane.",
-          enabled: true,
-          hideToggle: true,
-          status: "ENABLED",
-        },
-        "Cluster Secret Encryption": {
-          message:
-            "Cluster secrets can be encrypted using an AWS KMS Key. Secrets will be encrypted at rest, and encryption cannot be disabled for secrets.",
-          enabled: false,
-          disabledTooltip:
-            "Enable KMS encryption for the cluster to enable SOC 2 compliance.",
-          link: "https://aws.amazon.com/about-aws/whats-new/2020/03/amazon-eks-adds-envelope-encryption-for-secrets-with-aws-kms/",
-          locked: true,
-          status: "",
-        },
-        "Control Plane Log Retention": {
-          message:
-            "EKS Control Plane logs are by default available for a minimal amount of time, typically 1 hour or less. EKS CloudTrail Forwarding automatically sends control plane logs to CloudTrail for longer retention and later inspection.",
-          enabled: false,
-          enabledField: "Retain CloudTrail logs for 365 days",
-          status: "",
-        },
-        "Enhanced Image Vulnerability Scanning": {
-          message:
-            "AWS ECR scans for CVEs from the open-source Clair database on image push. Enhanced scanning provides continuous, automated scans against images as new vulnerabilities appear.",
-          link: "https://docs.aws.amazon.com/AmazonECR/latest/userguide/image-scanning-enhanced.html",
-          enabled: false,
-          info: "",
-          status: "",
-        },
-      },
-    },
-    setSoc2Data: (soc2Data) => {
-      localStorage.setItem("soc2Data", JSON.stringify(soc2Data));
-    },
-  };
-
-  render() {
-    return <Provider value={{ ...this.state }}>{this.props.children}</Provider>;
-  }
-}
-
-export { Context, ContextConsumer, ContextProvider };

+ 0 - 153
dashboard/src/legacy/shared/DeploymentTargetContext.tsx

@@ -1,153 +0,0 @@
-import React, { createContext, useContext, useEffect, useMemo } from "react";
-import { useQuery } from "@tanstack/react-query";
-import {
-  deploymentTargetValidator,
-  useDefaultDeploymentTarget,
-  type DeploymentTarget,
-} from "legacy/lib/hooks/useDeploymentTarget";
-import { useLocation } from "react-router";
-import { z } from "zod";
-
-import api from "./api";
-import { Context } from "./Context";
-import { clusterValidator } from "./types";
-
-export const DeploymentTargetContext = createContext<{
-  currentDeploymentTarget: DeploymentTarget | null;
-} | null>(null);
-
-export const useDeploymentTarget = (): {
-  currentDeploymentTarget: DeploymentTarget | null;
-} => {
-  const context = useContext(DeploymentTargetContext);
-  if (context === null) {
-    throw new Error(
-      "useDeploymentTarget must be used within a DeploymentTargetContext"
-    );
-  }
-  return context;
-};
-
-const DeploymentTargetProvider = ({
-  children,
-}: {
-  children: JSX.Element;
-}): JSX.Element => {
-  const location = useLocation();
-  const { currentProject, currentCluster, setCurrentCluster } =
-    useContext(Context);
-
-  const deploymentTargetID = useMemo(() => {
-    const queryParams = new URLSearchParams(location.search);
-    return queryParams.get("target");
-  }, [location.search]);
-
-  const { defaultDeploymentTarget, isDefaultDeploymentTargetLoading } =
-    useDefaultDeploymentTarget();
-
-  const { data: deploymentTargetFromIdParam, status } = useQuery(
-    [
-      "getDeploymentTarget",
-      {
-        project_id: currentProject?.id,
-        deployment_target_id: deploymentTargetID,
-      },
-    ],
-    async () => {
-      if (!currentProject || !deploymentTargetID) {
-        return;
-      }
-      const res = await api.getDeploymentTarget(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          deployment_target_id: deploymentTargetID,
-        }
-      );
-
-      const deploymentTarget = await z
-        .object({ deployment_target: deploymentTargetValidator })
-        .parseAsync(res.data);
-
-      return deploymentTarget.deployment_target;
-    },
-    {
-      enabled: !!currentProject && !!deploymentTargetID,
-    }
-  );
-
-  const deploymentTarget: DeploymentTarget | null = useMemo(() => {
-    if (!deploymentTargetID && isDefaultDeploymentTargetLoading) {
-      return null;
-    }
-
-    if (deploymentTargetID) {
-      if (status === "loading" || !deploymentTargetFromIdParam) {
-        return null;
-      }
-
-      return deploymentTargetFromIdParam;
-    }
-
-    if (defaultDeploymentTarget) {
-      return defaultDeploymentTarget;
-    }
-
-    return null;
-  }, [
-    deploymentTargetID,
-    isDefaultDeploymentTargetLoading,
-    defaultDeploymentTarget,
-    deploymentTargetFromIdParam,
-    status,
-  ]);
-
-  const { data: cluster, isSuccess } = useQuery(
-    [
-      "getDeploymentTargetCluster",
-      {
-        project_id: currentProject?.id,
-        cluster_id: deploymentTarget?.cluster_id,
-      },
-    ],
-    async () => {
-      if (!currentProject || !deploymentTarget) {
-        return;
-      }
-      const { data } = await api.getCluster(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          cluster_id: deploymentTarget?.cluster_id,
-        }
-      );
-
-      const cluster = await clusterValidator.parseAsync(data);
-
-      return cluster;
-    },
-    {
-      enabled: !!currentProject && !!deploymentTargetID,
-    }
-  );
-
-  useEffect(() => {
-    if (cluster && cluster.id !== currentCluster?.id && setCurrentCluster) {
-      setCurrentCluster(cluster);
-    }
-  }, [isSuccess, cluster, setCurrentCluster]);
-
-  return (
-    <DeploymentTargetContext.Provider
-      value={{
-        currentDeploymentTarget: deploymentTarget,
-      }}
-    >
-      {children}
-    </DeploymentTargetContext.Provider>
-  );
-};
-
-export default DeploymentTargetProvider;

+ 0 - 134
dashboard/src/legacy/shared/ansiparser.tsx

@@ -1,134 +0,0 @@
-/* eslint-disable no-plusplus, no-continue */
-const foregroundColors = {
-  "30": "black",
-  "31": "red",
-  "32": "green",
-  "33": "yellow",
-  "34": "blue",
-  "35": "magenta",
-  "36": "cyan",
-  "37": "white",
-  "90": "grey",
-} as Record<string, string>;
-
-const backgroundColors = {
-  "40": "black",
-  "41": "red",
-  "42": "green",
-  "43": "yellow",
-  "44": "blue",
-  "45": "magenta",
-  "46": "cyan",
-  "47": "white",
-} as Record<string, string>;
-
-const styles = {
-  "1": "bold",
-  "3": "italic",
-  "4": "underline",
-} as Record<string, string>;
-
-const eraseChar = (matchingText: any, result: any) => {
-  if (matchingText.length) {
-    return [matchingText.substr(0, matchingText.length - 1), result];
-  } else if (result.length) {
-    const index = result.length - 1;
-    const { text } = result[index];
-    const newResult =
-      text.length === 1
-        ? result.slice(0, result.length - 1)
-        : result.map((item: any, i: number) =>
-            index === i
-              ? { ...item, text: text.substr(0, text.length - 1) }
-              : item
-          );
-
-    return [matchingText, newResult];
-  }
-
-  return [matchingText, result];
-};
-
-const ansiparse = (str: string) => {
-  let matchingControl = null;
-  let matchingData = null;
-  let matchingText = "";
-  let ansiState = [] as any[];
-  let result = [] as any[];
-  let state = {} as any;
-
-  for (let i = 0; i < str.length; i++) {
-    if (matchingControl !== null) {
-      if (matchingControl === "\x1b" && str[i] === "[") {
-        if (matchingText) {
-          state.text = matchingText;
-          result.push(state);
-          state = {};
-          matchingText = "";
-        }
-
-        matchingControl = null;
-        matchingData = "";
-      } else {
-        matchingText += matchingControl + str[i];
-        matchingControl = null;
-      }
-
-      continue;
-    } else if (matchingData !== null) {
-      if (str[i] === ";") {
-        ansiState.push(matchingData);
-        matchingData = "";
-      } else if (str[i] === "m") {
-        ansiState.push(matchingData);
-        matchingData = null;
-        matchingText = "";
-
-        for (let a = 0; a < ansiState.length; a++) {
-          const ansiCode = ansiState[a];
-
-          if (foregroundColors[ansiCode]) {
-            state.foreground = foregroundColors[ansiCode];
-          } else if (backgroundColors[ansiCode]) {
-            state.background = backgroundColors[ansiCode];
-          } else if (ansiCode === 39) {
-            delete state.foreground;
-          } else if (ansiCode === 49) {
-            delete state.background;
-          } else if (styles[ansiCode]) {
-            state[styles[ansiCode]] = true;
-          } else if (ansiCode === 22) {
-            state.bold = false;
-          } else if (ansiCode === 23) {
-            state.italic = false;
-          } else if (ansiCode === 24) {
-            state.underline = false;
-          }
-        }
-
-        ansiState = [];
-      } else {
-        matchingData += str[i];
-      }
-
-      continue;
-    }
-
-    if (str[i] === "\x1b") {
-      matchingControl = str[i];
-    } else if (str[i] === "\u0008") {
-      [matchingText, result] = eraseChar(matchingText, result);
-    } else {
-      matchingText += str[i];
-    }
-  }
-
-  if (matchingText) {
-    state.text = matchingText + (matchingControl || "");
-    result.push(state);
-  }
-
-  return result;
-};
-
-export default ansiparse;

+ 0 - 1
dashboard/src/legacy/shared/regex.tsx

@@ -1 +0,0 @@
-export const emailRegex = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

+ 0 - 17
dashboard/src/legacy/utils/ip.ts

@@ -1,17 +0,0 @@
-import {z} from "zod";
-
-export const isIP = (value: string): boolean => {
-    const ip = z.string().ip();
-
-    const parsed = ip.safeParse(value);
-
-    return parsed.success;
-};
-
-export const stringifiedDNSRecordType = (value: string): string => {
-    if (isIP(value)) {
-       return "an A record"
-    } else {
-        return "a CNAME record"
-    }
-};

+ 0 - 134
dashboard/src/shared/ansiparser.tsx

@@ -1,134 +0,0 @@
-/* eslint-disable no-plusplus, no-continue */
-const foregroundColors = {
-  "30": "black",
-  "31": "red",
-  "32": "green",
-  "33": "yellow",
-  "34": "blue",
-  "35": "magenta",
-  "36": "cyan",
-  "37": "white",
-  "90": "grey",
-} as Record<string, string>;
-
-const backgroundColors = {
-  "40": "black",
-  "41": "red",
-  "42": "green",
-  "43": "yellow",
-  "44": "blue",
-  "45": "magenta",
-  "46": "cyan",
-  "47": "white",
-} as Record<string, string>;
-
-const styles = {
-  "1": "bold",
-  "3": "italic",
-  "4": "underline",
-} as Record<string, string>;
-
-const eraseChar = (matchingText: any, result: any) => {
-  if (matchingText.length) {
-    return [matchingText.substr(0, matchingText.length - 1), result];
-  } else if (result.length) {
-    const index = result.length - 1;
-    const { text } = result[index];
-    const newResult =
-      text.length === 1
-        ? result.slice(0, result.length - 1)
-        : result.map((item: any, i: number) =>
-            index === i
-              ? { ...item, text: text.substr(0, text.length - 1) }
-              : item
-          );
-
-    return [matchingText, newResult];
-  }
-
-  return [matchingText, result];
-};
-
-const ansiparse = (str: string) => {
-  let matchingControl = null;
-  let matchingData = null;
-  let matchingText = "";
-  let ansiState = [] as any[];
-  let result = [] as any[];
-  let state = {} as any;
-
-  for (let i = 0; i < str.length; i++) {
-    if (matchingControl !== null) {
-      if (matchingControl === "\x1b" && str[i] === "[") {
-        if (matchingText) {
-          state.text = matchingText;
-          result.push(state);
-          state = {};
-          matchingText = "";
-        }
-
-        matchingControl = null;
-        matchingData = "";
-      } else {
-        matchingText += matchingControl + str[i];
-        matchingControl = null;
-      }
-
-      continue;
-    } else if (matchingData !== null) {
-      if (str[i] === ";") {
-        ansiState.push(matchingData);
-        matchingData = "";
-      } else if (str[i] === "m") {
-        ansiState.push(matchingData);
-        matchingData = null;
-        matchingText = "";
-
-        for (let a = 0; a < ansiState.length; a++) {
-          const ansiCode = ansiState[a];
-
-          if (foregroundColors[ansiCode]) {
-            state.foreground = foregroundColors[ansiCode];
-          } else if (backgroundColors[ansiCode]) {
-            state.background = backgroundColors[ansiCode];
-          } else if (ansiCode === 39) {
-            delete state.foreground;
-          } else if (ansiCode === 49) {
-            delete state.background;
-          } else if (styles[ansiCode]) {
-            state[styles[ansiCode]] = true;
-          } else if (ansiCode === 22) {
-            state.bold = false;
-          } else if (ansiCode === 23) {
-            state.italic = false;
-          } else if (ansiCode === 24) {
-            state.underline = false;
-          }
-        }
-
-        ansiState = [];
-      } else {
-        matchingData += str[i];
-      }
-
-      continue;
-    }
-
-    if (str[i] === "\x1b") {
-      matchingControl = str[i];
-    } else if (str[i] === "\u0008") {
-      [matchingText, result] = eraseChar(matchingText, result);
-    } else {
-      matchingText += str[i];
-    }
-  }
-
-  if (matchingText) {
-    state.text = matchingText + (matchingControl || "");
-    result.push(state);
-  }
-
-  return result;
-};
-
-export default ansiparse;

+ 0 - 10
dashboard/src/shared/array_utils.ts

@@ -1,10 +0,0 @@
-export function onlyInLeft<T>(
-  left: Array<T>,
-  right: Array<T>,
-  compareFunction: (leftValue: T, rightValue: T) => boolean
-): Array<T> {
-  return left.filter(
-    (leftValue) =>
-      !right.some((rightValue) => compareFunction(leftValue, rightValue))
-  );
-}

+ 0 - 326
dashboard/src/shared/hooks/useChart.ts

@@ -1,326 +0,0 @@
-import yaml from "js-yaml";
-import { useContext, useEffect, useState } from "react";
-import { useRouteMatch } from "react-router";
-import api from "shared/api";
-import { onlyInLeft } from "shared/array_utils";
-import { Context } from "shared/Context";
-import { useRouting } from "shared/routing";
-import { ChartType, ChartTypeWithExtendedConfig } from "shared/types";
-
-export const useChart = (oldChart: ChartType, closeChart: () => void) => {
-  const { currentProject, currentCluster, setCurrentError } = useContext(
-    Context
-  );
-  const [chart, setChart] = useState<ChartTypeWithExtendedConfig>(null);
-  const { url: matchUrl } = useRouteMatch();
-
-  const [status, setStatus] = useState<"ready" | "loading" | "deleting">(
-    "loading"
-  );
-
-  const [saveStatus, setSaveStatus] = useState<
-    "loading" | "successful" | string
-  >("");
-
-  const { pushFiltered, getQueryParam, pushQueryParams } = useRouting();
-
-  useEffect(() => {
-    const { namespace, name: chartName } = oldChart;
-    setStatus("loading");
-
-    const revision = getQueryParam("chart_revision");
-
-    api
-      .getChart<ChartTypeWithExtendedConfig>(
-        "token",
-        {},
-        {
-          id: currentProject?.id,
-          cluster_id: currentCluster?.id,
-          namespace,
-          name: chartName,
-          revision: Number(revision) ? Number(revision) : 0,
-        }
-      )
-      .then((res) => {
-        if (res?.data) {
-          setChart(res.data);
-        }
-      })
-      .finally(() => {
-        setStatus("ready");
-      });
-  }, [oldChart, currentCluster, currentProject]);
-
-  /**
-   * Upgrade chart version
-   */
-  const upgradeChart = async () => {
-    // convert current values to yaml
-    let valuesYaml = yaml.dump({
-      ...(chart.config as Object),
-    });
-
-    try {
-      await api.upgradeChartValues(
-        "<token>",
-        {
-          values: valuesYaml,
-          version: chart.latest_version,
-          latest_revision: chart.version,
-        },
-        {
-          id: currentProject.id,
-          name: chart.name,
-          namespace: chart.namespace,
-          cluster_id: currentCluster.id,
-        }
-      );
-
-      window.analytics?.track("Chart Upgraded", {
-        chart: chart.name,
-        values: valuesYaml,
-      });
-    } catch (err) {
-      let parsedErr = err?.response?.data?.error;
-
-      if (parsedErr) {
-        err = parsedErr;
-      }
-      setCurrentError(parsedErr);
-
-      window.analytics?.track("Failed to Upgrade Chart", {
-        chart: chart.name,
-        values: valuesYaml,
-        error: err,
-      });
-    }
-  };
-
-  const uninstallChart = async () => {
-    if (chart.stack_id) {
-      await api.removeStackAppResource(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          cluster_id: currentCluster.id,
-          app_resource_name: chart.name,
-          namespace: chart.namespace,
-          stack_id: chart.stack_id,
-        }
-      );
-    } else {
-      await api.uninstallTemplate(
-        "<token>",
-        {},
-        {
-          namespace: chart.namespace,
-          name: chart.name,
-          id: currentProject.id,
-          cluster_id: currentCluster.id,
-        }
-      );
-    }
-  };
-
-  /**
-   * Delete/Uninstall chart
-   */
-  const deleteChart = async () => {
-    setStatus("deleting");
-    try {
-      const syncedEnvGroups = chart.config?.container?.env?.synced || [];
-      const removeApplicationToEnvGroupPromises = syncedEnvGroups.map(
-        (envGroup: any) => {
-          return api.removeApplicationFromEnvGroup(
-            "<token>",
-            {
-              name: envGroup?.name,
-              app_name: chart.name,
-            },
-            {
-              project_id: currentProject.id,
-              cluster_id: currentCluster.id,
-              namespace: chart.namespace,
-            }
-          );
-        }
-      );
-      try {
-        await Promise.all(removeApplicationToEnvGroupPromises);
-      } catch (error) {
-        setCurrentError(
-          "We coudln't remove the synced env group from the application, please remove it manually before uninstalling the chart, or try again."
-        );
-        return;
-      }
-
-      await uninstallChart();
-
-      setStatus("ready");
-      closeChart();
-      return;
-    } catch (error) {
-      console.log(error);
-      throw new Error("Couldn't uninstall the chart");
-    }
-  };
-
-  /**
-   * Update chart values
-   */
-  const updateChart = async (
-    processValues: (
-      chart: ChartType,
-      oldChart?: ChartType
-    ) => { yaml: string; metadata: any }
-  ) => {
-    setSaveStatus("loading");
-    const { yaml: values, metadata } = processValues(chart, oldChart);
-
-    const syncEnvGroups = metadata ? metadata["container.env"] : {};
-
-    const addedEnvGroups = syncEnvGroups?.added || [];
-    const deletedEnvGroups = syncEnvGroups?.deleted || [];
-
-    const addApplicationToEnvGroupPromises = addedEnvGroups.map(
-      (envGroup: any) => {
-        return api.addApplicationToEnvGroup(
-          "<token>",
-          {
-            name: envGroup?.name,
-            app_name: chart.name,
-          },
-          {
-            project_id: currentProject.id,
-            cluster_id: currentCluster.id,
-            namespace: chart.namespace,
-          }
-        );
-      }
-    );
-
-    try {
-      await Promise.all(addApplicationToEnvGroupPromises);
-    } catch (error) {
-      setCurrentError(
-        "We coudln't sync the env group to the application, please try again."
-      );
-    }
-
-    const removeApplicationToEnvGroupPromises = deletedEnvGroups.map(
-      (envGroup: any) => {
-        return api.removeApplicationFromEnvGroup(
-          "<token>",
-          {
-            name: envGroup?.name,
-            app_name: chart.name,
-          },
-          {
-            project_id: currentProject.id,
-            cluster_id: currentCluster.id,
-            namespace: chart.namespace,
-          }
-        );
-      }
-    );
-    try {
-      await Promise.all(removeApplicationToEnvGroupPromises);
-    } catch (error) {
-      setCurrentError(
-        "We coudln't remove the synced env group from the application, please try again."
-      );
-    }
-
-    try {
-      await api.upgradeChartValues(
-        "<token>",
-        {
-          values,
-          latest_revision: chart.version,
-        },
-        {
-          id: currentProject.id,
-          name: chart.name,
-          namespace: chart.namespace,
-          cluster_id: currentCluster.id,
-        }
-      );
-
-      setSaveStatus("successful");
-      setTimeout(() => setSaveStatus(""), 500);
-    } catch (err) {
-      let parsedErr = err?.response?.data?.error;
-
-      if (!parsedErr) {
-        parsedErr = err;
-      }
-      setCurrentError(parsedErr);
-      setSaveStatus("Couldn't process the request.");
-      // throw new Error(parsedErr);
-    }
-  };
-
-  /**
-   * Refresh the chart data
-   */
-  const refreshChart = async () => {
-    try {
-      const newChart = await api
-        .getChart(
-          "<token>",
-          {},
-          {
-            name: chart.name,
-            revision: 0,
-            namespace: chart.namespace,
-            cluster_id: currentCluster.id,
-            id: currentProject.id,
-          }
-        )
-        .then((res) => res.data);
-
-      pushQueryParams({
-        chart_version: newChart.version,
-      });
-
-      setChart(newChart);
-    } catch (error) {}
-  };
-
-  const loadChartWithSpecificRevision = async (revision: number) => {
-    try {
-      const newChart = await api
-        .getChart(
-          "<token>",
-          {},
-          {
-            name: chart.name,
-            revision: revision,
-            namespace: chart.namespace,
-            cluster_id: currentCluster.id,
-            id: currentProject.id,
-          }
-        )
-        .then((res) => res.data);
-
-      pushQueryParams({
-        chart_revision: newChart.version,
-      });
-
-      setChart(newChart);
-    } catch (error) {}
-  };
-
-  return {
-    chart,
-    status,
-    saveStatus,
-    upgradeChart,
-    deleteChart,
-    updateChart,
-    refreshChart,
-    loadChartWithSpecificRevision,
-  };
-};

+ 0 - 34
dashboard/src/shared/hooks/useEffectDebugger.ts

@@ -1,34 +0,0 @@
-import { useEffect } from "react";
-import { usePrevious } from "./usePrevious";
-
-export const useEffectDebugger = (
-  effectHook: any,
-  dependencies: any,
-  dependencyNames: any = []
-) => {
-  const previousDeps = usePrevious(dependencies, []);
-
-  const changedDeps = dependencies.reduce(
-    (accum: any, dependency: any, index: any) => {
-      if (dependency !== previousDeps[index]) {
-        const keyName = dependencyNames[index] || index;
-        return {
-          ...accum,
-          [keyName]: {
-            before: previousDeps[index],
-            after: dependency,
-          },
-        };
-      }
-
-      return accum;
-    },
-    {}
-  );
-
-  if (Object.keys(changedDeps).length) {
-    // console.log("[use-effect-debugger] ", changedDeps);
-  }
-
-  useEffect(effectHook, dependencies);
-};

+ 0 - 103
dashboard/src/shared/hooks/usePagination.ts

@@ -1,103 +0,0 @@
-/**
- * Improved version using as base the usePagination hook by gh user @damiisdandy
- * Base hook on his repo https://github.com/damiisdandy/use-pagination
- */
-
-import { useState } from "react";
-
-interface UsePaginationProps {
-  count: number;
-  initialPageSize?: number;
-}
-
-interface UsePaginationReturn {
-  page: number;
-  totalPages: number;
-  setPage: (page: number) => void;
-  nextPage: () => void;
-  prevPage: () => void;
-  firstContentIndex: number;
-  lastContentIndex: number;
-  pageSize: number;
-  setPageSize: (pageSize: number) => void;
-  canNextPage: boolean;
-  canPreviousPage: boolean;
-}
-
-type UsePagination = (props: UsePaginationProps) => UsePaginationReturn;
-
-const usePagination: UsePagination = ({ count, initialPageSize }) => {
-  const [pageSize, setPageSize] = useState(() => {
-    if (typeof initialPageSize === "number" && initialPageSize !== NaN) {
-      return initialPageSize;
-    }
-
-    return 10;
-  });
-
-  const [page, setPage] = useState(1);
-  // number of pages in total (total items / content on each page)
-  const pageCount = Math.ceil(count / pageSize);
-  // index of last item of current page
-  const lastContentIndex = page * pageSize;
-  // index of first item of current page
-  const firstContentIndex = lastContentIndex - pageSize;
-
-  // change page based on direction either front or back
-  const changePage = (direction: boolean) => {
-    setPage((state) => {
-      // move forward
-      if (direction) {
-        // if page is the last page, do nothing
-        if (state === pageCount) {
-          return state;
-        }
-        return state + 1;
-        // go back
-      } else {
-        // if page is the first page, do nothing
-        if (state === 1) {
-          return state;
-        }
-        return state - 1;
-      }
-    });
-  };
-
-  const setPageSAFE = (num: number) => {
-    // if number is greater than number of pages, set to last page
-    if (num > pageCount) {
-      setPage(pageCount);
-      // if number is less than 1, set page to first page
-    } else if (num < 1) {
-      setPage(1);
-    } else {
-      setPage(num);
-    }
-  };
-
-  const setPageSizeSAFE = (pageSize: number) => {
-    if (typeof initialPageSize === "number" && initialPageSize !== NaN) {
-      setPageSize(pageSize);
-    }
-  };
-
-  const canNextPage = page <= pageCount - 1;
-  const canPreviousPage = page > 1;
-
-  return {
-    totalPages: pageCount,
-    nextPage: () => changePage(true),
-    prevPage: () => changePage(false),
-    setPage: setPageSAFE,
-    firstContentIndex,
-    lastContentIndex,
-    page,
-    pageSize,
-    setPageSize: setPageSizeSAFE,
-    canNextPage,
-    canPreviousPage,
-  };
-};
-
-export default usePagination;

+ 0 - 143
dashboard/src/shared/hooks/usePods.ts

@@ -1,143 +0,0 @@
-import { useEffect, useState } from "react";
-import api from "shared/api";
-import { NewWebsocketOptions, useWebsockets } from "./useWebsockets";
-
-interface Props {
-  selectors: string[];
-  namespace: string;
-  project_id: number;
-  cluster_id: number;
-  controller_kind?: string;
-  controller_name?: string;
-  // subscribed controls whether or not pods should be returned from this hook. for example, we
-  // use this hook to query a list of job runs, but only want to return pods (and live status)
-  // for job runs which are currently active. as we don't want to mess with conditional hooks,
-  // we simply toggle "subscribed" instead
-  subscribed?: boolean;
-}
-
-type UsePods = (props: Props) => [pods: any[], isLoading: boolean];
-
-export const usePods: UsePods = ({
-  selectors,
-  namespace,
-  project_id,
-  cluster_id,
-  controller_kind,
-  controller_name,
-  subscribed,
-}) => {
-  const [pods, setPods] = useState([]);
-  const [isLoading, setIsLoading] = useState(true);
-
-  const {
-    newWebsocket,
-    openWebsocket,
-    closeAllWebsockets,
-    closeWebsocket,
-  } = useWebsockets();
-
-  const setupWebsocket = () => {
-    let apiEndpoint = `/api/projects/${project_id}/clusters/${cluster_id}/pod/status?`;
-
-    if (selectors) {
-      for (let selector of selectors) {
-        apiEndpoint += `selectors=${selector}`;
-      }
-    }
-
-    const options: NewWebsocketOptions = {};
-
-    options.onopen = () => {
-      console.log("connected to websocket");
-    };
-
-    options.onmessage = (evt: MessageEvent) => {
-      let event = JSON.parse(evt.data);
-      let object = event.Object;
-      object.metadata.kind = event.Kind;
-
-      mergeAndUpdatePods(object);
-    };
-
-    options.onclose = () => {
-      console.log("closing websocket");
-    };
-
-    options.onerror = (err: ErrorEvent) => {
-      console.log(err);
-      closeWebsocket(apiEndpoint);
-    };
-
-    newWebsocket(apiEndpoint, apiEndpoint, options);
-    openWebsocket(apiEndpoint);
-  };
-
-  const mergeAndUpdatePods = (pod: any) => {
-    // find pods with the same name and namespace and overwrite them
-    let newPods = [...pods];
-    let assigned = false;
-
-    newPods.forEach((newPod, i) => {
-      if (
-        newPod.metadata.name == pod.metadata.name &&
-        newPod.metadata.namespace == pod.metadata.namespace
-      ) {
-        newPods[i] = pod;
-        assigned = true;
-      }
-    });
-
-    if (!assigned) {
-      newPods = [...newPods, pod];
-    }
-
-    setPods(newPods);
-  };
-
-  useEffect(() => {
-    if (!subscribed) {
-      return;
-    }
-    setIsLoading(true);
-    if (controller_kind == "job") {
-      api
-        .getJobPods(
-          "<token>",
-          {},
-          {
-            id: project_id,
-            name: controller_name,
-            cluster_id: cluster_id,
-            namespace: namespace,
-          }
-        )
-        .then((res) => {
-          setPods(res.data);
-          setIsLoading(false);
-        });
-    } else {
-      api
-        .getMatchingPods(
-          "<token>",
-          {
-            namespace: namespace,
-            selectors: selectors,
-          },
-          {
-            id: project_id,
-            cluster_id: cluster_id,
-          }
-        )
-        .then((res) => {
-          setPods(res.data);
-        });
-    }
-
-    setupWebsocket();
-
-    return () => closeAllWebsockets();
-  }, [project_id, cluster_id]);
-
-  return [pods, isLoading];
-};

+ 0 - 9
dashboard/src/shared/hooks/usePrevious.ts

@@ -1,9 +0,0 @@
-import { useEffect, useRef } from "react";
-
-export const usePrevious = (value: any, initialValue: any) => {
-  const ref = useRef(initialValue);
-  useEffect(() => {
-    ref.current = value;
-  });
-  return ref.current;
-};

+ 0 - 24
dashboard/src/shared/icons/MoonBase.tsx

@@ -1,24 +0,0 @@
-import React from "react";
-
-import { type IconProps } from "./types";
-
-const MoonBaseIcon: React.FC<IconProps> = ({ className, styles, fill }) => {
-  return (
-    <svg
-      viewBox="0 0 24 24"
-      xmlns="http://www.w3.org/2000/svg"
-      className={className}
-      style={styles}
-      fill={fill}
-    >
-      <path
-        d="M21.5999 14.6398C20.6977 14.9134 19.7404 15.0606 18.7487 15.0606C13.3307 15.0606 8.93856 10.6684 8.93856 5.25042C8.93856 4.2592 9.08557 3.30232 9.35897 2.40039C5.33153 3.62177 2.40002 7.36343 2.40002 11.7898C2.40002 17.2078 6.79218 21.5999 12.2102 21.5999C16.637 21.5999 20.3789 18.6679 21.5999 14.6398Z"
-        stroke="black"
-        strokeWidth="2"
-        strokeLinejoin="round"
-      />
-    </svg>
-  );
-};
-
-export default MoonBaseIcon;

+ 0 - 7
dashboard/src/shared/release/utils.ts

@@ -1,7 +0,0 @@
-import { ChartTypeWithExtendedConfig } from "shared/types";
-
-export const isDeployedFromGithub = (release: ChartTypeWithExtendedConfig) => {
-  const githubRepository = release?.git_action_config?.git_repo;
-
-  return !!githubRepository?.length;
-};

+ 0 - 18
dashboard/src/shared/themes/opal.ts

@@ -1,18 +0,0 @@
-const theme = {
-  bg: "#f3f5f8",
-  fg: "#ffffff",
-  fg2: "#ffffff11",
-  border: "#bbbbcc",
-  border2: "#9999aa",
-  button: "#3A48CA",
-  clickable: {
-    bg: "linear-gradient(180deg, #ffffff, #f3f5f8)",
-  },
-  modalBg: "#171B2111",
-  text: {
-    primary: "#414142",
-    helper: "#aaaabb",
-  },
-}
-
-export default theme;