From 8a095d3b381fdf647e1e13416faf5a9110fc9ef9 Mon Sep 17 00:00:00 2001 From: Andrew Aquino Date: Thu, 9 Jul 2026 10:48:14 -0700 Subject: [PATCH] feat(site/src/pages/TemplateBuilder): deselect modules using button in main content area instead of sidebar (#27113) closes DEVEX-588 Prototyped in #27077, broken off into a separate PR to make this work easier to track ## changes - Reveals the previously hidden trash can icon within `ModuleConfiguration` (main content area) - Removes the "x" icons from `ModuleSelection` (sidebar) ## context @tracyjohnsonux and I decided [in Slack](https://codercom.slack.com/archives/C0AUKB54P0E/p1783456607073329?thread_ts=1783450189.570979&cid=C0AUKB54P0E) that it would be a better UX to move the deletion action from the "x" icons in the sidebar to the trash can icons in the main content area. This change has the benefits of 1. making it harder to delete modules accidentally 2. removing the responsibility of deletion from the items in `ModuleSelection` - interacting with these items will serve only to navigate to configuring that module (DEVEX-587, to be done in a separate PR) image --- .../TemplateBuilder/ModuleSettingsStep.tsx | 3 ++ .../SelectionSummary.stories.tsx | 5 +--- .../TemplateBuilder/SelectionSummary.tsx | 28 ++----------------- .../TemplateBuilderPageView.tsx | 4 ++- 4 files changed, 10 insertions(+), 30 deletions(-) diff --git a/site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx b/site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx index 538b754ed9..eb89be0810 100644 --- a/site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx +++ b/site/src/pages/TemplateBuilder/ModuleSettingsStep.tsx @@ -26,6 +26,7 @@ interface ModuleSettingsStepProps { moduleId: string, variables: Record, ) => void; + onRemoveModule: (moduleId: string) => void; } function variableToField( @@ -107,6 +108,7 @@ export const ModuleSettingsStep: FC = ({ selectedModuleIds, moduleVariables, onChangeModuleVariables, + onRemoveModule, }) => { const { data } = useQuery(templateBuilderModules(baseId)); const modules = data?.modules ?? []; @@ -157,6 +159,7 @@ export const ModuleSettingsStep: FC = ({ detailsUrl={moduleDetailsUrl(mod.id)} fields={requiredFields} optionalFields={optionalFields} + onRemove={() => onRemoveModule(mod.id)} /> {sensitiveVars.length > 0 && ( diff --git a/site/src/pages/TemplateBuilder/SelectionSummary.stories.tsx b/site/src/pages/TemplateBuilder/SelectionSummary.stories.tsx index 7c83ef57df..3c50d9e07d 100644 --- a/site/src/pages/TemplateBuilder/SelectionSummary.stories.tsx +++ b/site/src/pages/TemplateBuilder/SelectionSummary.stories.tsx @@ -1,13 +1,10 @@ import type { Meta, StoryObj } from "@storybook/react-vite"; -import { expect, fn, within } from "storybook/test"; +import { expect, within } from "storybook/test"; import { SelectionSummary } from "./SelectionSummary"; const meta: Meta = { title: "pages/TemplateBuilder/SelectionSummary", component: SelectionSummary, - args: { - onDeselectModule: fn(), - }, }; export default meta; diff --git a/site/src/pages/TemplateBuilder/SelectionSummary.tsx b/site/src/pages/TemplateBuilder/SelectionSummary.tsx index 0c83339b37..f669143048 100644 --- a/site/src/pages/TemplateBuilder/SelectionSummary.tsx +++ b/site/src/pages/TemplateBuilder/SelectionSummary.tsx @@ -1,8 +1,6 @@ import { cva } from "class-variance-authority"; -import { XIcon } from "lucide-react"; import { createContext, type PropsWithChildren, useContext } from "react"; import { Avatar } from "#/components/Avatar/Avatar"; -import { Button } from "#/components/Button/Button"; import { cn } from "#/utils/cn"; type Variant = "complete" | "current" | "upcoming" | null | undefined; @@ -24,14 +22,12 @@ type SelectionSummaryProps = { currentStep: number; selectedTemplate?: SelectedTemplate; selectedModules?: SelectedModule[]; - onDeselectModule: (moduleId: string) => void; }; export const SelectionSummary: React.FC = ({ currentStep, selectedTemplate, selectedModules, - onDeselectModule, }) => { const variant = (step: number) => { if (currentStep === step) return "current"; @@ -53,10 +49,7 @@ export const SelectionSummary: React.FC = ({ Modules {selectedModules ? ( - + ) : ( )} @@ -161,19 +154,15 @@ const BaseTemplateSelection: React.FC = ({ type ModuleSelectionProps = { modules: SelectedModule[]; - onDeselectModule: (moduleId: string) => void; }; -const ModuleSelection: React.FC = ({ - modules, - onDeselectModule, -}) => { +const ModuleSelection: React.FC = ({ modules }) => { return ( {modules.map((module) => (
@@ -181,17 +170,6 @@ const ModuleSelection: React.FC = ({ {module.name} -
- -
))} diff --git a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx index bb11c33d9c..8d5ede68cd 100644 --- a/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx +++ b/site/src/pages/TemplateBuilder/TemplateBuilderPageView.tsx @@ -162,6 +162,7 @@ export const TemplateBuilderPageView: FC = ({ moduleVarMap, createError, handleProvisionerStatusChange, + handleDeselectModule, )}
@@ -199,7 +200,6 @@ export const TemplateBuilderPageView: FC = ({ ? state.selectedModules : undefined } - onDeselectModule={handleDeselectModule} /> @@ -214,6 +214,7 @@ function renderStepContent( moduleVarMap: Record>, createError: Error | null, onProvisionerStatusChange: (value: boolean | undefined) => void, + onRemoveModule: (moduleId: string) => void, ): ReactNode { switch (stepId) { case "base-infra": @@ -259,6 +260,7 @@ function renderStepContent( variables, }) } + onRemoveModule={onRemoveModule} /> ); case "customizations":