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

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

Justin Rhee 3 лет назад
Родитель
Сommit
199d367539
32 измененных файлов с 270 добавлено и 132 удалено
  1. 48 39
      .github/workflows/porter_preview_env.yml
  2. BIN
      dashboard/src/assets/job-bold.png
  3. BIN
      dashboard/src/assets/job.png
  4. BIN
      dashboard/src/assets/web-bold.png
  5. BIN
      dashboard/src/assets/web.png
  6. BIN
      dashboard/src/assets/worker.png
  7. 3 3
      dashboard/src/components/CloudFormationForm.tsx
  8. 10 6
      dashboard/src/components/ClusterProvisioningPlaceholder.tsx
  9. 6 4
      dashboard/src/components/CredentialsForm.tsx
  10. 3 3
      dashboard/src/components/ProvisionerFlow.tsx
  11. 9 10
      dashboard/src/components/ProvisionerForm.tsx
  12. 7 3
      dashboard/src/components/ProvisionerSettings.tsx
  13. 7 3
      dashboard/src/components/ProvisionerSettingsOld.tsx
  14. 1 1
      dashboard/src/components/TabSelector.tsx
  15. 0 1
      dashboard/src/components/TitleSection.tsx
  16. 0 1
      dashboard/src/components/porter/Button.tsx
  17. 1 1
      dashboard/src/components/repo-selector/RepoList.tsx
  18. 2 2
      dashboard/src/main/home/cluster-dashboard/apps/AppDashboard.tsx
  19. 1 2
      dashboard/src/main/home/cluster-dashboard/chart/Chart.tsx
  20. 36 3
      dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx
  21. 2 2
      dashboard/src/main/home/cluster-dashboard/jobs/JobDashboard.tsx
  22. 1 1
      dashboard/src/main/home/integrations/IntegrationList.tsx
  23. 1 1
      dashboard/src/main/home/integrations/IntegrationRow.tsx
  24. 2 2
      dashboard/src/main/home/launch/Launch.tsx
  25. 31 14
      dashboard/src/main/home/launch/TemplateList.tsx
  26. 1 1
      dashboard/src/main/home/modals/Modal.tsx
  27. 1 1
      dashboard/src/main/home/provisioner/ProvisionerSettings.tsx
  28. 4 4
      dashboard/src/main/home/sidebar/ClusterSection.tsx
  29. 4 4
      dashboard/src/main/home/sidebar/Clusters.tsx
  30. 0 1
      dashboard/src/main/home/sidebar/ProjectSection.tsx
  31. 14 19
      dashboard/src/main/home/sidebar/Sidebar.tsx
  32. 75 0
      porter.yaml

+ 48 - 39
.github/workflows/porter_preview_env.yml

@@ -22,50 +22,59 @@ jobs:
   porter-preview:
     runs-on: ubuntu-latest
     steps:
-    - name: Checkout code
-      id: checkout-code
-      uses: actions/checkout@v3
-    - name: Create Porter preview env
-      id: preview
-      timeout-minutes: 30
-      uses: porter-dev/porter-preview-action@dev
-      with:
-        action_id: ${{ github.run_id }}
-        cluster: "2489"
-        host: https://dashboard.getporter.dev
-        installation_id: "18533943"
-        namespace: pr-${{ github.event.inputs.pr_number }}-porter
-        pr_branch_from: ${{ github.event.inputs.pr_branch_from }}
-        pr_branch_into: ${{ github.event.inputs.pr_branch_into }}
-        pr_id: ${{ github.event.inputs.pr_number }}
-        pr_name: ${{ github.event.inputs.pr_title }}
-        project: "6680"
-        repo_name: porter
-        repo_owner: porter-dev
-        token: ${{ secrets.PORTER_PREVIEW_6680_2489 }}
-    - name: Attach vcluster
-      run: |
-        sudo apt-get update
-        sudo apt-get install bash curl jq unzip
+      - name: Checkout monorepo code
+        id: checkout-monorepo-code
+        uses: actions/checkout@v3
+      - name: Checkout CCP code
+        id: checkout-ccp-code
+        uses: actions/checkout@v3
+        with:
+          repository: porter-dev/cluster-control-plane
+          token: ${{ secrets.PORTER_DEV_GITHUB_TOKEN }}
+          path: external/ccp
+      - name: Create Porter preview env
+        id: preview
+        timeout-minutes: 30
+        uses: porter-dev/porter-preview-action@dev
+        with:
+          action_id: ${{ github.run_id }}
+          cluster: "2489"
+          host: https://dashboard.getporter.dev
+          installation_id: "18533943"
+          namespace: pr-${{ github.event.inputs.pr_number }}-porter
+          pr_branch_from: ${{ github.event.inputs.pr_branch_from }}
+          pr_branch_into: ${{ github.event.inputs.pr_branch_into }}
+          pr_id: ${{ github.event.inputs.pr_number }}
+          pr_name: ${{ github.event.inputs.pr_title }}
+          project: "6680"
+          repo_name: porter
+          repo_owner: porter-dev
+          token: ${{ secrets.PORTER_PREVIEW_6680_2489 }}
+        env:
+          PORTER_APPLY_HONEYCOMB_PASSWORD: ${{ secrets.HONEYCOMB_PASSWORD_PREVIEW_ENVIRONMENTS }}
+      - name: Attach vcluster
+        run: |
+          sudo apt-get update
+          sudo apt-get install bash curl jq unzip
 
