Files
twenty/packages/twenty-front/src/pages/settings/admin-panel/SettingsAdminApplicationRegistrationGeneralToggles.tsx
T
martmull baa84bb2e0 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"
/>
2026-07-20 16:12:44 +02:00

182 lines
6.0 KiB
TypeScript

import { Section } from 'twenty-ui/layout';
import { AppTooltip, Card, TooltipDelay } from 'twenty-ui/surfaces';
import { SettingsOptionCardContentToggle } from '@/settings/components/SettingsOptions/SettingsOptionCardContentToggle';
import {
IconArrowBarToDown,
IconPinned,
IconReload,
IconShield,
} from 'twenty-ui/icon';
import { Button } from 'twenty-ui/input';
import { H2Title } from 'twenty-ui/typography';
import { type ApplicationRegistration } from '~/generated-metadata/graphql';
import {
BackfillApplicationInstallationDocument,
UpdateAdminApplicationRegistrationDocument,
} from '~/generated-admin/graphql';
import { styled } from '@linaria/react';
import { themeCssVariables } from 'twenty-ui/theme-constants';
import { useMutation } from '@apollo/client/react';
import { useLingui } from '@lingui/react/macro';
import { useState } from 'react';
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';
const StyledToggleContainer = styled.div`
display: flex;
flex-direction: column;
gap: ${themeCssVariables.spacing[3]};
`;
const StyledBackfillContainer = styled.div`
align-items: center;
display: flex;
gap: ${themeCssVariables.spacing[2]};
margin-top: ${themeCssVariables.spacing[6]};
`;
const StyledButtonWrapper = styled.span`
display: inline-flex;
`;
const BACKFILL_INSTALLATION_MODAL_ID =
'backfill-application-installation-modal';
const BACKFILL_BUTTON_ID = 'backfill-application-installation-button';
export const SettingsAdminApplicationRegistrationGeneralToggles = ({
registration,
}: {
registration: ApplicationRegistration;
}) => {
const { t } = useLingui();
const apolloAdminClient = useApolloAdminClient();
const { enqueueSuccessSnackBar, enqueueErrorSnackBar } = useSnackBar();
const { openModal, closeModal } = useModal();
const [isBackfilling, setIsBackfilling] = useState(false);
const [updateRegistration] = useMutation(
UpdateAdminApplicationRegistrationDocument,
{ client: apolloAdminClient },
);
const [backfillInstallation] = useMutation(
BackfillApplicationInstallationDocument,
{ client: apolloAdminClient },
);
const handleBackfill = async () => {
setIsBackfilling(true);
try {
await backfillInstallation({
variables: { applicationRegistrationId: registration.id },
});
enqueueSuccessSnackBar({
message: t`Backfill started. This app will be installed on all existing workspaces in the background.`,
});
} catch {
enqueueErrorSnackBar({
message: t`Failed to start backfill`,
});
} finally {
setIsBackfilling(false);
closeModal(BACKFILL_INSTALLATION_MODAL_ID);
}
};
return (
<Section>
<H2Title title={t`Installation`} />
<StyledToggleContainer>
<Card rounded fullWidth>
<SettingsOptionCardContentToggle
Icon={IconArrowBarToDown}
title={t`Allow installation`}
description={t`Display this app in the NPM packages list`}
checked={registration.isListed}
onChange={(checked) =>
updateRegistration({
variables: {
input: {
id: registration.id,
update: { isListed: checked },
},
},
})
}
/>
</Card>
<Card rounded fullWidth>
<SettingsOptionCardContentToggle
Icon={IconShield}
title={t`Vetted`}
description={t`Mark this app as reviewed and approved`}
checked={registration.isVetted}
onChange={(checked) =>
updateRegistration({
variables: {
input: {
id: registration.id,
update: { isVetted: checked },
},
},
})
}
/>
</Card>
<Card rounded fullWidth>
<SettingsOptionCardContentToggle
Icon={IconPinned}
title={t`Pre-install on new workspaces`}
description={t`Automatically install this app on every newly created workspace`}
checked={registration.isPreInstalled}
onChange={(checked) =>
updateRegistration({
variables: {
input: {
id: registration.id,
update: { isPreInstalled: checked },
},
},
})
}
/>
</Card>
</StyledToggleContainer>
<StyledBackfillContainer>
<StyledButtonWrapper id={BACKFILL_BUTTON_ID}>
<Button
Icon={IconReload}
title={t`Install on all workspaces`}
variant="secondary"
onClick={() => openModal(BACKFILL_INSTALLATION_MODAL_ID)}
disabled={isBackfilling || !registration.isPreInstalled}
/>
</StyledButtonWrapper>
{!registration.isPreInstalled && (
<AppTooltip
anchorSelect={`#${BACKFILL_BUTTON_ID}`}
content={t`Pre-install must be enabled.`}
noArrow
place="bottom"
positionStrategy="fixed"
delay={TooltipDelay.shortDelay}
/>
)}
</StyledBackfillContainer>
<ConfirmationModal
modalInstanceId={BACKFILL_INSTALLATION_MODAL_ID}
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`Install`}
confirmButtonAccent="blue"
loading={isBackfilling}
/>
</Section>
);
};