فهرست منبع

Merge branch 'master' of https://github.com/porter-dev/porter

jusrhee 5 سال پیش
والد
کامیت
1dc3a02fd8
100فایلهای تغییر یافته به همراه902 افزوده شده و 642 حذف شده
  1. 0 6
      cmd/migrate/keyrotate/rotate.go
  2. 1 1
      dashboard/src/components/forms/VeleroForm.tsx
  3. 17 17
      dashboard/src/components/image-selector/ImageList.tsx
  4. 1 1
      dashboard/src/components/image-selector/ImageSelector.tsx
  5. 4 4
      dashboard/src/components/image-selector/TagList.tsx
  6. 2 2
      dashboard/src/components/repo-selector/ActionConfEditor.tsx
  7. 3 3
      dashboard/src/components/repo-selector/ActionDetails.tsx
  8. 4 4
      dashboard/src/components/repo-selector/BranchList.tsx
  9. 6 6
      dashboard/src/components/repo-selector/ContentsList.tsx
  10. 2 2
      dashboard/src/components/repo-selector/NewGHAction.tsx
  11. 54 51
      dashboard/src/components/repo-selector/RepoList.tsx
  12. 1 1
      dashboard/src/components/values-form/Base64InputRow.tsx
  13. 1 1
      dashboard/src/components/values-form/CheckboxList.tsx
  14. 1 1
      dashboard/src/components/values-form/Heading.tsx
  15. 1 1
      dashboard/src/components/values-form/InputRow.tsx
  16. 1 1
      dashboard/src/components/values-form/KeyValueArray.tsx
  17. 1 1
      dashboard/src/components/values-form/MultiSelect.tsx
  18. 3 3
      dashboard/src/components/values-form/ValuesForm.tsx
  19. 1 1
      dashboard/src/components/values-form/ValuesWrapper.tsx
  20. 6 6
      dashboard/src/main/auth/Login.tsx
  21. 6 6
      dashboard/src/main/auth/Register.tsx
  22. 9 9
      dashboard/src/main/auth/ResetPasswordFinalize.tsx
  23. 5 5
      dashboard/src/main/auth/ResetPasswordInit.tsx
  24. 4 6
      dashboard/src/main/auth/VerifyEmail.tsx
  25. 15 23
      dashboard/src/main/home/Home.tsx
  26. 7 7
      dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx
  27. 7 7
      dashboard/src/main/home/cluster-dashboard/NamespaceSelector.tsx
  28. 3 3
      dashboard/src/main/home/cluster-dashboard/SortSelector.tsx
  29. 2 2
      dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx
  30. 15 15
      dashboard/src/main/home/cluster-dashboard/chart/ChartList.tsx
  31. 39 39
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx
  32. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/GraphSection.tsx
  33. 3 3
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ListSection.tsx
  34. 9 9
      dashboard/src/main/home/cluster-dashboard/expanded-chart/RevisionSection.tsx
  35. 18 19
      dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx
  36. 5 5
      dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx
  37. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/deploy/DeploySection.tsx
  38. 3 3
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/Edge.tsx
  39. 19 19
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/GraphDisplay.tsx
  40. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/InfoPanel.tsx
  41. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/Node.tsx
  42. 2 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/SelectRegion.tsx
  43. 1 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/ZoomPanel.tsx
  44. 13 13
      dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/AreaChart.tsx
  45. 135 29
      dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx
  46. 8 8
      dashboard/src/main/home/cluster-dashboard/expanded-chart/status/ControllerTab.tsx
  47. 3 3
      dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx
  48. 5 5
      dashboard/src/main/home/cluster-dashboard/expanded-chart/status/StatusSection.tsx
  49. 3 3
      dashboard/src/main/home/dashboard/ClusterList.tsx
  50. 1 1
      dashboard/src/main/home/dashboard/ClusterPlaceholder.tsx
  51. 4 4
      dashboard/src/main/home/dashboard/Dashboard.tsx
  52. 13 9
      dashboard/src/main/home/integrations/IntegrationCategories.tsx
  53. 48 33
      dashboard/src/main/home/integrations/IntegrationList.tsx
  54. 6 9
      dashboard/src/main/home/integrations/IntegrationRow.tsx
  55. 4 4
      dashboard/src/main/home/integrations/Integrations.tsx
  56. 2 2
      dashboard/src/main/home/integrations/create-integration/DockerHubForm.tsx
  57. 4 4
      dashboard/src/main/home/integrations/create-integration/ECRForm.tsx
  58. 2 2
      dashboard/src/main/home/integrations/create-integration/EKSForm.tsx
  59. 8 8
      dashboard/src/main/home/integrations/create-integration/GCRForm.tsx
  60. 2 2
      dashboard/src/main/home/integrations/create-integration/GKEForm.tsx
  61. 2 2
      dashboard/src/main/home/integrations/edit-integration/DockerHubForm.tsx
  62. 4 4
      dashboard/src/main/home/integrations/edit-integration/ECRForm.tsx
  63. 2 2
      dashboard/src/main/home/integrations/edit-integration/EKSForm.tsx
  64. 8 8
      dashboard/src/main/home/integrations/edit-integration/GCRForm.tsx
  65. 2 2
      dashboard/src/main/home/integrations/edit-integration/GKEForm.tsx
  66. 8 8
      dashboard/src/main/home/launch/Launch.tsx
  67. 5 5
      dashboard/src/main/home/launch/expanded-template/ExpandedTemplate.tsx
  68. 38 38
      dashboard/src/main/home/launch/expanded-template/LaunchTemplate.tsx
  69. 1 1
      dashboard/src/main/home/launch/expanded-template/TemplateInfo.tsx
  70. 1 1
      dashboard/src/main/home/launch/hardcodedNameDict.tsx
  71. 2 2
      dashboard/src/main/home/modals/ClusterInstructionsModal.tsx
  72. 1 1
      dashboard/src/main/home/modals/IntegrationsInstructionsModal.tsx
  73. 7 7
      dashboard/src/main/home/modals/IntegrationsModal.tsx
  74. 9 10
      dashboard/src/main/home/modals/UpdateClusterModal.tsx
  75. 4 4
      dashboard/src/main/home/navbar/Feedback.tsx
  76. 2 2
      dashboard/src/main/home/navbar/Navbar.tsx
  77. 1 1
      dashboard/src/main/home/new-project/NewProject.tsx
  78. 17 18
      dashboard/src/main/home/project-settings/InviteList.tsx
  79. 18 3
      dashboard/src/main/home/project-settings/ProjectSettings.tsx
  80. 13 13
      dashboard/src/main/home/provisioner/AWSFormSection.tsx
  81. 7 7
      dashboard/src/main/home/provisioner/DOFormSection.tsx
  82. 4 4
      dashboard/src/main/home/provisioner/ExistingClusterSection.tsx
  83. 12 12
      dashboard/src/main/home/provisioner/GCPFormSection.tsx
  84. 1 1
      dashboard/src/main/home/provisioner/InfraStatuses.tsx
  85. 4 4
      dashboard/src/main/home/provisioner/Provisioner.tsx
  86. 4 4
      dashboard/src/main/home/provisioner/ProvisionerLogs.tsx
  87. 5 5
      dashboard/src/main/home/provisioner/ProvisionerSettings.tsx
  88. 10 5
      dashboard/src/main/home/sidebar/ClusterSection.tsx
  89. 1 1
      dashboard/src/main/home/sidebar/ProjectSection.tsx
  90. 5 5
      dashboard/src/main/home/sidebar/Sidebar.tsx
  91. 10 0
      dashboard/src/shared/api.tsx
  92. 1 1
      docs/GETTING_STARTED.md
  93. 2 2
      go.mod
  94. 1 0
      internal/helm/agent.go
  95. 19 10
      internal/helm/config.go
  96. 12 3
      internal/kubernetes/config.go
  97. 41 4
      internal/kubernetes/prometheus/metrics.go
  98. 49 0
      server/api/k8s_handler.go
  99. 18 0
      server/api/oauth_github_handler.go
  100. 2 1
      server/api/release_handler.go

+ 0 - 6
cmd/migrate/keyrotate/rotate.go

@@ -22,12 +22,6 @@ func Rotate(db *_gorm.DB, oldKey, newKey *[32]byte) error {
 	copy(oldKeyBytes[:], oldKey[:])
 	copy(oldKeyBytes[:], oldKey[:])
 	copy(newKeyBytes[:], newKey[:])
 	copy(newKeyBytes[:], newKey[:])
 
 
-	fmt.Printf("beginning key rotation from %s to %s\n", string(oldKeyBytes), string(newKeyBytes))
-
-	for i, b := range oldKeyBytes {
-		fmt.Println(i, ":", string(b), string(newKeyBytes[i]))
-	}
-
 	err := rotateClusterModel(db, oldKey, newKey)
 	err := rotateClusterModel(db, oldKey, newKey)
 
 
 	if err != nil {
 	if err != nil {

+ 1 - 1
dashboard/src/components/forms/VeleroForm.tsx

@@ -24,7 +24,7 @@ export default class VeleroForm extends Component<PropsType, StateType> {
     includeNamespaces: [] as string[],
     includeNamespaces: [] as string[],
     includeResources: [] as string[],
     includeResources: [] as string[],
     storageLocation: "",
     storageLocation: "",
-    volumeSnapshotLocations: [] as string[],
+    volumeSnapshotLocations: [] as string[]
   };
   };
 
 
   render() {
   render() {

+ 17 - 17
dashboard/src/components/image-selector/ImageList.tsx

@@ -30,7 +30,7 @@ export default class ImageList extends Component<PropsType, StateType> {
   state = {
   state = {
     loading: true,
     loading: true,
     error: false,
     error: false,
-    images: [] as ImageType[],
+    images: [] as ImageType[]
   };
   };
 
 
   // TODO: Try to unhook before unmount
   // TODO: Try to unhook before unmount
@@ -42,7 +42,7 @@ export default class ImageList extends Component<PropsType, StateType> {
     if (!this.props.registry) {
     if (!this.props.registry) {
       api
       api
         .getProjectRegistries("<token>", {}, { id: currentProject.id })
         .getProjectRegistries("<token>", {}, { id: currentProject.id })
-        .then((res) => {
+        .then(res => {
           let registries = res.data;
           let registries = res.data;
           if (registries.length === 0) {
           if (registries.length === 0) {
             this.setState({ loading: false });
             this.setState({ loading: false });
@@ -58,10 +58,10 @@ export default class ImageList extends Component<PropsType, StateType> {
                     {},
                     {},
                     {
                     {
                       project_id: currentProject.id,
                       project_id: currentProject.id,
-                      registry_id: registry.id,
+                      registry_id: registry.id
                     }
                     }
                   )
                   )
-                  .then((res) => {
+                  .then(res => {
                     res.data.sort((a: any, b: any) =>
                     res.data.sort((a: any, b: any) =>
                       a.name > b.name ? 1 : -1
                       a.name > b.name ? 1 : -1
                     );
                     );
@@ -72,20 +72,20 @@ export default class ImageList extends Component<PropsType, StateType> {
                           kind: registry.service,
                           kind: registry.service,
                           source: img.uri,
                           source: img.uri,
                           name: img.name,
                           name: img.name,
-                          registryId: registry.id,
+                          registryId: registry.id
                         });
                         });
                       }
                       }
                       return {
                       return {
                         kind: registry.service,
                         kind: registry.service,
                         source: img.uri,
                         source: img.uri,
                         name: img.name,
                         name: img.name,
-                        registryId: registry.id,
+                        registryId: registry.id
                       };
                       };
                     });
                     });
                     images.push(...newImg);
                     images.push(...newImg);
                     errors.push(0);
                     errors.push(0);
                   })
                   })
-                  .catch((err) => errors.push(1))
+                  .catch(err => errors.push(1))
                   .finally(() => {
                   .finally(() => {
                     if (i == registries.length - 1) {
                     if (i == registries.length - 1) {
                       let error =
                       let error =
@@ -98,11 +98,11 @@ export default class ImageList extends Component<PropsType, StateType> {
                       this.setState({
                       this.setState({
                         images,
                         images,
                         loading: false,
                         loading: false,
-                        error,
+                        error
                       });
                       });
                     } else {
                     } else {
                       this.setState({
                       this.setState({
-                        images,
+                        images
                       });
                       });
                     }
                     }
 
 
@@ -112,7 +112,7 @@ export default class ImageList extends Component<PropsType, StateType> {
             );
             );
           });
           });
         })
         })
-        .catch((err) => {
+        .catch(err => {
           console.log(err);
           console.log(err);
           this.setState({ loading: false, error: true });
           this.setState({ loading: false, error: true });
         });
         });
@@ -123,10 +123,10 @@ export default class ImageList extends Component<PropsType, StateType> {
           {},
           {},
           {
           {
             project_id: currentProject.id,
             project_id: currentProject.id,
-            registry_id: this.props.registry.id,
+            registry_id: this.props.registry.id
           }
           }
         )
         )
-        .then((res) => {
+        .then(res => {
           res.data.sort((a: any, b: any) => (a.name > b.name ? 1 : -1));
           res.data.sort((a: any, b: any) => (a.name > b.name ? 1 : -1));
           // Loop over found image repositories
           // Loop over found image repositories
           let newImg = res.data.map((img: any) => {
           let newImg = res.data.map((img: any) => {
@@ -135,14 +135,14 @@ export default class ImageList extends Component<PropsType, StateType> {
                 kind: this.props.registry.service,
                 kind: this.props.registry.service,
                 source: img.uri,
                 source: img.uri,
                 name: img.name,
                 name: img.name,
-                registryId: this.props.registry.id,
+                registryId: this.props.registry.id
               });
               });
             }
             }
             return {
             return {
               kind: this.props.registry.service,
               kind: this.props.registry.service,
               source: img.uri,
               source: img.uri,
               name: img.name,
               name: img.name,
-              registryId: this.props.registry.id,
+              registryId: this.props.registry.id
             };
             };
           });
           });
           images.push(...newImg);
           images.push(...newImg);
@@ -150,13 +150,13 @@ export default class ImageList extends Component<PropsType, StateType> {
           this.setState({
           this.setState({
             images,
             images,
             loading: false,
             loading: false,
-            error: false,
+            error: false
           });
           });
         })
         })
-        .catch((err) =>
+        .catch(err =>
           this.setState({
           this.setState({
             loading: false,
             loading: false,
-            error: true,
+            error: true
           })
           })
         );
         );
     }
     }

+ 1 - 1
dashboard/src/components/image-selector/ImageSelector.tsx

@@ -33,7 +33,7 @@ export default class ImageSelector extends Component<PropsType, StateType> {
     loading: true,
     loading: true,
     error: false,
     error: false,
     images: [] as ImageType[],
     images: [] as ImageType[],
-    clickedImage: null as ImageType | null,
+    clickedImage: null as ImageType | null
   };
   };
 
 
   // componentDidMount() {
   // componentDidMount() {

+ 4 - 4
dashboard/src/components/image-selector/TagList.tsx

@@ -27,7 +27,7 @@ export default class TagList extends Component<PropsType, StateType> {
     loading: true,
     loading: true,
     error: false,
     error: false,
     tags: [] as string[],
     tags: [] as string[],
-    currentTag: this.props.selectedTag,
+    currentTag: this.props.selectedTag
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -41,16 +41,16 @@ export default class TagList extends Component<PropsType, StateType> {
         {
         {
           project_id: currentProject.id,
           project_id: currentProject.id,
           registry_id: this.props.registryId,
           registry_id: this.props.registryId,
-          repo_name: repoName,
+          repo_name: repoName
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let tags = res.data.map((tag: any, i: number) => {
         let tags = res.data.map((tag: any, i: number) => {
           return tag.tag;
           return tag.tag;
         });
         });
         this.setState({ tags, loading: false });
         this.setState({ tags, loading: false });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         this.setState({ loading: false, error: true });
         this.setState({ loading: false, error: true });
       });
       });

+ 2 - 2
dashboard/src/components/repo-selector/ActionConfEditor.tsx

