Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/Web/Components/Features/Categories/CategoriesPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@
<Template Context="cat">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
Click="@(() => EditRow(cat))" @onclick:stopPropagation="true" />
<AuthorizeView Policy="Admin">
<AuthorizeView Roles="Admin">
<Authorized>
<RadzenButton Icon="archive" ButtonStyle="ButtonStyle.Danger" Size="ButtonSize.Small"
<RadzenButton id="@($"archive-{cat.Id}")" Icon="archive" ButtonStyle="ButtonStyle.Danger" Size="ButtonSize.Small"
Click="@(() => HandleArchive(cat.Id, cat.CategoryName))" @onclick:stopPropagation="true"
Class="ms-1" />
</Authorized>
Expand All @@ -58,7 +58,12 @@
}
</div>

@if (!string.IsNullOrEmpty(_errorMessage))
{
<div id="archive-error" class="mt-4 text-red-600 text-sm">@_errorMessage</div>
}

<!-- Archive Confirmation Dialog -->
<ConfirmDialog IsVisible="@_showArchiveDialog" Title="Archive Category"
Message="@_archiveConfirmMessage" ConfirmText="Archive"
Message="@_archiveConfirmMessage" ConfirmText="Yes, Archive"
CancelText="Cancel" OnConfirm="HandleArchiveConfirm" OnCancel="HandleArchiveCancel" />
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public partial class CategoriesPage : ComponentBase
private bool _showArchiveDialog = false;
private string? _categoryToArchiveId = null;
private string _archiveConfirmMessage = "";
private string? _errorMessage;

protected override async Task OnInitializedAsync()
{
Expand Down Expand Up @@ -150,6 +151,10 @@ private async Task HandleArchiveConfirm()
_categories = _categories.Where(c => c.Id != _categoryToArchiveId).ToList();
await InvokeAsync(StateHasChanged);
}
else
{
_errorMessage = "Failed to archive the category. Please try again.";
}
_categoryToArchiveId = null;
}

Expand Down
13 changes: 3 additions & 10 deletions src/Web/Components/Features/Statuses/StatusApiClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IStatusApiClient
/// <summary>Updates an existing status.</summary>
Task<StatusDto?> UpdateAsync(string id, UpdateStatusCommand command, CancellationToken cancellationToken = default);

/// <summary>Archives a status by its identifier.</summary>
/// <summary>Archives (soft-deletes) a status by its identifier.</summary>
Task<bool> ArchiveAsync(string id, CancellationToken cancellationToken = default);
}

Expand Down Expand Up @@ -76,15 +76,8 @@ public async Task<IEnumerable<StatusDto>> GetAllAsync(CancellationToken cancella
/// <inheritdoc/>
public async Task<bool> ArchiveAsync(string id, CancellationToken cancellationToken = default)
{
try
{
var response = await _httpClient.DeleteAsync($"/api/v1/statuses/{id}", cancellationToken).ConfigureAwait(false);
return response.IsSuccessStatusCode;
}
catch (HttpRequestException)
{
return false;
}
var response = await _httpClient.DeleteAsync($"/api/v1/statuses/{id}", cancellationToken).ConfigureAwait(false);
return response.IsSuccessStatusCode;
}

}
110 changes: 58 additions & 52 deletions src/Web/Components/Features/Statuses/StatusesPage.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,66 @@
<PageTitle>Statuses — IssueManager</PageTitle>

<div class="max-w-4xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex items-center justify-between mb-6">
<h1 class="page-title">Statuses</h1>
<RadzenButton ButtonStyle="ButtonStyle.Success" Icon="add_circle_outline" Text="Add Status" Click="@InsertRow"
Disabled="@(_insertingStatus != null || _editingStatus != null)" class="px-4 py-2 text-sm" />
<div class="flex items-center justify-between mb-6">
<h1 class="page-title">Statuses</h1>
<RadzenButton ButtonStyle="ButtonStyle.Success" Icon="add_circle_outline" Text="Add Status" Click="@InsertRow"
Disabled="@(_insertingStatus != null || _editingStatus != null)" class="px-4 py-2 text-sm" />
</div>

@if (_isLoading)
{
<div class="loading-state">Loading...</div>
}
else
{
<div class="card-flush">
<RadzenDataGrid @ref="_grid" Data="@_statuses" TItem="StatusEditModel" EditMode="DataGridEditMode.Single"
RowUpdate="@OnUpdateRow" RowCreate="@OnCreateRow" AllowSorting="true" AllowPaging="true" PageSize="10">
<Columns>
<RadzenDataGridColumn TItem="StatusEditModel" Property="StatusName" Title="Status Name" Width="200px">
<EditTemplate Context="status">
<RadzenTextBox @bind-Value="status.StatusName" Style="width:100%" Name="StatusName" />
<RadzenRequiredValidator Component="StatusName" Text="Name is required" Popup="true" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="StatusEditModel" Property="StatusDescription" Title="Description">
<EditTemplate Context="status">
<RadzenTextBox @bind-Value="status.StatusDescription" Style="width:100%" Name="StatusDesc" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="StatusEditModel" Context="status" Filterable="false" Sortable="false"
TextAlign="TextAlign.Right" Width="140px" Title="Actions">
<Template Context="status">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
Click="@(() => EditRow(status))" @onclick:stopPropagation="true" />
<AuthorizeView Roles="Admin">
<RadzenButton id="@($"archive-{status.Id}")" Icon="archive" ButtonStyle="ButtonStyle.Danger"
Size="ButtonSize.Small" Class="ms-1"
Click="@(() => InitiateArchive(status))" @onclick:stopPropagation="true" />
</AuthorizeView>
</Template>
<EditTemplate Context="status">
<RadzenButton Icon="check" ButtonStyle="ButtonStyle.Success" Size="ButtonSize.Small"
Click="@(() => SaveRow(status))" />
<RadzenButton Icon="close" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
Click="@(() => CancelEdit(status))" Class="ms-1" />
</EditTemplate>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
}
</div>

