Browse Source

Merge pull request #2481 from porter-dev/release-edit

handle release name
Porter Support 3 years ago
parent
commit
7bb269b8e0
37 changed files with 334 additions and 46 deletions
  1. BIN
      dashboard/src/assets/azure.png
  2. 0 1
      dashboard/src/components/Button.tsx
  3. 0 2
      dashboard/src/components/MultiSaveButton.tsx
  4. 0 2
      dashboard/src/components/ProvisionerStatus.tsx
  5. 0 2
      dashboard/src/components/SaveButton.tsx
  6. 0 1
      dashboard/src/components/repo-selector/ContentsList.tsx
  7. 0 1
      dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx
  8. 1 1
      dashboard/src/main/home/cluster-dashboard/SortSelector.tsx
  9. 0 2
      dashboard/src/main/home/cluster-dashboard/dashboard/ClusterSettings.tsx
  10. 0 1
      dashboard/src/main/home/cluster-dashboard/dashboard/NamespaceList.tsx
  11. 0 1
      dashboard/src/main/home/cluster-dashboard/dashboard/events/EventsTab.tsx
  12. 0 1
      dashboard/src/main/home/cluster-dashboard/dashboard/incidents/IncidentsTab.tsx
  13. 0 2
      dashboard/src/main/home/cluster-dashboard/databases/DatabasesList.tsx
  14. 0 1
      dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroupDashboard.tsx
  15. 0 2
      dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx
  16. 0 2
      dashboard/src/main/home/cluster-dashboard/expanded-chart/SettingsSection.tsx
  17. 0 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx
  18. 0 1
      dashboard/src/main/home/cluster-dashboard/expanded-chart/incidents/IncidentsTab.tsx
  19. 0 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/components/ButtonEnablePREnvironments.tsx
  20. 0 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/components/RecreateWorkflowFilesModal.tsx
  21. 0 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentCard.tsx
  22. 0 1
      dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentsList.tsx
  23. 1 2
      dashboard/src/main/home/cluster-dashboard/stacks/Dashboard.tsx
  24. 0 2
      dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/components/Settings.tsx
  25. 0 1
      dashboard/src/main/home/cluster-dashboard/stacks/components/styles.ts
  26. 0 1
      dashboard/src/main/home/integrations/IntegrationCategories.tsx
  27. 0 1
      dashboard/src/main/home/integrations/IntegrationList.tsx
  28. 0 1
      dashboard/src/main/home/launch/expanded-template/TemplateInfo.tsx
  29. 0 1
      dashboard/src/main/home/modals/RedirectToOnboardingModal.tsx
  30. 0 1
      dashboard/src/main/home/modals/UsageWarningModal.tsx
  31. 0 1
      dashboard/src/main/home/onboarding/steps/ConnectRegistry/forms/_DORegistryForm.tsx
  32. 0 1
      dashboard/src/main/home/onboarding/steps/ConnectSource.tsx
  33. 0 2
      dashboard/src/main/home/project-settings/APITokensSection.tsx
  34. 0 2
      dashboard/src/main/home/project-settings/InviteList.tsx
  35. 0 1
      dashboard/src/main/home/project-settings/ProjectSettings.tsx
  36. 296 0
      dashboard/src/main/home/provisioner/AzureFormSection.tsx
  37. 36 1
      dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

BIN
dashboard/src/assets/azure.png


+ 0 - 1
dashboard/src/components/Button.tsx