@@ -31,13 +31,13 @@ type StateType = {
 const defaultActionConfig: ActionConfigType = {
 const defaultActionConfig: ActionConfigType = {
   git_repo: "",
   git_repo: "",
   image_repo_uri: "",
   image_repo_uri: "",
-  git_repo_id: 0,
+  git_repo_id: 0
 };
 };
 
 
 export default class ActionConfEditor extends Component<PropsType, StateType> {
 export default class ActionConfEditor extends Component<PropsType, StateType> {
   state = {
   state = {
     loading: true,
     loading: true,
-    error: false,
+    error: false
   };
   };
 
 
   renderExpanded = () => {
   renderExpanded = () => {

+ 3 - 3
dashboard/src/components/repo-selector/ActionDetails.tsx

@@ -32,7 +32,7 @@ type StateType = {
 const dummyRegistries = [
 const dummyRegistries = [
   { id: 1, service: "ecr", url: "https://idfkasdfasdf" },
   { id: 1, service: "ecr", url: "https://idfkasdfasdf" },
   { id: 12, service: "ecr", url: "https://dfasdfidfkasdfasdf" },
   { id: 12, service: "ecr", url: "https://dfasdfidfkasdfasdf" },
-  { id: 11, service: "gcr", url: "https://idfkasdfasdf" },
+  { id: 11, service: "gcr", url: "https://idfkasdfasdf" }
 ] as any[];
 ] as any[];
 
 
 export default class ActionDetails extends Component<PropsType, StateType> {
 export default class ActionDetails extends Component<PropsType, StateType> {
@@ -40,7 +40,7 @@ export default class ActionDetails extends Component<PropsType, StateType> {
     dockerRepo: "",
     dockerRepo: "",
     error: false,
     error: false,
     registries: null as any[] | null,
     registries: null as any[] | null,
-    loading: true,
+    loading: true
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -281,7 +281,7 @@ const StatusWrapper = styled.div<{ successful?: boolean }>`
   > i {
   > i {
     font-size: 18px;
     font-size: 18px;
     margin-right: 10px;
     margin-right: 10px;
-    color: ${(props) => (props.successful ? "#4797ff" : "#fcba03")};
+    color: ${props => (props.successful ? "#4797ff" : "#fcba03")};
   }
   }
 
 
   animation: statusFloatIn 0.5s;
   animation: statusFloatIn 0.5s;

+ 4 - 4
dashboard/src/components/repo-selector/BranchList.tsx

@@ -24,7 +24,7 @@ export default class BranchList extends Component<PropsType, StateType> {
   state = {
   state = {
     loading: true,
     loading: true,
     error: false,
     error: false,
-    branches: [] as string[],
+    branches: [] as string[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -41,13 +41,13 @@ export default class BranchList extends Component<PropsType, StateType> {
           git_repo_id: actionConfig.git_repo_id,
           git_repo_id: actionConfig.git_repo_id,
           kind: "github",
           kind: "github",
           owner: actionConfig.git_repo.split("/")[0],
           owner: actionConfig.git_repo.split("/")[0],
-          name: actionConfig.git_repo.split("/")[1],
+          name: actionConfig.git_repo.split("/")[1]
         }
         }
       )
       )
-      .then((res) =>
+      .then(res =>
         this.setState({ branches: res.data, loading: false, error: false })
         this.setState({ branches: res.data, loading: false, error: false })
       )
       )
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         this.setState({ loading: false, error: true });
         this.setState({ loading: false, error: true });
       });
       });

+ 6 - 6
dashboard/src/components/repo-selector/ContentsList.tsx

@@ -35,7 +35,7 @@ export default class ContentsList extends Component<PropsType, StateType> {
     error: false,
     error: false,
     contents: [] as FileType[],
     contents: [] as FileType[],
     currentDir: "",
     currentDir: "",
-    dockerfiles: [] as string[],
+    dockerfiles: [] as string[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -61,10 +61,10 @@ export default class ContentsList extends Component<PropsType, StateType> {
           kind: "github",
           kind: "github",
           owner: actionConfig.git_repo.split("/")[0],
           owner: actionConfig.git_repo.split("/")[0],
           name: actionConfig.git_repo.split("/")[1],
           name: actionConfig.git_repo.split("/")[1],
-          branch: branch,
+          branch: branch
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let files = [] as FileType[];
         let files = [] as FileType[];
         let folders = [] as FileType[];
         let folders = [] as FileType[];
         res.data.map((x: FileType, i: number) => {
         res.data.map((x: FileType, i: number) => {
@@ -81,7 +81,7 @@ export default class ContentsList extends Component<PropsType, StateType> {
 
 
         this.setState({ contents, loading: false, error: false });
         this.setState({ contents, loading: false, error: false });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
 
 
         this.setState({ loading: false, error: true });
         this.setState({ loading: false, error: true });
@@ -317,7 +317,7 @@ const Indicator = styled.div<{ selected: boolean }>`
   border: 1px solid #ffffff55;
   border: 1px solid #ffffff55;
   margin: 1px 10px 0px 1px;
   margin: 1px 10px 0px 1px;
   margin-right: 13px;
   margin-right: 13px;
-  background: ${(props) => (props.selected ? "#ffffff22" : "#ffffff11")};
+  background: ${props => (props.selected ? "#ffffff22" : "#ffffff11")};
 `;
 `;
 
 
 const Label = styled.div`
 const Label = styled.div`
@@ -343,7 +343,7 @@ const Row = styled.div<{ isLast: boolean }>`
   padding-left: 10px;
   padding-left: 10px;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
-  border-bottom: ${(props) => !props.isLast && "1px solid #aaaabb"};
+  border-bottom: ${props => !props.isLast && "1px solid #aaaabb"};
   cursor: pointer;
   cursor: pointer;
   :hover {
   :hover {
     background: #ffffff22;
     background: #ffffff22;

+ 2 - 2
dashboard/src/components/repo-selector/NewGHAction.tsx

@@ -27,7 +27,7 @@ export default class NewGHAction extends Component<PropsType, StateType> {
     dockerRepo: "",
     dockerRepo: "",
     trueDockerPath: this.props.dockerPath,
     trueDockerPath: this.props.dockerPath,
     loading: false,
     loading: false,
-    error: false,
+    error: false
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -36,7 +36,7 @@ export default class NewGHAction extends Component<PropsType, StateType> {
         trueDockerPath: this.props.dockerPath.substring(
         trueDockerPath: this.props.dockerPath.substring(
           1,
           1,
           this.props.dockerPath.length
           this.props.dockerPath.length
-        ),
+        )
       });
       });
     }
     }
   }
   }

+ 54 - 51
dashboard/src/components/repo-selector/RepoList.tsx

@@ -28,7 +28,7 @@ export default class RepoList extends Component<PropsType, StateType> {
     repos: [] as RepoType[],
     repos: [] as RepoType[],
     loading: true,
     loading: true,
     error: false,
     error: false,
-    searchFilter: "",
+    searchFilter: ""
   };
   };
 
 
   // TODO: Try to unhook before unmount
   // TODO: Try to unhook before unmount
@@ -39,14 +39,14 @@ export default class RepoList extends Component<PropsType, StateType> {
     if (!this.props.userId && this.props.userId !== 0) {
     if (!this.props.userId && this.props.userId !== 0) {
       api
       api
         .getGitRepos("<token>", {}, { project_id: currentProject.id })
         .getGitRepos("<token>", {}, { project_id: currentProject.id })
-        .then(async (res) => {
+        .then(async res => {
           if (res.data.length == 0) {
           if (res.data.length == 0) {
             this.setState({ loading: false, error: false });
             this.setState({ loading: false, error: false });
-            return
+            return;
           }
           }
 
 
           var allRepos: any = [];
           var allRepos: any = [];
-          var errors : any = [];
+          var errors: any = [];
 
 
           var promises = res.data.map((gitrepo: any, id: number) => {
           var promises = res.data.map((gitrepo: any, id: number) => {
             return new Promise((resolve, reject) => {
             return new Promise((resolve, reject) => {
@@ -56,32 +56,34 @@ export default class RepoList extends Component<PropsType, StateType> {
                   {},
                   {},
                   { project_id: currentProject.id, git_repo_id: gitrepo.id }
                   { project_id: currentProject.id, git_repo_id: gitrepo.id }
                 )
                 )
-                .then((res) => {
+                .then(res => {
                   res.data.forEach((repo: any, id: number) => {
                   res.data.forEach((repo: any, id: number) => {
                     repo.GHRepoID = gitrepo.id;
                     repo.GHRepoID = gitrepo.id;
                   });
                   });
 
 
-                  resolve(res.data)
+                  resolve(res.data);
                 })
                 })
-                .catch((err) => {
-                  errors.push(err)
-                  resolve([])
+                .catch(err => {
+                  errors.push(err);
+                  resolve([]);
                 });
                 });
-              })
-            })  
+            });
+          });
 
 
           var sepRepos = await Promise.all(promises);
           var sepRepos = await Promise.all(promises);
 
 
           allRepos = [].concat.apply([], sepRepos);
           allRepos = [].concat.apply([], sepRepos);
 
 
           // remove duplicates based on name
           // remove duplicates based on name
-          allRepos = allRepos.filter((repo : any, index : number, self : any) => {
-            var keep = index === self.findIndex((_repo : any) => {
-              return repo.FullName === _repo.FullName
-            })
-
-            return keep
-          })
+          allRepos = allRepos.filter((repo: any, index: number, self: any) => {
+            var keep =
+              index ===
+              self.findIndex((_repo: any) => {
+                return repo.FullName === _repo.FullName;
+              });
+
+            return keep;
+          });
 
 
           // sort repos based on name
           // sort repos based on name
           allRepos.sort((a: any, b: any) => {
           allRepos.sort((a: any, b: any) => {
@@ -100,11 +102,11 @@ export default class RepoList extends Component<PropsType, StateType> {
             this.setState({
             this.setState({
               repos: allRepos,
               repos: allRepos,
               loading: false,
               loading: false,
-              error: false,
+              error: false
             });
             });
           }
           }
         })
         })
-        .catch((_) => this.setState({ loading: false, error: true }));
+        .catch(_ => this.setState({ loading: false, error: true }));
     } else {
     } else {
       let grid = this.props.userId;
       let grid = this.props.userId;
 
 
@@ -114,8 +116,8 @@ export default class RepoList extends Component<PropsType, StateType> {
           {},
           {},
           { project_id: currentProject.id, git_repo_id: grid }
           { project_id: currentProject.id, git_repo_id: grid }
         )
         )
-        .then((res) => {
-          var repos : any = res.data
+        .then(res => {
+          var repos: any = res.data;
 
 
           repos.forEach((repo: any, id: number) => {
           repos.forEach((repo: any, id: number) => {
             repo.GHRepoID = grid;
             repo.GHRepoID = grid;
@@ -133,7 +135,7 @@ export default class RepoList extends Component<PropsType, StateType> {
 
 
           this.setState({ repos: repos, loading: false, error: false });
           this.setState({ repos: repos, loading: false, error: false });
         })
         })
-        .catch((err) => {
+        .catch(err => {
           this.setState({ loading: false, error: true });
           this.setState({ loading: false, error: true });
         });
         });
     }
     }
@@ -171,27 +173,29 @@ export default class RepoList extends Component<PropsType, StateType> {
       );
       );
     }
     }
 
 
-    return repos.filter((repo: RepoType, i: number) => {
-      return repo.FullName.includes(this.state.searchFilter || "")
-    }).map((repo: RepoType, i: number) => {
-      return (
-        <RepoName
-          key={i}
-          isSelected={repo.FullName === this.props.actionConfig.git_repo}
-          lastItem={i === repos.length - 1}
-          onClick={() => this.setRepo(repo)}
-          readOnly={this.props.readOnly}
-        >
-          <img src={github} />
-          {repo.FullName}
-        </RepoName>
-      );
-    });
+    return repos
+      .filter((repo: RepoType, i: number) => {
+        return repo.FullName.includes(this.state.searchFilter || "");
+      })
+      .map((repo: RepoType, i: number) => {
+        return (
+          <RepoName
+            key={i}
+            isSelected={repo.FullName === this.props.actionConfig.git_repo}
+            lastItem={i === repos.length - 1}
+            onClick={() => this.setRepo(repo)}
+            readOnly={this.props.readOnly}
+          >
+            <img src={github} />
+            {repo.FullName}
+          </RepoName>
+        );
+      });
   };
   };
 
 
   renderExpanded = () => {
   renderExpanded = () => {
     if (this.props.readOnly) {
     if (this.props.readOnly) {
-      return <ExpandedWrapperAlt>{this.renderRepoList()}</ExpandedWrapperAlt>
+      return <ExpandedWrapperAlt>{this.renderRepoList()}</ExpandedWrapperAlt>;
     } else {
     } else {
       return (
       return (
         <ExpandedWrapper>
         <ExpandedWrapper>
@@ -201,7 +205,7 @@ export default class RepoList extends Component<PropsType, StateType> {
             readOnly={this.props.readOnly}
             readOnly={this.props.readOnly}
           >
           >
             <i className="material-icons">search</i>
             <i className="material-icons">search</i>
-            <SearchInput 
+            <SearchInput
               value={this.state.searchFilter}
               value={this.state.searchFilter}
               onChange={(e: any) => {
               onChange={(e: any) => {
                 this.setState({ searchFilter: e.target.value });
                 this.setState({ searchFilter: e.target.value });
@@ -209,9 +213,7 @@ export default class RepoList extends Component<PropsType, StateType> {
               placeholder="Search repos..."
               placeholder="Search repos..."
             />
             />
           </InfoRow>
           </InfoRow>
-          <ExpandedWrapper>
-            {this.renderRepoList()}
-          </ExpandedWrapper>
+          <ExpandedWrapper>{this.renderRepoList()}</ExpandedWrapper>
         </ExpandedWrapper>
         </ExpandedWrapper>
       );
       );
     }
     }
@@ -258,7 +260,8 @@ const RepoName = styled.div`
     }
     }
   }
   }
 
 
-  > img,i {
+  > img,
+  i {
     width: 18px;
     width: 18px;
     height: 18px;
     height: 18px;
     margin-left: 12px;
     margin-left: 12px;
@@ -294,14 +297,14 @@ const ExpandedWrapper = styled.div`
   border-radius: 3px;
   border-radius: 3px;
   border: 0px solid #ffffff44;
   border: 0px solid #ffffff44;
   max-height: 235px;
   max-height: 235px;
-  top: 40px; 
+  top: 40px;
 
 
   > i {
   > i {
     font-size: 18px;
     font-size: 18px;
     display: block;
     display: block;
-    position: absolute; 
-    left: 10px; 
-    top: 10px; 
+    position: absolute;
+    left: 10px;
+    top: 10px;
   }
   }
 `;
 `;
 
 
@@ -326,5 +329,5 @@ const SearchInput = styled.input`
   width: 100%;
   width: 100%;
   color: white;
   color: white;
   padding: 0;
   padding: 0;
-  height: 20px; 
-`;
+  height: 20px;
+`;

+ 1 - 1
dashboard/src/components/values-form/Base64InputRow.tsx

@@ -19,7 +19,7 @@ type StateType = {
 
 
 export default class InputRow extends Component<PropsType, StateType> {
 export default class InputRow extends Component<PropsType, StateType> {
   state = {
   state = {
-    readOnly: true,
+    readOnly: true
   };
   };
 
 
   handleChange = (e: ChangeEvent<HTMLInputElement>) => {
   handleChange = (e: ChangeEvent<HTMLInputElement>) => {

+ 1 - 1
dashboard/src/components/values-form/CheckboxList.tsx

@@ -67,7 +67,7 @@ const CheckboxOption = styled.div<{ isLast: boolean }>`
   display: flex;
   display: flex;
   cursor: pointer;
   cursor: pointer;
   align-items: center;
   align-items: center;
-  border-bottom: ${(props) => (props.isLast ? "" : "1px solid #ffffff22")};
+  border-bottom: ${props => (props.isLast ? "" : "1px solid #ffffff22")};
   font-size: 13px;
   font-size: 13px;
 
 
   :hover {
   :hover {

+ 1 - 1
dashboard/src/components/values-form/Heading.tsx

@@ -11,7 +11,7 @@ const StyledHeading = styled.div<{ isAtTop: boolean }>`
   color: white;
   color: white;
   font-weight: 500;
   font-weight: 500;
   font-size: 16px;
   font-size: 16px;
-  margin-top: ${(props) => (props.isAtTop ? "0" : "30px")};
+  margin-top: ${props => (props.isAtTop ? "0" : "30px")};
   margin-bottom: 5px;
   margin-bottom: 5px;
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;

+ 1 - 1
dashboard/src/components/values-form/InputRow.tsx

@@ -19,7 +19,7 @@ type StateType = {
 
 
 export default class InputRow extends Component<PropsType, StateType> {
 export default class InputRow extends Component<PropsType, StateType> {
   state = {
   state = {
-    readOnly: true,
+    readOnly: true
   };
   };
 
 
   handleChange = (e: ChangeEvent<HTMLInputElement>) => {
   handleChange = (e: ChangeEvent<HTMLInputElement>) => {

+ 1 - 1
dashboard/src/components/values-form/KeyValueArray.tsx

@@ -14,7 +14,7 @@ type StateType = {
 
 
 export default class KeyValueArray extends Component<PropsType, StateType> {
 export default class KeyValueArray extends Component<PropsType, StateType> {
   state = {
   state = {
-    values: [] as any[],
+    values: [] as any[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {

+ 1 - 1
dashboard/src/components/values-form/MultiSelect.tsx

@@ -9,7 +9,7 @@ type StateType = {
 
 
 export default class MultiSelect extends Component<PropsType, StateType> {
 export default class MultiSelect extends Component<PropsType, StateType> {
   state = {
   state = {
-    options: [] as { label: string; value: string }[],
+    options: [] as { label: string; value: string }[]
   };
   };
 
 
   renderOptions = () => {};
   renderOptions = () => {};

+ 3 - 3
dashboard/src/components/values-form/ValuesForm.tsx

@@ -168,7 +168,7 @@ export default class ValuesForm extends Component<PropsType, StateType> {
             <SelectRow
             <SelectRow
               key={i}
               key={i}
               value={this.props.metaState[key]}
               value={this.props.metaState[key]}
-              setActiveValue={(val) => this.props.setMetaState({ [key]: val })}
+              setActiveValue={val => this.props.setMetaState({ [key]: val })}
               options={item.settings.options}
               options={item.settings.options}
               dropdownLabel=""
               dropdownLabel=""
               label={item.label}
               label={item.label}
@@ -179,11 +179,11 @@ export default class ValuesForm extends Component<PropsType, StateType> {
             <SelectRow
             <SelectRow
               key={i}
               key={i}
               value={this.props.metaState[key]}
               value={this.props.metaState[key]}
-              setActiveValue={(val) => this.props.setMetaState({ [key]: val })}
+              setActiveValue={val => this.props.setMetaState({ [key]: val })}
               options={[
               options={[
                 { value: "aws", label: "Amazon Web Services (AWS)" },
                 { value: "aws", label: "Amazon Web Services (AWS)" },
                 { value: "gcp", label: "Google Cloud Platform (GCP)" },
                 { value: "gcp", label: "Google Cloud Platform (GCP)" },
-                { value: "do", label: "DigitalOcean" },
+                { value: "do", label: "DigitalOcean" }
               ]}
               ]}
               dropdownLabel=""
               dropdownLabel=""
               label={item.label}
               label={item.label}

+ 1 - 1
dashboard/src/components/values-form/ValuesWrapper.tsx

@@ -20,7 +20,7 @@ type StateType = any;
 const providerMap: any = {
 const providerMap: any = {
   gke: "gcp",
   gke: "gcp",
   eks: "aws",
   eks: "aws",
-  doks: "do",
+  doks: "do"
 };
 };
 
 
 // Manages the consolidated state of all form tabs ("metastate")
 // Manages the consolidated state of all form tabs ("metastate")

+ 6 - 6
dashboard/src/main/auth/Login.tsx

@@ -23,7 +23,7 @@ export default class Login extends Component<PropsType, StateType> {
     email: "",
     email: "",
     password: "",
     password: "",
     emailError: false,
     emailError: false,
-    credentialError: false,
+    credentialError: false
   };
   };
 
 
   handleKeyDown = (e: any) => {
   handleKeyDown = (e: any) => {
@@ -57,11 +57,11 @@ export default class Login extends Component<PropsType, StateType> {
           "",
           "",
           {
           {
             email: email,
             email: email,
-            password: password,
+            password: password
           },
           },
           {}
           {}
         )
         )
-        .then((res) => {
+        .then(res => {
           // TODO: case and set credential error
           // TODO: case and set credential error
           if (res?.data?.redirect) {
           if (res?.data?.redirect) {
             window.location.href = res.data.redirect;
             window.location.href = res.data.redirect;
@@ -70,7 +70,7 @@ export default class Login extends Component<PropsType, StateType> {
             authenticate();
             authenticate();
           }
           }
         })
         })
-        .catch((err) =>
+        .catch(err =>
           this.context.setCurrentError(err.response.data.errors[0])
           this.context.setCurrentError(err.response.data.errors[0])
         );
         );
     }
     }
@@ -137,7 +137,7 @@ export default class Login extends Component<PropsType, StateType> {
                   this.setState({
                   this.setState({
                     email: e.target.value,
                     email: e.target.value,
                     emailError: false,
                     emailError: false,
-                    credentialError: false,
+                    credentialError: false
                   })
                   })
                 }
                 }
                 valid={!credentialError && !emailError}
                 valid={!credentialError && !emailError}
@@ -152,7 +152,7 @@ export default class Login extends Component<PropsType, StateType> {
                 onChange={(e: ChangeEvent<HTMLInputElement>) =>
                 onChange={(e: ChangeEvent<HTMLInputElement>) =>
                   this.setState({
                   this.setState({
                     password: e.target.value,
                     password: e.target.value,
-                    credentialError: false,
+                    credentialError: false
                   })
                   })
                 }
                 }
                 valid={!credentialError}
                 valid={!credentialError}

+ 6 - 6
dashboard/src/main/auth/Register.tsx

@@ -25,7 +25,7 @@ export default class Register extends Component<PropsType, StateType> {
     password: "",
     password: "",
     confirmPassword: "",
     confirmPassword: "",
     emailError: false,
     emailError: false,
-    confirmPasswordError: false,
+    confirmPasswordError: false
   };
   };
 
 
   handleKeyDown = (e: any) => {
   handleKeyDown = (e: any) => {
@@ -66,7 +66,7 @@ export default class Register extends Component<PropsType, StateType> {
           "",
           "",
           {
           {
             email: email,
             email: email,
-            password: password,
+            password: password
           },
           },
           {}
           {}
         )
         )
@@ -78,7 +78,7 @@ export default class Register extends Component<PropsType, StateType> {
             authenticate();
             authenticate();
           }
           }
         })
         })
-        .catch((err) => setCurrentError(err.response.data.errors[0]));
+        .catch(err => setCurrentError(err.response.data.errors[0]));
     }
     }
   };
   };
 
 
@@ -112,7 +112,7 @@ export default class Register extends Component<PropsType, StateType> {
       password,
       password,
       confirmPassword,
       confirmPassword,
       emailError,
       emailError,
-      confirmPasswordError,
+      confirmPasswordError
     } = this.state;
     } = this.state;
 
 
     return (
     return (
@@ -154,7 +154,7 @@ export default class Register extends Component<PropsType, StateType> {
               onChange={(e: ChangeEvent<HTMLInputElement>) =>
               onChange={(e: ChangeEvent<HTMLInputElement>) =>
                 this.setState({
                 this.setState({
                   password: e.target.value,
                   password: e.target.value,
-                  confirmPasswordError: false,
+                  confirmPasswordError: false
                 })
                 })
               }
               }
               valid={true}
               valid={true}
@@ -167,7 +167,7 @@ export default class Register extends Component<PropsType, StateType> {
                 onChange={(e: ChangeEvent<HTMLInputElement>) =>
                 onChange={(e: ChangeEvent<HTMLInputElement>) =>
                   this.setState({
                   this.setState({
                     confirmPassword: e.target.value,
                     confirmPassword: e.target.value,
-                    confirmPasswordError: false,
+                    confirmPasswordError: false
                   })
                   })
                 }
                 }
                 valid={!confirmPasswordError}
                 valid={!confirmPasswordError}

+ 9 - 9
dashboard/src/main/auth/ResetPasswordFinalize.tsx

@@ -28,7 +28,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
     passwordError: false,
     passwordError: false,
     tokenError: false,
     tokenError: false,
     loading: true,
     loading: true,
-    submitted: false,
+    submitted: false
   };
   };
 
 
   handleKeyDown = (e: any) => {
   handleKeyDown = (e: any) => {
@@ -48,21 +48,21 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
         {
         {
           email: emailFromParam,
           email: emailFromParam,
           token: tokenFromParams,
           token: tokenFromParams,
-          token_id: parseInt(tokenIDFromParams),
+          token_id: parseInt(tokenIDFromParams)
         },
         },
         {}
         {}
       )
       )
       .then(() => {
       .then(() => {
         this.setState({ loading: false });
         this.setState({ loading: false });
       })
       })
-      .catch((err) => this.setState({ loading: false, tokenError: true }));
+      .catch(err => this.setState({ loading: false, tokenError: true }));
 
 
     document.addEventListener("keydown", this.handleKeyDown);
     document.addEventListener("keydown", this.handleKeyDown);
 
 
     this.setState({
     this.setState({
       email: emailFromParam,
       email: emailFromParam,
       token: tokenFromParams,
       token: tokenFromParams,
-      token_id: parseInt(tokenIDFromParams),
+      token_id: parseInt(tokenIDFromParams)
     });
     });
   }
   }
 
 
@@ -93,11 +93,11 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
           email: email,
           email: email,
           token: token,
           token: token,
           token_id: token_id,
           token_id: token_id,
-          new_password: password,
+          new_password: password
         },
         },
         {}
         {}
       )
       )
-      .then((res) => {
+      .then(res => {
         // redirect to dashboard with message after timeout
         // redirect to dashboard with message after timeout
         this.setState({ submitted: true });
         this.setState({ submitted: true });
 
 
@@ -105,7 +105,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
           window.location.href = "/login";
           window.location.href = "/login";
         }, 2000);
         }, 2000);
       })
       })
-      .catch((err) => this.setState({ tokenError: true }));
+      .catch(err => this.setState({ tokenError: true }));
   };
   };
 
 
   render() {
   render() {
@@ -114,7 +114,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
       passwordError,
       passwordError,
       submitted,
       submitted,
       loading,
       loading,
-      tokenError,
+      tokenError
     } = this.state;
     } = this.state;
 
 
     let inputSection = (
     let inputSection = (
@@ -127,7 +127,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
             onChange={(e: ChangeEvent<HTMLInputElement>) =>
             onChange={(e: ChangeEvent<HTMLInputElement>) =>
               this.setState({
               this.setState({
                 password: e.target.value,
                 password: e.target.value,
-                passwordError: false,
+                passwordError: false
               })
               })
             }
             }
             valid={!passwordError}
             valid={!passwordError}

+ 5 - 5
dashboard/src/main/auth/ResetPasswordInit.tsx

@@ -18,7 +18,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
   state = {
   state = {
     email: "",
     email: "",
     emailError: false,
     emailError: false,
-    submitted: false,
+    submitted: false
   };
   };
 
 
   handleKeyDown = (e: any) => {
   handleKeyDown = (e: any) => {
@@ -57,14 +57,14 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
         .createPasswordReset(
         .createPasswordReset(
           "",
           "",
           {
           {
-            email: email,
+            email: email
           },
           },
           {}
           {}
         )
         )
-        .then((res) => {
+        .then(res => {
           this.setState({ submitted: true });
           this.setState({ submitted: true });
         })
         })
-        .catch((err) =>
+        .catch(err =>
           this.context.setCurrentError(err.response.data.errors[0])
           this.context.setCurrentError(err.response.data.errors[0])
         );
         );
     }
     }
@@ -83,7 +83,7 @@ export default class ResetPasswordInit extends Component<PropsType, StateType> {
             onChange={(e: ChangeEvent<HTMLInputElement>) =>
             onChange={(e: ChangeEvent<HTMLInputElement>) =>
               this.setState({
               this.setState({
                 email: e.target.value,
                 email: e.target.value,
-                emailError: false,
+                emailError: false
               })
               })
             }
             }
             valid={!emailError}
             valid={!emailError}

+ 4 - 6
dashboard/src/main/auth/VerifyEmail.tsx

@@ -16,18 +16,16 @@ type StateType = {
 
 
 export default class VerifyEmail extends Component<PropsType, StateType> {
 export default class VerifyEmail extends Component<PropsType, StateType> {
   state = {
   state = {
-    submitted: false,
+    submitted: false
   };
   };
 
 
   handleSendEmail = (): void => {
   handleSendEmail = (): void => {
     api
     api
       .createEmailVerification("", {}, {})
       .createEmailVerification("", {}, {})
-      .then((res) => {
+      .then(res => {
         this.setState({ submitted: true });
         this.setState({ submitted: true });
       })
       })
-      .catch((err) =>
-        this.context.setCurrentError(err.response.data.errors[0])
-      );
+      .catch(err => this.context.setCurrentError(err.response.data.errors[0]));
   };
   };
 
 
   render() {
   render() {
@@ -299,7 +297,7 @@ const Logo = styled.img`
 `;
 `;
 
 
 const StatusText = styled.div<{ lessPadding?: boolean }>`
 const StatusText = styled.div<{ lessPadding?: boolean }>`
-  padding: ${(props) => (props.lessPadding ? "10px" : "18px")} 40px;
+  padding: ${props => (props.lessPadding ? "10px" : "18px")} 40px;
   font-family: "Work Sans", sans-serif;
   font-family: "Work Sans", sans-serif;
   font-size: 14px;
   font-size: 14px;
   line-height: 160%;
   line-height: 160%;

+ 15 - 23
dashboard/src/main/home/Home.tsx

@@ -50,7 +50,7 @@ class Home extends Component<PropsType, StateType> {
     forceRefreshClusters: false,
     forceRefreshClusters: false,
     sidebarReady: false,
     sidebarReady: false,
     handleDO: false,
     handleDO: false,
-    ghRedirect: false,
+    ghRedirect: false
   };
   };
 
 
   // TODO: Refactor and prevent flash + multiple reload
   // TODO: Refactor and prevent flash + multiple reload
@@ -64,10 +64,10 @@ class Home extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {},
         {},
         {
         {
-          project_id: currentProject.id,
+          project_id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let creating = false;
         let creating = false;
 
 
         for (var i = 0; i < res.data.length; i++) {
         for (var i = 0; i < res.data.length; i++) {
@@ -87,7 +87,7 @@ class Home extends Component<PropsType, StateType> {
     let { currentProject } = this.props;
     let { currentProject } = this.props;
     api
     api
       .getProjects("<token>", {}, { id: user.userId })
       .getProjects("<token>", {}, { id: user.userId })
-      .then((res) => {
+      .then(res => {
         if (res.data) {
         if (res.data) {
           if (res.data.length === 0) {
           if (res.data.length === 0) {
             this.props.history.push("new-project");
             this.props.history.push("new-project");
@@ -134,10 +134,10 @@ class Home extends Component<PropsType, StateType> {
       {
       {
         do_integration_id: integrationId,
         do_integration_id: integrationId,
         docr_name: this.props.currentProject.name,
         docr_name: this.props.currentProject.name,
-        docr_subscription_tier: tier,
+        docr_subscription_tier: tier
       },
       },
       {
       {
-        project_id: this.props.currentProject.id,
+        project_id: this.props.currentProject.id
       }
       }
     );
     );
     return callback();
     return callback();
@@ -150,10 +150,10 @@ class Home extends Component<PropsType, StateType> {
       {
       {
         do_integration_id: integrationId,
         do_integration_id: integrationId,
         doks_name: this.props.currentProject.name,
         doks_name: this.props.currentProject.name,
-        do_region: region,
+        do_region: region
       },
       },
       {
       {
-        project_id: this.props.currentProject.id,
+        project_id: this.props.currentProject.id
       }
       }
     );
     );
     return this.props.history.push("dashboard?tab=provisioner");
     return this.props.history.push("dashboard?tab=provisioner");
@@ -167,10 +167,10 @@ class Home extends Component<PropsType, StateType> {
           "<token>",
           "<token>",
           {},
           {},
           {
           {
-            project_id: currentProject.id,
+            project_id: currentProject.id
           }
           }
         )
         )
-        .then((res) => {
+        .then(res => {
           let tgtIntegration = res.data.find((integration: any) => {
           let tgtIntegration = res.data.find((integration: any) => {
             return integration.client === "do";
             return integration.client === "do";
           });
           });
@@ -197,18 +197,10 @@ class Home extends Component<PropsType, StateType> {
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
-    let { user, projects } = this.context;
-
     // Handle redirect from DO
     // Handle redirect from DO
     let queryString = window.location.search;
     let queryString = window.location.search;
     let urlParams = new URLSearchParams(queryString);
     let urlParams = new URLSearchParams(queryString);
 
 
-    window.analytics.identify(user.userId, {
-      email: user.email,
-      createdAt: Date.now(),
-      projects,
-    });
-
     let err = urlParams.get("error");
     let err = urlParams.get("error");
     if (err) {
     if (err) {
       this.context.setCurrentError(err);
       this.context.setCurrentError(err);
@@ -338,7 +330,7 @@ class Home extends Component<PropsType, StateType> {
     let { user, setProjects } = this.context;
     let { user, setProjects } = this.context;
     api
     api
       .getProjects("<token>", {}, { id: user.userId })
       .getProjects("<token>", {}, { id: user.userId })
-      .then((res) => {
+      .then(res => {
         if (res.data) {
         if (res.data) {
           setProjects(res.data);
           setProjects(res.data);
           if (res.data.length > 0) {
           if (res.data.length > 0) {
@@ -364,7 +356,7 @@ class Home extends Component<PropsType, StateType> {
     // Loop through and delete infra of all clusters we've provisioned
     // Loop through and delete infra of all clusters we've provisioned
     api
     api
       .getClusters("<token>", {}, { id: currentProject.id })
       .getClusters("<token>", {}, { id: currentProject.id })
-      .then((res) => {
+      .then(res => {
         // TODO: promise.map
         // TODO: promise.map
         for (var i = 0; i < res.data.length; i++) {
         for (var i = 0; i < res.data.length; i++) {
           let cluster = res.data[i];
           let cluster = res.data[i];
@@ -379,7 +371,7 @@ class Home extends Component<PropsType, StateType> {
                   { eks_name: cluster.name },
                   { eks_name: cluster.name },
                   {
                   {
                     project_id: currentProject.id,
                     project_id: currentProject.id,
-                    infra_id: cluster.infra_id,
+                    infra_id: cluster.infra_id
                   }
                   }
                 )
                 )
                 .then(() =>
                 .then(() =>
@@ -395,7 +387,7 @@ class Home extends Component<PropsType, StateType> {
                   { gke_name: cluster.name },
                   { gke_name: cluster.name },
                   {
                   {
                     project_id: currentProject.id,
                     project_id: currentProject.id,
-                    infra_id: cluster.infra_id,
+                    infra_id: cluster.infra_id
                   }
                   }
                 )
                 )
                 .then(() =>
                 .then(() =>
@@ -411,7 +403,7 @@ class Home extends Component<PropsType, StateType> {
                   { doks_name: cluster.name },
                   { doks_name: cluster.name },
                   {
                   {
                     project_id: currentProject.id,
                     project_id: currentProject.id,
-                    infra_id: cluster.infra_id,
+                    infra_id: cluster.infra_id
                   }
                   }
                 )
                 )
                 .then(() =>
                 .then(() =>

+ 7 - 7
dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx

@@ -32,7 +32,7 @@ class ClusterDashboard extends Component<PropsType, StateType> {
       ? localStorage.getItem("SortType")
       ? localStorage.getItem("SortType")
       : "Newest",
       : "Newest",
     currentChart: null as ChartType | null,
     currentChart: null as ChartType | null,
-    isMetricsInstalled: false,
+    isMetricsInstalled: false
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -40,13 +40,13 @@ class ClusterDashboard extends Component<PropsType, StateType> {
       .getPrometheusIsInstalled(
       .getPrometheusIsInstalled(
         "<token>",
         "<token>",
         {
         {
-          cluster_id: this.context.currentCluster.id,
+          cluster_id: this.context.currentCluster.id
         },
         },
         {
         {
-          id: this.context.currentProject.id,
+          id: this.context.currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ isMetricsInstalled: true });
         this.setState({ isMetricsInstalled: true });
       })
       })
       .catch(() => {
       .catch(() => {
@@ -63,7 +63,7 @@ class ClusterDashboard extends Component<PropsType, StateType> {
         sortType: localStorage.getItem("SortType")
         sortType: localStorage.getItem("SortType")
           ? localStorage.getItem("SortType")
           ? localStorage.getItem("SortType")
           : "Newest",
           : "Newest",
-        currentChart: null,
+        currentChart: null
       });
       });
     }
     }
   }
   }
@@ -138,11 +138,11 @@ class ClusterDashboard extends Component<PropsType, StateType> {
           </Button>
           </Button>
           <SortFilterWrapper>
           <SortFilterWrapper>
             <SortSelector
             <SortSelector
-              setSortType={(sortType) => this.setState({ sortType })}
+              setSortType={sortType => this.setState({ sortType })}
               sortType={this.state.sortType}
               sortType={this.state.sortType}
             />
             />
             <NamespaceSelector
             <NamespaceSelector
-              setNamespace={(namespace) => this.setState({ namespace })}
+              setNamespace={namespace => this.setState({ namespace })}
               namespace={this.state.namespace}
               namespace={this.state.namespace}
             />
             />
           </SortFilterWrapper>
           </SortFilterWrapper>

+ 7 - 7
dashboard/src/main/home/cluster-dashboard/NamespaceSelector.tsx

@@ -20,7 +20,7 @@ export default class NamespaceSelector extends Component<PropsType, StateType> {
   _isMounted = false;
   _isMounted = false;
 
 
   state = {
   state = {
-    namespaceOptions: [] as { label: string; value: string }[],
+    namespaceOptions: [] as { label: string; value: string }[]
   };
   };
 
 
   updateOptions = () => {
   updateOptions = () => {
@@ -30,27 +30,27 @@ export default class NamespaceSelector extends Component<PropsType, StateType> {
       .getNamespaces(
       .getNamespaces(
         "<token>",
         "<token>",
         {
         {
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) => {
+      .then(res => {
         if (this._isMounted) {
         if (this._isMounted) {
           let namespaceOptions: { label: string; value: string }[] = [
           let namespaceOptions: { label: string; value: string }[] = [
-            { label: "All", value: "" },
+            { label: "All", value: "" }
           ];
           ];
           res.data.items.forEach(
           res.data.items.forEach(
             (x: { metadata: { name: string } }, i: number) => {
             (x: { metadata: { name: string } }, i: number) => {
               namespaceOptions.push({
               namespaceOptions.push({
                 label: x.metadata.name,
                 label: x.metadata.name,
-                value: x.metadata.name,
+                value: x.metadata.name
               });
               });
             }
             }
           );
           );
           this.setState({ namespaceOptions });
           this.setState({ namespaceOptions });
         }
         }
       })
       })
-      .catch((err) => {
+      .catch(err => {
         if (this._isMounted) {
         if (this._isMounted) {
           this.setState({ namespaceOptions: [{ label: "All", value: "" }] });
           this.setState({ namespaceOptions: [{ label: "All", value: "" }] });
         }
         }
@@ -80,7 +80,7 @@ export default class NamespaceSelector extends Component<PropsType, StateType> {
         </Label>
         </Label>
         <Selector
         <Selector
           activeValue={this.props.namespace}
           activeValue={this.props.namespace}
-          setActiveValue={(namespace) => this.props.setNamespace(namespace)}
+          setActiveValue={namespace => this.props.setNamespace(namespace)}
           options={this.state.namespaceOptions}
           options={this.state.namespaceOptions}
           dropdownLabel="Namespace"
           dropdownLabel="Namespace"
           width="150px"
           width="150px"

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/SortSelector.tsx

@@ -20,8 +20,8 @@ export default class SortSelector extends Component<PropsType, StateType> {
     sortOptions: [
     sortOptions: [
       { label: "Newest", value: "Newest" },
       { label: "Newest", value: "Newest" },
       { label: "Oldest", value: "Oldest" },
       { label: "Oldest", value: "Oldest" },
-      { label: "Alphabetical", value: "Alphabetical" },
-    ] as { label: string; value: string }[],
+      { label: "Alphabetical", value: "Alphabetical" }
+    ] as { label: string; value: string }[]
   };
   };
 
 
   render() {
   render() {
@@ -32,7 +32,7 @@ export default class SortSelector extends Component<PropsType, StateType> {
         </Label>
         </Label>
         <Selector
         <Selector
           activeValue={this.props.sortType}
           activeValue={this.props.sortType}
-          setActiveValue={(sortType) => this.props.setSortType(sortType)}
+          setActiveValue={sortType => this.props.setSortType(sortType)}
           options={this.state.sortOptions}
           options={this.state.sortOptions}
           dropdownLabel="Sort By"
           dropdownLabel="Sort By"
           width="150px"
           width="150px"

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx

@@ -19,7 +19,7 @@ type StateType = {
 export default class Chart extends Component<PropsType, StateType> {
 export default class Chart extends Component<PropsType, StateType> {
   state = {
   state = {
     expand: false,
     expand: false,
-    update: [] as any[],
+    update: [] as any[]
   };
   };
 
 
   renderIcon = () => {
   renderIcon = () => {
@@ -37,7 +37,7 @@ export default class Chart extends Component<PropsType, StateType> {
     let date = ts.toLocaleDateString();
     let date = ts.toLocaleDateString();
     let time = ts.toLocaleTimeString([], {
     let time = ts.toLocaleTimeString([], {
       hour: "numeric",
       hour: "numeric",
-      minute: "2-digit",
+      minute: "2-digit"
     });
     });
     return `${time} on ${date}`;
     return `${time} on ${date}`;
   };
   };

+ 15 - 15
dashboard/src/main/home/cluster-dashboard/chart/ChartList.tsx

@@ -31,7 +31,7 @@ export default class ChartList extends Component<PropsType, StateType> {
     controllers: {} as Record<string, Record<string, any>>,
     controllers: {} as Record<string, Record<string, any>>,
     loading: false,
     loading: false,
     error: false,
     error: false,
-    websockets: {} as Record<string, any>,
+    websockets: {} as Record<string, any>
   };
   };
 
 
   // TODO: promisify
   // TODO: promisify
@@ -56,12 +56,12 @@ export default class ChartList extends Component<PropsType, StateType> {
             "pending_upgrade",
             "pending_upgrade",
             "pending_rollback",
             "pending_rollback",
             "superseded",
             "superseded",
-            "failed",
-          ],
+            "failed"
+          ]
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) => {
+      .then(res => {
         let charts = res.data || [];
         let charts = res.data || [];
         if (this.props.sortType == "Newest") {
         if (this.props.sortType == "Newest") {
           charts.sort((a: any, b: any) =>
           charts.sort((a: any, b: any) =>
@@ -83,7 +83,7 @@ export default class ChartList extends Component<PropsType, StateType> {
         });
         });
         callback(charts);
         callback(charts);
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         this.setState({ loading: false, error: true });
         this.setState({ loading: false, error: true });
@@ -117,8 +117,8 @@ export default class ChartList extends Component<PropsType, StateType> {
       this.setState({
       this.setState({
         controllers: {
         controllers: {
           ...this.state.controllers,
           ...this.state.controllers,
-          [chartKey]: chartControllers,
-        },
+          [chartKey]: chartControllers
+        }
       });
       });
     };
     };
 
 
@@ -155,15 +155,15 @@ export default class ChartList extends Component<PropsType, StateType> {
             {
             {
               namespace: chart.namespace,
               namespace: chart.namespace,
               cluster_id: currentCluster.id,
               cluster_id: currentCluster.id,
-              storage: StorageType.Secret,
+              storage: StorageType.Secret
             },
             },
             {
             {
               id: currentProject.id,
               id: currentProject.id,
               name: chart.name,
               name: chart.name,
-              revision: chart.version,
+              revision: chart.version
             }
             }
           )
           )
-          .then((res) => {
+          .then(res => {
             // transform controller array into hash table for easy lookup during updates.
             // transform controller array into hash table for easy lookup during updates.
             let chartControllers = {} as Record<string, Record<string, any>>;
             let chartControllers = {} as Record<string, Record<string, any>>;
             res.data.forEach((c: any) => {
             res.data.forEach((c: any) => {
@@ -177,12 +177,12 @@ export default class ChartList extends Component<PropsType, StateType> {
                   {
                   {
                     chartLookupTable: {
                     chartLookupTable: {
                       ...this.state.chartLookupTable,
                       ...this.state.chartLookupTable,
-                      [c.metadata.uid]: `${chart.namespace}-${chart.name}`,
+                      [c.metadata.uid]: `${chart.namespace}-${chart.name}`
                     },
                     },
                     controllers: {
                     controllers: {
                       ...this.state.controllers,
                       ...this.state.controllers,
-                      [`${chart.namespace}-${chart.name}`]: chartControllers,
-                    },
+                      [`${chart.namespace}-${chart.name}`]: chartControllers
+                    }
                   },
                   },
                   () => {
                   () => {
                     nextController();
                     nextController();
@@ -192,7 +192,7 @@ export default class ChartList extends Component<PropsType, StateType> {
             });
             });
             next();
             next();
           })
           })
-          .catch((err) => {
+          .catch(err => {
             setCurrentError(JSON.stringify(err));
             setCurrentError(JSON.stringify(err));
             return;
             return;
           });
           });
@@ -206,7 +206,7 @@ export default class ChartList extends Component<PropsType, StateType> {
       "deployment",
       "deployment",
       "statefulset",
       "statefulset",
       "daemonset",
       "daemonset",
-      "replicaset",
+      "replicaset"
     ]);
     ]);
   }
   }
 
 

+ 39 - 39
dashboard/src/main/home/cluster-dashboard/expanded-chart/ExpandedChart.tsx

@@ -8,7 +8,7 @@ import {
   ResourceType,
   ResourceType,
   ChartType,
   ChartType,
   StorageType,
   StorageType,
-  ClusterType,
+  ClusterType
 } from "shared/types";
 } from "shared/types";
 import { Context } from "shared/Context";
 import { Context } from "shared/Context";
 import api from "shared/api";
 import api from "shared/api";
@@ -72,7 +72,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
     websockets: {} as Record<string, any>,
     websockets: {} as Record<string, any>,
     url: null as string | null,
     url: null as string | null,
     showDeleteOverlay: false,
     showDeleteOverlay: false,
-    deleting: false,
+    deleting: false
   };
   };
 
 
   // Retrieve full chart data (includes form and values)
   // Retrieve full chart data (includes form and values)
@@ -87,15 +87,15 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
         {
         {
           namespace: currentChart.namespace,
           namespace: currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         {
         {
           name: chart.name,
           name: chart.name,
           revision: chart.version,
           revision: chart.version,
-          id: currentProject.id,
+          id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         setCurrentChart(res.data);
         setCurrentChart(res.data);
         this.setState({ loading: false });
         this.setState({ loading: false });
       })
       })
@@ -116,15 +116,15 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
           {
           {
             namespace: chart.namespace,
             namespace: chart.namespace,
             cluster_id: currentCluster.id,
             cluster_id: currentCluster.id,
-            storage: StorageType.Secret,
+            storage: StorageType.Secret
           },
           },
           {
           {
             id: currentProject.id,
             id: currentProject.id,
             name: chart.name,
             name: chart.name,
-            revision: chart.version,
+            revision: chart.version
           }
           }
         )
         )
-        .then((res) => {
+        .then(res => {
           res.data.forEach(async (c: any) => {
           res.data.forEach(async (c: any) => {
             await new Promise((nextController: (res?: any) => void) => {
             await new Promise((nextController: (res?: any) => void) => {
               c.metadata.kind = c.kind;
               c.metadata.kind = c.kind;
@@ -132,8 +132,8 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
                 {
                 {
                   controllers: {
                   controllers: {
                     ...this.state.controllers,
                     ...this.state.controllers,
-                    [c.metadata.uid]: c,
-                  },
+                    [c.metadata.uid]: c
+                  }
                 },
                 },
                 () => {
                 () => {
                   nextController();
                   nextController();
@@ -143,7 +143,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
           });
           });
           next();
           next();
         })
         })
-        .catch((err) => setCurrentError(JSON.stringify(err)));
+        .catch(err => setCurrentError(JSON.stringify(err)));
     });
     });
   };
   };
 
 
@@ -167,8 +167,8 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
       this.setState({
       this.setState({
         controllers: {
         controllers: {
           ...this.state.controllers,
           ...this.state.controllers,
-          [object.metadata.uid]: object,
-        },
+          [object.metadata.uid]: object
+        }
       });
       });
     };
     };
 
 
@@ -201,18 +201,18 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
         {
         {
           namespace: currentChart.namespace,
           namespace: currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: currentChart.name,
           name: currentChart.name,
-          revision: currentChart.version,
+          revision: currentChart.version
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({
         this.setState({
           components: res.data.Objects,
           components: res.data.Objects,
-          podSelectors: res.data.PodSelectors,
+          podSelectors: res.data.PodSelectors
         });
         });
       })
       })
       .catch(console.log);
       .catch(console.log);
@@ -233,7 +233,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
     // Weave in preexisting values and convert to yaml
     // Weave in preexisting values and convert to yaml
     let valuesYaml = yaml.dump({
     let valuesYaml = yaml.dump({
       ...(this.props.currentChart.config as Object),
       ...(this.props.currentChart.config as Object),
-      ...values,
+      ...values
     });
     });
 
 
     this.setState({ saveValuesStatus: "loading" });
     this.setState({ saveValuesStatus: "loading" });
@@ -244,31 +244,31 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
         {
         {
           namespace: this.props.currentChart.namespace,
           namespace: this.props.currentChart.namespace,
           storage: StorageType.Secret,
           storage: StorageType.Secret,
-          values: valuesYaml,
+          values: valuesYaml
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: this.props.currentChart.name,
           name: this.props.currentChart.name,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({
         this.setState({
           saveValuesStatus: "successful",
           saveValuesStatus: "successful",
-          forceRefreshRevisions: true,
+          forceRefreshRevisions: true
         });
         });
 
 
         window.analytics.track("Chart Upgraded", {
         window.analytics.track("Chart Upgraded", {
           chart: this.props.currentChart.name,
           chart: this.props.currentChart.name,
-          values: valuesYaml,
+          values: valuesYaml
         });
         });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         this.setState({ saveValuesStatus: "error" });
         this.setState({ saveValuesStatus: "error" });
         window.analytics.track("Failed to Upgrade Chart", {
         window.analytics.track("Failed to Upgrade Chart", {
           chart: this.props.currentChart.name,
           chart: this.props.currentChart.name,
           values: valuesYaml,
           values: valuesYaml,
-          error: err,
+          error: err
         });
         });
       });
       });
   };
   };
@@ -280,7 +280,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
       components,
       components,
       showRevisions,
       showRevisions,
       saveValuesStatus,
       saveValuesStatus,
-      tabOptions,
+      tabOptions
     } = this.state;
     } = this.state;
     let { currentChart, setSidebar } = this.props;
     let { currentChart, setSidebar } = this.props;
     let chart = currentChart;
     let chart = currentChart;
@@ -374,7 +374,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
           value: "@" + tab.name,
           value: "@" + tab.name,
           label: tab.label,
           label: tab.label,
           sections: tab.sections,
           sections: tab.sections,
-          context: tab.context,
+          context: tab.context
         });
         });
       });
       });
     }
     }
@@ -447,7 +447,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
     let date = ts.toLocaleDateString();
     let date = ts.toLocaleDateString();
     let time = ts.toLocaleTimeString([], {
     let time = ts.toLocaleTimeString([], {
       hour: "numeric",
       hour: "numeric",
-      minute: "2-digit",
+      minute: "2-digit"
     });
     });
     return `${time} on ${date}`;
     return `${time} on ${date}`;
   };
   };
@@ -499,7 +499,7 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
     let { currentChart } = this.props;
     let { currentChart } = this.props;
 
 
     window.analytics.track("Opened Chart", {
     window.analytics.track("Opened Chart", {
-      chart: currentChart.name,
+      chart: currentChart.name
     });
     });
 
 
     this.getChartData(currentChart);
     this.getChartData(currentChart);
@@ -515,15 +515,15 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
         {
         {
           namespace: currentChart.namespace,
           namespace: currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: currentChart.name,
           name: currentChart.name,
-          revision: currentChart.version,
+          revision: currentChart.version
         }
         }
       )
       )
-      .then((res) =>
+      .then(res =>
         this.setState({ components: res.data.Objects }, () => {
         this.setState({ components: res.data.Objects }, () => {
           let ingressName = null;
           let ingressName = null;
           for (var i = 0; i < this.state.components.length; i++) {
           for (var i = 0; i < this.state.components.length; i++) {
@@ -536,25 +536,25 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
             .getIngress(
             .getIngress(
               "<token>",
               "<token>",
               {
               {
-                cluster_id: currentCluster.id,
+                cluster_id: currentCluster.id
               },
               },
               {
               {
                 id: currentProject.id,
                 id: currentProject.id,
                 name: ingressName,
                 name: ingressName,
-                namespace: `${this.props.currentChart.namespace}`,
+                namespace: `${this.props.currentChart.namespace}`
               }
               }
             )
             )
-            .then((res) => {
+            .then(res => {
               if (res.data?.spec?.rules && res.data?.spec?.rules[0]?.host) {
               if (res.data?.spec?.rules && res.data?.spec?.rules[0]?.host) {
                 this.setState({
                 this.setState({
-                  url: `https://${res.data?.spec?.rules[0]?.host}`,
+                  url: `https://${res.data?.spec?.rules[0]?.host}`
                 });
                 });
                 return;
                 return;
               }
               }
 
 
               if (res.data?.status?.loadBalancer?.ingress) {
               if (res.data?.status?.loadBalancer?.ingress) {
                 this.setState({
                 this.setState({
-                  url: `http://${res.data?.status?.loadBalancer?.ingress[0]?.hostname}`,
+                  url: `http://${res.data?.status?.loadBalancer?.ingress[0]?.hostname}`
                 });
                 });
                 return;
                 return;
               }
               }
@@ -623,10 +623,10 @@ export default class ExpandedChart extends Component<PropsType, StateType> {
           storage: StorageType.Secret,
           storage: StorageType.Secret,
           name: currentChart.name,
           name: currentChart.name,
           id: currentProject.id,
           id: currentProject.id,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ showDeleteOverlay: false });
         this.setState({ showDeleteOverlay: false });
         this.props.setCurrentChart(null);
         this.props.setCurrentChart(null);
       })
       })

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/GraphSection.tsx

@@ -20,7 +20,7 @@ type StateType = {
 
 
 export default class GraphSection extends Component<PropsType, StateType> {
 export default class GraphSection extends Component<PropsType, StateType> {
   state = {
   state = {
-    isExpanded: false,
+    isExpanded: false
   };
   };
 
 
   renderContents = () => {
   renderContents = () => {

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/expanded-chart/ListSection.tsx

@@ -27,7 +27,7 @@ export default class ListSection extends Component<PropsType, StateType> {
     showKindLabels: true,
     showKindLabels: true,
     yaml: "# Select a resource to view its manifest" as string | null,
     yaml: "# Select a resource to view its manifest" as string | null,
     wrapperHeight: 0,
     wrapperHeight: 0,
-    selectedResource: null as { kind: string; name: string } | null,
+    selectedResource: null as { kind: string; name: string } | null
   };
   };
 
 
   wrapperRef: any = React.createRef();
   wrapperRef: any = React.createRef();
@@ -75,7 +75,7 @@ export default class ListSection extends Component<PropsType, StateType> {
           handleClick={() =>
           handleClick={() =>
             this.setState({
             this.setState({
               yaml: rawYaml,
               yaml: rawYaml,
-              selectedResource: { kind: resource.Kind, name: resource.Name },
+              selectedResource: { kind: resource.Kind, name: resource.Name }
             })
             })
           }
           }
           selected={this.state.yaml === rawYaml}
           selected={this.state.yaml === rawYaml}
@@ -99,7 +99,7 @@ export default class ListSection extends Component<PropsType, StateType> {
     return (
     return (
       <StyledListSection>
       <StyledListSection>
         {this.renderTabs()}
         {this.renderTabs()}
-        <FlexWrapper ref={(element) => (this.wrapperRef = element)}>
+        <FlexWrapper ref={element => (this.wrapperRef = element)}>
           <YamlWrapper>
           <YamlWrapper>
             <YamlEditor
             <YamlEditor
               value={this.state.yaml}
               value={this.state.yaml}

+ 9 - 9
dashboard/src/main/home/cluster-dashboard/expanded-chart/RevisionSection.tsx

@@ -32,7 +32,7 @@ export default class RevisionSection extends Component<PropsType, StateType> {
     revisions: [] as ChartType[],
     revisions: [] as ChartType[],
     rollbackRevision: null as number | null,
     rollbackRevision: null as number | null,
     loading: false,
     loading: false,
-    maxVersion: 0, // Track most recent version even when previewing old revisions
+    maxVersion: 0 // Track most recent version even when previewing old revisions
   };
   };
 
 
   refreshHistory = () => {
   refreshHistory = () => {
@@ -44,17 +44,17 @@ export default class RevisionSection extends Component<PropsType, StateType> {
         {
         {
           namespace: chart.namespace,
           namespace: chart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         { id: currentProject.id, name: chart.name }
         { id: currentProject.id, name: chart.name }
       )
       )
-      .then((res) => {
+      .then(res => {
         res.data.sort((a: ChartType, b: ChartType) => {
         res.data.sort((a: ChartType, b: ChartType) => {
           return -(a.version - b.version);
           return -(a.version - b.version);
         });
         });
         this.setState({
         this.setState({
           revisions: res.data,
           revisions: res.data,
-          maxVersion: res.data[0].version,
+          maxVersion: res.data[0].version
         });
         });
       })
       })
       .catch(console.log);
       .catch(console.log);
@@ -83,7 +83,7 @@ export default class RevisionSection extends Component<PropsType, StateType> {
     let date = ts.toLocaleDateString();
     let date = ts.toLocaleDateString();
     let time = ts.toLocaleTimeString([], {
     let time = ts.toLocaleTimeString([], {
       hour: "numeric",
       hour: "numeric",
-      minute: "2-digit",
+      minute: "2-digit"
     });
     });
     return `${time} on ${date}`;
     return `${time} on ${date}`;
   };
   };
@@ -100,21 +100,21 @@ export default class RevisionSection extends Component<PropsType, StateType> {
         {
         {
           namespace: this.props.chart.namespace,
           namespace: this.props.chart.namespace,
           storage: StorageType.Secret,
           storage: StorageType.Secret,
-          revision: revisionNumber,
+          revision: revisionNumber
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: this.props.chart.name,
           name: this.props.chart.name,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ loading: false });
         this.setState({ loading: false });
         this.refreshHistory().then(() => {
         this.refreshHistory().then(() => {
           this.props.setRevision(this.state.revisions[0], true);
           this.props.setRevision(this.state.revisions[0], true);
         });
         });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         setCurrentError(err.response.data);
         setCurrentError(err.response.data);
         this.setState({ loading: false });
         this.setState({ loading: false });

+ 18 - 19
dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx

@@ -7,7 +7,7 @@ import {
   ChartType,
   ChartType,
   RepoType,
   RepoType,
   StorageType,
   StorageType,
-  ActionConfigType,
+  ActionConfigType
 } from "shared/types";
 } from "shared/types";
 import { Context } from "shared/Context";
 import { Context } from "shared/Context";
 
 
@@ -47,8 +47,8 @@ export default class SettingsSection extends Component<PropsType, StateType> {
     action: {
     action: {
       git_repo: "",
       git_repo: "",
       image_repo_uri: "",
       image_repo_uri: "",
-      git_repo_id: 0,
-    } as ActionConfigType,
+      git_repo_id: 0
+    } as ActionConfigType
   };
   };
 
 
   // TODO: read in set image from form context instead of config
   // TODO: read in set image from form context instead of config
@@ -58,7 +58,7 @@ export default class SettingsSection extends Component<PropsType, StateType> {
     let image = this.props.currentChart.config?.image;
     let image = this.props.currentChart.config?.image;
     this.setState({
     this.setState({
       selectedImageUrl: image?.repository,
       selectedImageUrl: image?.repository,
-      selectedTag: image?.tag,
+      selectedTag: image?.tag
     });
     });
 
 
     api
     api
@@ -67,15 +67,15 @@ export default class SettingsSection extends Component<PropsType, StateType> {
         {
         {
           namespace: this.props.currentChart.namespace,
           namespace: this.props.currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         { id: currentProject.id, name: this.props.currentChart.name }
         { id: currentProject.id, name: this.props.currentChart.name }
       )
       )
-      .then((res) => {
+      .then(res => {
         console.log(res.data);
         console.log(res.data);
         this.setState({
         this.setState({
           action: res.data.git_action_config,
           action: res.data.git_action_config,
-          webhookToken: res.data.webhook_token,
+          webhookToken: res.data.webhook_token
         });
         });
       })
       })
       .catch(console.log);
       .catch(console.log);
@@ -96,8 +96,8 @@ export default class SettingsSection extends Component<PropsType, StateType> {
     let image = {
     let image = {
       image: {
       image: {
         repository: img,
         repository: img,
-        tag: parsedTag || tag,
-      },
+        tag: parsedTag || tag
+      }
     };
     };
 
 
     let values = {};
     let values = {};
@@ -109,7 +109,7 @@ export default class SettingsSection extends Component<PropsType, StateType> {
     // Weave in preexisting values and convert to yaml
     // Weave in preexisting values and convert to yaml
     let valuesYaml = yaml.dump({
     let valuesYaml = yaml.dump({
       ...values,
       ...values,
-      ...image,
+      ...image
     });
     });
 
 
     api
     api
@@ -118,19 +118,19 @@ export default class SettingsSection extends Component<PropsType, StateType> {
         {
         {
           namespace: this.props.currentChart.namespace,
           namespace: this.props.currentChart.namespace,
           storage: StorageType.Secret,
           storage: StorageType.Secret,
-          values: valuesYaml,
+          values: valuesYaml
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: this.props.currentChart.name,
           name: this.props.currentChart.name,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ saveValuesStatus: "successful" });
         this.setState({ saveValuesStatus: "successful" });
         this.props.refreshChart();
         this.props.refreshChart();
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         this.setState({ saveValuesStatus: "error" });
         this.setState({ saveValuesStatus: "error" });
       });
       });
@@ -213,16 +213,15 @@ const Button = styled.button`
   text-align: left;
   text-align: left;
   border: 0;
   border: 0;
   border-radius: 5px;
   border-radius: 5px;
-  background: ${(props) => (!props.disabled ? props.color : "#aaaabb")};
-  box-shadow: ${(props) =>
-    !props.disabled ? "0 2px 5px 0 #00000030" : "none"};
-  cursor: ${(props) => (!props.disabled ? "pointer" : "default")};
+  background: ${props => (!props.disabled ? props.color : "#aaaabb")};
+  box-shadow: ${props => (!props.disabled ? "0 2px 5px 0 #00000030" : "none")};
+  cursor: ${props => (!props.disabled ? "pointer" : "default")};
   user-select: none;
   user-select: none;
   :focus {
   :focus {
     outline: 0;
     outline: 0;
   }
   }
   :hover {
   :hover {
-    filter: ${(props) => (!props.disabled ? "brightness(120%)" : "")};
+    filter: ${props => (!props.disabled ? "brightness(120%)" : "")};
   }
   }
 `;
 `;
 
 

+ 5 - 5
dashboard/src/main/home/cluster-dashboard/expanded-chart/ValuesYaml.tsx

@@ -23,7 +23,7 @@ type StateType = {
 export default class ValuesYaml extends Component<PropsType, StateType> {
 export default class ValuesYaml extends Component<PropsType, StateType> {
   state = {
   state = {
     values: "",
     values: "",
-    saveValuesStatus: null as string | null,
+    saveValuesStatus: null as string | null
   };
   };
 
 
   updateValues() {
   updateValues() {
@@ -54,19 +54,19 @@ export default class ValuesYaml extends Component<PropsType, StateType> {
         {
         {
           namespace: this.props.currentChart.namespace,
           namespace: this.props.currentChart.namespace,
           storage: StorageType.Secret,
           storage: StorageType.Secret,
-          values: this.state.values,
+          values: this.state.values
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: this.props.currentChart.name,
           name: this.props.currentChart.name,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ saveValuesStatus: "successful" });
         this.setState({ saveValuesStatus: "successful" });
         this.props.refreshChart();
         this.props.refreshChart();
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         this.setState({ saveValuesStatus: "error" });
         this.setState({ saveValuesStatus: "error" });
       });
       });

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/deploy/DeploySection.tsx

@@ -19,7 +19,7 @@ type StateType = {
 export default class StatusSection extends Component<PropsType, StateType> {
 export default class StatusSection extends Component<PropsType, StateType> {
   state = {
   state = {
     events: [] as any[],
     events: [] as any[],
-    loading: true,
+    loading: true
   };
   };
 
 
   renderTabs = () => {
   renderTabs = () => {

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/Edge.tsx

@@ -23,7 +23,7 @@ type StateType = {
 
 
 export default class Edge extends Component<PropsType, StateType> {
 export default class Edge extends Component<PropsType, StateType> {
   state = {
   state = {
-    showArrowHead: true,
+    showArrowHead: true
   };
   };
 
 
   render() {
   render() {
@@ -81,8 +81,8 @@ const StyledEdge: any = styled.div.attrs((props: any) => ({
     top: props.cy + "px",
     top: props.cy + "px",
     left: props.cx + "px",
     left: props.cx + "px",
     transform: "rotate(" + props.angle + "deg)",
     transform: "rotate(" + props.angle + "deg)",
-    width: props.length + "px",
-  },
+    width: props.length + "px"
+  }
 }))`
 }))`
   position: absolute;
   position: absolute;
   height: ${thickness}px;
   height: ${thickness}px;

+ 19 - 19
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/GraphDisplay.tsx

@@ -82,7 +82,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
     currentEdge: null as EdgeType | null,
     currentEdge: null as EdgeType | null,
     openedNode: null as NodeType | null,
     openedNode: null as NodeType | null,
     suppressCloseNode: false,
     suppressCloseNode: false,
-    suppressDisplay: false,
+    suppressDisplay: false
   };
   };
 
 
   spaceRef: any = React.createRef();
   spaceRef: any = React.createRef();
@@ -122,7 +122,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
     let width = this.spaceRef.offsetWidth;
     let width = this.spaceRef.offsetWidth;
     this.setState({
     this.setState({
       originX: Math.round(width / 2),
       originX: Math.round(width / 2),
-      originY: Math.round(height / 2),
+      originY: Math.round(height / 2)
     });
     });
 
 
     // Suppress trackpad gestures
     // Suppress trackpad gestures
@@ -164,7 +164,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
             x: this.getRandomIntBetweenRange(-500, 0),
             x: this.getRandomIntBetweenRange(-500, 0),
             y: this.getRandomIntBetweenRange(0, 250),
             y: this.getRandomIntBetweenRange(0, 250),
             w: 40,
             w: 40,
-            h: 40,
+            h: 40
           };
           };
         case "Deployment":
         case "Deployment":
         case "StatefulSet":
         case "StatefulSet":
@@ -178,7 +178,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
             x: this.getRandomIntBetweenRange(0, 500),
             x: this.getRandomIntBetweenRange(0, 500),
             y: this.getRandomIntBetweenRange(0, 250),
             y: this.getRandomIntBetweenRange(0, 250),
             w: 40,
             w: 40,
-            h: 40,
+            h: 40
           };
           };
         case "Service":
         case "Service":
         case "Ingress":
         case "Ingress":
@@ -191,7 +191,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
             x: this.getRandomIntBetweenRange(0, 500),
             x: this.getRandomIntBetweenRange(0, 500),
             y: this.getRandomIntBetweenRange(-250, 0),
             y: this.getRandomIntBetweenRange(-250, 0),
             w: 40,
             w: 40,
-            h: 40,
+            h: 40
           };
           };
         default:
         default:
           return {
           return {
@@ -202,7 +202,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
             x: this.getRandomIntBetweenRange(-400, 0),
             x: this.getRandomIntBetweenRange(-400, 0),
             y: this.getRandomIntBetweenRange(-250, 0),
             y: this.getRandomIntBetweenRange(-250, 0),
             w: 40,
             w: 40,
-            h: 40,
+            h: 40
           };
           };
       }
       }
     });
     });
@@ -216,7 +216,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
           edges.push({
           edges.push({
             type: "ControlRel",
             type: "ControlRel",
             source: rel.Source,
             source: rel.Source,
-            target: rel.Target,
+            target: rel.Target
           });
           });
         }
         }
       });
       });
@@ -225,7 +225,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
           edges.push({
           edges.push({
             type: "LabelRel",
             type: "LabelRel",
             source: rel.Source,
             source: rel.Source,
-            target: rel.Target,
+            target: rel.Target
           });
           });
         }
         }
       });
       });
@@ -234,7 +234,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
           edges.push({
           edges.push({
             type: "SpecRel",
             type: "SpecRel",
             source: rel.Source,
             source: rel.Source,
-            target: rel.Target,
+            target: rel.Target
           });
           });
         }
         }
       });
       });
@@ -287,7 +287,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
         panX: null,
         panX: null,
         panY: null,
         panY: null,
         deltaX: null,
         deltaX: null,
-        deltaY: null,
+        deltaY: null
       });
       });
     }
     }
   };
   };
@@ -302,7 +302,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
         panX: null,
         panX: null,
         panY: null,
         panY: null,
         deltaX: null,
         deltaX: null,
-        deltaY: null,
+        deltaY: null
       });
       });
     }
     }
   };
   };
@@ -314,7 +314,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
     this.setState({
     this.setState({
       nodeClickX: cursorX,
       nodeClickX: cursorX,
       nodeClickY: cursorY,
       nodeClickY: cursorY,
-      suppressCloseNode: true,
+      suppressCloseNode: true
     });
     });
 
 
     // Push to activeIds if not already present
     // Push to activeIds if not already present
@@ -334,7 +334,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
     this.setState({
     this.setState({
       activeIds: holding,
       activeIds: holding,
       preventBgDrag: true,
       preventBgDrag: true,
-      relocateAllowed: true,
+      relocateAllowed: true
     });
     });
   };
   };
 
 
@@ -362,7 +362,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
       deltaY: null,
       deltaY: null,
       panX: null,
       panX: null,
       panY: null,
       panY: null,
-      scale: 1,
+      scale: 1
     });
     });
   };
   };
 
 
@@ -372,7 +372,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
       nodeClickX,
       nodeClickX,
       cursorY,
       cursorY,
       nodeClickY,
       nodeClickY,
-      suppressCloseNode,
+      suppressCloseNode
     } = this.state;
     } = this.state;
     this.setState({ dragBg: false, activeIds: [] });
     this.setState({ dragBg: false, activeIds: [] });
 
 
@@ -401,7 +401,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
       anchorY,
       anchorY,
       nodes,
       nodes,
       activeIds,
       activeIds,
-      relocateAllowed,
+      relocateAllowed
     } = this.state;
     } = this.state;
 
 
     // Suppress navigation gestures
     // Suppress navigation gestures
@@ -478,7 +478,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
       }
       }
       this.setState({
       this.setState({
         originX: Math.round(width / 2) - nudge,
         originX: Math.round(width / 2) - nudge,
-        originY: Math.round(height / 2),
+        originY: Math.round(height / 2)
       });
       });
     });
     });
   };
   };
@@ -496,7 +496,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
       panY,
       panY,
       anchorX,
       anchorX,
       anchorY,
       anchorY,
-      relocateAllowed,
+      relocateAllowed
     } = this.state;
     } = this.state;
 
 
     let minX = 0;
     let minX = 0;
@@ -606,7 +606,7 @@ export default class GraphDisplay extends Component<PropsType, StateType> {
     return (
     return (
       <StyledGraphDisplay
       <StyledGraphDisplay
         isExpanded={this.state.isExpanded}
         isExpanded={this.state.isExpanded}
-        ref={(element) => (this.spaceRef = element)}
+        ref={element => (this.spaceRef = element)}
         onMouseMove={this.handleMouseMove}
         onMouseMove={this.handleMouseMove}
         onMouseDown={this.state.suppressDisplay ? null : this.handleMouseDown}
         onMouseDown={this.state.suppressDisplay ? null : this.handleMouseDown}
         onMouseUp={this.state.suppressDisplay ? null : this.handleMouseUp}
         onMouseUp={this.state.suppressDisplay ? null : this.handleMouseUp}

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/InfoPanel.tsx

@@ -23,7 +23,7 @@ type StateType = {
 
 
 export default class InfoPanel extends Component<PropsType, StateType> {
 export default class InfoPanel extends Component<PropsType, StateType> {
   state = {
   state = {
-    wrapperHeight: 0,
+    wrapperHeight: 0
   };
   };
 
 
   renderIcon = (kind: string) => {
   renderIcon = (kind: string) => {
@@ -70,7 +70,7 @@ export default class InfoPanel extends Component<PropsType, StateType> {
             {openedNode.kind}
             {openedNode.kind}
             <ResourceName>{openedNode.name}</ResourceName>
             <ResourceName>{openedNode.name}</ResourceName>
           </Div>
           </Div>
-          <YamlWrapper ref={(element) => (this.wrapperRef = element)}>
+          <YamlWrapper ref={element => (this.wrapperRef = element)}>
             <YamlEditor
             <YamlEditor
               value={yaml.dump(openedNode.RawYAML)}
               value={yaml.dump(openedNode.RawYAML)}
               readOnly={true}
               readOnly={true}

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/Node.tsx

@@ -116,8 +116,8 @@ const NodeBlock = styled.div`
 const StyledNode: any = styled.div.attrs((props: NodeType) => ({
 const StyledNode: any = styled.div.attrs((props: NodeType) => ({
   style: {
   style: {
     top: props.y + "px",
     top: props.y + "px",
-    left: props.x + "px",
-  },
+    left: props.x + "px"
+  }
 }))`
 }))`
   position: absolute;
   position: absolute;
   width: ${(props: NodeType) => props.w + "px"};
   width: ${(props: NodeType) => props.w + "px"};

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/SelectRegion.tsx

@@ -50,8 +50,8 @@ const StyledSelectRegion: any = styled.div.attrs(
       top: props.y + "px",
       top: props.y + "px",
       left: props.x + "px",
       left: props.x + "px",
       width: props.w + "px",
       width: props.w + "px",
-      height: props.h + "px",
-    },
+      height: props.h + "px"
+    }
   })
   })
 )`
 )`
   position: absolute;
   position: absolute;

+ 1 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/graph/ZoomPanel.tsx

@@ -12,7 +12,7 @@ type StateType = {
 
 
 export default class ZoomPanel extends Component<PropsType, StateType> {
 export default class ZoomPanel extends Component<PropsType, StateType> {
   state = {
   state = {
-    wrapperHeight: 0,
+    wrapperHeight: 0
   };
   };
 
 
   wrapperRef: any = React.createRef();
   wrapperRef: any = React.createRef();

+ 13 - 13
dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/AreaChart.tsx

@@ -8,7 +8,7 @@ import {
   withTooltip,
   withTooltip,
   Tooltip,
   Tooltip,
   TooltipWithBounds,
   TooltipWithBounds,
-  defaultStyles,
+  defaultStyles
 } from "@visx/tooltip";
 } from "@visx/tooltip";
 
 
 import { GridRows, GridColumns } from "@visx/grid";
 import { GridRows, GridColumns } from "@visx/grid";
@@ -41,7 +41,7 @@ const tooltipStyles = {
   ...defaultStyles,
   ...defaultStyles,
   background,
   background,
   border: "1px solid white",
   border: "1px solid white",
-  color: "white",
+  color: "white"
 };
 };
 
 
 // util
 // util
@@ -55,14 +55,14 @@ const formats: { [range: string]: (date: Date) => string } = {
   "1H": hourFormat,
   "1H": hourFormat,
   "6H": hourFormat,
   "6H": hourFormat,
   "1D": hourFormat,
   "1D": hourFormat,
-  "1M": dayFormat,
+  "1M": dayFormat
 };
 };
 
 
 // accessors
 // accessors
 const getDate = (d: MetricsData) => new Date(d.date * 1000);
 const getDate = (d: MetricsData) => new Date(d.date * 1000);
 const getValue = (d: MetricsData) => d.value;
 const getValue = (d: MetricsData) => d.value;
 
 
-const bisectDate = bisector<MetricsData, Date>((d) => new Date(d.date * 1000))
+const bisectDate = bisector<MetricsData, Date>(d => new Date(d.date * 1000))
   .left;
   .left;
 
 
 export type AreaProps = {
 export type AreaProps = {
@@ -84,7 +84,7 @@ export default withTooltip<AreaProps, TooltipData>(
     hideTooltip,
     hideTooltip,
     tooltipData,
     tooltipData,
     tooltipTop = 0,
     tooltipTop = 0,
-    tooltipLeft = 0,
+    tooltipLeft = 0
   }: AreaProps & WithTooltipProvidedProps<TooltipData>) => {
   }: AreaProps & WithTooltipProvidedProps<TooltipData>) => {
     globalData = data;
     globalData = data;
 
 
@@ -101,7 +101,7 @@ export default withTooltip<AreaProps, TooltipData>(
       () =>
       () =>
         scaleTime({
         scaleTime({
           range: [margin.left, innerWidth + margin.left],
           range: [margin.left, innerWidth + margin.left],
-          domain: extent(globalData, getDate) as [Date, Date],
+          domain: extent(globalData, getDate) as [Date, Date]
         }),
         }),
       [innerWidth, margin.left, width, height, data]
       [innerWidth, margin.left, width, height, data]
     );
     );
@@ -110,7 +110,7 @@ export default withTooltip<AreaProps, TooltipData>(
         scaleLinear({
         scaleLinear({
           range: [innerHeight + margin.top, margin.top],
           range: [innerHeight + margin.top, margin.top],
           domain: [0, 1.25 * max(globalData, getValue)],
           domain: [0, 1.25 * max(globalData, getValue)],
-          nice: true,
+          nice: true
         }),
         }),
       [margin.top, innerHeight, width, height, data]
       [margin.top, innerHeight, width, height, data]
     );
     );
@@ -140,7 +140,7 @@ export default withTooltip<AreaProps, TooltipData>(
         showTooltip({
         showTooltip({
           tooltipData: d,
           tooltipData: d,
           tooltipLeft: x || 0,
           tooltipLeft: x || 0,
-          tooltipTop: valueScale(getValue(d)) || 0,
+          tooltipTop: valueScale(getValue(d)) || 0
         });
         });
       },
       },
       [showTooltip, valueScale, dateScale, width, height, data]
       [showTooltip, valueScale, dateScale, width, height, data]
@@ -188,8 +188,8 @@ export default withTooltip<AreaProps, TooltipData>(
           />
           />
           <AreaClosed<MetricsData>
           <AreaClosed<MetricsData>
             data={data}
             data={data}
-            x={(d) => dateScale(getDate(d)) ?? 0}
-            y={(d) => valueScale(getValue(d)) ?? 0}
+            x={d => dateScale(getDate(d)) ?? 0}
+            y={d => valueScale(getValue(d)) ?? 0}
             height={innerHeight}
             height={innerHeight}
             yScale={valueScale}
             yScale={valueScale}
             strokeWidth={1}
             strokeWidth={1}
@@ -207,7 +207,7 @@ export default withTooltip<AreaProps, TooltipData>(
               fontSize: 11,
               fontSize: 11,
               textAnchor: "start",
               textAnchor: "start",
               fillOpacity: 0.4,
               fillOpacity: 0.4,
-              dy: 0,
+              dy: 0
             })}
             })}
           />
           />
           <AxisBottom
           <AxisBottom
@@ -220,7 +220,7 @@ export default withTooltip<AreaProps, TooltipData>(
               fill: "white",
               fill: "white",
               fontSize: 11,
               fontSize: 11,
               textAnchor: "middle",
               textAnchor: "middle",
-              fillOpacity: 0.4,
+              fillOpacity: 0.4
             })}
             })}
           />
           />
           <Bar
           <Bar
