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:
parent
d2452b91f2
commit
edae8801d8
@ -82,7 +82,7 @@ export const Limit: FC<{
|
|||||||
|
|
||||||
const footerContent = isOss() ? (
|
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>.
|
<a href='https://slack.unleash.run'>Unleash community Slack</a>.
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
|
@ -13,6 +13,8 @@ import { formatUnknownError } from 'utils/formatUnknownError';
|
|||||||
import { useUiFlag } from 'hooks/useUiFlag';
|
import { useUiFlag } from 'hooks/useUiFlag';
|
||||||
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
|
||||||
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
|
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')(() => ({
|
const StyledButtonContainer = styled('div')(() => ({
|
||||||
marginTop: 'auto',
|
marginTop: 'auto',
|
||||||
@ -31,7 +33,12 @@ export const CreateReleasePlanTemplate = () => {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { createReleasePlanTemplate } = useReleasePlanTemplatesApi();
|
const { createReleasePlanTemplate } = useReleasePlanTemplatesApi();
|
||||||
const { trackEvent } = usePlausibleTracker();
|
const { trackEvent } = usePlausibleTracker();
|
||||||
|
const { templates } = useReleasePlanTemplates();
|
||||||
|
const releaseTemplateLimit = uiConfig.resourceLimits.releaseTemplates;
|
||||||
|
const canCreateMore = templates.length < releaseTemplateLimit;
|
||||||
|
|
||||||
usePageTitle('Create release template');
|
usePageTitle('Create release template');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
name,
|
name,
|
||||||
setName,
|
setName,
|
||||||
@ -102,11 +109,19 @@ export const CreateReleasePlanTemplate = () => {
|
|||||||
formTitle='Create release template'
|
formTitle='Create release template'
|
||||||
formatApiCode={formatApiCode}
|
formatApiCode={formatApiCode}
|
||||||
handleSubmit={handleSubmit}
|
handleSubmit={handleSubmit}
|
||||||
|
Limit={
|
||||||
|
<Limit
|
||||||
|
name='release templates'
|
||||||
|
limit={releaseTemplateLimit}
|
||||||
|
currentValue={templates.length}
|
||||||
|
/>
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<StyledButtonContainer>
|
<StyledButtonContainer>
|
||||||
<CreateButton
|
<CreateButton
|
||||||
name='template'
|
name='template'
|
||||||
permission={RELEASE_PLAN_TEMPLATE_CREATE}
|
permission={RELEASE_PLAN_TEMPLATE_CREATE}
|
||||||
|
disabled={!canCreateMore}
|
||||||
>
|
>
|
||||||
Save template
|
Save template
|
||||||
</CreateButton>
|
</CreateButton>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Input from 'component/common/Input/Input';
|
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 type { IReleasePlanMilestonePayload } from 'interfaces/releasePlans';
|
||||||
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
|
||||||
import { TemplateFormDescription } from './TemplateFormDescription.tsx';
|
import { TemplateFormDescription } from './TemplateFormDescription.tsx';
|
||||||
@ -33,6 +33,14 @@ const StyledForm = styled('form')(({ theme }) => ({
|
|||||||
paddingTop: theme.spacing(5),
|
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 {
|
interface ITemplateFormProps {
|
||||||
name: string;
|
name: string;
|
||||||
setName: React.Dispatch<React.SetStateAction<string>>;
|
setName: React.Dispatch<React.SetStateAction<string>>;
|
||||||
@ -49,6 +57,7 @@ interface ITemplateFormProps {
|
|||||||
formatApiCode: () => string;
|
formatApiCode: () => string;
|
||||||
handleSubmit: (e: React.FormEvent) => void;
|
handleSubmit: (e: React.FormEvent) => void;
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
Limit?: React.ReactNode;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,6 +74,7 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
|
|||||||
archived,
|
archived,
|
||||||
formatApiCode,
|
formatApiCode,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
|
Limit,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
@ -135,6 +145,8 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
|
|||||||
milestoneChanged={milestoneChanged}
|
milestoneChanged={milestoneChanged}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<StyledLimitContainer>{Limit}</StyledLimitContainer>
|
||||||
|
|
||||||
{children}
|
{children}
|
||||||
</StyledForm>
|
</StyledForm>
|
||||||
</FormTemplate>
|
</FormTemplate>
|
||||||
|
@ -45,5 +45,6 @@ export const defaultValue: IUiConfig = {
|
|||||||
segments: 300,
|
segments: 300,
|
||||||
apiTokens: 2000,
|
apiTokens: 2000,
|
||||||
featureFlags: 5000,
|
featureFlags: 5000,
|
||||||
|
releaseTemplates: 5,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -42,6 +42,8 @@ export interface ResourceLimitsSchema {
|
|||||||
* @minimum 1
|
* @minimum 1
|
||||||
*/
|
*/
|
||||||
projects: number;
|
projects: number;
|
||||||
|
/** The maximum number of release templates allowed. */
|
||||||
|
releaseTemplates: number;
|
||||||
/** The maximum number of segments allowed. */
|
/** The maximum number of segments allowed. */
|
||||||
segments: number;
|
segments: number;
|
||||||
/** The maximum number of values per segment allowed. */
|
/** The maximum number of values per segment allowed. */
|
||||||
|
@ -121,6 +121,7 @@ exports[`should create default config 1`] = `
|
|||||||
"featureEnvironmentStrategies": 30,
|
"featureEnvironmentStrategies": 30,
|
||||||
"featureFlags": 5000,
|
"featureFlags": 5000,
|
||||||
"projects": 500,
|
"projects": 500,
|
||||||
|
"releaseTemplates": 5,
|
||||||
"segmentValues": 1000,
|
"segmentValues": 1000,
|
||||||
"segments": 300,
|
"segments": 300,
|
||||||
"signalEndpoints": 5,
|
"signalEndpoints": 5,
|
||||||
|
@ -758,6 +758,13 @@ export function createConfig(options: IUnleashOptions): IUnleashConfig {
|
|||||||
options?.resourceLimits?.featureFlags ?? 5000,
|
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;
|
const openAIAPIKey = process.env.OPENAI_API_KEY;
|
||||||
|
@ -21,6 +21,7 @@ export const resourceLimitsSchema = {
|
|||||||
'segments',
|
'segments',
|
||||||
'featureFlags',
|
'featureFlags',
|
||||||
'constraints',
|
'constraints',
|
||||||
|
'releaseTemplates',
|
||||||
],
|
],
|
||||||
additionalProperties: false,
|
additionalProperties: false,
|
||||||
properties: {
|
properties: {
|
||||||
@ -118,6 +119,11 @@ export const resourceLimitsSchema = {
|
|||||||
description:
|
description:
|
||||||
'The maximum number of feature flags you can have at the same time. Archived flags do not count towards this limit.',
|
'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: {},
|
components: {},
|
||||||
} as const;
|
} as const;
|
||||||
|
@ -26,6 +26,7 @@ test('uiConfigSchema', () => {
|
|||||||
segments: 0,
|
segments: 0,
|
||||||
featureFlags: 1,
|
featureFlags: 1,
|
||||||
constraints: 0,
|
constraints: 0,
|
||||||
|
releaseTemplates: 0,
|
||||||
},
|
},
|
||||||
versionInfo: {
|
versionInfo: {
|
||||||
current: {},
|
current: {},
|
||||||
|
@ -135,6 +135,7 @@ export interface ResourceLimits {
|
|||||||
actionSetFilterValues: number;
|
actionSetFilterValues: number;
|
||||||
signalEndpoints: number;
|
signalEndpoints: number;
|
||||||
signalTokensPerEndpoint: number;
|
signalTokensPerEndpoint: number;
|
||||||
|
releaseTemplates: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUnleashOptions {
|
export interface IUnleashOptions {
|
||||||
|
Loading…
Reference in New Issue
Block a user