fix: support manifest-type tool definitions in Tool Workshop
Backend: - Allow 'manifest' in tool_types definition_type validators - Add manifest_id to ToolTypeCreate, ToolTypeUpdate, ToolTypeResponse - Skip compose/dockerfile template validation when definition_type is manifest - Require manifest_id when definition_type is manifest - Clear legacy templates when switching to manifest type Frontend: - Load manifest data via getToolDefinition when selecting a manifest-type tool - Create/update manifest definition via tool-definitions API when saving - Pass manifest_id to tool-types create/update API - Fix unused EmptyState import after configs/folders cleanup
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
EmptyState,
|
||||
ErrorState,
|
||||
LoadingState,
|
||||
} from "../components/data-states";
|
||||
@@ -22,7 +21,10 @@ import {
|
||||
type UpdateToolTypeRequest,
|
||||
} from "../api/tool_types";
|
||||
import {
|
||||
createToolDefinition,
|
||||
getToolDefinition,
|
||||
listToolDefinitions,
|
||||
updateToolDefinition,
|
||||
type ToolDefinitionManifest,
|
||||
} from "../api/tool_definitions";
|
||||
import { ManifestEditor } from "../components/manifest-editor";
|
||||
@@ -120,7 +122,7 @@ export const ToolWorkshopPage = () => {
|
||||
setManifestDefinitionId(null);
|
||||
};
|
||||
|
||||
const populateToolTypeForm = (toolType: ToolType) => {
|
||||
const populateToolTypeForm = async (toolType: ToolType) => {
|
||||
setToolTypeForm({
|
||||
name: toolType.name,
|
||||
display_name: toolType.display_name,
|
||||
@@ -142,9 +144,18 @@ export const ToolWorkshopPage = () => {
|
||||
});
|
||||
setToolTypeError(null);
|
||||
setToolTypeDirty(false);
|
||||
// For manifest types, we'd need to load the manifest data separately
|
||||
setManifestData(null);
|
||||
setManifestDefinitionId(toolType.manifest_id || null);
|
||||
|
||||
if (toolType.definition_type === "manifest" && toolType.manifest_id) {
|
||||
try {
|
||||
const defn = await getToolDefinition(toolType.manifest_id);
|
||||
setManifestData(defn.manifest);
|
||||
} catch {
|
||||
setManifestData(null);
|
||||
}
|
||||
} else {
|
||||
setManifestData(null);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectToolType = (toolType: ToolType | null) => {
|
||||
@@ -203,6 +214,9 @@ export const ToolWorkshopPage = () => {
|
||||
);
|
||||
return;
|
||||
}
|
||||
} else if (!manifestData) {
|
||||
setToolTypeError("Manifest data is required for manifest definition type");
|
||||
return;
|
||||
}
|
||||
|
||||
const variables = toolTypeForm.required_variables
|
||||
@@ -226,6 +240,23 @@ export const ToolWorkshopPage = () => {
|
||||
|
||||
try {
|
||||
if (isCreating) {
|
||||
let manifestId: string | undefined;
|
||||
if (toolTypeForm.definition_type === "manifest" && manifestData) {
|
||||
const manifestPayload = {
|
||||
name: toolTypeForm.name.trim(),
|
||||
display_name: toolTypeForm.display_name.trim(),
|
||||
description: toolTypeForm.description.trim() || undefined,
|
||||
category: toolTypeForm.category.trim() || undefined,
|
||||
interface_type: toolTypeForm.interface_type,
|
||||
base_image: (manifestData.base_image as string) || undefined,
|
||||
base_definition_id:
|
||||
(manifestData.base_definition_id as string) || undefined,
|
||||
manifest: manifestData,
|
||||
};
|
||||
const newManifest = await createToolDefinition(manifestPayload);
|
||||
manifestId = newManifest.id;
|
||||
}
|
||||
|
||||
const input: CreateToolTypeRequest = {
|
||||
name: toolTypeForm.name.trim(),
|
||||
display_name: toolTypeForm.display_name.trim(),
|
||||
@@ -237,6 +268,7 @@ export const ToolWorkshopPage = () => {
|
||||
? Number(toolTypeForm.default_port)
|
||||
: 0,
|
||||
definition_type: toolTypeForm.definition_type,
|
||||
manifest_id: manifestId,
|
||||
compose_template:
|
||||
toolTypeForm.definition_type === "compose" ? template : undefined,
|
||||
dockerfile_template:
|
||||
@@ -252,6 +284,34 @@ export const ToolWorkshopPage = () => {
|
||||
setSelectedToolTypeId(newTool.id);
|
||||
setToolTypeDirty(false);
|
||||
} else if (selectedToolType) {
|
||||
let manifestId = selectedToolType.manifest_id || undefined;
|
||||
if (toolTypeForm.definition_type === "manifest" && manifestData) {
|
||||
if (manifestId) {
|
||||
await updateToolDefinition(manifestId, {
|
||||
display_name: toolTypeForm.display_name.trim(),
|
||||
description: toolTypeForm.description.trim() || undefined,
|
||||
category: toolTypeForm.category.trim() || undefined,
|
||||
manifest: manifestData,
|
||||
});
|
||||
} else {
|
||||
const manifestPayload = {
|
||||
name: toolTypeForm.name.trim(),
|
||||
display_name: toolTypeForm.display_name.trim(),
|
||||
description: toolTypeForm.description.trim() || undefined,
|
||||
category: toolTypeForm.category.trim() || undefined,
|
||||
interface_type: toolTypeForm.interface_type,
|
||||
base_image:
|
||||
(manifestData.base_image as string) || undefined,
|
||||
base_definition_id:
|
||||
(manifestData.base_definition_id as string) || undefined,
|
||||
manifest: manifestData,
|
||||
};
|
||||
const newManifest =
|
||||
await createToolDefinition(manifestPayload);
|
||||
manifestId = newManifest.id;
|
||||
}
|
||||
}
|
||||
|
||||
const input: UpdateToolTypeRequest = {
|
||||
display_name: toolTypeForm.display_name.trim(),
|
||||
description: toolTypeForm.description.trim() || undefined,
|
||||
@@ -262,6 +322,10 @@ export const ToolWorkshopPage = () => {
|
||||
? Number(toolTypeForm.default_port)
|
||||
: 0,
|
||||
definition_type: toolTypeForm.definition_type,
|
||||
manifest_id:
|
||||
toolTypeForm.definition_type === "manifest"
|
||||
? manifestId
|
||||
: undefined,
|
||||
compose_template:
|
||||
toolTypeForm.definition_type === "compose" ? template : undefined,
|
||||
dockerfile_template:
|
||||
|
||||
Reference in New Issue
Block a user