@@ -288,7 +288,7 @@ export default withTooltip<AreaProps, TooltipData>(
                 width: 100,
                 width: 100,
                 paddingTop: 35,
                 paddingTop: 35,
                 textAlign: "center",
                 textAlign: "center",
-                transform: "translateX(-60px)",
+                transform: "translateX(-60px)"
               }}
               }}
             >
             >
               {formatDate(getDate(tooltipData))}
               {formatDate(getDate(tooltipData))}

+ 135 - 29
dashboard/src/main/home/cluster-dashboard/expanded-chart/metrics/MetricsSection.tsx

@@ -17,7 +17,9 @@ type PropsType = {
 
 
 type StateType = {
 type StateType = {
   controllerOptions: any[];
   controllerOptions: any[];
+  ingressOptions: any[];
   selectedController: any;
   selectedController: any;
+  selectedIngress: any;
   pods: any[];
   pods: any[];
   selectedPod: string;
   selectedPod: string;
   selectedRange: string;
   selectedRange: string;
@@ -28,6 +30,7 @@ type StateType = {
   dropdownExpanded: boolean;
   dropdownExpanded: boolean;
   data: MetricsData[];
   data: MetricsData[];
   showMetricsSettings: boolean;
   showMetricsSettings: boolean;
+  metricsOptions: MetricsOption[];
 };
 };
 
 
 type MetricsCPUDataResponse = {
 type MetricsCPUDataResponse = {
@@ -54,18 +57,31 @@ type MetricsNetworkDataResponse = {
   }[];
   }[];
 }[];
 }[];
 
 
+type MetricsNGINXErrorsDataResponse = {
+  pod?: string;
+  results: {
+    date: number;
+    error_pct: string;
+  }[];
+}[];
+
+type MetricsOption = {
+  value: string;
+  label: string;
+};
+
 const resolutions: { [range: string]: string } = {
 const resolutions: { [range: string]: string } = {
   "1H": "15s",
   "1H": "15s",
   "6H": "15s",
   "6H": "15s",
   "1D": "15s",
   "1D": "15s",
-  "1M": "5h",
+  "1M": "5h"
 };
 };
 
 
 const secondsBeforeNow: { [range: string]: number } = {
 const secondsBeforeNow: { [range: string]: number } = {
   "1H": 60 * 60,
   "1H": 60 * 60,
   "6H": 60 * 60 * 6,
   "6H": 60 * 60 * 6,
   "1D": 60 * 60 * 24,
   "1D": 60 * 60 * 24,
-  "1M": 60 * 60 * 24 * 30,
+  "1M": 60 * 60 * 24 * 30
 };
 };
 
 
 export default class MetricsSection extends Component<PropsType, StateType> {
 export default class MetricsSection extends Component<PropsType, StateType> {
@@ -74,6 +90,8 @@ export default class MetricsSection extends Component<PropsType, StateType> {
     selectedPod: "",
     selectedPod: "",
     controllerOptions: [] as any[],
     controllerOptions: [] as any[],
     selectedController: null as any,
     selectedController: null as any,
+    ingressOptions: [] as any[],
+    selectedIngress: null as any,
     selectedRange: "1H",
     selectedRange: "1H",
     selectedMetric: "cpu",
     selectedMetric: "cpu",
     selectedMetricLabel: "CPU Utilization (vCPUs)",
     selectedMetricLabel: "CPU Utilization (vCPUs)",
@@ -82,6 +100,11 @@ export default class MetricsSection extends Component<PropsType, StateType> {
     controllerDropdownExpanded: false,
     controllerDropdownExpanded: false,
     data: [] as MetricsData[],
     data: [] as MetricsData[],
     showMetricsSettings: false,
     showMetricsSettings: false,
+    metricsOptions: [
+      { value: "cpu", label: "CPU Utilization (vCPUs)" },
+      { value: "memory", label: "RAM Utilization (Mi)" },
+      { value: "network", label: "Network Received Bytes (Ki)" }
+    ]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -89,21 +112,57 @@ export default class MetricsSection extends Component<PropsType, StateType> {
     let { currentChart } = this.props;
     let { currentChart } = this.props;
     let { currentCluster, currentProject, setCurrentError } = this.context;
     let { currentCluster, currentProject, setCurrentError } = this.context;
 
 
+    if (currentChart.chart?.metadata?.name == "ingress-nginx") {
+      api
+        .getNGINXIngresses(
+          "<token>",
+          {
+            cluster_id: currentCluster.id
+          },
+          {
+            id: currentProject.id
+          }
+        )
+        .then(res => {
+          let metricsOptions = this.state.metricsOptions;
+          metricsOptions.push({
+            value: "nginx:errors",
+            label: "5XX Error Percentage"
+          });
+
+          let ingressOptions = [] as any[];
+          res.data.map((ingress: any) => {
+            ingressOptions.push({ value: ingress, label: ingress.name });
+          });
+
+          // iterate through the controllers to get the list of pods
+          this.setState({
+            metricsOptions,
+            ingressOptions,
+            selectedIngress: ingressOptions[0].value
+          });
+        })
+        .catch(err => {
+          setCurrentError(JSON.stringify(err));
+          this.setState({ controllerOptions: [] as any[] });
+        });
+    }
+
     api
     api
       .getChartControllers(
       .getChartControllers(
         "<token>",
         "<token>",
         {
         {
           namespace: currentChart.namespace,
           namespace: currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: currentChart.name,
           name: currentChart.name,
-          revision: currentChart.version,
+          revision: currentChart.version
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         // TODO -- check at least one controller returned
         // TODO -- check at least one controller returned
         let controllerOptions = [] as any[];
         let controllerOptions = [] as any[];
         res.data.map((controller: any) => {
         res.data.map((controller: any) => {
@@ -114,12 +173,12 @@ export default class MetricsSection extends Component<PropsType, StateType> {
         // iterate through the controllers to get the list of pods
         // iterate through the controllers to get the list of pods
         this.setState({
         this.setState({
           controllerOptions,
           controllerOptions,
-          selectedController: controllerOptions[0].value,
+          selectedController: controllerOptions[0].value
         });
         });
 
 
         this.getPods();
         this.getPods();
       })
       })
-      .catch((err) => {
+      .catch(err => {
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         this.setState({ controllerOptions: [] as any[] });
         this.setState({ controllerOptions: [] as any[] });
       });
       });
@@ -145,6 +204,10 @@ export default class MetricsSection extends Component<PropsType, StateType> {
     ) {
     ) {
       this.getMetrics();
       this.getMetrics();
     }
     }
+
+    if (this.state.selectedIngress?.name != prevState.selectedIngress?.name) {
+      this.getMetrics();
+    }
   }
   }
 
 
   getMetrics = () => {
   getMetrics = () => {
@@ -156,6 +219,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
     let { currentCluster, currentProject, setCurrentError } = this.context;
     let { currentCluster, currentProject, setCurrentError } = this.context;
     let kind = this.state.selectedMetric;
     let kind = this.state.selectedMetric;
     let shouldsum = true;
     let shouldsum = true;
+    let namespace = currentChart.namespace;
 
 
     // calculate start and end range
     // calculate start and end range
     var d = new Date();
     var d = new Date();
@@ -170,6 +234,12 @@ export default class MetricsSection extends Component<PropsType, StateType> {
       pods = [this.state.selectedPod];
       pods = [this.state.selectedPod];
     }
     }
 
 
+    if (this.state.selectedMetric == "nginx:errors") {
+      pods = [this.state.selectedIngress?.name];
+      namespace = this.state.selectedIngress?.namespace || "default"
+      shouldsum = false;
+    }
+
     api
     api
       .getMetrics(
       .getMetrics(
         "<token>",
         "<token>",
@@ -178,16 +248,16 @@ export default class MetricsSection extends Component<PropsType, StateType> {
           metric: kind,
           metric: kind,
           shouldsum: shouldsum,
           shouldsum: shouldsum,
           pods,
           pods,
-          namespace: currentChart.namespace,
+          namespace: namespace,
           startrange: start,
           startrange: start,
           endrange: end,
           endrange: end,
-          resolution: resolutions[this.state.selectedRange],
+          resolution: resolutions[this.state.selectedRange]
         },
         },
         {
         {
-          id: currentProject.id,
+          id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         // transform the metrics to expected form
         // transform the metrics to expected form
         if (kind == "cpu") {
         if (kind == "cpu") {
           let data = res.data as MetricsCPUDataResponse;
           let data = res.data as MetricsCPUDataResponse;
@@ -203,7 +273,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
             ) => {
             ) => {
               return {
               return {
                 date: d.date,
                 date: d.date,
-                value: parseFloat(d.cpu),
+                value: parseFloat(d.cpu)
               };
               };
             }
             }
           );
           );
@@ -222,7 +292,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
             ) => {
             ) => {
               return {
               return {
                 date: d.date,
                 date: d.date,
-                value: parseFloat(d.memory) / (1024 * 1024), // put units in Mi
+                value: parseFloat(d.memory) / (1024 * 1024) // put units in Mi
               };
               };
             }
             }
           );
           );
@@ -241,7 +311,26 @@ export default class MetricsSection extends Component<PropsType, StateType> {
             ) => {
             ) => {
               return {
               return {
                 date: d.date,
                 date: d.date,
-                value: parseFloat(d.bytes) / 1024, // put units in Ki
+                value: parseFloat(d.bytes) / 1024 // put units in Ki
+              };
+            }
+          );
+
+          this.setState({ data: tData });
+        } else if (kind == "nginx:errors") {
+          let data = res.data as MetricsNGINXErrorsDataResponse;
+
+          let tData = data[0].results.map(
+            (
+              d: {
+                date: number;
+                error_pct: string;
+              },
+              i: number
+            ) => {
+              return {
+                date: d.date,
+                value: parseFloat(d.error_pct) // put units in Ki
               };
               };
             }
             }
           );
           );
@@ -249,7 +338,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
           this.setState({ data: tData });
           this.setState({ data: tData });
         }
         }
       })
       })
