mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 08:49:02 +08:00
AWS Integration changes (#7025)
* fix: update AWS accounts API response to return accounts list * feat: display skeleton UI for account actions and refactored rendering logic * chore: update AWS service naming from "AWS Web Services" to "Amazon Web Services" * feat: aws integration success modal changes * feat: auto-select first service when no service is active * feat: display 'enable service' if service hasn't been configured and 'Configure (x/2)' if configured * fix: display no data yet if status is not available * feat: properly handle remove integration account flow * fix: rename accountId param to cloudAccountId * fix: update the aws service list and details api parameter from account_id to cloud_account_id * fix: fix the issue of stale service config modal enabled/disabled state * chore: improve the UI of configure button * feat: add connection parameters support for AWS cloud integration * feat: add optional link support for cloud service dashboards * fix: get the correct supported signals count + a minor refactoring * fix: remove cloudAccountId on success of account remove * chore: update the remove integration copy * refactor: add react query key for AWS connection parameters * fix: correct typo in integration loading state variable name * refactor: move skeleton inline styles to style file and do overall refactoring * chore: address the requested changes
This commit is contained in:
parent
b215c6a0ce
commit
c3164912e6
19
frontend/src/api/Integrations/removeAwsIntegrationAccount.ts
Normal file
19
frontend/src/api/Integrations/removeAwsIntegrationAccount.ts
Normal file
@ -0,0 +1,19 @@
|
||||
import axios from 'api';
|
||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||
|
||||
const removeAwsIntegrationAccount = async (
|
||||
accountId: string,
|
||||
): Promise<SuccessResponse<Record<string, never>> | ErrorResponse> => {
|
||||
const response = await axios.post(
|
||||
`/cloud-integrations/aws/accounts/${accountId}/disconnect`,
|
||||
);
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: response.data.status,
|
||||
payload: response.data.data,
|
||||
};
|
||||
};
|
||||
|
||||
export default removeAwsIntegrationAccount;
|
@ -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,
|
||||
});
|
||||
@ -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 },
|
||||
@ -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;
|
||||
};
|
||||
|
@ -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',
|
||||
};
|
||||
|
@ -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>
|
||||
),
|
||||
},
|
||||
]}
|
||||
|
@ -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>
|
||||
|
@ -1,41 +1,56 @@
|
||||
.hero-section__actions {
|
||||
margin-top: 12px;
|
||||
.hero-section {
|
||||
&__actions {
|
||||
margin-top: 12px;
|
||||
|
||||
&-with-account {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
.hero-section__action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.hero-section__action-button {
|
||||
font-family: 'Inter';
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
padding: 8px 17px;
|
||||
|
||||
&.primary {
|
||||
background: var(--bg-robin-500);
|
||||
border: none;
|
||||
color: var(--bg-vanilla-100);
|
||||
&-with-account {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
&__input-skeleton {
|
||||
width: 300px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
&__new-account-button-skeleton {
|
||||
width: 180px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
&__account-settings-button-skeleton {
|
||||
width: 140px;
|
||||
}
|
||||
&__action-buttons {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--bg-ink-300);
|
||||
color: var(--bg-vanilla-100);
|
||||
gap: 8px;
|
||||
}
|
||||
&__action-button {
|
||||
font-family: 'Inter';
|
||||
border-radius: 2px;
|
||||
background: var(--bg-slate-400);
|
||||
box-shadow: none;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 16px;
|
||||
padding: 8px 17px;
|
||||
|
||||
&.primary {
|
||||
background: var(--bg-robin-500);
|
||||
border: none;
|
||||
color: var(--bg-vanilla-100);
|
||||
}
|
||||
|
||||
&.secondary {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid var(--bg-ink-300);
|
||||
color: var(--bg-vanilla-100);
|
||||
border-radius: 2px;
|
||||
background: var(--bg-slate-400);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
@ -53,15 +53,100 @@ 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
|
||||
className="hero-section__input-skeleton"
|
||||
/>
|
||||
<div className="hero-section__action-buttons">
|
||||
<Skeleton.Button
|
||||
active
|
||||
size="large"
|
||||
className="hero-section__new-account-button-skeleton"
|
||||
/>
|
||||
<Skeleton.Button
|
||||
active
|
||||
size="large"
|
||||
className="hero-section__account-settings-button-skeleton"
|
||||
/>
|
||||
</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],
|
||||
);
|
||||
@ -74,7 +159,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
|
||||
@ -98,60 +183,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>
|
||||
<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)}
|
||||
/>
|
||||
|
||||
{isIntegrationModalOpen && (
|
||||
<CloudAccountSetupModal
|
||||
onClose={(): void => setIsIntegrationModalOpen(false)}
|
||||
/>
|
||||
)}
|
||||
|
||||
<CloudAccountSetupModal
|
||||
isOpen={isIntegrationModalOpen}
|
||||
onClose={(): void => setIsIntegrationModalOpen(false)}
|
||||
/>
|
||||
|
||||
<AccountSettingsModal
|
||||
isOpen={isAccountSettingsModalOpen}
|
||||
onClose={(): void => setIsAccountSettingsModalOpen(false)}
|
||||
account={activeAccount as CloudAccount}
|
||||
setActiveAccount={setActiveAccount}
|
||||
/>
|
||||
{isAccountSettingsModalOpen && (
|
||||
<AccountSettingsModal
|
||||
onClose={(): void => setIsAccountSettingsModalOpen(false)}
|
||||
account={activeAccount as CloudAccount}
|
||||
setActiveAccount={setActiveAccount}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
@ -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 (
|
||||
@ -120,7 +130,7 @@ function AccountSettingsModal({
|
||||
|
||||
return (
|
||||
<SignozModal
|
||||
open={isOpen}
|
||||
open
|
||||
title={modalTitle}
|
||||
onCancel={handleClose}
|
||||
onOk={handleSubmit}
|
||||
@ -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>
|
||||
|
@ -2,11 +2,9 @@ import './CloudAccountSetupModal.style.scss';
|
||||
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import SignozModal from 'components/SignozModal/SignozModal';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { useIntegrationModal } from 'hooks/integrations/aws/useIntegrationModal';
|
||||
import { SquareArrowOutUpRight } from 'lucide-react';
|
||||
import { useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import {
|
||||
ActiveViewEnum,
|
||||
@ -18,7 +16,6 @@ import { RegionSelector } from './RegionSelector';
|
||||
import { SuccessView } from './SuccessView';
|
||||
|
||||
function CloudAccountSetupModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
}: IntegrationModalProps): JSX.Element {
|
||||
const {
|
||||
@ -41,6 +38,8 @@ function CloudAccountSetupModal({
|
||||
accountId,
|
||||
selectedDeploymentRegion,
|
||||
handleRegionChange,
|
||||
connectionParams,
|
||||
isConnectionParamsLoading,
|
||||
} = useIntegrationModal({ onClose });
|
||||
|
||||
const renderContent = useCallback(() => {
|
||||
@ -71,6 +70,8 @@ function CloudAccountSetupModal({
|
||||
accountId={accountId}
|
||||
selectedDeploymentRegion={selectedDeploymentRegion}
|
||||
handleRegionChange={handleRegionChange}
|
||||
connectionParams={connectionParams}
|
||||
isConnectionParamsLoading={isConnectionParamsLoading}
|
||||
/>
|
||||
);
|
||||
}, [
|
||||
@ -86,6 +87,8 @@ function CloudAccountSetupModal({
|
||||
accountId,
|
||||
selectedDeploymentRegion,
|
||||
handleRegionChange,
|
||||
connectionParams,
|
||||
isConnectionParamsLoading,
|
||||
setSelectedRegions,
|
||||
setIncludeAllRegions,
|
||||
]);
|
||||
@ -96,11 +99,6 @@ function CloudAccountSetupModal({
|
||||
[selectedRegions, allRegions],
|
||||
);
|
||||
|
||||
const navigate = useNavigate();
|
||||
const handleGoToDashboards = useCallback((): void => {
|
||||
navigate(ROUTES.ALL_DASHBOARD);
|
||||
}, [navigate]);
|
||||
|
||||
const getModalConfig = useCallback(() => {
|
||||
// Handle success state first
|
||||
if (modalState === ModalStateEnum.SUCCESS) {
|
||||
@ -108,11 +106,11 @@ function CloudAccountSetupModal({
|
||||
title: 'AWS Webservice Integration',
|
||||
okText: (
|
||||
<div className="cloud-account-setup-success-view__footer-button">
|
||||
Go to Dashboards
|
||||
Continue
|
||||
</div>
|
||||
),
|
||||
block: true,
|
||||
onOk: handleGoToDashboards,
|
||||
onOk: handleClose,
|
||||
cancelButtonProps: { style: { display: 'none' } },
|
||||
disabled: false,
|
||||
};
|
||||
@ -151,7 +149,7 @@ function CloudAccountSetupModal({
|
||||
isLoading,
|
||||
isGeneratingUrl,
|
||||
activeView,
|
||||
handleGoToDashboards,
|
||||
handleClose,
|
||||
setActiveView,
|
||||
]);
|
||||
|
||||
@ -159,7 +157,7 @@ function CloudAccountSetupModal({
|
||||
|
||||
return (
|
||||
<SignozModal
|
||||
open={isOpen}
|
||||
open
|
||||
className="cloud-account-setup-modal"
|
||||
title={modalConfig.title}
|
||||
onCancel={handleClose}
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
MonitoringRegionsSection,
|
||||
RegionDeploymentSection,
|
||||
} from './IntegrateNowFormSections';
|
||||
import RenderConnectionFields from './RenderConnectionParams';
|
||||
|
||||
const allRegions = (): string[] =>
|
||||
regions.flatMap((r) => r.subRegions.map((sr) => sr.name));
|
||||
@ -35,6 +36,8 @@ export function RegionForm({
|
||||
accountId,
|
||||
selectedDeploymentRegion,
|
||||
handleRegionChange,
|
||||
connectionParams,
|
||||
isConnectionParamsLoading,
|
||||
}: RegionFormProps): JSX.Element {
|
||||
const startTimeRef = useRef(Date.now());
|
||||
const refetchInterval = 10 * 1000;
|
||||
@ -88,6 +91,11 @@ export function RegionForm({
|
||||
isFormDisabled={isFormDisabled}
|
||||
/>
|
||||
<ComplianceNote />
|
||||
<RenderConnectionFields
|
||||
isConnectionParamsLoading={isConnectionParamsLoading}
|
||||
connectionParams={connectionParams}
|
||||
isFormDisabled={isFormDisabled}
|
||||
/>
|
||||
</div>
|
||||
</Form>
|
||||
);
|
||||
|
@ -0,0 +1,48 @@
|
||||
.remove-integration-account {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding: 16px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid rgba(218, 85, 101, 0.2);
|
||||
background: rgba(218, 85, 101, 0.06);
|
||||
&__header {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
}
|
||||
|
||||
&__title {
|
||||
color: var(--bg-cherry-500);
|
||||
font-size: 14px;
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
&__subtitle {
|
||||
color: var(--bg-cherry-300);
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
letter-spacing: -0.07px;
|
||||
}
|
||||
|
||||
&__button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: var(--bg-cherry-500);
|
||||
border: none;
|
||||
color: var(--bg-vanilla-100);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
line-height: 13.3px; /* 110.833% */
|
||||
padding: 9px 13px;
|
||||
.ant-btn-icon {
|
||||
margin-inline-end: 4px !important;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&.ant-btn-default {
|
||||
color: var(--bg-vanilla-300) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
import './RemoveIntegrationAccount.scss';
|
||||
|
||||
import { Button, Modal } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import removeAwsIntegrationAccount from 'api/Integrations/removeAwsIntegrationAccount';
|
||||
import { SOMETHING_WENT_WRONG } from 'constants/api';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { X } from 'lucide-react';
|
||||
import { INTEGRATION_TELEMETRY_EVENTS } from 'pages/Integrations/utils';
|
||||
import { useState } from 'react';
|
||||
import { useMutation } from 'react-query';
|
||||
|
||||
function RemoveIntegrationAccount({
|
||||
accountId,
|
||||
onRemoveIntegrationAccountSuccess,
|
||||
}: {
|
||||
accountId: string;
|
||||
onRemoveIntegrationAccountSuccess: () => void;
|
||||
}): JSX.Element {
|
||||
const { notifications } = useNotifications();
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
|
||||
const showModal = (): void => {
|
||||
setIsModalOpen(true);
|
||||
};
|
||||
|
||||
const {
|
||||
mutate: removeIntegration,
|
||||
isLoading: isRemoveIntegrationLoading,
|
||||
} = useMutation(removeAwsIntegrationAccount, {
|
||||
onSuccess: () => {
|
||||
onRemoveIntegrationAccountSuccess?.();
|
||||
setIsModalOpen(false);
|
||||
},
|
||||
onError: () => {
|
||||
notifications.error({
|
||||
message: SOMETHING_WENT_WRONG,
|
||||
});
|
||||
},
|
||||
});
|
||||
const handleOk = (): void => {
|
||||
logEvent(INTEGRATION_TELEMETRY_EVENTS.AWS_INTEGRATION_ACCOUNT_REMOVED, {
|
||||
accountId,
|
||||
});
|
||||
removeIntegration(accountId);
|
||||
};
|
||||
|
||||
const handleCancel = (): void => {
|
||||
setIsModalOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="remove-integration-account">
|
||||
<div className="remove-integration-account__header">
|
||||
<div className="remove-integration-account__title">Remove Integration</div>
|
||||
<div className="remove-integration-account__subtitle">
|
||||
Removing this integration won't delete any existing data but will stop
|
||||
collecting new data from AWS.
|
||||
</div>
|
||||
</div>
|
||||
<Button
|
||||
className="remove-integration-account__button"
|
||||
icon={<X size={14} />}
|
||||
onClick={(): void => showModal()}
|
||||
>
|
||||
Remove
|
||||
</Button>
|
||||
<Modal
|
||||
className="remove-integration-modal"
|
||||
open={isModalOpen}
|
||||
title="Remove integration"
|
||||
onOk={handleOk}
|
||||
onCancel={handleCancel}
|
||||
okText="Remove Integration"
|
||||
okButtonProps={{
|
||||
danger: true,
|
||||
disabled: isRemoveIntegrationLoading,
|
||||
}}
|
||||
>
|
||||
<div className="remove-integration-modal__text">
|
||||
Removing this account will remove all components created for sending
|
||||
telemetry to SigNoz in your AWS account within the next ~15 minutes
|
||||
(cloudformation stacks named signoz-integration-telemetry-collection in
|
||||
enabled regions). <br />
|
||||
<br />
|
||||
After that, you can delete the cloudformation stack that was created
|
||||
manually when connecting this account.
|
||||
</div>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RemoveIntegrationAccount;
|
@ -0,0 +1,61 @@
|
||||
import { Form, Input } from 'antd';
|
||||
import { ConnectionParams } from 'types/api/integrations/aws';
|
||||
|
||||
function RenderConnectionFields({
|
||||
isConnectionParamsLoading,
|
||||
connectionParams,
|
||||
isFormDisabled,
|
||||
}: {
|
||||
isConnectionParamsLoading?: boolean;
|
||||
connectionParams?: ConnectionParams | null;
|
||||
isFormDisabled?: boolean;
|
||||
}): JSX.Element | null {
|
||||
if (
|
||||
isConnectionParamsLoading ||
|
||||
(!!connectionParams?.ingestion_url &&
|
||||
!!connectionParams?.ingestion_key &&
|
||||
!!connectionParams?.signoz_api_url)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Form.Item name="connection_params">
|
||||
{!connectionParams?.ingestion_url && (
|
||||
<Form.Item
|
||||
name="ingestion_url"
|
||||
label="Ingestion URL"
|
||||
rules={[{ required: true, message: 'Please enter ingestion URL' }]}
|
||||
>
|
||||
<Input placeholder="Enter ingestion URL" disabled={isFormDisabled} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{!connectionParams?.ingestion_key && (
|
||||
<Form.Item
|
||||
name="ingestion_key"
|
||||
label="Ingestion Key"
|
||||
rules={[{ required: true, message: 'Please enter ingestion key' }]}
|
||||
>
|
||||
<Input placeholder="Enter ingestion key" disabled={isFormDisabled} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{!connectionParams?.signoz_api_url && (
|
||||
<Form.Item
|
||||
name="signoz_api_url"
|
||||
label="SigNoz API URL"
|
||||
rules={[{ required: true, message: 'Please enter SigNoz API URL' }]}
|
||||
>
|
||||
<Input placeholder="Enter SigNoz API URL" disabled={isFormDisabled} />
|
||||
</Form.Item>
|
||||
)}
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
|
||||
RenderConnectionFields.defaultProps = {
|
||||
connectionParams: null,
|
||||
isFormDisabled: false,
|
||||
isConnectionParamsLoading: false,
|
||||
};
|
||||
|
||||
export default RenderConnectionFields;
|
@ -53,23 +53,18 @@ export function SuccessView(): JSX.Element {
|
||||
WHAT NEXT
|
||||
</h4>
|
||||
<div className="what-next-items-wrapper">
|
||||
{[
|
||||
'Understand your AWS services with SigNoz’s out-of-the-box dashboards',
|
||||
'Set up alerts for real-time monitoring.',
|
||||
'Track logs and traces.',
|
||||
].map((item) => (
|
||||
<Alert
|
||||
key={item}
|
||||
message={
|
||||
<div className="what-next-items-wrapper__item">
|
||||
<div className="what-next-item-bullet-icon">•</div>
|
||||
<div className="what-next-item-text">{item}</div>
|
||||
<Alert
|
||||
message={
|
||||
<div className="what-next-items-wrapper__item">
|
||||
<div className="what-next-item-bullet-icon">•</div>
|
||||
<div className="what-next-item-text">
|
||||
Set up your AWS services effortlessly under your enabled account.
|
||||
</div>
|
||||
}
|
||||
type="info"
|
||||
className="what-next-items-wrapper__item"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
}
|
||||
type="info"
|
||||
className="what-next-items-wrapper__item"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { FormInstance } from 'antd';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { ConnectionParams } from 'types/api/integrations/aws';
|
||||
|
||||
export enum ActiveViewEnum {
|
||||
SELECT_REGIONS = 'select-regions',
|
||||
@ -25,9 +26,10 @@ export interface RegionFormProps {
|
||||
accountId?: string;
|
||||
selectedDeploymentRegion: string | undefined;
|
||||
handleRegionChange: (value: string) => void;
|
||||
connectionParams?: ConnectionParams;
|
||||
isConnectionParamsLoading?: boolean;
|
||||
}
|
||||
|
||||
export interface IntegrationModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { ServiceData } from './types';
|
||||
|
||||
function DashboardItem({
|
||||
@ -5,8 +7,8 @@ function DashboardItem({
|
||||
}: {
|
||||
dashboard: ServiceData['assets']['dashboards'][number];
|
||||
}): JSX.Element {
|
||||
return (
|
||||
<div className="cloud-service-dashboard-item">
|
||||
const content = (
|
||||
<>
|
||||
<div className="cloud-service-dashboard-item__title">{dashboard.title}</div>
|
||||
<div className="cloud-service-dashboard-item__preview">
|
||||
<img
|
||||
@ -15,6 +17,18 @@ function DashboardItem({
|
||||
className="cloud-service-dashboard-item__preview-image"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="cloud-service-dashboard-item">
|
||||
{dashboard.url ? (
|
||||
<Link to={dashboard.url} className="cloud-service-dashboard-item__link">
|
||||
{content}
|
||||
</Link>
|
||||
) : (
|
||||
content
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Tabs, TabsProps } from 'antd';
|
||||
import { MarkdownRenderer } from 'components/MarkdownRenderer/MarkdownRenderer';
|
||||
import Spinner from 'components/Spinner';
|
||||
@ -8,8 +7,7 @@ import { IServiceStatus } from 'container/CloudIntegrationPage/ServicesSection/t
|
||||
import dayjs from 'dayjs';
|
||||
import { useServiceDetails } from 'hooks/integrations/aws/useServiceDetails';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { Wrench } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import ConfigureServiceModal from './ConfigureServiceModal';
|
||||
|
||||
@ -38,7 +36,7 @@ const getStatus = (
|
||||
function ServiceStatus({
|
||||
serviceStatus,
|
||||
}: {
|
||||
serviceStatus: IServiceStatus | null;
|
||||
serviceStatus: IServiceStatus | undefined;
|
||||
}): JSX.Element {
|
||||
const logsLastReceivedTimestamp = serviceStatus?.logs?.last_received_ts_ms;
|
||||
const metricsLastReceivedTimestamp =
|
||||
@ -54,7 +52,7 @@ function ServiceStatus({
|
||||
|
||||
function ServiceDetails(): JSX.Element | null {
|
||||
const urlQuery = useUrlQuery();
|
||||
const accountId = urlQuery.get('accountId');
|
||||
const cloudAccountId = urlQuery.get('cloudAccountId');
|
||||
const serviceId = urlQuery.get('service');
|
||||
const [isConfigureServiceModalOpen, setIsConfigureServiceModalOpen] = useState(
|
||||
false,
|
||||
@ -62,7 +60,24 @@ function ServiceDetails(): JSX.Element | null {
|
||||
|
||||
const { data: serviceDetailsData, isLoading } = useServiceDetails(
|
||||
serviceId || '',
|
||||
accountId || undefined,
|
||||
cloudAccountId || undefined,
|
||||
);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
const { config, supported_signals } = serviceDetailsData ?? {};
|
||||
|
||||
const totalSupportedSignals = Object.entries(supported_signals || {}).filter(
|
||||
([, value]) => !!value,
|
||||
).length;
|
||||
const enabledSignals = useMemo(
|
||||
() =>
|
||||
Object.values(config || {}).filter((item) => item && item.enabled).length,
|
||||
[config],
|
||||
);
|
||||
|
||||
const isAnySignalConfigured = useMemo(
|
||||
() => !!config?.logs?.enabled || !!config?.metrics?.enabled,
|
||||
[config],
|
||||
);
|
||||
|
||||
if (isLoading) {
|
||||
@ -96,16 +111,22 @@ function ServiceDetails(): JSX.Element | null {
|
||||
<div className="service-details__title-bar">
|
||||
<div className="service-details__details-title">Details</div>
|
||||
<div className="service-details__right-actions">
|
||||
{serviceDetailsData?.status && (
|
||||
<ServiceStatus serviceStatus={serviceDetailsData.status} />
|
||||
)}
|
||||
{!!accountId && (
|
||||
<ServiceStatus serviceStatus={serviceDetailsData.status} />
|
||||
|
||||
{!!cloudAccountId && isAnySignalConfigured ? (
|
||||
<Button
|
||||
className="configure-button"
|
||||
className="configure-button configure-button--default"
|
||||
onClick={(): void => setIsConfigureServiceModalOpen(true)}
|
||||
>
|
||||
<Wrench size={12} color={Color.BG_VANILLA_400} />
|
||||
Configure
|
||||
Configure ({enabledSignals}/{totalSupportedSignals})
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
type="primary"
|
||||
className="configure-button configure-button--primary"
|
||||
onClick={(): void => setIsConfigureServiceModalOpen(true)}
|
||||
>
|
||||
Enable Service
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@ -119,15 +140,17 @@ function ServiceDetails(): JSX.Element | null {
|
||||
<div className="service-details__tabs">
|
||||
<Tabs items={tabItems} />
|
||||
</div>
|
||||
<ConfigureServiceModal
|
||||
isOpen={isConfigureServiceModalOpen}
|
||||
onClose={(): void => setIsConfigureServiceModalOpen(false)}
|
||||
serviceName={serviceDetailsData.title}
|
||||
serviceId={serviceId || ''}
|
||||
cloudAccountId={accountId || ''}
|
||||
initialConfig={serviceDetailsData.config}
|
||||
supportedSignals={serviceDetailsData.supported_signals || {}}
|
||||
/>
|
||||
{isConfigureServiceModalOpen && (
|
||||
<ConfigureServiceModal
|
||||
isOpen
|
||||
onClose={(): void => setIsConfigureServiceModalOpen(false)}
|
||||
serviceName={serviceDetailsData.title}
|
||||
serviceId={serviceId || ''}
|
||||
cloudAccountId={cloudAccountId || ''}
|
||||
initialConfig={serviceDetailsData.config}
|
||||
supportedSignals={serviceDetailsData.supported_signals || {}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,26 +1,34 @@
|
||||
import Spinner from 'components/Spinner';
|
||||
import { useGetAccountServices } from 'hooks/integrations/aws/useGetAccountServices';
|
||||
import useUrlQuery from 'hooks/useUrlQuery';
|
||||
import { useMemo } from 'react';
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
|
||||
import ServiceItem from './ServiceItem';
|
||||
|
||||
interface ServicesListProps {
|
||||
accountId: string;
|
||||
cloudAccountId: string;
|
||||
filter: 'all_services' | 'enabled' | 'available';
|
||||
}
|
||||
|
||||
function ServicesList({ accountId, filter }: ServicesListProps): JSX.Element {
|
||||
function ServicesList({
|
||||
cloudAccountId,
|
||||
filter,
|
||||
}: ServicesListProps): JSX.Element {
|
||||
const urlQuery = useUrlQuery();
|
||||
const navigate = useNavigate();
|
||||
const { data: services = [], isLoading } = useGetAccountServices(accountId);
|
||||
const { data: services = [], isLoading } = useGetAccountServices(
|
||||
cloudAccountId,
|
||||
);
|
||||
const activeService = urlQuery.get('service');
|
||||
|
||||
const handleServiceClick = (serviceId: string): void => {
|
||||
urlQuery.set('service', serviceId);
|
||||
navigate({ search: urlQuery.toString() });
|
||||
};
|
||||
const handleActiveService = useCallback(
|
||||
(serviceId: string): void => {
|
||||
urlQuery.set('service', serviceId);
|
||||
navigate({ search: urlQuery.toString() });
|
||||
},
|
||||
[navigate, urlQuery],
|
||||
);
|
||||
|
||||
const filteredServices = useMemo(() => {
|
||||
if (filter === 'all_services') return services;
|
||||
@ -32,6 +40,12 @@ function ServicesList({ accountId, filter }: ServicesListProps): JSX.Element {
|
||||
});
|
||||
}, [services, filter]);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeService || !services?.length) return;
|
||||
|
||||
handleActiveService(services[0].id);
|
||||
}, [services, activeService, handleActiveService]);
|
||||
|
||||
if (isLoading) return <Spinner size="large" height="25vh" />;
|
||||
if (!services) return <div>No services found</div>;
|
||||
|
||||
@ -41,7 +55,7 @@ function ServicesList({ accountId, filter }: ServicesListProps): JSX.Element {
|
||||
<ServiceItem
|
||||
key={service.id}
|
||||
service={service}
|
||||
onClick={handleServiceClick}
|
||||
onClick={handleActiveService}
|
||||
isActive={service.id === activeService}
|
||||
/>
|
||||
))}
|
||||
|
@ -135,18 +135,25 @@
|
||||
color: var(--bg-cherry-400);
|
||||
}
|
||||
}
|
||||
|
||||
.configure-button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
color: var(--bg-vanilla-400);
|
||||
background: var(--bg-ink-300);
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
line-height: 10px; /* 83.333% */
|
||||
letter-spacing: 0.12px;
|
||||
font-weight: 500;
|
||||
width: 116px;
|
||||
box-shadow: none;
|
||||
&--default {
|
||||
color: var(--bg-vanilla-400);
|
||||
background: var(--bg-slate-400);
|
||||
border: 1px solid var(--bg-slate-400);
|
||||
}
|
||||
&--primary {
|
||||
background-color: var(--bg-robin-500);
|
||||
color: var(--bg-vanilla-100);
|
||||
font-weight: 500;
|
||||
color: var(--Vanilla-100, #fff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,17 +20,17 @@ export enum ServiceFilterType {
|
||||
}
|
||||
|
||||
interface ServicesFilterProps {
|
||||
accountId: string;
|
||||
cloudAccountId: string;
|
||||
onFilterChange: (value: ServiceFilterType) => void;
|
||||
}
|
||||
|
||||
function ServicesFilter({
|
||||
accountId,
|
||||
cloudAccountId,
|
||||
onFilterChange,
|
||||
}: ServicesFilterProps): JSX.Element | null {
|
||||
const { data: services, isLoading } = useQuery(
|
||||
[REACT_QUERY_KEY.AWS_SERVICES, accountId],
|
||||
() => getAwsServices(accountId),
|
||||
[REACT_QUERY_KEY.AWS_SERVICES, cloudAccountId],
|
||||
() => getAwsServices(cloudAccountId),
|
||||
);
|
||||
|
||||
const { enabledCount, availableCount } = useMemo(() => {
|
||||
@ -77,7 +77,7 @@ function ServicesFilter({
|
||||
|
||||
function ServicesSection(): JSX.Element {
|
||||
const urlQuery = useUrlQuery();
|
||||
const accountId = urlQuery.get('accountId') || '';
|
||||
const cloudAccountId = urlQuery.get('cloudAccountId') || '';
|
||||
|
||||
const [activeFilter, setActiveFilter] = useState<
|
||||
'all_services' | 'enabled' | 'available'
|
||||
@ -86,8 +86,11 @@ function ServicesSection(): JSX.Element {
|
||||
return (
|
||||
<div className="services-section">
|
||||
<div className="services-section__sidebar">
|
||||
<ServicesFilter accountId={accountId} onFilterChange={setActiveFilter} />
|
||||
<ServicesList accountId={accountId} filter={activeFilter} />
|
||||
<ServicesFilter
|
||||
cloudAccountId={cloudAccountId}
|
||||
onFilterChange={setActiveFilter}
|
||||
/>
|
||||
<ServicesList cloudAccountId={cloudAccountId} filter={activeFilter} />
|
||||
</div>
|
||||
<div className="services-section__content">
|
||||
<ServiceDetails />
|
||||
|
17
frontend/src/hooks/integrations/aws/useConnectionParams.ts
Normal file
17
frontend/src/hooks/integrations/aws/useConnectionParams.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { getConnectionParams } from 'api/integrations/aws';
|
||||
import { AxiosError } from 'axios';
|
||||
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
|
||||
import { useQuery, UseQueryOptions, UseQueryResult } from 'react-query';
|
||||
import { ConnectionParams } from 'types/api/integrations/aws';
|
||||
|
||||
export function useConnectionParams({
|
||||
options,
|
||||
}: {
|
||||
options?: UseQueryOptions<ConnectionParams, AxiosError>;
|
||||
}): UseQueryResult<ConnectionParams, AxiosError> {
|
||||
return useQuery<ConnectionParams, AxiosError>(
|
||||
[REACT_QUERY_KEY.AWS_GET_CONNECTION_PARAMS],
|
||||
getConnectionParams,
|
||||
options,
|
||||
);
|
||||
}
|
@ -4,6 +4,7 @@ import {
|
||||
ActiveViewEnum,
|
||||
ModalStateEnum,
|
||||
} from 'container/CloudIntegrationPage/HeroSection/types';
|
||||
import useAxiosError from 'hooks/useAxiosError';
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
@ -13,11 +14,13 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
import {
|
||||
ConnectionParams,
|
||||
ConnectionUrlResponse,
|
||||
GenerateConnectionUrlPayload,
|
||||
} from 'types/api/integrations/aws';
|
||||
import { regions } from 'utils/regions';
|
||||
|
||||
import { useConnectionParams } from './useConnectionParams';
|
||||
import { useGenerateConnectionUrl } from './useGenerateConnectionUrl';
|
||||
|
||||
interface UseIntegrationModalProps {
|
||||
@ -44,6 +47,8 @@ interface UseIntegrationModal {
|
||||
accountId?: string;
|
||||
selectedDeploymentRegion: string | undefined;
|
||||
handleRegionChange: (value: string) => void;
|
||||
connectionParams?: ConnectionParams;
|
||||
isConnectionParamsLoading: boolean;
|
||||
}
|
||||
|
||||
export function useIntegrationModal({
|
||||
@ -102,6 +107,12 @@ export function useIntegrationModal({
|
||||
isLoading: isGeneratingUrl,
|
||||
} = useGenerateConnectionUrl();
|
||||
|
||||
const handleError = useAxiosError();
|
||||
const {
|
||||
data: connectionParams,
|
||||
isLoading: isConnectionParamsLoading,
|
||||
} = useConnectionParams({ options: { onError: handleError } });
|
||||
|
||||
const handleGenerateUrl = useCallback(
|
||||
(payload: GenerateConnectionUrlPayload): void => {
|
||||
generateUrl(payload, {
|
||||
@ -126,6 +137,9 @@ export function useIntegrationModal({
|
||||
const payload: GenerateConnectionUrlPayload = {
|
||||
agent_config: {
|
||||
region: values.region,
|
||||
ingestion_url: connectionParams?.ingestion_url || values.ingestion_url,
|
||||
ingestion_key: connectionParams?.ingestion_key || values.ingestion_key,
|
||||
signoz_api_url: connectionParams?.signoz_api_url || values.signoz_api_url,
|
||||
},
|
||||
account_config: {
|
||||
regions: includeAllRegions ? ['all'] : selectedRegions,
|
||||
@ -138,7 +152,13 @@ export function useIntegrationModal({
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
}, [form, includeAllRegions, selectedRegions, handleGenerateUrl]);
|
||||
}, [
|
||||
form,
|
||||
includeAllRegions,
|
||||
selectedRegions,
|
||||
handleGenerateUrl,
|
||||
connectionParams,
|
||||
]);
|
||||
|
||||
return {
|
||||
form,
|
||||
@ -160,5 +180,7 @@ export function useIntegrationModal({
|
||||
setModalState,
|
||||
selectedDeploymentRegion,
|
||||
handleRegionChange,
|
||||
connectionParams,
|
||||
isConnectionParamsLoading,
|
||||
};
|
||||
}
|
||||
|
@ -5,11 +5,11 @@ import { useQuery, UseQueryResult } from 'react-query';
|
||||
|
||||
export function useServiceDetails(
|
||||
serviceId: string,
|
||||
accountId?: string,
|
||||
cloudAccountId?: string,
|
||||
): UseQueryResult<ServiceData> {
|
||||
return useQuery(
|
||||
[REACT_QUERY_KEY.AWS_SERVICE_DETAILS, serviceId, accountId],
|
||||
() => getServiceDetails(serviceId, accountId),
|
||||
[REACT_QUERY_KEY.AWS_SERVICE_DETAILS, serviceId, cloudAccountId],
|
||||
() => getServiceDetails(serviceId, cloudAccountId),
|
||||
{
|
||||
enabled: !!serviceId,
|
||||
},
|
||||
|
@ -16,7 +16,7 @@ import { handleContactSupport, INTEGRATION_TYPES } from './utils';
|
||||
|
||||
export const AWS_INTEGRATION = {
|
||||
id: INTEGRATION_TYPES.AWS_INTEGRATION,
|
||||
title: 'AWS Web Services',
|
||||
title: 'Amazon Web Services',
|
||||
description: 'One-click setup for AWS monitoring with SigNoz',
|
||||
author: {
|
||||
name: 'SigNoz',
|
||||
|
@ -19,6 +19,8 @@ export const INTEGRATION_TELEMETRY_EVENTS = {
|
||||
'Integrations Detail Page: Clicked remove Integration button for integration',
|
||||
INTEGRATIONS_DETAIL_CONFIGURE_INSTRUCTION:
|
||||
'Integrations Detail Page: Navigated to configure an integration',
|
||||
AWS_INTEGRATION_ACCOUNT_REMOVED:
|
||||
'AWS Integration Detail page: Clicked remove Integration button for integration',
|
||||
};
|
||||
|
||||
export const INTEGRATION_TYPES = {
|
||||
|
@ -1,9 +1,15 @@
|
||||
import { CloudAccount } from 'container/CloudIntegrationPage/ServicesSection/types';
|
||||
|
||||
export interface ConnectionParams {
|
||||
ingestion_url?: string;
|
||||
ingestion_key?: string;
|
||||
signoz_api_url?: string;
|
||||
}
|
||||
|
||||
export interface GenerateConnectionUrlPayload {
|
||||
agent_config: {
|
||||
region: string;
|
||||
};
|
||||
} & ConnectionParams;
|
||||
account_config: {
|
||||
regions: string[];
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user