diff --git a/dashboard/src/lib/databases/types.ts b/dashboard/src/lib/databases/types.ts index f911db5275..620392abb7 100644 --- a/dashboard/src/lib/databases/types.ts +++ b/dashboard/src/lib/databases/types.ts @@ -41,99 +41,77 @@ export const datastoreValidator = z.object({ export type SerializedDatastore = z.infer; 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; - -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["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["type"]; -export const DATABASE_TYPE_RDS = "RDS" as const; -export const DATABASE_TYPE_ELASTICACHE = "ELASTICACHE" as const; +export type DatastoreType = z.infer["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["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([ diff --git a/dashboard/src/lib/hooks/useDatabaseList.ts b/dashboard/src/lib/hooks/useDatabaseList.ts index d903fd4ca6..bc9e6f7d8b 100644 --- a/dashboard/src/lib/hooks/useDatabaseList.ts +++ b/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; +type DatastoreListType = { + datastores: Array; 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 ); diff --git a/dashboard/src/lib/hooks/useDatabaseMethods.ts b/dashboard/src/lib/hooks/useDatabaseMethods.ts index 1383741ec4..5031ea3dec 100644 --- a/dashboard/src/lib/hooks/useDatabaseMethods.ts +++ b/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; deleteDatastore: (name: string) => Promise; 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(); diff --git a/dashboard/src/main/home/Home.tsx b/dashboard/src/main/home/Home.tsx index 609950e92f..50e623303f 100644 --- a/dashboard/src/main/home/Home.tsx +++ b/dashboard/src/main/home/Home.tsx @@ -472,19 +472,19 @@ const Home: React.FC = (props) => { )} - + - + - + - + - + @@ -544,7 +544,7 @@ const Home: React.FC = (props) => { "/applications", "/jobs", "/env-groups", - "/databases", + "/datastores", ...(!currentProject?.validate_apply_v2 ? ["/preview-environments"] : []), diff --git a/dashboard/src/main/home/database-dashboard/CreateDatabase.tsx b/dashboard/src/main/home/database-dashboard/CreateDatabase.tsx index d780ea165c..38ec316e24 100644 --- a/dashboard/src/main/home/database-dashboard/CreateDatabase.tsx +++ b/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 = ({ 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 = ({ 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 = ({ history, match: queryMatch }) => { {match(templateMatch) .with( - { type: DATABASE_TYPE_RDS, engine: DATABASE_ENGINE_POSTGRES }, + { type: DATASTORE_TYPE_RDS, engine: DATASTORE_ENGINE_POSTGRES }, (t) => ) .with( - { type: DATABASE_TYPE_RDS, engine: DATABASE_ENGINE_AURORA_POSTGRES }, + { + type: DATASTORE_TYPE_RDS, + engine: DATASTORE_ENGINE_AURORA_POSTGRES, + }, (t) => ) .with( - { type: DATABASE_TYPE_ELASTICACHE, engine: DATABASE_ENGINE_REDIS }, + { type: DATASTORE_TYPE_ELASTICACHE, engine: DATASTORE_ENGINE_REDIS }, (t) => ) .otherwise(() => ( <> - + @@ -80,7 +83,7 @@ const CreateDatabase: React.FC = ({ history, match: queryMatch }) => { - {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 = ({ history, match: queryMatch }) => { disabled={disabled} key={`${name}-${engine.name}`} onClick={() => { - history.push(`/databases/new/${type}/${engine.name}`); + history.push(`/datastores/new/${type}/${engine.name}`); }} > diff --git a/dashboard/src/main/home/database-dashboard/DatabaseContextProvider.tsx b/dashboard/src/main/home/database-dashboard/DatabaseContextProvider.tsx index 7ec0edfb95..1aabc4074d 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseContextProvider.tsx +++ b/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(null); +const DatastoreContext = createContext(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< - No database matching "{datastoreName}" was found. + No datastore matching "{datastoreName}" was found. - Return to dashboard + Return to dashboard ); } return ( - {children} - + ); }; diff --git a/dashboard/src/main/home/database-dashboard/DatabaseDashboard.tsx b/dashboard/src/main/home/database-dashboard/DatabaseDashboard.tsx index b3640a5d02..2be81ebff0 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseDashboard.tsx +++ b/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 ( - No databases have been created yet + No datastores have been created yet - Get started by creating a database. + Get started by creating a datastore. - - - {filteredDatabases.length === 0 ? ( + {filteredDatastores.length === 0 ? (
- No databases matching filters were found. + No datastores matching filters were found.
@@ -247,10 +233,10 @@ const DatabaseDashboard: React.FC = () => { ) : view === "grid" ? ( - {(filteredDatabases ?? []).map( + {(filteredDatastores ?? []).map( (datastore: ClientDatastore, i: number) => { return ( - + @@ -283,10 +269,10 @@ const DatabaseDashboard: React.FC = () => { ) : ( - {(filteredDatabases ?? []).map( + {(filteredDatastores ?? []).map( (datastore: ClientDatastore, i: number) => { return ( - + @@ -326,7 +312,7 @@ const DatabaseDashboard: React.FC = () => { diff --git a/dashboard/src/main/home/database-dashboard/DatabaseHeader.tsx b/dashboard/src/main/home/database-dashboard/DatabaseHeader.tsx index 722678fc8d..cad8bc87c0 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseHeader.tsx +++ b/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 ( <> diff --git a/dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx b/dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx index 171bb0fdb4..dbe25c198a 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx +++ b/dashboard/src/main/home/database-dashboard/DatabaseHeaderItem.tsx @@ -34,7 +34,7 @@ const DatabaseHeaderItem: React.FC = ({ item }) => { {titleizeText(item.name)} - + {truncateText(item.value, 42)} diff --git a/dashboard/src/main/home/database-dashboard/DatabaseTabs.tsx b/dashboard/src/main/home/database-dashboard/DatabaseTabs.tsx index 199576cdf1..5d6314ce28 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseTabs.tsx +++ b/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 = ({ 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 = ({ 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 = ({ tabParam }) => { options={tabs} currentTab={currentTab} setCurrentTab={(tab) => { - history.push(`/databases/${datastore.name}/${tab}`); + history.push(`/datastores/${datastore.name}/${tab}`); }} /> {match(currentTab) - .with("credentials", () => ) + .with("credentials", () => ) .with("settings", () => ) .with("metrics", () => ) .with("configuration", () => ) diff --git a/dashboard/src/main/home/database-dashboard/DatabaseView.tsx b/dashboard/src/main/home/database-dashboard/DatabaseView.tsx index 43f890c668..1b23028914 100644 --- a/dashboard/src/main/home/database-dashboard/DatabaseView.tsx +++ b/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 = ({ match }) => { }, [match]); return ( - + - + - + ); }; diff --git a/dashboard/src/main/home/database-dashboard/DatastoreProvisioningIndicator.tsx b/dashboard/src/main/home/database-dashboard/DatastoreProvisioningIndicator.tsx index c7e6fb72c4..29172e1f67 100644 --- a/dashboard/src/main/home/database-dashboard/DatastoreProvisioningIndicator.tsx +++ b/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(); diff --git a/dashboard/src/main/home/database-dashboard/constants.ts b/dashboard/src/main/home/database-dashboard/constants.ts index 8c300a04cb..eb8e367bfc 100644 --- a/dashboard/src/main/home/database-dashboard/constants.ts +++ b/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.", diff --git a/dashboard/src/main/home/database-dashboard/forms/DatabaseForm.tsx b/dashboard/src/main/home/database-dashboard/forms/DatabaseForm.tsx index 05e61c3644..ff5b8b5153 100644 --- a/dashboard/src/main/home/database-dashboard/forms/DatabaseForm.tsx +++ b/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 = ({ history, }) => { const [submitErrorMessage, setSubmitErrorMessage] = useState(""); - 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 = ({ 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.", }); } }); diff --git a/dashboard/src/main/home/database-dashboard/forms/DatabaseFormAuroraPostgres.tsx b/dashboard/src/main/home/database-dashboard/forms/DatabaseFormAuroraPostgres.tsx index f9c43115aa..a5c4952b2e 100644 --- a/dashboard/src/main/home/database-dashboard/forms/DatabaseFormAuroraPostgres.tsx +++ b/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 = ({ history, template }) => { @@ -83,7 +83,7 @@ const DatabaseFormAuroraPostgres: React.FC = ({ history, template }) => { { - history.push(`/databases/new`); + history.push(`/datastores/new`); }} /> = ({ @@ -84,7 +84,7 @@ const DatabaseFormElasticacheRedis: React.FC = ({ { - history.push(`/databases/new`); + history.push(`/datastores/new`); }} /> = ({ history, template }) => { @@ -83,7 +83,7 @@ const DatabaseFormRDSPostgres: React.FC = ({ history, template }) => { { - history.push(`/databases/new`); + history.push(`/datastores/new`); }} /> = { - [DATABASE_TYPE_ELASTICACHE]: awsElasticache, - [DATABASE_TYPE_RDS]: awsRDS, + [DATASTORE_TYPE_ELASTICACHE]: awsElasticache, + [DATASTORE_TYPE_RDS]: awsRDS, }; const engineIcons: Record = { - [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 => { diff --git a/dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx b/dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx index f6cb572a88..5b512c2fbb 100644 --- a/dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx +++ b/dashboard/src/main/home/database-dashboard/shared/ConnectAppsModal.tsx @@ -68,7 +68,7 @@ const ConnectAppsModal: React.FC = ({ 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); diff --git a/dashboard/src/main/home/database-dashboard/tabs/ConfigurationTab.tsx b/dashboard/src/main/home/database-dashboard/tabs/ConfigurationTab.tsx index c7fa1e2611..9bafff8f44 100644 --- a/dashboard/src/main/home/database-dashboard/tabs/ConfigurationTab.tsx +++ b/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 (
- Database details: + Datastore details: {datastore.metadata !== undefined && datastore.metadata?.length > 0 && ( diff --git a/dashboard/src/main/home/database-dashboard/tabs/ConnectedAppsTab.tsx b/dashboard/src/main/home/database-dashboard/tabs/ConnectedAppsTab.tsx index b6fdd9a47a..73741a2686 100644 --- a/dashboard/src/main/home/database-dashboard/tabs/ConnectedAppsTab.tsx +++ b/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 = () => { Connected Apps - - - Credentials for this datastore are injected as environment variables to - connected apps. - - ({ app: ra, diff --git a/dashboard/src/main/home/database-dashboard/tabs/CredentialsTab.tsx b/dashboard/src/main/home/database-dashboard/tabs/CredentialsTab.tsx new file mode 100644 index 0000000000..b7a37552f1 --- /dev/null +++ b/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 ( + + + Credentials + + {keyValues.length !== 0 && ( + <> + + + Once an app is connected to this datastore, it has access to its + credentials through the following environment variables: + + + {keyValues.map( + ( + entry: { key: string; value: string; secret: boolean }, + i: number + ) => { + return ( + + ({})} + disabled={entry.secret} + disabledTooltip={"Stored as a secret on your cluster"} + /> + + ({})} + disabled={entry.secret} + disabledTooltip={"Stored as a secret on your cluster"} + /> + {!entry.secret && ( + <> + + + + + + )} + + ); + } + )} + + + )} + + Connect + + + If you have the{" "} + + Porter CLI + {" "} + installed, you can connect to this datastore locally by running the + following command: + + + + {`$ porter datastore connect ${datastore.name}`} + + + + + + + + ); +}; + +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; +`; diff --git a/dashboard/src/main/home/database-dashboard/tabs/DatabaseEnvTab.tsx b/dashboard/src/main/home/database-dashboard/tabs/DatabaseEnvTab.tsx deleted file mode 100644 index 531596e636..0000000000 --- a/dashboard/src/main/home/database-dashboard/tabs/DatabaseEnvTab.tsx +++ /dev/null @@ -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 = ({ 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 ( - - - Environment Variables - - These environment variables are available to your applications once - the "{envData.name}" env group is linked to your app. - - {}} - fileUpload={true} - secretOption={false} - disabled={true} - /> - - {connectionString && ( - - Connection String - - - - Connection String: - - {connectionString} - - - - - - - - - )} - - ); -}; - -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; -`; diff --git a/dashboard/src/main/home/database-dashboard/tabs/SettingsTab.tsx b/dashboard/src/main/home/database-dashboard/tabs/SettingsTab.tsx index 56f6a3232b..0acec915d0 100644 --- a/dashboard/src/main/home/database-dashboard/tabs/SettingsTab.tsx +++ b/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 => { 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 = () => { Delete "{datastore.name}" - Delete this database and all of its resources. + Delete this datastore and all of its resources.