Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: release template sidebar #8871

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions frontend/src/assets/icons/milestone.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { scrollToTop } from 'component/common/util';
import useToast from 'hooks/useToast';
import { formatUnknownError } from 'utils/formatUnknownError';
import { useUiFlag } from 'hooks/useUiFlag';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

const StyledButtonContainer = styled('div')(() => ({
marginTop: 'auto',
Expand All @@ -23,6 +24,7 @@ const StyledCancelButton = styled(Button)(({ theme }) => ({
}));

export const CreateReleasePlanTemplate = () => {
const { uiConfig } = useUiConfig();
const releasePlansEnabled = useUiFlag('releasePlans');
const { setToastApiError, setToastData } = useToast();
const navigate = useNavigate();
Expand Down Expand Up @@ -50,12 +52,10 @@ export const CreateReleasePlanTemplate = () => {
clearErrors();
const isValid = validate();
if (isValid) {
const payload = getTemplatePayload();
try {
const template = await createReleasePlanTemplate({
...payload,
milestones,
});
const template = await createReleasePlanTemplate(
getTemplatePayload(),
);
scrollToTop();
setToastData({
type: 'success',
Expand All @@ -68,6 +68,13 @@ export const CreateReleasePlanTemplate = () => {
}
};

const formatApiCode = () => `curl --location --request POST '${
uiConfig.unleashUrl
}/api/admin/release-plan-templates' \\
--header 'Authorization: INSERT_API_KEY' \\
--header 'Content-Type: application/json' \\
--data-raw '${JSON.stringify(getTemplatePayload(), undefined, 2)}'`;

if (!releasePlansEnabled) {
return null;
}
Expand All @@ -83,7 +90,7 @@ export const CreateReleasePlanTemplate = () => {
errors={errors}
clearErrors={clearErrors}
formTitle='Create release plan template'
formDescription='Create a release plan template to make it easier for you and your team to release features.'
formatApiCode={formatApiCode}
handleSubmit={handleSubmit}
>
<StyledButtonContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useNavigate } from 'react-router-dom';
import { formatUnknownError } from 'utils/formatUnknownError';
import useToast from 'hooks/useToast';
import useReleasePlanTemplatesApi from 'hooks/api/actions/useReleasePlanTemplatesApi/useReleasePlanTemplatesApi';
import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';

const StyledButtonContainer = styled('div')(() => ({
marginTop: 'auto',
Expand All @@ -23,6 +24,7 @@ const StyledCancelButton = styled(Button)(({ theme }) => ({
}));

export const EditReleasePlanTemplate = () => {
const { uiConfig } = useUiConfig();
const releasePlansEnabled = useUiFlag('releasePlans');
const templateId = useRequiredPathParam('templateId');
const { template, loading, error, refetch } =
Expand Down Expand Up @@ -56,13 +58,11 @@ export const EditReleasePlanTemplate = () => {
clearErrors();
const isValid = validate();
if (isValid) {
const payload = getTemplatePayload();
try {
await updateReleasePlanTemplate({
...payload,
id: templateId,
milestones,
});
await updateReleasePlanTemplate(
templateId,
getTemplatePayload(),
);
await refetch();
setToastData({
type: 'success',
Expand All @@ -74,6 +74,13 @@ export const EditReleasePlanTemplate = () => {
}
};

const formatApiCode = () => `curl --location --request PUT '${
uiConfig.unleashUrl
}/api/admin/release-plan-templates/${templateId}' \\
--header 'Authorization: INSERT_API_KEY' \\
--header 'Content-Type: application/json' \\
--data-raw '${JSON.stringify(getTemplatePayload(), undefined, 2)}'`;

if (!releasePlansEnabled) {
return null;
}
Expand All @@ -89,7 +96,7 @@ export const EditReleasePlanTemplate = () => {
errors={errors}
clearErrors={clearErrors}
formTitle={`Edit template ${template.name}`}
formDescription='Edit a release plan template that makes it easier for you and your team to release features.'
formatApiCode={formatApiCode}
handleSubmit={handleSubmit}
loading={loading}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ import type {
IReleasePlanMilestoneStrategy,
} from 'interfaces/releasePlans';
import FormTemplate from 'component/common/FormTemplate/FormTemplate';
import ReleaseTemplateIcon from '@mui/icons-material/DashboardOutlined';
import { SidebarModal } from 'component/common/SidebarModal/SidebarModal';
import { useState } from 'react';
import { ReleasePlanTemplateAddStrategyForm } from './ReleasePlanTemplateAddStrategyForm';
import { TemplateFormDescription } from './TemplateFormDescription';

const StyledInputDescription = styled('p')(({ theme }) => ({
marginBottom: theme.spacing(1),
Expand Down Expand Up @@ -38,7 +38,7 @@ interface ITemplateFormProps {
errors: { [key: string]: string };
clearErrors: () => void;
formTitle: string;
formDescription: string;
formatApiCode: () => string;
handleSubmit: (e: React.FormEvent) => void;
loading?: boolean;
children?: React.ReactNode;
Expand All @@ -54,7 +54,7 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
errors,
clearErrors,
formTitle,
formDescription,
formatApiCode,
handleSubmit,
children,
}) => {
Expand Down Expand Up @@ -115,8 +115,8 @@ export const TemplateForm: React.FC<ITemplateFormProps> = ({
return (
<FormTemplate
title={formTitle}
description={formDescription}
documentationIcon={<ReleaseTemplateIcon />}
description={<TemplateFormDescription />}
formatApiCode={formatApiCode}
>
<StyledForm onSubmit={handleSubmit}>
<StyledInputDescription>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import ReleaseTemplateIcon from '@mui/icons-material/DashboardOutlined';
import { ReactComponent as MilestoneIcon } from 'assets/icons/milestone.svg';
import { styled } from '@mui/material';

const StyledDescription = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
fontSize: theme.fontSizes.smallBody,
}));

const StyledDescriptionHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
fontSize: theme.fontSizes.bodySize,
fontWeight: theme.fontWeight.bold,
}));

const StyledExampleUsage = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(1),
}));

const StyledMilestones = styled('div')(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing(2),
}));

const StyledLabel = styled('p')(({ theme }) => ({
fontWeight: theme.fontWeight.bold,
}));

const StyledMilestoneHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
gap: theme.spacing(1),
}));

export const TemplateFormDescription = () => {
return (
<StyledDescription>
<StyledDescriptionHeader>
<ReleaseTemplateIcon />
Release templates
</StyledDescriptionHeader>
<p>
Standardize your team's approach to rolling out new
functionality with release templates. These templates allow you
to predefine strategies, or groups of strategies, making it
easier to set up new flags and ensure alignment in how rollouts
are managed.
</p>
<p>
Customize templates to suit your needs by adding strategies to
specific milestones. Each milestone will execute sequentially,
streamlining your release process.
</p>
<StyledExampleUsage>
<StyledLabel>Example usage</StyledLabel>
<StyledMilestones>
<div>
<StyledMilestoneHeader>
<MilestoneIcon />
Milestone 1
</StyledMilestoneHeader>
<p>
Enable the feature for internal teams to test
functionality and resolve initial issues.
</p>
</div>
<div>
<StyledMilestoneHeader>
<MilestoneIcon />
Milestone 2
</StyledMilestoneHeader>
<p>
Expand the rollout to 20% of beta users to gather
feedback and monitor performance.
</p>
</div>
<div>
<StyledMilestoneHeader>
<MilestoneIcon />
Milestone 3
</StyledMilestoneHeader>
<p>
Release the feature to all users after confirming
stability and addressing earlier feedback.
</p>
</div>
</StyledMilestones>
</StyledExampleUsage>
</StyledDescription>
);
};
1 change: 1 addition & 0 deletions frontend/src/component/releases/hooks/useTemplateForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export const useTemplateForm = (
return {
name,
description,
milestones,
};
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import type { IReleasePlanTemplatePayload } from 'interfaces/releasePlans';
import type {
IReleasePlanTemplate,
IReleasePlanTemplatePayload,
} from 'interfaces/releasePlans';
import useAPI from '../useApi/useApi';

export const useReleasePlanTemplatesApi = () => {
Expand All @@ -23,7 +26,7 @@ export const useReleasePlanTemplatesApi = () => {

const createReleasePlanTemplate = async (
template: IReleasePlanTemplatePayload,
): Promise<IReleasePlanTemplatePayload> => {
): Promise<IReleasePlanTemplate> => {
const requestId = 'createReleasePlanTemplate';
const path = 'api/admin/release-plan-templates';
const req = createRequest(
Expand All @@ -40,10 +43,11 @@ export const useReleasePlanTemplatesApi = () => {
};

const updateReleasePlanTemplate = async (
templateId: string,
template: IReleasePlanTemplatePayload,
) => {
const requestId = 'updateReleasePlanTemplate';
const path = `api/admin/release-plan-templates/${template.id}`;
const path = `api/admin/release-plan-templates/${templateId}`;
const req = createRequest(
path,
{
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/interfaces/releasePlans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ export interface IReleasePlanMilestoneStrategy extends IFeatureStrategy {
}

export interface IReleasePlanTemplatePayload {
id?: string;
name: string;
description: string;
milestones?: IReleasePlanMilestonePayload[];
milestones: IReleasePlanMilestonePayload[];
}

export interface IReleasePlanMilestonePayload {
Expand Down
Loading