-
Notifications
You must be signed in to change notification settings - Fork 432
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow user to manage existing cloud accounts from dashboard
- Loading branch information
Showing
11 changed files
with
669 additions
and
267 deletions.
There are no files selected for viewing
184 changes: 184 additions & 0 deletions
184
dashboard/components/account-details/AwsAccountDetails.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
import { ChangeEvent, ReactNode, useRef, useState } from 'react'; | ||
import Folder2Icon from '../icons/Folder2Icon'; | ||
import SelectInput from '../onboarding-wizard/SelectInput'; | ||
import LabelledInput from '../onboarding-wizard/LabelledInput'; | ||
import InputFileSelect from '../onboarding-wizard/InputFileSelect'; | ||
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'; | ||
|
||
interface SelectOptions { | ||
icon: ReactNode; | ||
label: string; | ||
value: string; | ||
} | ||
|
||
interface AwsAccountDetailsProps { | ||
cloudAccountData: CloudAccount; | ||
setCloudAccountData: (formData: CloudAccount) => void; | ||
} | ||
|
||
const options: SelectOptions[] = [ | ||
{ | ||
icon: <DocumentTextIcon />, | ||
label: 'Credentials File', | ||
value: 'credentials-file' | ||
}, | ||
{ | ||
icon: <KeyIcon />, | ||
label: 'Credentials keys', | ||
value: 'credentials-keys' | ||
}, | ||
{ | ||
icon: <VariableIcon />, | ||
label: 'Environment Variables', | ||
value: 'environment-variables' | ||
}, | ||
{ | ||
icon: <ShieldSecurityIcon />, | ||
label: 'IAM Instance Role', | ||
value: 'iam-instance-role' | ||
} | ||
]; | ||
|
||
function AwsAccountDetails({ | ||
cloudAccountData, | ||
setCloudAccountData | ||
}: AwsAccountDetailsProps) { | ||
const [credentialType, setCredentialType] = useState<string>( | ||
options.find(option => option.value === cloudAccountData.credentials.source) | ||
?.value ?? options[0].value | ||
); | ||
|
||
const fileInputRef = useRef<HTMLInputElement | null>(null); | ||
const handleButtonClick = () => { | ||
if (fileInputRef.current) { | ||
fileInputRef.current.click(); | ||
} | ||
}; | ||
|
||
function handleNameChange(event: ChangeEvent<HTMLInputElement>) { | ||
setCloudAccountData({ | ||
...cloudAccountData, | ||
name: event?.target.value | ||
}); | ||
} | ||
|
||
function handleSelectChange(newValue: string) { | ||
setCredentialType(newValue); | ||
|
||
setCloudAccountData({ | ||
...cloudAccountData, | ||
credentials: { | ||
...cloudAccountData.credentials, | ||
source: newValue | ||
} | ||
}); | ||
} | ||
|
||
function handleProfileChange(event: ChangeEvent<HTMLInputElement>) { | ||
setCloudAccountData({ | ||
...cloudAccountData, | ||
credentials: { | ||
...cloudAccountData.credentials, | ||
profile: event?.target.value | ||
} | ||
}); | ||
} | ||
|
||
const handleFileChange = (event: ChangeEvent<HTMLInputElement>) => { | ||
const file = event.target.files?.[0]; | ||
|
||
if (!file) return; | ||
|
||
setCloudAccountData({ | ||
...cloudAccountData, | ||
credentials: { | ||
...cloudAccountData.credentials, | ||
path: file.name | ||
} | ||
}); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col space-y-8 py-10"> | ||
<LabelledInput | ||
type="text" | ||
id="account-name" | ||
label="Account name" | ||
placeholder="my-aws-account" | ||
value={cloudAccountData.name} | ||
onChange={handleNameChange} | ||
/> | ||
|
||
<div className="flex flex-col space-y-8 rounded-md bg-komiser-100 p-5"> | ||
<div> | ||
<SelectInput | ||
icon="Change" | ||
label={'Source'} | ||
displayValues={options} | ||
value={credentialType} | ||
handleChange={handleSelectChange} | ||
values={options.map(option => option.value)} | ||
/> | ||
{[options[2].value, options[3].value].includes(credentialType) && ( | ||
<div className="mt-2 text-sm text-black-400"> | ||
{credentialType === options[3].value | ||
? 'Komiser will fetch the credentials from AWS' | ||
: 'Komiser will load credentials from AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.'} | ||
</div> | ||
)} | ||
</div> | ||
|
||
{credentialType === options[0].value && ( | ||
<div> | ||
<InputFileSelect | ||
type="text" | ||
label="File path" | ||
id="file-path-input" | ||
icon={<Folder2Icon />} | ||
subLabel="Enter the path or browse the file" | ||
placeholder="C:\Documents\Komiser\credentials" | ||
fileInputRef={fileInputRef} | ||
iconClick={handleButtonClick} | ||
handleFileChange={handleFileChange} | ||
value={cloudAccountData.credentials.path} | ||
/> | ||
<LabelledInput | ||
type="text" | ||
id="profile" | ||
label="Profile" | ||
placeholder="default" | ||
subLabel="Name of the section in the credentials file" | ||
value={cloudAccountData.credentials.profile} | ||
onChange={handleProfileChange} | ||
/> | ||
</div> | ||
)} | ||
|
||
{credentialType === options[1].value && ( | ||
<div> | ||
<LabelledInput | ||
type="text" | ||
id="access-key-id" | ||
label="Access key ID" | ||
placeholder="AKIABCDEFGHIJKLMN12" | ||
subLabel="Unique identifier used to access AWS services" | ||
/> | ||
<LabelledInput | ||
type="text" | ||
id="secret-access-key" | ||
label="Secret access key" | ||
placeholder="AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCd" | ||
subLabel="The secret access key is generated by AWS when an access key is created" | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
export default AwsAccountDetails; |
78 changes: 78 additions & 0 deletions
78
dashboard/components/cloud-account/components/CloudAccountDeleteContents.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { useState } from 'react'; | ||
import AlertCircleIcon from '../../icons/AlertCircleIcon'; | ||
import Button from '../../button/Button'; | ||
import { CloudAccount } from '../hooks/useCloudAccounts/useCloudAccount'; | ||
import settingsService from '../../../services/settingsService'; | ||
import { ToastProps } from '../../toast/hooks/useToast'; | ||
|
||
interface CloudAccountDeleteContentsProps { | ||
cloudAccount: CloudAccount; | ||
onCancel: () => void; | ||
setToast: (toast: ToastProps) => void; | ||
} | ||
|
||
function CloudAccountDeleteContents({ | ||
cloudAccount, | ||
onCancel, | ||
setToast | ||
}: CloudAccountDeleteContentsProps) { | ||
const [loading, setLoading] = useState(false); | ||
|
||
const deleteCloudAccount = () => { | ||
if (!cloudAccount.id) return false; | ||
|
||
setLoading(true); | ||
|
||
settingsService.deleteCloudAccount(cloudAccount.id).then(res => { | ||
setLoading(false); | ||
if (res === Error) { | ||
setToast({ | ||
hasError: true, | ||
title: 'Cloud account was not deleted', | ||
message: | ||
'There was an error deleting this cloud account. Please try again.' | ||
}); | ||
} else { | ||
setToast({ | ||
hasError: false, | ||
title: 'Cloud account deleted', | ||
message: `The cloud account was successfully deleted!` | ||
}); | ||
} | ||
}); | ||
|
||
return true; | ||
}; | ||
|
||
return ( | ||
<> | ||
<div className="flex flex-col items-center gap-y-6"> | ||
<AlertCircleIcon className="h-16 w-16" /> | ||
<h1 className="text-center text-xl font-semibold text-black-800"> | ||
Are you sure you want to | ||
<br /> | ||
remove this cloud account? | ||
</h1> | ||
<h3 className="text-center"> | ||
All related data (like custom views and tags) will be deleted | ||
<br /> | ||
and the {cloudAccount.name} account will be disconnected from Komiser. | ||
</h3> | ||
</div> | ||
<div className="flex flex-row place-content-end gap-x-8"> | ||
<Button style="text" onClick={() => onCancel()}> | ||
Cancel | ||
</Button> | ||
<Button | ||
style="delete" | ||
loading={loading} | ||
onClick={() => deleteCloudAccount()} | ||
> | ||
Delete account | ||
</Button> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export default CloudAccountDeleteContents; |
23 changes: 23 additions & 0 deletions
23
dashboard/components/cloud-account/components/CloudAccountStatus.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import classNames from 'classnames'; | ||
import { CloudAccount } from '../hooks/useCloudAccounts/useCloudAccount'; | ||
|
||
function CloudAccountStatus({ status }: { status: CloudAccount['status'] }) { | ||
if (!status) return null; | ||
|
||
return ( | ||
<div | ||
className={classNames( | ||
'relative inline-block rounded-3xl px-2 py-1 text-sm', | ||
{ | ||
'bg-green-200 text-green-600': status === 'CONNECTED', | ||
'bg-red-200 text-red-600': | ||
status === 'PERMISSION_ISSUE' || status === 'INTEGRATION_ISSUE' | ||
} | ||
)} | ||
> | ||
<span>{status.charAt(0) + status.slice(1).toLocaleLowerCase()}</span> | ||
</div> | ||
); | ||
} | ||
|
||
export default CloudAccountStatus; |
Oops, something went wrong.