Add auto-upgrade-in-apps (#23001)

We need to auto upgrade application, lets add this column in application
entity, and add an admin button to autoupgrade all applications to
latest app registrration version manually

<img width="1131" height="372" alt="image"
src="https://github.com/user-attachments/assets/4e755abc-38ad-4895-a2e8-d55ee1948ac2"
/>

<img width="906" height="533" alt="image"
src="https://github.com/user-attachments/assets/ce002057-0341-4581-bf9a-66ac2bd84a9b"
/>
This commit is contained in:
martmull
2026-07-20 16:12:44 +02:00
committed by GitHub
parent 5bf3472eb9
commit baa84bb2e0
36 changed files with 561 additions and 72 deletions
@@ -453,6 +453,7 @@ export type Mutation = {
updateDatabaseConfigVariable: Scalars['Boolean']['output'];
updateServerAdminAccess: ServerAdmin;
updateWorkspaceFeatureFlag: Scalars['Boolean']['output'];
upgradeRegistrationApplications: Scalars['Boolean']['output'];
};
@@ -579,6 +580,11 @@ export type MutationUpdateWorkspaceFeatureFlagArgs = {
workspaceId: Scalars['UUID']['input'];
};
export type MutationUpgradeRegistrationApplicationsArgs = {
applicationRegistrationId: Scalars['String']['input'];
};
export type PaginatedApplicationRegistrations = {
__typename?: 'PaginatedApplicationRegistrations';
hasMore: Scalars['Boolean']['output'];
@@ -1094,6 +1100,13 @@ export type UpdateAdminApplicationRegistrationVariableMutationVariables = Exact<
export type UpdateAdminApplicationRegistrationVariableMutation = { __typename?: 'Mutation', updateAdminApplicationRegistrationVariable: { __typename?: 'ApplicationRegistrationVariableDTO', id: string, key: string, description: string, isSecret: boolean, isRequired: boolean, isFilled: boolean, createdAt: string, updatedAt: string } };
export type UpgradeRegistrationApplicationsMutationVariables = Exact<{
applicationRegistrationId: Scalars['String']['input'];
}>;
export type UpgradeRegistrationApplicationsMutation = { __typename?: 'Mutation', upgradeRegistrationApplications: boolean };
export type FindAdminApplicationRegistrationInstalledWorkspacesQueryVariables = Exact<{
input: FindApplicationRegistrationInstalledWorkspacesInput;
}>;
@@ -1363,6 +1376,7 @@ export const BackfillApplicationInstallationDocument = {"kind":"Document","defin
export const SyncMarketplaceCatalogDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SyncMarketplaceCatalog"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"syncMarketplaceCatalog"}}]}}]} as unknown as DocumentNode<SyncMarketplaceCatalogMutation, SyncMarketplaceCatalogMutationVariables>;
export const UpdateAdminApplicationRegistrationDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateAdminApplicationRegistration"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateAdminApplicationRegistration"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"ApplicationRegistrationFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApplicationRegistrationFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApplicationRegistration"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"universalIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"logoUrl"}},{"kind":"Field","name":{"kind":"Name","value":"galleryImagesUrls"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthClientId"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthRedirectUris"}},{"kind":"Field","name":{"kind":"Name","value":"oAuthScopes"}},{"kind":"Field","name":{"kind":"Name","value":"sourceType"}},{"kind":"Field","name":{"kind":"Name","value":"sourcePackage"}},{"kind":"Field","name":{"kind":"Name","value":"latestAvailableVersion"}},{"kind":"Field","name":{"kind":"Name","value":"isListed"}},{"kind":"Field","name":{"kind":"Name","value":"isVetted"}},{"kind":"Field","name":{"kind":"Name","value":"isPreInstalled"}},{"kind":"Field","name":{"kind":"Name","value":"isConfigured"}},{"kind":"Field","name":{"kind":"Name","value":"ownerWorkspaceId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode<UpdateAdminApplicationRegistrationMutation, UpdateAdminApplicationRegistrationMutationVariables>;
export const UpdateAdminApplicationRegistrationVariableDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpdateAdminApplicationRegistrationVariable"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateApplicationRegistrationVariableInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"updateAdminApplicationRegistrationVariable"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<UpdateAdminApplicationRegistrationVariableMutation, UpdateAdminApplicationRegistrationVariableMutationVariables>;
export const UpgradeRegistrationApplicationsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"UpgradeRegistrationApplications"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"upgradeRegistrationApplications"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}}]}]}}]} as unknown as DocumentNode<UpgradeRegistrationApplicationsMutation, UpgradeRegistrationApplicationsMutationVariables>;
export const FindAdminApplicationRegistrationInstalledWorkspacesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAdminApplicationRegistrationInstalledWorkspaces"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"FindApplicationRegistrationInstalledWorkspacesInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAdminApplicationRegistrationInstalledWorkspaces"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"totalCount"}},{"kind":"Field","name":{"kind":"Name","value":"hasMore"}},{"kind":"Field","name":{"kind":"Name","value":"workspaces"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"displayName"}},{"kind":"Field","name":{"kind":"Name","value":"logo"}},{"kind":"Field","name":{"kind":"Name","value":"version"}}]}}]}}]}}]} as unknown as DocumentNode<FindAdminApplicationRegistrationInstalledWorkspacesQuery, FindAdminApplicationRegistrationInstalledWorkspacesQueryVariables>;
export const FindAdminApplicationRegistrationStatsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAdminApplicationRegistrationStats"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAdminApplicationRegistrationStats"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activeInstalls"}},{"kind":"Field","name":{"kind":"Name","value":"mostInstalledVersion"}},{"kind":"Field","name":{"kind":"Name","value":"versionDistribution"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"version"}},{"kind":"Field","name":{"kind":"Name","value":"count"}}]}}]}}]}}]} as unknown as DocumentNode<FindAdminApplicationRegistrationStatsQuery, FindAdminApplicationRegistrationStatsQueryVariables>;
export const FindAdminApplicationRegistrationVariablesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindAdminApplicationRegistrationVariables"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findAdminApplicationRegistrationVariables"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"applicationRegistrationId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"applicationRegistrationId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"value"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"isSecret"}},{"kind":"Field","name":{"kind":"Name","value":"isRequired"}},{"kind":"Field","name":{"kind":"Name","value":"isFilled"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"options"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]}}]} as unknown as DocumentNode<FindAdminApplicationRegistrationVariablesQuery, FindAdminApplicationRegistrationVariablesQueryVariables>;
File diff suppressed because one or more lines are too long
@@ -22,6 +22,7 @@ export const APPLICATION_FRAGMENT = gql`
logoUrl
}
canBeUninstalled
autoUpgrade
defaultRoleId
settingsCustomTabFrontComponentId
availablePackages
@@ -8,6 +8,7 @@ export const CUSTOM_WORKSPACE_APPLICATION_MOCK = {
commandMenuItems: [],
availablePackages: {},
canBeUninstalled: false,
autoUpgrade: false,
description: 'workpace custom application',
name: 'custom',
objects: [],
@@ -0,0 +1,11 @@
import { gql } from '@apollo/client';
export const UPGRADE_REGISTRATION_APPLICATIONS = gql`
mutation UpgradeRegistrationApplications(
$applicationRegistrationId: String!
) {
upgradeRegistrationApplications(
applicationRegistrationId: $applicationRegistrationId
)
}
`;
@@ -0,0 +1,10 @@
import gql from 'graphql-tag';
export const UPDATE_APPLICATION = gql`
mutation UpdateApplication($id: UUID!, $input: UpdateApplicationInput!) {
updateApplication(id: $id, input: $input) {
id
autoUpgrade
}
}
`;
@@ -30,6 +30,7 @@ describe('useComputeObjectAndFieldsContentForApplication', () => {
name: 'Test App',
logo: null,
canBeUninstalled: true,
autoUpgrade: false,
availablePackages: {},
applicationVariables: [],
agents: [],
@@ -60,6 +61,7 @@ describe('useComputeObjectAndFieldsContentForApplication', () => {
name: 'Test App',
logo: null,
canBeUninstalled: true,
autoUpgrade: false,
availablePackages: {},
applicationVariables: [],
agents: [],
@@ -88,6 +90,7 @@ describe('useComputeObjectAndFieldsContentForApplication', () => {
name: 'Test App',
logo: null,
canBeUninstalled: true,
autoUpgrade: false,
availablePackages: {},
applicationVariables: [],
agents: [],
@@ -117,6 +120,7 @@ describe('useComputeObjectAndFieldsContentForApplication', () => {
name: 'Test App',
logo: null,
canBeUninstalled: true,
autoUpgrade: false,
availablePackages: {},
applicationVariables: [],
agents: [],
@@ -274,6 +278,7 @@ describe('useComputeObjectAndFieldsContentForApplication', () => {
name: 'Test App',
logo: null,
canBeUninstalled: true,
autoUpgrade: false,
availablePackages: {},
applicationVariables: [],
agents: [],
@@ -150,7 +150,7 @@ export const SettingsAdminApplicationRegistrationGeneralToggles = ({
<StyledButtonWrapper id={BACKFILL_BUTTON_ID}>
<Button
Icon={IconReload}
title={t`Install latest version on all workspaces`}
title={t`Install on all workspaces`}
variant="secondary"
onClick={() => openModal(BACKFILL_INSTALLATION_MODAL_ID)}
disabled={isBackfilling || !registration.isPreInstalled}
@@ -169,10 +169,10 @@ export const SettingsAdminApplicationRegistrationGeneralToggles = ({
</StyledBackfillContainer>
<ConfirmationModal
modalInstanceId={BACKFILL_INSTALLATION_MODAL_ID}
title={t`Backfill installation`}
subtitle={t`This will install the latest version of "${registration.name}" on all existing active and suspended workspaces, upgrading any workspace that already has an older version. It runs as a background job and may take a while. Continue?`}
title={t`Install on all workspaces`}
subtitle={t`This will install the latest version of "${registration.name}" on all existing active and suspended workspaces, including the ones that don't have it yet. It runs as a background job and may take a while. Continue?`}
onConfirmClick={handleBackfill}
confirmButtonText={t`Backfill`}
confirmButtonText={t`Install`}
confirmButtonAccent="blue"
loading={isBackfilling}
/>
@@ -235,7 +235,10 @@ export const SettingsApplicationDetails = () => {
applicationHasHttpTriggeredFunctions(application);
const canShowFunctionDomain = hasHttpTriggeredFunctions;
const hasNothingToConfigure =
!hasVariables && !hasConnectionProviders && !canShowFunctionDomain;
!hasVariables &&
!hasConnectionProviders &&
!canShowFunctionDomain &&
!isUpgradableApplicationSourceType(sourceType);
return {
id: 'settings',
@@ -1,9 +1,27 @@
import { useApolloAdminClient } from '@/settings/admin-panel/apollo/hooks/useApolloAdminClient';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { ConfirmationModal } from '@/ui/layout/modal/components/ConfirmationModal';
import { useModal } from '@/ui/layout/modal/hooks/useModal';
import { useMutation } from '@apollo/client/react';
import { useLingui } from '@lingui/react/macro';
import { useState } from 'react';
import { IconRefresh } from 'twenty-ui/icon';
import { Button } from 'twenty-ui/input';
import { Section } from 'twenty-ui/layout';
import { H2Title } from 'twenty-ui/typography';
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { UpgradeRegistrationApplicationsDocument } from '~/generated-admin/graphql';
import { type ApplicationRegistration } from '~/generated-metadata/graphql';
import { SettingsApplicationRegistrationInstalledWorkspaces } from '~/pages/settings/applications/components/SettingsApplicationRegistrationInstalledWorkspaces';
import { SettingsApplicationRegistrationInstallStats } from '~/pages/settings/applications/components/SettingsApplicationRegistrationInstallStats';
import { H2Title } from 'twenty-ui/typography';
import { useLingui } from '@lingui/react/macro';
import { Section } from 'twenty-ui/layout';
const StyledUpgradeContainer = styled.div`
margin-top: ${themeCssVariables.spacing[6]};
`;
const UPGRADE_INSTALLATIONS_MODAL_ID =
'upgrade-registration-applications-modal';
export const SettingsApplicationRegistrationGeneralStats = ({
registration,
@@ -11,6 +29,35 @@ export const SettingsApplicationRegistrationGeneralStats = ({
registration: ApplicationRegistration;
}) => {
const { t } = useLingui();
const apolloAdminClient = useApolloAdminClient();
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const { openModal, closeModal } = useModal();
const [isUpgrading, setIsUpgrading] = useState(false);
const [upgradeApplications] = useMutation(
UpgradeRegistrationApplicationsDocument,
{ client: apolloAdminClient },
);
const handleUpgrade = async () => {
setIsUpgrading(true);
try {
await upgradeApplications({
variables: { applicationRegistrationId: registration.id },
});
enqueueSuccessSnackBar({
message: t`Upgrade started. Existing installations will be upgraded to the latest version in the background.`,
});
} catch {
enqueueErrorSnackBar({
message: t`Failed to start upgrade`,
});
} finally {
setIsUpgrading(false);
closeModal(UPGRADE_INSTALLATIONS_MODAL_ID);
}
};
return (
<Section>
@@ -24,6 +71,24 @@ export const SettingsApplicationRegistrationGeneralStats = ({
<SettingsApplicationRegistrationInstalledWorkspaces
registration={registration}
/>
<StyledUpgradeContainer>
<Button
Icon={IconRefresh}
title={t`Upgrade existing installations`}
variant="secondary"
onClick={() => openModal(UPGRADE_INSTALLATIONS_MODAL_ID)}
disabled={isUpgrading}
/>
</StyledUpgradeContainer>
<ConfirmationModal
modalInstanceId={UPGRADE_INSTALLATIONS_MODAL_ID}
title={t`Upgrade existing installations`}
subtitle={t`This will upgrade "${registration.name}" to its latest available version on every workspace that already has it installed. Workspaces without the app are not affected. It runs as a background job and may take a while. Continue?`}
onConfirmClick={handleUpgrade}
confirmButtonText={t`Upgrade`}
confirmButtonAccent="blue"
loading={isUpgrading}
/>
</Section>
);
};
@@ -37,6 +37,7 @@ const buildApplication = (variableValue: string): Application => ({
applicationRegistrationId: null,
applicationRegistration: null,
canBeUninstalled: true,
autoUpgrade: false,
defaultRoleId: null,
settingsCustomTabFrontComponentId: null,
availablePackages: {},
@@ -3,7 +3,9 @@ import { useUpdateOneApplicationVariable } from '~/pages/settings/applications/h
import { SettingsApplicationConnectionsSection } from '~/pages/settings/applications/tabs/SettingsApplicationConnectionsSection';
import { SettingsApplicationDetailEnvironmentVariablesTable } from '~/pages/settings/applications/tabs/SettingsApplicationDetailEnvironmentVariablesTable';
import { SettingsApplicationFunctionDomainSection } from '~/pages/settings/applications/tabs/SettingsApplicationFunctionDomainSection';
import { SettingsApplicationGeneralSection } from '~/pages/settings/applications/tabs/SettingsApplicationGeneralSection';
import { applicationHasHttpTriggeredFunctions } from '~/pages/settings/applications/utils/applicationHasHttpTriggeredFunctions';
import { isUpgradableApplicationSourceType } from '~/pages/settings/applications/utils/isUpgradableApplicationSourceType';
export const SettingsApplicationDetailSettingsTab = ({
application,
@@ -14,6 +16,8 @@ export const SettingsApplicationDetailSettingsTab = ({
| 'id'
| 'universalIdentifier'
| 'canBeUninstalled'
| 'autoUpgrade'
| 'applicationRegistration'
| 'logicFunctions'
>;
}) => {
@@ -26,8 +30,18 @@ export const SettingsApplicationDetailSettingsTab = ({
const hasHttpTriggeredFunctions =
applicationHasHttpTriggeredFunctions(application);
const isUpgradable = isUpgradableApplicationSourceType(
application?.applicationRegistration?.sourceType,
);
return (
<>
{isUpgradable && application?.id && (
<SettingsApplicationGeneralSection
applicationId={application.id}
autoUpgrade={application.autoUpgrade}
/>
)}
{hasHttpTriggeredFunctions && application?.id && (
<SettingsApplicationFunctionDomainSection
applicationId={application.id}
@@ -0,0 +1,51 @@
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useMutation } from '@apollo/client/react';
import { t } from '@lingui/core/macro';
import { IconRefresh } from 'twenty-ui/icon';
import { Section } from 'twenty-ui/layout';
import { Card } from 'twenty-ui/surfaces';
import { H2Title } from 'twenty-ui/typography';
import { UpdateApplicationDocument } from '~/generated-metadata/graphql';
export const SettingsApplicationGeneralSection = ({
applicationId,
autoUpgrade,
}: {
applicationId: string;
autoUpgrade: boolean;
}) => {
const { enqueueErrorSnackBar } = useSnackBar();
const [updateApplication] = useMutation(UpdateApplicationDocument);
const handleAutoUpgradeChange = async (checked: boolean) => {
try {
await updateApplication({
variables: {
id: applicationId,
input: { autoUpgrade: checked },
},
});
} catch {
enqueueErrorSnackBar({
message: t`Failed to update auto-upgrade setting.`,
});
}
};
return (
<Section>
<H2Title title={t`General`} />
<Card rounded fullWidth>
<SettingsOptionCardContentToggle
Icon={IconRefresh}
title={t`Auto-upgrade`}
description={t`Automatically upgrade this application when a new version is published`}
checked={autoUpgrade}
onChange={handleAutoUpgradeChange}
/>
</Card>
</Section>
);
};