Feroze Mohideen 2 anni fa
parent
commit
ea5ae4f6f1

+ 85 - 192
dashboard/src/main/home/database-dashboard/CreateDatabase.tsx

@@ -1,197 +1,89 @@
+import React, { useState } from "react";
 import _ from "lodash";
-import React, { useContext, useMemo, useState } from "react";
 import styled from "styled-components";
-import DashboardHeader from "../cluster-dashboard/DashboardHeader";
-
-import awsRDS from "assets/amazon-rds.png";
-import awsElastiCache from "assets/aws-elasticache.png";
-import database from "assets/database.svg";
-import notFound from "assets/not-found.png";
-
-import { Context } from "shared/Context";
-import { search } from "shared/search";
-import { AddonCard } from "shared/types";
+import { match } from "ts-pattern";
 
 import Back from "components/porter/Back";
-import Container from "components/porter/Container";
-import Fieldset from "components/porter/Fieldset";
 import Spacer from "components/porter/Spacer";
+import Tag from "components/porter/Tag";
 import Text from "components/porter/Text";
-import AuroraPostgresForm from "./forms/AuroraPostgresForm";
-import ElasticacheRedisForm from "./forms/ElasticacheRedisForm";
-import RDSForm from "./forms/RDSForm";
 
-type Props = {
-};
+import database from "assets/database.svg";
+
+import DashboardHeader from "../cluster-dashboard/DashboardHeader";
+import { SUPPORTED_DATABASE_TEMPLATES } from "./constants";
+import DatabaseForm from "./forms/DatabaseForm";
+import { type DatabaseTemplate } from "./types";
 
