feat: Implement recipe copy and delete functionality

Backend changes (C#):
- Add CopyRecipe method to MachineBridge
  - Generates new GUID for copied recipe
  - Returns new recipe with current timestamp
- Add DeleteRecipe method to MachineBridge
  - Prevents deletion of currently selected recipe
  - Returns success/failure status
- Add COPY_RECIPE and DELETE_RECIPE handlers in WebSocketServer

Frontend changes (React/TypeScript):
- Add CopyRecipe and DeleteRecipe to Window interface types
- Add copyRecipe and deleteRecipe methods to communication layer
- Implement handleCopy in RecipePage
  - Prompts user for new name
  - Adds copied recipe to list
  - Selects newly copied recipe
- Implement handleDelete in RecipePage
  - Shows confirmation dialog
  - Removes recipe from list
  - Selects next available recipe
- Connect Copy and Delete buttons with handlers
- Disable buttons when no recipe is selected

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-24 23:53:35 +09:00
parent 8c1a87ded0
commit 27cc2507cf
5 changed files with 206 additions and 2 deletions

View File

@@ -153,5 +153,58 @@ namespace HMIWeb
return Newtonsoft.Json.JsonConvert.SerializeObject(recipes);
}
public string CopyRecipe(string recipeId, string newName)
{
Console.WriteLine($"[C#] Copying Recipe: {recipeId} as {newName}");
try
{
// In real app, copy recipe data from database/file
// Generate new ID
string newId = System.Guid.NewGuid().ToString().Substring(0, 8);
string timestamp = System.DateTime.Now.ToString("yyyy-MM-dd");
var response = new {
success = true,
message = "Recipe copied successfully",
newRecipe = new {
id = newId,
name = newName,
lastModified = timestamp
}
};
return JsonConvert.SerializeObject(response);
}
catch (Exception ex)
{
var response = new { success = false, message = ex.Message };
return JsonConvert.SerializeObject(response);
}
}
public string DeleteRecipe(string recipeId)
{
Console.WriteLine($"[C#] Deleting Recipe: {recipeId}");
try
{
// In real app, delete recipe from database/file
// Check if recipe is in use
if (recipeId == _host.GetCurrentRecipe())
{
var response = new { success = false, message = "Cannot delete currently selected recipe" };
return JsonConvert.SerializeObject(response);
}
var response = new { success = true, message = "Recipe deleted successfully", recipeId = recipeId };
return JsonConvert.SerializeObject(response);
}
catch (Exception ex)
{
var response = new { success = false, message = ex.Message };
return JsonConvert.SerializeObject(response);
}
}
}
}

View File

@@ -177,6 +177,23 @@ namespace HMIWeb
var response = new { type = "RECIPE_SELECTED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "COPY_RECIPE")
{
string recipeId = json.recipeId;
string newName = json.newName;
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.CopyRecipe(recipeId, newName);
var response = new { type = "RECIPE_COPIED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "DELETE_RECIPE")
{
string recipeId = json.recipeId;
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.DeleteRecipe(recipeId);
var response = new { type = "RECIPE_DELETED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
}
catch (Exception ex)
{