diff --git a/Marechai.Database/Models/MarechaiContext.cs b/Marechai.Database/Models/MarechaiContext.cs index d80a8f0a..c57f910c 100644 --- a/Marechai.Database/Models/MarechaiContext.cs +++ b/Marechai.Database/Models/MarechaiContext.cs @@ -120,6 +120,7 @@ namespace Marechai.Database.Models public virtual DbSet MediaFiles { get; set; } public virtual DbSet Dumps { get; set; } public virtual DbSet SoftwareFamilies { get; set; } + public virtual DbSet SoftwareVersions { get; set; } public virtual DbSet SoftwareVariants { get; set; } public virtual DbSet StandaloneFiles { get; set; } public virtual DbSet MasteringTexts { get; set; } @@ -1850,6 +1851,8 @@ namespace Marechai.Database.Models modelBuilder.Entity(entity => { + entity.ToTable("SoftwareVersion"); + entity.HasIndex(e => e.Name); entity.HasIndex(e => e.Introduced); entity.HasIndex(e => e.Codename); diff --git a/Marechai.Database/Models/SoftwareVersion.cs b/Marechai.Database/Models/SoftwareVersion.cs index ea767b35..09964f10 100644 --- a/Marechai.Database/Models/SoftwareVersion.cs +++ b/Marechai.Database/Models/SoftwareVersion.cs @@ -44,5 +44,9 @@ namespace Marechai.Database.Models public virtual ICollection Companies { get; set; } public virtual ICollection People { get; set; } public virtual ICollection Variants { get; set; } + + public ulong FamilyId { get; set; } + public int? LicenseId { get; set; } + public ulong? PreviousId { get; set; } } } \ No newline at end of file diff --git a/Marechai/Marechai.csproj b/Marechai/Marechai.csproj index 7ca719cd..ea6257fa 100644 --- a/Marechai/Marechai.csproj +++ b/Marechai/Marechai.csproj @@ -2,7 +2,7 @@ netcoreapp3.1 - 4.0.0.1811 + 4.0.0.1816 Canary Islands Computer Museum Copyright © 2003-2020 Natalia Portillo Canary Islands Computer Museum Website diff --git a/Marechai/Pages/Admin/Details/SoftwareVersion.razor b/Marechai/Pages/Admin/Details/SoftwareVersion.razor new file mode 100644 index 00000000..efd80de3 --- /dev/null +++ b/Marechai/Pages/Admin/Details/SoftwareVersion.razor @@ -0,0 +1,189 @@ +@{ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/software_versions/details/{Id:ulong}" +@page "/admin/software_versions/edit/{Id:ulong}" +@page "/admin/software_versions/create" +@using Marechai.Database +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject SoftwareFamiliesService SoftwareFamiliesService +@inject LicensesService LicensesService +@inject NavigationManager NavigationManager +@inject IWebHostEnvironment Host +@inject IJSRuntime JSRuntime +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] + + +

@L["Software version details"]

+
+ +@if (!_loaded) +{ +

@L["Loading..."]

+ + return; +} + +
+ + @L["Software family"] + + + + @L["Version"] + + + + @L["Please enter a valid version."] + + + + + @if (_editing || _model.Name != null) + { + + @L["Name, if different from family name"] + @if (_editing) + { + @L["Unknown (name)"] + } + @if (!_editing || + !_unknownName) + { + + + + @L["Please enter a valid name."] + + + + } + + } + @if (_editing || _model.Codename != null) + { + + @L["Codename"] + @if (_editing) + { + @L["Unknown (codename)"] + } + @if (!_editing || + !_unknownCodename) + { + + + + @L["Please enter a valid codename."] + + + + } + + } + @if (_editing || _model.Introduced != null) + { + + @L["Introduced"] + @if (_editing) + { + @L["Unknown (introduction date)"] + } + @if (!_editing || !_unknownIntroduced) + { + + + + @L["Please enter a valid introduction date."] + + + + } + + } + @if (_editing || _model.LicenseId != null) + { + + @L["License"] + @if (_editing) + { + @L["Unknown (license)"] + } + @if (!_editing || + !_unknownLicense) + { + + } + + } + @if (_editing || _model.PreviousId != null) + { + + @L["Previous"] + @if (_editing) + { + @L["Unknown or none (previous version)"] + } + @if (!_editing || + !_unknownPrevious) + { + + } + + } +
+
+ @if (!_editing) + { + + } + else + { + + + } + @L["Back to list"] +
diff --git a/Marechai/Pages/Admin/Details/SoftwareVersion.razor.cs b/Marechai/Pages/Admin/Details/SoftwareVersion.razor.cs new file mode 100644 index 00000000..7b77bca4 --- /dev/null +++ b/Marechai/Pages/Admin/Details/SoftwareVersion.razor.cs @@ -0,0 +1,173 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// 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 SoftwareVersion + { + AuthenticationState _authState; + bool _creating; + bool _editing; + List _licenses; + bool _loaded; + SoftwareVersionViewModel _model; + List _softwareFamilies; + List _softwareVersions; + bool _unknownCodename; + bool _unknownIntroduced; + bool _unknownLicense; + + bool _unknownName; + bool _unknownPrevious; + + [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_versions/create", + StringComparison.InvariantCulture); + + if(Id <= 0 && + !_creating) + return; + + _softwareVersions = await Service.GetAsync(); + _softwareFamilies = await SoftwareFamiliesService.GetAsync(); + _licenses = await LicensesService.GetAsync(); + _model = _creating ? new SoftwareVersionViewModel() : await Service.GetAsync(Id); + _authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + _editing = _creating || NavigationManager.ToBaseRelativePath(NavigationManager.Uri).ToLowerInvariant(). + StartsWith("admin/software_versions/edit/", + StringComparison.InvariantCulture); + + if(_editing) + SetCheckboxes(); + + StateHasChanged(); + } + + void SetCheckboxes() + { + _unknownName = string.IsNullOrWhiteSpace(_model.Name); + _unknownCodename = string.IsNullOrWhiteSpace(_model.Codename); + _unknownLicense = !_model.LicenseId.HasValue; + _unknownIntroduced = !_model.Introduced.HasValue; + _unknownPrevious = !_model.PreviousId.HasValue; + } + + void OnEditClicked() + { + _editing = true; + SetCheckboxes(); + StateHasChanged(); + } + + async void OnCancelClicked() + { + _editing = false; + + if(_creating) + { + NavigationManager.ToBaseRelativePath("admin/software_versions"); + + return; + } + + _model = await Service.GetAsync(Id); + SetCheckboxes(); + StateHasChanged(); + } + + async void OnSaveClicked() + { + if(_unknownName) + _model.Name = null; + else if(string.IsNullOrWhiteSpace(_model.Name)) + return; + + if(_unknownCodename) + _model.Codename = null; + else if(string.IsNullOrWhiteSpace(_model.Codename)) + return; + + if(_unknownLicense) + _model.LicenseId = null; + else if(_model.LicenseId < 1) + return; + + if(_unknownPrevious) + _model.PreviousId = null; + else if(_model.PreviousId < 1) + return; + + if(_unknownIntroduced) + _model.Introduced = null; + else if(_model.Introduced?.Date >= DateTime.UtcNow.Date) + return; + + if(string.IsNullOrWhiteSpace(_model.Version)) + 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 ValidateCodename(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Codename must be smaller than 256 characters."], 256); + + void ValidateVersion(ValidatorEventArgs e) => + Validators.ValidateString(e, L["Version must be smaller than 256 characters."], 256); + + void ValidateIntroduced(ValidatorEventArgs e) => Validators.ValidateDate(e); + } +} \ No newline at end of file diff --git a/Marechai/Pages/Admin/Index.razor b/Marechai/Pages/Admin/Index.razor index 2523756e..4c80d9d2 100644 --- a/Marechai/Pages/Admin/Index.razor +++ b/Marechai/Pages/Admin/Index.razor @@ -134,5 +134,8 @@
  • @L["Software families"]
  • +
  • + @L["Software versions"] +
  • diff --git a/Marechai/Pages/Admin/SoftwareVersions.razor b/Marechai/Pages/Admin/SoftwareVersions.razor new file mode 100644 index 00000000..6aad524e --- /dev/null +++ b/Marechai/Pages/Admin/SoftwareVersions.razor @@ -0,0 +1,110 @@ +@{ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ +} + +@page "/admin/software_versions" +@using Marechai.Database.Models +@inherits OwningComponentBase +@inject IStringLocalizer L +@inject Microsoft.AspNetCore.Identity.UserManager UserManager +@inject AuthenticationStateProvider AuthenticationStateProvider +@attribute [Authorize(Roles = "UberAdmin, Admin")] +

    @L["Software versions"]

    +@if (_softwareVersions is null) +{ +

    @L["Loading..."]

    + + return; +} +

    + @L["Create new"] +

    + + + + + + + + + + + + + @foreach (var item in _softwareVersions) + { + + + + + + + + + } + +
    + @L["Family"] + + @L["Version"] + + @L["Name"] + + @L["Codename"] + + @L["Introduced"] +
    + @item.Family + + @item.Version + + @item.Name + + @item.Codename + + @($"{item.Introduced:d}") + + @L["Details"] + @L["Edit"] + +
    + + + + + + @L["Delete software version"] + + + + @string.Format(@L["Are you sure you want to delete the software version {0}?"], _currentSoftwareVersion?.Name ?? _currentSoftwareVersion?.Version) + + + + + + + diff --git a/Marechai/Pages/Admin/SoftwareVersions.razor.cs b/Marechai/Pages/Admin/SoftwareVersions.razor.cs new file mode 100644 index 00000000..5dcf0083 --- /dev/null +++ b/Marechai/Pages/Admin/SoftwareVersions.razor.cs @@ -0,0 +1,88 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// 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 SoftwareVersions + { + SoftwareVersionViewModel _currentSoftwareVersion; + bool _deleteInProgress; + Modal _frmDelete; + bool _loaded; + List _softwareVersions; + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if(_loaded) + return; + + _softwareVersions = await Service.GetAsync(); + _loaded = true; + StateHasChanged(); + } + + void ShowModal(ulong itemId) + { + _currentSoftwareVersion = _softwareVersions.FirstOrDefault(n => n.Id == itemId); + _frmDelete.Show(); + } + + void HideModal() => _frmDelete.Hide(); + + async void ConfirmDelete() + { + if(_currentSoftwareVersion is null) + return; + + _deleteInProgress = true; + _softwareVersions = null; + AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync(); + + // Yield thread to let UI to update + await Task.Yield(); + + await Service.DeleteAsync(_currentSoftwareVersion.Id, (await UserManager.GetUserAsync(authState.User)).Id); + _softwareVersions = 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) => _currentSoftwareVersion = null; + } +} \ No newline at end of file diff --git a/Marechai/Resources/Services/AdminService.en.resx b/Marechai/Resources/Services/AdminService.en.resx index c8e8a8c5..838eee51 100644 --- a/Marechai/Resources/Services/AdminService.en.resx +++ b/Marechai/Resources/Services/AdminService.en.resx @@ -44,4 +44,7 @@ + + Software versions + \ No newline at end of file diff --git a/Marechai/Resources/Services/AdminService.es.resx b/Marechai/Resources/Services/AdminService.es.resx index 84c7a136..0a98252d 100644 --- a/Marechai/Resources/Services/AdminService.es.resx +++ b/Marechai/Resources/Services/AdminService.es.resx @@ -243,4 +243,7 @@ Familias de software + + Versiones de software + \ No newline at end of file diff --git a/Marechai/Resources/Services/SoftwareVersionsService.en.resx b/Marechai/Resources/Services/SoftwareVersionsService.en.resx new file mode 100644 index 00000000..aced7c94 --- /dev/null +++ b/Marechai/Resources/Services/SoftwareVersionsService.en.resx @@ -0,0 +1,104 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Software versions + + + Loading... + + + Create new + + + Family + + + Version + + + Name + + + Codename + + + Introduced + + + Details + + + Edit + + + Delete + + + Delete software version + + + Are you sure you want to delete the software version {0}? + + + Cancel + + + Software version details + + + Software family + + + Please enter a valid version. + + + Name, if different from family name + + + Unknown + + + Please enter a valid name. + + + Unknown + + + Please enter a valid codename. + + + Unknown + + + Please enter a valid introduction date. + + + License + + + Unknown + + + Previous + + + Unknown or none + + + Save + + + Back to list + + \ No newline at end of file diff --git a/Marechai/Resources/Services/SoftwareVersionsService.es.resx b/Marechai/Resources/Services/SoftwareVersionsService.es.resx new file mode 100644 index 00000000..cd5dfc89 --- /dev/null +++ b/Marechai/Resources/Services/SoftwareVersionsService.es.resx @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Versiones de software + + + Cargando... + + + Crear nueva + + + Familia + + + Versión + + + Nombre + + + Nombre en clave + + + Introducida + + + Detalles + + + Editar + + + Eliminar + + + Eliminar versión de software + + + ¿Estás seguro de eliminar la versión de software {0}? + + + Cancelar + + + Detalles de versión de software + + + Familia de software + + + Por favor introduce una versión válida. + + + Nombre, si es diferente del nombre de la familia + + + Desconocido + + + Por favor introduce un nombre válido. + + + Desconocido + + + Por favor introduce un nombre en clave válido. + + + Desconocida + + + Por favor introduce una fecha de introducción válida. + + + Licencia + + + Desconocida + + + Anterior + + + Desconocida o ninguna + + + Guardar + + + Volver a la lista + + \ No newline at end of file diff --git a/Marechai/Services/Register.cs b/Marechai/Services/Register.cs index f901f67a..e1bc1566 100644 --- a/Marechai/Services/Register.cs +++ b/Marechai/Services/Register.cs @@ -77,6 +77,7 @@ namespace Marechai.Services services.AddScoped(); services.AddScoped(); services.AddScoped(); + services.AddScoped(); } } } \ No newline at end of file diff --git a/Marechai/Services/SoftwareVersionsService.cs b/Marechai/Services/SoftwareVersionsService.cs new file mode 100644 index 00000000..2491e9b8 --- /dev/null +++ b/Marechai/Services/SoftwareVersionsService.cs @@ -0,0 +1,125 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Marechai.Database.Models; +using Marechai.ViewModels; +using Microsoft.EntityFrameworkCore; + +namespace Marechai.Services +{ + public class SoftwareVersionsService + { + readonly MarechaiContext _context; + + public SoftwareVersionsService(MarechaiContext context) => _context = context; + + public async Task> GetAsync() => await _context. + SoftwareVersions. + OrderBy(b => b.Family.Name). + ThenBy(b => b.Version). + ThenBy(b => b.Introduced). + Select(b => new SoftwareVersionViewModel + { + Id = b.Id, + Family = b.Family.Name, + Name = b.Name, + Codename = b.Codename, + Version = b.Version, + Introduced = b.Introduced, + Previous = b.Previous.Name, + License = b.License.Name, + FamilyId = b.FamilyId, + LicenseId = b.LicenseId, + PreviousId = b.PreviousId + }).ToListAsync(); + + public async Task GetAsync(ulong id) => + await _context.SoftwareVersions.Where(b => b.Id == id).Select(b => new SoftwareVersionViewModel + { + Id = b.Id, + Family = b.Family.Name, + Name = b.Name, + Codename = b.Codename, + Version = b.Version, + Introduced = b.Introduced, + Previous = b.Previous.Name, + License = b.License.Name, + FamilyId = b.FamilyId, + LicenseId = b.LicenseId, + PreviousId = b.PreviousId + }).FirstOrDefaultAsync(); + + public async Task UpdateAsync(SoftwareVersionViewModel viewModel, string userId) + { + SoftwareVersion model = await _context.SoftwareVersions.FindAsync(viewModel.Id); + + if(model is null) + return; + + model.Name = viewModel.Name; + model.Codename = viewModel.Codename; + model.Version = viewModel.Version; + model.Introduced = viewModel.Introduced; + model.FamilyId = viewModel.FamilyId; + model.LicenseId = viewModel.LicenseId; + model.PreviousId = viewModel.PreviousId; + await _context.SaveChangesWithUserAsync(userId); + } + + public async Task CreateAsync(SoftwareVersionViewModel viewModel, string userId) + { + var model = new SoftwareVersion + { + Name = viewModel.Name, + Codename = viewModel.Codename, + Version = viewModel.Version, + Introduced = viewModel.Introduced, + FamilyId = viewModel.FamilyId, + LicenseId = viewModel.LicenseId, + PreviousId = viewModel.PreviousId + }; + + await _context.SoftwareVersions.AddAsync(model); + await _context.SaveChangesWithUserAsync(userId); + + return model.Id; + } + + public async Task DeleteAsync(ulong id, string userId) + { + SoftwareVersion item = await _context.SoftwareVersions.FindAsync(id); + + if(item is null) + return; + + _context.SoftwareVersions.Remove(item); + + await _context.SaveChangesWithUserAsync(userId); + } + } +} \ No newline at end of file diff --git a/Marechai/ViewModels/SoftwareVersionViewModel.cs b/Marechai/ViewModels/SoftwareVersionViewModel.cs new file mode 100644 index 00000000..5db6b4dd --- /dev/null +++ b/Marechai/ViewModels/SoftwareVersionViewModel.cs @@ -0,0 +1,43 @@ +/****************************************************************************** +// MARECHAI: Master repository of computing history artifacts information +// ---------------------------------------------------------------------------- +// +// Author(s) : Natalia Portillo +// +// --[ 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 . +// +// ---------------------------------------------------------------------------- +// Copyright © 2003-2020 Natalia Portillo +*******************************************************************************/ + +using System; + +namespace Marechai.ViewModels +{ + public class SoftwareVersionViewModel : BaseViewModel + { + public string Family { get; set; } + public string Name { get; set; } + public string Codename { get; set; } + public string Version { get; set; } + public DateTime? Introduced { get; set; } + public string Previous { get; set; } + public string License { get; set; } + public ulong FamilyId { get; set; } + public int? LicenseId { get; set; } + public ulong? PreviousId { get; set; } + } +} \ No newline at end of file