mirror of
https://github.com/SigNoz/signoz.git
synced 2026-08-10 15:00:47 +01:00
feat(gcp): add account settings (edit) drawer
Adds the GCP edit-account drawer for managing monitored project ids and wires it into AccountActions so 'Edit Account' works for GCP.
This commit is contained in:
@@ -18,6 +18,7 @@ import { ChevronDown, Dot, PencilLine, Plug, Plus } from '@signozhq/icons';
|
||||
import AzureCloudAccountSetupModal from '../../AzureCloudServices/AddNewAccount/CloudAccountSetupModal';
|
||||
import AzureAccountSettingsModal from '../../AzureCloudServices/EditAccount/AccountSettingsModal';
|
||||
import GcpCloudAccountSetupDrawer from '../../GoogleCloudPlatform/AddNewAccount/CloudAccountSetupDrawer';
|
||||
import GcpAccountSettingsDrawer from '../../GoogleCloudPlatform/EditAccount/AccountSettingsDrawer';
|
||||
import {
|
||||
mapAccountDtoToAwsCloudAccount,
|
||||
mapAccountDtoToAzureCloudAccount,
|
||||
@@ -310,6 +311,13 @@ function AccountActions({ type }: { type: IntegrationType }): JSX.Element {
|
||||
setActiveAccount={setActiveAccount}
|
||||
/>
|
||||
)}
|
||||
{type === IntegrationType.GCP_SERVICES && (
|
||||
<GcpAccountSettingsDrawer
|
||||
onClose={(): void => setIsAccountSettingsModalOpen(false)}
|
||||
account={activeAccount}
|
||||
setActiveAccount={setActiveAccount}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,165 @@
|
||||
import { Dispatch, SetStateAction, useMemo } from 'react';
|
||||
import { useQueryClient } from 'react-query';
|
||||
import { Save } from '@signozhq/icons';
|
||||
import { Button } from '@signozhq/ui/button';
|
||||
import { DrawerWrapper } from '@signozhq/ui/drawer';
|
||||
import { Form, Select } from 'antd';
|
||||
import { invalidateListAccounts } from 'api/generated/services/cloudintegration';
|
||||
import { INTEGRATION_TYPES } from 'container/Integrations/constants';
|
||||
import { CloudAccount } from 'container/Integrations/types';
|
||||
import { useAccountSettingsDrawer } from 'hooks/integration/gcp/useAccountSettingsDrawer';
|
||||
|
||||
import RemoveIntegrationAccount from '../../RemoveAccount/RemoveIntegrationAccount';
|
||||
|
||||
import '../../AmazonWebServices/EditAccount/AccountSettingsModal.style.scss';
|
||||
|
||||
interface AccountSettingsDrawerProps {
|
||||
onClose: () => void;
|
||||
account: CloudAccount;
|
||||
setActiveAccount: Dispatch<SetStateAction<CloudAccount | null>>;
|
||||
}
|
||||
|
||||
function AccountSettingsDrawer({
|
||||
onClose,
|
||||
account,
|
||||
setActiveAccount,
|
||||
}: AccountSettingsDrawerProps): JSX.Element {
|
||||
const {
|
||||
form,
|
||||
isLoading,
|
||||
projectIds,
|
||||
isSaveDisabled,
|
||||
setProjectIds,
|
||||
handleSubmit,
|
||||
handleClose,
|
||||
} = useAccountSettingsDrawer({ onClose, account, setActiveAccount });
|
||||
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const gcpConfig = useMemo(
|
||||
() => ('project_ids' in account.config ? account.config : null),
|
||||
[account.config],
|
||||
);
|
||||
|
||||
return (
|
||||
<DrawerWrapper
|
||||
open={true}
|
||||
className="account-settings-modal"
|
||||
title="Account Settings"
|
||||
direction="right"
|
||||
showCloseButton
|
||||
onOpenChange={(open): void => {
|
||||
if (!open) {
|
||||
handleClose();
|
||||
}
|
||||
}}
|
||||
width="wide"
|
||||
footer={
|
||||
<div className="account-settings-modal__footer">
|
||||
<RemoveIntegrationAccount
|
||||
accountId={account?.id}
|
||||
onRemoveIntegrationAccountSuccess={(): void => {
|
||||
void invalidateListAccounts(queryClient, {
|
||||
cloudProvider: INTEGRATION_TYPES.GCP,
|
||||
});
|
||||
setActiveAccount(null);
|
||||
handleClose();
|
||||
}}
|
||||
cloudProvider={INTEGRATION_TYPES.GCP}
|
||||
/>
|
||||
<Button
|
||||
variant="solid"
|
||||
color="secondary"
|
||||
disabled={isSaveDisabled}
|
||||
onClick={handleSubmit}
|
||||
loading={isLoading}
|
||||
prefix={<Save size={14} />}
|
||||
data-testid="gcp-update-account-btn"
|
||||
>
|
||||
Update Changes
|
||||
</Button>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={{
|
||||
projectIds: gcpConfig?.project_ids || [],
|
||||
}}
|
||||
>
|
||||
<div className="account-settings-modal__body">
|
||||
<div className="account-settings-modal__body-account-info">
|
||||
<div className="account-settings-modal__body-account-info-connected-account-details">
|
||||
<div className="account-settings-modal__body-account-info-connected-account-details-title">
|
||||
Connected Account details
|
||||
</div>
|
||||
<div className="account-settings-modal__body-account-info-connected-account-details-account-id">
|
||||
Account Name:{' '}
|
||||
<span className="account-settings-modal__body-account-info-connected-account-details-account-id-account-id">
|
||||
{account?.providerAccountId}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{gcpConfig?.deployment_project_id && (
|
||||
<div className="account-settings-modal__body-region-selector">
|
||||
<div className="account-settings-modal__body-region-selector-title">
|
||||
Deployment project ID
|
||||
</div>
|
||||
<div className="account-settings-modal__body-region-selector-description">
|
||||
{gcpConfig.deployment_project_id}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{gcpConfig?.deployment_region && (
|
||||
<div className="account-settings-modal__body-region-selector">
|
||||
<div className="account-settings-modal__body-region-selector-title">
|
||||
Deployment region
|
||||
</div>
|
||||
<div className="account-settings-modal__body-region-selector-description">
|
||||
{gcpConfig.deployment_region}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="account-settings-modal__body-region-selector">
|
||||
<div className="account-settings-modal__body-region-selector-title">
|
||||
Projects to monitor
|
||||
</div>
|
||||
<div className="account-settings-modal__body-region-selector-description">
|
||||
Update the GCP project IDs that should be monitored.
|
||||
</div>
|
||||
|
||||
<Form.Item
|
||||
name="projectIds"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
type: 'array',
|
||||
min: 1,
|
||||
message: 'Please add at least one project ID',
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
mode="tags"
|
||||
value={projectIds}
|
||||
tokenSeparators={[',']}
|
||||
onChange={(values): void => {
|
||||
setProjectIds(values);
|
||||
form.setFieldValue('projectIds', values);
|
||||
}}
|
||||
data-testid="gcp-edit-project-ids-select"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</DrawerWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default AccountSettingsDrawer;
|
||||
148
frontend/src/hooks/integration/gcp/useAccountSettingsDrawer.ts
Normal file
148
frontend/src/hooks/integration/gcp/useAccountSettingsDrawer.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import {
|
||||
Dispatch,
|
||||
SetStateAction,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from 'react';
|
||||
import { toast } from '@signozhq/ui/sonner';
|
||||
import { Form } from 'antd';
|
||||
import { FormInstance } from 'antd/lib';
|
||||
import { useUpdateAccount } from 'api/generated/services/cloudintegration';
|
||||
import { INTEGRATION_TYPES } from 'container/Integrations/constants';
|
||||
import { CloudAccount } from 'container/Integrations/types';
|
||||
import { isEqual } from 'lodash-es';
|
||||
|
||||
import logEvent from '../../../api/common/logEvent';
|
||||
|
||||
interface UseAccountSettingsDrawerProps {
|
||||
onClose: () => void;
|
||||
account: CloudAccount;
|
||||
setActiveAccount: Dispatch<SetStateAction<CloudAccount | null>>;
|
||||
}
|
||||
|
||||
interface UseAccountSettingsDrawer {
|
||||
form: FormInstance;
|
||||
isLoading: boolean;
|
||||
projectIds: string[];
|
||||
isSaveDisabled: boolean;
|
||||
setProjectIds: Dispatch<SetStateAction<string[]>>;
|
||||
handleSubmit: () => Promise<void>;
|
||||
handleClose: () => void;
|
||||
}
|
||||
|
||||
export function useAccountSettingsDrawer({
|
||||
onClose,
|
||||
account,
|
||||
setActiveAccount,
|
||||
}: UseAccountSettingsDrawerProps): UseAccountSettingsDrawer {
|
||||
const [form] = Form.useForm();
|
||||
const { mutate: updateAccount, isLoading } = useUpdateAccount();
|
||||
const accountConfig = useMemo(
|
||||
() => ('project_ids' in account.config ? account.config : null),
|
||||
[account.config],
|
||||
);
|
||||
const [projectIds, setProjectIds] = useState<string[]>(
|
||||
accountConfig?.project_ids || [],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!accountConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
form.setFieldsValue({
|
||||
projectIds: accountConfig.project_ids,
|
||||
});
|
||||
setProjectIds(accountConfig.project_ids);
|
||||
}, [accountConfig, form]);
|
||||
|
||||
const handleSubmit = useCallback(async (): Promise<void> => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
|
||||
if (!accountConfig) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateAccount(
|
||||
{
|
||||
pathParams: {
|
||||
cloudProvider: INTEGRATION_TYPES.GCP,
|
||||
id: account?.id || '',
|
||||
},
|
||||
data: {
|
||||
config: {
|
||||
gcp: {
|
||||
// Deployment region & project ID are immutable in the UI, but the
|
||||
// Updatable GCP DTO requires all three fields to be sent.
|
||||
deploymentRegion: accountConfig.deployment_region,
|
||||
deploymentProjectId: accountConfig.deployment_project_id,
|
||||
projectIds: values.projectIds || [],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
onSuccess: () => {
|
||||
const nextConfig = {
|
||||
deployment_region: accountConfig.deployment_region,
|
||||
deployment_project_id: accountConfig.deployment_project_id,
|
||||
project_ids: values.projectIds || [],
|
||||
};
|
||||
|
||||
setActiveAccount({
|
||||
...account,
|
||||
config: nextConfig,
|
||||
});
|
||||
onClose();
|
||||
|
||||
toast.success('Account settings updated successfully', {
|
||||
position: 'bottom-right',
|
||||
});
|
||||
|
||||
void logEvent('GCP Integration: Account settings updated', {
|
||||
cloudAccountId: account.cloud_account_id,
|
||||
deploymentRegion: nextConfig.deployment_region,
|
||||
projectIds: nextConfig.project_ids,
|
||||
});
|
||||
},
|
||||
onError: (error) => {
|
||||
toast.error('Failed to update account settings', {
|
||||
description: error?.message,
|
||||
position: 'bottom-right',
|
||||
});
|
||||
},
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Form submission failed:', error);
|
||||
}
|
||||
}, [form, updateAccount, account, accountConfig, setActiveAccount, onClose]);
|
||||
|
||||
const isSaveDisabled = useMemo(() => {
|
||||
if (!accountConfig) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isEqual(
|
||||
[...(projectIds || [])].sort(),
|
||||
[...accountConfig.project_ids].sort(),
|
||||
);
|
||||
}, [accountConfig, projectIds]);
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
onClose();
|
||||
}, [onClose]);
|
||||
|
||||
return {
|
||||
form,
|
||||
isLoading,
|
||||
projectIds,
|
||||
isSaveDisabled,
|
||||
setProjectIds,
|
||||
handleSubmit,
|
||||
handleClose,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user