Răsfoiți Sursa

Datastore credentials tab (#4197)

Feroze Mohideen 2 ani în urmă
părinte
comite
aee79b9e04
27 a modificat fișierele cu 350 adăugiri și 378 ștergeri
  1. 20 42
      dashboard/src/lib/databases/types.ts
  2. 6 6
      dashboard/src/lib/hooks/useDatabaseList.ts
  3. 2 2
      dashboard/src/lib/hooks/useDatabaseMethods.ts
  4. 6 6
      dashboard/src/main/home/Home.tsx
  5. 19 16
      dashboard/src/main/home/database-dashboard/CreateDatabase.tsx
  6. 14 14
      dashboard/src/main/home/database-dashboard/DatabaseContextProvider.tsx
  7. 18 32
      dashboard/src/main/home/database-dashboard/DatabaseDashboard.tsx
  8. 2 2
      dashboard/src/main/home/database-dashboard/DatabaseHeader.tsx
  9. 1 1
      dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx
  10. 7 7
      dashboard/src/main/home/database-dashboard/DatabaseTabs.tsx
  11. 4 4
      dashboard/src/main/home/database-dashboard/DatabaseView.tsx
  12. 6 6
      dashboard/src/main/home/database-dashboard/DatastoreProvisioningIndicator.tsx
  13. 33 33
      dashboard/src/main/home/database-dashboard/constants.ts
  14. 10 10
      dashboard/src/main/home/database-dashboard/forms/DatabaseForm.tsx
  15. 3 3
      dashboard/src/main/home/database-dashboard/forms/DatabaseFormAuroraPostgres.tsx
  16. 3 3
      dashboard/src/main/home/database-dashboard/forms/DatabaseFormElasticacheRedis.tsx
  17. 3 3
      dashboard/src/main/home/database-dashboard/forms/DatabaseFormRDSPostgres.tsx
  18. 10 10
      dashboard/src/main/home/database-dashboard/icons.tsx
  19. 1 1
      dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx
  20. 3 3
      dashboard/src/main/home/database-dashboard/tabs/ConfigurationTab.tsx
  21. 5 11
      dashboard/src/main/home/database-dashboard/tabs/ConnectedAppsTab.tsx
  22. 161 0
      dashboard/src/main/home/database-dashboard/tabs/CredentialsTab.tsx
  23. 0 151
      dashboard/src/main/home/database-dashboard/tabs/DatabaseEnvTab.tsx
  24. 6 6
      dashboard/src/main/home/database-dashboard/tabs/SettingsTab.tsx
  25. 2 2
      dashboard/src/main/home/database-dashboard/tags/EngineTag.tsx
  26. 4 4
      dashboard/src/main/home/sidebar/Sidebar.tsx
  27. 1 0
      dashboard/src/shared/routing.tsx

+ 20 - 42
dashboard/src/lib/databases/types.ts

@@ -41,99 +41,77 @@ export const datastoreValidator = z.object({
 export type SerializedDatastore = z.infer<typeof datastoreValidator>;
 
 export type ClientDatastore = SerializedDatastore & {
-  template: DatabaseTemplate;
+  template: DatastoreTemplate;
 };
 
 export const datastoreListResponseValidator = z.object({
   datastores: datastoreValidator.array(),
 });
 
-export const cloudProviderValidator = z.object({
-  cloud_provider_id: z.string(),
-  project_id: z.number(),
-});
-
-export type CloudProviderWithSource = z.infer<typeof cloudProviderValidator>;
-
-export const cloudProviderListResponseValidator = z.object({
-  accounts: cloudProviderValidator.array(),
-});
-
-export const cloudProviderDatastoreSchema = z.object({
-  project_id: z.number(),
-  cloud_provider_name: z.string(),
-  cloud_provider_id: z.string(),
-  datastore: datastoreValidator,
-});
-
-export type CloudProviderDatastore = z.infer<
-  typeof cloudProviderDatastoreSchema
->;
-
-export type DatabaseEngine = {
+export type DatastoreEngine = {
   name: z.infer<typeof datastoreValidator>["engine"];
   displayName: string;
 };
-export const DATABASE_ENGINE_POSTGRES = {
+export const DATASTORE_ENGINE_POSTGRES = {
   name: "POSTGRES" as const,
   displayName: "PostgreSQL",
 };
-export const DATABASE_ENGINE_AURORA_POSTGRES = {
+export const DATASTORE_ENGINE_AURORA_POSTGRES = {
   name: "AURORA-POSTGRES" as const,
   displayName: "Aurora PostgreSQL",
 };
-export const DATABASE_ENGINE_REDIS = {
+export const DATASTORE_ENGINE_REDIS = {
   name: "REDIS" as const,
   displayName: "Redis",
 };
-export const DATABASE_ENGINE_MEMCACHED = {
+export const DATASTORE_ENGINE_MEMCACHED = {
   name: "MEMCACHED" as const,
   displayName: "Memcached",
 };
 
-export type DatabaseType = z.infer<typeof datastoreValidator>["type"];
-export const DATABASE_TYPE_RDS = "RDS" as const;
-export const DATABASE_TYPE_ELASTICACHE = "ELASTICACHE" as const;
+export type DatastoreType = z.infer<typeof datastoreValidator>["type"];
+export const DATASTORE_TYPE_RDS = "RDS" as const;
+export const DATASTORE_TYPE_ELASTICACHE = "ELASTICACHE" as const;
 
-export type DatabaseState = {
+export type DatastoreState = {
   state: z.infer<typeof datastoreValidator>["status"];
   displayName: string;
 };
-export const DATABASE_STATE_CREATING: DatabaseState = {
+export const DATASTORE_STATE_CREATING: DatastoreState = {
   state: "CREATING",
   displayName: "Creating",
 };
-export const DATABASE_STATE_CONFIGURING_LOG_EXPORTS: DatabaseState = {
+export const DATASTORE_STATE_CONFIGURING_LOG_EXPORTS: DatastoreState = {
   state: "CONFIGURING_LOG_EXPORTS",
   displayName: "Configuring log exports",
 };
-export const DATABASE_STATE_MODIFYING: DatabaseState = {
+export const DATASTORE_STATE_MODIFYING: DatastoreState = {
   state: "MODIFYING",
   displayName: "Modifying",
 };
-export const DATABASE_STATE_CONFIGURING_ENHANCED_MONITORING: DatabaseState = {
+export const DATASTORE_STATE_CONFIGURING_ENHANCED_MONITORING: DatastoreState = {
   state: "CONFIGURING_ENHANCED_MONITORING",
   displayName: "Configuring enhanced monitoring",
 };
-export const DATABASE_STATE_BACKING_UP: DatabaseState = {
+export const DATASTORE_STATE_BACKING_UP: DatastoreState = {
   state: "BACKING_UP",
   displayName: "Backing up",
 };
-export const DATABASE_STATE_AVAILABLE: DatabaseState = {
+export const DATASTORE_STATE_AVAILABLE: DatastoreState = {
   state: "AVAILABLE",
   displayName: "Finishing provision",
 };
 
-export type DatabaseTemplate = {
-  type: DatabaseType;
-  engine: DatabaseEngine;
+export type DatastoreTemplate = {
+  type: DatastoreType;
+  engine: DatastoreEngine;
   icon: string;
   name: string;
   description: string;
   disabled: boolean;
   instanceTiers: ResourceOption[];
   formTitle: string;
-  creationStateProgression: DatabaseState[];
+  creationStateProgression: DatastoreState[];
 };
 
 const instanceTierValidator = z.enum([

+ 6 - 6
dashboard/src/lib/hooks/useDatabaseList.ts

@@ -1,10 +1,10 @@
 import { useContext } from "react";
 import { useQuery } from "@tanstack/react-query";
 
-import { SUPPORTED_DATABASE_TEMPLATES } from "main/home/database-dashboard/constants";
+import { SUPPORTED_DATASTORE_TEMPLATES } from "main/home/database-dashboard/constants";
 import {
   datastoreListResponseValidator,
-  type DatabaseTemplate,
+  type DatastoreTemplate,
   type SerializedDatastore,
 } from "lib/databases/types";
 
@@ -12,11 +12,11 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import { valueExists } from "shared/util";
 
-type DatabaseListType = {
-  datastores: Array<SerializedDatastore & { template: DatabaseTemplate }>;
+type DatastoreListType = {
+  datastores: Array<SerializedDatastore & { template: DatastoreTemplate }>;
   isLoading: boolean;
 };
-export const useDatabaseList = (): DatabaseListType => {
+export const useDatastoreList = (): DatastoreListType => {
   const { currentProject } = useContext(Context);
 
   const { data: datastores, isLoading: isLoadingDatastores } = useQuery(
@@ -39,7 +39,7 @@ export const useDatabaseList = (): DatabaseListType => {
       );
       return parsed.datastores
         .map((d) => {
-          const template = SUPPORTED_DATABASE_TEMPLATES.find(
+          const template = SUPPORTED_DATASTORE_TEMPLATES.find(
             (t) => t.type === d.type && t.engine.name === d.engine
           );
 

+ 2 - 2
dashboard/src/lib/hooks/useDatabaseMethods.ts

@@ -7,7 +7,7 @@ import { type DbFormData } from "lib/databases/types";
 import api from "shared/api";
 import { Context } from "shared/Context";
 
-type DatabaseHook = {
+type DatastoreHook = {
   create: (values: DbFormData) => Promise<void>;
   deleteDatastore: (name: string) => Promise<void>;
   attachDatastoreToAppInstances: ({
@@ -84,7 +84,7 @@ const clientDbToCreateInput = (values: DbFormData): CreateDatastoreInput => {
     .exhaustive();
 };
 
-export const useDatabaseMethods = (): DatabaseHook => {
+export const useDatastoreMethods = (): DatastoreHook => {
   const { currentProject, currentCluster } = useContext(Context);
 
   const queryClient = useQueryClient();

+ 6 - 6
dashboard/src/main/home/Home.tsx

@@ -472,19 +472,19 @@ const Home: React.FC<Props> = (props) => {
                   )}
                 </Route>
 
-                <Route path="/databases/new/:type/:engine">
+                <Route path="/datastores/new/:type/:engine">
                   <CreateDatabase />
                 </Route>
-                <Route path="/databases/new">
+                <Route path="/datastores/new">
                   <CreateDatabase />
                 </Route>
-                <Route path="/databases/:datastoreName/:tab">
+                <Route path="/datastores/:datastoreName/:tab">
                   <DatabaseView />
                 </Route>
-                <Route path="/databases/:datastoreName">
+                <Route path="/datastores/:datastoreName">
                   <DatabaseView />
                 </Route>
-                <Route path="/databases">
+                <Route path="/datastores">
                   <DatabaseDashboard />
                 </Route>
 
@@ -544,7 +544,7 @@ const Home: React.FC<Props> = (props) => {
                     "/applications",
                     "/jobs",
                     "/env-groups",
-                    "/databases",
+                    "/datastores",
                     ...(!currentProject?.validate_apply_v2
                       ? ["/preview-environments"]
                       : []),

+ 19 - 16
dashboard/src/main/home/database-dashboard/CreateDatabase.tsx

@@ -9,18 +9,18 @@ import Back from "components/porter/Back";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import {
-  DATABASE_ENGINE_AURORA_POSTGRES,
-  DATABASE_ENGINE_POSTGRES,
-  DATABASE_ENGINE_REDIS,
-  DATABASE_TYPE_ELASTICACHE,
-  DATABASE_TYPE_RDS,
-  type DatabaseTemplate,
+  DATASTORE_ENGINE_AURORA_POSTGRES,
+  DATASTORE_ENGINE_POSTGRES,
+  DATASTORE_ENGINE_REDIS,
+  DATASTORE_TYPE_ELASTICACHE,
+  DATASTORE_TYPE_RDS,
+  type DatastoreTemplate,
 } from "lib/databases/types";
 
 import database from "assets/database.svg";
 
 import DashboardHeader from "../cluster-dashboard/DashboardHeader";
-import { SUPPORTED_DATABASE_TEMPLATES } from "./constants";
+import { SUPPORTED_DATASTORE_TEMPLATES } from "./constants";
 import DatabaseFormAuroraPostgres from "./forms/DatabaseFormAuroraPostgres";
 import DatabaseFormElasticacheRedis from "./forms/DatabaseFormElasticacheRedis";
 import DatabaseFormRDSPostgres from "./forms/DatabaseFormRDSPostgres";
@@ -28,7 +28,7 @@ import EngineTag from "./tags/EngineTag";
 
 type Props = RouteComponentProps;
 const CreateDatabase: React.FC<Props> = ({ history, match: queryMatch }) => {
-  const templateMatch: DatabaseTemplate | undefined = useMemo(() => {
+  const templateMatch: DatastoreTemplate | undefined = useMemo(() => {
     const { params } = queryMatch;
     const validParams = z
       .object({
@@ -41,7 +41,7 @@ const CreateDatabase: React.FC<Props> = ({ history, match: queryMatch }) => {
       return undefined;
     }
 
-    return SUPPORTED_DATABASE_TEMPLATES.find(
+    return SUPPORTED_DATASTORE_TEMPLATES.find(
       (t) =>
         !t.disabled &&
         t.type === validParams.data.type &&
@@ -53,23 +53,26 @@ const CreateDatabase: React.FC<Props> = ({ history, match: queryMatch }) => {
     <StyledTemplateComponent>
       {match(templateMatch)
         .with(
-          { type: DATABASE_TYPE_RDS, engine: DATABASE_ENGINE_POSTGRES },
+          { type: DATASTORE_TYPE_RDS, engine: DATASTORE_ENGINE_POSTGRES },
           (t) => <DatabaseFormRDSPostgres template={t} />
         )
         .with(
-          { type: DATABASE_TYPE_RDS, engine: DATABASE_ENGINE_AURORA_POSTGRES },
+          {
+            type: DATASTORE_TYPE_RDS,
+            engine: DATASTORE_ENGINE_AURORA_POSTGRES,
+          },
           (t) => <DatabaseFormAuroraPostgres template={t} />
         )
         .with(
-          { type: DATABASE_TYPE_ELASTICACHE, engine: DATABASE_ENGINE_REDIS },
+          { type: DATASTORE_TYPE_ELASTICACHE, engine: DATASTORE_ENGINE_REDIS },
           (t) => <DatabaseFormElasticacheRedis template={t} />
         )
         .otherwise(() => (
           <>
-            <Back to="/databases" />
+            <Back to="/datastores" />
             <DashboardHeader
               image={database}
-              title="Create a new database"
+              title="Create a new datastore"
               capitalize={false}
               disableLineBreak
             />
@@ -80,7 +83,7 @@ const CreateDatabase: React.FC<Props> = ({ history, match: queryMatch }) => {
             </Text>
             <Spacer y={0.5} />
             <TemplateListWrapper>
-              {SUPPORTED_DATABASE_TEMPLATES.map((template) => {
+              {SUPPORTED_DATASTORE_TEMPLATES.map((template) => {
                 const { name, icon, description, disabled, engine, type } =
                   template;
                 return (
@@ -88,7 +91,7 @@ const CreateDatabase: React.FC<Props> = ({ history, match: queryMatch }) => {
                     disabled={disabled}
                     key={`${name}-${engine.name}`}
                     onClick={() => {
-                      history.push(`/databases/new/${type}/${engine.name}`);
+                      history.push(`/datastores/new/${type}/${engine.name}`);
                     }}
                   >
                     <TemplateHeader>

+ 14 - 14
dashboard/src/main/home/database-dashboard/DatabaseContextProvider.tsx

@@ -14,31 +14,31 @@ import api from "shared/api";
 import { Context } from "shared/Context";
 import notFound from "assets/not-found.png";
 
-import { SUPPORTED_DATABASE_TEMPLATES } from "./constants";
+import { SUPPORTED_DATASTORE_TEMPLATES } from "./constants";
 
-type DatabaseContextType = {
+type DatastoreContextType = {
   datastore: ClientDatastore;
   projectId: number;
 };
 
-const DatabaseContext = createContext<DatabaseContextType | null>(null);
+const DatastoreContext = createContext<DatastoreContextType | null>(null);
 
-export const useDatabaseContext = (): DatabaseContextType => {
-  const ctx = React.useContext(DatabaseContext);
+export const useDatastoreContext = (): DatastoreContextType => {
+  const ctx = React.useContext(DatastoreContext);
   if (!ctx) {
     throw new Error(
-      "useDatabaseContext must be used within a DatabaseContextProvider"
+      "useDatastoreContext must be used within a DatastoreContextProvider"
     );
   }
   return ctx;
 };
 
-type DatabaseContextProviderProps = {
+type DatastoreContextProviderProps = {
   datastoreName?: string;
   children: JSX.Element;
 };
-export const DatabaseContextProvider: React.FC<
-  DatabaseContextProviderProps
+export const DatastoreContextProvider: React.FC<
+  DatastoreContextProviderProps
 > = ({ datastoreName, children }) => {
   const { currentProject } = useContext(Context);
   const paramsExist =
@@ -63,7 +63,7 @@ export const DatabaseContextProvider: React.FC<
         .parseAsync(response.data);
 
       const datastore = results.datastore;
-      const matchingTemplate = SUPPORTED_DATABASE_TEMPLATES.find(
+      const matchingTemplate = SUPPORTED_DATASTORE_TEMPLATES.find(
         (t) => t.type === datastore.type && t.engine.name === datastore.engine
       );
 
@@ -93,24 +93,24 @@ export const DatabaseContextProvider: React.FC<
         <Container row>
           <PlaceholderIcon src={notFound} />
           <Text color="helper">
-            No database matching &quot;{datastoreName}&quot; was found.
+            No datastore matching &quot;{datastoreName}&quot; was found.
           </Text>
         </Container>
         <Spacer y={1} />
-        <Link to="/databases">Return to dashboard</Link>
+        <Link to="/datastores">Return to dashboard</Link>
       </Placeholder>
     );
   }
 
   return (
-    <DatabaseContext.Provider
+    <DatastoreContext.Provider
       value={{
         datastore,
         projectId: currentProject.id,
       }}
     >
       {children}
-    </DatabaseContext.Provider>
+    </DatastoreContext.Provider>
   );
 };
 

+ 18 - 32
dashboard/src/main/home/database-dashboard/DatabaseDashboard.tsx

@@ -19,7 +19,7 @@ import Text from "components/porter/Text";
 import Toggle from "components/porter/Toggle";
 import DashboardHeader from "main/home/cluster-dashboard/DashboardHeader";
 import { type ClientDatastore } from "lib/databases/types";
-import { useDatabaseList } from "lib/hooks/useDatabaseList";
+import { useDatastoreList } from "lib/hooks/useDatabaseList";
 
 import { Context } from "shared/Context";
 import { search } from "shared/search";
@@ -46,9 +46,9 @@ const DatabaseDashboard: React.FC = () => {
     "all" | "POSTGRES" | "AURORA-POSTGRES" | "REDIS"
   >("all");
 
-  const { datastores, isLoading } = useDatabaseList();
+  const { datastores, isLoading } = useDatastoreList();
 
-  const filteredDatabases = useMemo(() => {
+  const filteredDatastores = useMemo(() => {
     const filteredBySearch = search(datastores, searchValue, {
       keys: ["name"],
       isCaseSensitive: false,
@@ -89,21 +89,14 @@ const DatabaseDashboard: React.FC = () => {
     if (datastores.length === 0) {
       return (
         <DashboardPlaceholder>
-          <Text size={16}>No databases have been created yet</Text>
+          <Text size={16}>No datastores have been created yet</Text>
           <Spacer y={0.5} />
 
-          <Text color={"helper"}>Get started by creating a database.</Text>
+          <Text color={"helper"}>Get started by creating a datastore.</Text>
           <Spacer y={1} />
-          <PorterLink to="/databases/new">
-            <Button
-              onClick={async () =>
-                // TODO: add analytics
-                true
-              }
-              height="35px"
-              alt
-            >
-              Create database <Spacer inline x={1} />{" "}
+          <PorterLink to="/datastores/new">
+            <Button onClick={() => ({})} height="35px" alt>
+              Create datastore <Spacer inline x={1} />{" "}
               <i className="material-icons" style={{ fontSize: "18px" }}>
                 east
               </i>
@@ -198,7 +191,7 @@ const DatabaseDashboard: React.FC = () => {
             setValue={(x) => {
               setSearchValue(x);
             }}
-            placeholder="Search databases . . ."
+            placeholder="Search datastores . . ."
             width="100%"
           />
           <Spacer inline x={1} />
@@ -219,27 +212,20 @@ const DatabaseDashboard: React.FC = () => {
           />
 
           <Spacer inline x={2} />
-          <PorterLink to="/databases/new">
-            <Button
-              onClick={async () =>
-                // TODO: add analytics
-                true
-              }
-              height="30px"
-              width="70px"
-            >
+          <PorterLink to="/datastores/new">
+            <Button onClick={() => ({})} height="30px" width="70px">
               <I className="material-icons">add</I> New
             </Button>
           </PorterLink>
         </Container>
         <Spacer y={1} />
 
-        {filteredDatabases.length === 0 ? (
+        {filteredDatastores.length === 0 ? (
           <Fieldset>
             <Container row>
               <PlaceholderIcon src={notFound} />
               <Text color="helper">
-                No databases matching filters were found.
+                No datastores matching filters were found.
               </Text>
             </Container>
           </Fieldset>
@@ -247,10 +233,10 @@ const DatabaseDashboard: React.FC = () => {
           <Loading offset="-150px" />
         ) : view === "grid" ? (
           <GridList>
-            {(filteredDatabases ?? []).map(
+            {(filteredDatastores ?? []).map(
               (datastore: ClientDatastore, i: number) => {
                 return (
-                  <Link to={`/databases/${datastore.name}`} key={i}>
+                  <Link to={`/datastores/${datastore.name}`} key={i}>
                     <Block>
                       <Container row spaced>
                         <Container row>
@@ -283,10 +269,10 @@ const DatabaseDashboard: React.FC = () => {
           </GridList>
         ) : (
           <List>
-            {(filteredDatabases ?? []).map(
+            {(filteredDatastores ?? []).map(
               (datastore: ClientDatastore, i: number) => {
                 return (
-                  <Row to={`/databases/${datastore.name}`} key={i}>
+                  <Row to={`/datastores/${datastore.name}`} key={i}>
                     <Container row spaced>
                       <Container row>
                         <MidIcon src={datastore.template.icon} />
@@ -326,7 +312,7 @@ const DatabaseDashboard: React.FC = () => {
     <StyledAppDashboard>
       <DashboardHeader
         image={database}
-        title="Databases"
+        title="Datastores"
         description="Storage, caches, and stateful workloads for this project."
         disableLineBreak
       />

+ 2 - 2
dashboard/src/main/home/database-dashboard/DatabaseHeader.tsx

@@ -10,13 +10,13 @@ import Text from "components/porter/Text";
 
 import { readableDate } from "shared/string_utils";
 
-import { useDatabaseContext } from "./DatabaseContextProvider";
+import { useDatastoreContext } from "./DatabaseContextProvider";
 import { getDatastoreIcon } from "./icons";
 import EngineTag from "./tags/EngineTag";
 import { datastoreField } from "./utils";
 
 const DatabaseHeader: React.FC = () => {
-  const { datastore } = useDatabaseContext();
+  const { datastore } = useDatastoreContext();
 
   return (
     <>

+ 1 - 1
dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx

@@ -34,7 +34,7 @@ const DatabaseHeaderItem: React.FC<DatabaseHeaderItemProps> = ({ item }) => {
       <Text size={12}>{titleizeText(item.name)}</Text>
 
       <Container row>
-        <Text title={item.value} color="helper" size={10}>
+        <Text color="helper" size={10}>
           {truncateText(item.value, 42)}
         </Text>
         <CopyToClipboard text={item.value.toString()}>

+ 7 - 7
dashboard/src/main/home/database-dashboard/DatabaseTabs.tsx

@@ -5,11 +5,11 @@ import { match } from "ts-pattern";
 import Spacer from "components/porter/Spacer";
 import TabSelector from "components/TabSelector";
 
-import { useDatabaseContext } from "./DatabaseContextProvider";
+import { useDatastoreContext } from "./DatabaseContextProvider";
 import DatastoreProvisioningIndicator from "./DatastoreProvisioningIndicator";
 import ConfigurationTab from "./tabs/ConfigurationTab";
 import ConnectedAppsTab from "./tabs/ConnectedAppsTab";
-import DatabaseEnvTab from "./tabs/DatabaseEnvTab";
+import CredentialsTab from "./tabs/CredentialsTab";
 import MetricsTab from "./tabs/MetricsTab";
 import SettingsTab from "./tabs/SettingsTab";
 
@@ -20,7 +20,7 @@ const validTabs = [
   "settings",
   "connected-apps",
 ] as const;
-const DEFAULT_TAB = "connected-apps";
+const DEFAULT_TAB = "credentials";
 type ValidTab = (typeof validTabs)[number];
 
 type DbTabProps = {
@@ -32,7 +32,7 @@ export type ButtonStatus = "" | "loading" | JSX.Element | "success";
 
 const DatabaseTabs: React.FC<DbTabProps> = ({ tabParam }) => {
   const history = useHistory();
-  const { datastore } = useDatabaseContext();
+  const { datastore } = useDatastoreContext();
 
   const currentTab = useMemo(() => {
     if (tabParam && validTabs.includes(tabParam as ValidTab)) {
@@ -44,8 +44,8 @@ const DatabaseTabs: React.FC<DbTabProps> = ({ tabParam }) => {
 
   const tabs = useMemo(() => {
     return [
-      { label: "Connected Apps", value: "connected-apps" },
       { label: "Credentials", value: "credentials" },
+      { label: "Connected Apps", value: "connected-apps" },
       { label: "Configuration", value: "configuration" },
       { label: "Settings", value: "settings" },
     ];
@@ -62,12 +62,12 @@ const DatabaseTabs: React.FC<DbTabProps> = ({ tabParam }) => {
         options={tabs}
         currentTab={currentTab}
         setCurrentTab={(tab) => {
-          history.push(`/databases/${datastore.name}/${tab}`);
+          history.push(`/datastores/${datastore.name}/${tab}`);
         }}
       />
       <Spacer y={1} />
       {match(currentTab)
-        .with("credentials", () => <DatabaseEnvTab envData={datastore.env} />)
+        .with("credentials", () => <CredentialsTab />)
         .with("settings", () => <SettingsTab />)
         .with("metrics", () => <MetricsTab />)
         .with("configuration", () => <ConfigurationTab />)

+ 4 - 4
dashboard/src/main/home/database-dashboard/DatabaseView.tsx

@@ -6,7 +6,7 @@ import { z } from "zod";
 import Back from "components/porter/Back";
 import Spacer from "components/porter/Spacer";
 
-import { DatabaseContextProvider } from "./DatabaseContextProvider";
+import { DatastoreContextProvider } from "./DatabaseContextProvider";
 import DatabaseHeader from "./DatabaseHeader";
 import DatabaseTabs from "./DatabaseTabs";
 
@@ -32,14 +32,14 @@ const DatabaseView: React.FC<Props> = ({ match }) => {
   }, [match]);
 
   return (
-    <DatabaseContextProvider datastoreName={params.datastoreName}>
+    <DatastoreContextProvider datastoreName={params.datastoreName}>
       <StyledExpandedDB>
-        <Back to="/databases" />
+        <Back to="/datastores" />
         <DatabaseHeader />
         <Spacer y={1} />
         <DatabaseTabs tabParam={params.tab} />
       </StyledExpandedDB>
-    </DatabaseContextProvider>
+    </DatastoreContextProvider>
   );
 };
 

+ 6 - 6
dashboard/src/main/home/database-dashboard/DatastoreProvisioningIndicator.tsx

@@ -3,14 +3,14 @@ import { match } from "ts-pattern";
 
 import StatusBar from "components/porter/StatusBar";
 import {
-  DATABASE_TYPE_ELASTICACHE,
-  DATABASE_TYPE_RDS,
+  DATASTORE_TYPE_ELASTICACHE,
+  DATASTORE_TYPE_RDS,
 } from "lib/databases/types";
 
-import { useDatabaseContext } from "./DatabaseContextProvider";
+import { useDatastoreContext } from "./DatabaseContextProvider";
 
 const DatastoreProvisioningIndicator: React.FC = () => {
-  const { datastore } = useDatabaseContext();
+  const { datastore } = useDatastoreContext();
 
   const { percentCompleted, title, titleDescriptor } = useMemo(() => {
     const creationSteps = datastore.template.creationStateProgression.map(
@@ -22,9 +22,9 @@ const DatastoreProvisioningIndicator: React.FC = () => {
         ? 0
         : (stepsCompleted / creationSteps.length) * 100.0;
     const title = match(datastore.template)
-      .with({ type: DATABASE_TYPE_RDS }, () => "RDS provisioning status")
+      .with({ type: DATASTORE_TYPE_RDS }, () => "RDS provisioning status")
       .with(
-        { type: DATABASE_TYPE_ELASTICACHE },
+        { type: DATASTORE_TYPE_ELASTICACHE },
         () => "Elasticache provisioning status"
       )
       .exhaustive();

+ 33 - 33
dashboard/src/main/home/database-dashboard/constants.ts

@@ -1,27 +1,27 @@
 import {
-  DATABASE_ENGINE_AURORA_POSTGRES,
-  DATABASE_ENGINE_MEMCACHED,
-  DATABASE_ENGINE_POSTGRES,
-  DATABASE_ENGINE_REDIS,
-  DATABASE_STATE_AVAILABLE,
-  DATABASE_STATE_BACKING_UP,
-  DATABASE_STATE_CONFIGURING_ENHANCED_MONITORING,
-  DATABASE_STATE_CONFIGURING_LOG_EXPORTS,
-  DATABASE_STATE_CREATING,
-  DATABASE_STATE_MODIFYING,
-  DATABASE_TYPE_ELASTICACHE,
-  DATABASE_TYPE_RDS,
-  type DatabaseTemplate,
+  DATASTORE_ENGINE_AURORA_POSTGRES,
+  DATASTORE_ENGINE_MEMCACHED,
+  DATASTORE_ENGINE_POSTGRES,
+  DATASTORE_ENGINE_REDIS,
+  DATASTORE_STATE_AVAILABLE,
+  DATASTORE_STATE_BACKING_UP,
+  DATASTORE_STATE_CONFIGURING_ENHANCED_MONITORING,
+  DATASTORE_STATE_CONFIGURING_LOG_EXPORTS,
+  DATASTORE_STATE_CREATING,
+  DATASTORE_STATE_MODIFYING,
+  DATASTORE_TYPE_ELASTICACHE,
+  DATASTORE_TYPE_RDS,
+  type DatastoreTemplate,
 } from "lib/databases/types";
 
 import awsRDS from "assets/amazon-rds.png";
 import awsElastiCache from "assets/aws-elasticache.png";
 
-export const SUPPORTED_DATABASE_TEMPLATES: DatabaseTemplate[] = [
+export const SUPPORTED_DATASTORE_TEMPLATES: DatastoreTemplate[] = [
   Object.freeze({
     name: "Amazon RDS",
-    type: DATABASE_TYPE_RDS,
-    engine: DATABASE_ENGINE_POSTGRES,
+    type: DATASTORE_TYPE_RDS,
+    engine: DATASTORE_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.",
@@ -51,18 +51,18 @@ export const SUPPORTED_DATABASE_TEMPLATES: DatabaseTemplate[] = [
     ],
     formTitle: "Create an RDS PostgreSQL instance",
     creationStateProgression: [
-      DATABASE_STATE_CREATING,
-      DATABASE_STATE_CONFIGURING_LOG_EXPORTS,
-      DATABASE_STATE_MODIFYING,
-      DATABASE_STATE_CONFIGURING_ENHANCED_MONITORING,
-      DATABASE_STATE_BACKING_UP,
-      DATABASE_STATE_AVAILABLE,
+      DATASTORE_STATE_CREATING,
+      DATASTORE_STATE_CONFIGURING_LOG_EXPORTS,
+      DATASTORE_STATE_MODIFYING,
+      DATASTORE_STATE_CONFIGURING_ENHANCED_MONITORING,
+      DATASTORE_STATE_BACKING_UP,
+      DATASTORE_STATE_AVAILABLE,
     ],
   }),
   Object.freeze({
     name: "Amazon Aurora",
-    type: DATABASE_TYPE_RDS,
-    engine: DATABASE_ENGINE_AURORA_POSTGRES,
+    type: DATASTORE_TYPE_RDS,
+    engine: DATASTORE_ENGINE_AURORA_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.",
@@ -85,14 +85,14 @@ export const SUPPORTED_DATABASE_TEMPLATES: DatabaseTemplate[] = [
     ],
     formTitle: "Create an Aurora PostgreSQL instance",
     creationStateProgression: [
-      DATABASE_STATE_CREATING,
-      DATABASE_STATE_AVAILABLE,
+      DATASTORE_STATE_CREATING,
+      DATASTORE_STATE_AVAILABLE,
     ],
   }),
   Object.freeze({
     name: "Amazon ElastiCache",
-    type: DATABASE_TYPE_ELASTICACHE,
-    engine: DATABASE_ENGINE_REDIS,
+    type: DATASTORE_TYPE_ELASTICACHE,
+    engine: DATASTORE_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.",
@@ -129,15 +129,15 @@ export const SUPPORTED_DATABASE_TEMPLATES: DatabaseTemplate[] = [
     ],
     formTitle: "Create an ElastiCache Redis instance",
     creationStateProgression: [
-      DATABASE_STATE_CREATING,
-      DATABASE_STATE_MODIFYING,
-      DATABASE_STATE_AVAILABLE,
+      DATASTORE_STATE_CREATING,
+      DATASTORE_STATE_MODIFYING,
+      DATASTORE_STATE_AVAILABLE,
     ],
   }),
   Object.freeze({
     name: "Amazon ElastiCache",
-    type: DATABASE_TYPE_ELASTICACHE,
-    engine: DATABASE_ENGINE_MEMCACHED,
+    type: DATASTORE_TYPE_ELASTICACHE,
+    engine: DATASTORE_ENGINE_MEMCACHED,
     icon: awsElastiCache as string,
     description:
       "Currently unavailable. Please contact support@porter.run for more details.",

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

@@ -14,8 +14,8 @@ import Text from "components/porter/Text";
 import VerticalSteps from "components/porter/VerticalSteps";
 import { type DbFormData } from "lib/databases/types";
 import { useClusterList } from "lib/hooks/useClusterList";
-import { useDatabaseList } from "lib/hooks/useDatabaseList";
-import { useDatabaseMethods } from "lib/hooks/useDatabaseMethods";
+import { useDatastoreList } from "lib/hooks/useDatabaseList";
+import { useDatastoreMethods } from "lib/hooks/useDatabaseMethods";
 import { useIntercom } from "lib/hooks/useIntercom";
 
 import { Context } from "shared/Context";
@@ -33,7 +33,7 @@ const DatabaseForm: React.FC<Props> = ({
   history,
 }) => {
   const [submitErrorMessage, setSubmitErrorMessage] = useState<string>("");
-  const { create: createDatabase } = useDatabaseMethods();
+  const { create: createDatastore } = useDatastoreMethods();
   const { showIntercomWithMessage } = useIntercom();
   const { clusters } = useClusterList();
   const { currentProject } = useContext(Context);
@@ -46,29 +46,29 @@ const DatabaseForm: React.FC<Props> = ({
     watch,
   } = form;
 
-  const { datastores: existingDatabases } = useDatabaseList();
+  const { datastores: existingDatastores } = useDatastoreList();
 
   const chosenClusterId = watch("clusterId", 0);
 
   const onSubmit = handleSubmit(async (data) => {
     setSubmitErrorMessage("");
-    if (existingDatabases.some((db) => db.name === data.name)) {
+    if (existingDatastores.some((db) => db.name === data.name)) {
       setSubmitErrorMessage(
-        "A database with this name already exists. Please choose a different name."
+        "A datastore with this name already exists. Please choose a different name."
       );
       return;
     }
     try {
-      await createDatabase(data);
-      history.push(`/databases/${data.name}`);
+      await createDatastore(data);
+      history.push(`/datastores/${data.name}`);
     } catch (err) {
       const errorMessage =
         axios.isAxiosError(err) && err.response?.data?.error
           ? err.response.data.error
-          : "An error occurred while creating your database. Please try again.";
+          : "An error occurred while creating your datastore. Please try again.";
       setSubmitErrorMessage(errorMessage);
       showIntercomWithMessage({
-        message: "I am having trouble creating a database.",
+        message: "I am having trouble creating a datastore.",
       });
     }
   });

+ 3 - 3
dashboard/src/main/home/database-dashboard/forms/DatabaseFormAuroraPostgres.tsx

@@ -14,7 +14,7 @@ import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import {
   dbFormValidator,
-  type DatabaseTemplate,
+  type DatastoreTemplate,
   type DbFormData,
   type ResourceOption,
 } from "lib/databases/types";
@@ -33,7 +33,7 @@ import DatabaseForm, {
 } from "./DatabaseForm";
 
 type Props = RouteComponentProps & {
-  template: DatabaseTemplate;
+  template: DatastoreTemplate;
 };
 
 const DatabaseFormAuroraPostgres: React.FC<Props> = ({ history, template }) => {
@@ -83,7 +83,7 @@ const DatabaseFormAuroraPostgres: React.FC<Props> = ({ history, template }) => {
         <StyledConfigureTemplate>
           <Back
             onClick={() => {
-              history.push(`/databases/new`);
+              history.push(`/datastores/new`);
             }}
           />
           <DashboardHeader

+ 3 - 3
dashboard/src/main/home/database-dashboard/forms/DatabaseFormElasticacheRedis.tsx

@@ -14,7 +14,7 @@ import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import {
   dbFormValidator,
-  type DatabaseTemplate,
+  type DatastoreTemplate,
   type DbFormData,
   type ResourceOption,
 } from "lib/databases/types";
@@ -33,7 +33,7 @@ import DatabaseForm, {
 } from "./DatabaseForm";
 
 type Props = RouteComponentProps & {
-  template: DatabaseTemplate;
+  template: DatastoreTemplate;
 };
 
 const DatabaseFormElasticacheRedis: React.FC<Props> = ({
@@ -84,7 +84,7 @@ const DatabaseFormElasticacheRedis: React.FC<Props> = ({
         <StyledConfigureTemplate>
           <Back
             onClick={() => {
-              history.push(`/databases/new`);
+              history.push(`/datastores/new`);
             }}
           />
           <DashboardHeader

+ 3 - 3
dashboard/src/main/home/database-dashboard/forms/DatabaseFormRDSPostgres.tsx

@@ -14,7 +14,7 @@ import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import {
   dbFormValidator,
-  type DatabaseTemplate,
+  type DatastoreTemplate,
   type DbFormData,
   type ResourceOption,
 } from "lib/databases/types";
@@ -33,7 +33,7 @@ import DatabaseForm, {
 } from "./DatabaseForm";
 
 type Props = RouteComponentProps & {
-  template: DatabaseTemplate;
+  template: DatastoreTemplate;
 };
 
 const DatabaseFormRDSPostgres: React.FC<Props> = ({ history, template }) => {
@@ -83,7 +83,7 @@ const DatabaseFormRDSPostgres: React.FC<Props> = ({ history, template }) => {
         <StyledConfigureTemplate>
           <Back
             onClick={() => {
-              history.push(`/databases/new`);
+              history.push(`/datastores/new`);
             }}
           />
           <DashboardHeader

+ 10 - 10
dashboard/src/main/home/database-dashboard/icons.tsx

@@ -1,9 +1,9 @@
 import {
-  DATABASE_ENGINE_AURORA_POSTGRES,
-  DATABASE_ENGINE_POSTGRES,
-  DATABASE_ENGINE_REDIS,
-  DATABASE_TYPE_ELASTICACHE,
-  DATABASE_TYPE_RDS,
+  DATASTORE_ENGINE_AURORA_POSTGRES,
+  DATASTORE_ENGINE_POSTGRES,
+  DATASTORE_ENGINE_REDIS,
+  DATASTORE_TYPE_ELASTICACHE,
+  DATASTORE_TYPE_RDS,
 } from "lib/databases/types";
 
 import awsRDS from "assets/amazon-rds.png";
@@ -14,14 +14,14 @@ import postgresql from "assets/postgresql.svg";
 import redis from "assets/redis.svg";
 
 const datastoreIcons: Record<string, string> = {
-  [DATABASE_TYPE_ELASTICACHE]: awsElasticache,
-  [DATABASE_TYPE_RDS]: awsRDS,
+  [DATASTORE_TYPE_ELASTICACHE]: awsElasticache,
+  [DATASTORE_TYPE_RDS]: awsRDS,
 };
 
 const engineIcons: Record<string, string> = {
-  [DATABASE_ENGINE_POSTGRES.name]: postgresql,
-  [DATABASE_ENGINE_AURORA_POSTGRES.name]: postgresql,
-  [DATABASE_ENGINE_REDIS.name]: redis,
+  [DATASTORE_ENGINE_POSTGRES.name]: postgresql,
+  [DATASTORE_ENGINE_AURORA_POSTGRES.name]: postgresql,
+  [DATASTORE_ENGINE_REDIS.name]: redis,
 };
 
 export const getDatastoreIcon = (datastoreType: string): string => {

+ 1 - 1
dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx

@@ -68,7 +68,7 @@ const ConnectAppsModal: React.FC<Props> = ({ closeModal, apps, onSubmit }) => {
       }
       setSubmitErrorMessage(message);
       showIntercomWithMessage({
-        message: "I am having trouble connecting apps to my database.",
+        message: "I am having trouble connecting apps to my datastore.",
       });
     } finally {
       setIsSubmitting(false);

+ 3 - 3
dashboard/src/main/home/database-dashboard/tabs/ConfigurationTab.tsx

@@ -5,14 +5,14 @@ import Fieldset from "components/porter/Fieldset";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 
-import { useDatabaseContext } from "../DatabaseContextProvider";
+import { useDatastoreContext } from "../DatabaseContextProvider";
 import DatabaseHeaderItem from "../DatabaseHeaderItem";
 
 const ConfigurationTab: React.FC = () => {
-  const { datastore } = useDatabaseContext();
+  const { datastore } = useDatastoreContext();
   return (
     <Fieldset>
-      <Text size={12}>Database details: </Text>
+      <Text size={12}>Datastore details: </Text>
       <Spacer y={0.5} />
 
       {datastore.metadata !== undefined && datastore.metadata?.length > 0 && (

+ 5 - 11
dashboard/src/main/home/database-dashboard/tabs/ConnectedAppsTab.tsx

@@ -7,26 +7,26 @@ import Container from "components/porter/Container";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import SelectableAppList from "main/home/app-dashboard/apps/SelectableAppList";
-import { useDatabaseMethods } from "lib/hooks/useDatabaseMethods";
+import { useDatastoreMethods } from "lib/hooks/useDatabaseMethods";
 import { useLatestAppRevisions } from "lib/hooks/useLatestAppRevisions";
 
 import { Context } from "shared/Context";
 
-import { useDatabaseContext } from "../DatabaseContextProvider";
+import { useDatastoreContext } from "../DatabaseContextProvider";
 import ConnectAppsModal from "../shared/ConnectAppsModal";
 
 const ConnectedAppsTab: React.FC = () => {
   const [showConnectAppsModal, setShowConnectAppsModal] = useState(false);
-  const { projectId, datastore } = useDatabaseContext();
+  const { projectId, datastore } = useDatastoreContext();
   // NB: the cluster id here is coming from the global context, but really it should be coming from
-  // the database context. However, we do not currently have a way to relate db to the cluster it lives in.
+  // the datastore context. However, we do not currently have a way to relate db to the cluster it lives in.
   // This will be a bug for multi-cluster projects.
   const { currentCluster: { id: clusterId = 0 } = {} } = useContext(Context);
   const { revisions } = useLatestAppRevisions({
     projectId,
     clusterId,
   });
-  const { attachDatastoreToAppInstances } = useDatabaseMethods();
+  const { attachDatastoreToAppInstances } = useDatastoreMethods();
   const history = useHistory();
 
   const { connectedApps, remainingApps } = useMemo(() => {
@@ -49,12 +49,6 @@ const ConnectedAppsTab: React.FC = () => {
       <Container row>
         <Text size={16}>Connected Apps</Text>
       </Container>
-      <Spacer y={0.5} />
-      <Text color="helper">
-        Credentials for this datastore are injected as environment variables to
-        connected apps.
-      </Text>
-      <Spacer y={0.5} />
       <SelectableAppList
         appListItems={connectedApps.map((ra) => ({
           app: ra,

+ 161 - 0
dashboard/src/main/home/database-dashboard/tabs/CredentialsTab.tsx

@@ -0,0 +1,161 @@
+import React, { useMemo } from "react";
+import styled from "styled-components";
+
+import CopyToClipboard from "components/CopyToClipboard";
+import Container from "components/porter/Container";
+import Input from "components/porter/Input";
+import Link from "components/porter/Link";
+import Spacer from "components/porter/Spacer";
+import Text from "components/porter/Text";
+
+import copy from "assets/copy-left.svg";
+
+import { useDatastoreContext } from "../DatabaseContextProvider";
+
+const CredentialsTab: React.FC = () => {
+  const { datastore } = useDatastoreContext();
+
+  const keyValues = useMemo(() => {
+    const datastoreEnvEntries = Object.entries(datastore.env?.variables ?? {});
+    const datastoreSecretEntries = Object.entries(
+      datastore.env?.secret_variables ?? {}
+    );
+    const keyValues = [
+      ...datastoreEnvEntries.map(([key, value]) => ({
+        key,
+        value,
+        secret: false,
+      })),
+      ...datastoreSecretEntries.map(([key, value]) => ({
+        key,
+        value,
+        secret: true,
+      })),
+    ];
+
+    return keyValues;
+  }, [datastore]);
+  return (
+    <CredentialsTabContainer>
+      <Container row>
+        <Text size={16}>Credentials</Text>
+      </Container>
+      {keyValues.length !== 0 && (
+        <>
+          <Spacer y={0.5} />
+          <Text color="helper">
+            Once an app is connected to this datastore, it has access to its
+            credentials through the following environment variables:
+          </Text>
+          <StyledInputArray>
+            {keyValues.map(
+              (
+                entry: { key: string; value: string; secret: boolean },
+                i: number
+              ) => {
+                return (
+                  <InputWrapper key={i}>
+                    <Input
+                      placeholder="ex: key"
+                      width="120px"
+                      value={entry.key}
+                      setValue={() => ({})}
+                      disabled={entry.secret}
+                      disabledTooltip={"Stored as a secret on your cluster"}
+                    />
+                    <Spacer x={0.5} inline />
+                    <Input
+                      placeholder="ex: key"
+                      width="500px"
+                      value={entry.value}
+                      setValue={() => ({})}
+                      disabled={entry.secret}
+                      disabledTooltip={"Stored as a secret on your cluster"}
+                    />
+                    {!entry.secret && (
+                      <>
+                        <Spacer x={0.5} inline />
+                        <CopyToClipboard text={entry.value}>
+                          <CopyIcon src={copy} alt="copy" />
+                        </CopyToClipboard>
+                      </>
+                    )}
+                  </InputWrapper>
+                );
+              }
+            )}
+          </StyledInputArray>
+        </>
+      )}
+      <Spacer y={0.5} />
+      <Text size={16}>Connect</Text>
+      <Spacer y={0.5} />
+      <Text color="helper">
+        If you have the{" "}
+        <Link to="https://docs.porter.run/cli/installation" target="_blank">
+          <Text>Porter CLI</Text>
+        </Link>{" "}
+        installed, you can connect to this datastore locally by running the
+        following command:
+      </Text>
+      <Spacer y={0.5} />
+      <IdContainer>
+        <Code>{`$ porter datastore connect ${datastore.name}`}</Code>
+        <CopyContainer>
+          <CopyToClipboard text={`porter datastore connect ${datastore.name}`}>
+            <CopyIcon src={copy} alt="copy" />
+          </CopyToClipboard>
+        </CopyContainer>
+      </IdContainer>
+    </CredentialsTabContainer>
+  );
+};
+
+export default CredentialsTab;
+
+const CredentialsTabContainer = styled.div`
+  width: 100%;
+`;
+
+const IdContainer = styled.div`
+  width: fit-content;
+  background: #000000;
+  border-radius: 5px;
+  padding: 10px;
+  display: flex;
+  border-radius: 5px;
+  border: 1px solid ${({ theme }) => theme.border};
+  align-items: center;
+`;
+
+const CopyContainer = styled.div`
+  display: flex;
+  align-items: center;
+  margin-left: auto;
+`;
+
+const CopyIcon = styled.img`
+  cursor: pointer;
+  margin-left: 5px;
+  margin-right: 5px;
+  width: 15px;
+  height: 15px;
+  :hover {
+    opacity: 0.8;
+  }
+`;
+
+const Code = styled.span`
+  font-family: monospace;
+`;
+
+const StyledInputArray = styled.div`
+  margin-bottom: 15px;
+  margin-top: 22px;
+`;
+
+const InputWrapper = styled.div`
+  display: flex;
+  align-items: center;
+  margin-top: 5px;
+`;

+ 0 - 151
dashboard/src/main/home/database-dashboard/tabs/DatabaseEnvTab.tsx

@@ -1,151 +0,0 @@
-import React from "react";
-import styled from "styled-components";
-
-import CopyToClipboard from "components/CopyToClipboard";
-import Helper from "components/form-components/Helper";
-import Spacer from "components/porter/Spacer";
-import Text from "components/porter/Text";
-import EnvGroupArray from "main/home/cluster-dashboard/env-groups/EnvGroupArray";
-import { type DatastoreEnvWithSource } from "lib/databases/types";
-
-import copy from "assets/copy-left.svg";
-
-type Props = {
-  envData: DatastoreEnvWithSource;
-  connectionString?: string;
-};
-
-export type KeyValueType = {
-  key: string;
-  value: string;
-  hidden: boolean;
-  locked: boolean;
-  deleted: boolean;
-};
-
-const DatabaseEnvTab: React.FC<Props> = ({ envData, connectionString }) => {
-  const setKeys = (): KeyValueType[] => {
-    const keys: KeyValueType[] = [];
-    if (envData != null) {
-      Object.entries(envData?.variables).forEach(([key, value]) => {
-        keys.push({ key, value, hidden: false, locked: false, deleted: false });
-      });
-
-      // Adding secret variables with locked set to true
-      Object.entries(envData?.secret_variables).forEach(([key, value]) => {
-        keys.push({ key, value, hidden: false, locked: true, deleted: false });
-      });
-    }
-
-    return keys;
-  };
-
-  return (
-    <StyledTemplateComponent>
-      <InnerWrapper>
-        <Text size={16}>Environment Variables</Text>
-        <Helper>
-          These environment variables are available to your applications once
-          the &quot;{envData.name}&quot; env group is linked to your app.
-        </Helper>
-        <EnvGroupArray
-          values={setKeys()}
-          setValues={(_) => {}}
-          fileUpload={true}
-          secretOption={false}
-          disabled={true}
-        />
-      </InnerWrapper>
-      {connectionString && (
-        <InnerWrapper>
-          <Text size={16}>Connection String</Text>
-          <Spacer y={0.5} />
-          <IdContainer>
-            <ConnectionContainer>
-              <IconWithName>Connection String: </IconWithName>
-              <CopyContainer>
-                <IdText> {connectionString}</IdText>
-                <CopyToClipboard text={connectionString.toString()}>
-                  <CopyIcon src={copy} alt="copy" />
-                </CopyToClipboard>
-              </CopyContainer>
-            </ConnectionContainer>
-          </IdContainer>
-          <Spacer y={1} />
-        </InnerWrapper>
-      )}
-    </StyledTemplateComponent>
-  );
-};
-
-export default DatabaseEnvTab;
-
-const StyledTemplateComponent = styled.div`
-  width: 100%;
-  animation: fadeIn 0.3s 0s;
-  @keyframes fadeIn {
-    from {
-      opacity: 0;
-    }
-    to {
-      opacity: 1;
-    }
-  }
-`;
-
-const IdContainer = styled.div`
-  color: #aaaabb;
-  border-radius: 5px;
-  padding: 5px;
-  padding-left: 10px;
-  display: block;
-  width: 100%;
-  border-radius: 5px;
-  background: ${(props) => props.theme.fg};
-  border: 1px solid ${({ theme }) => theme.border};
-  margin-bottom: 10px;
-`;
-
-const ConnectionContainer = styled.div`
-  padding: 5px;
-  display: flex;
-  justify-content: flex-start;
-  align-items: center;
-`;
-
-const IconWithName = styled.span`
-  font-size: 0.8em;
-  margin-left: 10px;
-`;
-
-const CopyContainer = styled.div`
-  display: flex;
-  align-items: center;
-  margin-left: auto;
-`;
-
-const IdText = styled.span`
-  font-size: 0.8em;
-  margin-right: 5px;
-`;
-
-const CopyIcon = styled.img`
-  cursor: pointer;
-  margin-left: 5px;
-  margin-right: 5px;
-  width: 10px;
-  height: 10px;
-`;
-
-const InnerWrapper = styled.div<{ full?: boolean }>`
-  width: 100%;
-  height: ${(props) => (props.full ? "100%" : "calc(100% - 65px)")};
-  padding: 30px;
-  padding-bottom: 15px;
-  position: relative;
-  overflow: auto;
-  margin-bottom: 30px;
-  border-radius: 5px;
-  background: ${(props) => props.theme.fg};
-  border: 1px solid #494b4f;
-`;

+ 6 - 6
dashboard/src/main/home/database-dashboard/tabs/SettingsTab.tsx

@@ -5,17 +5,17 @@ import styled from "styled-components";
 import Button from "components/porter/Button";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
-import { useDatabaseMethods } from "lib/hooks/useDatabaseMethods";
+import { useDatastoreMethods } from "lib/hooks/useDatabaseMethods";
 
 import { Context } from "shared/Context";
 
-import { useDatabaseContext } from "../DatabaseContextProvider";
+import { useDatastoreContext } from "../DatabaseContextProvider";
 
 const SettingsTab: React.FC = () => {
   const { setCurrentOverlay } = useContext(Context);
   const history = useHistory();
-  const { datastore } = useDatabaseContext();
-  const { deleteDatastore } = useDatabaseMethods();
+  const { datastore } = useDatastoreContext();
+  const { deleteDatastore } = useDatastoreMethods();
   const handleDeletionSubmit = async (): Promise<void> => {
     if (setCurrentOverlay == null) {
       return;
@@ -24,7 +24,7 @@ const SettingsTab: React.FC = () => {
     try {
       await deleteDatastore(datastore.name);
       setCurrentOverlay(null);
-      history.push("/databases");
+      history.push("/datastores");
     } catch (error) {
       // todo: handle error
     }
@@ -50,7 +50,7 @@ const SettingsTab: React.FC = () => {
         <Text size={16}>Delete &quot;{datastore.name}&quot;</Text>
         <Spacer y={0.5} />
         <Text color="helper">
-          Delete this database and all of its resources.
+          Delete this datastore and all of its resources.
         </Text>
         <Spacer y={0.5} />
         <Button color="#b91133" onClick={handleDeletionClick}>

+ 2 - 2
dashboard/src/main/home/database-dashboard/tags/EngineTag.tsx

@@ -6,13 +6,13 @@ import Icon from "components/porter/Icon";
 import Spacer from "components/porter/Spacer";
 import Tag from "components/porter/Tag";
 import Text from "components/porter/Text";
-import { type DatabaseEngine } from "lib/databases/types";
+import { type DatastoreEngine } from "lib/databases/types";
 
 import postgresql from "assets/postgresql.svg";
 import redis from "assets/redis.svg";
 
 type Props = {
-  engine: DatabaseEngine;
+  engine: DatastoreEngine;
   heightPixels?: number;
 };
 

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

@@ -208,11 +208,11 @@ class Sidebar extends Component<PropsType, StateType> {
               )}
             {currentProject.db_enabled && (
               <NavButton
-                path="/databases"
+                path="/datastores"
                 active={window.location.pathname.startsWith("/apps")}
               >
                 <Img src={database} />
-                Databases
+                Datastores
               </NavButton>
             )}
             {currentCluster && (
@@ -288,11 +288,11 @@ class Sidebar extends Component<PropsType, StateType> {
             </NavButton>
             {currentProject.db_enabled && (
               <NavButton
-                path="/databases"
+                path="/datastores"
                 active={window.location.pathname.startsWith("/apps")}
               >
                 <Img src={database} />
-                Databases
+                Datastores
               </NavButton>
             )}
             <NavButton

+ 1 - 0
dashboard/src/shared/routing.tsx

@@ -32,6 +32,7 @@ export const PorterUrls = [
   "jobs",
   "onboarding",
   "databases",
+  "datastores",
   "preview-environments",
   "apps",
   "addons",