feat: move admin panel to dedicated /admin-panel GraphQL endpoint (#19852)

## Summary

Splits admin-panel resolvers off the shared `/metadata` GraphQL endpoint
onto a dedicated `/admin-panel` endpoint. The backend plumbing mirrors
the existing `metadata` / `core` pattern (new scope, decorator, module,
factory), and admin types now live in their own
`generated-admin/graphql.ts` on the frontend — dropping 877 lines of
admin noise from `generated-metadata`.

## Why

- **Smaller attack surface on `/metadata`** — every authenticated user
hits that endpoint; admin ops don't belong there.
- **Independent complexity limits and monitoring** per endpoint.
- **Cleaner module boundaries** — admin is a cross-cutting concern that
doesn't match the "shared-schema configuration" meaning of `/metadata`.
- **Deploy / blast-radius isolation** — a broken admin query can't
affect `/metadata`.

Runtime behavior, auth, and authorization are unchanged — this is a
relocation, not a re-permissioning. All existing guards
(`WorkspaceAuthGuard`, `UserAuthGuard`,
`SettingsPermissionGuard(SECURITY)` at class level; `AdminPanelGuard` /
`ServerLevelImpersonateGuard` at method level) remain on
`AdminPanelResolver`.

## What changed

### Backend
- `@AdminResolver()` decorator with scope `'admin'`, naming parallels
`CoreResolver` / `MetadataResolver`.
- `AdminPanelGraphQLApiModule` + `adminPanelModuleFactory` registered at
`/admin-panel`, same Yoga hook set as the metadata factory (Sentry
tracing, error handler, introspection-disabling in prod, complexity
validation).
- Middleware chain on `/admin-panel` is identical to `/metadata`.
- `@nestjs/graphql` patch extended: `resolverSchemaScope?: 'core' |
'metadata' | 'admin'`.
- `AdminPanelResolver` class decorator swapped from
`@MetadataResolver()` to `@AdminResolver()` — no other changes.

### Frontend
- `codegen-admin.cjs` → `src/generated-admin/graphql.ts` (982 lines).
- `codegen-metadata.cjs` excludes admin paths; metadata file shrinks by
877 lines.
- `ApolloAdminProvider` / `useApolloAdminClient` follow the existing
`ApolloCoreProvider` / `useApolloCoreClient` pattern, wired inside
`AppRouterProviders` alongside the core provider.
- 37 admin consumer files migrated: imports switched to
`~/generated-admin/graphql` and `client: useApolloAdminClient()` is
passed to `useQuery` / `useMutation`.
- Three files intentionally kept on `generated-metadata` because they
consume non-admin Documents: `useHandleImpersonate.ts`,
`SettingsAdminApplicationRegistrationDangerZone.tsx`,
`SettingsAdminApplicationRegistrationGeneralToggles.tsx`.

### CI
- `ci-server.yaml` runs all three `graphql:generate` configurations and
diff-checks all three generated dirs.

## Authorization (unchanged, but audited while reviewing)

Every one of the 38 methods on `AdminPanelResolver` has a method-level
guard:
- `AdminPanelGuard` (32 methods) — requires `canAccessFullAdminPanel ===
true`
- `ServerLevelImpersonateGuard` (6 methods: user/workspace lookup + chat
thread views) — requires `canImpersonate === true`

On top of the class-level guards above. No resolver method is accessible
without these flags + `SECURITY` permission in the workspace.

## Test plan

- [ ] Dev server boots; `/graphql`, `/metadata`, `/admin-panel` all
mapped as separate GraphQL routes (confirmed locally during
development).
- [ ] `nx typecheck twenty-server` passes.
- [ ] `nx typecheck twenty-front` passes.
- [ ] `nx lint:diff-with-main twenty-server` and `twenty-front` both
clean.
- [ ] Manual smoke test: log in with a user who has
`canAccessFullAdminPanel=true`, open the admin panel at
`/settings/admin-panel`, verify each tab loads (General, Health, Config
variables, AI, Apps, Workspace details, User details, chat threads).
- [ ] Manual smoke test: log in with a user who has
`canImpersonate=false` and `canAccessFullAdminPanel=false`, hit
`/admin-panel` directly with a raw GraphQL request, confirm permission
error on every operation.
- [ ] Production deploy note: reverse proxy / ingress must route the new
`/admin-panel` path to the Nest server. If the proxy has an explicit
allowlist, infra change required before cutover.

## Follow-ups (out of scope here)

- Consider cutting over the three
`SettingsAdminApplicationRegistration*` components to admin-scope
versions of the app-registration operations so the admin page is fully
on the admin endpoint.
- The `renderGraphiQL` double-assignment in
`admin-panel.module-factory.ts` is copied from
`metadata.module-factory.ts` — worth cleaning up in both.
This commit is contained in:
Félix Malfait
2026-04-19 20:55:10 +02:00
committed by GitHub
parent 90661cc821
commit 75848ff8ea
70 changed files with 1857 additions and 3844 deletions
@@ -13,6 +13,7 @@ import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { billingState } from '@/client-config/states/billingState';
import { useClientConfig } from '@/client-config/hooks/useClientConfig';
import { SettingsAiModelsTable } from '@/settings/ai/components/SettingsAiModelsTable';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { SettingsAdminAiProviderListCard } from '@/settings/admin-panel/ai/components/SettingsAdminAiProviderListCard';
import { AI_PROVIDER_SOURCE } from '@/settings/admin-panel/ai/constants/AiProviderSource';
import { SET_ADMIN_AI_MODEL_RECOMMENDED } from '@/settings/admin-panel/ai/graphql/mutations/setAdminAiModelRecommended';
@@ -42,7 +43,7 @@ import { GenericDropdownContentWidth } from '@/ui/layout/dropdown/constants/Gene
import {
AiModelRole,
type AdminAiModelConfig,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
const USAGE_TABLE_GRID_TEMPLATE_COLUMNS = '1fr 120px';
@@ -53,6 +54,7 @@ type UsageBreakdownItem = {
};
export const SettingsAdminAI = () => {
const apolloAdminClient = useApolloAdminClient();
const { enqueueErrorSnackBar } = useSnackBar();
const { refetch: refetchClientConfig } = useClientConfig();
const { formatUsageValue } = useUsageValueFormatter();
@@ -75,18 +77,27 @@ export const SettingsAdminAI = () => {
defaultFastModelId?: string | null;
models: AdminAiModelConfig[];
};
}>(GET_ADMIN_AI_MODELS);
}>(GET_ADMIN_AI_MODELS, { client: apolloAdminClient });
const [setModelRecommended] = useMutation(SET_ADMIN_AI_MODEL_RECOMMENDED);
const [setModelsRecommended] = useMutation(SET_ADMIN_AI_MODELS_RECOMMENDED);
const [setDefaultModel] = useMutation(SET_ADMIN_DEFAULT_AI_MODEL);
const [setModelRecommended] = useMutation(SET_ADMIN_AI_MODEL_RECOMMENDED, {
client: apolloAdminClient,
});
const [setModelsRecommended] = useMutation(SET_ADMIN_AI_MODELS_RECOMMENDED, {
client: apolloAdminClient,
});
const [setDefaultModel] = useMutation(SET_ADMIN_DEFAULT_AI_MODEL, {
client: apolloAdminClient,
});
const { data: providersData, loading: isLoadingProviders } =
useQuery<GetAiProvidersResult>(GET_AI_PROVIDERS);
useQuery<GetAiProvidersResult>(GET_AI_PROVIDERS, {
client: apolloAdminClient,
});
const { data: usageData, previousData: previousUsageData } = useQuery<{
getAdminAiUsageByWorkspace: UsageBreakdownItem[];
}>(GET_ADMIN_AI_USAGE_BY_WORKSPACE, {
client: apolloAdminClient,
variables: {
periodStart: usageDates.periodStart,
periodEnd: usageDates.periodEnd,
@@ -8,7 +8,7 @@ import {
type IconComponent,
} from 'twenty-ui/display';
import { ModelFamily } from '~/generated-metadata/graphql';
import { ModelFamily } from '~/generated-admin/graphql';
export type ModelIconConfigKey = ModelFamily | 'FALLBACK';
@@ -0,0 +1,19 @@
import { useApolloFactory } from '@/apollo/hooks/useApolloFactory';
import { ApolloAdminClientContext } from '@/settings/admin-panel/apollo/contexts/ApolloAdminClientContext';
import { REACT_APP_SERVER_BASE_URL } from '~/config';
export const ApolloAdminProvider = ({
children,
}: {
children: React.ReactNode;
}) => {
const apolloAdminClient = useApolloFactory({
uri: `${REACT_APP_SERVER_BASE_URL}/admin-panel`,
});
return (
<ApolloAdminClientContext.Provider value={apolloAdminClient}>
{children}
</ApolloAdminClientContext.Provider>
);
};
@@ -0,0 +1,6 @@
import { type ApolloClient } from '@apollo/client';
import { createContext } from 'react';
export const ApolloAdminClientContext = createContext<ApolloClient | null>(
null,
);
@@ -0,0 +1,19 @@
import { useApolloClient } from '@apollo/client/react';
import { useContext } from 'react';
import { ApolloAdminClientContext } from '@/settings/admin-panel/apollo/contexts/ApolloAdminClientContext';
export const useApolloAdminClient = () => {
const apolloAdminClient = useContext(ApolloAdminClientContext);
const apolloClient = useApolloClient();
if (process.env.NODE_ENV === 'test') {
return apolloClient;
}
if (!apolloAdminClient) {
throw new Error('ApolloAdminClient not found');
}
return apolloAdminClient;
};
@@ -1,3 +1,4 @@
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { Table } from '@/ui/layout/table/components/Table';
import { TableBody } from '@/ui/layout/table/components/TableBody';
import { TableCell } from '@/ui/layout/table/components/TableCell';
@@ -21,7 +22,7 @@ import {
type ApplicationRegistrationFragmentFragment,
ApplicationRegistrationSourceType,
FindAllApplicationRegistrationsDocument,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
const StyledTableContainer = styled.div`
border-bottom: 1px solid ${themeCssVariables.border.color.light};
@@ -32,10 +33,13 @@ const TABLE_GRID = '1fr 100px 100px 40px';
const TABLE_GRID_MOBILE = '3fr 3fr 1fr 40px';
export const SettingsAdminApps = () => {
const apolloAdminClient = useApolloAdminClient();
const [searchQuery, setSearchQuery] = useState('');
const { theme } = useContext(ThemeContext);
const { data } = useQuery(FindAllApplicationRegistrationsDocument);
const { data } = useQuery(FindAllApplicationRegistrationsDocument, {
client: apolloAdminClient,
});
const registrations: ApplicationRegistrationFragmentFragment[] =
data?.findAllApplicationRegistrations ?? [];
@@ -9,7 +9,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
AgentMessageRole,
type GetAdminChatThreadMessagesQuery,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
type ChatMessage = NonNullable<
GetAdminChatThreadMessagesQuery['getAdminChatThreadMessages']
@@ -1,4 +1,5 @@
import { canManageFeatureFlagsState } from '@/client-config/states/canManageFeatureFlagsState';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { SettingsAdminVersionContainer } from '@/settings/admin-panel/components/SettingsAdminVersionContainer';
import { ADMIN_PANEL_RECENT_USERS } from '@/settings/admin-panel/graphql/queries/adminPanelRecentUsers';
import { ADMIN_PANEL_TOP_WORKSPACES } from '@/settings/admin-panel/graphql/queries/adminPanelTopWorkspaces';
@@ -29,6 +30,7 @@ const StyledEmptyState = styled.div`
`;
export const SettingsAdminGeneral = () => {
const apolloAdminClient = useApolloAdminClient();
const [userSearchTerm, setUserSearchTerm] = useState('');
const [debouncedUserSearchTerm] = useDebounce(userSearchTerm, 300);
@@ -51,6 +53,7 @@ export const SettingsAdminGeneral = () => {
workspaceId?: string | null;
}[];
}>(ADMIN_PANEL_RECENT_USERS, {
client: apolloAdminClient,
variables: { searchTerm: debouncedUserSearchTerm },
skip: !canImpersonate,
});
@@ -63,6 +66,7 @@ export const SettingsAdminGeneral = () => {
subdomain: string;
}[];
}>(ADMIN_PANEL_TOP_WORKSPACES, {
client: apolloAdminClient,
variables: { searchTerm: debouncedWorkspaceSearchTerm },
skip: !canImpersonate,
});
@@ -1,12 +1,16 @@
import { SettingsTableCard } from '@/settings/components/SettingsTableCard';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { SettingsAdminVersionDisplay } from '@/settings/admin-panel/components/SettingsAdminVersionDisplay';
import { t } from '@lingui/core/macro';
import { IconCircleDot, IconStatusChange } from 'twenty-ui/display';
import { useQuery } from '@apollo/client/react';
import { GetVersionInfoDocument } from '~/generated-metadata/graphql';
import { GetVersionInfoDocument } from '~/generated-admin/graphql';
export const SettingsAdminVersionContainer = () => {
const { data, loading } = useQuery(GetVersionInfoDocument);
const apolloAdminClient = useApolloAdminClient();
const { data, loading } = useQuery(GetVersionInfoDocument, {
client: apolloAdminClient,
});
const { currentVersion, latestVersion } = data?.versionInfo ?? {};
const versionItems = [
@@ -12,7 +12,7 @@ import { CustomError } from 'twenty-shared/utils';
import { CodeEditor } from 'twenty-ui/input';
import { MenuItemMultiSelect } from 'twenty-ui/navigation';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { ConfigVariableType } from '~/generated-metadata/graphql';
import { ConfigVariableType } from '~/generated-admin/graphql';
import { type ConfigVariableOptions } from '@/settings/admin-panel/config-variables/types/ConfigVariableOptions';
const StyledJsonEditorContainer = styled.div`
@@ -4,10 +4,7 @@ import { useLingui } from '@lingui/react/macro';
import { isConfigVariablesInDbEnabledState } from '@/client-config/states/isConfigVariablesInDbEnabledState';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
ConfigSource,
type ConfigVariable,
} from '~/generated-metadata/graphql';
import { ConfigSource, type ConfigVariable } from '~/generated-admin/graphql';
const StyledHelpText = styled.div<{ color?: string }>`
color: ${themeCssVariables.font.color.tertiary};
@@ -5,7 +5,7 @@ import { TextInput } from '@/ui/input/components/TextInput';
import { styled } from '@linaria/react';
import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue';
import { type ConfigVariableValue } from 'twenty-shared/types';
import { type ConfigVariable } from '~/generated-metadata/graphql';
import { type ConfigVariable } from '~/generated-admin/graphql';
import { ConfigVariableDatabaseInput } from './ConfigVariableDatabaseInput';
type ConfigVariableValueInputProps = {
@@ -1,4 +1,5 @@
import { SettingsAdminTabSkeletonLoader } from '@/settings/admin-panel/components/SettingsAdminTabSkeletonLoader';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { ConfigVariableFilterContainer } from '@/settings/admin-panel/config-variables/components/ConfigVariableFilterContainer';
import { ConfigVariableFilterDropdown } from '@/settings/admin-panel/config-variables/components/ConfigVariableFilterDropdown';
import { SettingsAdminConfigVariablesTable } from '@/settings/admin-panel/config-variables/components/SettingsAdminConfigVariablesTable';
@@ -15,7 +16,7 @@ import { useQuery } from '@apollo/client/react';
import {
ConfigSource,
GetConfigVariablesGroupedDocument,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
import { normalizeSearchText } from '~/utils/normalizeSearchText';
import { ConfigVariableSearchInput } from './ConfigVariableSearchInput';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
@@ -31,9 +32,11 @@ const StyledTableContainer = styled.div`
`;
export const SettingsAdminConfigVariables = () => {
const apolloAdminClient = useApolloAdminClient();
const { data: configVariables, loading: configVariablesLoading } = useQuery(
GetConfigVariablesGroupedDocument,
{
client: apolloAdminClient,
fetchPolicy: 'network-only',
},
);
@@ -1,4 +1,4 @@
import { type ConfigVariable } from '~/generated-metadata/graphql';
import { type ConfigVariable } from '~/generated-admin/graphql';
import { ConfigVariableTable } from '@/settings/config-variables/components/ConfigVariableTable';
import { getSettingsPath } from 'twenty-shared/utils';
import { SettingsPath } from 'twenty-shared/types';
@@ -1,4 +1,5 @@
import { useClientConfig } from '@/client-config/hooks/useClientConfig';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { GET_DATABASE_CONFIG_VARIABLE } from '@/settings/admin-panel/config-variables/graphql/queries/getDatabaseConfigVariable';
import { type ConfigVariableValue } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
@@ -7,19 +8,23 @@ import {
CreateDatabaseConfigVariableDocument,
DeleteDatabaseConfigVariableDocument,
UpdateDatabaseConfigVariableDocument,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
export const useConfigVariableActions = (variableName: string) => {
const apolloAdminClient = useApolloAdminClient();
const { refetch: refetchClientConfig } = useClientConfig();
const [updateDatabaseConfigVariable] = useMutation(
UpdateDatabaseConfigVariableDocument,
{ client: apolloAdminClient },
);
const [createDatabaseConfigVariable] = useMutation(
CreateDatabaseConfigVariableDocument,
{ client: apolloAdminClient },
);
const [deleteDatabaseConfigVariable] = useMutation(
DeleteDatabaseConfigVariableDocument,
{ client: apolloAdminClient },
);
const handleUpdateVariable = async (
@@ -3,7 +3,7 @@ import { useContext } from 'react';
import { CustomError } from 'twenty-shared/utils';
import { ThemeContext } from 'twenty-ui/theme-constants';
import { ConfigSource } from '~/generated-metadata/graphql';
import { ConfigSource } from '~/generated-admin/graphql';
export const useSourceContent = (source: ConfigSource) => {
const { theme } = useContext(ThemeContext);
@@ -4,7 +4,7 @@ import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { useContext } from 'react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AdminPanelHealthServiceStatus } from '~/generated-metadata/graphql';
import { AdminPanelHealthServiceStatus } from '~/generated-admin/graphql';
const StyledErrorMessage = styled.div`
color: ${themeCssVariables.color.red};
@@ -1,3 +1,4 @@
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { SettingsAdminTabSkeletonLoader } from '@/settings/admin-panel/components/SettingsAdminTabSkeletonLoader';
import { SettingsAdminHealthStatusListCard } from '@/settings/admin-panel/health-status/components/SettingsAdminHealthStatusListCard';
import { SettingsAdminMaintenanceModeFetchEffect } from '@/settings/admin-panel/health-status/maintenance-mode/components/SettingsAdminMaintenanceModeFetchEffect';
@@ -6,12 +7,14 @@ import { t } from '@lingui/core/macro';
import { H2Title } from 'twenty-ui/display';
import { Section } from 'twenty-ui/layout';
import { useQuery } from '@apollo/client/react';
import { GetSystemHealthStatusDocument } from '~/generated-metadata/graphql';
import { GetSystemHealthStatusDocument } from '~/generated-admin/graphql';
export const SettingsAdminHealthStatus = () => {
const apolloAdminClient = useApolloAdminClient();
const { data, loading: loadingHealthStatus } = useQuery(
GetSystemHealthStatusDocument,
{
client: apolloAdminClient,
fetchPolicy: 'network-only',
},
);
@@ -14,7 +14,7 @@ import { ThemeContext } from 'twenty-ui/theme-constants';
import {
HealthIndicatorId,
type SystemHealthService,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
import { SettingsAdminHealthStatusRightContainer } from './SettingsAdminHealthStatusRightContainer';
@@ -1,6 +1,6 @@
import { t } from '@lingui/core/macro';
import { Status } from 'twenty-ui/display';
import { AdminPanelHealthServiceStatus } from '~/generated-metadata/graphql';
import { AdminPanelHealthServiceStatus } from '~/generated-admin/graphql';
export const SettingsAdminHealthStatusRightContainer = ({
status,
@@ -2,7 +2,7 @@ import { SettingsAdminConnectedAccountHealthStatus } from '@/settings/admin-pane
import { SettingsAdminJsonDataIndicatorHealthStatus } from '@/settings/admin-panel/health-status/components/SettingsAdminJsonDataIndicatorHealthStatus';
import { SettingsAdminWorkerHealthStatus } from '@/settings/admin-panel/health-status/components/SettingsAdminWorkerHealthStatus';
import { useParams } from 'react-router-dom';
import { HealthIndicatorId } from '~/generated-metadata/graphql';
import { HealthIndicatorId } from '~/generated-admin/graphql';
export const SettingsAdminIndicatorHealthStatusContent = () => {
const { indicatorId } = useParams();
@@ -3,7 +3,7 @@ import { t } from '@lingui/core/macro';
import { JsonTree } from 'twenty-ui/json-visualizer';
import { AnimatedExpandableContainer } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { type QueueJob } from '~/generated-metadata/graphql';
import { type QueueJob } from '~/generated-admin/graphql';
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
type SettingsAdminJobDetailsExpandableProps = {
@@ -1,7 +1,7 @@
import { styled } from '@linaria/react';
import { Tag, type TagColor } from 'twenty-ui/components';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { JobState } from '~/generated-metadata/graphql';
import { JobState } from '~/generated-admin/graphql';
type SettingsAdminJobStateBadgeProps = {
state: JobState;
@@ -5,7 +5,7 @@ import { useContext } from 'react';
import { JsonTree } from 'twenty-ui/json-visualizer';
import { Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { AdminPanelHealthServiceStatus } from '~/generated-metadata/graphql';
import { AdminPanelHealthServiceStatus } from '~/generated-admin/graphql';
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
const StyledDetailsContainer = styled.div`
@@ -6,7 +6,7 @@ import { t } from '@lingui/core/macro';
import { IconDotsVertical, IconRefresh, IconTrash } from 'twenty-ui/display';
import { LightIconButton } from 'twenty-ui/input';
import { MenuItem } from 'twenty-ui/navigation';
import { JobState } from '~/generated-metadata/graphql';
import { JobState } from '~/generated-admin/graphql';
type SettingsAdminQueueJobRowDropdownMenuProps = {
jobId: string;
@@ -4,6 +4,7 @@ import { SettingsAdminJobDetailsExpandable } from '@/settings/admin-panel/health
import { SettingsAdminJobStateBadge } from '@/settings/admin-panel/health-status/components/SettingsAdminJobStateBadge';
import { SettingsAdminQueueJobRowDropdownMenu } from '@/settings/admin-panel/health-status/components/SettingsAdminQueueJobRowDropdownMenu';
import { SettingsAdminRetryJobsConfirmationModal } from '@/settings/admin-panel/health-status/components/SettingsAdminRetryJobsConfirmationModal';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { useDeleteJobs } from '@/settings/admin-panel/health-status/hooks/useDeleteJobs';
import { useRetryJobs } from '@/settings/admin-panel/health-status/hooks/useRetryJobs';
import { Select } from '@/ui/input/components/Select';
@@ -24,7 +25,7 @@ import {
JobState,
type QueueJob,
GetQueueJobsDocument,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
import { beautifyPastDateRelativeToNow } from '~/utils/date-utils';
type SettingsAdminQueueJobsTableProps = {
@@ -74,6 +75,7 @@ export const SettingsAdminQueueJobsTable = ({
queueName,
onRetentionConfigLoaded,
}: SettingsAdminQueueJobsTableProps) => {
const apolloAdminClient = useApolloAdminClient();
const [page, setPage] = useState(0);
const [stateFilter, setStateFilter] = useState<JobState>(JobState.COMPLETED);
const [expandedJobId, setExpandedJobId] = useState<string | null>(null);
@@ -93,6 +95,7 @@ export const SettingsAdminQueueJobsTable = ({
const offset = page * LIMIT;
const { data, loading, refetch } = useQuery(GetQueueJobsDocument, {
client: apolloAdminClient,
variables: {
queueName,
state: stateFilter,
@@ -2,7 +2,7 @@ import { SettingsAdminWorkerQueueMetricsSection } from '@/settings/admin-panel/h
import { styled } from '@linaria/react';
import { t } from '@lingui/core/macro';
import { useContext } from 'react';
import { AdminPanelHealthServiceStatus } from '~/generated-metadata/graphql';
import { AdminPanelHealthServiceStatus } from '~/generated-admin/graphql';
import { SettingsAdminIndicatorHealthContext } from '@/settings/admin-panel/health-status/contexts/SettingsAdminIndicatorHealthContext';
import { themeCssVariables } from 'twenty-ui/theme-constants';
@@ -1,5 +1,6 @@
import { isDefined } from 'twenty-shared/utils';
import { SettingsTableCard } from '@/settings/components/SettingsTableCard';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { SettingsAdminWorkerMetricsTooltip } from '@/settings/admin-panel/health-status/components/SettingsAdminWorkerMetricsTooltip';
import { useSnackBarOnQueryError } from '@/apollo/hooks/useSnackBarOnQueryError';
import { styled } from '@linaria/react';
@@ -11,7 +12,7 @@ import { useQuery } from '@apollo/client/react';
import {
QueueMetricsTimeRange,
GetQueueMetricsDocument,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
const StyledGraphContainer = styled.div`
background-color: ${themeCssVariables.background.secondary};
@@ -48,9 +49,11 @@ export const SettingsAdminWorkerMetricsGraph = ({
queueName,
timeRange,
}: SettingsAdminWorkerMetricsGraphProps) => {
const apolloAdminClient = useApolloAdminClient();
const { theme } = useContext(ThemeContext);
const { loading, data, error } = useQuery(GetQueueMetricsDocument, {
client: apolloAdminClient,
variables: {
queueName,
timeRange,
@@ -13,7 +13,7 @@ import { themeCssVariables } from 'twenty-ui/theme-constants';
import {
type AdminPanelWorkerQueueHealth,
QueueMetricsTimeRange,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
const SettingsAdminWorkerMetricsGraph = lazy(() =>
import('./SettingsAdminWorkerMetricsGraph').then((module) => ({
@@ -1,5 +1,5 @@
import { msg } from '@lingui/core/macro';
import { QueueMetricsTimeRange } from '~/generated-metadata/graphql';
import { QueueMetricsTimeRange } from '~/generated-admin/graphql';
export const WORKER_QUEUE_METRICS_SELECT_OPTIONS = [
{ value: QueueMetricsTimeRange.SevenDays, label: msg`This week` },
@@ -3,7 +3,7 @@ import {
AdminPanelHealthServiceStatus,
HealthIndicatorId,
type AdminPanelHealthServiceData,
} from '~/generated-metadata/graphql';
} from '~/generated-admin/graphql';
type SettingsAdminIndicatorHealthContextType = {
indicatorHealth: AdminPanelHealthServiceData;
@@ -1,16 +1,20 @@
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
import { plural, t } from '@lingui/core/macro';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useMutation } from '@apollo/client/react';
import { DeleteJobsDocument } from '~/generated-metadata/graphql';
import { DeleteJobsDocument } from '~/generated-admin/graphql';
import { getErrorMessageFromApolloError } from '~/utils/get-error-message-from-apollo-error.util';
export const useDeleteJobs = (queueName: string, onSuccess?: () => void) => {
const apolloAdminClient = useApolloAdminClient();
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const [isDeleting, setIsDeleting] = useState(false);
const [deleteJobsMutation] = useMutation(DeleteJobsDocument);
const [deleteJobsMutation] = useMutation(DeleteJobsDocument, {
client: apolloAdminClient,
});
const deleteJobs = async (jobIds: string[]) => {
setIsDeleting(true);
@@ -1,16 +1,20 @@
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { CombinedGraphQLErrors } from '@apollo/client/errors';
import { plural, t } from '@lingui/core/macro';
import { useState } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useMutation } from '@apollo/client/react';
import { RetryJobsDocument } from '~/generated-metadata/graphql';
import { RetryJobsDocument } from '~/generated-admin/graphql';
import { getErrorMessageFromApolloError } from '~/utils/get-error-message-from-apollo-error.util';
export const useRetryJobs = (queueName: string, onSuccess?: () => void) => {
const apolloAdminClient = useApolloAdminClient();
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const [isRetrying, setIsRetrying] = useState(false);
const [retryJobsMutation] = useMutation(RetryJobsDocument);
const [retryJobsMutation] = useMutation(RetryJobsDocument, {
client: apolloAdminClient,
});
const retryJobs = async (jobIds: string[]) => {
setIsRetrying(true);
@@ -9,6 +9,7 @@ import { Card, CardContent, Section } from 'twenty-ui/layout';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { maintenanceModeState } from '@/client-config/states/maintenanceModeState';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { CLEAR_MAINTENANCE_MODE } from '@/settings/admin-panel/health-status/maintenance-mode/graphql/mutations/clearMaintenanceMode';
import { SET_MAINTENANCE_MODE } from '@/settings/admin-panel/health-status/maintenance-mode/graphql/mutations/setMaintenanceMode';
import { adminPanelMaintenanceModeState } from '@/settings/admin-panel/health-status/maintenance-mode/states/adminPanelMaintenanceModeState';
@@ -34,6 +35,7 @@ const StyledStatusRow = styled.div`
`;
export const SettingsAdminMaintenanceMode = () => {
const apolloAdminClient = useApolloAdminClient();
const [adminPanelMaintenanceMode, setAdminPanelMaintenanceMode] =
useAtomState(adminPanelMaintenanceModeState);
@@ -43,8 +45,12 @@ export const SettingsAdminMaintenanceMode = () => {
const { userTimezone } = useUserTimezone();
const { enqueueErrorSnackBar } = useSnackBar();
const [setMaintenanceModeMutation] = useMutation(SET_MAINTENANCE_MODE);
const [clearMaintenanceModeMutation] = useMutation(CLEAR_MAINTENANCE_MODE);
const [setMaintenanceModeMutation] = useMutation(SET_MAINTENANCE_MODE, {
client: apolloAdminClient,
});
const [clearMaintenanceModeMutation] = useMutation(CLEAR_MAINTENANCE_MODE, {
client: apolloAdminClient,
});
const isEnabled = isDefined(adminPanelMaintenanceMode);
@@ -2,13 +2,16 @@ import { useQuery } from '@apollo/client/react';
import { useEffect } from 'react';
import { isDefined } from 'twenty-shared/utils';
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { GET_MAINTENANCE_MODE } from '@/settings/admin-panel/health-status/maintenance-mode/graphql/queries/getMaintenanceMode';
import { adminPanelMaintenanceModeState } from '@/settings/admin-panel/health-status/maintenance-mode/states/adminPanelMaintenanceModeState';
import { useSetAtomState } from '@/ui/utilities/state/jotai/hooks/useSetAtomState';
import { type GetMaintenanceModeQuery } from '~/generated-metadata/graphql';
import { type GetMaintenanceModeQuery } from '~/generated-admin/graphql';
export const SettingsAdminMaintenanceModeFetchEffect = () => {
const apolloAdminClient = useApolloAdminClient();
const { data } = useQuery<GetMaintenanceModeQuery>(GET_MAINTENANCE_MODE, {
client: apolloAdminClient,
fetchPolicy: 'network-only',
});
@@ -1,7 +1,7 @@
import { currentWorkspaceState } from '@/auth/states/currentWorkspaceState';
import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState';
import { isDefined } from 'twenty-shared/utils';
import { type FeatureFlagKey } from '~/generated-metadata/graphql';
import { type FeatureFlagKey } from '~/generated-admin/graphql';
export const useFeatureFlagState = () => {
const [currentWorkspace, setCurrentWorkspace] = useAtomState(
@@ -1,4 +1,4 @@
import { type WorkspaceLookupAdminPanelQuery } from '~/generated-metadata/graphql';
import { type WorkspaceLookupAdminPanelQuery } from '~/generated-admin/graphql';
export type WorkspaceInfo =
WorkspaceLookupAdminPanelQuery['workspaceLookupAdminPanel']['workspaces'][number];