-const CreateDatabase: React.FC<Props> = ({
-}) => {
-  const { capabilities, currentProject, currentCluster, user } = useContext(Context);
-  const [isLoading, setIsLoading] = useState<boolean>(true);
-  const [searchValue, setSearchValue] = useState("");
-  const [currentTemplate, setCurrentTemplate] = useState<any>(null);
-  const [databaseTemplates, setDatabaseTemplates] = useState<AddonCard[]>([
-    {
-      id: "rds-postgresql",
-      icon: awsRDS,
-      name: "RDS PostgreSQL",
-      description: "Amazon Relational Database Service (RDS) is a web service that makes it easier to set up, operate, and scale a relational database in the cloud.",
-    },
-    {
-      id: "rds-postgresql-aurora",
-      icon: awsRDS,
-      name: "Aurora PostgreSQL",
-      description: "Amazon Aurora PostgreSQL is a fully managed, PostgreSQL–compatible, and ACID–compliant relational database engine that combines the speed, reliability, and manageability of Amazon Aurora with the simplicity and cost-effectiveness of open-source databases.",
-    },
-    {
-      id: "elasticache-redis",
-      icon: awsElastiCache,
-      name: "ElastiCache Redis",
-      description: "A fast nosql datastore used for caching, real-time interactions, and more.",
-    },
-    {
-      id: "elasticache-memcached",
-      icon: awsElastiCache,
-      name: "ElastiCache Memcached",
-      description: "Contact support@porter.run",
-      disabled: true,
-    },
-  ]);
-  
-  const allFilteredTemplates = useMemo(() => {
-    const filteredBySearch = search(
-      databaseTemplates ?? [],
-      searchValue,
-      {
-        keys: ["name"],
-        isCaseSensitive: false,
-      }
-    );
-    return _.sortBy(filteredBySearch);
-  }, [databaseTemplates, searchValue]);
+const CreateDatabase: React.FC = () => {
+  const [selectedTemplate, setSelectedTemplate] = useState<
+    DatabaseTemplate | undefined
+  >(undefined);
 
   return (
     <StyledTemplateComponent>
-      {
-        (currentTemplate) ? (
-          <>
-            {currentTemplate.id === "rds-postgresql" && (
-              <RDSForm
-                currentTemplate={currentTemplate}
-                goBack={() => setCurrentTemplate(null)}
-                repoURL={capabilities?.default_addon_helm_repo_url}
-              />
-            )}
-            {currentTemplate.id === "rds-postgresql-aurora" && (
-              <AuroraPostgresForm
-                currentTemplate={currentTemplate}
-                goBack={() => setCurrentTemplate(null)}
-                repoURL={capabilities?.default_addon_helm_repo_url}
+      {match(selectedTemplate)
+        .with(undefined, () => {
+          return (
+            <>
+              <Back to="/databases" />
+              <DashboardHeader
+                image={database}
+                title="Create a new database"
+                capitalize={false}
+                disableLineBreak
               />
-            )}
-            {currentTemplate.id === "elasticache-redis" && (
-              <ElasticacheRedisForm
-                currentTemplate={currentTemplate}
-                goBack={() => setCurrentTemplate(null)}
-                repoURL={capabilities?.default_addon_helm_repo_url}
-              />
-            )}
-          </>
-        ) : (
-          <>
-            <Back to="/databases" />
-            <DashboardHeader
-              image={database}
-              title="Create a new database"
-              capitalize={false}
-              disableLineBreak
-            />
-            {/*
-            <SearchBar
-              value={searchValue}
-              setValue={setSearchValue}
-              placeholder="Search available databases . . ."
-              width="100%"
-            />
-            <Spacer y={1} />
-            */}
-
-            {allFilteredTemplates.length === 0 && (
-              <Fieldset>
-                <Container row>
-                  <PlaceholderIcon src={notFound} />
-                  <Text color="helper">No matching add-ons were found.</Text>
-                </Container>
-              </Fieldset>
-            )}
-            <DarkMatter />
-
-            {databaseTemplates?.length > 0 &&
-              <>
-                <Spacer y={1.5} />
-                <Text size={15}>Production datastores</Text>
-                <Spacer y={.5} />
-                <Text color="helper">Fully-managed production-ready datastores.</Text>
-                <Spacer y={.5} />
-                <TemplateListWrapper>
-                  {databaseTemplates.map((template) => {
-                    let { id, name, icon, description, tags, disabled } = template;
-                    return (
-                      <TemplateBlock
-                        disabled={disabled}
-                        key={id}
-                        onClick={() => {
-                          !disabled && setCurrentTemplate(template);
-                        }}
-                      >
+              <Text size={15}>Production datastores</Text>
+              <Spacer y={0.5} />
+              <Text color="helper">
+                Fully-managed production-ready datastores.
+              </Text>
+              <Spacer y={0.5} />
+              <TemplateListWrapper>
+                {SUPPORTED_DATABASE_TEMPLATES.map((template) => {
+                  const { name, icon, description, disabled, engine } =
+                    template;
+                  return (
+                    <TemplateBlock
+                      disabled={disabled}
+                      key={name}
+                      onClick={() => {
+                        !disabled && setSelectedTemplate(template);
+                      }}
+                    >
+                      <TemplateHeader>
                         <Icon src={icon} />
+                        <Spacer inline x={0.5} />
                         <TemplateTitle>{name}</TemplateTitle>
-                        <TemplateDescription>{description}</TemplateDescription>
-                        <Spacer y={0.5} />
-                      </TemplateBlock>
-                    );
-                  })}
-                </TemplateListWrapper>
-              </>
-            }
-          </>
-        )
-      }
-    </StyledTemplateComponent >
+                        <Spacer inline x={0.5} />
+                        <Tag hoverable={false}>{engine.displayName}</Tag>
+                      </TemplateHeader>
+                      <Spacer y={0.5} />
+                      <TemplateDescription>{description}</TemplateDescription>
+                      <Spacer y={0.5} />
+                    </TemplateBlock>
+                  );
+                })}
+              </TemplateListWrapper>
+            </>
+          );
+        })
+        .otherwise((tp) => (
+          <DatabaseForm
+            template={tp}
+            onFormExit={() => {
+              setSelectedTemplate(undefined);
+            }}
+          />
+        ))}
+    </StyledTemplateComponent>
   );
 };
 
 export default CreateDatabase;
 
 const Icon = styled.img`
-  height: 25px;
-  margin-top: 30px;
-  margin-bottom: 5px;
-`;
-
-const PlaceholderIcon = styled.img`
-  height: 13px;
-  margin-right: 12px;
-  opacity: 0.65;
-`;
-
-const DarkMatter = styled.div`
-  width: 100%;
-  margin-top: -35px;
-`;
-
-const I = styled.i`
-  font-size: 16px;
-  padding: 4px;
-  cursor: pointer;
-  border-radius: 50%;
-  margin-right: 15px;
-  background: ${props => props.theme.fg};
-  color: ${props => props.theme.text.primary};
-  border: 1px solid ${props => props.theme.border};
-  :hover {
-    filter: brightness(150%);
-  }
+  height: 18px;
 `;
 
 const StyledTemplateComponent = styled.div`
@@ -200,26 +92,29 @@ const StyledTemplateComponent = styled.div`
 `;
 
 const TemplateDescription = styled.div`
+  display: flex;
   margin-bottom: 15px;
   color: #ffffff66;
-  text-align: center;
   font-weight: default;
-  padding: 0px 25px;
+  padding: 0px 50px;
   line-height: 1.4;
-  font-size: 12px;
-  display: -webkit-box;
-  overflow: hidden;
-  -webkit-line-clamp: 2;
-  -webkit-box-orient: vertical;
+  font-size: 14px;
+  text-align: center;
+`;
+
+const TemplateHeader = styled.div`
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  margin-top: 50px;
 `;
 
 const TemplateTitle = styled.div`
-  width: 80%;
-  text-align: center;
-  font-size: 14px;
+  display: flex;
+  width: 100%;
+  justify-content: center;
+  font-size: 22px;
   white-space: nowrap;
-  overflow: hidden;
-  text-overflow: ellipsis;
 `;
 
 const TemplateBlock = styled.div<{ disabled?: boolean }>`
@@ -231,12 +126,11 @@ const TemplateBlock = styled.div<{ disabled?: boolean }>`
   font-size: 13px;
   flex-direction: column;
   align-item: center;
-  justify-content: space-between;
-  height: 180px;
+  height: 220px;
   color: #ffffff;
   position: relative;
   border-radius: 5px;
-  background: ${props => props.theme.clickable.bg};
+  background: ${(props) => props.theme.clickable.bg};
   border: 1px solid #494b4f;
   :hover {
     border: ${(props) => (props.disabled ? "" : "1px solid #7a7b80")};
@@ -256,9 +150,8 @@ const TemplateBlock = styled.div<{ disabled?: boolean }>`
 const TemplateListWrapper = styled.div`
   overflow: visible;
   margin-top: 15px;
-  padding-bottom: 50px;
   display: grid;
   grid-column-gap: 30px;
   grid-row-gap: 30px;
-  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
-`;
+  grid-template-columns: repeat(2, 1fr);
+`;

+ 51 - 0
dashboard/src/main/home/database-dashboard/constants.ts

@@ -0,0 +1,51 @@
+import awsRDS from "assets/amazon-rds.png";
+import awsElastiCache from "assets/aws-elasticache.png";
+
+import {
+  DATABASE_ENGINE_MEMCACHED,
+  DATABASE_ENGINE_POSTGRES,
+  DATABASE_ENGINE_REDIS,
+  DATABASE_TYPE_AURORA,
+  DATABASE_TYPE_ELASTICACHE,
+  DATABASE_TYPE_RDS,
+  type DatabaseTemplate,
+} from "./types";
+
+export const SUPPORTED_DATABASE_TEMPLATES: DatabaseTemplate[] = [
+  {
+    name: "Amazon RDS",
+    type: DATABASE_TYPE_RDS,
+    engine: DATABASE_ENGINE_POSTGRES,
+    icon: awsRDS as string,
+    description:
+      "Amazon Relational Database Service (RDS) is a web service that makes it easier to set up, operate, and scale a relational database in the cloud.",
+    disabled: false,
+  },
+  {
+    name: "Amazon Aurora",
+    type: DATABASE_TYPE_AURORA,
+    engine: DATABASE_ENGINE_POSTGRES,
+    icon: awsRDS as string,
+    description:
+      "Amazon Aurora PostgreSQL is an ACID–compliant relational database engine that combines the speed, reliability, and manageability of Amazon Aurora with the simplicity and cost-effectiveness of open-source databases.",
+    disabled: false,
+  },
+  {
+    name: "Amazon ElastiCache",
+    type: DATABASE_TYPE_ELASTICACHE,
+    engine: DATABASE_ENGINE_REDIS,
+    icon: awsElastiCache as string,
+    description:
+      "Amazon ElastiCache is a web service that makes it easy to deploy, operate, and scale an in-memory data store or cache in the cloud.",
+    disabled: false,
+  },
+  {
+    name: "Amazon ElastiCache",
+    type: DATABASE_TYPE_ELASTICACHE,
+    engine: DATABASE_ENGINE_MEMCACHED,
+    icon: awsElastiCache as string,
+    description:
+      "Currently unavailable. Please contact support@porter.run for more details.",
+    disabled: true,
+  },
+];

+ 48 - 0
dashboard/src/main/home/database-dashboard/forms/DatabaseForm.tsx

@@ -0,0 +1,48 @@
+import React, { useContext } from "react";
+import { match } from "ts-pattern";
+
+import { Context } from "shared/Context";
+
+import {
+  DATABASE_TYPE_AURORA,
+  DATABASE_TYPE_ELASTICACHE,
+  DATABASE_TYPE_RDS,
+  type DatabaseTemplate,
+} from "../types";
+import AuroraPostgresForm from "./AuroraPostgresForm";
+import ElasticacheRedisForm from "./ElasticacheRedisForm";
+import RDSForm from "./RDSForm";
+
+type Props = {
+  template: DatabaseTemplate;
+  onFormExit: () => void;
+};
+const DatabaseForm: React.FC<Props> = ({ template, onFormExit }) => {
+  const { capabilities } = useContext(Context);
+
+  return match(template)
+    .with({ type: DATABASE_TYPE_RDS }, () => (
+      <RDSForm
+        currentTemplate={template}
+        goBack={onFormExit}
+        repoURL={capabilities?.default_addon_helm_repo_url}
+      />
+    ))
+    .with({ type: DATABASE_TYPE_AURORA }, () => (
+      <AuroraPostgresForm
+        currentTemplate={template}
+        goBack={onFormExit}
+        repoURL={capabilities?.default_addon_helm_repo_url}
+      />
+    ))
+    .with({ type: DATABASE_TYPE_ELASTICACHE }, () => (
+      <ElasticacheRedisForm
+        currentTemplate={template}
+        goBack={onFormExit}
+        repoURL={capabilities?.default_addon_helm_repo_url}
+      />
+    ))
+    .exhaustive();
+};
+
+export default DatabaseForm;

+ 34 - 0
dashboard/src/main/home/database-dashboard/types.ts

@@ -55,3 +55,37 @@ export const cloudProviderDatastoreSchema = z.object({
 export type CloudProviderDatastore = z.infer<
   typeof cloudProviderDatastoreSchema
 >;
+
+export type DatabaseEngine =
+  | typeof DATABASE_ENGINE_POSTGRES
+  | typeof DATABASE_ENGINE_REDIS
+  | typeof DATABASE_ENGINE_MEMCACHED;
+export const DATABASE_ENGINE_POSTGRES = {
+  name: "postgres" as const,
+  displayName: "PostgreSQL",
+};
+export const DATABASE_ENGINE_REDIS = {
+  name: "redis" as const,
+  displayName: "Redis",
+};
+export const DATABASE_ENGINE_MEMCACHED = {
+  name: "memcached" as const,
+  displayName: "Memcached",
+};
+
+export type DatabaseType =
+  | typeof DATABASE_TYPE_RDS
+  | typeof DATABASE_TYPE_AURORA
+  | typeof DATABASE_TYPE_ELASTICACHE;
+export const DATABASE_TYPE_RDS = "rds" as const;
+export const DATABASE_TYPE_AURORA = "aurora" as const;
+export const DATABASE_TYPE_ELASTICACHE = "elasticache" as const;
+
+export type DatabaseTemplate = {
+  type: DatabaseType;
+  engine: DatabaseEngine;
+  icon: string;
+  name: string;
+  description: string;
+  disabled: boolean;
+};