-        /bin/bash -c "$(curl -fsSL https://install.porter.run)"
+          /bin/bash -c "$(curl -fsSL https://install.porter.run)"
 
-        echo "$VCLUSTER_KUBECONFIG" > /tmp/vcluster_kubeconfig
+          echo "$VCLUSTER_KUBECONFIG" > /tmp/vcluster_kubeconfig
 
-        dashboard_domain=$(echo "$DOMAINS" | jq '.subdomains[] | select(test("porter-dashboard*"))')
-        dashboard_domain=$(sed -e 's/^"//' -e 's/"$//' <<<"$dashboard_domain")
+          dashboard_domain=$(echo "$DOMAINS" | jq '.subdomains[] | select(test("porter-dashboard*"))')
+          dashboard_domain=$(sed -e 's/^"//' -e 's/"$//' <<<"$dashboard_domain")
 
-        if [ -z "$dashboard_domain" ]; then
-          exit 1
-        fi
+          if [ -z "$dashboard_domain" ]; then
+            exit
+          fi
 
-        export PORTER_HOST="https://${dashboard_domain}"
+          export PORTER_HOST="https://${dashboard_domain}"
 
-        porter connect kubeconfig --kubeconfig /tmp/vcluster_kubeconfig
-      env:
-        PORTER_TOKEN: ${{ secrets.PREVIEW_DEPLOYMENT_PORTER_KEY }}
-        PORTER_PROJECT: 1
-        VCLUSTER_KUBECONFIG: ${{ secrets.VCLUSTER_KUBECONFIG }}
-        DOMAINS: ${{ steps.preview.outputs.domains  }}
+          porter connect kubeconfig --kubeconfig /tmp/vcluster_kubeconfig
+        env:
+          PORTER_TOKEN: ${{ secrets.PREVIEW_DEPLOYMENT_PORTER_KEY }}
+          PORTER_PROJECT: 1
+          VCLUSTER_KUBECONFIG: ${{ secrets.VCLUSTER_KUBECONFIG }}
+          DOMAINS: ${{ steps.preview.outputs.domains  }}
     concurrency:
       group: ${{ github.workflow }}-${{ github.event.inputs.pr_number }}

BIN
dashboard/src/assets/job-bold.png


BIN
dashboard/src/assets/job.png


BIN
dashboard/src/assets/web-bold.png


BIN
dashboard/src/assets/web.png


BIN
dashboard/src/assets/worker.png


+ 3 - 3
dashboard/src/components/CloudFormationForm.tsx

