diff --git a/dashboard/components/account-details/AwsAccountDetails.tsx b/dashboard/components/account-details/AwsAccountDetails.tsx index 146bb808e..f1e20e09d 100644 --- a/dashboard/components/account-details/AwsAccountDetails.tsx +++ b/dashboard/components/account-details/AwsAccountDetails.tsx @@ -1,4 +1,6 @@ import { ChangeEvent, ReactNode, useRef, useState } from 'react'; +import classNames from 'classnames'; +import { AWSCredentials } from '@utils/cloudAccountHelpers'; import Folder2Icon from '../icons/Folder2Icon'; import SelectInput from '../onboarding-wizard/SelectInput'; import LabelledInput from '../onboarding-wizard/LabelledInput'; @@ -7,7 +9,7 @@ import KeyIcon from '../icons/KeyIcon'; import VariableIcon from '../icons/VariableIcon'; import DocumentTextIcon from '../icons/DocumentTextIcon'; import ShieldSecurityIcon from '../icons/ShieldSecurityIcon'; -import { CloudAccount } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; interface SelectOptions { icon: ReactNode; @@ -16,8 +18,8 @@ interface SelectOptions { } interface AwsAccountDetailsProps { - cloudAccountData: CloudAccount; - setCloudAccountData: (formData: CloudAccount) => void; + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; } const options: SelectOptions[] = [ @@ -45,12 +47,15 @@ const options: SelectOptions[] = [ function AwsAccountDetails({ cloudAccountData, - setCloudAccountData + hasError = false }: AwsAccountDetailsProps) { const [credentialType, setCredentialType] = useState( - options.find(option => option.value === cloudAccountData.credentials.source) - ?.value ?? options[0].value + options.find( + option => option.value === cloudAccountData?.credentials.source + )?.value ?? options[0].value ); + const [isValidationError, setIsValidationError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); const fileInputRef = useRef(null); const handleButtonClick = () => { @@ -59,65 +64,49 @@ function AwsAccountDetails({ } }; - function handleNameChange(event: ChangeEvent) { - setCloudAccountData({ - ...cloudAccountData, - name: event?.target.value - }); - } - function handleSelectChange(newValue: string) { setCredentialType(newValue); - - setCloudAccountData({ - ...cloudAccountData, - credentials: { - ...cloudAccountData.credentials, - source: newValue - } - }); - } - - function handleProfileChange(event: ChangeEvent) { - setCloudAccountData({ - ...cloudAccountData, - credentials: { - ...cloudAccountData.credentials, - profile: event?.target.value - } - }); } const handleFileChange = (event: ChangeEvent) => { - const file = event.target.files?.[0]; - - if (!file) return; - - setCloudAccountData({ - ...cloudAccountData, - credentials: { - ...cloudAccountData.credentials, - path: file.name + const fileName = event.target.files?.[0]?.name; + + if (fileName) { + if (!fileName.endsWith('.db')) { + setIsValidationError(true); + setErrorMessage( + 'The chosen file is not supported. Please choose a different file for the credentials.' + ); } - }); + } else { + setIsValidationError(true); + setErrorMessage('Please choose a file.'); + } }; return ( -
+
-
+
} subLabel="Enter the path or browse the file" placeholder="C:\Documents\Komiser\credentials" fileInputRef={fileInputRef} iconClick={handleButtonClick} handleFileChange={handleFileChange} - value={cloudAccountData.credentials.path} + value={cloudAccountData?.credentials.path} + hasError={isValidationError} + errorMessage={errorMessage} />
)} @@ -163,20 +156,30 @@ function AwsAccountDetails({
)}
+ {hasError && ( +
+ We couldn't connect to your AWS account. Please check if the file + is correct. +
+ )}
); } diff --git a/dashboard/components/account-details/AzureAccountDetails.tsx b/dashboard/components/account-details/AzureAccountDetails.tsx new file mode 100644 index 000000000..6d6ffeb6f --- /dev/null +++ b/dashboard/components/account-details/AzureAccountDetails.tsx @@ -0,0 +1,127 @@ +import classNames from 'classnames'; +import { AzureCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface AzureAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function AzureAccountDetails({ + cloudAccountData, + hasError = false +}: AzureAccountDetailsProps) { + return ( +
+ + +
+ + + + + + } + /> + + + + +
+ {hasError && ( +
+ We couldn't connect to your Azure account. Please check if the + file is correct. +
+ )} +
+ ); +} + +export default AzureAccountDetails; diff --git a/dashboard/components/account-details/CivoAccountDetails.tsx b/dashboard/components/account-details/CivoAccountDetails.tsx new file mode 100644 index 000000000..1d8fb3a7e --- /dev/null +++ b/dashboard/components/account-details/CivoAccountDetails.tsx @@ -0,0 +1,62 @@ +import classNames from 'classnames'; +import RecordCircleIcon from '@components/icons/RecordCircleIcon'; +import { CivoCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface CivoAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function CivoAccountDetails({ + cloudAccountData, + hasError = false +}: CivoAccountDetailsProps) { + return ( +
+ + +
+ } + /> + +
+ {hasError && ( +
+ We couldn't connect to your Civo account. Please check if the + file is correct. +
+ )} +
+ ); +} + +export default CivoAccountDetails; diff --git a/dashboard/components/account-details/DigitalOceanAccountDetails.tsx b/dashboard/components/account-details/DigitalOceanAccountDetails.tsx new file mode 100644 index 000000000..4db9ad4b1 --- /dev/null +++ b/dashboard/components/account-details/DigitalOceanAccountDetails.tsx @@ -0,0 +1,61 @@ +import classNames from 'classnames'; +import RecordCircleIcon from '@components/icons/RecordCircleIcon'; +import { DigitalOceanCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface DigitalOceanAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function DigitalOceanAccountDetails({ + cloudAccountData, + hasError = false +}: DigitalOceanAccountDetailsProps) { + return ( +
+ + +
+ } + /> + +
+ {hasError && ( +
+ We couldn't connect to your Digital Ocean account. Please check + if the file is correct. +
+ )} +
+ ); +} + +export default DigitalOceanAccountDetails; diff --git a/dashboard/components/account-details/GcpAccountDetails.tsx b/dashboard/components/account-details/GcpAccountDetails.tsx new file mode 100644 index 000000000..720d170f7 --- /dev/null +++ b/dashboard/components/account-details/GcpAccountDetails.tsx @@ -0,0 +1,90 @@ +import { ChangeEvent, useRef, useState } from 'react'; +import classNames from 'classnames'; +import { GCPCredentials } from '@utils/cloudAccountHelpers'; +import Folder2Icon from '../icons/Folder2Icon'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import InputFileSelect from '../onboarding-wizard/InputFileSelect'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface GcpAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function GcpAccountDetails({ + cloudAccountData, + hasError = false +}: GcpAccountDetailsProps) { + const [isValidationError, setIsValidationError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + const fileInputRef = useRef(null); + const handleButtonClick = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }; + + const handleFileChange = (event: ChangeEvent) => { + const fileName = event.target.files?.[0]?.name; + + if (fileName) { + if (!fileName.endsWith('.json')) { + setIsValidationError(true); + setErrorMessage( + 'The chosen file is not supported. Please choose a different file for the credentials.' + ); + } + } else { + setIsValidationError(true); + setErrorMessage('Please choose a file.'); + } + }; + + return ( +
+ + +
+
+ } + subLabel="Enter the path or browse the file" + placeholder="C:\Documents\Komiser\credentials" + fileInputRef={fileInputRef} + iconClick={handleButtonClick} + handleFileChange={handleFileChange} + value={cloudAccountData?.credentials.serviceAccountKeyPath} + hasError={isValidationError} + errorMessage={errorMessage} + /> +
+
+ {hasError && ( +
+ We couldn't connect to your GCP account. Please check if the file + is correct. +
+ )} +
+ ); +} + +export default GcpAccountDetails; diff --git a/dashboard/components/account-details/KubernetesAccountDetails.tsx b/dashboard/components/account-details/KubernetesAccountDetails.tsx new file mode 100644 index 000000000..2dcb9e2bb --- /dev/null +++ b/dashboard/components/account-details/KubernetesAccountDetails.tsx @@ -0,0 +1,120 @@ +import { ReactNode, useRef, useState, ChangeEvent } from 'react'; +import classNames from 'classnames'; +import DocumentTextIcon from '@components/icons/DocumentTextIcon'; +import SelectInput from '@components/onboarding-wizard/SelectInput'; +import InputFileSelect from '@components/onboarding-wizard/InputFileSelect'; +import Folder2Icon from '@components/icons/Folder2Icon'; +import { KubernetesCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface KubernetesAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +interface SelectOptions { + icon: ReactNode; + label: string; + value: string; +} + +const options: SelectOptions[] = [ + { + icon: , + label: 'Credentials File', + value: 'credentials-file' + } +]; + +function KubernetesAccountDetails({ + cloudAccountData, + hasError = false +}: KubernetesAccountDetailsProps) { + const [credentialType, setCredentialType] = useState( + options.find( + option => option.value === cloudAccountData?.credentials.source + )?.value ?? options[0].value + ); + const [isValidationError, setIsValidationError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + const fileInputRef = useRef(null); + const handleButtonClick = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }; + + function handleSelectChange(newValue: string) { + setCredentialType(newValue); + } + + const handleFileChange = (event: ChangeEvent) => { + const fileName = event.target.files?.[0]?.name; + + if (fileName) { + if (!fileName.endsWith('.db')) { + setIsValidationError(true); + setErrorMessage( + 'The chosen file is not supported. Please choose a different file for the credentials.' + ); + } + } else { + setIsValidationError(true); + setErrorMessage('Please choose a file.'); + } + }; + + return ( +
+ +
+ option.value)} + /> + } + fileInputRef={fileInputRef} + iconClick={handleButtonClick} + handleFileChange={handleFileChange} + hasError={isValidationError} + errorMessage={errorMessage} + /> +
+ {hasError && ( +
+ We couldn't connect to your Kubernetes account. Please check if + the file is correct. +
+ )} +
+ ); +} + +export default KubernetesAccountDetails; diff --git a/dashboard/components/account-details/LinodeAccountDetails.tsx b/dashboard/components/account-details/LinodeAccountDetails.tsx new file mode 100644 index 000000000..0950727f8 --- /dev/null +++ b/dashboard/components/account-details/LinodeAccountDetails.tsx @@ -0,0 +1,52 @@ +import classNames from 'classnames'; +import { LinodeCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface LinodeAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function LinodeAccountDetails({ + cloudAccountData, + hasError = false +}: LinodeAccountDetailsProps) { + return ( +
+ + +
+ +
+ {hasError && ( +
+ We couldn't connect to your Linode account. Please check if the + file is correct. +
+ )} +
+ ); +} + +export default LinodeAccountDetails; diff --git a/dashboard/components/account-details/MongoDBAtlasAccountDetails.tsx b/dashboard/components/account-details/MongoDBAtlasAccountDetails.tsx new file mode 100644 index 000000000..b6981badd --- /dev/null +++ b/dashboard/components/account-details/MongoDBAtlasAccountDetails.tsx @@ -0,0 +1,67 @@ +import classNames from 'classnames'; +import { MongoDBAtlasCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface MongoDbAtlasAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function MongoDbAtlasAccountDetails({ + cloudAccountData, + hasError = false +}: MongoDbAtlasAccountDetailsProps) { + return ( +
+ + +
+ + + +
+ {hasError && ( +
+ We couldn't connect to your MongoDB Atlas account. Please check + if the file is correct. +
+ )} +
+ ); +} + +export default MongoDbAtlasAccountDetails; diff --git a/dashboard/components/account-details/OciAccountDetails.tsx b/dashboard/components/account-details/OciAccountDetails.tsx new file mode 100644 index 000000000..6000cc565 --- /dev/null +++ b/dashboard/components/account-details/OciAccountDetails.tsx @@ -0,0 +1,90 @@ +import { ChangeEvent, useRef, useState } from 'react'; +import classNames from 'classnames'; +import { OCICredentials } from '@utils/cloudAccountHelpers'; +import Folder2Icon from '../icons/Folder2Icon'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import InputFileSelect from '../onboarding-wizard/InputFileSelect'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface OciAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function OciAccountDetails({ + cloudAccountData, + hasError = false +}: OciAccountDetailsProps) { + const [isValidationError, setIsValidationError] = useState(false); + const [errorMessage, setErrorMessage] = useState(''); + + const fileInputRef = useRef(null); + const handleButtonClick = () => { + if (fileInputRef.current) { + fileInputRef.current.click(); + } + }; + + const handleFileChange = (event: ChangeEvent) => { + const fileName = event.target.files?.[0]?.name; + + if (fileName) { + if (!fileName.endsWith('.db')) { + setIsValidationError(true); + setErrorMessage( + 'The chosen file is not supported. Please choose a different file for the credentials.' + ); + } + } else { + setIsValidationError(true); + setErrorMessage('Please choose a file.'); + } + }; + + return ( +
+ + +
+
+ } + subLabel="Enter the path or browse the file" + placeholder="C:\Documents\Komiser\credentials" + fileInputRef={fileInputRef} + iconClick={handleButtonClick} + handleFileChange={handleFileChange} + value={cloudAccountData?.credentials.path} + hasError={isValidationError} + errorMessage={errorMessage} + /> +
+
+ {hasError && ( +
+ We couldn't connect to your OCI account. Please check if the file + is correct. +
+ )} +
+ ); +} + +export default OciAccountDetails; diff --git a/dashboard/components/account-details/ScalewayAccountDetails.tsx b/dashboard/components/account-details/ScalewayAccountDetails.tsx new file mode 100644 index 000000000..149b56a44 --- /dev/null +++ b/dashboard/components/account-details/ScalewayAccountDetails.tsx @@ -0,0 +1,67 @@ +import classNames from 'classnames'; +import { ScalewayCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface ScalewayAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function ScalewayAccountDetails({ + cloudAccountData, + hasError = false +}: ScalewayAccountDetailsProps) { + return ( +
+ + +
+ + + +
+ {hasError && ( +
+ We couldn't connect to your Scaleway account. Please check if the + file is correct. +
+ )} +
+ ); +} + +export default ScalewayAccountDetails; diff --git a/dashboard/components/account-details/TencentAccountDetails.tsx b/dashboard/components/account-details/TencentAccountDetails.tsx new file mode 100644 index 000000000..7ac7c3fc1 --- /dev/null +++ b/dashboard/components/account-details/TencentAccountDetails.tsx @@ -0,0 +1,52 @@ +import classNames from 'classnames'; +import { TencentCredentials } from '@utils/cloudAccountHelpers'; +import LabelledInput from '../onboarding-wizard/LabelledInput'; +import { CloudAccountPayload } from '../cloud-account/hooks/useCloudAccounts/useCloudAccount'; + +interface TencentAccountDetailsProps { + cloudAccountData?: CloudAccountPayload; + hasError?: boolean; +} + +function TencentAccountDetails({ + cloudAccountData, + hasError = false +}: TencentAccountDetailsProps) { + return ( +
+ + +
+ +
+ {hasError && ( +
+ We couldn't connect to your Tencent account. Please check if the + file is correct. +
+ )} +
+ ); +} + +export default TencentAccountDetails; diff --git a/dashboard/components/cloud-account/components/CloudAccountsLayout.tsx b/dashboard/components/cloud-account/components/CloudAccountsLayout.tsx index 6447c7341..5aabb40c7 100644 --- a/dashboard/components/cloud-account/components/CloudAccountsLayout.tsx +++ b/dashboard/components/cloud-account/components/CloudAccountsLayout.tsx @@ -3,13 +3,19 @@ import { ReactNode, useContext } from 'react'; import GlobalAppContext from '../../layout/context/GlobalAppContext'; import Providers, { allProviders } from '../../../utils/providerHelper'; +import { CloudAccount } from '../hooks/useCloudAccounts/useCloudAccount'; type CloudAccountsLayoutProps = { + cloudAccounts: CloudAccount[]; children: ReactNode; router: NextRouter; }; -function CloudAccountsLayout({ children, router }: CloudAccountsLayoutProps) { +function CloudAccountsLayout({ + cloudAccounts, + children, + router +}: CloudAccountsLayoutProps) { const { displayBanner } = useContext(GlobalAppContext); const cloudProviders = Object.values(allProviders); @@ -38,16 +44,17 @@ function CloudAccountsLayout({ children, router }: CloudAccountsLayoutProps) {
- {cloudProviders && cloudProviders.length > 0 && ( + {cloudAccounts && cloudAccounts.length > 0 && (
- {cloudProviders.map(view => { - const isActive = router.query.view === view; + {cloudAccounts.map(account => { + const { provider } = account; + const isActive = router.query.view === provider; return ( diff --git a/dashboard/components/cloud-account/components/CloudAccountsSidePanel.tsx b/dashboard/components/cloud-account/components/CloudAccountsSidePanel.tsx index 586cdb412..1baab7d47 100644 --- a/dashboard/components/cloud-account/components/CloudAccountsSidePanel.tsx +++ b/dashboard/components/cloud-account/components/CloudAccountsSidePanel.tsx @@ -1,5 +1,19 @@ -import { useState } from 'react'; -import providers from '../../../utils/providerHelper'; +import { FormEvent, useState } from 'react'; +import AzureAccountDetails from '@components/account-details/AzureAccountDetails'; +import GcpAccountDetails from '@components/account-details/GcpAccountDetails'; +import DigitalOceanAccountDetails from '@components/account-details/DigitalOceanAccountDetails'; +import CivoAccountDetails from '@components/account-details/CivoAccountDetails'; +import LinodeAccountDetails from '@components/account-details/LinodeAccountDetails'; +import KubernetesAccountDetails from '@components/account-details/KubernetesAccountDetails'; +import TencentAccountDetails from '@components/account-details/TencentAccountDetails'; +import MongoDbAtlasAccountDetails from '@components/account-details/MongoDBAtlasAccountDetails'; +import OciAccountDetails from '@components/account-details/OciAccountDetails'; +import ScalewayAccountDetails from '@components/account-details/ScalewayAccountDetails'; +import { getPayloadFromForm } from '@utils/cloudAccountHelpers'; +import providers, { + allProviders, + Provider +} from '../../../utils/providerHelper'; import AwsAccountDetails from '../../account-details/AwsAccountDetails'; import Button from '../../button/Button'; import Sidepanel from '../../sidepanel/Sidepanel'; @@ -24,6 +38,39 @@ interface CloudAccountsSidePanelProps { setToast: (toast: ToastProps) => void; } +function AccountDetails({ + cloudAccountData +}: { + cloudAccountData: CloudAccount; +}) { + switch (cloudAccountData.provider.toLocaleLowerCase()) { + case allProviders.AWS: + return ; + case allProviders.GCP: + return ; + case allProviders.DIGITAL_OCEAN: + return ; + case allProviders.AZURE: + return ; + case allProviders.CIVO: + return ; + case allProviders.KUBERNETES: + return ; + case allProviders.LINODE: + return ; + case allProviders.TENCENT: + return ; + case allProviders.OCI: + return ; + case allProviders.SCALE_WAY: + return ; + case allProviders.MONGODB_ATLAS: + return ; + default: + return null; + } +} + function CloudAccountsSidePanel({ isOpen, closeModal, @@ -36,40 +83,41 @@ function CloudAccountsSidePanel({ }: CloudAccountsSidePanelProps) { const [isDeleteOpen, setIsDeleteOpen] = useState(false); const [loading, setLoading] = useState(false); - const [cloudAccountData, setCloudAccountData] = - useState(cloudAccount); - const handleEditCloudAccount = () => { - if (!cloudAccountData.id) return false; + const handleEditCloudAccount = ( + event: FormEvent, + id: number | undefined, + provider: Provider + ) => { + event.preventDefault(); + if (!id) return false; setLoading(true); - const payloadJson = JSON.stringify(cloudAccountData); - settingsService - .editCloudAccount(cloudAccountData.id, payloadJson) - .then(res => { - if (res === Error || res.error) { - setLoading(false); - setToast({ - hasError: true, - title: 'Cloud account not edited', - message: - 'There was an error editing this cloud account. Refer to the logs and try again.' - }); - } else { - setLoading(false); - setToast({ - hasError: false, - title: 'Cloud account edited', - message: `The cloud account was successfully edited!` - }); - setCloudAccounts( - cloudAccounts.map(c => - c.id === cloudAccountData.id ? cloudAccountData : c - ) - ); - closeModal(); - } - }); + const payloadJson = JSON.stringify( + getPayloadFromForm(new FormData(event.currentTarget), provider) + ); + settingsService.editCloudAccount(id, payloadJson).then(res => { + if (res === Error || res.error) { + setLoading(false); + setToast({ + hasError: true, + title: 'Cloud account not edited', + message: + 'There was an error editing this cloud account. Refer to the logs and try again.' + }); + } else { + setLoading(false); + setToast({ + hasError: false, + title: 'Cloud account edited', + message: `The cloud account was successfully edited!` + }); + setCloudAccounts( + cloudAccounts.map(c => (c.id === cloudAccount.id ? cloudAccount : c)) + ); + closeModal(); + } + }); return true; }; @@ -77,7 +125,7 @@ function CloudAccountsSidePanel({ return ( <> -
+
{/* Modal headers */}
{cloudAccount && ( @@ -95,28 +143,6 @@ function CloudAccountsSidePanel({

{cloudAccount.name}

- {/* - - - - */}

{cloudAccount.resources} resources in this cloud account @@ -164,32 +190,32 @@ function CloudAccountsSidePanel({ {/* Cloud account details */} {page === 'cloud account details' && ( - <> -

+
+ handleEditCloudAccount( + event, + cloudAccount.id, + cloudAccount.provider + ) + } + > +
- - +
-
+
-
- + )} )} diff --git a/dashboard/components/cloud-account/hooks/useCloudAccounts/useCloudAccount.ts b/dashboard/components/cloud-account/hooks/useCloudAccounts/useCloudAccount.ts index 200557c85..2ad515f9c 100644 --- a/dashboard/components/cloud-account/hooks/useCloudAccounts/useCloudAccount.ts +++ b/dashboard/components/cloud-account/hooks/useCloudAccounts/useCloudAccount.ts @@ -1,16 +1,13 @@ import { useEffect, useState } from 'react'; import { useRouter } from 'next/router'; -import useToast from '../../../toast/hooks/useToast'; +import { Credentials } from '@utils/cloudAccountHelpers'; + import { Provider } from '../../../../utils/providerHelper'; import settingsService from '../../../../services/settingsService'; export interface CloudAccount { - credentials: { - path: string; - profile: string; - source: string; - }; + credentials: Credentials; id?: number; name: string; provider: Provider; @@ -18,11 +15,16 @@ export interface CloudAccount { status?: 'CONNECTED' | 'INTEGRATION_ISSUE' | 'PERMISSION_ISSUE'; } +export interface CloudAccountPayload { + name: string; + provider: Provider; + credentials: T; +} + export type CloudAccountsPage = 'cloud account details'; function useCloudAccount() { const router = useRouter(); - const { toast, setToast, dismissToast } = useToast(); const [page, setPage] = useState('cloud account details'); const [cloudAccounts, setCloudAccounts] = useState([]); const [cloudAccountItem, setCloudAccountItem] = useState(); @@ -71,16 +73,12 @@ function useCloudAccount() { } return { - router, openModal, page, cloudAccountItem, setCloudAccountItem, goTo, - toast, hasError, - setToast, - dismissToast, cloudAccounts, setCloudAccounts, isNotCustomView, diff --git a/dashboard/components/layout/Layout.tsx b/dashboard/components/layout/Layout.tsx index 834f6180c..9a303920c 100644 --- a/dashboard/components/layout/Layout.tsx +++ b/dashboard/components/layout/Layout.tsx @@ -1,4 +1,5 @@ import * as Sentry from '@sentry/react'; +import classNames from 'classnames'; import { BrowserTracing } from '@sentry/tracing'; import { useRouter } from 'next/router'; import { ReactNode, useEffect } from 'react'; @@ -61,11 +62,12 @@ function Layout({ children }: LayoutProps) {
{canRender && children} diff --git a/dashboard/components/onboarding-wizard/CredentialsButton.tsx b/dashboard/components/onboarding-wizard/CredentialsButton.tsx index d45950174..d4b566f43 100644 --- a/dashboard/components/onboarding-wizard/CredentialsButton.tsx +++ b/dashboard/components/onboarding-wizard/CredentialsButton.tsx @@ -16,7 +16,7 @@ function CredentialsButton({ return (
diff --git a/dashboard/components/onboarding-wizard/ProgressBar.tsx b/dashboard/components/onboarding-wizard/ProgressBar.tsx index 4cd49a8b0..108d0f876 100644 --- a/dashboard/components/onboarding-wizard/ProgressBar.tsx +++ b/dashboard/components/onboarding-wizard/ProgressBar.tsx @@ -1,6 +1,6 @@ function OnboardingWizardProgressBar({ width }: { width: string }) { return ( -
+
); diff --git a/dashboard/components/onboarding-wizard/SelectInput.tsx b/dashboard/components/onboarding-wizard/SelectInput.tsx index a0c25517b..913854a39 100644 --- a/dashboard/components/onboarding-wizard/SelectInput.tsx +++ b/dashboard/components/onboarding-wizard/SelectInput.tsx @@ -5,6 +5,7 @@ import ChevronDownIcon from '../icons/ChevronDownIcon'; export type SelectInputProps = { label: string; + name?: string; value: string; values: string[]; icon?: string | ReactNode; @@ -14,6 +15,7 @@ export type SelectInputProps = { function SelectInput({ label, + name, value, values, handleChange, @@ -41,6 +43,8 @@ function SelectInput({ {icon}
+ + +
+
+ ))} +
+ + + +
+ {/* Row 1 */} +
+
+
+
+
+
+
+ + {/* Row 2 */} +
+
+
+
+ AWS +
+
+
+
+
+
+ + {/* Row 3 */} +
+
+
+ Civo +
+
+
+
+
+
+
+ + {/* Row 4 */} +
+
+
+ {' '} +
+ GCP +
+
+
+
+
+
+ + {/* Row 5 */} +
+
+
+
+ {' '} +
+ Azure +
+
+
+
+
+ + {/* Row 6 */} +
+
+
+
+
+
+
+ + {/* Row 7 */} +
+
+
+
+
+
+
+
+
+ + + closeRemoveModal()}> +
+ {cloudAccountItem && ( + + )} +
+
+ + {/* Toast component */} + {toast && } +
+ ); +} diff --git a/dashboard/pages/onboarding/provider/aws.tsx b/dashboard/pages/onboarding/provider/aws.tsx index 0236b64ac..b830fa3f4 100644 --- a/dashboard/pages/onboarding/provider/aws.tsx +++ b/dashboard/pages/onboarding/provider/aws.tsx @@ -1,6 +1,7 @@ -import Head from 'next/head'; -import { useRouter } from 'next/router'; import { useState } from 'react'; +import Head from 'next/head'; + +import { configureAccount } from '@utils/cloudAccountHelpers'; import { allProviders } from '../../../utils/providerHelper'; @@ -11,26 +12,15 @@ import OnboardingWizardLayout, { import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; import AwsAccountDetails from '../../../components/account-details/AwsAccountDetails'; -import { CloudAccount } from '../../../components/cloud-account/hooks/useCloudAccounts/useCloudAccount'; +import Toast from '../../../components/toast/Toast'; +import useToast from '../../../components/toast/hooks/useToast'; export default function AWSCredentials() { const provider = allProviders.AWS; - const [cloudAccountData, setCloudAccountData] = useState({ - credentials: { - path: '', - profile: '', - source: '' - }, - name: '', - provider: 'aws' - }); + const { toast, setToast, dismissToast } = useToast(); - const router = useRouter(); - - const handleNext = () => { - // TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation - }; + const [hasError, setHasError] = useState(false); return (
@@ -54,7 +44,7 @@ export default function AWSCredentials() { Read our guide on{' '} @@ -62,11 +52,14 @@ export default function AWSCredentials() {
- - +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + @@ -75,6 +68,9 @@ export default function AWSCredentials() { + + {/* Toast component */} + {toast && } ); } diff --git a/dashboard/pages/onboarding/provider/azure.tsx b/dashboard/pages/onboarding/provider/azure.tsx index da10e9dc2..c1ca7563f 100644 --- a/dashboard/pages/onboarding/provider/azure.tsx +++ b/dashboard/pages/onboarding/provider/azure.tsx @@ -1,4 +1,8 @@ +import { useState } from 'react'; import Head from 'next/head'; +import AzureAccountDetails from '@components/account-details/AzureAccountDetails'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; import { allProviders } from '../../../utils/providerHelper'; @@ -7,15 +11,14 @@ import OnboardingWizardLayout, { RightSideLayout } from '../../../components/onboarding-wizard/OnboardingWizardLayout'; import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; -import LabelledInput from '../../../components/onboarding-wizard/LabelledInput'; import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; export default function AzureCredentials() { const provider = allProviders.AZURE; - const handleNext = () => { - // TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation - }; + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); return (
@@ -41,7 +44,7 @@ export default function AzureCredentials() { Read our guide on{' '} @@ -50,87 +53,14 @@ export default function AzureCredentials() {
-
- - -
- - - - - - } - /> - - - - -
-
- +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + diff --git a/dashboard/pages/onboarding/provider/civo.tsx b/dashboard/pages/onboarding/provider/civo.tsx index edd41e2e4..d6d2aed27 100644 --- a/dashboard/pages/onboarding/provider/civo.tsx +++ b/dashboard/pages/onboarding/provider/civo.tsx @@ -1,23 +1,24 @@ +import { useState } from 'react'; import Head from 'next/head'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; +import CivoAccountDetails from '@components/account-details/CivoAccountDetails'; import { allProviders } from '../../../utils/providerHelper'; -import RecordCircleIcon from '../../../components/icons/RecordCircleIcon'; - import OnboardingWizardLayout, { LeftSideLayout, RightSideLayout } from '../../../components/onboarding-wizard/OnboardingWizardLayout'; import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; -import LabelledInput from '../../../components/onboarding-wizard/LabelledInput'; import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; export default function CivoCredentials() { const provider = allProviders.CIVO; - const handleNext = () => { - // TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation - }; + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); return (
@@ -49,34 +50,14 @@ export default function CivoCredentials() {
-
- - -
- } - /> - -
-
- - +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + diff --git a/dashboard/pages/onboarding/provider/digitalocean.tsx b/dashboard/pages/onboarding/provider/digitalocean.tsx index d23e967d2..b7a1f0464 100644 --- a/dashboard/pages/onboarding/provider/digitalocean.tsx +++ b/dashboard/pages/onboarding/provider/digitalocean.tsx @@ -1,23 +1,24 @@ +import { useState } from 'react'; import Head from 'next/head'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import DigitalOceanAccountDetails from '@components/account-details/DigitalOceanAccountDetails'; +import useToast from '@components/toast/hooks/useToast'; import { allProviders } from '../../../utils/providerHelper'; -import RecordCircleIcon from '../../../components/icons/RecordCircleIcon'; - import OnboardingWizardLayout, { LeftSideLayout, RightSideLayout } from '../../../components/onboarding-wizard/OnboardingWizardLayout'; -import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; -import LabelledInput from '../../../components/onboarding-wizard/LabelledInput'; import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; export default function DigitalOceanCredentials() { const provider = allProviders.DIGITAL_OCEAN; - const handleNext = () => { - // TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation - }; + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); return (
-
- - -
- } - /> - -
-
- - +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + diff --git a/dashboard/pages/onboarding/provider/gcp.tsx b/dashboard/pages/onboarding/provider/gcp.tsx new file mode 100644 index 000000000..6e16e332c --- /dev/null +++ b/dashboard/pages/onboarding/provider/gcp.tsx @@ -0,0 +1,75 @@ +import { useState } from 'react'; +import Head from 'next/head'; +import GcpAccountDetails from '@components/account-details/GcpAccountDetails'; +import { configureAccount } from '@utils/cloudAccountHelpers'; + +import { allProviders } from '../../../utils/providerHelper'; + +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; +import Toast from '../../../components/toast/Toast'; +import useToast from '../../../components/toast/hooks/useToast'; + +export default function GcpCredentials() { + const provider = allProviders.GCP; + + const { toast, setToast, dismissToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ ); +} diff --git a/dashboard/pages/onboarding/provider/kubernetes.tsx b/dashboard/pages/onboarding/provider/kubernetes.tsx index f52096ac7..893166b99 100644 --- a/dashboard/pages/onboarding/provider/kubernetes.tsx +++ b/dashboard/pages/onboarding/provider/kubernetes.tsx @@ -1,65 +1,24 @@ +import { useState } from 'react'; import Head from 'next/head'; -import { useRouter } from 'next/router'; -import { ReactNode, useRef, useState } from 'react'; +import KubernetesAccountDetails from '@components/account-details/KubernetesAccountDetails'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; import { allProviders } from '../../../utils/providerHelper'; -import Folder2Icon from '../../../components/icons/Folder2Icon'; -import DocumentTextIcon from '../../../components/icons/DocumentTextIcon'; - import OnboardingWizardLayout, { LeftSideLayout, RightSideLayout } from '../../../components/onboarding-wizard/OnboardingWizardLayout'; -import SelectInput from '../../../components/onboarding-wizard/SelectInput'; import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; -import LabelledInput from '../../../components/onboarding-wizard/LabelledInput'; -import InputFileSelect from '../../../components/onboarding-wizard/InputFileSelect'; import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; -interface SelectOptions { - icon: ReactNode; - label: string; - value: string; -} - -const options: SelectOptions[] = [ - { - icon: , - label: 'Credentials File', - value: 'credentials-file' - } -]; - export default function KubernetesCredentials() { const provider = allProviders.KUBERNETES; - const router = useRouter(); - const [credentialType, setCredentialType] = useState( - options[0].value - ); - - const handleNext = () => { - // TODO: (onboarding-wizard) complete form inputs, validation, submission and navigation - router.push(`/onboarding/${provider}`); - }; + const { setToast } = useToast(); - const fileInputRef = useRef(null); - const handleButtonClick = () => { - if (fileInputRef.current) { - fileInputRef.current.click(); - } - }; - - const handleFileChange = (event: any) => { - const file = event.target.files[0]; - // TODO: (onboarding-wizard) handle file change and naming. Set Input field to file.name and use temporary file path for the upload value - console.log(file); - }; - - function handleSelectChange(newValue: string) { - setCredentialType(newValue); - } + const [hasError, setHasError] = useState(false); return (
@@ -91,36 +50,15 @@ export default function KubernetesCredentials() {
-
- -
- option.value)} - /> - } - fileInputRef={fileInputRef} - iconClick={handleButtonClick} - handleFileChange={handleFileChange} - /> -
-
- + +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + diff --git a/dashboard/pages/onboarding/provider/linode.tsx b/dashboard/pages/onboarding/provider/linode.tsx new file mode 100644 index 000000000..2b033e20d --- /dev/null +++ b/dashboard/pages/onboarding/provider/linode.tsx @@ -0,0 +1,67 @@ +import { useState } from 'react'; +import Head from 'next/head'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; +import LinodeAccountDetails from '@components/account-details/LinodeAccountDetails'; + +import { allProviders } from '../../../utils/providerHelper'; + +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; + +export default function LinodeCredentials() { + const provider = allProviders.LINODE; + + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ + Setup Linode - Komiser + + + + + +
+
+ Read our guide on{' '} + + adding a Linode account to Komiser. + +
+
+ +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + +
+ + +
+ +
+
+
+
+ ); +} diff --git a/dashboard/pages/onboarding/provider/mongodbatlas.tsx b/dashboard/pages/onboarding/provider/mongodbatlas.tsx new file mode 100644 index 000000000..08afabe1b --- /dev/null +++ b/dashboard/pages/onboarding/provider/mongodbatlas.tsx @@ -0,0 +1,67 @@ +import { useState } from 'react'; +import Head from 'next/head'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; +import MongoDbAtlasAccountDetails from '@components/account-details/MongoDBAtlasAccountDetails'; + +import { allProviders } from '../../../utils/providerHelper'; + +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; + +export default function MongoDBAtlasCredentials() { + const provider = allProviders.TENCENT; + + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ + Setup MongoDB Atlas - Komiser + + + + + +
+ +
+ +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + +
+ + +
+ +
+
+
+
+ ); +} diff --git a/dashboard/pages/onboarding/provider/oci.tsx b/dashboard/pages/onboarding/provider/oci.tsx new file mode 100644 index 000000000..6a4a7bc3a --- /dev/null +++ b/dashboard/pages/onboarding/provider/oci.tsx @@ -0,0 +1,74 @@ +import { useState } from 'react'; +import Head from 'next/head'; + +import { configureAccount } from '@utils/cloudAccountHelpers'; +import GcpAccountDetails from '@components/account-details/GcpAccountDetails'; +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; +import Toast from '../../../components/toast/Toast'; +import useToast from '../../../components/toast/hooks/useToast'; +import { allProviders } from '../../../utils/providerHelper'; + +export default function OciCredentials() { + const provider = allProviders.OCI; + + const { toast, setToast, dismissToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ + Setup GCP - Komiser + + + + + +
+
+ GCP is a cloud computing platform that provides infrastructure + services, application services, and developer tools provided by + Google. +
+
+ Read our guide on{' '} + + adding an GCP account to Komiser. + +
+
+
+ configureAccount(event, allProviders.GCP, setToast, setHasError) + } + > + + + +
+ + +
+ +
+
+
+ + {/* Toast component */} + {toast && } +
+ ); +} diff --git a/dashboard/pages/onboarding/provider/scaleway.tsx b/dashboard/pages/onboarding/provider/scaleway.tsx new file mode 100644 index 000000000..19c5d7728 --- /dev/null +++ b/dashboard/pages/onboarding/provider/scaleway.tsx @@ -0,0 +1,66 @@ +import { useState } from 'react'; +import Head from 'next/head'; + +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; +import ScalewayAccountDetails from '@components/account-details/ScalewayAccountDetails'; +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; +import { allProviders } from '../../../utils/providerHelper'; + +export default function ScalewayCredentials() { + const provider = allProviders.TENCENT; + + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ + Setup Scaleway - Komiser + + + + + +
+
+ Read our guide on{' '} + + adding a Scaleway account to Komiser. + +
+
+ +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + +
+ + +
+ +
+
+
+
+ ); +} diff --git a/dashboard/pages/onboarding/provider/tencent.tsx b/dashboard/pages/onboarding/provider/tencent.tsx new file mode 100644 index 000000000..0ed7b53da --- /dev/null +++ b/dashboard/pages/onboarding/provider/tencent.tsx @@ -0,0 +1,66 @@ +import { useState } from 'react'; +import Head from 'next/head'; +import { configureAccount } from '@utils/cloudAccountHelpers'; +import useToast from '@components/toast/hooks/useToast'; +import TencentAccountDetails from '@components/account-details/TencentAccountDetails'; + +import OnboardingWizardLayout, { + LeftSideLayout, + RightSideLayout +} from '../../../components/onboarding-wizard/OnboardingWizardLayout'; +import PurplinCloud from '../../../components/onboarding-wizard/PurplinCloud'; +import CredentialsButton from '../../../components/onboarding-wizard/CredentialsButton'; +import { allProviders } from '../../../utils/providerHelper'; + +export default function TencentCredentials() { + const provider = allProviders.TENCENT; + + const { setToast } = useToast(); + + const [hasError, setHasError] = useState(false); + + return ( +
+ + Setup Tencent - Komiser + + + + + +
+
+ Read our guide on{' '} + + adding a Tencent account to Komiser. + +
+
+ +
+ configureAccount(event, provider, setToast, setHasError) + } + > + + + +
+ + +
+ +
+
+
+
+ ); +} diff --git a/dashboard/public/assets/img/providers/ovh.jpeg b/dashboard/public/assets/img/providers/ovh.jpeg deleted file mode 100644 index 5b43de9d5..000000000 Binary files a/dashboard/public/assets/img/providers/ovh.jpeg and /dev/null differ diff --git a/dashboard/services/settingsService.ts b/dashboard/services/settingsService.ts index 42d5b9466..6804c61e0 100644 --- a/dashboard/services/settingsService.ts +++ b/dashboard/services/settingsService.ts @@ -398,6 +398,19 @@ const settingsService = { } }, + async addCloudAccount(payload: string) { + try { + const res = await fetch( + `${BASE_URL}/cloud_accounts`, + settings('POST', payload) + ); + const data = await res.json(); + return data; + } catch (error) { + return Error; + } + }, + async editCloudAccount(id: number, payload: string) { try { const res = await fetch( diff --git a/dashboard/utils/cloudAccountHelpers.ts b/dashboard/utils/cloudAccountHelpers.ts new file mode 100644 index 000000000..d9992da09 --- /dev/null +++ b/dashboard/utils/cloudAccountHelpers.ts @@ -0,0 +1,205 @@ +import { FormEvent } from 'react'; +import { allProviders, Provider } from './providerHelper'; +import settingsService from '@services/settingsService'; + +export interface Credentials {} + +export interface AWSCredentials extends Credentials { + source?: string; + path?: string; + profile?: string; + aws_access_key_id?: string; + aws_secret_access_key?: string; +} + +export interface AzureCredentials extends Credentials { + source?: string; + tenantId?: string; + clientId?: string; + clientSecret?: string; + subscriptionId?: string; +} + +export interface CivoCredentials extends Credentials { + source?: string; + token?: string; +} + +export interface DigitalOceanCredentials extends Credentials { + source?: string; + token?: string; +} + +export interface KubernetesCredentials extends Credentials { + source?: string; + file?: string; +} + +export interface LinodeCredentials extends Credentials { + token?: string; +} + +export interface TencentCredentials extends Credentials { + token?: string; +} + +export interface ScalewayCredentials extends Credentials { + accessKey?: string; + secretKey?: string; + organizationId?: string; +} + +export interface MongoDBAtlasCredentials extends Credentials { + publicApiKey?: string; + privateApiKey?: string; + organizationId?: string; +} + +export interface GCPCredentials extends Credentials { + serviceAccountKeyPath?: string; +} + +export interface OCICredentials extends Credentials { + path?: string; +} + +export const getPayloadFromForm = (formData: FormData, provider: Provider) => { + const data = Object.fromEntries(formData.entries()); + + switch (provider) { + case allProviders.AWS: + return { + name: data.name, + provider: provider, + credentials: { + source: data.source, + path: data.path, + profile: data.profile, + aws_access_key_id: data.aws_access_key_id, + aws_secret_access_key: data.aws_secret_access_key + } + }; + case allProviders.AZURE: + return { + name: data.name, + provider: provider, + credentials: { + source: data.source, + tenantId: data.tenantId, + clientId: data.clientId, + clientSecret: data.clientSecret, + subscriptionId: data.subscriptionId + } + }; + case allProviders.CIVO: + return { + name: data.name, + provider: provider, + credentials: { + source: data.source, + token: data.token + } + }; + case allProviders.DIGITAL_OCEAN: + return { + name: data.name, + provider: provider, + credentials: { + source: data.source, + token: data.token + } + }; + case allProviders.KUBERNETES: + return { + name: data.name, + provider: provider, + credentials: { + source: data.source, + file: data.file + } + }; + case allProviders.LINODE: + return { + name: data.name, + provider: provider, + credentials: { + token: data.token + } + }; + case allProviders.TENCENT: + return { + name: data.name, + provider: provider, + credentials: { + token: data.token + } + }; + case allProviders.SCALE_WAY: + return { + name: data.name, + provider: provider, + credentials: { + accessKey: data.accessKey, + secretKey: data.secretKey, + organizationId: data.organizationId + } + }; + case allProviders.MONGODB_ATLAS: + return { + name: data.name, + provider: provider, + credentials: { + publicApiKey: data.publicApiKey, + privateApiKey: data.privateApiKey, + organizationId: data.organizationId + } + }; + case allProviders.GCP: + return { + name: data.name, + provider: provider, + credentials: { + serviceAccountKeyPath: data.serviceAccountKeyPath + } + }; + case allProviders.OCI: + return { + name: data.name, + provider: provider, + credentials: { + path: data.path + } + }; + } +}; + +export const configureAccount = ( + e: FormEvent, + provider: Provider, + setToast: (toast: { + hasError: boolean; + title: string; + message: string; + }) => void, + setHasError: (value: boolean) => void +) => { + e.preventDefault(); + + if (setHasError) setHasError(false); + const payloadJson = JSON.stringify( + getPayloadFromForm(new FormData(e.currentTarget), provider) + ); + settingsService.addCloudAccount(payloadJson).then(res => { + if (res === Error || res.error) { + if (setHasError) setHasError(true); + } else { + setToast({ + hasError: false, + title: 'Cloud account added', + message: 'The cloud account was successfully added!' + }); + } + }); + + return true; +}; diff --git a/dashboard/utils/providerHelper.ts b/dashboard/utils/providerHelper.ts index ccb051c23..9e25de73e 100644 --- a/dashboard/utils/providerHelper.ts +++ b/dashboard/utils/providerHelper.ts @@ -1,7 +1,6 @@ export type Provider = | 'aws' | 'gcp' - | 'ovh' | 'digitalocean' | 'azure' | 'civo' @@ -15,7 +14,6 @@ export type Provider = type ProviderKey = | 'AWS' | 'GCP' - | 'OVH' | 'DIGITAL_OCEAN' | 'AZURE' | 'CIVO' @@ -29,7 +27,6 @@ type ProviderKey = export const allProviders: { [key in ProviderKey]: Provider } = { AWS: 'aws', GCP: 'gcp', - OVH: 'ovh', DIGITAL_OCEAN: 'digitalocean', AZURE: 'azure', CIVO: 'civo', @@ -61,11 +58,6 @@ const providers = { if (arg.toLowerCase() === 'gcp') { label = 'Google Cloud Platform'; } - - if (arg.toLowerCase() === 'ovh') { - label = 'OVH'; - } - if (arg.toLowerCase() === 'digitalocean') { label = 'DigitalOcean'; } @@ -115,10 +107,6 @@ const providers = { img = '/assets/img/providers/gcp.png'; } - if (arg.toLowerCase() === 'ovh') { - img = '/assets/img/providers/ovh.jpeg'; - } - if (arg.toLowerCase() === 'digitalocean') { img = '/assets/img/providers/digitalocean.png'; }