Added normalization for date dimensions in SqlDashboardStorage to ensure consistent grouping for "AddedWhen" and "ChangedWhen" fields. Refactored CatalogsGrid.razor to use custom sort icons and default DxGrid filter row UI, simplifying markup and improving visual consistency. Updated related CSS for sortable headers and filter inputs.
226 lines
7.3 KiB
Plaintext
226 lines
7.3 KiB
Plaintext
@inject CatalogApiClient Api
|
|
|
|
<style>
|
|
.action-panel { margin-bottom: 16px; }
|
|
.grid-section { margin-top: 12px; }
|
|
</style>
|
|
|
|
@if (!string.IsNullOrWhiteSpace(errorMessage))
|
|
{
|
|
<div class="alert alert-danger" role="alert">@errorMessage</div>
|
|
}
|
|
else if (!string.IsNullOrWhiteSpace(infoMessage))
|
|
{
|
|
<div class="alert alert-success" role="alert">@infoMessage</div>
|
|
}
|
|
|
|
<div class="mb-3">
|
|
<DxButton RenderStyle="ButtonRenderStyle.Primary" Click="@StartCreate">Neuen Eintrag anlegen</DxButton>
|
|
</div>
|
|
|
|
@if (showForm)
|
|
{
|
|
<div class="action-panel">
|
|
<EditForm Model="formModel" OnValidSubmit="HandleSubmit" Context="editCtx">
|
|
<DxFormLayout ColCount="2">
|
|
<DxFormLayoutItem Caption="Titel" Context="itemCtx">
|
|
<DxTextBox @bind-Text="formModel.CatTitle" Enabled="@(isEditing ? formModel.UpdateProcedure != 0 : true)" />
|
|
</DxFormLayoutItem>
|
|
<DxFormLayoutItem Caption="Kennung" Context="itemCtx">
|
|
<DxTextBox @bind-Text="formModel.CatString" />
|
|
</DxFormLayoutItem>
|
|
@if (isEditing)
|
|
{
|
|
<DxFormLayoutItem Caption="Update-Prozedur" Context="itemCtx">
|
|
<DxComboBox Data="@procedureOptions"
|
|
TextFieldName="Text"
|
|
ValueFieldName="Value"
|
|
@bind-Value="formModel.UpdateProcedure" />
|
|
</DxFormLayoutItem>
|
|
}
|
|
<DxFormLayoutItem Caption=" " Context="itemCtx">
|
|
<DxStack Orientation="Orientation.Horizontal" Spacing="8">
|
|
<DxButton RenderStyle="ButtonRenderStyle.Success" ButtonType="ButtonType.Submit" SubmitFormOnClick="true" Context="btnCtx">@((isEditing ? "Speichern" : "Anlegen"))</DxButton>
|
|
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Click="@CancelEdit" Context="btnCtx">Abbrechen</DxButton>
|
|
</DxStack>
|
|
</DxFormLayoutItem>
|
|
</DxFormLayout>
|
|
</EditForm>
|
|
</div>
|
|
}
|
|
|
|
@if (isLoading)
|
|
{
|
|
<p><em>Lade Daten...</em></p>
|
|
}
|
|
else if (items.Count == 0)
|
|
{
|
|
<p>Keine Einträge vorhanden.</p>
|
|
}
|
|
else
|
|
{
|
|
<div class="grid-section">
|
|
<DxGrid Data="@items" TItem="CatalogReadDto" KeyFieldName="@nameof(CatalogReadDto.Guid)" ShowFilterRow="true" PageSize="10" CssClass="mb-4 catalog-grid">
|
|
<Columns>
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.Guid)" Caption="Id" Width="140px" SortIndex="0" SortOrder="GridColumnSortOrder.Ascending" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.CatTitle)" Caption="Titel" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.CatString)" Caption="String" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.AddedWho)" Caption="Angelegt von" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.AddedWhen)" Caption="Angelegt am" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.ChangedWho)" Caption="Geändert von" />
|
|
<DxGridDataColumn FieldName="@nameof(CatalogReadDto.ChangedWhen)" Caption="Geändert am" />
|
|
<DxGridDataColumn Caption="" Width="220px" AllowSort="false">
|
|
<CellDisplayTemplate Context="cell">
|
|
@{ var item = (CatalogReadDto)cell.DataItem; }
|
|
<div style="white-space: nowrap;">
|
|
<DxButton RenderStyle="ButtonRenderStyle.Secondary" Size="ButtonSize.Small" Click="@(() => StartEdit(item))">Bearbeiten</DxButton>
|
|
<DxButton RenderStyle="ButtonRenderStyle.Danger" Size="ButtonSize.Small" Click="@(() => DeleteCatalog(item.Guid))">Löschen</DxButton>
|
|
</div>
|
|
</CellDisplayTemplate>
|
|
</DxGridDataColumn>
|
|
</Columns>
|
|
</DxGrid>
|
|
</div>
|
|
}
|
|
|
|
@code {
|
|
private List<CatalogReadDto> items = new();
|
|
private CatalogWriteDto formModel = new();
|
|
private int editingId;
|
|
private bool isLoading;
|
|
private bool isEditing;
|
|
private bool showForm;
|
|
private string? errorMessage;
|
|
private string? infoMessage;
|
|
|
|
private readonly List<ProcedureOption> procedureOptions = new()
|
|
{
|
|
new() { Value = 0, Text = "PRTBMY_CATALOG_UPDATE" },
|
|
new() { Value = 1, Text = "PRTBMY_CATALOG_SAVE" }
|
|
};
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
await LoadCatalogs();
|
|
}
|
|
|
|
private async Task LoadCatalogs()
|
|
{
|
|
isLoading = true;
|
|
errorMessage = null;
|
|
try
|
|
{
|
|
items = await Api.GetAllAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = $"Kataloge konnten nicht geladen werden: {ex.Message}";
|
|
}
|
|
finally
|
|
{
|
|
isLoading = false;
|
|
StateHasChanged();
|
|
}
|
|
}
|
|
|
|
private void StartCreate()
|
|
{
|
|
formModel = new CatalogWriteDto();
|
|
editingId = 0;
|
|
isEditing = false;
|
|
showForm = true;
|
|
infoMessage = null;
|
|
errorMessage = null;
|
|
}
|
|
|
|
private void StartEdit(CatalogReadDto item)
|
|
{
|
|
formModel = new CatalogWriteDto
|
|
{
|
|
CatTitle = item.CatTitle,
|
|
CatString = item.CatString,
|
|
UpdateProcedure = 0
|
|
};
|
|
editingId = item.Guid;
|
|
isEditing = true;
|
|
showForm = true;
|
|
infoMessage = null;
|
|
errorMessage = null;
|
|
}
|
|
|
|
private async Task HandleSubmit()
|
|
{
|
|
errorMessage = null;
|
|
infoMessage = null;
|
|
|
|
try
|
|
{
|
|
if (isEditing)
|
|
{
|
|
var updated = await Api.UpdateAsync(editingId, formModel);
|
|
if (!updated.Success)
|
|
{
|
|
errorMessage = updated.Error ?? "Aktualisierung fehlgeschlagen.";
|
|
return;
|
|
}
|
|
|
|
infoMessage = "Katalog aktualisiert.";
|
|
}
|
|
else
|
|
{
|
|
var created = await Api.CreateAsync(formModel);
|
|
if (!created.Success || created.Value == null)
|
|
{
|
|
errorMessage = created.Error ?? "Anlegen fehlgeschlagen.";
|
|
return;
|
|
}
|
|
|
|
infoMessage = "Katalog angelegt.";
|
|
}
|
|
|
|
showForm = false;
|
|
await LoadCatalogs();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = $"Fehler beim Speichern: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
private void CancelEdit()
|
|
{
|
|
showForm = false;
|
|
infoMessage = null;
|
|
errorMessage = null;
|
|
}
|
|
|
|
private async Task DeleteCatalog(int id)
|
|
{
|
|
errorMessage = null;
|
|
infoMessage = null;
|
|
|
|
try
|
|
{
|
|
var deleted = await Api.DeleteAsync(id);
|
|
if (!deleted.Success)
|
|
{
|
|
errorMessage = deleted.Error ?? "Löschen fehlgeschlagen.";
|
|
return;
|
|
}
|
|
|
|
infoMessage = "Katalog gelöscht.";
|
|
await LoadCatalogs();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
errorMessage = $"Fehler beim Löschen: {ex.Message}";
|
|
}
|
|
}
|
|
|
|
private sealed class ProcedureOption
|
|
{
|
|
public int Value { get; set; }
|
|
public string Text { get; set; } = string.Empty;
|
|
}
|
|
}
|