Add software family admin page.

This commit is contained in:
2020-08-08 18:57:22 +01:00
parent f24810e808
commit b118afce1e
14 changed files with 866 additions and 1 deletions

View File

@@ -0,0 +1,116 @@
@{
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2020 Natalia Portillo
*******************************************************************************/
}
@page "/admin/software_families/details/{Id:ulong}"
@page "/admin/software_families/edit/{Id:ulong}"
@page "/admin/software_families/create"
@using Marechai.Database
@using Marechai.Database.Models
@inherits OwningComponentBase<SoftwareFamiliesService>
@inject IStringLocalizer<SoftwareFamiliesService> L
@inject NavigationManager NavigationManager
@inject IWebHostEnvironment Host
@inject IJSRuntime JSRuntime
@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [Authorize(Roles = "UberAdmin, Admin")]
<h3>@L["Software family details"]</h3>
<hr />
@if (!_loaded)
{
<p align="center">@L["Loading..."]</p>
return;
}
<div>
<Field>
<FieldLabel>@L["Name"]</FieldLabel>
<Validation Validator="@ValidateName">
<TextEdit ReadOnly="!_editing" @bind-Text="@_model.Name">
<Feedback>
<ValidationError>@L["Please enter a valid name."]</ValidationError>
</Feedback>
</TextEdit>
</Validation>
</Field>
@if (_editing || _model.Introduced != null)
{
<Field>
<FieldLabel>@L["Introduced"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownIntroduced">@L["Unknown (introduction date)"]</Check>
}
@if (!_editing || !_unknownIntroduced)
{
<Validation Validator="@ValidateIntroduced">
<DateEdit TValue="DateTime?" ReadOnly="!_editing" @bind-Date="@_model.Introduced" >
<Feedback>
<ValidationError>@L["Please enter a valid introduction date."]</ValidationError>
</Feedback>
</DateEdit>
</Validation>
}
</Field>
}
@if (_editing || _model.ParentId != null)
{
<Field>
<FieldLabel>@L["Parent software family"]</FieldLabel>
@if (_editing)
{
<Check TValue="bool" @bind-Checked="@_unknownParent">@L["Unknown or none (parent software family)"]</Check>
}
@if (!_editing ||
!_unknownParent)
{
<Select Disabled="!_editing" TValue="ulong?" @bind-SelectedValue="@_model.ParentId">
@foreach (var family in _softwareFamilies)
{
<SelectItem TValue="ulong?" Value="@family.Id">@family.Name</SelectItem>
}
</Select>
}
</Field>
}
</div>
<div>
@if (!_editing)
{
<Button Color="Color.Primary" Clicked="@OnEditClicked">@L["Edit"]</Button>
}
else
{
<Button Color="Color.Success" Clicked="@OnSaveClicked">@L["Save"]</Button>
<Button Color="Color.Danger" Clicked="@OnCancelClicked">@L["Cancel"]</Button>
}
<a href="/admin/software_families" class="btn btn-secondary">@L["Back to list"]</a>
</div>

View File

@@ -0,0 +1,141 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2020 Natalia Portillo
*******************************************************************************/
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Blazorise;
using Marechai.Shared;
using Marechai.ViewModels;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Authorization;
namespace Marechai.Pages.Admin.Details
{
public partial class SoftwareFamily
{
AuthenticationState _authState;
bool _creating;
bool _editing;
bool _loaded;
SoftwareFamilyViewModel _model;
List<SoftwareFamilyViewModel> _softwareFamilies;
bool _unknownIntroduced;
bool _unknownParent;
[Parameter]
public ulong Id { get; set; }
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(_loaded)
return;
_loaded = true;
_creating = NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
StartsWith("admin/software_families/create",
StringComparison.InvariantCulture);
if(Id <= 0 &&
!_creating)
return;
_softwareFamilies = await Service.GetAsync();
_model = _creating ? new SoftwareFamilyViewModel() : await Service.GetAsync(Id);
_authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
_editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant().
StartsWith("admin/software_families/edit/",
StringComparison.InvariantCulture);
if(_editing)
SetCheckboxes();
StateHasChanged();
}
void SetCheckboxes()
{
_unknownParent = !_model.ParentId.HasValue;
_unknownIntroduced = !_model.Introduced.HasValue;
}
void OnEditClicked()
{
_editing = true;
SetCheckboxes();
StateHasChanged();
}
async void OnCancelClicked()
{
_editing = false;
if(_creating)
{
NavigationManager.ToBaseRelativePath("admin/software_families");
return;
}
_model = await Service.GetAsync(Id);
SetCheckboxes();
StateHasChanged();
}
async void OnSaveClicked()
{
if(_unknownParent)
_model.ParentId = null;
else if(_model.ParentId < 1)
return;
if(_unknownIntroduced)
_model.Introduced = null;
else if(_model.Introduced?.Date >= DateTime.UtcNow.Date)
return;
if(string.IsNullOrWhiteSpace(_model.Name))
return;
if(_creating)
Id = await Service.CreateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id);
else
await Service.UpdateAsync(_model, (await UserManager.GetUserAsync(_authState.User)).Id);
_editing = false;
_creating = false;
_model = await Service.GetAsync(Id);
SetCheckboxes();
StateHasChanged();
}
void ValidateName(ValidatorEventArgs e) =>
Validators.ValidateString(e, L["Name must be smaller than 256 characters."], 256);
void ValidateIntroduced(ValidatorEventArgs e) => Validators.ValidateDate(e);
}
}

