Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AWS Integration changes #7025

Merged
merged 24 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
cc5482b
fix: update AWS accounts API response to return accounts list
ahmadshaheer Feb 4, 2025
82a5242
feat: display skeleton UI for account actions and refactored renderin…
ahmadshaheer Feb 4, 2025
5f76dc3
chore: update AWS service naming from "AWS Web Services" to "Amazon W…
ahmadshaheer Feb 4, 2025
b4c76b7
feat: aws integration success modal changes
ahmadshaheer Feb 4, 2025
158cdb0
feat: auto-select first service when no service is active
ahmadshaheer Feb 4, 2025
7718ab1
feat: display 'enable service' if service hasn't been configured and …
ahmadshaheer Feb 4, 2025
21725ca
fix: display no data yet if status is not available
ahmadshaheer Feb 4, 2025
d2e67dd
feat: properly handle remove integration account flow
ahmadshaheer Feb 4, 2025
80a0ef5
fix: rename accountId param to cloudAccountId
ahmadshaheer Feb 5, 2025
ce683bb
fix: update the aws service list and details api parameter from accou…
ahmadshaheer Feb 5, 2025
bb33560
fix: fix the issue of stale service config modal enabled/disabled state
ahmadshaheer Feb 5, 2025
e0f5a6c
chore: improve the UI of configure button
ahmadshaheer Feb 5, 2025
89cf1f1
feat: add connection parameters support for AWS cloud integration
ahmadshaheer Feb 5, 2025
f2c0e21
feat: add optional link support for cloud service dashboards
ahmadshaheer Feb 5, 2025
a80b247
fix: get the correct supported signals count + a minor refactoring
ahmadshaheer Feb 5, 2025
90d4c10
fix: remove cloudAccountId on success of account remove
ahmadshaheer Feb 5, 2025
704cd11
chore: update the remove integration copy
ahmadshaheer Feb 5, 2025
7535ad8
refactor: add react query key for AWS connection parameters
ahmadshaheer Feb 5, 2025
1cd03be
Merge branch 'main' into feat/aws-integration-changes
ahmadshaheer Feb 5, 2025
75f753b
fix: correct typo in integration loading state variable name
ahmadshaheer Feb 6, 2025
adca0dd
refactor: move skeleton inline styles to style file and do overall re…
ahmadshaheer Feb 6, 2025
1d67fd1
chore: address the requested changes
ahmadshaheer Feb 6, 2025
9c3ad77
Merge branch 'main' into feat/aws-integration-changes
ahmadshaheer Feb 6, 2025
892ea06
Merge branch 'main' into feat/aws-integration-changes
ahmadshaheer Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions frontend/src/api/Integrations/removeAwsIntegrationAccount.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';