@@ -37,7 +37,6 @@ const ButtonWrapper = styled.div`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 2
dashboard/src/components/MultiSaveButton.tsx

@@ -258,8 +258,6 @@ const Button = styled.button<ButtonProps>`
   border: 0;
   border-radius: ${(props) => (props.rounded ? "100px" : "5px 0 0 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")};
   user-select: none;
   :focus {

+ 0 - 2
dashboard/src/components/ProvisionerStatus.tsx

@@ -951,8 +951,6 @@ const Button = styled.button`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 2
dashboard/src/components/SaveButton.tsx

@@ -195,8 +195,6 @@ const Button = styled.button<{
   border: 0;
   border-radius: ${(props) => (props.rounded ? "100px" : "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")};
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/components/repo-selector/ContentsList.tsx

@@ -689,7 +689,6 @@ const UseButton = styled.div`
   font-weight: 500;
   padding: 10px 15px;
   border-radius: 100px;
-  box-shadow: 0 2px 5px 0 #00000030;
   cursor: pointer;
   :hover {
     filter: brightness(120%);

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/ClusterDashboard.tsx

@@ -419,7 +419,6 @@ const Button = styled.div`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

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

@@ -53,7 +53,7 @@ export default class SortSelector extends Component<PropsType, StateType> {
           options={this.getSortOptions()}
           name="Sort"
           icon={sort}
-          dropdownAlignRight={true}
+          dropdownAlignRight={false}
           noMargin
         />
       </StyledSortSelector>

+ 0 - 2
dashboard/src/main/home/cluster-dashboard/dashboard/ClusterSettings.tsx

@@ -241,8 +241,6 @@ const Button = styled.button`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/dashboard/NamespaceList.tsx

@@ -258,7 +258,6 @@ const Button = styled.div`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/dashboard/events/EventsTab.tsx

@@ -164,7 +164,6 @@ const InstallPorterAgentButton = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
   background: ${(props: { disabled?: boolean }) =>

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/dashboard/incidents/IncidentsTab.tsx

@@ -153,7 +153,6 @@ const InstallPorterAgentButton = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
   background: ${(props: { disabled?: boolean }) =>

+ 0 - 2
dashboard/src/main/home/cluster-dashboard/databases/DatabasesList.tsx

@@ -316,7 +316,6 @@ const Button = styled(Link)`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 
@@ -354,7 +353,6 @@ const ConnectButton = styled.button<{}>`
   border: 0;
   border-radius: 5px;
   background: #5561c0;
-  box-shadow: 0 2px 5px 0 #00000030;
   cursor: pointer;
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/env-groups/EnvGroupDashboard.tsx

@@ -192,7 +192,6 @@ const Button = styled.div`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 2
dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx

@@ -871,8 +871,6 @@ const Button = styled.button`
   border: 0;
   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")};
   user-select: none;
   :focus {

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

@@ -355,8 +355,6 @@ const Button = styled.button`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/events/EventsTab.tsx

@@ -245,7 +245,6 @@ const InstallPorterAgentButton = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
   background: ${(props: { disabled?: boolean }) =>

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/expanded-chart/incidents/IncidentsTab.tsx

@@ -155,7 +155,6 @@ const InstallPorterAgentButton = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
   background: ${(props: { disabled?: boolean }) =>

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/components/ButtonEnablePREnvironments.tsx

@@ -134,7 +134,6 @@ const Button = styled(DynamicLink)`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/components/RecreateWorkflowFilesModal.tsx

@@ -62,7 +62,6 @@ const Button = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: pointer;
   border: none;
   :not(:last-child) {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentCard.tsx

@@ -250,7 +250,6 @@ const Button = styled.button`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: pointer;
   border: none;
   :not(:last-child) {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/preview-environments/environments/EnvironmentsList.tsx

@@ -179,7 +179,6 @@ const Button = styled(DynamicLink)`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 1 - 2
dashboard/src/main/home/cluster-dashboard/stacks/Dashboard.tsx

@@ -50,7 +50,7 @@ const Dashboard = () => {
           <RadioFilter
             selected={currentSort}
             noMargin
-            dropdownAlignRight={true}
+            dropdownAlignRight={false}
             setSelected={(sortType: any) => setCurrentSort(sortType as any)}
             options={[
               {
@@ -105,7 +105,6 @@ const Button = styled(DynamicLink)`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 2
dashboard/src/main/home/cluster-dashboard/stacks/ExpandedStack/components/Settings.tsx

@@ -128,8 +128,6 @@ const Button = styled.button`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/cluster-dashboard/stacks/components/styles.ts

@@ -157,7 +157,6 @@ export const Action = {
     overflow: hidden;
     white-space: nowrap;
     text-overflow: ellipsis;
-    box-shadow: 0 5px 8px 0px #00000010;
     cursor: ${(props: { disabled?: boolean }) =>
       props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 1
dashboard/src/main/home/integrations/IntegrationCategories.tsx

@@ -240,7 +240,6 @@ const Button = styled.div`
   padding-right: 12px;
   border-radius: 5px;
   cursor: pointer;
-  box-shadow: 0 5px 8px 0px #00000010;
   display: flex;
   flex-direction: row;
   align-items: center;

+ 0 - 1
dashboard/src/main/home/integrations/IntegrationList.tsx

@@ -302,7 +302,6 @@ const Button = styled.div`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

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

@@ -283,7 +283,6 @@ const Button = styled.div`
   border-radius: 3px;
   cursor: ${(props: { isDisabled: boolean }) =>
     !props.isDisabled ? "pointer" : "default"};
-  box-shadow: 0 5px 8px 0px #00000010;
   display: flex;
   flex-direction: row;
   align-items: center;

+ 0 - 1
dashboard/src/main/home/modals/RedirectToOnboardingModal.tsx

@@ -46,7 +46,6 @@ const ContinueButton = styled.a`
   width: 160px;
   border-radius: 5px;
   background: #616feecc;
-  box-shadow: 0 2px 5px 0 #00000030;
   cursor: pointer;
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/modals/UsageWarningModal.tsx

@@ -167,7 +167,6 @@ const Button = styled.button`
   padding: 10px 15px;
   border-radius: 3px;
   cursor: "pointer";
-  box-shadow: 0 5px 8px 0px #00000010;
   display: flex;
   flex-direction: row;
   align-items: center;

+ 0 - 1
dashboard/src/main/home/onboarding/steps/ConnectRegistry/forms/_DORegistryForm.tsx

@@ -290,7 +290,6 @@ const ConnectDigitalOceanButton = styled.a`
   overflow: hidden;
   white-space: nowrap;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 1
dashboard/src/main/home/onboarding/steps/ConnectSource.tsx

@@ -283,7 +283,6 @@ const ConnectToGithubButton = styled.a`
   margin-top: 25px;
   margin-bottom: 25px;
   text-overflow: ellipsis;
-  box-shadow: 0 5px 8px 0px #00000010;
   cursor: ${(props: { disabled?: boolean }) =>
     props.disabled ? "not-allowed" : "pointer"};
 

+ 0 - 2
dashboard/src/main/home/project-settings/APITokensSection.tsx

@@ -231,8 +231,6 @@ const InviteButton = styled.div<{ disabled: boolean }>`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 2
dashboard/src/main/home/project-settings/InviteList.tsx

@@ -579,8 +579,6 @@ const InviteButton = styled.div<{ disabled: boolean }>`
   border: 0;
   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")};
   user-select: none;
   :focus {

+ 0 - 1
dashboard/src/main/home/project-settings/ProjectSettings.tsx

@@ -232,7 +232,6 @@ const DeleteButton = styled.div`
   margin-left: 0;
   justify-content: center;
   border-radius: 5px;
-  box-shadow: 0 2px 5px 0 #00000030;
   cursor: pointer;
   user-select: none;
   :focus {

+ 296 - 0
dashboard/src/main/home/provisioner/AzureFormSection.tsx

@@ -0,0 +1,296 @@
+import React, { Component, useContext, useEffect, useState } from "react";
+import styled from "styled-components";
+
+import close from "assets/close.png";
+import { isAlphanumeric } from "shared/common";
+import api from "shared/api";
+import { Context } from "shared/Context";
+import { InfraType } from "shared/types";
+
+import InputRow from "components/form-components/InputRow";
+import CheckboxRow from "components/form-components/CheckboxRow";
+import SelectRow from "components/form-components/SelectRow";
+import Helper from "components/form-components/Helper";
+import Heading from "components/form-components/Heading";
+import SaveButton from "components/SaveButton";
+import CheckboxList from "components/form-components/CheckboxList";
+
+type PropsType = {
+  setSelectedProvisioner: (x: string | null) => void;
+  handleError: () => void;
+  projectName: string;
+  highlightCosts?: boolean;
+  infras: InfraType[];
+  trackOnSave: () => void;
+};
+
+const provisionOptions = [
+  { value: "docr", label: "DigitalOcean Container Registry" },
+  { value: "doks", label: "DigitalOcean Kubernetes Service" },
+];
+
+const tierOptions = [
+  { value: "basic", label: "Basic" },
+  { value: "professional", label: "Professional" },
+];
+
+const regionOptions = [
+  { value: "ams3", label: "Amsterdam 3" },
+  { value: "blr1", label: "Bangalore 1" },
+  { value: "fra1", label: "Frankfurt 1" },
+  { value: "lon1", label: "London 1" },
+  { value: "nyc1", label: "New York 1" },
+  { value: "nyc3", label: "New York 3" },
+  { value: "sfo2", label: "San Francisco 2" },
+  { value: "sfo3", label: "San Francisco 3" },
+  { value: "sgp1", label: "Singapore 1" },
+  { value: "tor1", label: "Toronto 1" },
+];
+
+const AzureFormSectionFC: React.FC<PropsType> = (props) => {
+  const [selectedInfras, setSelectedInfras] = useState([...provisionOptions]);
+  const [applicationId, setApplicationId] = useState("");
+  const [azureServicePrincipal, setAzureServicePrincipal] = useState("");
+  const [tenantId, setTenantId] = useState("");
+  const [subscriptionId, setSubscriptionId] = useState("");
+  const [clusterName, setClusterName] = useState("");
+  const [clusterNameSet, setClusterNameSet] = useState(false);
+  const [provisionConfirmed, setProvisionConfirmed] = useState(false);
+
+  const context = useContext(Context);
+
+  // This is added only for tracking purposes
+  // With this prop we will track down if the user has had an intent of filling the formulary
+  const [isFormDirty, setIsFormDirty] = useState(false);
+
+  useEffect(() => {
+    if (!isFormDirty) {
+      return;
+    }
+
+    window.analytics?.track("provision_form-dirty", {
+      provider: "do",
+    });
+  }, [isFormDirty]);
+
+  useEffect(() => {
+    if (props.infras) {
+      // From the dashboard, only uncheck and disable if "creating" or "created"
+      let filtered = selectedInfras;
+      props.infras.forEach((infra: InfraType, i: number) => {
+        let { kind, status } = infra;
+        if (status === "creating" || status === "created") {
+          filtered = filtered.filter((item: any) => {
+            return item.value !== kind;
+          });
+        }
+      });
+      setSelectedInfras(filtered);
+    }
+  }, [props.infras]);
+
+  useEffect(() => {
+    setClusterNameIfNotSet();
+  }, [props.projectName]);
+
+  const setClusterNameIfNotSet = () => {
+    let projectName = props.projectName || context.currentProject?.name;
+
+    if (!clusterNameSet && !clusterName.includes(`${projectName}-cluster`)) {
+      setClusterName(
+        `${projectName}-cluster-${Math.random().toString(36).substring(2, 8)}`
+      );
+    }
+  };
+
+  const checkFormDisabled = () => {
+    if (!provisionConfirmed) {
+      return true;
+    }
+
+    let { projectName } = props;
+    if (projectName || projectName === "") {
+      return (
+        !isAlphanumeric(projectName) ||
+        selectedInfras.length === 0 ||
+        !clusterName
+      );
+    } else {
+      return selectedInfras.length === 0 || !clusterName;
+    }
+  };
+
+  const getButtonStatus = () => {
+    if (props.projectName) {
+      if (!isAlphanumeric(props.projectName)) {
+        return "Project name contains illegal characters";
+      }
+    }
+    if (!provisionConfirmed || props.projectName === "" || !clusterName) {
+      return "Required fields missing";
+    }
+  };
+
+  return (
+    <StyledAWSFormSection>
+      <FormSection>
+        <CloseButton onClick={() => props.setSelectedProvisioner(null)}>
+          <CloseButtonImg src={close} />
+        </CloseButton>
+        <Heading isAtTop={true}>Azure credentials</Heading>
+        <InputRow
+          type="text"
+          value={applicationId}
+          setValue={(x: string) => setApplicationId(x)}
+          label="⚙️ Azure application (client) ID"
+          placeholder="ex: 123456780-abcd-1234-abcd-12345678"
+          width="100%"
+          isRequired={true}
+        />
+        <InputRow
+          type="password"
+          value={azureServicePrincipal}
+          setValue={(x: string) => setAzureServicePrincipal(x)}
+          label="🔒 Azure service principal"
+          placeholder="○ ○ ○ ○ ○ ○ ○ ○ ○"
+          width="100%"
+          isRequired={true}
+        />
+        <InputRow
+          type="text"
+          value={tenantId}
+          setValue={(x: string) => setTenantId(x)}
+          label="👤 Azure tenant ID"
+          placeholder="ex: 123456780-abcd-1234-abcd-12345678"
+          width="100%"
+          isRequired={true}
+        />
+        <InputRow
+          type="text"
+          value={subscriptionId}
+          setValue={(x: string) => setSubscriptionId(x)}
+          label="💳 Azure subscription ID"
+          placeholder="ex: 123456780-abcd-1234-abcd-12345678"
+          width="100%"
+          isRequired={true}
+        />
+      </FormSection>
+      {props.children ? props.children : <Padding />}
+      <SaveButton
+        text="Submit"
+        onClick={() => {}}
+        makeFlush={true}
+        helper="Note: Provisioning can take up to 15 minutes"
+      />
+    </StyledAWSFormSection>
+  );
+};
+
+export default AzureFormSectionFC;
+
+const Highlight = styled.a`
+  color: #8590ff;
+  cursor: pointer;
+  text-decoration: none;
+  margin-left: 5px;
+`;
+
+const Padding = styled.div`
+  height: 15px;
+`;
+
+const Br = styled.div`
+  width: 100%;
+  height: 2px;
+`;
+
+const StyledAWSFormSection = styled.div`
+  position: relative;
+  padding-bottom: 35px;
+`;
+
+const FormSection = styled.div`
+  background: #ffffff11;
+  margin-top: 25px;
+  background: #26282f;
+  border-radius: 5px;
+  margin-bottom: 25px;
+  padding: 25px;
+  padding-bottom: 16px;
+  font-size: 13px;
+  animation: fadeIn 0.3s 0s;
+  position: relative;
+`;
+
+const CloseButton = styled.div`
+  position: absolute;
+  display: block;
+  width: 40px;
+  height: 40px;
+  padding: 13px 0 12px 0;
+  z-index: 1;
+  text-align: center;
+  border-radius: 50%;
+  right: 15px;
+  top: 12px;
+  cursor: pointer;
+  :hover {
+    background-color: #ffffff11;
+  }
+`;
+
+const GuideButton = styled.a`
+  display: flex;
+  align-items: center;
+  margin-left: 20px;
+  color: #aaaabb;
+  font-size: 13px;
+  margin-bottom: -1px;
+  border: 1px solid #aaaabb;
+  padding: 5px 10px;
+  padding-left: 6px;
+  border-radius: 5px;
+  cursor: pointer;
+  :hover {
+    background: #ffffff11;
+    color: #ffffff;
+    border: 1px solid #ffffff;
+
+    > i {
+      color: #ffffff;
+    }
+  }
+
+  > i {
+    color: #aaaabb;
+    font-size: 16px;
+    margin-right: 6px;
+  }
+`;
+
+const CloseButtonImg = styled.img`
+  width: 14px;
+  margin: 0 auto;
+`;
+
+const CostHighlight = styled.span<{ highlight: boolean }>`
+  background-color: ${(props) => props.highlight && "yellow"};
+`;
+
+const StyledInfoTooltip = styled.div`
+  display: inline-block;
+  position: relative;
+  margin-right: 2px;
+  > i {
+    display: flex;
+    align-items: center;
+    position: absolute;
+    top: -10px;
+    font-size: 10px;
+    color: #858faaaa;
+    cursor: pointer;
+    :hover {
+      color: #aaaabb;
+    }
+  }
+`;

+ 36 - 1
dashboard/src/main/home/provisioner/ProvisionerSettings.tsx

@@ -15,10 +15,12 @@ import Helper from "components/form-components/Helper";
 import AWSFormSection from "./AWSFormSection";
 import GCPFormSection from "./GCPFormSection";
 import DOFormSection from "./DOFormSection";
+import AzureFormSection from "./AzureFormSection";
 import SaveButton from "components/SaveButton";
 import ExistingClusterSection from "./ExistingClusterSection";
 import { useHistory, useLocation } from "react-router";
 import { pushFiltered } from "shared/routing";
+import azure from "assets/azure.png";
 
 type Props = {
   isInNewProject?: boolean;
@@ -163,6 +165,21 @@ const ProvisionerSettings: React.FC<Props> = ({
       );
     }
 
+    if (selectedProvider === "azure") {
+      return (
+        <AzureFormSection
+          handleError={handleError}
+          projectName={projectName}
+          infras={infras}
+          highlightCosts={highlightCosts}
+          setSelectedProvisioner={(x: string | null) => {
+            handleSelectProvider(x);
+          }}
+          trackOnSave={() => trackOnSave(selectedProvider)}
+        />
+      );
+    }
+
     if (selectedProvider === "do") {
       return (
         <DOFormSection
@@ -267,10 +284,28 @@ const ProvisionerSettings: React.FC<Props> = ({
                   <InfoTooltip text={""} />
                   */}
                 </CostSection>
-                <BlockDescription>Hosted in your own cloud.</BlockDescription>
+                <BlockDescription>Hosted in your own cloud</BlockDescription>
               </Block>
             );
           })}
+          {
+            window.location.href.includes("dashboard.staging.getporter.dev") && (
+              <Block
+                key={3}
+                disabled={isUsageExceeded}
+                onClick={() => {
+                  if (!isUsageExceeded) {
+                    handleSelectProvider("azure");
+                    setHighlightCosts(false);
+                  }
+                }}
+              >
+                <Icon src={azure} />
+                <BlockTitle>Azure</BlockTitle>
+                <BlockDescription>Hosted in your own cloud</BlockDescription>
+              </Block>
+            )
+          }
         </BlockList>
       ) : (
         <>{renderSelectedProvider()}</>