@@ -88,7 +88,7 @@ const CloudFormationForm: React.FC<Props> = ({
       <>
         <Spacer y={1} />
         <Fieldset>
-          <Text size={16} weight={500}>
+          <Text size={16}>
             Log in to AWS and "Create stack"
           </Text>
           <Spacer height="15px" />
@@ -149,7 +149,7 @@ const CloudFormationForm: React.FC<Props> = ({
                 ctaText="Troubleshooting steps"
                 errorModalContents={
                   <>
-                    <Text size={16} weight={500}>Granting Porter access to AWS</Text>
+                    <Text size={16}>Granting Porter access to AWS</Text>
                     <Spacer y={1} />
                     <Text color="helper">
                       Porter needs access to your AWS account in order to create infrastructure. You can grant Porter access to AWS by following these steps:
@@ -192,7 +192,7 @@ const CloudFormationForm: React.FC<Props> = ({
 
   return (
     <>
-      <Text size={16} weight={500}>
+      <Text size={16}>
         <BackButton width="140px" onClick={goBack}>
           <i className="material-icons">first_page</i>
           Select cloud

+ 10 - 6
dashboard/src/components/ClusterProvisioningPlaceholder.tsx

@@ -8,6 +8,8 @@ import loading from "assets/loading.gif";
 import { Context } from "shared/Context";
 import Heading from "components/form-components/Heading";
 import Helper from "components/form-components/Helper";
+import Text from "./porter/Text";
+import Spacer from "./porter/Spacer";
 
 type Props = {};
 
@@ -16,11 +18,13 @@ const ClusterProvisioningPlaceholder: React.FC<RouteComponentProps> = (props) =>
 
   return (
     <ClusterPlaceholder>
-      <Heading isAtTop>
+      <Text size={16}>
         <Img src={loading} /> Your cluster is being created
-      </Heading>
-      <Helper>
-        You can view the status of your cluster creation{" "}
+      </Text>
+      <Spacer height="15px" />
+      <Text color="helper">
+        You can view the status of your cluster creation
+        <Spacer inline width="5px" />
         <Link onClick={() => {
           pushFiltered(props, "/cluster-dashboard", ["project_id"], {
             cluster: currentCluster.name,
@@ -29,7 +33,7 @@ const ClusterProvisioningPlaceholder: React.FC<RouteComponentProps> = (props) =>
           here
           <i className="material-icons">arrow_forward</i> 
         </Link>
-      </Helper>
+      </Text>
     </ClusterPlaceholder>
   );
 };
@@ -59,5 +63,5 @@ const ClusterPlaceholder = styled.div`
   border-radius: 5px;
   background: #26292e;
   border: 1px solid #494b4f;
-  padding-bottom: 10px;
+  padding-bottom: 35px;
 `;

+ 6 - 4
dashboard/src/components/CredentialsForm.tsx

@@ -187,7 +187,7 @@ const CredentialsForm: React.FC<Props> = ({
 
   return (
     <>
-      <Heading isAtTop>
+      <Text size={16}>
         <BackButton width="140px" onClick={goBack}>
           <i className="material-icons">first_page</i>
           Select cloud
@@ -198,10 +198,12 @@ const CredentialsForm: React.FC<Props> = ({
         <HelperButton onClick={() => window.open("https://docs.porter.run/getting-started/provisioning-on-aws/", "_blank")}>
           <i className="material-icons">help_outline</i>
         </HelperButton>
-      </Heading>
-      <Helper>
+      </Text>
+      <Spacer y={1} />
+      <Text color="helper">
         Select your credentials from the list below, or add a new set of credentials:
-      </Helper>
+      </Text>
+      <Spacer y={1} />
       {
         isLoading ? (
           <Loading height="150px" />

+ 3 - 3
dashboard/src/components/ProvisionerFlow.tsx

@@ -94,7 +94,7 @@ const ProvisionerFlow: React.FC<Props> = ({
             setConfirmCost("");
             setShowCostConfirmModal(false);
           }}>
-            <Text size={16} weight={500}>
+            <Text size={16}>
               Base AWS cost consent
             </Text>
             <Spacer height="15px" />
@@ -212,7 +212,7 @@ const BlockList = styled.div`
 `;
 
 const Icon = styled.img<{ bw?: boolean }>`
-  height: 42px;
+  height: 30px;
   margin-top: 30px;
   margin-bottom: 15px;
   filter: ${(props) => (props.bw ? "grayscale(1)" : "")};
@@ -260,7 +260,7 @@ const Block = styled.div<{ disabled?: boolean }>`
   color: #ffffff;
   position: relative;
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(160deg, #26292e, #26292e);
   border: 1px solid #494b4f;
   :hover {
     border: ${(props) => (props.disabled ? "" : "1px solid #7a7b80")};

+ 9 - 10
dashboard/src/components/ProvisionerForm.tsx

@@ -7,6 +7,8 @@ import Heading from "components/form-components/Heading";
 import Helper from "./form-components/Helper";
 import ProvisionerSettings from "./ProvisionerSettings";
 import ProvisionerSettingsOld from "./ProvisionerSettingsOld";
+import Text from "./porter/Text";
+import Spacer from "./porter/Spacer";
 
 type Props = {
   goBack: () => void;
@@ -23,18 +25,20 @@ const ProvisionerForm: React.FC<Props> = ({
 }) => {
   return (
     <>
-      <Heading isAtTop>
+      <Text size={16}>
         <BackButton width="155px" onClick={goBack}>
           <i className="material-icons">first_page</i>
           Set credentials
         </BackButton>
-        <Spacer />
+        <Spacer inline width="17px" />
         <Img src={aws} />
         Configure settings
-      </Heading>
-      <Helper>
+      </Text>
+      <Spacer y={1} />
+      <Text color="helper">
         Configure settings for your AWS environment.
-      </Helper>
+      </Text>
+      <Spacer y={1} />
       {useAssumeRole ? (
         <ProvisionerSettings credentialId={credentialId} AWSAccountID={AWSAccountID} />
       ) : (
@@ -46,11 +50,6 @@ const ProvisionerForm: React.FC<Props> = ({
 
 export default ProvisionerForm;
 
-const Spacer = styled.div`
-  height: 1px;
-  width: 17px;
-`;
-
 const Img = styled.img`
   height: 18px;
   margin-right: 15px;

+ 7 - 3
dashboard/src/components/ProvisionerSettings.tsx

@@ -15,6 +15,8 @@ import SaveButton from "./SaveButton";
 import { Contract, EnumKubernetesKind, EnumCloudProvider, NodeGroupType, EKSNodeGroup, EKS, Cluster } from "@porter-dev/api-contracts";
 import { ClusterType } from "shared/types";
 import Button from "./porter/Button";
+import Text from "./porter/Text";
+import Spacer from "./porter/Spacer";
 
 const regionOptions = [
   { value: "us-east-1", label: "US East (N. Virginia) us-east-1" },
@@ -226,10 +228,12 @@ const ProvisionerSettings: React.FC<Props> = props => {
     if (!props.clusterId) {
       return (
         <>
-          <Heading isAtTop>Select an AWS region</Heading>
-          <Helper>
+          <Text size={16}>Select an AWS region</Text>
+          <Spacer y={1} />
+          <Text color="helper">
             Porter will automatically provision your infrastructure in the specified region.
-          </Helper>
+          </Text>
+          <Spacer height="10px" />
           <SelectRow
             options={regionOptions}
             width="350px"

+ 7 - 3
dashboard/src/components/ProvisionerSettingsOld.tsx

@@ -14,6 +14,8 @@ import InputRow from "./form-components/InputRow";
 import SaveButton from "./SaveButton";
 import { Contract, EnumKubernetesKind, EnumCloudProvider, NodeGroupType, EKSNodeGroup, EKS, Cluster } from "@porter-dev/api-contracts";
 import { ClusterType } from "shared/types";
+import Text from "./porter/Text";
+import Spacer from "./porter/Spacer";
 
 const regionOptions = [
   { value: "us-east-1", label: "US East (N. Virginia) us-east-1" },
@@ -206,10 +208,12 @@ const ProvisionerSettingsOld: React.FC<Props> = props => {
     if (!props.clusterId) {
       return (
         <>
-          <Heading isAtTop>Select an AWS region</Heading>
-          <Helper>
+          <Text size={16}>Select an AWS region</Text>
+          <Spacer y={1} />
+          <Text color="helper">
             Porter will automatically provision your infrastructure in the specified region.
-          </Helper>
+          </Text>
+          <Spacer height="10px" />
           <SelectRow
             options={regionOptions}
             width="350px"

+ 1 - 1
dashboard/src/components/TabSelector.tsx

@@ -34,7 +34,7 @@ export default class TabSelector extends Component<PropsType, StateType> {
   };
 
   renderTabList = () => {
-    let color = this.props.color || "#949effff";
+    let color = this.props.color || "#aaaabb";
     return this.props.options.map((option: selectOption, i: number) => {
       return (
         <Tab

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

@@ -90,7 +90,6 @@ const StyledTitle = styled.div<{
   onClick?: any;
 }>`
   font-size: 21px;
-  font-weight: 600;
   user-select: text;
   text-transform: ${(props) => (props.capitalize ? "capitalize" : "")};
   display: flex;

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

@@ -142,7 +142,6 @@ const StyledButton = styled.button<{
   padding: 15px;
   border: none;
   outline: none;
-  font-weight: 500;
   color: white;
   background: ${props => (props.disabled && !props.color) ? "#aaaabb" : (props.color || "#5561C0")};
   display: flex;

+ 1 - 1
dashboard/src/components/repo-selector/RepoList.tsx

@@ -308,7 +308,7 @@ const RepoList: React.FC<Props> = ({
 
     return (
       <>
-                <Text size={16} weight={500}>
+                <Text size={16}>
                   No connected repositories were found.
                 </Text>
                 <ConnectToGithubButton

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/apps/AppDashboard.tsx

@@ -2,7 +2,7 @@ import React, { useContext, useState } from "react";
 import styled from "styled-components";
 import { RouteComponentProps, withRouter } from "react-router";
 
-import monoweb from "assets/monoweb.png";
+import web from "assets/web.png";
 
 import { Context } from "shared/Context";
 import { JobStatusType } from "shared/types";
@@ -44,7 +44,7 @@ const AppDashboard: React.FC<Props> = ({
   return (
     <StyledAppDashboard>
       <DashboardHeader
-        image={monoweb}
+        image={web}
         title={currentView}
         description="Continuously running web services, workers, and add-ons."
         disableLineBreak

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

@@ -352,7 +352,6 @@ const Title = styled.div`
   padding: 12px 35px 12px 45px;
   font-size: 14px;
   font-family: "Work Sans", sans-serif;
-  font-weight: 500;
   color: #ffffff;
   width: 80%;
   overflow: hidden;
@@ -394,7 +393,7 @@ const StyledChart = styled.div`
   width: calc(100% + 2px);
   height: calc(100% + 2px);
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(180deg, #26292e, #24272c);
   border: 1px solid #494b4f;
   :hover {
     border: 1px solid #7a7b80;

+ 36 - 3
dashboard/src/main/home/cluster-dashboard/env-groups/ExpandedEnvGroup.tsx

@@ -478,7 +478,39 @@ const EnvGroupVariablesEditor = ({
   handleUpdateValues: () => void;
 }) => {
   const [isAuthorized] = useAuth();
+  const [localVariables, setLocalVariables] = useState(variables);
 
+  const handleVisibilityChange = () => {
+    if (document.hidden) {
+      localStorage.setItem("envGroupVariables", JSON.stringify(localVariables));
+    } else {
+      const savedVariables = localStorage.getItem("envGroupVariables");
+      if (savedVariables) {
+        setLocalVariables(JSON.parse(savedVariables));
+        localStorage.removeItem("envGroupVariables");
+      }
+    }
+  };
+
+  useEffect(() => {
+    document.addEventListener("visibilitychange", handleVisibilityChange);
+
+    return () => {
+      document.removeEventListener("visibilitychange", handleVisibilityChange);
+    };
+  }, [localVariables]);
+
+  useEffect(() => {
+    return () => {
+      // Reset to the original state when the component is unmounted
+      localStorage.removeItem("envGroupVariables");
+    };
+  }, []);
+
+  const handleUpdate = () => {
+    handleUpdateValues();
+    localStorage.removeItem("envGroupVariables");
+  };
   return (
     <TabWrapper>
       <InnerWrapper>
@@ -488,8 +520,9 @@ const EnvGroupVariablesEditor = ({
           configuration.
         </Helper>
         <EnvGroupArray
-          values={variables}
-          setValues={(x: any) => {
+          values={localVariables}
+          setValues={(x) => {
+            setLocalVariables(x);
             onChange(x);
           }}
           fileUpload={true}
@@ -507,7 +540,7 @@ const EnvGroupVariablesEditor = ({
       {isAuthorized("env_group", "", ["get", "update"]) && (
         <SaveButton
           text="Update"
-          onClick={() => handleUpdateValues()}
+          onClick={handleUpdate}
           status={buttonStatus}
           makeFlush={true}
           clearPosition={true}

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/jobs/JobDashboard.tsx

@@ -2,7 +2,7 @@ import React, { useContext, useState } from "react";
 import styled from "styled-components";
 import { RouteComponentProps, withRouter } from "react-router";
 
-import monojob from "assets/monojob.png";
+import job from "assets/job.png";
 
 import { Context } from "shared/Context";
 import { JobStatusType } from "shared/types";
@@ -44,7 +44,7 @@ const JobDashboard: React.FC<Props> = ({
   return (
     <StyledJobDashboard>
       <DashboardHeader
-        image={monojob}
+        image={job}
         title={currentView}
         description="Scripts and tasks that run once or on a repeating interval."
         disableLineBreak

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

@@ -233,7 +233,7 @@ const Integration = styled.div`
     props.disabled ? "not-allowed" : "pointer"};
   margin-bottom: 20px;
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(180deg, #26292e, #24272c);
   border: 1px solid #494b4f;
   :hover {
     border: 1px solid #7a7b80;

+ 1 - 1
dashboard/src/main/home/integrations/IntegrationRow.tsx

@@ -133,7 +133,7 @@ const Integration = styled.div`
     props.disabled ? "not-allowed" : "pointer"};
   margin-bottom: 15px;
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(180deg, #26292e, #24272c);
   border: 1px solid #494b4f;
   :hover {
     border: 1px solid #7a7b80;

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

@@ -427,10 +427,10 @@ class Templates extends Component<PropsType, StateType> {
       return (
         <TemplatesWrapper>
           <DashboardHeader
-            image={rocket}
-            title="Launch"
+            title="Launch a new service"
             description="Deploy applications and add-ons to your environment."
             disableLineBreak
+            capitalize={false}
           />
           {this.renderContents()}
         </TemplatesWrapper>

+ 31 - 14
dashboard/src/main/home/launch/TemplateList.tsx

@@ -8,6 +8,10 @@ import { hardcodedNames } from "shared/hardcodedNameDict";
 import { PorterTemplate } from "shared/types";
 import semver from "semver";
 
+import web from "assets/web.png";
+import worker from "assets/worker.png";
+import job from "assets/job.png";
+
 type Props = {
   helm_repo_id?: number;
   templates?: PorterTemplate[];
@@ -99,7 +103,16 @@ const TemplateList: React.FC<Props> = ({
     );
   }
 
-  const renderIcon = (icon: string) => {
+  const renderIcon = (icon: string, name?: string) => {
+    if (name === "web") {
+      return <NewIcon src={web} />;
+    }
+    if (name === "worker") {
+      return <NewIcon src={worker} />;
+    }
+    if (name === "job") {
+      return <NewIcon src={job} />;
+    }
     if (icon) {
       return <Icon src={icon} />;
     }
@@ -123,7 +136,7 @@ const TemplateList: React.FC<Props> = ({
             key={name}
             onClick={() => setCurrentTemplate(template)}
           >
-            {renderIcon(icon)}
+            {renderIcon(icon, template.name)}
             <TemplateTitle>{name}</TemplateTitle>
             <TemplateDescription>{description}</TemplateDescription>
           </TemplateBlock>
@@ -155,16 +168,22 @@ const LoadingWrapper = styled.div`
 `;
 
 const Icon = styled.img`
-  height: 42px;
-  margin-top: 35px;
-  margin-bottom: 13px;
+  height: 25px;
+  margin-top: 30px;
+  margin-bottom: 5px;
+`;
+
+const NewIcon = styled.img`
+  height: 25px;
+  margin-top: 30px;
+  margin-bottom: 5px;
 `;
 
 const Polymer = styled.div`
   > i {
-    font-size: 34px;
-    margin-top: 38px;
-    margin-bottom: 20px;
+    font-size: 25px;
+    margin-top: 30px;
+    margin-bottom: 5px;
   }
 `;
 
@@ -174,7 +193,7 @@ const TemplateDescription = styled.div`
   text-align: center;
   font-weight: default;
   padding: 0px 25px;
-  height: 2.4em;
+  line-height: 1.4;
   font-size: 12px;
   display: -webkit-box;
   overflow: hidden;
@@ -183,7 +202,6 @@ const TemplateDescription = styled.div`
 `;
 
 const TemplateTitle = styled.div`
-  margin-bottom: 12px;
   width: 80%;
   text-align: center;
   font-size: 14px;
@@ -197,17 +215,16 @@ const TemplateBlock = styled.div`
   user-select: none;
   display: flex;
   font-size: 13px;
-  font-weight: 500;
   padding: 3px 0px 5px;
   flex-direction: column;
   align-item: center;
   justify-content: space-between;
-  height: 200px;
+  height: 170px;
   cursor: pointer;
   color: #ffffff;
   position: relative;
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(160deg, #26292e, #1e2023);
   border: 1px solid #494b4f;
   :hover {
     border: 1px solid #7a7b80;
@@ -231,5 +248,5 @@ const TemplateListWrapper = styled.div`
   display: grid;
   grid-column-gap: 25px;
   grid-row-gap: 25px;
-  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
+  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
 `;

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

@@ -146,7 +146,7 @@ const StyledModal = styled.div<{
   z-index: 999;
   font-size: 13px;
   border-radius: 10px;
-  background: #42444944;
+  background: #38444944;
   backdrop-filter: saturate(150%) blur(10px);
   border: 1px solid #494b4f;
   overflow: auto;

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

@@ -401,7 +401,7 @@ const Block = styled.div<{ disabled?: boolean }>`
   color: #ffffff;
   position: relative;
   border-radius: 5px;
-  background: #26292e;
+  background: linear-gradient(180deg, #26292e, #24272c);
   border: 1px solid #494b4f;
   :hover {
     border: ${(props) => (props.disabled ? "" : "1px solid #7a7b80")};

+ 4 - 4
dashboard/src/main/home/sidebar/ClusterSection.tsx

@@ -5,8 +5,8 @@ import { ClusterType, ProjectType } from "shared/types";
 import { Tooltip } from "@material-ui/core";
 
 import settings from "assets/settings.svg";
-import monojob from "assets/monojob.png";
-import monoweb from "assets/monoweb.png";
+import job from "assets/job-bold.png";
+import web from "assets/web-bold.png";
 import sliders from "assets/sliders.svg";
 
 import SidebarLink from "./SidebarLink";
@@ -53,7 +53,7 @@ export const ClusterSection: React.FC<Props> = ({
               window.location.pathname.startsWith("/applications")
             }
           >
-            <Img src={monoweb} />
+            <Img src={web} />
             Applications
           </NavButton>
           <NavButton
@@ -64,7 +64,7 @@ export const ClusterSection: React.FC<Props> = ({
               window.location.pathname.startsWith("/jobs")
             }
           >
-            <Img src={monojob} />
+            <Img src={job} />
             Jobs
           </NavButton>
           <NavButton

+ 4 - 4
dashboard/src/main/home/sidebar/Clusters.tsx

@@ -9,8 +9,8 @@ import { ClusterSection } from "./ClusterSection";
 import SidebarLink from "./SidebarLink";
 
 import settings from "assets/settings.svg";
-import monojob from "assets/monojob.png";
-import monoweb from "assets/monoweb.png";
+import job from "assets/job-bold.png";
+import web from "assets/web-bold.png";
 import sliders from "assets/sliders.svg";
 
 import { RouteComponentProps, withRouter } from "react-router";
@@ -180,7 +180,7 @@ class Clusters extends Component<PropsType, StateType> {
               window.location.pathname.startsWith("/applications")
             }
           >
-            <Img src={monoweb} />
+            <Img src={web} />
             Applications
           </NavButton>
           <NavButton
@@ -191,7 +191,7 @@ class Clusters extends Component<PropsType, StateType> {
               window.location.pathname.startsWith("/jobs")
             }
           >
-            <Img src={monojob} />
+            <Img src={job} />
             Jobs
           </NavButton>
           <NavButton

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

@@ -263,7 +263,6 @@ const MainSelector = styled.div`
   margin: 10px 0 0;
   font-size: 14px;
   font-family: "Work Sans", sans-serif;
-  font-weight: 600;
   cursor: pointer;
   padding: 10px 0;
   padding-left: 20px;

+ 14 - 19
dashboard/src/main/home/sidebar/Sidebar.tsx

@@ -148,24 +148,20 @@ class Sidebar extends Component<PropsType, StateType> {
 
           <br />
 
-          {currentCluster && (
-            <>
-              <SidebarLabel>
-                {currentProject.capi_provisioner_enabled ? (
-                  "Your team"
-                ) : (
-                  "Clusters"
-                )}
-              </SidebarLabel>
-              <Clusters
-                setWelcome={this.props.setWelcome}
-                currentView={currentView}
-                isSelected={false}
-                forceRefreshClusters={this.props.forceRefreshClusters}
-                setRefreshClusters={this.props.setRefreshClusters}
-              />
-            </>
-          )}
+          <SidebarLabel>
+            {currentProject.capi_provisioner_enabled ? (
+              "Your team"
+            ) : (
+              "Clusters"
+            )}
+          </SidebarLabel>
+          <Clusters
+            setWelcome={this.props.setWelcome}
+            currentView={currentView}
+            isSelected={false}
+            forceRefreshClusters={this.props.forceRefreshClusters}
+            setRefreshClusters={this.props.setRefreshClusters}
+          />
         </ScrollWrapper>
       );
     }
@@ -295,7 +291,6 @@ const SidebarLabel = styled.div`
   margin-bottom: 5px;
   font-size: 13px;
   z-index: 1;
-  font-weight: 500;
 `;
 
 const PullTab = styled.div`

+ 75 - 0
porter.yaml

@@ -14,6 +14,13 @@ builds:
   env:
     import_from:
       - default/base-env
+- name: ccp
+  method: docker
+  dockerfile: ./external/ccp/zarf/docker/Dockerfile
+  context: ./external/ccp
+  env:
+    import_from:
+      - default/ccp-base-env
 
 apps:
 - name: setup-job
@@ -23,6 +30,22 @@ apps:
   helm_chart:
     name: job
   build_ref: job
+- name: porter-ccp
+  depends_on:
+    - postgres
+    - nats
+  helm_chart:
+    name: web
+  build_ref: ccp
+  helm_values:
+    ingress:
+      enabled: false
+    service:
+      port: 7833
+    container:
+      port: 7833
+      command: ccp
+      args: "start --server --all-consumers"
 - name: porter-dashboard
   depends_on:
     - postgres
@@ -49,3 +72,55 @@ addons:
     postgresqlUsername: postgres
     postgresqlPassword: postgres
     postgresqlDatabase: postgres
+- name: opentelemetry-collector
+  helm_chart:
+    name: opentelemetry-collector
+    url: https://open-telemetry.github.io/opentelemetry-helm-charts
+  helm_values:
+    mode: daemonset
+    config:
+      exporters:
+        otlp/honeycomb:
+          endpoint: api.honeycomb.io:443
+          headers:
+            x-honeycomb-team: p4Xkp5DeAOoDvwDCM7uJNH
+      receivers:
+        jaeger: null
+        otlp:
+          protocols:
+            http: null
+        prometheus: null
+        zipkin: null
+      service:
+        pipelines:
+          logs: null
+          metrics: null
+          traces:
+            exporters:
+              - otlp/honeycomb
+            processors:
+              - batch
+            receivers:
+              - otlp
+- name: nats
+  helm_chart:
+    name: nats
+    url: https://nats-io.github.io/k8s/helm/charts
+  helm_values:
+    cluster:
+      enabled: true
+      replicas: 3
+    nats:
+      jetstream:
+        enabled: true
+        memStorage:
+          enabled: true
+          size: 2Gi
+        fileStorage:
+          enabled: false
+    websocket:
+      enabled: true
+      port: 4223
+      noTLS: true
+    natsbox:
+      enabled: true