-      .catch((err) => {
+      .catch(err => {
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         // this.setState({ controllers: [], loading: false });
         // this.setState({ controllers: [], loading: false });
       });
       });
@@ -279,13 +368,13 @@ export default class MetricsSection extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {
         {
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          selectors,
+          selectors
         },
         },
         {
         {
-          id: currentProject.id,
+          id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let pods = [{ value: "All", label: "All (Summed)" }] as any[];
         let pods = [{ value: "All", label: "All (Summed)" }] as any[];
         res?.data?.forEach((pod: any) => {
         res?.data?.forEach((pod: any) => {
           let name = pod?.metadata?.name;
           let name = pod?.metadata?.name;
@@ -296,7 +385,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
 
 
         this.getMetrics();
         this.getMetrics();
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         return;
         return;
@@ -323,12 +412,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
   };
   };
 
 
   renderOptionList = () => {
   renderOptionList = () => {
-    let metricOptions = [
-      { value: "cpu", label: "CPU Utilization (vCPUs)" },
-      { value: "memory", label: "RAM Utilization (Mi)" },
-      { value: "network", label: "Network Received Bytes (Ki)" },
-    ];
-    return metricOptions.map(
+    return this.state.metricsOptions.map(
       (option: { value: string; label: string }, i: number) => {
       (option: { value: string; label: string }, i: number) => {
         return (
         return (
           <Option
           <Option
@@ -337,10 +421,10 @@ export default class MetricsSection extends Component<PropsType, StateType> {
             onClick={() =>
             onClick={() =>
               this.setState({
               this.setState({
                 selectedMetric: option.value,
                 selectedMetric: option.value,
-                selectedMetricLabel: option.label,
+                selectedMetricLabel: option.label
               })
               })
             }
             }
-            lastItem={i === metricOptions.length - 1}
+            lastItem={i === this.state.metricsOptions.length - 1}
           >
           >
             {option.label}
             {option.label}
           </Option>
           </Option>
@@ -351,6 +435,28 @@ export default class MetricsSection extends Component<PropsType, StateType> {
 
 
   renderMetricsSettings = () => {
   renderMetricsSettings = () => {
     if (this.state.showMetricsSettings && true) {
     if (this.state.showMetricsSettings && true) {
+      if (this.state.selectedMetric == "nginx:errors") {
+        return (
+          <>
+            <DropdownOverlay
+              onClick={() => this.setState({ showMetricsSettings: false })}
+            />
+            <DropdownAlt dropdownWidth="330px" dropdownMaxHeight="300px">
+              <Label>Additional Settings</Label>
+              <SelectRow
+                label="Target Ingress"
+                value={this.state.selectedIngress}
+                setActiveValue={(x: any) =>
+                  this.setState({ selectedIngress: x })
+                }
+                options={this.state.ingressOptions}
+                width="100%"
+              />
+            </DropdownAlt>
+          </>
+        );
+      }
+
       return (
       return (
         <>
         <>
           <DropdownOverlay
           <DropdownOverlay
@@ -388,7 +494,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
             <MetricSelector
             <MetricSelector
               onClick={() =>
               onClick={() =>
                 this.setState({
                 this.setState({
-                  dropdownExpanded: !this.state.dropdownExpanded,
+                  dropdownExpanded: !this.state.dropdownExpanded
                 })
                 })
               }
               }
             >
             >
@@ -412,7 +518,7 @@ export default class MetricsSection extends Component<PropsType, StateType> {
                 { value: "1H", label: "1H" },
                 { value: "1H", label: "1H" },
                 { value: "6H", label: "6H" },
                 { value: "6H", label: "6H" },
                 { value: "1D", label: "1D" },
                 { value: "1D", label: "1D" },
-                { value: "1M", label: "1M" },
+                { value: "1M", label: "1M" }
               ]}
               ]}
               currentTab={this.state.selectedRange}
               currentTab={this.state.selectedRange}
               setCurrentTab={(x: string) => this.setState({ selectedRange: x })}
               setCurrentTab={(x: string) => this.setState({ selectedRange: x })}

+ 8 - 8
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/ControllerTab.tsx

@@ -26,7 +26,7 @@ export default class ControllerTab extends Component<PropsType, StateType> {
   state = {
   state = {
     pods: [] as any[],
     pods: [] as any[],
     raw: [] as any[],
     raw: [] as any[],
-    showTooltip: [] as boolean[],
+    showTooltip: [] as boolean[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -56,18 +56,18 @@ export default class ControllerTab extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {
         {
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          selectors,
+          selectors
         },
         },
         {
         {
-          id: currentProject.id,
+          id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let pods = res?.data?.map((pod: any) => {
         let pods = res?.data?.map((pod: any) => {
           return {
           return {
             namespace: pod?.metadata?.namespace,
             namespace: pod?.metadata?.namespace,
             name: pod?.metadata?.name,
             name: pod?.metadata?.name,
-            phase: pod?.status?.phase,
+            phase: pod?.status?.phase
           };
           };
         });
         });
         let showTooltip = new Array(pods.length);
         let showTooltip = new Array(pods.length);
@@ -86,7 +86,7 @@ export default class ControllerTab extends Component<PropsType, StateType> {
           selectPod(res.data[0]);
           selectPod(res.data[0]);
         }
         }
       })
       })
-      .catch((err) => {
+      .catch(err => {
         console.log(err);
         console.log(err);
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         return;
         return;
@@ -101,14 +101,14 @@ export default class ControllerTab extends Component<PropsType, StateType> {
           c.status?.availableReplicas ||
           c.status?.availableReplicas ||
             c.status?.replicas - c.status?.unavailableReplicas ||
             c.status?.replicas - c.status?.unavailableReplicas ||
             0,
             0,
-          c.status?.replicas || 0,
+          c.status?.replicas || 0
         ];
         ];
       case "statefulset":
       case "statefulset":
         return [c.status?.readyReplicas || 0, c.status?.replicas || 0];
         return [c.status?.readyReplicas || 0, c.status?.replicas || 0];
       case "daemonset":
       case "daemonset":
         return [
         return [
           c.status?.numberAvailable || 0,
           c.status?.numberAvailable || 0,
-          c.status?.desiredNumberScheduled || 0,
+          c.status?.desiredNumberScheduled || 0
         ];
         ];
       case "job":
       case "job":
         console.log(c);
         console.log(c);

+ 3 - 3
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/Logs.tsx

@@ -17,7 +17,7 @@ export default class Logs extends Component<PropsType, StateType> {
   state = {
   state = {
     logs: [] as string[],
     logs: [] as string[],
     ws: null as any,
     ws: null as any,
-    scroll: true,
+    scroll: true
   };
   };
 
 
   ws = null as any;
   ws = null as any;
@@ -26,11 +26,11 @@ export default class Logs extends Component<PropsType, StateType> {
   scrollToBottom = (smooth: boolean) => {
   scrollToBottom = (smooth: boolean) => {
     if (smooth) {
     if (smooth) {
       this.parentRef.current.lastElementChild.scrollIntoView({
       this.parentRef.current.lastElementChild.scrollIntoView({
-        behavior: "smooth",
+        behavior: "smooth"
       });
       });
     } else {
     } else {
       this.parentRef.current.lastElementChild.scrollIntoView({
       this.parentRef.current.lastElementChild.scrollIntoView({
-        behavior: "auto",
+        behavior: "auto"
       });
       });
     }
     }
   };
   };

+ 5 - 5
dashboard/src/main/home/cluster-dashboard/expanded-chart/status/StatusSection.tsx

@@ -30,7 +30,7 @@ export default class StatusSection extends Component<PropsType, StateType> {
     selectedPod: {} as any,
     selectedPod: {} as any,
     controllers: [] as any[],
     controllers: [] as any[],
     loading: true,
     loading: true,
-    podError: "",
+    podError: ""
   };
   };
 
 
   renderLogs = () => {
   renderLogs = () => {
@@ -45,7 +45,7 @@ export default class StatusSection extends Component<PropsType, StateType> {
 
 
   selectPod = (pod: any) => {
   selectPod = (pod: any) => {
     this.setState({
     this.setState({
-      selectedPod: pod,
+      selectedPod: pod
     });
     });
   };
   };
 
 
@@ -112,12 +112,12 @@ export default class StatusSection extends Component<PropsType, StateType> {
         {
         {
           namespace: currentChart.namespace,
           namespace: currentChart.namespace,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
-          storage: StorageType.Secret,
+          storage: StorageType.Secret
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           name: currentChart.name,
           name: currentChart.name,
-          revision: currentChart.version,
+          revision: currentChart.version
         }
         }
       )
       )
       .then((res: any) => {
       .then((res: any) => {
@@ -127,7 +127,7 @@ export default class StatusSection extends Component<PropsType, StateType> {
             : res.data;
             : res.data;
         this.setState({ controllers, loading: false });
         this.setState({ controllers, loading: false });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         setCurrentError(JSON.stringify(err));
         setCurrentError(JSON.stringify(err));
         this.setState({ controllers: [], loading: false });
         this.setState({ controllers: [], loading: false });
       });
       });

+ 3 - 3
dashboard/src/main/home/dashboard/ClusterList.tsx

@@ -21,20 +21,20 @@ class Templates extends Component<PropsType, StateType> {
   state = {
   state = {
     loading: true,
     loading: true,
     error: "",
     error: "",
-    clusters: [] as ClusterType[],
+    clusters: [] as ClusterType[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
     api
     api
       .getClusters("<token>", {}, { id: this.context.currentProject.id })
       .getClusters("<token>", {}, { id: this.context.currentProject.id })
-      .then((res) => {
+      .then(res => {
         if (res.data) {
         if (res.data) {
           this.setState({ clusters: res.data, loading: false, error: "" });
           this.setState({ clusters: res.data, loading: false, error: "" });
         } else {
         } else {
           this.setState({ loading: false, error: "Response data missing" });
           this.setState({ loading: false, error: "Response data missing" });
         }
         }
       })
       })
-      .catch((err) => this.setState(err));
+      .catch(err => this.setState(err));
   }
   }
 
 
   renderIcon = () => {
   renderIcon = () => {

+ 1 - 1
dashboard/src/main/home/dashboard/ClusterPlaceholder.tsx

@@ -20,7 +20,7 @@ export default class ClusterPlaceholder extends Component<
   StateType
   StateType
 > {
 > {
   state = {
   state = {
-    loading: true,
+    loading: true
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {

+ 4 - 4
dashboard/src/main/home/dashboard/Dashboard.tsx

@@ -20,7 +20,7 @@ type PropsType = RouteComponentProps & {
 
 
 const tabOptions = [
 const tabOptions = [
   { label: "Project Overview", value: "overview" },
   { label: "Project Overview", value: "overview" },
-  { label: "Provisioner Status", value: "provisioner" },
+  { label: "Provisioner Status", value: "provisioner" }
 ];
 ];
 // TODO: rethink this list, should be coupled with tabOptions
 // TODO: rethink this list, should be coupled with tabOptions
 const tabOptionStrings = ["overview", "provisioner"];
 const tabOptionStrings = ["overview", "provisioner"];
@@ -31,7 +31,7 @@ type StateType = {
 
 
 class Dashboard extends Component<PropsType, StateType> {
 class Dashboard extends Component<PropsType, StateType> {
   state = {
   state = {
-    infras: [] as InfraType[],
+    infras: [] as InfraType[]
   };
   };
 
 
   refreshInfras = () => {
   refreshInfras = () => {
@@ -41,10 +41,10 @@ class Dashboard extends Component<PropsType, StateType> {
           "<token>",
           "<token>",
           {},
           {},
           {
           {
-            project_id: this.props.projectId,
+            project_id: this.props.projectId
           }
           }
         )
         )
-        .then((res) => this.setState({ infras: res.data }))
+        .then(res => this.setState({ infras: res.data }))
         .catch(console.log);
         .catch(console.log);
     }
     }
   };
   };

+ 13 - 9
dashboard/src/main/home/integrations/IntegrationCategories.tsx

@@ -25,7 +25,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
     currentOptions: [] as any[],
     currentOptions: [] as any[],
     currentTitles: [] as any[],
     currentTitles: [] as any[],
     currentIds: [] as any[],
     currentIds: [] as any[],
-    currentIntegrationData: [] as any[],
+    currentIntegrationData: [] as any[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -43,7 +43,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
     this.setState({
     this.setState({
       currentOptions: [],
       currentOptions: [],
       currentTitles: [],
       currentTitles: [],
-      currentIntegrationData: [],
+      currentIntegrationData: []
     });
     });
     switch (categoryType) {
     switch (categoryType) {
       case "kubernetes":
       case "kubernetes":
@@ -55,7 +55,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
       case "registry":
       case "registry":
         api
         api
           .getProjectRegistries("<token>", {}, { id: currentProject.id })
           .getProjectRegistries("<token>", {}, { id: currentProject.id })
-          .then((res) => {
+          .then(res => {
             // Sort res.data into service type and sort each service's registry alphabetically
             // Sort res.data into service type and sort each service's registry alphabetically
             let grouped: any = {};
             let grouped: any = {};
             let final: any = [];
             let final: any = [];
@@ -81,7 +81,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
             this.setState({
             this.setState({
               currentOptions,
               currentOptions,
               currentTitles,
               currentTitles,
-              currentIntegrationData: final,
+              currentIntegrationData: final
             });
             });
           })
           })
           .catch(console.log);
           .catch(console.log);
@@ -89,7 +89,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
       case "repo":
       case "repo":
         api
         api
           .getGitRepos("<token>", {}, { project_id: currentProject.id })
           .getGitRepos("<token>", {}, { project_id: currentProject.id })
-          .then((res) => {
+          .then(res => {
             let currentOptions = [] as string[];
             let currentOptions = [] as string[];
             let currentTitles = [] as string[];
             let currentTitles = [] as string[];
             let currentIds = [] as any[];
             let currentIds = [] as any[];
@@ -102,7 +102,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
               currentOptions,
               currentOptions,
               currentTitles,
               currentTitles,
               currentIds,
               currentIds,
-              currentIntegrationData: res.data,
+              currentIntegrationData: res.data
             });
             });
           })
           })
           .catch(console.log);
           .catch(console.log);
@@ -143,7 +143,7 @@ class IntegrationCategories extends Component<PropsType, StateType> {
                   setCurrentIntegration: (x: string) =>
                   setCurrentIntegration: (x: string) =>
                     this.props.history.push(
                     this.props.history.push(
                       `/integrations/${this.props.category}/create/${x}`
                       `/integrations/${this.props.category}/create/${x}`
-                    ),
+                    )
                 })
                 })
               }
               }
             >
             >
@@ -159,7 +159,9 @@ class IntegrationCategories extends Component<PropsType, StateType> {
             integrations={this.state.currentOptions}
             integrations={this.state.currentOptions}
             titles={this.state.currentTitles}
             titles={this.state.currentTitles}
             itemIdentifier={this.state.currentIntegrationData}
             itemIdentifier={this.state.currentIntegrationData}
-            updateIntegrationList={() => this.getIntegrationsForCategory(this.props.category)}
+            updateIntegrationList={() =>
+              this.getIntegrationsForCategory(this.props.category)
+            }
           />
           />
         </div>
         </div>
       );
       );
@@ -196,7 +198,9 @@ class IntegrationCategories extends Component<PropsType, StateType> {
             integrations={this.state.currentOptions}
             integrations={this.state.currentOptions}
             titles={this.state.currentTitles}
             titles={this.state.currentTitles}
             itemIdentifier={this.state.currentIds}
             itemIdentifier={this.state.currentIds}
-            updateIntegrationList={() => this.getIntegrationsForCategory(this.props.category)}
+            updateIntegrationList={() =>
+              this.getIntegrationsForCategory(this.props.category)
+            }
           />
           />
         </div>
         </div>
       );
       );

+ 48 - 33
dashboard/src/main/home/integrations/IntegrationList.tsx

@@ -29,7 +29,7 @@ export default class IntegrationList extends Component<PropsType, StateType> {
     displayExpanded: this.props.integrations.map(() => false),
     displayExpanded: this.props.integrations.map(() => false),
     isDelete: false,
     isDelete: false,
     deleteName: "",
     deleteName: "",
-    deleteID: 0,
+    deleteID: 0
   };
   };
 
 
   allCollapsed = () =>
   allCollapsed = () =>
@@ -43,7 +43,7 @@ export default class IntegrationList extends Component<PropsType, StateType> {
 
 
   collapseAll = () => {
   collapseAll = () => {
     this.setState({
     this.setState({
-      displayExpanded: this.props.integrations.map(() => false),
+      displayExpanded: this.props.integrations.map(() => false)
     });
     });
   };
   };
 
 
@@ -65,42 +65,52 @@ export default class IntegrationList extends Component<PropsType, StateType> {
       event.stopPropagation();
       event.stopPropagation();
     }
     }
 
 
-    this.setState({ isDelete: true, deleteName: this.props.titles[i], deleteID: id })
-  }
+    this.setState({
+      isDelete: true,
+      deleteName: this.props.titles[i],
+      deleteID: id
+    });
+  };
 
 
   handleDeleteIntegration = () => {
   handleDeleteIntegration = () => {
     let { currentProject } = this.context;
     let { currentProject } = this.context;
 
 
     if (this.props.currentCategory === "registry") {
     if (this.props.currentCategory === "registry") {
-      api.deleteRegistryIntegration(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          registry_id: this.state.deleteID,
-        }
-      ).then(() => {
-        this.setState({ isDelete: false })
-        this.props.updateIntegrationList()
-      }).catch((err) => {
-        this.context.setCurrentError(err)
-      })
+      api
+        .deleteRegistryIntegration(
+          "<token>",
+          {},
+          {
+            project_id: currentProject.id,
+            registry_id: this.state.deleteID
+          }
+        )
+        .then(() => {
+          this.setState({ isDelete: false });
+          this.props.updateIntegrationList();
+        })
+        .catch(err => {
+          this.context.setCurrentError(err);
+        });
     } else if (this.props.currentCategory === "repo") {
     } else if (this.props.currentCategory === "repo") {
-      api.deleteGitRepoIntegration(
-        "<token>",
-        {},
-        {
-          project_id: currentProject.id,
-          git_repo_id: this.state.deleteID,
-        }
-      ).then(() => {
-        this.setState({ isDelete: false })
-        this.props.updateIntegrationList()
-      }).catch((err) => {
-        this.context.setCurrentError(err)
-      })
+      api
+        .deleteGitRepoIntegration(
+          "<token>",
+          {},
+          {
+            project_id: currentProject.id,
+            git_repo_id: this.state.deleteID
+          }
+        )
+        .then(() => {
+          this.setState({ isDelete: false });
+          this.props.updateIntegrationList();
+        })
+        .catch(err => {
+          this.context.setCurrentError(err);
+        });
     }
     }
-  }
+  };
 
 
   handleParent = (event: any, integration: string) =>
   handleParent = (event: any, integration: string) =>
     this.props.setCurrent && this.props.setCurrent(integration);
     this.props.setCurrent && this.props.setCurrent(integration);
@@ -111,7 +121,8 @@ export default class IntegrationList extends Component<PropsType, StateType> {
     if (titles && titles.length > 0) {
     if (titles && titles.length > 0) {
       return integrations.map((integration: string, i: number) => {
       return integrations.map((integration: string, i: number) => {
         let label = titles[i];
         let label = titles[i];
-        let item_id = this.props.itemIdentifier[i].id || this.props.itemIdentifier[i]
+        let item_id =
+          this.props.itemIdentifier[i].id || this.props.itemIdentifier[i];
 
 
         return (
         return (
           <IntegrationRow
           <IntegrationRow
@@ -180,7 +191,11 @@ export default class IntegrationList extends Component<PropsType, StateType> {
       <StyledIntegrationList>
       <StyledIntegrationList>
         <ConfirmOverlay
         <ConfirmOverlay
           show={this.state.isDelete}
           show={this.state.isDelete}
-          message={`Are you sure you want to delete the ${this.props.currentCategory === "registry" ? "Docker registry integration" : "Github integration"} with name ${this.state.deleteName}?`}
+          message={`Are you sure you want to delete the ${
+            this.props.currentCategory === "registry"
+              ? "Docker registry integration"
+              : "Github integration"
+          } with name ${this.state.deleteName}?`}
           onYes={this.handleDeleteIntegration}
           onYes={this.handleDeleteIntegration}
           onNo={() => this.setState({ isDelete: false })}
           onNo={() => this.setState({ isDelete: false })}
         />
         />

+ 6 - 9
dashboard/src/main/home/integrations/IntegrationRow.tsx

@@ -24,19 +24,19 @@ type StateType = {
 
 
 export default class IntegrationRow extends Component<PropsType, StateType> {
 export default class IntegrationRow extends Component<PropsType, StateType> {
   state = {
   state = {
-    editMode: false,
+    editMode: false
   };
   };
 
 
   editButtonOnClick = (e: MouseEvent) => {
   editButtonOnClick = (e: MouseEvent) => {
     e.stopPropagation();
     e.stopPropagation();
     if (!this.props.expanded) {
     if (!this.props.expanded) {
       this.setState({
       this.setState({
-        editMode: true,
+        editMode: true
       });
       });
       this.props.toggleCollapse(null);
       this.props.toggleCollapse(null);
     } else {
     } else {
       this.setState({
       this.setState({
-        editMode: !this.state.editMode,
+        editMode: !this.state.editMode
       });
       });
       if (this.state.editMode) {
       if (this.state.editMode) {
         this.props.toggleCollapse(null);
         this.props.toggleCollapse(null);
@@ -64,10 +64,7 @@ export default class IntegrationRow extends Component<PropsType, StateType> {
           <MaterialIconTray disabled={false}>
           <MaterialIconTray disabled={false}>
             {/* <i className="material-icons"
             {/* <i className="material-icons"
             onClick={this.editButtonOnClick}>mode_edit</i> */}
             onClick={this.editButtonOnClick}>mode_edit</i> */}
-            <i
-              className="material-icons"
-              onClick={this.props.triggerDelete}
-            >
+            <i className="material-icons" onClick={this.props.triggerDelete}>
               delete
               delete
             </i>
             </i>
             <I
             <I
@@ -98,7 +95,7 @@ export default class IntegrationRow extends Component<PropsType, StateType> {
                     git_repo: "",
                     git_repo: "",
                     image_repo_uri: "",
                     image_repo_uri: "",
                     git_repo_id: 0,
                     git_repo_id: 0,
-                    dockerfile_path: "",
+                    dockerfile_path: ""
                   } as ActionConfigType
                   } as ActionConfigType
                 }
                 }
                 setActionConfig={() => {}}
                 setActionConfig={() => {}}
@@ -184,7 +181,7 @@ const MaterialIconTray = styled.div`
     border-radius: 20px;
     border-radius: 20px;
     font-size: 18px;
     font-size: 18px;
     padding: 5px;
     padding: 5px;
-    margin: 0 5px; 
+    margin: 0 5px;
     color: #ffffff44;
     color: #ffffff44;
     :hover {
     :hover {
       background: ${(props: { disabled: boolean }) =>
       background: ${(props: { disabled: boolean }) =>

+ 4 - 4
dashboard/src/main/home/integrations/Integrations.tsx

@@ -18,7 +18,7 @@ const IntegrationCategoryStrings = ["registry", "repo"]; /*"kubernetes",*/
 
 
 class Integrations extends Component<PropsType, StateType> {
 class Integrations extends Component<PropsType, StateType> {
   state = {
   state = {
-    currentIntegrationData: [] as any[],
+    currentIntegrationData: [] as any[]
   };
   };
 
 
   render = () => (
   render = () => (
@@ -26,7 +26,7 @@ class Integrations extends Component<PropsType, StateType> {
       <Switch>
       <Switch>
         <Route
         <Route
           path="/integrations/:category/create/:integration"
           path="/integrations/:category/create/:integration"
-          render={(rp) => {
+          render={rp => {
             const { integration, category } = rp.match.params;
             const { integration, category } = rp.match.params;
             if (!IntegrationCategoryStrings.includes(category)) {
             if (!IntegrationCategoryStrings.includes(category)) {
               this.props.history.push("/integrations");
               this.props.history.push("/integrations");
@@ -62,7 +62,7 @@ class Integrations extends Component<PropsType, StateType> {
         />
         />
         <Route
         <Route
           path="/integrations/:category"
           path="/integrations/:category"
-          render={(rp) => {
+          render={rp => {
             const currentCategory = rp.match.params.category;
             const currentCategory = rp.match.params.category;
             if (!IntegrationCategoryStrings.includes(currentCategory)) {
             if (!IntegrationCategoryStrings.includes(currentCategory)) {
               this.props.history.push("/integrations");
               this.props.history.push("/integrations");
@@ -83,7 +83,7 @@ class Integrations extends Component<PropsType, StateType> {
             <IntegrationList
             <IntegrationList
               currentCategory={""}
               currentCategory={""}
               integrations={["kubernetes", "registry", "repo"]}
               integrations={["kubernetes", "registry", "repo"]}
-              setCurrent={(x) => this.props.history.push(`/integrations/${x}`)}
+              setCurrent={x => this.props.history.push(`/integrations/${x}`)}
               isCategory={true}
               isCategory={true}
               updateIntegrationList={() => {}}
               updateIntegrationList={() => {}}
             />
             />

+ 2 - 2
dashboard/src/main/home/integrations/create-integration/DockerHubForm.tsx

@@ -20,7 +20,7 @@ export default class DockerHubForm extends Component<PropsType, StateType> {
     registryURL: "",
     registryURL: "",
     dockerEmail: "",
     dockerEmail: "",
     dockerUsername: "",
     dockerUsername: "",
-    dockerPassword: "",
+    dockerPassword: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -28,7 +28,7 @@ export default class DockerHubForm extends Component<PropsType, StateType> {
       registryURL,
       registryURL,
       dockerEmail,
       dockerEmail,
       dockerUsername,
       dockerUsername,
-      dockerPassword,
+      dockerPassword
     } = this.state;
     } = this.state;
     if (
     if (
       registryURL === "" ||
       registryURL === "" ||

+ 4 - 4
dashboard/src/main/home/integrations/create-integration/ECRForm.tsx

@@ -25,7 +25,7 @@ export default class ECRForm extends Component<PropsType, StateType> {
     credentialsName: "",
     credentialsName: "",
     awsRegion: "",
     awsRegion: "",
     awsAccessId: "",
     awsAccessId: "",
-    awsSecretKey: "",
+    awsSecretKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -53,16 +53,16 @@ export default class ECRForm extends Component<PropsType, StateType> {
         {
         {
           aws_region: awsRegion,
           aws_region: awsRegion,
           aws_access_key_id: awsAccessId,
           aws_access_key_id: awsAccessId,
-          aws_secret_access_key: awsSecretKey,
+          aws_secret_access_key: awsSecretKey
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.connectECRRegistry(
         api.connectECRRegistry(
           "<token>",
           "<token>",
           {
           {
             name: credentialsName,
             name: credentialsName,
-            aws_integration_id: res.data.id,
+            aws_integration_id: res.data.id
           },
           },
           { id: currentProject.id }
           { id: currentProject.id }
         )
         )

+ 2 - 2
dashboard/src/main/home/integrations/create-integration/EKSForm.tsx

@@ -25,7 +25,7 @@ export default class EKSForm extends Component<PropsType, StateType> {
     clusterEndpoint: "",
     clusterEndpoint: "",
     clusterCA: "",
     clusterCA: "",
     awsAccessId: "",
     awsAccessId: "",
-    awsSecretKey: "",
+    awsSecretKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -34,7 +34,7 @@ export default class EKSForm extends Component<PropsType, StateType> {
       clusterEndpoint,
       clusterEndpoint,
       clusterCA,
       clusterCA,
       awsAccessId,
       awsAccessId,
-      awsSecretKey,
+      awsSecretKey
     } = this.state;
     } = this.state;
     if (
     if (
       clusterName === "" ||
       clusterName === "" ||

+ 8 - 8
dashboard/src/main/home/integrations/create-integration/GCRForm.tsx

@@ -28,7 +28,7 @@ export default class GCRForm extends Component<PropsType, StateType> {
     gcpRegion: "",
     gcpRegion: "",
     serviceAccountKey: "",
     serviceAccountKey: "",
     gcpProjectID: "",
     gcpProjectID: "",
-    url: "",
+    url: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -36,7 +36,7 @@ export default class GCRForm extends Component<PropsType, StateType> {
       credentialsName,
       credentialsName,
       gcpRegion,
       gcpRegion,
       gcpProjectID,
       gcpProjectID,
-      serviceAccountKey,
+      serviceAccountKey
     } = this.state;
     } = this.state;
     if (
     if (
       credentialsName === "" ||
       credentialsName === "" ||
@@ -60,26 +60,26 @@ export default class GCRForm extends Component<PropsType, StateType> {
         {
         {
           gcp_region: this.state.gcpRegion,
           gcp_region: this.state.gcpRegion,
           gcp_key_data: this.state.serviceAccountKey,
           gcp_key_data: this.state.serviceAccountKey,
-          gcp_project_id: this.state.gcpProjectID,
+          gcp_project_id: this.state.gcpProjectID
         },
         },
         {
         {
-          project_id: currentProject.id,
+          project_id: currentProject.id
         }
         }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.connectGCRRegistry(
         api.connectGCRRegistry(
           "<token>",
           "<token>",
           {
           {
             name: this.state.credentialsName,
             name: this.state.credentialsName,
             gcp_integration_id: res.data.id,
             gcp_integration_id: res.data.id,
-            url: this.state.url,
+            url: this.state.url
           },
           },
           {
           {
-            id: currentProject.id,
+            id: currentProject.id
           }
           }
         )
         )
       )
       )
-      .then((res) => {
+      .then(res => {
         console.log(res.data);
         console.log(res.data);
         this.props.closeForm();
         this.props.closeForm();
       })
       })

+ 2 - 2
dashboard/src/main/home/integrations/create-integration/GKEForm.tsx

@@ -23,7 +23,7 @@ export default class GKEForm extends Component<PropsType, StateType> {
     clusterName: "",
     clusterName: "",
     clusterEndpoint: "",
     clusterEndpoint: "",
     clusterCA: "",
     clusterCA: "",
-    serviceAccountKey: "",
+    serviceAccountKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -31,7 +31,7 @@ export default class GKEForm extends Component<PropsType, StateType> {
       clusterName,
       clusterName,
       clusterEndpoint,
       clusterEndpoint,
       clusterCA,
       clusterCA,
-      serviceAccountKey,
+      serviceAccountKey
     } = this.state;
     } = this.state;
     if (
     if (
       clusterName === "" ||
       clusterName === "" ||

+ 2 - 2
dashboard/src/main/home/integrations/edit-integration/DockerHubForm.tsx

@@ -20,7 +20,7 @@ export default class DockerHubForm extends Component<PropsType, StateType> {
     registryURL: "",
     registryURL: "",
     dockerEmail: "",
     dockerEmail: "",
     dockerUsername: "",
     dockerUsername: "",
-    dockerPassword: "",
+    dockerPassword: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -28,7 +28,7 @@ export default class DockerHubForm extends Component<PropsType, StateType> {
       registryURL,
       registryURL,
       dockerEmail,
       dockerEmail,
       dockerUsername,
       dockerUsername,
-      dockerPassword,
+      dockerPassword
     } = this.state;
     } = this.state;
     if (
     if (
       registryURL === "" ||
       registryURL === "" ||

+ 4 - 4
dashboard/src/main/home/integrations/edit-integration/ECRForm.tsx

@@ -25,7 +25,7 @@ export default class ECRForm extends Component<PropsType, StateType> {
     credentialsName: "",
     credentialsName: "",
     awsRegion: "",
     awsRegion: "",
     awsAccessId: "",
     awsAccessId: "",
-    awsSecretKey: "",
+    awsSecretKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -53,16 +53,16 @@ export default class ECRForm extends Component<PropsType, StateType> {
         {
         {
           aws_region: awsRegion,
           aws_region: awsRegion,
           aws_access_key_id: awsAccessId,
           aws_access_key_id: awsAccessId,
-          aws_secret_access_key: awsSecretKey,
+          aws_secret_access_key: awsSecretKey
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.connectECRRegistry(
         api.connectECRRegistry(
           "<token>",
           "<token>",
           {
           {
             name: credentialsName,
             name: credentialsName,
-            aws_integration_id: res.data.id,
+            aws_integration_id: res.data.id
           },
           },
           { id: currentProject.id }
           { id: currentProject.id }
         )
         )

+ 2 - 2
dashboard/src/main/home/integrations/edit-integration/EKSForm.tsx

@@ -25,7 +25,7 @@ export default class EKSForm extends Component<PropsType, StateType> {
     clusterEndpoint: "",
     clusterEndpoint: "",
     clusterCA: "",
     clusterCA: "",
     awsAccessId: "",
     awsAccessId: "",
-    awsSecretKey: "",
+    awsSecretKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -34,7 +34,7 @@ export default class EKSForm extends Component<PropsType, StateType> {
       clusterEndpoint,
       clusterEndpoint,
       clusterCA,
       clusterCA,
       awsAccessId,
       awsAccessId,
-      awsSecretKey,
+      awsSecretKey
     } = this.state;
     } = this.state;
     if (
     if (
       clusterName === "" ||
       clusterName === "" ||

+ 8 - 8
dashboard/src/main/home/integrations/edit-integration/GCRForm.tsx

@@ -28,7 +28,7 @@ export default class GCRForm extends Component<PropsType, StateType> {
     gcpRegion: "",
     gcpRegion: "",
     serviceAccountKey: "",
     serviceAccountKey: "",
     gcpProjectID: "",
     gcpProjectID: "",
-    url: "",
+    url: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -36,7 +36,7 @@ export default class GCRForm extends Component<PropsType, StateType> {
       credentialsName,
       credentialsName,
       gcpRegion,
       gcpRegion,
       gcpProjectID,
       gcpProjectID,
-      serviceAccountKey,
+      serviceAccountKey
     } = this.state;
     } = this.state;
     if (
     if (
       credentialsName === "" ||
       credentialsName === "" ||
@@ -60,26 +60,26 @@ export default class GCRForm extends Component<PropsType, StateType> {
         {
         {
           gcp_region: this.state.gcpRegion,
           gcp_region: this.state.gcpRegion,
           gcp_key_data: this.state.serviceAccountKey,
           gcp_key_data: this.state.serviceAccountKey,
-          gcp_project_id: this.state.gcpProjectID,
+          gcp_project_id: this.state.gcpProjectID
         },
         },
         {
         {
-          project_id: currentProject.id,
+          project_id: currentProject.id
         }
         }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.connectGCRRegistry(
         api.connectGCRRegistry(
           "<token>",
           "<token>",
           {
           {
             name: this.state.credentialsName,
             name: this.state.credentialsName,
             gcp_integration_id: res.data.id,
             gcp_integration_id: res.data.id,
-            url: this.state.url,
+            url: this.state.url
           },
           },
           {
           {
-            id: currentProject.id,
+            id: currentProject.id
           }
           }
         )
         )
       )
       )
-      .then((res) => {
+      .then(res => {
         console.log(res.data);
         console.log(res.data);
         this.props.closeForm();
         this.props.closeForm();
       })
       })

+ 2 - 2
dashboard/src/main/home/integrations/edit-integration/GKEForm.tsx

@@ -23,7 +23,7 @@ export default class GKEForm extends Component<PropsType, StateType> {
     clusterName: "",
     clusterName: "",
     clusterEndpoint: "",
     clusterEndpoint: "",
     clusterCA: "",
     clusterCA: "",
-    serviceAccountKey: "",
+    serviceAccountKey: ""
   };
   };
 
 
   isDisabled = (): boolean => {
   isDisabled = (): boolean => {
@@ -31,7 +31,7 @@ export default class GKEForm extends Component<PropsType, StateType> {
       clusterName,
       clusterName,
       clusterEndpoint,
       clusterEndpoint,
       clusterCA,
       clusterCA,
-      serviceAccountKey,
+      serviceAccountKey
     } = this.state;
     } = this.state;
     if (
     if (
       clusterName === "" ||
       clusterName === "" ||

+ 8 - 8
dashboard/src/main/home/launch/Launch.tsx

@@ -14,7 +14,7 @@ import { Link } from "react-router-dom";
 
 
 const tabOptions = [
 const tabOptions = [
   { label: "New Application", value: "docker" },
   { label: "New Application", value: "docker" },
-  { label: "Community Add-ons", value: "community" },
+  { label: "Community Add-ons", value: "community" }
 ];
 ];
 
 
 type PropsType = {};
 type PropsType = {};
@@ -35,17 +35,17 @@ export default class Templates extends Component<PropsType, StateType> {
     addonTemplates: [] as PorterTemplate[],
     addonTemplates: [] as PorterTemplate[],
     applicationTemplates: [] as PorterTemplate[],
     applicationTemplates: [] as PorterTemplate[],
     loading: true,
     loading: true,
-    error: false,
+    error: false
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
     api
     api
       .getAddonTemplates("<token>", {}, {})
       .getAddonTemplates("<token>", {}, {})
-      .then((res) => {
+      .then(res => {
         this.setState({ addonTemplates: res.data, error: false }, () => {
         this.setState({ addonTemplates: res.data, error: false }, () => {
           this.state.addonTemplates.sort((a, b) => (a.name > b.name ? 1 : -1));
           this.state.addonTemplates.sort((a, b) => (a.name > b.name ? 1 : -1));
           this.setState({
           this.setState({
-            loading: false,
+            loading: false
           });
           });
         });
         });
       })
       })
@@ -55,17 +55,17 @@ export default class Templates extends Component<PropsType, StateType> {
       .getApplicationTemplates(
       .getApplicationTemplates(
         "<token>",
         "<token>",
         {
         {
-          repo_url: process.env.APPLICATION_CHART_REPO_URL,
+          repo_url: process.env.APPLICATION_CHART_REPO_URL
         },
         },
         {}
         {}
       )
       )
-      .then((res) => {
+      .then(res => {
         this.setState({ applicationTemplates: res.data, error: false }, () => {
         this.setState({ applicationTemplates: res.data, error: false }, () => {
           this.state.applicationTemplates.sort((a, b) =>
           this.state.applicationTemplates.sort((a, b) =>
             a.version > b.version ? 1 : -1
             a.version > b.version ? 1 : -1
           );
           );
           this.setState({
           this.setState({
-            loading: false,
+            loading: false
           });
           });
         });
         });
       })
       })
@@ -238,7 +238,7 @@ export default class Templates extends Component<PropsType, StateType> {
           setCurrentTab={(value: string) =>
           setCurrentTab={(value: string) =>
             this.setState({
             this.setState({
               currentTab: value,
               currentTab: value,
-              currentTemplate: null,
+              currentTemplate: null
             })
             })
           }
           }
         />
         />

+ 5 - 5
dashboard/src/main/home/launch/expanded-template/ExpandedTemplate.tsx

@@ -33,7 +33,7 @@ export default class ExpandedTemplate extends Component<PropsType, StateType> {
     loading: true,
     loading: true,
     error: false,
     error: false,
     markdown: null as string | null,
     markdown: null as string | null,
-    keywords: [] as string[],
+    keywords: [] as string[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -50,9 +50,9 @@ export default class ExpandedTemplate extends Component<PropsType, StateType> {
     api
     api
       .getTemplateInfo("<token>", params, {
       .getTemplateInfo("<token>", params, {
         name: this.props.currentTemplate.name.toLowerCase().trim(),
         name: this.props.currentTemplate.name.toLowerCase().trim(),
-        version: "latest",
+        version: "latest"
       })
       })
-      .then((res) => {
+      .then(res => {
         let { form, values, markdown, metadata } = res.data;
         let { form, values, markdown, metadata } = res.data;
         let keywords = metadata.keywords;
         let keywords = metadata.keywords;
         this.setState({
         this.setState({
@@ -61,10 +61,10 @@ export default class ExpandedTemplate extends Component<PropsType, StateType> {
           markdown,
           markdown,
           keywords,
           keywords,
           loading: false,
           loading: false,
-          error: false,
+          error: false
         });
         });
       })
       })
-      .catch((err) => this.setState({ loading: false, error: true }));
+      .catch(err => this.setState({ loading: false, error: true }));
   };
   };
 
 
   componentDidUpdate = (prevProps: PropsType) => {
   componentDidUpdate = (prevProps: PropsType) => {

+ 38 - 38
dashboard/src/main/home/launch/expanded-template/LaunchTemplate.tsx

@@ -11,7 +11,7 @@ import {
   ActionConfigType,
   ActionConfigType,
   ChoiceType,
   ChoiceType,
   ClusterType,
   ClusterType,
-  StorageType,
+  StorageType
 } from "shared/types";
 } from "shared/types";
 import Selector from "components/Selector";
 import Selector from "components/Selector";
 import ImageSelector from "components/image-selector/ImageSelector";
 import ImageSelector from "components/image-selector/ImageSelector";
@@ -60,7 +60,7 @@ type StateType = {
 const defaultActionConfig: ActionConfigType = {
 const defaultActionConfig: ActionConfigType = {
   git_repo: "",
   git_repo: "",
   image_repo_uri: "",
   image_repo_uri: "",
-  git_repo_id: 0,
+  git_repo_id: 0
 };
 };
 
 
 class LaunchTemplate extends Component<PropsType, StateType> {
 class LaunchTemplate extends Component<PropsType, StateType> {
@@ -85,7 +85,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
     dockerfilePath: null as string | null,
     dockerfilePath: null as string | null,
     folderPath: null as string | null,
     folderPath: null as string | null,
     selectedRegistry: null as any | null,
     selectedRegistry: null as any | null,
-    env: {},
+    env: {}
   };
   };
 
 
   createGHAction = (chartName: string, chartNamespace: string) => {
   createGHAction = (chartName: string, chartNamespace: string) => {
@@ -108,16 +108,16 @@ class LaunchTemplate extends Component<PropsType, StateType> {
           folder_path: this.state.folderPath,
           folder_path: this.state.folderPath,
           image_repo_uri: imageRepoUri,
           image_repo_uri: imageRepoUri,
           git_repo_id: actionConfig.git_repo_id,
           git_repo_id: actionConfig.git_repo_id,
-          env: this.state.env,
+          env: this.state.env
         },
         },
         {
         {
           project_id: currentProject.id,
           project_id: currentProject.id,
           CLUSTER_ID: currentCluster.id,
           CLUSTER_ID: currentCluster.id,
           RELEASE_NAME: chartName,
           RELEASE_NAME: chartName,
-          RELEASE_NAMESPACE: chartNamespace,
+          RELEASE_NAMESPACE: chartNamespace
         }
         }
       )
       )
-      .then((res) => console.log(res.data))
+      .then(res => console.log(res.data))
       .catch(console.log);
       .catch(console.log);
   };
   };
 
 
@@ -140,16 +140,16 @@ class LaunchTemplate extends Component<PropsType, StateType> {
           storage: StorageType.Secret,
           storage: StorageType.Secret,
           formValues: values,
           formValues: values,
           namespace: this.state.selectedNamespace,
           namespace: this.state.selectedNamespace,
-          name,
+          name
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
           name: this.props.currentTemplate.name.toLowerCase().trim(),
           name: this.props.currentTemplate.name.toLowerCase().trim(),
-          version: "latest",
+          version: "latest"
         }
         }
       )
       )
-      .then((_) => {
+      .then(_ => {
         // this.props.setCurrentView('cluster-dashboard');
         // this.props.setCurrentView('cluster-dashboard');
         this.setState({ saveValuesStatus: "successful" }, () => {
         this.setState({ saveValuesStatus: "successful" }, () => {
           // redirect to dashboard
           // redirect to dashboard
@@ -159,18 +159,18 @@ class LaunchTemplate extends Component<PropsType, StateType> {
           window.analytics.track("Deployed Add-on", {
           window.analytics.track("Deployed Add-on", {
             name: this.props.currentTemplate.name,
             name: this.props.currentTemplate.name,
             namespace: this.state.selectedNamespace,
             namespace: this.state.selectedNamespace,
-            values: values,
+            values: values
           });
           });
         });
         });
       })
       })
-      .catch((err) => {
+      .catch(err => {
         this.setState({ saveValuesStatus: "error" });
         this.setState({ saveValuesStatus: "error" });
         setCurrentError(err.response.data.errors[0]);
         setCurrentError(err.response.data.errors[0]);
         window.analytics.track("Failed to Deploy Add-on", {
         window.analytics.track("Failed to Deploy Add-on", {
           name: this.props.currentTemplate.name,
           name: this.props.currentTemplate.name,
           namespace: this.state.selectedNamespace,
           namespace: this.state.selectedNamespace,
           values: values,
           values: values,
-          error: err,
+          error: err
         });
         });
       });
       });
   };
   };
@@ -235,17 +235,17 @@ class LaunchTemplate extends Component<PropsType, StateType> {
             .createSubdomain(
             .createSubdomain(
               "<token>",
               "<token>",
               {
               {
-                release_name: name,
+                release_name: name
               },
               },
               {
               {
                 id: currentProject.id,
                 id: currentProject.id,
-                cluster_id: currentCluster.id,
+                cluster_id: currentCluster.id
               }
               }
             )
             )
-            .then((res) => {
+            .then(res => {
               resolve(res.data?.external_url);
               resolve(res.data?.external_url);
             })
             })
-            .catch((err) => {
+            .catch(err => {
               this.setState({ saveValuesStatus: "error" });
               this.setState({ saveValuesStatus: "error" });
             });
             });
         });
         });
@@ -266,17 +266,17 @@ class LaunchTemplate extends Component<PropsType, StateType> {
           storage: StorageType.Secret,
           storage: StorageType.Secret,
           formValues: values,
           formValues: values,
           namespace: this.state.selectedNamespace,
           namespace: this.state.selectedNamespace,
-          name,
+          name
         },
         },
         {
         {
           id: currentProject.id,
           id: currentProject.id,
           cluster_id: currentCluster.id,
           cluster_id: currentCluster.id,
           name: this.props.currentTemplate.name.toLowerCase().trim(),
           name: this.props.currentTemplate.name.toLowerCase().trim(),
           version: "latest",
           version: "latest",
-          repo_url: process.env.APPLICATION_CHART_REPO_URL,
+          repo_url: process.env.APPLICATION_CHART_REPO_URL
         }
         }
       )
       )
-      .then((_) => {
+      .then(_ => {
         console.log("Deployed template.");
         console.log("Deployed template.");
         if (this.state.sourceType === "repo") {
         if (this.state.sourceType === "repo") {
           console.log("Creating GHA");
           console.log("Creating GHA");
@@ -302,7 +302,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
         }
         }
         */
         */
       })
       })
-      .catch((err) => {
+      .catch(err => {
         this.setState({ saveValuesStatus: "error" });
         this.setState({ saveValuesStatus: "error" });
         /*
         /*
         try {
         try {
@@ -326,7 +326,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
       sourceType,
       sourceType,
       selectedImageUrl,
       selectedImageUrl,
       dockerfilePath,
       dockerfilePath,
-      folderPath,
+      folderPath
     } = this.state;
     } = this.state;
 
 
     // Allow if name is invalid
     // Allow if name is invalid
@@ -356,7 +356,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
       selectedRegistry,
       selectedRegistry,
       sourceType,
       sourceType,
       dockerfilePath,
       dockerfilePath,
-      folderPath,
+      folderPath
     } = this.state;
     } = this.state;
 
 
     if (this.submitIsDisabled()) {
     if (this.submitIsDisabled()) {
@@ -423,12 +423,12 @@ class LaunchTemplate extends Component<PropsType, StateType> {
 
 
     this.setState({
     this.setState({
       tabOptions,
       tabOptions,
-      currentTab: tabOptions[0] && tabOptions[0]["value"],
+      currentTab: tabOptions[0] && tabOptions[0]["value"]
     });
     });
 
 
     // TODO: query with selected filter once implemented
     // TODO: query with selected filter once implemented
     let { currentProject, currentCluster } = this.context;
     let { currentProject, currentCluster } = this.context;
-    api.getClusters("<token>", {}, { id: currentProject.id }).then((res) => {
+    api.getClusters("<token>", {}, { id: currentProject.id }).then(res => {
       if (res.data) {
       if (res.data) {
         let clusterOptions: { label: string; value: string }[] = [];
         let clusterOptions: { label: string; value: string }[] = [];
         let clusterMap: { [clusterId: string]: ClusterType } = {};
         let clusterMap: { [clusterId: string]: ClusterType } = {};
@@ -451,11 +451,11 @@ class LaunchTemplate extends Component<PropsType, StateType> {
       .getNamespaces(
       .getNamespaces(
         "<token>",
         "<token>",
         {
         {
-          cluster_id: id,
+          cluster_id: id
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) => {
+      .then(res => {
         if (res.data) {
         if (res.data) {
           let namespaceOptions = res.data.items.map(
           let namespaceOptions = res.data.items.map(
             (x: { metadata: { name: string } }) => {
             (x: { metadata: { name: string } }) => {
@@ -597,12 +597,12 @@ class LaunchTemplate extends Component<PropsType, StateType> {
             options={[
             options={[
               {
               {
                 value: "dockerfile",
                 value: "dockerfile",
-                label: "Yes, I am using an existing Dockerfile",
+                label: "Yes, I am using an existing Dockerfile"
               },
               },
               {
               {
                 value: "buildpack",
                 value: "buildpack",
-                label: "No, I am not using an existing Dockerfile",
-              },
+                label: "No, I am not using an existing Dockerfile"
+              }
             ]}
             ]}
             selected={this.state.repoType}
             selected={this.state.repoType}
             setSelected={(x: string) => this.setState({ repoType: x })}
             setSelected={(x: string) => this.setState({ repoType: x })}
@@ -647,7 +647,7 @@ class LaunchTemplate extends Component<PropsType, StateType> {
                 actionConfig: { ...defaultActionConfig },
                 actionConfig: { ...defaultActionConfig },
                 branch: "",
                 branch: "",
                 dockerfilePath: null,
                 dockerfilePath: null,
-                folderPath: null,
+                folderPath: null
               });
               });
             }}
             }}
             setSelectedRegistry={(x: any) => {
             setSelectedRegistry={(x: any) => {
@@ -791,7 +791,7 @@ const BlockIcon = styled.img<{ bw?: boolean }>`
   padding: 2px;
   padding: 2px;
   margin-top: 30px;
   margin-top: 30px;
   margin-bottom: 15px;
   margin-bottom: 15px;
-  filter: ${(props) => (props.bw ? "grayscale(1)" : "")};
+  filter: ${props => (props.bw ? "grayscale(1)" : "")};
 `;
 `;
 
 
 const BlockDescription = styled.div`
 const BlockDescription = styled.div`
@@ -832,13 +832,13 @@ const Block = styled.div<{ disabled?: boolean }>`
   align-item: center;
   align-item: center;
   justify-content: space-between;
   justify-content: space-between;
   height: 170px;
   height: 170px;
-  cursor: ${(props) => (props.disabled ? "" : "pointer")};
+  cursor: ${props => (props.disabled ? "" : "pointer")};
   color: #ffffff;
   color: #ffffff;
   position: relative;
   position: relative;
   background: #26282f;
   background: #26282f;
   box-shadow: 0 3px 5px 0px #00000022;
   box-shadow: 0 3px 5px 0px #00000022;
   :hover {
   :hover {
-    background: ${(props) => (props.disabled ? "" : "#ffffff11")};
+    background: ${props => (props.disabled ? "" : "#ffffff11")};
   }
   }
 
 
   animation: fadeIn 0.3s 0s;
   animation: fadeIn 0.3s 0s;
@@ -893,14 +893,14 @@ const Heading = styled.div<{ isAtTop?: boolean }>`
   font-weight: 500;
   font-weight: 500;
   font-size: 16px;
   font-size: 16px;
   margin-bottom: 5px;
   margin-bottom: 5px;
-  margin-top: ${(props) => (props.isAtTop ? "10px" : "30px")};
+  margin-top: ${props => (props.isAtTop ? "10px" : "30px")};
   display: flex;
   display: flex;
   align-items: center;
   align-items: center;
 `;
 `;
 
 
 const Warning = styled.span<{ highlight: boolean; makeFlush?: boolean }>`
 const Warning = styled.span<{ highlight: boolean; makeFlush?: boolean }>`
-  color: ${(props) => (props.highlight ? "#f5cb42" : "")};
-  margin-left: ${(props) => (props.makeFlush ? "" : "5px")};
+  color: ${props => (props.highlight ? "#f5cb42" : "")};
+  margin-left: ${props => (props.makeFlush ? "" : "5px")};
 `;
 `;
 
 
 const Required = styled.div`
 const Required = styled.div`
@@ -935,7 +935,7 @@ const Placeholder = styled.div`
 
 
 const DarkMatter = styled.div<{ antiHeight?: string }>`
 const DarkMatter = styled.div<{ antiHeight?: string }>`
   width: 100%;
   width: 100%;
-  margin-top: ${(props) => props.antiHeight || "-15px"};
+  margin-top: ${props => props.antiHeight || "-15px"};
 `;
 `;
 
 
 const Subtitle = styled.div`
 const Subtitle = styled.div`
@@ -979,7 +979,7 @@ const Polymer = styled.div`
   margin-bottom: -3px;
   margin-bottom: -3px;
 
 
   > i {
   > i {
-    color: ${(props) => props.theme.containerIcon};
+    color: ${props => props.theme.containerIcon};
     font-size: 18px;
     font-size: 18px;
     margin-right: 10px;
     margin-right: 10px;
   }
   }

+ 1 - 1
dashboard/src/main/home/launch/expanded-template/TemplateInfo.tsx

@@ -280,7 +280,7 @@ const Polymer = styled.div`
   margin-bottom: -3px;
   margin-bottom: -3px;
 
 
   > i {
   > i {
-    color: ${(props) => props.theme.containerIcon};
+    color: ${props => props.theme.containerIcon};
     font-size: 24px;
     font-size: 24px;
     margin-left: 12px;
     margin-left: 12px;
     margin-right: 3px;
     margin-right: 3px;

+ 1 - 1
dashboard/src/main/home/launch/hardcodedNameDict.tsx

@@ -9,7 +9,7 @@ const hardcodedNames: { [key: string]: string } = {
   ubuntu: "Ubuntu",
   ubuntu: "Ubuntu",
   web: "Web Service",
   web: "Web Service",
   worker: "Worker",
   worker: "Worker",
-  job: "Job",
+  job: "Job"
 };
 };
 
 
 export default hardcodedNames;
 export default hardcodedNames;

+ 2 - 2
dashboard/src/main/home/modals/ClusterInstructionsModal.tsx

@@ -20,7 +20,7 @@ export default class ClusterInstructionsModal extends Component<
 > {
 > {
   state = {
   state = {
     currentTab: "mac",
     currentTab: "mac",
-    currentPage: 0,
+    currentPage: 0
   };
   };
 
 
   renderPage = () => {
   renderPage = () => {
@@ -84,7 +84,7 @@ export default class ClusterInstructionsModal extends Component<
             there are two contexts named minikube and staging, you could connect
             there are two contexts named minikube and staging, you could connect
             both of them via:
             both of them via:
             <Code>
             <Code>
-              porter connect kubeconfig --contexts minikube --contexts staging
+              porter connect kubeconfig --context minikube --context staging
             </Code>
             </Code>
           </Placeholder>
           </Placeholder>
         );
         );

+ 1 - 1
dashboard/src/main/home/modals/IntegrationsInstructionsModal.tsx

@@ -20,7 +20,7 @@ export default class ClusterInstructionsModal extends Component<
 > {
 > {
   state = {
   state = {
     currentTab: "mac",
     currentTab: "mac",
-    currentPage: 0,
+    currentPage: 0
   };
   };
 
 
   renderPage = () => {
   renderPage = () => {

+ 7 - 7
dashboard/src/main/home/modals/IntegrationsModal.tsx

@@ -14,7 +14,7 @@ type StateType = {
 
 
 export default class IntegrationsModal extends Component<PropsType, StateType> {
 export default class IntegrationsModal extends Component<PropsType, StateType> {
   state = {
   state = {
-    integrations: [] as any[],
+    integrations: [] as any[]
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -22,18 +22,18 @@ export default class IntegrationsModal extends Component<PropsType, StateType> {
     if (category === "kubernetes") {
     if (category === "kubernetes") {
       api
       api
         .getClusterIntegrations("<token>", {}, {})
         .getClusterIntegrations("<token>", {}, {})
-        .then((res) => this.setState({ integrations: res.data }))
-        .catch((err) => console.log(err));
+        .then(res => this.setState({ integrations: res.data }))
+        .catch(err => console.log(err));
     } else if (category === "registry") {
     } else if (category === "registry") {
       api
       api
         .getRegistryIntegrations("<token>", {}, {})
         .getRegistryIntegrations("<token>", {}, {})
-        .then((res) => this.setState({ integrations: res.data }))
-        .catch((err) => console.log(err));
+        .then(res => this.setState({ integrations: res.data }))
+        .catch(err => console.log(err));
     } else {
     } else {
       api
       api
         .getRepoIntegrations("<token>", {}, {})
         .getRepoIntegrations("<token>", {}, {})
-        .then((res) => this.setState({ integrations: res.data }))
-        .catch((err) => console.log(err));
+        .then(res => this.setState({ integrations: res.data }))
+        .catch(err => console.log(err));
     }
     }
   }
   }
 
 

+ 9 - 10
dashboard/src/main/home/modals/UpdateClusterModal.tsx

@@ -25,7 +25,7 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
   state = {
   state = {
     clusterName: this.context.currentCluster.name,
     clusterName: this.context.currentCluster.name,
     status: null as string | null,
     status: null as string | null,
-    showDeleteOverlay: false,
+    showDeleteOverlay: false
   };
   };
 
 
   catchErr = (err: any) => {
   catchErr = (err: any) => {
@@ -43,10 +43,10 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
         {},
         {},
         {
         {
           project_id: currentProject.id,
           project_id: currentProject.id,
-          cluster_id: currentCluster.id,
+          cluster_id: currentCluster.id
         }
         }
       )
       )
-      .then((_) => {
+      .then(_ => {
         if (!currentCluster?.infra_id) {
         if (!currentCluster?.infra_id) {
           // TODO: make this more declarative from the Home component
           // TODO: make this more declarative from the Home component
           this.props.setRefreshClusters(true);
           this.props.setRefreshClusters(true);
@@ -65,7 +65,7 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
                 { eks_name: currentCluster.name },
                 { eks_name: currentCluster.name },
                 {
                 {
                   project_id: currentProject.id,
                   project_id: currentProject.id,
-                  infra_id: currentCluster.infra_id,
+                  infra_id: currentCluster.infra_id
                 }
                 }
               )
               )
               .then(() => console.log("destroyed provisioned infra."))
               .then(() => console.log("destroyed provisioned infra."))
@@ -78,7 +78,7 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
                 { gke_name: currentCluster.name },
                 { gke_name: currentCluster.name },
                 {
                 {
                   project_id: currentProject.id,
                   project_id: currentProject.id,
-                  infra_id: currentCluster.infra_id,
+                  infra_id: currentCluster.infra_id
                 }
                 }
               )
               )
               .then(() => console.log("destroyed provisioned infra."))
               .then(() => console.log("destroyed provisioned infra."))
@@ -92,7 +92,7 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
                 { doks_name: currentCluster.name },
                 { doks_name: currentCluster.name },
                 {
                 {
                   project_id: currentProject.id,
                   project_id: currentProject.id,
-                  infra_id: currentCluster.infra_id,
+                  infra_id: currentCluster.infra_id
                 }
                 }
               )
               )
               .then(() => console.log("destroyed provisioned infra."))
               .then(() => console.log("destroyed provisioned infra."))
@@ -121,9 +121,8 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
 
 
     return (
     return (
       <Warning highlight={true}>
       <Warning highlight={true}>
-        ⚠️ Deletion may result in dangling resources. Please visit your cloud
-        provider's console to ensure that all resources have been removed. Note
-        that deleting the cluster does not delete your registries.
+        ⚠️ Deletion may result in dangling resources. For a guide on how to
+        delete dangling resources, click on the Help Button below.
       </Warning>
       </Warning>
     );
     );
   };
   };
@@ -159,7 +158,7 @@ class UpdateClusterModal extends Component<PropsType, StateType> {
         {this.renderWarning()}
         {this.renderWarning()}
 
 
         <Help
         <Help
-          href="https://docs.getporter.dev/docs/getting-started-with-porter-on-aws#deleting-provisioned-resources"
+          href="https://docs.getporter.dev/docs/deleting-dangling-resources"
           target="_blank"
           target="_blank"
         >
         >
           <i className="material-icons">help_outline</i> Help
           <i className="material-icons">help_outline</i> Help

+ 4 - 4
dashboard/src/main/home/navbar/Feedback.tsx

@@ -18,7 +18,7 @@ export default class Feedback extends Component<PropsType, StateType> {
   state = {
   state = {
     feedbackSent: false,
     feedbackSent: false,
     showFeedbackDropdown: false,
     showFeedbackDropdown: false,
-    feedbackText: "",
+    feedbackText: ""
   };
   };
 
 
   renderReceipt = () => {
   renderReceipt = () => {
@@ -57,7 +57,7 @@ export default class Feedback extends Component<PropsType, StateType> {
             onClick={() =>
             onClick={() =>
               this.setState({
               this.setState({
                 showFeedbackDropdown: false,
                 showFeedbackDropdown: false,
-                feedbackSent: false,
+                feedbackSent: false
               })
               })
             }
             }
           />
           />
@@ -69,7 +69,7 @@ export default class Feedback extends Component<PropsType, StateType> {
             <FeedbackInput
             <FeedbackInput
               autoFocus={true}
               autoFocus={true}
               value={this.state.feedbackText}
               value={this.state.feedbackText}
-              onChange={(e) => this.setState({ feedbackText: e.target.value })}
+              onChange={e => this.setState({ feedbackText: e.target.value })}
               placeholder="Help us improve this page."
               placeholder="Help us improve this page."
             />
             />
             <SendButton
             <SendButton
@@ -91,7 +91,7 @@ export default class Feedback extends Component<PropsType, StateType> {
         <Flex
         <Flex
           onClick={() =>
           onClick={() =>
             this.setState({
             this.setState({
-              showFeedbackDropdown: !this.state.showFeedbackDropdown,
+              showFeedbackDropdown: !this.state.showFeedbackDropdown
             })
             })
           }
           }
         >
         >

+ 2 - 2
dashboard/src/main/home/navbar/Navbar.tsx

@@ -17,7 +17,7 @@ type StateType = {
 
 
 export default class Navbar extends Component<PropsType, StateType> {
 export default class Navbar extends Component<PropsType, StateType> {
   state = {
   state = {
-    showDropdown: false,
+    showDropdown: false
   };
   };
 
 
   renderSettingsDropdown = () => {
   renderSettingsDropdown = () => {
@@ -83,7 +83,7 @@ const LogOutButton = styled.button`
   border: 0;
   border: 0;
   text-align: left;
   text-align: left;
   background: none;
   background: none;
-  cursor: ${(props) => (!props.disabled ? "pointer" : "default")};
+  cursor: ${props => (!props.disabled ? "pointer" : "default")};
   user-select: none;
   user-select: none;
   :focus {
   :focus {
     outline: 0;
     outline: 0;

+ 1 - 1
dashboard/src/main/home/new-project/NewProject.tsx

@@ -19,7 +19,7 @@ type StateType = {
 export default class NewProject extends Component<PropsType, StateType> {
 export default class NewProject extends Component<PropsType, StateType> {
   state = {
   state = {
     projectName: "",
     projectName: "",
-    selectedProvider: null as string | null,
+    selectedProvider: null as string | null
   };
   };
 
 
   render() {
   render() {

+ 17 - 18
dashboard/src/main/home/project-settings/InviteList.tsx

@@ -28,7 +28,7 @@ export default class InviteList extends Component<PropsType, StateType> {
     invites: [] as InviteType[],
     invites: [] as InviteType[],
     email: "",
     email: "",
     invalidEmail: false,
     invalidEmail: false,
-    isHTTPS: process.env.API_SERVER === "dashboard.getporter.dev",
+    isHTTPS: process.env.API_SERVER === "dashboard.getporter.dev"
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -44,11 +44,11 @@ export default class InviteList extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {},
         {},
         {
         {
-          id: currentProject.id,
+          id: currentProject.id
         }
         }
       )
       )
-      .then((res) => this.setState({ invites: res.data, loading: false }))
-      .catch((err) => console.log(err));
+      .then(res => this.setState({ invites: res.data, loading: false }))
+      .catch(err => console.log(err));
   };
   };
 
 
   validateEmail = () => {
   validateEmail = () => {
@@ -69,11 +69,11 @@ export default class InviteList extends Component<PropsType, StateType> {
         { email: this.state.email },
         { email: this.state.email },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((_) => {
+      .then(_ => {
         this.getInviteData();
         this.getInviteData();
         this.setState({ email: "" });
         this.setState({ email: "" });
       })
       })
-      .catch((err) => console.log(err));
+      .catch(err => console.log(err));
   };
   };
 
 
   deleteInvite = (index: number) => {
   deleteInvite = (index: number) => {
@@ -84,11 +84,11 @@ export default class InviteList extends Component<PropsType, StateType> {
         {},
         {},
         {
         {
           id: currentProject.id,
           id: currentProject.id,
-          invId: this.state.invites[index].id,
+          invId: this.state.invites[index].id
         }
         }
       )
       )
       .then(this.getInviteData)
       .then(this.getInviteData)
-      .catch((err) => console.log(err));
+      .catch(err => console.log(err));
   };
   };
 
 
   replaceInvite = (index: number) => {
   replaceInvite = (index: number) => {
@@ -99,18 +99,18 @@ export default class InviteList extends Component<PropsType, StateType> {
         { email: this.state.invites[index].email },
         { email: this.state.invites[index].email },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((_) =>
+      .then(_ =>
         api.deleteInvite(
         api.deleteInvite(
           "<token>",
           "<token>",
           {},
           {},
           {
           {
             id: currentProject.id,
             id: currentProject.id,
-            invId: this.state.invites[index].id,
+            invId: this.state.invites[index].id
           }
           }
         )
         )
       )
       )
       .then(this.getInviteData)
       .then(this.getInviteData)
-      .catch((err) => console.log(err));
+      .catch(err => console.log(err));
   };
   };
 
 
   copyToClip = (index: number) => {
   copyToClip = (index: number) => {
@@ -124,8 +124,8 @@ export default class InviteList extends Component<PropsType, StateType> {
         }`
         }`
       )
       )
       .then(
       .then(
-        function () {},
-        function () {
+        function() {},
+        function() {
           console.log("couldn't copy link to clipboard");
           console.log("couldn't copy link to clipboard");
         }
         }
       );
       );
@@ -327,16 +327,15 @@ const InviteButton = styled.div<{ disabled: boolean }>`
   justify-content: center;
   justify-content: center;
   border: 0;
   border: 0;
   border-radius: 5px;
   border-radius: 5px;
-  background: ${(props) => (!props.disabled ? "#616FEEcc" : "#aaaabb")};
-  box-shadow: ${(props) =>
-    !props.disabled ? "0 2px 5px 0 #00000030" : "none"};
-  cursor: ${(props) => (!props.disabled ? "pointer" : "default")};
+  background: ${props => (!props.disabled ? "#616FEEcc" : "#aaaabb")};
+  box-shadow: ${props => (!props.disabled ? "0 2px 5px 0 #00000030" : "none")};
+  cursor: ${props => (!props.disabled ? "pointer" : "default")};
   user-select: none;
   user-select: none;
   :focus {
   :focus {
     outline: 0;
     outline: 0;
   }
   }
   :hover {
   :hover {
-    filter: ${(props) => (!props.disabled ? "brightness(120%)" : "")};
+    filter: ${props => (!props.disabled ? "brightness(120%)" : "")};
   }
   }
   margin-bottom: 10px;
   margin-bottom: 10px;
 `;
 `;

+ 18 - 3
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -17,13 +17,13 @@ type StateType = {
 
 
 const tabOptions = [
 const tabOptions = [
   { value: "manage-access", label: "Manage Access" },
   { value: "manage-access", label: "Manage Access" },
-  { value: "additional-settings", label: "Additional Settings" },
+  { value: "additional-settings", label: "Additional Settings" }
 ];
 ];
 
 
 export default class ProjectSettings extends Component<PropsType, StateType> {
 export default class ProjectSettings extends Component<PropsType, StateType> {
   state = {
   state = {
     projectName: "",
     projectName: "",
-    currentTab: "manage-access",
+    currentTab: "manage-access"
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -45,12 +45,27 @@ export default class ProjectSettings extends Component<PropsType, StateType> {
             delete the registries, please do so manually in your cloud console.
             delete the registries, please do so manually in your cloud console.
           </Helper>
           </Helper>
 
 
+          <Helper>
+            Destruction of resources sometimes results in dangling resources. To
+            ensure that everything has been properly destroyed, please visit
+            your cloud provider's console. Instructions to properly delete all
+            resources can be found
+            <a
+              target="none"
+              href="https://docs.getporter.dev/docs/deleting-dangling-resources"
+            >
+              {" "}
+              here
+            </a>
+            .
+          </Helper>
+
           <Warning highlight={true}>This action cannot be undone.</Warning>
           <Warning highlight={true}>This action cannot be undone.</Warning>
 
 
           <DeleteButton
           <DeleteButton
             onClick={() => {
             onClick={() => {
               this.context.setCurrentModal("UpdateProjectModal", {
               this.context.setCurrentModal("UpdateProjectModal", {
-                currentProject: this.context.currentProject,
+                currentProject: this.context.currentProject
               });
               });
             }}
             }}
           >
           >

+ 13 - 13
dashboard/src/main/home/provisioner/AWSFormSection.tsx

@@ -34,7 +34,7 @@ type StateType = {
 
 
 const provisionOptions = [
 const provisionOptions = [
   { value: "ecr", label: "Elastic Container Registry (ECR)" },
   { value: "ecr", label: "Elastic Container Registry (ECR)" },
-  { value: "eks", label: "Elastic Kubernetes Service (EKS)" },
+  { value: "eks", label: "Elastic Kubernetes Service (EKS)" }
 ];
 ];
 
 
 const regionOptions = [
 const regionOptions = [
@@ -57,7 +57,7 @@ const regionOptions = [
   { value: "eu-west-3", label: "Europe (Paris) eu-west-3" },
   { value: "eu-west-3", label: "Europe (Paris) eu-west-3" },
   { value: "eu-north-1", label: "Europe (Stockholm) eu-north-1" },
   { value: "eu-north-1", label: "Europe (Stockholm) eu-north-1" },
   { value: "me-south-1", label: "Middle East (Bahrain) me-south-1" },
   { value: "me-south-1", label: "Middle East (Bahrain) me-south-1" },
-  { value: "sa-east-1", label: "South America (São Paulo) sa-east-1" },
+  { value: "sa-east-1", label: "South America (São Paulo) sa-east-1" }
 ];
 ];
 
 
 // TODO: Consolidate across forms w/ HOC
 // TODO: Consolidate across forms w/ HOC
@@ -68,7 +68,7 @@ class AWSFormSection extends Component<PropsType, StateType> {
     awsSecretKey: "",
     awsSecretKey: "",
     selectedInfras: [...provisionOptions],
     selectedInfras: [...provisionOptions],
     buttonStatus: "",
     buttonStatus: "",
-    provisionConfirmed: false,
+    provisionConfirmed: false
   };
   };
 
 
   componentDidMount = () => {
   componentDidMount = () => {
@@ -125,7 +125,7 @@ class AWSFormSection extends Component<PropsType, StateType> {
 
 
     api
     api
       .createProject("<token>", { name: projectName }, {})
       .createProject("<token>", { name: projectName }, {})
-      .then((res) => {
+      .then(res => {
         let proj = res.data;
         let proj = res.data;
         // Need to set project list for dropdown
         // Need to set project list for dropdown
         // TODO: consolidate into ProjectSection (case on exists in list on set)
         // TODO: consolidate into ProjectSection (case on exists in list on set)
@@ -134,10 +134,10 @@ class AWSFormSection extends Component<PropsType, StateType> {
             "<token>",
             "<token>",
             {},
             {},
             {
             {
-              id: user.userId,
+              id: user.userId
             }
             }
           )
           )
-          .then((res) => {
+          .then(res => {
             setProjects(res.data);
             setProjects(res.data);
             setCurrentProject(proj, () => {
             setCurrentProject(proj, () => {
               callback && callback();
               callback && callback();
@@ -159,16 +159,16 @@ class AWSFormSection extends Component<PropsType, StateType> {
         {
         {
           aws_region: awsRegion,
           aws_region: awsRegion,
           aws_access_key_id: awsAccessId,
           aws_access_key_id: awsAccessId,
-          aws_secret_access_key: awsSecretKey,
+          aws_secret_access_key: awsSecretKey
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.provisionECR(
         api.provisionECR(
           "<token>",
           "<token>",
           {
           {
             aws_integration_id: res.data.id,
             aws_integration_id: res.data.id,
-            ecr_name: `${currentProject.name}-registry`,
+            ecr_name: `${currentProject.name}-registry`
           },
           },
           { id: currentProject.id }
           { id: currentProject.id }
         )
         )
@@ -189,16 +189,16 @@ class AWSFormSection extends Component<PropsType, StateType> {
           aws_region: awsRegion,
           aws_region: awsRegion,
           aws_access_key_id: awsAccessId,
           aws_access_key_id: awsAccessId,
           aws_secret_access_key: awsSecretKey,
           aws_secret_access_key: awsSecretKey,
-          aws_cluster_id: clusterName,
+          aws_cluster_id: clusterName
         },
         },
         { id: currentProject.id }
         { id: currentProject.id }
       )
       )
-      .then((res) =>
+      .then(res =>
         api.provisionEKS(
         api.provisionEKS(
           "<token>",
           "<token>",
           {
           {
             aws_integration_id: res.data.id,
             aws_integration_id: res.data.id,
-            eks_name: clusterName,
+            eks_name: clusterName
           },
           },
           { id: currentProject.id }
           { id: currentProject.id }
         )
         )
@@ -336,7 +336,7 @@ class AWSFormSection extends Component<PropsType, StateType> {
             checked={this.state.provisionConfirmed}
             checked={this.state.provisionConfirmed}
             toggle={() =>
             toggle={() =>
               this.setState({
               this.setState({
-                provisionConfirmed: !this.state.provisionConfirmed,
+                provisionConfirmed: !this.state.provisionConfirmed
               })
               })
             }
             }
             label="I understand and wish to proceed"
             label="I understand and wish to proceed"

+ 7 - 7
dashboard/src/main/home/provisioner/DOFormSection.tsx

@@ -30,13 +30,13 @@ type StateType = {
 
 
 const provisionOptions = [
 const provisionOptions = [
   { value: "docr", label: "Digital Ocean Container Registry" },
   { value: "docr", label: "Digital Ocean Container Registry" },
-  { value: "doks", label: "Digital Ocean Kubernetes Service" },
+  { value: "doks", label: "Digital Ocean Kubernetes Service" }
 ];
 ];
 
 
 const tierOptions = [
 const tierOptions = [
   { value: "basic", label: "Basic" },
   { value: "basic", label: "Basic" },
   { value: "starter", label: "Starter" },
   { value: "starter", label: "Starter" },
-  { value: "professional", label: "Professional" },
+  { value: "professional", label: "Professional" }
 ];
 ];
 
 
 const regionOptions = [
 const regionOptions = [
@@ -49,7 +49,7 @@ const regionOptions = [
   { value: "sfo2", label: "San Francisco 2" },
   { value: "sfo2", label: "San Francisco 2" },
   { value: "sfo3", label: "San Francisco 3" },
   { value: "sfo3", label: "San Francisco 3" },
   { value: "sgp1", label: "Singapore 1" },
   { value: "sgp1", label: "Singapore 1" },
-  { value: "tor1", label: "Toronto 1" },
+  { value: "tor1", label: "Toronto 1" }
 ];
 ];
 
 
 // TODO: Consolidate across forms w/ HOC
 // TODO: Consolidate across forms w/ HOC
@@ -58,7 +58,7 @@ export default class DOFormSection extends Component<PropsType, StateType> {
     selectedInfras: [...provisionOptions],
     selectedInfras: [...provisionOptions],
     subscriptionTier: "starter",
     subscriptionTier: "starter",
     doRegion: "nyc1",
     doRegion: "nyc1",
-    provisionConfirmed: false,
+    provisionConfirmed: false
   };
   };
 
 
   componentDidMount = () => {
   componentDidMount = () => {
@@ -108,7 +108,7 @@ export default class DOFormSection extends Component<PropsType, StateType> {
 
 
     api
     api
       .createProject("<token>", { name: projectName }, {})
       .createProject("<token>", { name: projectName }, {})
-      .then(async (res) => {
+      .then(async res => {
         let proj = res.data;
         let proj = res.data;
 
 
         // Need to set project list for dropdown
         // Need to set project list for dropdown
@@ -117,7 +117,7 @@ export default class DOFormSection extends Component<PropsType, StateType> {
           "<token>",
           "<token>",
           {},
           {},
           {
           {
-            id: user.userId,
+            id: user.userId
           }
           }
         );
         );
         setProjects(res_1.data);
         setProjects(res_1.data);
@@ -219,7 +219,7 @@ export default class DOFormSection extends Component<PropsType, StateType> {
             checked={this.state.provisionConfirmed}
             checked={this.state.provisionConfirmed}
             toggle={() =>
             toggle={() =>
               this.setState({
               this.setState({
-                provisionConfirmed: !this.state.provisionConfirmed,
+                provisionConfirmed: !this.state.provisionConfirmed
               })
               })
             }
             }
             label="I understand and wish to proceed"
             label="I understand and wish to proceed"

+ 4 - 4
dashboard/src/main/home/provisioner/ExistingClusterSection.tsx

@@ -19,7 +19,7 @@ type StateType = {
 
 
 class ExistingClusterSection extends Component<PropsType, StateType> {
 class ExistingClusterSection extends Component<PropsType, StateType> {
   state = {
   state = {
-    buttonStatus: "",
+    buttonStatus: ""
   };
   };
 
 
   onCreateProject = () => {
   onCreateProject = () => {
@@ -29,16 +29,16 @@ class ExistingClusterSection extends Component<PropsType, StateType> {
     this.setState({ buttonStatus: "loading" });
     this.setState({ buttonStatus: "loading" });
     api
     api
       .createProject("<token>", { name: projectName }, {})
       .createProject("<token>", { name: projectName }, {})
-      .then((res) =>
+      .then(res =>
         api.getProjects(
         api.getProjects(
           "<token>",
           "<token>",
           {},
           {},
           {
           {
-            id: user.userId,
+            id: user.userId
           }
           }
         )
         )
       )
       )
-      .then((res) => {
+      .then(res => {
         if (res.data) {
         if (res.data) {
           setProjects(res.data);
           setProjects(res.data);
           if (res.data.length > 0) {
           if (res.data.length > 0) {

+ 12 - 12
dashboard/src/main/home/provisioner/GCPFormSection.tsx

@@ -34,7 +34,7 @@ type StateType = {
 
 
 const provisionOptions = [
 const provisionOptions = [
   { value: "gcr", label: "Google Container Registry (GCR)" },
   { value: "gcr", label: "Google Container Registry (GCR)" },
-  { value: "gke", label: "Google Kubernetes Engine (GKE)" },
+  { value: "gke", label: "Google Kubernetes Engine (GKE)" }
 ];
 ];
 
 
 const regionOptions = [
 const regionOptions = [
@@ -61,7 +61,7 @@ const regionOptions = [
   { value: "us-west1", label: "us-west1" },
   { value: "us-west1", label: "us-west1" },
   { value: "us-west2", label: "us-west2" },
   { value: "us-west2", label: "us-west2" },
   { value: "us-west3", label: "us-west3" },
   { value: "us-west3", label: "us-west3" },
-  { value: "us-west4", label: "us-west4" },
+  { value: "us-west4", label: "us-west4" }
 ];
 ];
 
 
 class GCPFormSection extends Component<PropsType, StateType> {
 class GCPFormSection extends Component<PropsType, StateType> {
@@ -71,7 +71,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
     gcpKeyData: "",
     gcpKeyData: "",
     selectedInfras: [...provisionOptions],
     selectedInfras: [...provisionOptions],
     buttonStatus: "",
     buttonStatus: "",
-    provisionConfirmed: false,
+    provisionConfirmed: false
   };
   };
 
 
   componentDidMount = () => {
   componentDidMount = () => {
@@ -127,7 +127,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
 
 
     api
     api
       .createProject("<token>", { name: projectName }, {})
       .createProject("<token>", { name: projectName }, {})
-      .then((res) => {
+      .then(res => {
         let proj = res.data;
         let proj = res.data;
 
 
         // Need to set project list for dropdown
         // Need to set project list for dropdown
@@ -137,10 +137,10 @@ class GCPFormSection extends Component<PropsType, StateType> {
             "<token>",
             "<token>",
             {},
             {},
             {
             {
-              id: user.userId,
+              id: user.userId
             }
             }
           )
           )
-          .then((res) => {
+          .then(res => {
             setProjects(res.data);
             setProjects(res.data);
             setCurrentProject(proj);
             setCurrentProject(proj);
             callback && callback();
             callback && callback();
@@ -158,7 +158,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
       .createGCR(
       .createGCR(
         "<token>",
         "<token>",
         {
         {
-          gcp_integration_id: id,
+          gcp_integration_id: id
         },
         },
         { project_id: currentProject.id }
         { project_id: currentProject.id }
       )
       )
@@ -176,11 +176,11 @@ class GCPFormSection extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {
         {
           gke_name: clusterName,
           gke_name: clusterName,
-          gcp_integration_id: id,
+          gcp_integration_id: id
         },
         },
         { project_id: currentProject.id }
         { project_id: currentProject.id }
       )
       )
-      .then((res) => {
+      .then(res => {
         this.props.history.push("dashboard?tab=provisioner");
         this.props.history.push("dashboard?tab=provisioner");
       })
       })
       .catch(this.catchError);
       .catch(this.catchError);
@@ -195,11 +195,11 @@ class GCPFormSection extends Component<PropsType, StateType> {
         {
         {
           gcp_region: gcpRegion,
           gcp_region: gcpRegion,
           gcp_key_data: gcpKeyData,
           gcp_key_data: gcpKeyData,
-          gcp_project_id: gcpProjectId,
+          gcp_project_id: gcpProjectId
         },
         },
         { project_id: currentProject.id }
         { project_id: currentProject.id }
       )
       )
-      .then((res) => {
+      .then(res => {
         if (res?.data) {
         if (res?.data) {
           console.log("gcp provisioned with response: ", res.data);
           console.log("gcp provisioned with response: ", res.data);
           let { id } = res.data;
           let { id } = res.data;
@@ -325,7 +325,7 @@ class GCPFormSection extends Component<PropsType, StateType> {
             checked={this.state.provisionConfirmed}
             checked={this.state.provisionConfirmed}
             toggle={() =>
             toggle={() =>
               this.setState({
               this.setState({
-                provisionConfirmed: !this.state.provisionConfirmed,
+                provisionConfirmed: !this.state.provisionConfirmed
               })
               })
             }
             }
             label="I understand and wish to proceed"
             label="I understand and wish to proceed"

+ 1 - 1
dashboard/src/main/home/provisioner/InfraStatuses.tsx

@@ -56,7 +56,7 @@ const StatusIcon = styled.div<{ color?: string }>`
   justify-content: center;
   justify-content: center;
   width: 20px;
   width: 20px;
   font-size: 16px;
   font-size: 16px;
-  color: ${(props) => (props.color ? props.color : "#68c49c")};
+  color: ${props => (props.color ? props.color : "#68c49c")};
   margin-left: 10px;
   margin-left: 10px;
 `;
 `;
 
 

+ 4 - 4
dashboard/src/main/home/provisioner/Provisioner.tsx

@@ -36,7 +36,7 @@ class Provisioner extends Component<PropsType, StateType> {
     infras: [] as InfraType[],
     infras: [] as InfraType[],
     selectedInfra: null as InfraType,
     selectedInfra: null as InfraType,
     loading: true,
     loading: true,
-    currentProject: this.context.currentProject,
+    currentProject: this.context.currentProject
   };
   };
 
 
   selectInfra = (infra: InfraType) => {
   selectInfra = (infra: InfraType) => {
@@ -51,10 +51,10 @@ class Provisioner extends Component<PropsType, StateType> {
         "<token>",
         "<token>",
         {},
         {},
         {
         {
-          project_id: currentProject.id,
+          project_id: currentProject.id
         }
         }
       )
       )
-      .then((res) => {
+      .then(res => {
         let infras = res.data.sort((a: InfraType, b: InfraType) => {
         let infras = res.data.sort((a: InfraType, b: InfraType) => {
           return b.id - a.id;
           return b.id - a.id;
         });
         });
@@ -63,7 +63,7 @@ class Provisioner extends Component<PropsType, StateType> {
           error: false,
           error: false,
           infras,
           infras,
           loading: false,
           loading: false,
-          selectedInfra: infras[0],
+          selectedInfra: infras[0]
         });
         });
       })
       })
       .catch();
       .catch();

+ 4 - 4
dashboard/src/main/home/provisioner/ProvisionerLogs.tsx

@@ -26,7 +26,7 @@ class ProvisionerLogs extends Component<PropsType, StateType> {
     ws: null as any,
     ws: null as any,
     scroll: true,
     scroll: true,
     maxStep: 0,
     maxStep: 0,
-    error: false,
+    error: false
   };
   };
 
 
   ws = null as any;
   ws = null as any;
@@ -34,7 +34,7 @@ class ProvisionerLogs extends Component<PropsType, StateType> {
 
 
   scrollToBottom = () => {
   scrollToBottom = () => {
     this.parentRef.current.lastElementChild.scrollIntoView({
     this.parentRef.current.lastElementChild.scrollIntoView({
-      behavior: "auto",
+      behavior: "auto"
     });
     });
   };
   };
 
 
@@ -138,7 +138,7 @@ class ProvisionerLogs extends Component<PropsType, StateType> {
 
 
       if (err) {
       if (err) {
         window.analytics.track("Provisioning Error", {
         window.analytics.track("Provisioning Error", {
-          error: err,
+          error: err
         });
         });
         let e = ansiparse(err).map((el: any) => {
         let e = ansiparse(err).map((el: any) => {
           return el.text;
           return el.text;
@@ -164,7 +164,7 @@ class ProvisionerLogs extends Component<PropsType, StateType> {
       this.setState(
       this.setState(
         {
         {
           logs: [...this.state.logs, ...logs],
           logs: [...this.state.logs, ...logs],
-          maxStep: validEvents[validEvents.length - 1]["total_resources"],
+          maxStep: validEvents[validEvents.length - 1]["total_resources"]
         },
         },
         () => {
         () => {
           this.scrollToBottom();
           this.scrollToBottom();

+ 5 - 5
dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

@@ -29,7 +29,7 @@ const providers = ["aws", "gcp", "do"];
 class NewProject extends Component<PropsType, StateType> {
 class NewProject extends Component<PropsType, StateType> {
   state = {
   state = {
     selectedProvider: null as string | null,
     selectedProvider: null as string | null,
-    infras: [] as InfraType[],
+    infras: [] as InfraType[]
   };
   };
 
 
   // Handle any submission (pre-status) error
   // Handle any submission (pre-status) error
@@ -65,7 +65,7 @@ class NewProject extends Component<PropsType, StateType> {
                 <Highlight
                 <Highlight
                   onClick={() =>
                   onClick={() =>
                     this.setState({
                     this.setState({
-                      selectedProvider: "skipped",
+                      selectedProvider: "skipped"
                     })
                     })
                   }
                   }
                 >
                 >
@@ -227,7 +227,7 @@ const Icon = styled.img<{ bw?: boolean }>`
   height: 42px;
   height: 42px;
   margin-top: 30px;
   margin-top: 30px;
   margin-bottom: 15px;
   margin-bottom: 15px;
-  filter: ${(props) => (props.bw ? "grayscale(1)" : "")};
+  filter: ${props => (props.bw ? "grayscale(1)" : "")};
 `;
 `;
 
 
 const BlockDescription = styled.div`
 const BlockDescription = styled.div`
@@ -268,13 +268,13 @@ const Block = styled.div<{ disabled?: boolean }>`
   align-item: center;
   align-item: center;
   justify-content: space-between;
   justify-content: space-between;
   height: 170px;
   height: 170px;
-  cursor: ${(props) => (props.disabled ? "" : "pointer")};
+  cursor: ${props => (props.disabled ? "" : "pointer")};
   color: #ffffff;
   color: #ffffff;
   position: relative;
   position: relative;
   background: #26282f;
   background: #26282f;
   box-shadow: 0 3px 5px 0px #00000022;
   box-shadow: 0 3px 5px 0px #00000022;
   :hover {
   :hover {
-    background: ${(props) => (props.disabled ? "" : "#ffffff11")};
+    background: ${props => (props.disabled ? "" : "#ffffff11")};
   }
   }
 
 
   animation: fadeIn 0.3s 0s;
   animation: fadeIn 0.3s 0s;

+ 10 - 5
dashboard/src/main/home/sidebar/ClusterSection.tsx

@@ -34,16 +34,21 @@ class ClusterSection extends Component<PropsType, StateType> {
     showDrawer: false,
     showDrawer: false,
     initializedDrawer: false,
     initializedDrawer: false,
     clusters: [] as ClusterType[],
     clusters: [] as ClusterType[],
-    prevProjectId: this.context.currentProject.id,
+    prevProjectId: this.context.currentProject.id
   };
   };
 
 
   updateClusters = () => {
   updateClusters = () => {
-    let { currentProject, setCurrentCluster } = this.context;
+    let { user, currentProject, setCurrentCluster } = this.context;
 
 
     // TODO: query with selected filter once implemented
     // TODO: query with selected filter once implemented
     api
     api
       .getClusters("<token>", {}, { id: currentProject.id })
       .getClusters("<token>", {}, { id: currentProject.id })
-      .then((res) => {
+      .then(res => {
+        window.analytics.identify(user.userId, {
+          currentProject,
+          clusters: res.data
+        });
+
         this.props.setWelcome(false);
         this.props.setWelcome(false);
         // TODO: handle uninitialized kubeconfig
         // TODO: handle uninitialized kubeconfig
         if (res.data) {
         if (res.data) {
@@ -79,7 +84,7 @@ class ClusterSection extends Component<PropsType, StateType> {
           }
           }
         }
         }
       })
       })
-      .catch((err) => this.props.setWelcome(true));
+      .catch(err => this.props.setWelcome(true));
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -126,7 +131,7 @@ class ClusterSection extends Component<PropsType, StateType> {
 
 
   showClusterConfigModal = () => {
   showClusterConfigModal = () => {
     this.context.setCurrentModal("ClusterConfigModal", {
     this.context.setCurrentModal("ClusterConfigModal", {
-      updateClusters: this.updateClusters,
+      updateClusters: this.updateClusters
     });
     });
   };
   };
 
 

+ 1 - 1
dashboard/src/main/home/sidebar/ProjectSection.tsx

@@ -17,7 +17,7 @@ type StateType = {
 
 
 class ProjectSection extends Component<PropsType, StateType> {
 class ProjectSection extends Component<PropsType, StateType> {
   state = {
   state = {
-    expanded: false,
+    expanded: false
   };
   };
 
 
   wrapperRef: any = React.createRef();
   wrapperRef: any = React.createRef();

+ 5 - 5
dashboard/src/main/home/sidebar/Sidebar.tsx

@@ -36,7 +36,7 @@ class Sidebar extends Component<PropsType, StateType> {
     initializedSidebar: false,
     initializedSidebar: false,
     pressingCtrl: false,
     pressingCtrl: false,
     showTooltip: false,
     showTooltip: false,
-    forceCloseDrawer: false,
+    forceCloseDrawer: false
   };
   };
 
 
   componentDidMount() {
   componentDidMount() {
@@ -73,7 +73,7 @@ class Sidebar extends Component<PropsType, StateType> {
   toggleSidebar = (): void => {
   toggleSidebar = (): void => {
     this.setState({
     this.setState({
       showSidebar: !this.state.showSidebar,
       showSidebar: !this.state.showSidebar,
-      forceCloseDrawer: true,
+      forceCloseDrawer: true
     });
     });
   };
   };
 
 
@@ -267,11 +267,11 @@ const NavButton = styled.div`
 
 
 const Img = styled.img<{ enlarge?: boolean }>`
 const Img = styled.img<{ enlarge?: boolean }>`
   padding: 4px 4px;
   padding: 4px 4px;
-  height: ${(props) => (props.enlarge ? "27px" : "23px")};
-  width: ${(props) => (props.enlarge ? "27px" : "23px")};
+  height: ${props => (props.enlarge ? "27px" : "23px")};
+  width: ${props => (props.enlarge ? "27px" : "23px")};
   border-radius: 3px;
   border-radius: 3px;
   position: absolute;
   position: absolute;
-  left: ${(props) => (props.enlarge ? "19px" : "20px")};
+  left: ${props => (props.enlarge ? "19px" : "20px")};
   top: 9px;
   top: 9px;
 `;
 `;
 
 

+ 10 - 0
dashboard/src/shared/api.tsx

@@ -451,6 +451,15 @@ const getNamespaces = baseApi<
   return `/api/projects/${pathParams.id}/k8s/namespaces`;
   return `/api/projects/${pathParams.id}/k8s/namespaces`;
 });
 });
 
 
+const getNGINXIngresses = baseApi<
+  {
+    cluster_id: number;
+  },
+  { id: number }
+>("GET", pathParams => {
+  return `/api/projects/${pathParams.id}/k8s/prometheus/ingresses`;
+});
+
 const getOAuthIds = baseApi<
 const getOAuthIds = baseApi<
   {},
   {},
   {
   {
@@ -716,6 +725,7 @@ export default {
   getMatchingPods,
   getMatchingPods,
   getMetrics,
   getMetrics,
   getNamespaces,
   getNamespaces,
+  getNGINXIngresses,
   getOAuthIds,
   getOAuthIds,
   getProjectClusters,
   getProjectClusters,
   getProjectRegistries,
   getProjectRegistries,

+ 1 - 1
docs/GETTING_STARTED.md

@@ -99,5 +99,5 @@ porter connect kubeconfig --kubeconfig path/to/kubeconfig
 You can initialize Porter with a set of contexts by passing a context list to start. The contexts that Porter will be able to access are the same as `kubectl config get-contexts`. For example, if there are two contexts named `minikube` and `staging`, you could connect both of them via:
 You can initialize Porter with a set of contexts by passing a context list to start. The contexts that Porter will be able to access are the same as `kubectl config get-contexts`. For example, if there are two contexts named `minikube` and `staging`, you could connect both of them via:
 
 
 ```sh
 ```sh
-porter connect kubeconfig --contexts minikube --contexts staging
+porter connect kubeconfig --context minikube --context staging
 ```
 ```

+ 2 - 2
go.mod

@@ -57,9 +57,9 @@ require (
 	github.com/pelletier/go-toml v1.8.1 // indirect
 	github.com/pelletier/go-toml v1.8.1 // indirect
 	github.com/pkg/errors v0.9.1
 	github.com/pkg/errors v0.9.1
 	github.com/rs/zerolog v1.20.0
 	github.com/rs/zerolog v1.20.0
-	github.com/sendgrid/rest v2.6.3+incompatible // indirect
-	github.com/sendgrid/sendgrid-go v3.8.0+incompatible // indirect
 	github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
 	github.com/segmentio/backo-go v0.0.0-20200129164019-23eae7c10bd3 // indirect
+	github.com/sendgrid/rest v2.6.3+incompatible // indirect
+	github.com/sendgrid/sendgrid-go v3.8.0+incompatible
 	github.com/sirupsen/logrus v1.7.0
 	github.com/sirupsen/logrus v1.7.0
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/cobra v1.0.0
 	github.com/spf13/viper v1.4.0
 	github.com/spf13/viper v1.4.0

+ 1 - 0
internal/helm/agent.go

@@ -94,6 +94,7 @@ func (a *Agent) UpgradeReleaseByValues(
 	ch := rel.Chart
 	ch := rel.Chart
 
 
 	cmd := action.NewUpgrade(a.ActionConfig)
 	cmd := action.NewUpgrade(a.ActionConfig)
+	cmd.Namespace = rel.Namespace
 
 
 	if conf.Cluster != nil && a.K8sAgent != nil && conf.Registries != nil && len(conf.Registries) > 0 {
 	if conf.Cluster != nil && a.K8sAgent != nil && conf.Registries != nil && len(conf.Registries) > 0 {
 		cmd.PostRenderer, err = NewDockerSecretsPostRenderer(
 		cmd.PostRenderer, err = NewDockerSecretsPostRenderer(

+ 19 - 10
internal/helm/config.go

@@ -33,6 +33,7 @@ func GetAgentOutOfClusterConfig(form *Form, l *logger.Logger) (*Agent, error) {
 	// create a kubernetes agent
 	// create a kubernetes agent
 	conf := &kubernetes.OutOfClusterConfig{
 	conf := &kubernetes.OutOfClusterConfig{
 		Cluster:           form.Cluster,
 		Cluster:           form.Cluster,
+		DefaultNamespace:  form.Namespace,
 		Repo:              form.Repo,
 		Repo:              form.Repo,
 		DigitalOceanOAuth: form.DigitalOceanOAuth,
 		DigitalOceanOAuth: form.DigitalOceanOAuth,
 	}
 	}
@@ -48,21 +49,29 @@ func GetAgentOutOfClusterConfig(form *Form, l *logger.Logger) (*Agent, error) {
 
 
 // GetAgentFromK8sAgent creates a new Agent
 // GetAgentFromK8sAgent creates a new Agent
 func GetAgentFromK8sAgent(stg string, ns string, l *logger.Logger, k8sAgent *kubernetes.Agent) (*Agent, error) {
 func GetAgentFromK8sAgent(stg string, ns string, l *logger.Logger, k8sAgent *kubernetes.Agent) (*Agent, error) {
-	clientset, ok := k8sAgent.Clientset.(*k8s.Clientset)
+	// clientset, ok := k8sAgent.Clientset.(*k8s.Clientset)
 
 
-	if !ok {
-		return nil, errors.New("Agent Clientset was not of type *(k8s.io/client-go/kubernetes).Clientset")
+	// if !ok {
+	// 	return nil, errors.New("Agent Clientset was not of type *(k8s.io/client-go/kubernetes).Clientset")
+	// }
+
+	// actionConf := &action.Configuration{
+	// 	RESTClientGetter: k8sAgent.RESTClientGetter,
+	// 	KubeClient:       kube.New(k8sAgent.RESTClientGetter),
+	// 	Releases:         StorageMap[stg](l, clientset.CoreV1(), ns),
+	// 	Log:              l.Printf,
+	// }
+
+	actionConf := &action.Configuration{}
+
+	if err := actionConf.Init(k8sAgent.RESTClientGetter, ns, stg, l.Printf); err != nil {
+		return nil, err
 	}
 	}
 
 
 	// use k8s agent to create Helm agent
 	// use k8s agent to create Helm agent
 	return &Agent{
 	return &Agent{
-		ActionConfig: &action.Configuration{
-			RESTClientGetter: k8sAgent.RESTClientGetter,
-			KubeClient:       kube.New(k8sAgent.RESTClientGetter),
-			Releases:         StorageMap[stg](l, clientset.CoreV1(), ns),
-			Log:              l.Printf,
-		},
-		K8sAgent: k8sAgent,
+		ActionConfig: actionConf,
+		K8sAgent:     k8sAgent,
 	}, nil
 	}, nil
 }
 }
 
 

+ 12 - 3
internal/kubernetes/config.go

@@ -89,8 +89,9 @@ func GetAgentTesting(objects ...runtime.Object) *Agent {
 // OutOfClusterConfig is the set of parameters required for an out-of-cluster connection.
 // OutOfClusterConfig is the set of parameters required for an out-of-cluster connection.
 // This implements RESTClientGetter
 // This implements RESTClientGetter
 type OutOfClusterConfig struct {
 type OutOfClusterConfig struct {
-	Cluster *models.Cluster
-	Repo    *repository.Repository
+	Cluster          *models.Cluster
+	Repo             *repository.Repository
+	DefaultNamespace string // optional
 
 
 	// Only required if using DigitalOcean OAuth as an auth mechanism
 	// Only required if using DigitalOcean OAuth as an auth mechanism
 	DigitalOceanOAuth *oauth2.Config
 	DigitalOceanOAuth *oauth2.Config
@@ -186,7 +187,15 @@ func (conf *OutOfClusterConfig) GetClientConfigFromCluster() (clientcmd.ClientCo
 		return nil, err
 		return nil, err
 	}
 	}
 
 
-	config := clientcmd.NewDefaultClientConfig(*apiConfig, &clientcmd.ConfigOverrides{})
+	overrides := &clientcmd.ConfigOverrides{}
+
+	if conf.DefaultNamespace != "" {
+		overrides.Context = api.Context{
+			Namespace: conf.DefaultNamespace,
+		}
+	}
+
+	config := clientcmd.NewDefaultClientConfig(*apiConfig, overrides)
 
 
 	return config, nil
 	return config, nil
 }
 }

+ 41 - 4
internal/kubernetes/prometheus/metrics.go

@@ -29,6 +29,36 @@ func GetPrometheusService(clientset kubernetes.Interface) (*v1.Service, bool, er
 	return &services.Items[0], true, nil
 	return &services.Items[0], true, nil
 }
 }
 
 
+type SimpleIngress struct {
+	Name      string `json:"name"`
+	Namespace string `json:"namespace"`
+}
+
+// GetIngressesWithNGINXAnnotation gets an array of names for all ingresses controlled by
+// NGINX
+func GetIngressesWithNGINXAnnotation(clientset kubernetes.Interface) ([]SimpleIngress, error) {
+	ingressList, err := clientset.NetworkingV1beta1().Ingresses("").List(context.TODO(), metav1.ListOptions{})
+
+	if err != nil {
+		return nil, err
+	}
+
+	res := make([]SimpleIngress, 0)
+
+	for _, ingress := range ingressList.Items {
+		if ingressAnn, found := ingress.ObjectMeta.Annotations["kubernetes.io/ingress.class"]; found {
+			if ingressAnn == "nginx" {
+				res = append(res, SimpleIngress{
+					Name:      ingress.ObjectMeta.Name,
+					Namespace: ingress.ObjectMeta.Namespace,
+				})
+			}
+		}
+	}
+
+	return res, nil
+}
+
 type QueryOpts struct {
 type QueryOpts struct {
 	Metric     string   `schema:"metric"`
 	Metric     string   `schema:"metric"`
 	ShouldSum  bool     `schema:"shouldsum"`
 	ShouldSum  bool     `schema:"shouldsum"`
@@ -58,6 +88,10 @@ func QueryPrometheus(
 	} else if opts.Metric == "network" {
 	} else if opts.Metric == "network" {
 		netPodSelector := fmt.Sprintf(`namespace="%s",pod=~"%s",container="POD"`, opts.Namespace, strings.Join(opts.PodList, "|"))
 		netPodSelector := fmt.Sprintf(`namespace="%s",pod=~"%s",container="POD"`, opts.Namespace, strings.Join(opts.PodList, "|"))
 		query = fmt.Sprintf("rate(container_network_receive_bytes_total{%s}[5m])", netPodSelector)
 		query = fmt.Sprintf("rate(container_network_receive_bytes_total{%s}[5m])", netPodSelector)
+	} else if opts.Metric == "nginx:errors" {
+		num := fmt.Sprintf(`sum(rate(nginx_ingress_controller_requests{status=~"5.*",namespace="%s",ingress=~"%s"}[5m]) OR on() vector(0))`, opts.Namespace, strings.Join(opts.PodList, "|"))
+		denom := fmt.Sprintf(`sum(rate(nginx_ingress_controller_requests{namespace="%s",ingress=~"%s"}[5m]) > 0)`, opts.Namespace, strings.Join(opts.PodList, "|"))
+		query = fmt.Sprintf(`%s / %s * 100 OR on() vector(0)`, num, denom)
 	}
 	}
 
 
 	if opts.ShouldSum {
 	if opts.ShouldSum {
@@ -101,10 +135,11 @@ type promRawQuery struct {
 }
 }
 
 
 type promParsedSingletonQueryResult struct {
 type promParsedSingletonQueryResult struct {
-	Date   interface{} `json:"date,omitempty"`
-	CPU    interface{} `json:"cpu,omitempty"`
-	Memory interface{} `json:"memory,omitempty"`
-	Bytes  interface{} `json:"bytes,omitempty"`
+	Date     interface{} `json:"date,omitempty"`
+	CPU      interface{} `json:"cpu,omitempty"`
+	Memory   interface{} `json:"memory,omitempty"`
+	Bytes    interface{} `json:"bytes,omitempty"`
+	ErrorPct interface{} `json:"error_pct,omitempty"`
 }
 }
 
 
 type promParsedSingletonQuery struct {
 type promParsedSingletonQuery struct {
@@ -137,6 +172,8 @@ func parseQuery(rawQuery []byte, metric string) ([]byte, error) {
 				singletonResult.Memory = values[1]
 				singletonResult.Memory = values[1]
 			} else if metric == "network" {
 			} else if metric == "network" {
 				singletonResult.Bytes = values[1]
 				singletonResult.Bytes = values[1]
+			} else if metric == "nginx:errors" {
+				singletonResult.ErrorPct = values[1]
 			}
 			}
 
 
 			singletonResults = append(singletonResults, *singletonResult)
 			singletonResults = append(singletonResults, *singletonResult)

+ 49 - 0
server/api/k8s_handler.go

@@ -371,6 +371,55 @@ func (app *App) HandleDetectPrometheusInstalled(w http.ResponseWriter, r *http.R
 	return
 	return
 }
 }
 
 
+// HandleListNGINXIngresses lists all NGINX ingresses in a target cluster
+func (app *App) HandleListNGINXIngresses(w http.ResponseWriter, r *http.Request) {
+	vals, err := url.ParseQuery(r.URL.RawQuery)
+
+	if err != nil {
+		app.handleErrorFormDecoding(err, ErrReleaseDecode, w)
+		return
+	}
+
+	// get the filter options
+	form := &forms.K8sForm{
+		OutOfClusterConfig: &kubernetes.OutOfClusterConfig{
+			Repo:              app.Repo,
+			DigitalOceanOAuth: app.DOConf,
+		},
+	}
+
+	form.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
+
+	// validate the form
+	if err := app.validator.Struct(form); err != nil {
+		app.handleErrorFormValidation(err, ErrK8sValidate, w)
+		return
+	}
+
+	// create a new agent
+	var agent *kubernetes.Agent
+
+	if app.ServerConf.IsTesting {
+		agent = app.TestAgents.K8sAgent
+	} else {
+		agent, err = kubernetes.GetAgentOutOfClusterConfig(form.OutOfClusterConfig)
+	}
+
+	res, err := prometheus.GetIngressesWithNGINXAnnotation(agent.Clientset)
+
+	if err != nil {
+		app.handleErrorInternal(err, w)
+		return
+	}
+
+	w.WriteHeader(http.StatusOK)
+
+	if err := json.NewEncoder(w).Encode(res); err != nil {
+		app.handleErrorFormDecoding(err, ErrK8sDecode, w)
+		return
+	}
+}
+
 func (app *App) HandleGetPodMetrics(w http.ResponseWriter, r *http.Request) {
 func (app *App) HandleGetPodMetrics(w http.ResponseWriter, r *http.Request) {
 	vals, err := url.ParseQuery(r.URL.RawQuery)
 	vals, err := url.ParseQuery(r.URL.RawQuery)
 
 

+ 18 - 0
server/api/oauth_github_handler.go

@@ -17,6 +17,7 @@ import (
 	"golang.org/x/oauth2"
 	"golang.org/x/oauth2"
 
 
 	"github.com/porter-dev/porter/internal/models/integrations"
 	"github.com/porter-dev/porter/internal/models/integrations"
+	segment "gopkg.in/segmentio/analytics-go.v3"
 )
 )
 
 
 // HandleGithubOAuthStartUser starts the oauth2 flow for a user login request.
 // HandleGithubOAuthStartUser starts the oauth2 flow for a user login request.
@@ -129,6 +130,23 @@ func (app *App) HandleGithubOAuthCallback(w http.ResponseWriter, r *http.Request
 			return
 			return
 		}
 		}
 
 
+		// send to segment
+		client := *app.segmentClient
+		client.Enqueue(segment.Identify{
+			UserId: fmt.Sprintf("%v", user.ID),
+			Traits: segment.NewTraits().
+				SetEmail(user.Email).
+				Set("github", "true"),
+		})
+
+		client.Enqueue(segment.Track{
+			UserId: fmt.Sprintf("%v", user.ID),
+			Event: "New User",
+			Properties: segment.NewProperties().
+				Set("email", user.Email),
+		})
+
+
 		// log the user in
 		// log the user in
 		app.Logger.Info().Msgf("New user created: %d", user.ID)
 		app.Logger.Info().Msgf("New user created: %d", user.ID)
 
 

+ 2 - 1
server/api/release_handler.go

@@ -131,6 +131,7 @@ func (app *App) HandleGetRelease(w http.ResponseWriter, r *http.Request) {
 	}
 	}
 
 
 	k8sForm.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
 	k8sForm.PopulateK8sOptionsFromQueryParams(vals, app.Repo.Cluster)
+	k8sForm.DefaultNamespace = form.ReleaseForm.Namespace
 
 
 	// validate the form
 	// validate the form
 	if err := app.validator.Struct(k8sForm); err != nil {
 	if err := app.validator.Struct(k8sForm); err != nil {
@@ -637,7 +638,7 @@ func (app *App) HandleReleaseDeployWebhook(w http.ResponseWriter, r *http.Reques
 	client := *app.segmentClient
 	client := *app.segmentClient
 	client.Enqueue(segment.Track{
 	client.Enqueue(segment.Track{
 		UserId: "anonymous",
 		UserId: "anonymous",
-		Event: "Triggered Re-deploy via Webhook",
+		Event:  "Triggered Re-deploy via Webhook",
 		Properties: segment.NewProperties().
 		Properties: segment.NewProperties().
 			Set("repository", repository),
 			Set("repository", repository),
 	})
 	})

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است