Просмотр исходного кода

final touches on styles and connected to api

jnfrati 4 лет назад
Родитель
Сommit
b86cf37dd8

+ 42 - 16
dashboard/src/components/SaveButton.tsx

@@ -13,6 +13,7 @@ type PropsType = {
   // Makes flush with corner if not within a modal
   makeFlush?: boolean;
   clearPosition?: boolean;
+  statusPosition?: "right" | "left";
 };
 
 type StateType = {};
@@ -22,28 +23,37 @@ export default class SaveButton extends Component<PropsType, StateType> {
     if (this.props.status) {
       if (this.props.status === "successful") {
         return (
-          <StatusWrapper successful={true}>
+          <StatusWrapper position={this.props.statusPosition} successful={true}>
             <i className="material-icons">done</i>
             <StatusTextWrapper>Successfully updated</StatusTextWrapper>
           </StatusWrapper>
         );
       } else if (this.props.status === "loading") {
         return (
-          <StatusWrapper successful={false}>
+          <StatusWrapper
+            position={this.props.statusPosition}
+            successful={false}
+          >
             <LoadingGif src={loading} />
             <StatusTextWrapper>Updating . . .</StatusTextWrapper>
           </StatusWrapper>
         );
       } else if (this.props.status === "error") {
         return (
-          <StatusWrapper successful={false}>
+          <StatusWrapper
+            position={this.props.statusPosition}
+            successful={false}
+          >
             <i className="material-icons">error_outline</i>
             <StatusTextWrapper>Could not update</StatusTextWrapper>
           </StatusWrapper>
         );
       } else {
         return (
-          <StatusWrapper successful={false}>
+          <StatusWrapper
+            position={this.props.statusPosition}
+            successful={false}
+          >
             <i className="material-icons">error_outline</i>
             <StatusTextWrapper>{this.props.status}</StatusTextWrapper>
           </StatusWrapper>
@@ -51,7 +61,9 @@ export default class SaveButton extends Component<PropsType, StateType> {
       }
     } else if (this.props.helper) {
       return (
-        <StatusWrapper successful={true}>{this.props.helper}</StatusWrapper>
+        <StatusWrapper position={this.props.statusPosition} successful={true}>
+          {this.props.helper}
+        </StatusWrapper>
       );
     }
   };
@@ -62,7 +74,9 @@ export default class SaveButton extends Component<PropsType, StateType> {
         makeFlush={this.props.makeFlush}
         clearPosition={this.props.clearPosition}
       >
-        <div>{this.renderStatus()}</div>
+        {this.props.statusPosition !== "right" && (
+          <div>{this.renderStatus()}</div>
+        )}
         <Button
           disabled={this.props.disabled}
           onClick={this.props.onClick}
@@ -70,6 +84,9 @@ export default class SaveButton extends Component<PropsType, StateType> {
         >
           {this.props.text}
         </Button>
+        {this.props.statusPosition === "right" && (
+          <div>{this.renderStatus()}</div>
+        )}
       </ButtonWrapper>
     );
   }
@@ -91,13 +108,21 @@ const StatusTextWrapper = styled.p`
   margin: 0;
 `;
 
-const StatusWrapper = styled.div`
+const StatusWrapper = styled.div<{
+  successful: boolean;
+  position: "right" | "left";
+}>`
   display: flex;
   align-items: center;
   font-family: "Work Sans", sans-serif;
   font-size: 13px;
   color: #ffffff55;
-  margin-right: 25px;
+  ${(props) => {
+    if (props.position !== "right") {
+      return "margin-right: 25px;";
+    }
+    return "margin-left: 25px;";
+  }}
   max-width: 500px;
   overflow: hidden;
   text-overflow: ellipsis;
@@ -106,8 +131,7 @@ const StatusWrapper = styled.div`
     font-size: 18px;
     margin-right: 10px;
     float: left;
-    color: ${(props: { successful: boolean }) =>
-      props.successful ? "#4797ff" : "#fcba03"};
+    color: ${(props) => (props.successful ? "#4797ff" : "#fcba03")};
   }
 
   animation: statusFloatIn 0.5s;
@@ -127,20 +151,20 @@ const StatusWrapper = styled.div`
 
 const ButtonWrapper = styled.div`
   ${(props: { makeFlush: boolean; clearPosition?: boolean }) => {
-    if (props.clearPosition) {
-      return "";
-    }
-
     const baseStyles = `
       display: flex;
       align-items: center;
-      position: absolute;
-      justify-content: flex-end;
     `;
 
+    if (props.clearPosition) {
+      return baseStyles;
+    }
+
     if (!props.makeFlush) {
       return `
         ${baseStyles}
+        position: absolute;
+        justify-content: flex-end;
         bottom: 25px;
         right: 27px;
         left: 27px;
@@ -148,6 +172,8 @@ const ButtonWrapper = styled.div`
     }
     return `
       ${baseStyles}
+      position: absolute;
+      justify-content: flex-end;
       bottom: 5px;
       right: 0;
     `;

+ 49 - 0
dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx

@@ -40,6 +40,11 @@ const SettingsSection: React.FC<PropsType> = ({
     false
   );
   const [webhookToken, setWebhookToken] = useState<string>("");
+  const [
+    createWebhookButtonStatus,
+    setCreateWebhookButtonStatus,
+  ] = useState<string>("");
+
   const [action, setAction] = useState<ActionConfigType>({
     git_repo: "",
     image_repo_uri: "",
@@ -134,6 +139,41 @@ const SettingsSection: React.FC<PropsType> = ({
     }
   };
 
+  const handleCreateWebhookToken = async () => {
+    setCreateWebhookButtonStatus("loading");
+    const { id: cluster_id } = currentCluster;
+    const { id: project_id } = currentProject;
+    const { name: chart_name, namespace } = currentChart;
+    try {
+      const res = await api.createWebhookToken(
+        "<token>",
+        {},
+        {
+          project_id,
+          chart_name,
+          namespace,
+          cluster_id,
+          storage: StorageType.Secret,
+        }
+      );
+      setCreateWebhookButtonStatus("successful");
+      setTimeout(() => {
+        setAction(res.data.git_action_config);
+        setWebhookToken(res.data.webhook_token);
+      }, 500);
+    } catch (err) {
+      let parsedErr =
+        err?.response?.data?.errors && err.response.data.errors[0];
+
+      if (parsedErr) {
+        err = parsedErr;
+      }
+
+      setCreateWebhookButtonStatus(parsedErr);
+      setCurrentError(parsedErr);
+    }
+  };
+
   const renderWebhookSection = () => {
     if (!currentChart?.form?.hasSource) {
       return;
@@ -164,6 +204,15 @@ const SettingsSection: React.FC<PropsType> = ({
           <Helper>
             Programmatically deploy by calling this secret webhook.
           </Helper>
+          {!webhookToken.length && (
+            <SaveButton
+              text={"Create Webhook"}
+              status={createWebhookButtonStatus}
+              onClick={handleCreateWebhookToken}
+              clearPosition={true}
+              statusPosition={"right"}
+            />
+          )}
           {webhookToken.length > 0 && (
             <Webhook copiedToClipboard={highlightCopyButton}>
               <div>{curlWebhook}</div>

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

@@ -949,6 +949,21 @@ const getPolicyDocument = baseApi<{}, { project_id: number }>(
   ({ project_id }) => `/api/projects/${project_id}/policy`
 );
 
+const createWebhookToken = baseApi<
+  {},
+  {
+    project_id: number;
+    chart_name: string;
+    namespace: string;
+    cluster_id: number;
+    storage: StorageType;
+  }
+>(
+  "POST",
+  ({ project_id, chart_name, namespace, cluster_id, storage }) =>
+    `/api/projects/${project_id}/releases/${chart_name}/webhook_token?namespace=${namespace}&cluster_id=${cluster_id}&storage=${storage}`
+);
+
 // Bundle export to allow default api import (api.<method> is more readable)
 export default {
   checkAuth,
@@ -1047,4 +1062,5 @@ export default {
   updateCollaborator,
   removeCollaborator,
   getPolicyDocument,
+  createWebhookToken,
 };