View File

@@ -128,3 +128,11 @@
</li>
</ul>
</div>
<div class="content">
<h3>@L["Administrative pages for software"]</h3>
<ul>
<li>
<a href="/admin/software_families">@L["Software families"]</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,98 @@
@{
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2020 Natalia Portillo
*******************************************************************************/
}
@page "/admin/software_families"
@using Marechai.Database.Models
@inherits OwningComponentBase<SoftwareFamiliesService>
@inject IStringLocalizer<SoftwareFamiliesService> L
@inject Microsoft.AspNetCore.Identity.UserManager<ApplicationUser> UserManager
@inject AuthenticationStateProvider AuthenticationStateProvider
@attribute [Authorize(Roles = "UberAdmin, Admin")]
<h3>@L["Software families"]</h3>
@if (_softwareFamilies is null)
{
<p>@L["Loading..."]</p>
return;
}
<p>
<a class="btn btn-primary" href="/admin/software_families/create">@L["Create new"]</a>
</p>
<table class="table table-striped">
<thead>
<tr>
<th>
@L["Name"]
</th>
<th>
@L["Introduced"]
</th>
<th>
@L["Parent"]
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in _softwareFamilies)
{
<tr>
<td>
@item.Name
</td>
<td>
@($"{item.Introduced:d}")
</td>
<td>
@item.Parent
</td>
<td>
<a class="btn btn-primary" href="/admin/software_families/details/@item.Id">@L["Details"]</a>
<a class="btn btn-secondary" href="/admin/software_families/edit/@item.Id">@L["Edit"]</a>
<Button Color="Color.Danger" Clicked="() => {ShowModal(item.Id);}">@L["Delete"]</Button>
</td>
</tr>
}
</tbody>
</table>
<Modal @ref="_frmDelete" IsCentered="true" Closing="@ModalClosing">
<ModalBackdrop/>
<ModalContent Centered="true">
<ModalHeader>
<ModalTitle>@L["Delete software family"]</ModalTitle>
<CloseButton Clicked="@HideModal"/>
</ModalHeader>
<ModalBody>
<Text>@string.Format(@L["Are you sure you want to delete the software family {0}?"], _currentSoftwareFamily?.Name)</Text>
</ModalBody>
<ModalFooter>
<Button Color="Color.Primary" Clicked="@HideModal" Disabled="@_deleteInProgress">@L["Cancel"]</Button>
<Button Color="Color.Danger" Clicked="@ConfirmDelete" Disabled="@_deleteInProgress">@L["Delete"]</Button>
</ModalFooter>
</ModalContent>
</Modal>

View File

@@ -0,0 +1,88 @@
/******************************************************************************
// MARECHAI: Master repository of computing history artifacts information
// ----------------------------------------------------------------------------
//
// Author(s) : Natalia Portillo <claunia@claunia.com>
//
// --[ License ] --------------------------------------------------------------
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// ----------------------------------------------------------------------------
// Copyright © 2003-2020 Natalia Portillo
*******************************************************************************/
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Blazorise;
using Marechai.ViewModels;
using Microsoft.AspNetCore.Components.Authorization;
namespace Marechai.Pages.Admin
{
public partial class SoftwareFamilies
{
SoftwareFamilyViewModel _currentSoftwareFamily;
bool _deleteInProgress;
Modal _frmDelete;
bool _loaded;
List<SoftwareFamilyViewModel> _softwareFamilies;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if(_loaded)
return;
_softwareFamilies = await Service.GetAsync();
_loaded = true;
StateHasChanged();
}
void ShowModal(ulong itemId)
{
_currentSoftwareFamily = _softwareFamilies.FirstOrDefault(n => n.Id == itemId);
_frmDelete.Show();
}
void HideModal() => _frmDelete.Hide();
async void ConfirmDelete()
{
if(_currentSoftwareFamily is null)
return;
_deleteInProgress = true;
_softwareFamilies = null;
AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
// Yield thread to let UI to update
await Task.Yield();
await Service.DeleteAsync(_currentSoftwareFamily.Id, (await UserManager.GetUserAsync(authState.User)).Id);
_softwareFamilies = await Service.GetAsync();
_deleteInProgress = false;
_frmDelete.Hide();
// Yield thread to let UI to update
await Task.Yield();
// Tell we finished loading
StateHasChanged();
}
void ModalClosing(ModalClosingEventArgs obj) => _currentSoftwareFamily = null;
}
}