@if (_isLoading)
@if (!string.IsNullOrEmpty(_errorMessage))
{
<div class="loading-state">Loading...</div>
<div id="archive-error" class="mt-4 text-red-600 text-sm">@_errorMessage</div>
}
else
{
<div class="card-flush">
<RadzenDataGrid @ref="_grid" Data="@_statuses" TItem="StatusEditModel" EditMode="DataGridEditMode.Single"
RowUpdate="@OnUpdateRow" RowCreate="@OnCreateRow" AllowSorting="true" AllowPaging="true" PageSize="10">
<Columns>
<RadzenDataGridColumn TItem="StatusEditModel" Property="StatusName" Title="Status Name" Width="200px">
<EditTemplate Context="status">
<RadzenTextBox @bind-Value="status.StatusName" Style="width:100%" Name="StatusName" />
<RadzenRequiredValidator Component="StatusName" Text="Name is required" Popup="true" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="StatusEditModel" Property="StatusDescription" Title="Description">
<EditTemplate Context="status">
<RadzenTextBox @bind-Value="status.StatusDescription" Style="width:100%" Name="StatusDesc" />
</EditTemplate>
</RadzenDataGridColumn>
<RadzenDataGridColumn TItem="StatusEditModel" Context="status" Filterable="false" Sortable="false"
TextAlign="TextAlign.Right" Width="180px" Title="Actions">
<Template Context="status">
<RadzenButton Icon="edit" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
Click="@(() => EditRow(status))" @onclick:stopPropagation="true" />
<AuthorizeView Policy="Admin">
<Authorized>
<RadzenButton Icon="archive" ButtonStyle="ButtonStyle.Danger" Size="ButtonSize.Small"
Click="@(() => ShowArchiveDialog(status.Id, status.StatusName))" @onclick:stopPropagation="true"
Class="ms-1" />
</Authorized>
</AuthorizeView>
</Template>
<EditTemplate Context="status">
<RadzenButton Icon="check" ButtonStyle="ButtonStyle.Success" Size="ButtonSize.Small"
Click="@(() => SaveRow(status))" />
<RadzenButton Icon="close" ButtonStyle="ButtonStyle.Light" Size="ButtonSize.Small"
Click="@(() => CancelEdit(status))" Class="ms-1" />
</EditTemplate>
</RadzenDataGridColumn>
</Columns>
</RadzenDataGrid>
</div>
}
</div>

<!-- Archive Confirmation Dialog -->
<ConfirmDialog IsVisible="@_showArchiveDialog" Title="Archive Status"
Message="@($"Archive '{_statusToArchiveName}'? Issues with this status will need to be reassigned.")"
ConfirmText="Archive" CancelText="Cancel" OnConfirm="HandleArchiveConfirm" OnCancel="HandleArchiveCancel" />
<ConfirmDialog IsVisible="@_showArchiveConfirm"
Title="Archive Status"
Message="Are you sure you want to archive this status? It will be hidden from the list."
ConfirmText="Yes, Archive"
CancelText="Cancel"
OnConfirm="ConfirmArchive"
OnCancel="CancelArchive" />
46 changes: 26 additions & 20 deletions src/Web/Components/Features/Statuses/StatusesPage.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ public partial class StatusesPage : ComponentBase
private StatusEditModel? _editingStatus;
private bool _isLoading = true;

// Archive dialog state
private bool _showArchiveDialog = false;
private string? _statusToArchiveId = null;
private string? _statusToArchiveName = null;
private StatusEditModel? _archiveTarget;

private bool _showArchiveConfirm;

private string? _errorMessage;

protected override async Task OnInitializedAsync()
{
Expand Down Expand Up @@ -108,32 +109,37 @@ private async Task OnUpdateRow(StatusEditModel status)
await StatusClient.UpdateAsync(status.Id, command);
}

private void ShowArchiveDialog(string id, string name)
private void InitiateArchive(StatusEditModel status)
{
_statusToArchiveId = id;
_statusToArchiveName = name;
_showArchiveDialog = true;
_archiveTarget = status;
_showArchiveConfirm = true;
}

private async Task HandleArchiveConfirm()
private async Task ConfirmArchive()
{
_showArchiveDialog = false;
if (string.IsNullOrEmpty(_statusToArchiveId)) return;
_showArchiveConfirm = false;

if (_archiveTarget is null) return;

var success = await StatusClient.ArchiveAsync(_archiveTarget.Id);

var success = await StatusClient.ArchiveAsync(_statusToArchiveId);
if (success)
{
_statuses = _statuses.Where(s => s.Id != _statusToArchiveId).ToList();
await InvokeAsync(StateHasChanged);
_statuses = _statuses.Where(s => s != _archiveTarget).ToList();
if (_grid is not null)
await _grid.Reload();
}
_statusToArchiveId = null;
_statusToArchiveName = null;
else
{
_errorMessage = "Failed to archive the status. Please try again.";
}

_archiveTarget = null;
}

private void HandleArchiveCancel()
private void CancelArchive()
{
_showArchiveDialog = false;
_statusToArchiveId = null;
_statusToArchiveName = null;
_showArchiveConfirm = false;
_archiveTarget = null;
}
}
Loading
Loading