const removeAwsIntegrationAccount = async (
accountId: string,
): Promise<SuccessResponse<Record<string, never>> | ErrorResponse> => {
try {
const response = await axios.post(
`/cloud-integrations/aws/accounts/${accountId}/disconnect`,
);

return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};

export default removeAwsIntegrationAccount;
22 changes: 17 additions & 5 deletions frontend/src/api/integrations/aws/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@ import {
import {
AccountConfigPayload,
AccountConfigResponse,
ConnectionParams,
ConnectionUrlResponse,
} from 'types/api/integrations/aws';

export const getAwsAccounts = async (): Promise<CloudAccount[]> => {
const response = await axios.get('/cloud-integrations/aws/accounts');

return response.data.data;
return response.data.data.accounts;
};

export const getAwsServices = async (
accountId?: string,
cloudAccountId?: string,
): Promise<Service[]> => {
const params = accountId ? { account_id: accountId } : undefined;
const params = cloudAccountId
? { cloud_account_id: cloudAccountId }
: undefined;
const response = await axios.get('/cloud-integrations/aws/services', {
params,
});
Expand All @@ -31,9 +34,11 @@ export const getAwsServices = async (

export const getServiceDetails = async (
serviceId: string,
accountId?: string,
cloudAccountId?: string,
): Promise<ServiceData> => {
const params = accountId ? { account_id: accountId } : undefined;
const params = cloudAccountId
? { cloud_account_id: cloudAccountId }
: undefined;
const response = await axios.get(
`/cloud-integrations/aws/services/${serviceId}`,
{ params },
Expand Down Expand Up @@ -74,3 +79,10 @@ export const updateServiceConfig = async (
);
return response.data;
};

export const getConnectionParams = async (): Promise<ConnectionParams> => {
const response = await axios.get(
'/cloud-integrations/aws/accounts/generate-connection-params',
);
return response.data.data;
};
1 change: 1 addition & 0 deletions frontend/src/constants/reactQueryKeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@ export const REACT_QUERY_KEY = {
AWS_UPDATE_ACCOUNT_CONFIG: 'AWS_UPDATE_ACCOUNT_CONFIG',
AWS_UPDATE_SERVICE_CONFIG: 'AWS_UPDATE_SERVICE_CONFIG',
AWS_GENERATE_CONNECTION_URL: 'AWS_GENERATE_CONNECTION_URL',
AWS_GET_CONNECTION_PARAMS: 'AWS_GET_CONNECTION_PARAMS',
GET_ATTRIBUTE_VALUES: 'GET_ATTRIBUTE_VALUES',
};
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ function Header(): JSX.Element {
},
{
title: (
<div className="cloud-header__breadcrumb-title">AWS web services</div>
<div className="cloud-header__breadcrumb-title">
Amazon Web Services
</div>
),
},
]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function HeroSection(): JSX.Element {
<img src="/Logos/aws-dark.svg" alt="aws-logo" />
</div>
<div className="hero-section__details">
<div className="title">AWS Web Services</div>
<div className="title">Amazon Web Services</div>
<div className="description">
One-click setup for AWS monitoring with SigNoz
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import './AccountActions.style.scss';

import { Color } from '@signozhq/design-tokens';
import { Button, Select } from 'antd';
import { Button, Select, Skeleton } from 'antd';
import { SelectProps } from 'antd/lib';
import { useAwsAccounts } from 'hooks/integrations/aws/useAwsAccounts';
import useUrlQuery from 'hooks/useUrlQuery';
Expand Down Expand Up @@ -53,15 +53,96 @@ const getAccountById = (
): CloudAccount | null =>
accounts.find((account) => account.cloud_account_id === accountId) || null;

function AccountActionsRenderer({
accounts,
isLoading,
activeAccount,
selectOptions,
onAccountChange,
onIntegrationModalOpen,
onAccountSettingsModalOpen,
}: {
accounts: CloudAccount[] | undefined;
isLoading: boolean;
activeAccount: CloudAccount | null;
selectOptions: SelectProps['options'];
onAccountChange: (value: string) => void;
onIntegrationModalOpen: () => void;
onAccountSettingsModalOpen: () => void;
}): JSX.Element {
if (isLoading) {
return (
<div className="hero-section__actions-with-account">
<Skeleton.Input
active
size="large"
block
style={{ width: '300px', marginBottom: '16px' }}
/>
<div className="hero-section__action-buttons">
<Skeleton.Button
active
size="large"
style={{ width: '180px', marginRight: '8px' }}
/>
<Skeleton.Button active size="large" style={{ width: '140px' }} />
</div>
</div>
);
}
if (accounts?.length) {
return (
<div className="hero-section__actions-with-account">
<Select
value={`Account: ${activeAccount?.cloud_account_id}`}
options={selectOptions}
rootClassName="cloud-account-selector"
placeholder="Select AWS Account"
suffixIcon={<ChevronDown size={16} color={Color.BG_VANILLA_400} />}
optionRender={(option): JSX.Element =>
renderOption(option, activeAccount?.cloud_account_id)
}
onChange={onAccountChange}
/>
<div className="hero-section__action-buttons">
<Button
type="primary"
className="hero-section__action-button primary"
onClick={onIntegrationModalOpen}
>
Add New AWS Account
</Button>
<Button
type="default"
className="hero-section__action-button secondary"
onClick={onAccountSettingsModalOpen}
>
Account Settings
</Button>
</div>
</div>
);
}
return (
<Button
className="hero-section__action-button primary"
onClick={onIntegrationModalOpen}
>
Integrate Now
</Button>
);
}

function AccountActions(): JSX.Element {
const urlQuery = useUrlQuery();
const navigate = useNavigate();
const { data: accounts } = useAwsAccounts();
const { data: accounts, isLoading } = useAwsAccounts();

const initialAccount = useMemo(
() =>
accounts?.length
? getAccountById(accounts, urlQuery.get('accountId') || '') || accounts[0]
? getAccountById(accounts, urlQuery.get('cloudAccountId') || '') ||
accounts[0]
: null,
[accounts, urlQuery],
);
Expand All @@ -74,7 +155,7 @@ function AccountActions(): JSX.Element {
useEffect(() => {
if (initialAccount !== null) {
setActiveAccount(initialAccount);
urlQuery.set('accountId', initialAccount.cloud_account_id);
urlQuery.set('cloudAccountId', initialAccount.cloud_account_id);
navigate({ search: urlQuery.toString() });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
Expand All @@ -98,60 +179,35 @@ function AccountActions(): JSX.Element {

return (
<div className="hero-section__actions">
{accounts?.length ? (
<div className="hero-section__actions-with-account">
<Select
value={`Account: ${activeAccount?.cloud_account_id}`}
options={selectOptions}
rootClassName="cloud-account-selector"
placeholder="Select AWS Account"
suffixIcon={<ChevronDown size={16} color={Color.BG_VANILLA_400} />}
optionRender={(option): JSX.Element =>
renderOption(option, activeAccount?.cloud_account_id)
}
onChange={(value): void => {
setActiveAccount(getAccountById(accounts, value));
urlQuery.set('accountId', value);
navigate({ search: urlQuery.toString() });
}}
/>
<div className="hero-section__action-buttons">
<Button
type="primary"
className="hero-section__action-button primary"
onClick={(): void => setIsIntegrationModalOpen(true)}
>
Add New AWS Account
</Button>
<Button
type="default"
className="hero-section__action-button secondary"
onClick={(): void => setIsAccountSettingsModalOpen(true)}
>
Account Settings
</Button>
</div>
</div>
) : (
<Button
className="hero-section__action-button primary"
onClick={(): void => setIsIntegrationModalOpen(true)}
>
Integrate Now
</Button>
)}

<CloudAccountSetupModal
isOpen={isIntegrationModalOpen}
onClose={(): void => setIsIntegrationModalOpen(false)}
<AccountActionsRenderer
accounts={accounts}
isLoading={isLoading}
activeAccount={activeAccount}
selectOptions={selectOptions}
onAccountChange={(value): void => {
if (accounts) {
setActiveAccount(getAccountById(accounts, value));
urlQuery.set('cloudAccountId', value);
navigate({ search: urlQuery.toString() });
}
}}
onIntegrationModalOpen={(): void => setIsIntegrationModalOpen(true)}
onAccountSettingsModalOpen={(): void => setIsAccountSettingsModalOpen(true)}
/>

<AccountSettingsModal
isOpen={isAccountSettingsModalOpen}
onClose={(): void => setIsAccountSettingsModalOpen(false)}
account={activeAccount as CloudAccount}
setActiveAccount={setActiveAccount}
/>
{isIntegrationModalOpen && (
<CloudAccountSetupModal
onClose={(): void => setIsIntegrationModalOpen(false)}
/>
)}

{isAccountSettingsModalOpen && (
<AccountSettingsModal
onClose={(): void => setIsAccountSettingsModalOpen(false)}
account={activeAccount as CloudAccount}
setActiveAccount={setActiveAccount}
/>
)}
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ import './AccountSettingsModal.style.scss';

import { Form, Select, Switch } from 'antd';
import SignozModal from 'components/SignozModal/SignozModal';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import {
getRegionPreviewText,
useAccountSettingsModal,
} from 'hooks/integrations/aws/useAccountSettingsModal';
import IntergrationsUninstallBar from 'pages/Integrations/IntegrationDetailPage/IntegrationsUninstallBar';
import { ConnectionStates } from 'pages/Integrations/IntegrationDetailPage/TestConnection';
import { AWS_INTEGRATION } from 'pages/Integrations/IntegrationsList';
import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';
import { Dispatch, SetStateAction, useCallback } from 'react';
import { useQueryClient } from 'react-query';

import { CloudAccount } from '../../ServicesSection/types';
import { RegionSelector } from './RegionSelector';
import RemoveIntegrationAccount from './RemoveIntegrationAccount';

interface AccountSettingsModalProps {
isOpen: boolean;
onClose: () => void;
account: CloudAccount;
setActiveAccount: Dispatch<SetStateAction<CloudAccount | null>>;
}

function AccountSettingsModal({
isOpen,
onClose,
account,
setActiveAccount,
Expand All @@ -42,6 +42,16 @@ function AccountSettingsModal({
handleClose,
} = useAccountSettingsModal({ onClose, account, setActiveAccount });

const queryClient = useQueryClient();
const urlQuery = useUrlQuery();

const handleRemoveIntegrationAccountSuccess = (): void => {
queryClient.invalidateQueries([REACT_QUERY_KEY.AWS_ACCOUNTS]);
urlQuery.delete('cloudAccountId');
handleClose();
history.replace({ search: urlQuery.toString() });
};

const renderRegionSelector = useCallback(() => {
if (isRegionSelectOpen) {
return (
Expand Down Expand Up @@ -120,7 +130,7 @@ function AccountSettingsModal({

return (
<SignozModal
open={isOpen}
open
title={modalTitle}
onCancel={handleClose}
onOk={handleSubmit}
Expand Down Expand Up @@ -164,12 +174,9 @@ function AccountSettingsModal({
</Form.Item>

<div className="integration-detail-content">
<IntergrationsUninstallBar
integrationTitle={AWS_INTEGRATION.title}
integrationId={AWS_INTEGRATION.id}
onUnInstallSuccess={handleClose}
removeIntegrationTitle="Remove"
connectionStatus={ConnectionStates.Connected}
<RemoveIntegrationAccount
accountId={account?.id}
onRemoveIntegrationAccountSuccess={handleRemoveIntegrationAccountSuccess}
/>
</div>
</div>
Expand Down
Loading
Loading