1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-09-19 17:52:45 +02:00

chore: release template resource limits (#10514)

https://linear.app/unleash/issue/2-3790/use-resource-limits-to-limit-the-amount-of-release-templates-you-can

Adds a new resource limit for release templates.

Needs a follow-up PR in Enterprise.
This commit is contained in:
Nuno Góis 2025-08-21 11:52:09 +01:00 committed by GitHub
parent d2452b91f2
commit edae8801d8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 48 additions and 2 deletions

View File

@ -82,7 +82,7 @@ export const Limit: FC<{
const footerContent = isOss() ? (
<>
Need help with resource limits? Try the the{' '}
Need help with resource limits? Try the{' '}
<a href='https://slack.unleash.run'>Unleash community Slack</a>.
</>
) : (

View File

@ -13,6 +13,8 @@ import { formatUnknownError } from 'utils/formatUnknownError';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { Limit } from 'component/common/Limit/Limit.tsx';
import { useReleasePlanTemplates } from 'hooks/api/getters/useReleasePlanTemplates/useReleasePlanTemplates.ts';
const StyledButtonContainer = styled('div')(() => ({
marginTop: 'auto',
@ -31,7 +33,12 @@ export const CreateReleasePlanTemplate = () => {
const navigate = useNavigate();
const { createReleasePlanTemplate } = useReleasePlanTemplatesApi();
const { trackEvent } = usePlausibleTracker();
const { templates } = useReleasePlanTemplates();
const releaseTemplateLimit = uiConfig.resourceLimits.releaseTemplates;
const canCreateMore = templates.length < releaseTemplateLimit;
usePageTitle('Create release template');
const {
name,
setName,
@ -102,11 +109,19 @@ export const CreateReleasePlanTemplate = () => {
formTitle='Create release template'
formatApiCode={formatApiCode}
handleSubmit={handleSubmit}
Limit={
<Limit
name='release templates'
limit={releaseTemplateLimit}
currentValue={templates.length}
/>
}
>
<StyledButtonContainer>
<CreateButton
name='template'
permission={RELEASE_PLAN_TEMPLATE_CREATE}
disabled={!canCreateMore}
>
Save template
</CreateButton>

View File

@ -1,5 +1,5 @@
import Input from 'component/common/Input/Input';
import { Alert, styled, useTheme } from '@mui/material';
import { Alert, Box, styled, useTheme } from '@mui/material';
import type { IReleasePlanMilestonePayload } from 'interfaces/releasePlans';
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
import { TemplateFormDescription } from './TemplateFormDescription.tsx';
@ -33,6 +33,14 @@ const StyledForm = styled('form')(({ theme }) => ({
paddingTop: theme.spacing(5),
}));
const StyledLimitContainer = styled(Box)(({ theme }) => ({
flex: 1,
display: 'flex',
alignItems: 'flex-end',
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
}));
interface ITemplateFormProps {
name: string;
setName: React.Dispatch<React.SetStateAction<string>>;
@ -49,6 +57,7 @@ interface ITemplateFormProps {
formatApiCode: () => string;
handleSubmit: (e: React.FormEvent) => void;
loading?: boolean;
Limit?: React.ReactNode;
children?: React.ReactNode;
}
@ -65,6 +74,7 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
archived,
formatApiCode,
handleSubmit,
Limit,
children,
}) => {
const theme = useTheme();
@ -135,6 +145,8 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
milestoneChanged={milestoneChanged}
/>
<StyledLimitContainer>{Limit}</StyledLimitContainer>
{children}
</StyledForm>
</FormTemplate>

View File

@ -45,5 +45,6 @@ export const defaultValue: IUiConfig = {
segments: 300,
apiTokens: 2000,
featureFlags: 5000,
releaseTemplates: 5,
},
};

View File

@ -42,6 +42,8 @@ export interface ResourceLimitsSchema {
* @minimum 1
*/
projects: number;
/** The maximum number of release templates allowed. */
releaseTemplates: number;
/** The maximum number of segments allowed. */
segments: number;
/** The maximum number of values per segment allowed. */

View File

@ -121,6 +121,7 @@ exports[`should create default config 1`] = `
"featureEnvironmentStrategies": 30,
"featureFlags": 5000,
"projects": 500,
"releaseTemplates": 5,
"segmentValues": 1000,
"segments": 300,
"signalEndpoints": 5,

View File

@ -758,6 +758,13 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
options?.resourceLimits?.featureFlags ?? 5000,
),
),
releaseTemplates: Math.max(
0,
parseEnvVarNumber(
process.env.UNLEASH_RELEASE_TEMPLATES_LIMIT,
options?.resourceLimits?.releaseTemplates ?? 5,
),
),
};
const openAIAPIKey = process.env.OPENAI_API_KEY;

View File

@ -21,6 +21,7 @@ export const resourceLimitsSchema = {
'segments',
'featureFlags',
'constraints',
'releaseTemplates',
],
additionalProperties: false,
properties: {
@ -118,6 +119,11 @@ export const resourceLimitsSchema = {
description:
'The maximum number of feature flags you can have at the same time. Archived flags do not count towards this limit.',
},
releaseTemplates: {
type: 'integer',
example: 5,
description: 'The maximum number of release templates allowed.',
},
},
components: {},
} as const;

View File

@ -26,6 +26,7 @@ test('uiConfigSchema', () => {
segments: 0,
featureFlags: 1,
constraints: 0,
releaseTemplates: 0,
},
versionInfo: {
current: {},

View File

@ -135,6 +135,7 @@ export interface ResourceLimits {
actionSetFilterValues: number;
signalEndpoints: number;
signalTokensPerEndpoint: number;
releaseTemplates: number;
}
export interface IUnleashOptions {