mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-28 22:50:32 +01:00
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
* feat(settings): add SigNoz MCP Server setup page Add a new Settings page at /settings/mcp-server that guides Cloud users through connecting AI assistants (Cursor, VS Code, Claude Desktop, Claude Code, Codex) to SigNoz via the Model Context Protocol, and provides a deep-link into Service Accounts for creating the API key the OAuth flow needs. * feat(settings): point MCP Server onboarding tile to in-app settings page The onboarding-config-with-links entry for SigNoz MCP Server previously linked out to the docs page. Now that we ship an in-product setup page at /settings/mcp-server, route Cloud users there directly via the existing internalRedirect pattern. Self-hosted users still see the in-page fallback card with a docs link. * fix(settings): fire MCP Server page-viewed event reliably on mount Previously gated the PAGE_VIEWED analytics event on isGlobalConfigFetched to avoid a double-fire when the async ingestion_url resolved. Side effect: if /global/config was slow or errored out, the event never fired. Fire once on mount instead with hostname-derived region metadata, which is synchronous and reliable. * feat(mcp-page): ui refactor and redesign * feat(mcp-page): global config and page access changes * feat(mcp-page): refactor and added fallback page * feat(mcp-page): added test cases * feat(mcp-page): formatting lint * feat(mcp-page): code refactor * feat(mcp-page): cleanup and migrated global config api to open api spec * feat(mcp-page): removed translation json and add endpoint url to copy * feat(mcp-page): added mcp server to menu always for cloud and enterprise --------- Co-authored-by: SagarRajput-7 <sagar@signoz.io> Co-authored-by: SagarRajput-7 <162284829+SagarRajput-7@users.noreply.github.com>
155 lines
3.7 KiB
TypeScript
155 lines
3.7 KiB
TypeScript
import { Controller, useForm } from 'react-hook-form';
|
|
import { useQueryClient } from 'react-query';
|
|
import { X } from '@signozhq/icons';
|
|
import {
|
|
Button,
|
|
DialogFooter,
|
|
DialogWrapper,
|
|
Input,
|
|
toast,
|
|
} from '@signozhq/ui';
|
|
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
|
|
import {
|
|
invalidateListServiceAccounts,
|
|
useCreateServiceAccount,
|
|
} from 'api/generated/services/serviceaccount';
|
|
import type { RenderErrorResponseDTO } from 'api/generated/services/sigNoz.schemas';
|
|
import { AxiosError } from 'axios';
|
|
import { SA_QUERY_PARAMS } from 'container/ServiceAccountsSettings/constants';
|
|
import { parseAsBoolean, useQueryState } from 'nuqs';
|
|
import { useErrorModal } from 'providers/ErrorModalProvider';
|
|
import APIError from 'types/api/error';
|
|
|
|
import './CreateServiceAccountModal.styles.scss';
|
|
|
|
interface FormValues {
|
|
name: string;
|
|
}
|
|
|
|
function CreateServiceAccountModal(): JSX.Element {
|
|
const queryClient = useQueryClient();
|
|
const [isOpen, setIsOpen] = useQueryState(
|
|
SA_QUERY_PARAMS.CREATE_SA,
|
|
parseAsBoolean.withDefault(false),
|
|
);
|
|
const [, setSelectedAccountId] = useQueryState(SA_QUERY_PARAMS.ACCOUNT);
|
|
|
|
const { showErrorModal, isErrorModalVisible } = useErrorModal();
|
|
|
|
const {
|
|
control,
|
|
handleSubmit,
|
|
reset,
|
|
formState: { isValid, errors },
|
|
} = useForm<FormValues>({
|
|
mode: 'onChange',
|
|
defaultValues: {
|
|
name: '',
|
|
},
|
|
});
|
|
|
|
const { mutate: createServiceAccount, isLoading: isSubmitting } =
|
|
useCreateServiceAccount({
|
|
mutation: {
|
|
onSuccess: async (response) => {
|
|
toast.success('Service account created successfully');
|
|
reset();
|
|
await setIsOpen(null);
|
|
await invalidateListServiceAccounts(queryClient);
|
|
await setSelectedAccountId(response.data.id);
|
|
},
|
|
onError: (err) => {
|
|
const errMessage = convertToApiError(
|
|
err as AxiosError<RenderErrorResponseDTO, unknown> | null,
|
|
);
|
|
showErrorModal(errMessage as APIError);
|
|
},
|
|
},
|
|
});
|
|
|
|
function handleClose(): void {
|
|
reset();
|
|
void setIsOpen(null);
|
|
}
|
|
|
|
function handleCreate(values: FormValues): void {
|
|
createServiceAccount({
|
|
data: {
|
|
name: values.name.trim(),
|
|
},
|
|
});
|
|
}
|
|
|
|
return (
|
|
<DialogWrapper
|
|
title="New Service Account"
|
|
open={isOpen}
|
|
onOpenChange={(open): void => {
|
|
if (!open) {
|
|
handleClose();
|
|
}
|
|
}}
|
|
showCloseButton
|
|
width="narrow"
|
|
className="create-sa-modal"
|
|
disableOutsideClick={isErrorModalVisible}
|
|
>
|
|
<div className="create-sa-modal__content">
|
|
<form
|
|
id="create-sa-form"
|
|
className="create-sa-form"
|
|
onSubmit={handleSubmit(handleCreate)}
|
|
>
|
|
<div className="create-sa-form__item">
|
|
<label htmlFor="sa-name">Name</label>
|
|
<Controller
|
|
name="name"
|
|
control={control}
|
|
rules={{ required: 'Name is required' }}
|
|
render={({ field }): JSX.Element => (
|
|
<Input
|
|
id="sa-name"
|
|
placeholder="Enter a name"
|
|
className="create-sa-form__input"
|
|
value={field.value}
|
|
onChange={field.onChange}
|
|
onBlur={field.onBlur}
|
|
/>
|
|
)}
|
|
/>
|
|
{errors.name && (
|
|
<p className="create-sa-form__error">{errors.name.message}</p>
|
|
)}
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<DialogFooter className="create-sa-modal__footer">
|
|
<Button
|
|
type="button"
|
|
variant="solid"
|
|
color="secondary"
|
|
onClick={handleClose}
|
|
>
|
|
<X size={12} />
|
|
Cancel
|
|
</Button>
|
|
|
|
<Button
|
|
type="submit"
|
|
// @ts-expect-error -- form prop not in @signozhq/ui Button type - TODO: Fix this - @SagarRajput
|
|
form="create-sa-form"
|
|
variant="solid"
|
|
color="primary"
|
|
loading={isSubmitting}
|
|
disabled={!isValid}
|
|
>
|
|
Create Service Account
|
|
</Button>
|
|
</DialogFooter>
|
|
</DialogWrapper>
|
|
);
|
|
}
|
|
|
|
export default CreateServiceAccountModal;
|