From 350b39345753967974db0e3d095407d9b309548f Mon Sep 17 00:00:00 2001 From: Developer Date: Sat, 13 Jun 2026 21:41:42 +0000 Subject: [PATCH] feat: rework mobile UI for Tool Workshop and Profile pages - Rework ToolWorkshopMobileView to support full desktop functionality: definition type selection (Compose/Dockerfile/Manifest), manifest editor, conditional port, startup command, readiness probe, required variables, and validation feedback. - Add ProfileMobileView and wire ProfilePage to render it on mobile. - Update useToolWorkshop hook to return boolean success from submit. - Add responsive CSS for mobile forms, edit views, and manifest editor. - Update project maps. Quality gates: npm run typecheck, npm run lint, npm test -- --run (87 passed) Refs: openspec/changes/mobile-tool-profile-ui --- .pi-map.index.md | 2 +- .pi-map.md | 4 +- apps/.pi-map.index.md | 2 +- apps/.pi-map.md | 4 +- apps/web/.pi-map.index.md | 2 +- apps/web/.pi-map.md | 4 +- apps/web/src/.pi-map.index.md | 2 +- apps/web/src/.pi-map.md | 4 +- apps/web/src/components/.pi-map.index.md | 2 +- .../src/components/features/.pi-map.index.md | 5 +- .../features/profile/.pi-map.index.md | 20 + .../components/features/profile/.pi-map.md | 20 + .../features/profile/ProfileMobileView.tsx | 119 ++++++ .../features/tool-workshop/.pi-map.index.md | 2 +- .../features/tool-workshop/.pi-map.md | 8 +- .../tool-workshop/ToolWorkshopMobileView.tsx | 400 ++++++++++++------ apps/web/src/hooks/.pi-map.index.md | 2 +- apps/web/src/hooks/.pi-map.md | 12 +- apps/web/src/hooks/use-tool-workshop.ts | 12 +- apps/web/src/pages/.pi-map.index.md | 2 +- apps/web/src/pages/.pi-map.md | 14 +- apps/web/src/pages/ProfilePage.tsx | 23 +- apps/web/src/pages/ToolWorkshopPage.tsx | 8 + apps/web/src/styles/.pi-map.index.md | 2 +- apps/web/src/styles/.pi-map.md | 6 +- apps/web/src/styles/utilities.css | 268 +++++++++++- .../changes/mobile-tool-profile-ui/change.md | 26 ++ .../changes/mobile-tool-profile-ui/tasks.md | 9 + 28 files changed, 797 insertions(+), 187 deletions(-) create mode 100644 apps/web/src/components/features/profile/.pi-map.index.md create mode 100644 apps/web/src/components/features/profile/.pi-map.md create mode 100644 apps/web/src/components/features/profile/ProfileMobileView.tsx create mode 100644 openspec/changes/mobile-tool-profile-ui/change.md create mode 100644 openspec/changes/mobile-tool-profile-ui/tasks.md diff --git a/.pi-map.index.md b/.pi-map.index.md index d5c5044..015bdf0 100644 --- a/.pi-map.index.md +++ b/.pi-map.index.md @@ -16,7 +16,7 @@ dir: . Trust boundary: index routes, map orients, source decides. ## role -Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing containerized orchestration, environment templates, and development tooling. +Infrastructure and deployment configuration for a self-hosted project management and git repository platform with OAuth2 authentication. ## parent - ## children diff --git a/.pi-map.md b/.pi-map.md index 54bb3f4..ecfa994 100644 --- a/.pi-map.md +++ b/.pi-map.md @@ -18,7 +18,7 @@ index: ./.pi-map.index.md Trust boundary: index routes, map orients, source decides. ## role -Infrastructure and deployment configuration package for a self-hosted project management platform with OAuth2 authentication, providing containerized orchestration, environment templates, and development tooling. +A self-hosted, containerized project management and Git repository platform with OAuth2/SSO authentication, designed for deployment via Docker Compose with optional Traefik reverse proxy integration. ## files - .env.example | Provides a template of environment variables for configuring a Headquarter application with PostgreSQL, Redis, Authentik SSO, and Docker/Traefik deployment - .gitignore | Specifies files and directories for Git to ignore across a multi-language project with Python, Node, and custom tooling | dep: Git @@ -31,7 +31,7 @@ Infrastructure and deployment configuration package for a self-hosted project ma - progress.md | Tracks completed and remaining tasks for a backend-frontend code refactoring project organized in 7 phases - swap-pane | Empty file with no functionality ## arch -Docker Compose-based microservices architecture with frontend/backend separation, PostgreSQL/Redis data layer, Traefik reverse proxy integration, and environment-driven configuration management following twelve-factor app principles. +Multi-service containerized architecture using PostgreSQL and Redis for persistence/caching, a decoupled frontend/backend web stack, environment-driven configuration via .env files, and infrastructure-as-code deployment patterns with Docker Compose profiles for standalone and reverse-proxy modes. ## tags docker, redis, git, application, postgresql, compose, traefik, project ## symbols diff --git a/apps/.pi-map.index.md b/apps/.pi-map.index.md index e4bae7d..9d5e74a 100644 --- a/apps/.pi-map.index.md +++ b/apps/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps ## role -Contains the main deployable application modules or entry points for the project. +Contains the main deployable application entry points and top-level configurations for the project. ## parent index: ./.pi-map.index.md map: ./.pi-map.md diff --git a/apps/.pi-map.md b/apps/.pi-map.md index 5415b96..0453b66 100644 --- a/apps/.pi-map.md +++ b/apps/.pi-map.md @@ -4,10 +4,10 @@ dir: apps index: apps/.pi-map.index.md ## role -Contains the main deployable application modules or entry points for the project. +Container directory for individual deployable applications within the project. ## files ## arch -Modular monolith or microservices architecture with separate application boundaries, each potentially having its own configuration, dependencies, and lifecycle. +Monorepo-style organization where each subdirectory represents a standalone application sharing common infrastructure and dependencies. ## tags - ## symbols diff --git a/apps/web/.pi-map.index.md b/apps/web/.pi-map.index.md index 44a1bb2..5435632 100644 --- a/apps/web/.pi-map.index.md +++ b/apps/web/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps/web ## role -Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project. +Frontend web application for a browser-based code editing and terminal environment with client-side routing. ## parent index: apps/.pi-map.index.md map: apps/.pi-map.md diff --git a/apps/web/.pi-map.md b/apps/web/.pi-map.md index 095844e..20e9c70 100644 --- a/apps/web/.pi-map.md +++ b/apps/web/.pi-map.md @@ -4,7 +4,7 @@ dir: apps/web index: apps/web/.pi-map.index.md ## role -Frontend web application providing a React-based UI with code editing, terminal, and routing capabilities for the "headquarter" project. +Frontend web application providing the user-facing interface for the "headquarter" project, built as a modern React SPA with code editing, terminal, and routing capabilities. ## files - .env.example | Template file defining example environment variables for frontend API and application URL configuration - .eslintrc.cjs | Configures ESLint for a TypeScript browser project with modern ECMAScript module support | dep: @typescript-eslint/parser, @typescript-eslint/eslint-plugin, eslint @@ -16,7 +16,7 @@ Frontend web application providing a React-based UI with code editing, terminal, - tsconfig.json | TypeScript configuration file for a React project using Vite with modern ES2020 target and bundler module resolution | dep: typescript, react, vite - vite.config.ts | Configures Vite build tool for a React project with custom dev server port and Vitest test settings. | dep: vite, @vitejs/plugin-react ## arch -Modern React SPA built with Vite and TypeScript, using nginx for production serving with client-side routing, multi-stage Docker deployment, and Vitest for testing. +Modern React SPA architecture using Vite for build tooling, TypeScript for type safety, nginx for static serving with SPA routing support, and Docker multi-stage builds for containerized deployment with non-root security. ## tags react, eslint, vite, typescript, dom, application, nginx, web ## symbols diff --git a/apps/web/src/.pi-map.index.md b/apps/web/src/.pi-map.index.md index 37825fa..54a2642 100644 --- a/apps/web/src/.pi-map.index.md +++ b/apps/web/src/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps/web/src ## role -Frontend web application entry point and core infrastructure for a React-based collaborative development platform. +Entry point and core infrastructure for a React web application providing authentication-aware routing and shared type definitions. ## parent index: apps/web/.pi-map.index.md map: apps/web/.pi-map.md diff --git a/apps/web/src/.pi-map.md b/apps/web/src/.pi-map.md index d00be5a..da8121e 100644 --- a/apps/web/src/.pi-map.md +++ b/apps/web/src/.pi-map.md @@ -4,13 +4,13 @@ dir: apps/web/src index: apps/web/src/.pi-map.index.md ## role -Frontend web application entry point and core infrastructure for a React-based collaborative development platform. +Provides the core web application entry point, routing infrastructure, and shared domain type definitions for a React-based frontend. ## files - main.tsx | Bootstraps a React application with routing, authentication, and session management providers. | dep: react, react-dom/client, react-router-dom, ./router, ./state/auth, ./state/sessions, ./styles/tokens.css, ./styles/global.css, ./styles/utilities.css, ./styles/syntax-highlight.css, ./styles/pages/git-history.css, ./styles/pages/projects.css, ./styles/pages/sessions.css, ./styles/pages/ssh-keys.css, ./styles/pages/workspace-detail.css, ./styles/pages/workspaces.css, react-dom - router.tsx | Defines the React Router configuration for a web application with protected routes, nested layouts, and redirects. | exp: AppRouter | dep: react-router-dom, ./components/app-shell, ./components/protected-route, ./pages/DashboardPage, ./pages/PlaceholderPage, ./pages/ProfilePage, ./pages/ProjectsPage, ./pages/GitRepositoriesPage, ./pages/GitHistoryPage, ./pages/ProjectSettingsPage, ./pages/SettingsPage, ./pages/TerminalPage, ./pages/ToolWorkshopPage, ./pages/SshKeysPage, ./pages/ConfigProfilesPage, ./pages/SessionsPage, ./pages/WorkspacesPage, ./pages/WorkspaceDetailPage - types.ts | Defines TypeScript type definitions for user sessions, projects, repositories, and workspaces in an application. | exp: SessionUser, SessionPayload, Project, WorkspaceSummary, RepositorySummary, ProjectWithRepos ## arch -Modular React SPA using React Router v6 with nested route layouts, protected route guards via authentication context, and centralized TypeScript domain models for session/workspace/project entities. +Layered React SPA architecture using React Router v6 with nested route layouts, provider composition pattern for auth/session context, and centralized TypeScript domain modeling. ## tags pages, styles, css, router, react, session, dom, project ## symbols diff --git a/apps/web/src/components/.pi-map.index.md b/apps/web/src/components/.pi-map.index.md index 1895804..92d53a9 100644 --- a/apps/web/src/components/.pi-map.index.md +++ b/apps/web/src/components/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps/web/src/components ## role -Provides reusable, accessible UI components and utilities for rendering the application shell, data states, icons, code display, notifications, and route protection in a React web application. +Provides reusable, accessible UI primitives and layout components for a React web application, including shell layout, data states, icons, code display, routing guards, and toast notifications. ## parent index: apps/web/src/.pi-map.index.md map: apps/web/src/.pi-map.md diff --git a/apps/web/src/components/features/.pi-map.index.md b/apps/web/src/components/features/.pi-map.index.md index fdcbc48..3f75e0e 100644 --- a/apps/web/src/components/features/.pi-map.index.md +++ b/apps/web/src/components/features/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps/web/src/components/features ## role -Contains reusable React components that implement specific user-facing features and functionality across the web application. +Reusable UI feature components that compose domain-specific functionality for the web application ## parent index: apps/web/src/components/.pi-map.index.md map: apps/web/src/components/.pi-map.md @@ -19,6 +19,9 @@ map: apps/web/src/components/.pi-map.md - apps/web/src/components/features/notification index: apps/web/src/components/features/notification/.pi-map.index.md map: apps/web/src/components/features/notification/.pi-map.md +- apps/web/src/components/features/profile + index: apps/web/src/components/features/profile/.pi-map.index.md + map: apps/web/src/components/features/profile/.pi-map.md - apps/web/src/components/features/project index: apps/web/src/components/features/project/.pi-map.index.md map: apps/web/src/components/features/project/.pi-map.md diff --git a/apps/web/src/components/features/profile/.pi-map.index.md b/apps/web/src/components/features/profile/.pi-map.index.md new file mode 100644 index 0000000..f5fc594 --- /dev/null +++ b/apps/web/src/components/features/profile/.pi-map.index.md @@ -0,0 +1,20 @@ +# apps/web/src/components/features/profile (index) +dir: apps/web/src/components/features/profile + +## role +Provides a mobile-specific UI for users to view and edit their profile information. +## parent +index: apps/web/src/components/features/.pi-map.index.md +map: apps/web/src/components/features/.pi-map.md +## children +- +## files +- ProfileMobileView.tsx +## links +index: apps/web/src/components/features/profile/.pi-map.index.md +map: apps/web/src/components/features/profile/.pi-map.md +## workflows +- change profile behavior + read: ProfileMobileView.tsx +## dirty +- diff --git a/apps/web/src/components/features/profile/.pi-map.md b/apps/web/src/components/features/profile/.pi-map.md new file mode 100644 index 0000000..54ca4ac --- /dev/null +++ b/apps/web/src/components/features/profile/.pi-map.md @@ -0,0 +1,20 @@ +# apps/web/src/components/features/profile +dir: apps/web/src/components/features/profile + +index: apps/web/src/components/features/profile/.pi-map.index.md + +## role +Provides a mobile-specific UI for users to view and edit their profile information. +## files +- ProfileMobileView.tsx | Renders a mobile-optimized profile editing form with avatar upload, name/email fields, and save/cancel functionality. | exp: ProfileMobileView | dep: react-router-dom, ../mobile/mobile-edit-view, ../../icon, ../../../api/profile +## arch +Single feature-focused component with form handling and file upload, likely using controlled inputs and local state management. +## tags +mobile, profile, view, renders, optimized, editing, form, avatar +## symbols +- ProfileMobileView +## workflows +- change profile behavior + read: ProfileMobileView.tsx +## dirty +- diff --git a/apps/web/src/components/features/profile/ProfileMobileView.tsx b/apps/web/src/components/features/profile/ProfileMobileView.tsx new file mode 100644 index 0000000..c255bc7 --- /dev/null +++ b/apps/web/src/components/features/profile/ProfileMobileView.tsx @@ -0,0 +1,119 @@ +import { useNavigate } from "react-router-dom"; +import { MobileEditView } from "../mobile/mobile-edit-view"; +import { Icon } from "../../icon"; +import type { UserProfile } from "../../../api/profile"; + +interface ProfileMobileViewProps { + profile: UserProfile; + name: string; + email: string; + error: string | null; + isSaving: boolean; + avatarUrl: string | null; + fileInputRef: React.RefObject; + onNameChange: (value: string) => void; + onEmailChange: (value: string) => void; + onAvatarButtonClick: () => void; + onAvatarChange: (event: React.ChangeEvent) => void; + onSave: () => void; +} + +export const ProfileMobileView = ({ + profile, + name, + email, + error, + isSaving, + avatarUrl, + fileInputRef, + onNameChange, + onEmailChange, + onAvatarButtonClick, + onAvatarChange, + onSave, +}: ProfileMobileViewProps) => { + const navigate = useNavigate(); + + return ( + navigate(-1)} + onSave={onSave} + isSaving={isSaving} + > +
+
+ {avatarUrl ? ( + Avatar + ) : ( +
+ {profile.name.charAt(0).toUpperCase()} +
+ )} +
+ + +
+ +
+ + onNameChange(e.target.value)} + placeholder="Your name" + type="text" + value={name} + /> +
+ +
+ + onEmailChange(e.target.value)} + placeholder="your.email@example.com" + type="email" + value={email} + /> +
+ + {error && ( +

+ + {error} +

+ )} +
+ ); +}; diff --git a/apps/web/src/components/features/tool-workshop/.pi-map.index.md b/apps/web/src/components/features/tool-workshop/.pi-map.index.md index 2c4a9b9..b8444b5 100644 --- a/apps/web/src/components/features/tool-workshop/.pi-map.index.md +++ b/apps/web/src/components/features/tool-workshop/.pi-map.index.md @@ -2,7 +2,7 @@ dir: apps/web/src/components/features/tool-workshop ## role -Provides a complete UI for managing custom tool types in a "Tool Workshop" interface with list, edit, and mobile-responsive views. +Provides a complete CRUD interface for managing reusable tool type definitions (Docker Compose, Dockerfile, Manifest) in a workshop-style admin panel with responsive desktop and mobile layouts. ## parent index: apps/web/src/components/features/.pi-map.index.md map: apps/web/src/components/features/.pi-map.md diff --git a/apps/web/src/components/features/tool-workshop/.pi-map.md b/apps/web/src/components/features/tool-workshop/.pi-map.md index c4c2d6f..54dead6 100644 --- a/apps/web/src/components/features/tool-workshop/.pi-map.md +++ b/apps/web/src/components/features/tool-workshop/.pi-map.md @@ -4,15 +4,15 @@ dir: apps/web/src/components/features/tool-workshop index: apps/web/src/components/features/tool-workshop/.pi-map.index.md ## role -Provides a complete UI for managing custom tool types in a "Tool Workshop" interface with list, edit, and mobile-responsive views. +Provides a complete CRUD interface for managing reusable tool type definitions (Docker Compose, Dockerfile, Manifest) in a workshop-style admin panel with responsive desktop and mobile layouts. ## files - ToolTypeEditorPanel.tsx | Renders a form panel for creating or editing tool types with support for compose, dockerfile, and manifest definition types | exp: ToolTypeFormState, ToolTypeEditorPanel | dep: ../../icon, ../tool/manifest-editor, ../../../api/tool-types, ../../../api/tool-definitions, React, Icon, ManifestEditor - ToolTypeListSidebar.tsx | Renders a sidebar component for listing, selecting, creating, and deleting tool types in a "Tool Workshop" interface. | exp: ToolTypeListSidebar | dep: ../../icon, ../../../api/tool-types, React, Icon component, ToolType type -- ToolWorkshopMobileView.tsx | Renders a mobile-responsive view for managing tool types with list, detail, and edit modes | exp: MobileView, ToolWorkshopMobileView | dep: ../mobile/mobile-list-view, ../mobile/mobile-detail-view, ../mobile/mobile-edit-view, ../mobile/mobile-fab, ../../../api/tool-types, ./ToolTypeEditorPanel, MobileListView, MobileDetailView, MobileEditView, MobileFAB, ToolType, ToolTypeFormState +- ToolWorkshopMobileView.tsx | Renders a mobile-responsive three-view (list/detail/edit) interface for managing tool types in a tool workshop, with form handling for creating and editing tool configurations including Docker Compose, Dockerfile, or Manifest definitions. | exp: MobileView, ToolWorkshopMobileView | dep: react, ../mobile/mobile-list-view, ../mobile/mobile-detail-view, ../mobile/mobile-edit-view, ../mobile/mobile-fab, ../tool/manifest-editor, ../../icon, ../../../api/tool-types, ./ToolTypeEditorPanel, ../../../api/tool-definitions, mobile-list-view, mobile-detail-view, mobile-edit-view, mobile-fab, manifest-editor, icon, tool-types, ToolTypeEditorPanel, tool-definitions ## arch -Uses a split-pane sidebar/detail panel pattern with dedicated mobile breakpoint handling, separating list navigation from form editing concerns across three specialized view components. +Compound component pattern with split-pane desktop layout (sidebar list + editor panel) and state-driven mobile view with three-view routing (list/detail/edit), using React state for form management and optimistic UI updates. ## tags -tool, mobile, type, view, types, list, panel, editor +tool, mobile, view, type, types, editor, list, workshop ## symbols - ToolTypeFormState - ToolTypeEditorPanel diff --git a/apps/web/src/components/features/tool-workshop/ToolWorkshopMobileView.tsx b/apps/web/src/components/features/tool-workshop/ToolWorkshopMobileView.tsx index dad3fda..555f814 100644 --- a/apps/web/src/components/features/tool-workshop/ToolWorkshopMobileView.tsx +++ b/apps/web/src/components/features/tool-workshop/ToolWorkshopMobileView.tsx @@ -1,9 +1,14 @@ +import { useState } from "react"; + import { MobileListView } from "../mobile/mobile-list-view"; import { MobileDetailView } from "../mobile/mobile-detail-view"; import { MobileEditView } from "../mobile/mobile-edit-view"; import { MobileFAB } from "../mobile/mobile-fab"; +import { ManifestEditor } from "../tool/manifest-editor"; +import { Icon } from "../../icon"; import type { ToolType } from "../../../api/tool-types"; import type { ToolTypeFormState } from "./ToolTypeEditorPanel"; +import type { ToolDefinitionManifest } from "../../../api/tool-definitions"; export type MobileView = "list" | "detail" | "edit"; @@ -13,13 +18,18 @@ interface ToolWorkshopMobileViewProps { mobileView: MobileView; isCreating: boolean; toolTypeForm: ToolTypeFormState; + manifestData: Record | null; + manifestDefinitionId: string | null; + baseDefinitions: ToolDefinitionManifest[]; toolTypeError: string | null; + toolTypeDirty: boolean; onViewChange: (view: MobileView) => void; onSelect: (toolType: ToolType) => void; onCreate: () => void; onDelete: (id: string) => void; onFormChange: (changes: Partial) => void; - onSubmit: () => void; + onManifestChange: (manifest: Record | null) => void; + onSubmit: (e?: React.FormEvent) => Promise; onCancel: () => void; } @@ -29,15 +39,41 @@ export const ToolWorkshopMobileView = ({ mobileView, isCreating, toolTypeForm, + manifestData, + manifestDefinitionId, + baseDefinitions, toolTypeError, + toolTypeDirty, onViewChange, onSelect, onCreate, onDelete, onFormChange, + onManifestChange, onSubmit, onCancel, }: ToolWorkshopMobileViewProps) => { + const [isSaving, setIsSaving] = useState(false); + + const handleSave = async () => { + setIsSaving(true); + try { + const ok = await onSubmit(); + if (ok) { + onViewChange("list"); + } + } finally { + setIsSaving(false); + } + }; + + const handleDelete = () => { + if (selectedToolType) { + void onDelete(selectedToolType.id); + onViewChange("list"); + } + }; + if (mobileView === "list") { return (
@@ -49,7 +85,7 @@ export const ToolWorkshopMobileView = ({ items={toolTypes.map((t) => ({ id: t.id, title: t.display_name, - subtitle: `${t.category || "Uncategorized"} · ${t.interface_type === "web" ? `Port ${t.default_port}` : "Terminal"}`, + subtitle: `${t.category || "Uncategorized"} · ${t.definition_type} · ${t.interface_type === "web" ? `Port ${t.default_port}` : "Terminal"}`, }))} onItemClick={(id) => { const toolType = toolTypes.find((t) => t.id === id); @@ -71,64 +107,70 @@ export const ToolWorkshopMobileView = ({ } if (mobileView === "detail" && selectedToolType) { + const fields = [ + { label: "Name", value: selectedToolType.name }, + { label: "Display Name", value: selectedToolType.display_name }, + { label: "Description", value: selectedToolType.description }, + { label: "Category", value: selectedToolType.category }, + { label: "Interface Type", value: selectedToolType.interface_type }, + { + label: "Requires Port", + value: selectedToolType.requires_port, + type: "boolean" as const, + }, + ...(selectedToolType.requires_port + ? [{ label: "Default Port", value: selectedToolType.default_port }] + : []), + { + label: "Definition Type", + value: selectedToolType.definition_type, + }, + { + label: "Startup Command", + value: selectedToolType.startup_command, + }, + { + label: "Readiness Command", + value: selectedToolType.readiness_probe?.command ?? null, + }, + { + label: "Readiness Timeout", + value: selectedToolType.readiness_probe?.timeout ?? null, + }, + { + label: "Readiness Interval", + value: selectedToolType.readiness_probe?.interval ?? null, + }, + { + label: "Required Variables", + value: selectedToolType.required_variables?.join(", ") ?? null, + }, + ...(selectedToolType.definition_type !== "manifest" + ? [ + { + label: + selectedToolType.definition_type === "compose" + ? "Compose Template" + : "Dockerfile Template", + value: + selectedToolType.definition_type === "compose" + ? selectedToolType.compose_template + : selectedToolType.dockerfile_template, + type: "code" as const, + }, + ] + : []), + ]; + return ( { onViewChange("edit"); }} - onDelete={() => { - void onDelete(selectedToolType.id); - onViewChange("list"); - }} + onDelete={handleDelete} onBack={() => { onViewChange("list"); }} @@ -137,18 +179,39 @@ export const ToolWorkshopMobileView = ({ } if (mobileView === "edit") { + const templateValue = + toolTypeForm.definition_type === "compose" + ? toolTypeForm.compose_template + : toolTypeForm.dockerfile_template; + return ( { - onSubmit(); - if (!toolTypeError) { - onViewChange("list"); - } - }} - isSaving={false} + onSave={handleSave} + isSaving={isSaving} > +
+ + +
+
onFormChange({ name: e.target.value })} className="mobile-form-input" placeholder="e.g., my-tool" + disabled={!isCreating} + required />
+
onFormChange({ display_name: e.target.value })} className="mobile-form-input" placeholder="e.g., My Tool" + required />
+