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:
+17
-6
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+19
@@ -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>
|
||||
);
|
||||
};
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
import { type ApolloClient } from '@apollo/client';
|
||||
import { createContext } from 'react';
|
||||
|
||||
export const ApolloAdminClientContext = createContext<ApolloClient | null>(
|
||||
null,
|
||||
);
|
||||
+19
@@ -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;
|
||||
};
|
||||
+6
-2
@@ -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 ?? [];
|
||||
|
||||
+1
-1
@@ -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']
|
||||
|
||||
+4
@@ -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,
|
||||
});
|
||||
|
||||
+6
-2
@@ -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 = [
|
||||
|
||||
+1
-1
@@ -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`
|
||||
|
||||
+1
-4
@@ -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};
|
||||
|
||||
+1
-1
@@ -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 = {
|
||||
|
||||
+4
-1
@@ -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
-1
@@ -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';
|
||||
|
||||
+6
-1
@@ -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 (
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
+1
-1
@@ -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};
|
||||
|
||||
+4
-1
@@ -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',
|
||||
},
|
||||
);
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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,
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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;
|
||||
|
||||
+1
-1
@@ -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`
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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,
|
||||
|
||||
+1
-1
@@ -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';
|
||||
|
||||
|
||||
+4
-1
@@ -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,
|
||||
|
||||
+1
-1
@@ -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
-1
@@ -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` },
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ import {
|
||||
AdminPanelHealthServiceStatus,
|
||||
HealthIndicatorId,
|
||||
type AdminPanelHealthServiceData,
|
||||
} from '~/generated-metadata/graphql';
|
||||
} from '~/generated-admin/graphql';
|
||||
|
||||
type SettingsAdminIndicatorHealthContextType = {
|
||||
indicatorHealth: AdminPanelHealthServiceData;
|
||||
|
||||
+6
-2
@@ -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);
|
||||
|
||||
+6
-2
@@ -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);
|
||||
|
||||
+8
-2
@@ -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);
|
||||
|
||||
|
||||
+4
-1
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user