chore: reduce prominence of Scratch starter and emphasize Docker in UI (#16665)

This commit is contained in:
Hugo Dutka
2025-02-24 20:59:21 +01:00
committed by GitHub
parent 658825cad2
commit c8abf58e29
6 changed files with 20 additions and 88 deletions

View File

@ -10,7 +10,7 @@ import {
import { server } from "testHelpers/server"; import { server } from "testHelpers/server";
import CreateTemplateGalleryPage from "./CreateTemplateGalleryPage"; import CreateTemplateGalleryPage from "./CreateTemplateGalleryPage";
test("does not display the scratch template", async () => { test("displays the scratch template", async () => {
server.use( server.use(
http.get("api/v2/templates/examples", () => { http.get("api/v2/templates/examples", () => {
return HttpResponse.json([ return HttpResponse.json([
@ -49,5 +49,5 @@ test("does not display the scratch template", async () => {
await screen.findByText(MockTemplateExample.name); await screen.findByText(MockTemplateExample.name);
screen.getByText(MockTemplateExample2.name); screen.getByText(MockTemplateExample2.name);
expect(screen.queryByText("Scratch")).not.toBeInTheDocument(); expect(screen.queryByText("Scratch")).toBeInTheDocument();
}); });

View File

@ -1,5 +1,4 @@
import { templateExamples } from "api/queries/templates"; import { templateExamples } from "api/queries/templates";
import type { TemplateExample } from "api/typesGenerated";
import type { FC } from "react"; import type { FC } from "react";
import { Helmet } from "react-helmet-async"; import { Helmet } from "react-helmet-async";
import { useQuery } from "react-query"; import { useQuery } from "react-query";
@ -10,8 +9,7 @@ import { CreateTemplateGalleryPageView } from "./CreateTemplateGalleryPageView";
const CreateTemplatesGalleryPage: FC = () => { const CreateTemplatesGalleryPage: FC = () => {
const templateExamplesQuery = useQuery(templateExamples()); const templateExamplesQuery = useQuery(templateExamples());
const starterTemplatesByTag = templateExamplesQuery.data const starterTemplatesByTag = templateExamplesQuery.data
? // Currently, the scratch template should not be displayed on the starter templates page. ? getTemplatesByTag(templateExamplesQuery.data)
getTemplatesByTag(removeScratchExample(templateExamplesQuery.data))
: undefined; : undefined;
return ( return (
@ -27,8 +25,4 @@ const CreateTemplatesGalleryPage: FC = () => {
); );
}; };
const removeScratchExample = (data: TemplateExample[]) => {
return data.filter((example) => example.id !== "scratch");
};
export default CreateTemplatesGalleryPage; export default CreateTemplatesGalleryPage;

View File

@ -41,34 +41,6 @@ export const CreateTemplateGalleryPageView: FC<
height: "max-content", height: "max-content",
}} }}
> >
<Card variant="outlined" css={{ width: 320, borderRadius: 6 }}>
<CardActionArea
component={RouterLink}
to="/templates/new?exampleId=scratch"
sx={{ height: 115, padding: 1 }}
>
<CardContent>
<Stack
direction="row"
spacing={3}
css={{ alignItems: "center" }}
>
<div css={styles.icon}>
<ExternalImage
src="/emojis/1f4c4.png"
css={{ width: "100%", height: "100%" }}
/>
</div>
<div>
<h4 css={styles.cardTitle}>Scratch Template</h4>
<span css={styles.cardDescription}>
Create a minimal starter template that you can customize
</span>
</div>
</Stack>
</CardContent>
</CardActionArea>
</Card>
<Card variant="outlined" css={{ width: 320, borderRadius: 6 }}> <Card variant="outlined" css={{ width: 320, borderRadius: 6 }}>
<CardActionArea <CardActionArea
component={RouterLink} component={RouterLink}

View File

@ -1,4 +1,5 @@
import type { Interpolation, Theme } from "@emotion/react"; import type { Interpolation, Theme } from "@emotion/react";
import type { TemplateExample } from "api/typesGenerated";
import { Stack } from "components/Stack/Stack"; import { Stack } from "components/Stack/Stack";
import { TemplateExampleCard } from "modules/templates/TemplateExampleCard/TemplateExampleCard"; import { TemplateExampleCard } from "modules/templates/TemplateExampleCard/TemplateExampleCard";
import type { FC } from "react"; import type { FC } from "react";
@ -21,6 +22,21 @@ const selectTags = (starterTemplatesByTag: StarterTemplatesByTag) => {
: undefined; : undefined;
}; };
const sortVisibleTemplates = (templates: TemplateExample[]) => {
// The docker template should be the first template in the list,
// as it's the easiest way to get started with Coder.
const dockerTemplateId = "docker";
return templates.sort((a, b) => {
if (a.id === dockerTemplateId) {
return -1;
}
if (b.id === dockerTemplateId) {
return 1;
}
return a.name.localeCompare(b.name);
});
};
export interface StarterTemplatesProps { export interface StarterTemplatesProps {
starterTemplatesByTag?: StarterTemplatesByTag; starterTemplatesByTag?: StarterTemplatesByTag;
} }
@ -34,7 +50,7 @@ export const StarterTemplates: FC<StarterTemplatesProps> = ({
: undefined; : undefined;
const activeTag = urlParams.get("tag") ?? "all"; const activeTag = urlParams.get("tag") ?? "all";
const visibleTemplates = starterTemplatesByTag const visibleTemplates = starterTemplatesByTag
? starterTemplatesByTag[activeTag] ? sortVisibleTemplates(starterTemplatesByTag[activeTag])
: undefined; : undefined;
return ( return (

View File

@ -26,14 +26,6 @@ export const CreateTemplateButton: FC<CreateTemplateButtonProps> = ({
</Button> </Button>
</MoreMenuTrigger> </MoreMenuTrigger>
<MoreMenuContent> <MoreMenuContent>
<MoreMenuItem
onClick={() => {
onNavigate("/templates/new?exampleId=scratch");
}}
>
<NoteAddOutlined />
From scratch
</MoreMenuItem>
<MoreMenuItem <MoreMenuItem
onClick={() => { onClick={() => {
onNavigate("/templates/new"); onNavigate("/templates/new");

View File

@ -1,42 +0,0 @@
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { AppProviders } from "App";
import { RequireAuth } from "contexts/auth/RequireAuth";
import { RouterProvider, createMemoryRouter } from "react-router-dom";
import TemplatesPage from "./TemplatesPage";
test("create template from scratch", async () => {
const user = userEvent.setup();
const router = createMemoryRouter(
[
{
element: <RequireAuth />,
children: [
{
path: "/templates",
element: <TemplatesPage />,
},
{
path: "/templates/new",
element: <div data-testid="new-template-page" />,
},
],
},
],
{ initialEntries: ["/templates"] },
);
render(
<AppProviders>
<RouterProvider router={router} />
</AppProviders>,
);
const createTemplateButton = await screen.findByRole("button", {
name: "Create Template",
});
await user.click(createTemplateButton);
const fromScratchMenuItem = await screen.findByText("From scratch");
await user.click(fromScratchMenuItem);
await screen.findByTestId("new-template-page");
expect(router.state.location.pathname).toBe("/templates/new");
expect(router.state.location.search).toBe("?exampleId=scratch");
});