Sean Rhee 5 лет назад
Родитель
Сommit
1068d64be3

+ 1 - 0
.gitignore

@@ -9,6 +9,7 @@ gon.hcl
 internal/local_templates
 internal/local_templates
 gon*.hcl
 gon*.hcl
 *prod.Dockerfile
 *prod.Dockerfile
+staging.sh
 
 
 # Local .terraform directories
 # Local .terraform directories
 **/.terraform/*
 **/.terraform/*

+ 7 - 3
README.md

@@ -19,9 +19,9 @@ Porter brings the simplicity of a traditional PaaS to your own cloud provider wh
 ## Features
 ## Features
 ### Basics
 ### Basics
 - One-click provisioning of a Kubernetes cluster in your own cloud console
 - One-click provisioning of a Kubernetes cluster in your own cloud console
-  - AWS
-  - GCP
-  - Digital Ocean
+  - AWS
+  - GCP
+  - Digital Ocean
   
   
 - Simple deploy of any public or private Docker image
 - Simple deploy of any public or private Docker image
 
 
@@ -74,6 +74,10 @@ For Linux and Windows installation, see our [Docs](https://docs.getporter.dev/do
 4. [Build and push your Docker image to the provisioned registry with the CLI](https://docs.getporter.dev/docs/cli-documentation#porter-docker-configure).
 4. [Build and push your Docker image to the provisioned registry with the CLI](https://docs.getporter.dev/docs/cli-documentation#porter-docker-configure).
 
 
 5. From the Templates tab on the Dashboard, select the Docker template. Click on the image you have just pushed, configure the port, then hit deploy.
 5. From the Templates tab on the Dashboard, select the Docker template. Click on the image you have just pushed, configure the port, then hit deploy.
+
+## Keep Updated
+We are iterating fast and will be regularly announcing new releases in this repository. If you'd like to follow our progress, please watch the repo for releases (**Watch > Custom > Releases**) and leave us a star!
+
 ## Want Help?
 ## Want Help?
 We are always hanging out in our [Discord community](https://discord.gg/MhYNuWwqum). Join us there if you need help or have any questions!
 We are always hanging out in our [Discord community](https://discord.gg/MhYNuWwqum). Join us there if you need help or have any questions!
 
 

+ 30 - 28
dashboard/src/main/home/Home.tsx

@@ -23,6 +23,7 @@ import ProvisionerStatus from './provisioner/ProvisionerStatus';
 import ProjectSettings from './project-settings/ProjectSettings';
 import ProjectSettings from './project-settings/ProjectSettings';
 import ConfirmOverlay from '../../components/ConfirmOverlay';
 import ConfirmOverlay from '../../components/ConfirmOverlay';
 import Modal from './modals/Modal';
 import Modal from './modals/Modal';
+import * as FullStory from '@fullstory/browser';
 
 
 type PropsType = {
 type PropsType = {
   logOut: () => void,
   logOut: () => void,
@@ -59,28 +60,27 @@ export default class Home extends Component<PropsType, StateType> {
   // TODO: Refactor and prevent flash + multiple reload
   // TODO: Refactor and prevent flash + multiple reload
   initializeView = () => {
   initializeView = () => {
     let { currentProject } = this.props;
     let { currentProject } = this.props;
-    if (currentProject) {
-      let { currentCluster } = this.context;
-      
-      // Check if current project is provisioning
-      api.getInfra('<token>', {}, { project_id: currentProject.id }, (err: any, res: any) => {
-        if (err) {
-          console.log(err);
-          return;
-        }
-        
-        if (res.data.length > 0 && (!currentCluster || !includesCompletedInfraSet(res.data))) {
+    let { currentCluster } = this.context;
+    
+    if (!currentProject) return;
+
+    // Check if current project is provisioning
+    api.getInfra('<token>', {}, { project_id: currentProject.id }, (err: any, res: any) => {
+      if (err) {
+        console.log(err);
+        return;
+      }
+
+      if (res.data.length > 0 && (!currentCluster && !includesCompletedInfraSet(res.data))) {
+        // force refresh if currentView is already set to provisioner.
+        this.setState({ currentView: 'dashboard'}, () => {
           this.setState({ currentView: 'provisioner', sidebarReady: true, });
           this.setState({ currentView: 'provisioner', sidebarReady: true, });
-        } else {
-          // console.log('getting here', currentCluster)
-          if (this.state.ghRedirect) {
-            this.setState({ currentView: 'integrations', sidebarReady: true, ghRedirect: false });
-          } else {
-            this.setState({ currentView: 'dashboard', sidebarReady: true });
-          }
-        }
-      });
-    }
+        });
+      } else {
+        // console.log('getting here', currentCluster)
+        this.setState({ currentView: 'dashboard', sidebarReady: true });
+      }
+    });
   }
   }
 
 
   getProjects = (id?: number) => {
   getProjects = (id?: number) => {
@@ -189,6 +189,8 @@ export default class Home extends Component<PropsType, StateType> {
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
+    let { user } = this.context;
+    FullStory.identify(user.email)
 
 
     // Handle redirect from DO
     // Handle redirect from DO
     let queryString = window.location.search;
     let queryString = window.location.search;
@@ -207,13 +209,13 @@ export default class Home extends Component<PropsType, StateType> {
       this.checkDO();
       this.checkDO();
     }
     }
 
 
-    this.setState({ ghRedirect: urlParams.get('gh_oauth') !== null });
-    urlParams.delete('gh_oauth');
-    
-    let { user } = this.context;
-    window.location.href.indexOf('127.0.0.1') === -1 && posthog.init(process.env.POSTHOG_API_KEY, {
-      api_host: process.env.POSTHOG_HOST,
-      loaded: function(posthog: any) { posthog.identify(user.email) }
+    // initialize posthog on non-localhosts. Gracefully fail when env vars are not set.
+    window.location.href.indexOf('127.0.0.1') === -1 && posthog.init(process.env.POSTHOG_API_KEY || 'placeholder', {
+      api_host: process.env.POSTHOG_HOST || 'placeholder',
+      loaded: function(posthog: any) { 
+        posthog.identify(user.userId) 
+        posthog.people.set({ email: user.email })
+      }
     })
     })
 
 
     this.getProjects(defaultProjectId);
     this.getProjects(defaultProjectId);

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

@@ -32,7 +32,7 @@ type StateType = {
 
 
 const provisionOptions = [
 const provisionOptions = [
   { value: 'gcr', label: 'Google Container Registry (GCR)' },
   { value: 'gcr', label: 'Google Container Registry (GCR)' },
-  { value: 'gke', label: 'Googke Kubernetes Engine (GKE)' },
+  { value: 'gke', label: 'Google Kubernetes Engine (GKE)' },
 ];
 ];
 
 
 const regionOptions = [
 const regionOptions = [

+ 6 - 3
dashboard/src/main/home/provisioner/ProvisionerStatus.tsx

@@ -1,5 +1,6 @@
 import React, { Component } from 'react';
 import React, { Component } from 'react';
 import styled from 'styled-components';
 import styled from 'styled-components';
+import posthog from 'posthog-js';
 
 
 import api from '../../../shared/api';
 import api from '../../../shared/api';
 import { Context } from '../../../shared/Context';
 import { Context } from '../../../shared/Context';
@@ -56,8 +57,8 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
   }
   }
 
 
   componentDidMount() {
   componentDidMount() {
+    console.log('mounting provisioner')
     let { currentProject } = this.context;
     let { currentProject } = this.context;
-    // console.log(currentProject)
     let protocol = process.env.NODE_ENV == 'production' ? 'wss' : 'ws'
     let protocol = process.env.NODE_ENV == 'production' ? 'wss' : 'ws'
 
 
     // Check if current project is provisioning
     // Check if current project is provisioning
@@ -69,7 +70,7 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
       } 
       } 
       
       
       let infras = filterOldInfras(res.data);
       let infras = filterOldInfras(res.data);
-      // console.log('filtered infras: ', infras);
+      console.log('infras: ', res.data);
       let error = false;
       let error = false;
 
 
       let maxStep = {} as Record<string, number>
       let maxStep = {} as Record<string, number>
@@ -117,7 +118,6 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
       let event = JSON.parse(evt.data);
       let event = JSON.parse(evt.data);
       let validEvents = [] as any[];
       let validEvents = [] as any[];
       let err = null;
       let err = null;
-
       
       
       for (var i = 0; i < event.length; i++) {
       for (var i = 0; i < event.length; i++) {
         let msg = event[i];
         let msg = event[i];
@@ -137,6 +137,8 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
       }
       }
 
 
       if (err) {
       if (err) {
+        posthog.capture('Provisioning Error', {error: err});
+
         let e = ansiparse(err).map((el: any) => {
         let e = ansiparse(err).map((el: any) => {
           return el.text;
           return el.text;
         })
         })
@@ -270,6 +272,7 @@ export default class ProvisionerStatus extends Component<PropsType, StateType> {
     }
     }
 
 
     if (maxStep !== 0 && currentStep === maxStep && !triggerEnd) {
     if (maxStep !== 0 && currentStep === maxStep && !triggerEnd) {
+      posthog.capture('Provisioning complete!')
       this.onEnd()
       this.onEnd()
       this.setState({ triggerEnd: true });
       this.setState({ triggerEnd: true });
     }
     }

+ 12 - 0
dashboard/src/main/home/templates/expanded-template/LaunchTemplate.tsx

@@ -1,6 +1,7 @@
 import React, { Component } from 'react';
 import React, { Component } from 'react';
 import styled from 'styled-components';
 import styled from 'styled-components';
 import randomWords from 'random-words';
 import randomWords from 'random-words';
+import posthog from 'posthog-js';
 import _ from 'lodash';
 import _ from 'lodash';
 import { Context } from '../../../../shared/Context';
 import { Context } from '../../../../shared/Context';
 import api from '../../../../shared/api';
 import api from '../../../../shared/api';
@@ -125,9 +126,20 @@ export default class LaunchTemplate extends Component<PropsType, StateType> {
     }, (err: any, res: any) => {
     }, (err: any, res: any) => {
       if (err) {
       if (err) {
         this.setState({ saveValuesStatus: 'error' });
         this.setState({ saveValuesStatus: 'error' });
+        posthog.capture('Failed to deploy template', {
+          name: this.props.currentTemplate.name,
+          namespace: this.state.selectedNamespace,
+          values: values,
+          error: err
+        })
       } else {
       } else {
         // this.props.setCurrentView('cluster-dashboard');
         // this.props.setCurrentView('cluster-dashboard');
         this.setState({ saveValuesStatus: 'successful' });
         this.setState({ saveValuesStatus: 'successful' });
+        posthog.capture('Deployed template', {
+          name: this.props.currentTemplate.name,
+          namespace: this.state.selectedNamespace,
+          values: values,
+        })
       }
       }
     });
     });
   }
   }

+ 0 - 1
internal/forms/release.go

@@ -20,7 +20,6 @@ func (rf *ReleaseForm) PopulateHelmOptionsFromQueryParams(
 	vals url.Values,
 	vals url.Values,
 	repo repository.ClusterRepository,
 	repo repository.ClusterRepository,
 ) error {
 ) error {
-	fmt.Println(vals)
 	if clusterID, ok := vals["cluster_id"]; ok && len(clusterID) == 1 {
 	if clusterID, ok := vals["cluster_id"]; ok && len(clusterID) == 1 {
 		id, err := strconv.ParseUint(clusterID[0], 10, 64)
 		id, err := strconv.ParseUint(clusterID[0], 10, 64)