ソースを参照

capabilities casing

sunguroku 5 年 前
コミット
57c0923d1a

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

@@ -82,6 +82,27 @@ class Home extends Component<PropsType, StateType> {
       });
   };
 
+  getCapabilities = () => {
+    let { currentProject } = this.props;
+    if (!currentProject) return;
+
+    api
+      .getCapabilities(
+        "<token>",
+        {},
+        {
+          id: currentProject.id
+        }
+      )
+      .then((res) => {
+        console.log(res.data)
+        this.context.setCapabilities(res.data)
+      })
+      .catch((err) => {
+        console.log(err)
+      });
+  }
+
   getProjects = (id?: number) => {
     let { user, setProjects } = this.context;
     let { currentProject } = this.props;
@@ -222,6 +243,7 @@ class Home extends Component<PropsType, StateType> {
     this.setState({ ghRedirect: urlParams.get("gh_oauth") !== null });
     urlParams.delete("gh_oauth");
     this.getProjects(defaultProjectId);
+    this.getCapabilities();
   }
 
   // TODO: Need to handle the following cases. Do a deep rearchitecture (Prov -> Dashboard?) if need be:
@@ -237,6 +259,7 @@ class Home extends Component<PropsType, StateType> {
         this.checkDO();
       } else {
         this.initializeView();
+        this.getCapabilities();
       }
     }
   }

+ 15 - 2
dashboard/src/main/home/dashboard/Dashboard.tsx

