fix(auth): C3 review — surface seam not-found (no silent success), partial-reconcile-failure guidance, create validation order, concurrent-edit reconciler test

This commit is contained in:
Joseph Doherty
2026-06-02 04:46:32 -04:00
parent 107e524914
commit d1191fddf9
4 changed files with 68 additions and 7 deletions
@@ -170,6 +170,12 @@
{
_formError = null;
if (!IsEditMode && string.IsNullOrWhiteSpace(_formName))
{
_formError = "Name is required.";
return;
}
// The seam/server reject empty scope sets; validate in the UI for a clear message.
if (_selectedMethodNames.Count == 0)
{
@@ -182,13 +188,16 @@
if (_editingKey != null)
{
// Edit: name is fixed; only the method-scope set is mutable.
await ApiKeyAdmin.SetMethodsAsync(_editingKey.KeyId, _selectedMethodNames.ToList());
var ok = await ApiKeyAdmin.SetMethodsAsync(_editingKey.KeyId, _selectedMethodNames.ToList());
if (!ok)
{
_formError = $"API key '{_editingKey.Name}' was not found. Reload and retry.";
return;
}
NavigationManager.NavigateTo("/admin/api-keys");
}
else
{
if (string.IsNullOrWhiteSpace(_formName)) { _formError = "Name is required."; return; }
var created = await ApiKeyAdmin.CreateAsync(_formName.Trim(), _selectedMethodNames.ToList());
_newlyCreatedKeyId = created.KeyId;
_newlyCreatedToken = created.Token; // shown once; never persisted client-side.
@@ -146,7 +146,13 @@
{
var newEnabled = !key.Enabled;
// The seam persists; there is no separate SaveChangesAsync.
await ApiKeyAdmin.SetEnabledAsync(key.KeyId, newEnabled);
var ok = await ApiKeyAdmin.SetEnabledAsync(key.KeyId, newEnabled);
if (!ok)
{
_toast.ShowError($"API key '{key.Name}' was not found — it may have been removed. Refreshing.");
await LoadDataAsync();
return;
}
_toast.ShowSuccess($"API key '{key.Name}' {(newEnabled ? "enabled" : "disabled")}.");
await LoadDataAsync();
}
@@ -166,7 +172,13 @@
try
{
await ApiKeyAdmin.DeleteAsync(key.KeyId);
var ok = await ApiKeyAdmin.DeleteAsync(key.KeyId);
if (!ok)
{
_toast.ShowError($"API key '{key.Name}' was not found — it may have been removed. Refreshing.");
await LoadDataAsync();
return;
}
_toast.ShowSuccess($"API key '{key.Name}' deleted.");
await LoadDataAsync();
}