@@ -82,7 +82,7 @@ class Dashboard extends Component<PropsType, StateType> {
             <i className="material-icons">info</i>
             Create a cluster to link to this project.
           </Banner>
-          <ProvisionerSettings infras={this.state.infras} />
+          <ProvisionerSettings infras={this.state.infras} provisioner={true} />
         </>
       );
     } else {
@@ -95,8 +95,21 @@ class Dashboard extends Component<PropsType, StateType> {
   };
 
   render() {
-    let { currentProject } = this.context;
+    let { currentProject, capabilities } = this.context;
     let { onShowProjectSettings } = this;
+
+    let tabOptions = [
+      { label: "Project Overview", value: "overview" },
+      { label: "Create a Cluster", value: "create-cluster" },
+      { label: "Provisioner Status", value: "provisioner" },
+    ]
+    
+    if (!capabilities?.provisioner) {
+      tabOptions = [
+        { label: "Project Overview", value: "overview" },
+      ]
+    }
+
     return (
       <>
         {currentProject && (

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

@@ -23,6 +23,7 @@ export default class NewProject extends Component<PropsType, StateType> {
   };
 
   render() {
+    let { capabilities } = this.context;
     let { projectName } = this.state;
     return (
       <StyledNewProject>
@@ -58,7 +59,7 @@ export default class NewProject extends Component<PropsType, StateType> {
             width="470px"
           />
         </InputWrapper>
-        <ProvisionerSettings isInNewProject={true} projectName={projectName} />
+        <ProvisionerSettings isInNewProject={true} projectName={projectName} provisioner={capabilities?.provisioner} />
         <Br />
       </StyledNewProject>
     );

+ 81 - 29
dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

@@ -17,6 +17,7 @@ type PropsType = RouteComponentProps & {
   isInNewProject?: boolean;
   projectName?: string;
   infras?: InfraType[];
+  provisioner?: boolean;
 };
 
 type StateType = {
@@ -42,11 +43,20 @@ class NewProject extends Component<PropsType, StateType> {
     this.props.history.push("dashboard?tab=overview");
   };
 
-  renderSelectedProvider = () => {
+  renderSelectedProvider = (override?: string) => {
     let { selectedProvider } = this.state;
     let { projectName, infras } = this.props;
 
+    if (override) {
+      selectedProvider = override;
+    }
+
     let renderSkipHelper = () => {
+
+      if (!this.props.provisioner) {
+        return;
+      }
+
       return (
         <>
           {selectedProvider === "skipped" ? (
@@ -125,19 +135,80 @@ class NewProject extends Component<PropsType, StateType> {
     }
   };
 
-  render() {
+  renderFooter = () => {
     let { selectedProvider } = this.state;
     let { isInNewProject } = this.props;
+    let { provisioner } = this.props;
+    let helper = provisioner ? "Note: Provisioning can take up to 15 minutes" : ""
+
+    if (isInNewProject && !selectedProvider) {
+      return (
+        <>
+          <Helper>
+            Already have a Kubernetes cluster?
+            <Highlight
+              onClick={() => this.setState({ selectedProvider: "skipped" })}
+            >
+              Skip
+            </Highlight>
+          </Helper>
+          <Br />
+          <SaveButton
+            text="Submit"
+            disabled={true}
+            onClick={() => {}}
+            makeFlush={true}
+            helper={helper}
+          />
+        </>
+      )
+    }
+  }
+
+  componentDidMount() {
+    let { provisioner } = this.props;
+
+    if (!provisioner) {
+      this.setState({selectedProvider: "skipped"})
+    }
+  }
+
+  componentDidUpdate(prevProps: PropsType) {
+    if (
+      prevProps.provisioner !== this.props.provisioner
+    ) {
+      if (!this.props.provisioner) {
+        this.setState({selectedProvider: "skipped"})
+      }
+    }
+  }
+
+  renderHelperText = () => {
+    let { isInNewProject, provisioner } = this.props;
+    if (!provisioner) {
+      return;
+    }
+
+    if (isInNewProject) {
+      return (
+        <>
+          Select your hosting backend:<Required>*</Required>
+        </>
+      )
+    } else {
+      return (
+        "Need a cluster? Provision through Porter:"
+      )
+    }
+  }
+
+  render() {
+    let { selectedProvider } = this.state;
+
     return (
       <StyledProvisionerSettings>
         <Helper>
-          {isInNewProject ? (
-            <>
-              Select your hosting backend:<Required>*</Required>
-            </>
-          ) : (
-            "Need a cluster? Provision through Porter:"
-          )}
+          {this.renderHelperText()}
         </Helper>
         {!selectedProvider ? (
           <BlockList>
@@ -160,26 +231,7 @@ class NewProject extends Component<PropsType, StateType> {
         ) : (
           <>{this.renderSelectedProvider()}</>
         )}
-        {isInNewProject && !selectedProvider && (
-          <>
-            <Helper>
-              Already have a Kubernetes cluster?
-              <Highlight
-                onClick={() => this.setState({ selectedProvider: "skipped" })}
-              >
-                Skip
-              </Highlight>
-            </Helper>
-            <Br />
-            <SaveButton
-              text="Submit"
-              disabled={true}
-              onClick={() => {}}
-              makeFlush={true}
-              helper="Note: Provisioning can take up to 15 minutes"
-            />
-          </>
-        )}
+        {this.renderFooter()}
       </StyledProvisionerSettings>
     );
   }

+ 5 - 1
dashboard/src/shared/Context.tsx

@@ -1,6 +1,6 @@
 import React, { Component } from "react";
 
-import { ProjectType, ClusterType } from "shared/types";
+import { ProjectType, ClusterType, CapabilityType } from "shared/types";
 
 const Context = React.createContext({});
 
@@ -63,6 +63,10 @@ class ContextProvider extends Component {
     setDevOpsMode: (devOpsMode: boolean) => {
       this.setState({ devOpsMode });
     },
+    capabilities: null as CapabilityType,
+    setCapabilities: (capabilities: CapabilityType) => {
+      this.setState({ capabilities })
+    },
     clearContext: () => {
       this.setState({
         currentModal: null,

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

@@ -629,6 +629,10 @@ const getUser = baseApi<{}, { id: number }>("GET", (pathParams) => {
   return `/api/users/${pathParams.id}`;
 });
 
+const getCapabilities = baseApi<{}, { id: number }>("GET", (pathParams) => {
+  return `/api/projects/${pathParams.id}/capabilities`;
+});
+
 const linkGithubProject = baseApi<
   {},
   {
@@ -818,6 +822,7 @@ export default {
   destroyDOKS,
   getBranchContents,
   getBranches,
+  getCapabilities,
   getChart,
   getCharts,
   getChartComponents,

+ 5 - 0
dashboard/src/shared/types.tsx

@@ -167,3 +167,8 @@ export interface ActionConfigType {
   image_repo_uri: string;
   git_repo_id: number;
 }
+
+export interface CapabilityType {
+  github: boolean;
+  provisioner: boolean;
+}

+ 6 - 0
internal/config/config.go

@@ -14,6 +14,7 @@ type Conf struct {
 	Db     DBConf
 	K8s    K8sConf
 	Redis  RedisConf
+	Capabilities CapConf
 }
 
 // ServerConf is the server configuration
@@ -70,6 +71,11 @@ type K8sConf struct {
 	IsTesting bool `env:"K8S_IS_TESTING,default=false"`
 }
 
+type CapConf struct {
+	Provisioner bool `env:"PROVISIONER_ENABLED,default=true"`
+	Github bool `env:"GITHUB_ENABLED,default=true"`
+}
+
 // FromEnv generates a configuration from environment variables
 func FromEnv() *Conf {
 	var c Conf

+ 5 - 0
server/api/api.go

@@ -42,6 +42,7 @@ type AppConfig struct {
 	ServerConf config.ServerConf
 	RedisConf  *config.RedisConf
 	DBConf     config.DBConf
+	CapConf config.CapConf
 
 	// TestAgents if API is in testing mode
 	TestAgents *TestAgents
@@ -71,6 +72,9 @@ type App struct {
 	// config for db
 	DBConf config.DBConf
 
+	// config for capabilities
+	CapConf config.CapConf
+
 	// oauth-specific clients
 	GithubUserConf    *oauth2.Config
 	GithubProjectConf *oauth2.Config
@@ -102,6 +106,7 @@ func New(conf *AppConfig) (*App, error) {
 		ServerConf: conf.ServerConf,
 		RedisConf:  conf.RedisConf,
 		DBConf:     conf.DBConf,
+		CapConf: 	conf.CapConf,
 		TestAgents: conf.TestAgents,
 		db:         conf.DB,
 		validator:  validator,

+ 29 - 0
server/api/capability_handler.go

@@ -0,0 +1,29 @@
+package api
+
+import (
+	"fmt"
+	"encoding/json"
+	"net/http"
+)
+
+// CapabilitiesExternal represents the Capabilities struct that will be sent over REST
+type CapabilitiesExternal struct {
+	Provisioner bool `json:"provisioner"`
+	GitHub bool	`json:"github"`
+}
+
+// HandleGetCapabilities gets the capabilities of the server
+func (app *App) HandleGetCapabilities(w http.ResponseWriter, r *http.Request) {
+
+	cap := app.CapConf
+	fmt.Println(app.CapConf)
+	capExternal := &CapabilitiesExternal{
+		Provisioner: cap.Provisioner,
+		GitHub: cap.Github,
+	}
+
+	if err := json.NewEncoder(w).Encode(capExternal); err != nil {
+		app.handleErrorFormDecoding(err, ErrK8sDecode, w)
+		return
+	}
+}

+ 11 - 0
server/router/router.go

@@ -1352,6 +1352,17 @@ func New(a *api.App) *chi.Mux {
 				mw.ReadAccess,
 			),
 		)
+
+		// capabilities
+		r.Method(
+			"GET",
+			"/projects/{project_id}/capabilities",
+			auth.DoesUserHaveProjectAccess(
+				requestlog.NewHandler(a.HandleGetCapabilities, l),
+				mw.URLParam,
+				mw.ReadAccess,
+			),
+		)
 	})
 
 	staticFilePath := a.ServerConf.StaticFilePath