Got the new ui flow working and the models updated. Need to get changes written to the database.

This commit is contained in:
Vincent Allen
2025-08-11 10:02:45 -04:00
parent a28663441e
commit dd3968f6ef
456 changed files with 17237 additions and 3851 deletions

View File

@@ -0,0 +1,216 @@
@page "/add"
@using OpenArchival.Blazor.Components.CustomComponents;
@using OpenArchival.Blazor.Components.Pages.Administration.Categories
@using OpenArchival.DataAccess;
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
<MudText Typo="Typo.h5" Color="Color.Primary">Add an Archive Item</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
@if (!IsValid && _isFormDivVisible)
{
<MudAlert Severity="Severity.Error" Class="mt-4">
All identifier fields must be filled in.
</MudAlert>
}
<MudGrid Justify="Justify.Center" Class="pt-4">
<MudItem>
<MudAutocomplete T="string" Label="Category" @bind-Value="Model.Category" @bind-Value:after=OnCategoryChanged SearchFunc="SearchCategory" CoerceValue=false CoerceText=false/>
</MudItem>
<MudItem>
<MudFab Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" OnClick="OnAddCategoryClicked"/>
</MudItem>
</MudGrid>
</MudPaper>
<div @ref="_formDiv" style="@_formDivStyle">
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Archive Item Identifier</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<IdentifierTextBox @ref="_identifierTextBox" IdentifierFields="@Model.IdentifierFields"></IdentifierTextBox>
</MudPaper>
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
<UploadDropBox FilesUploaded="OnFilesUploaded" ClearClicked="OnClearFilesClicked"></UploadDropBox>
</MudPaper>
@foreach (FilePathListing listing in _filePathListings)
{
<ArchiveEntryCreatorCard FilePath="listing" OnValueChanged="OnChanged"></ArchiveEntryCreatorCard>
}
</div>
<MudGrid Justify="Justify.FlexEnd" Class="pt-6">
<MudItem>
<MudCheckBox Label="Publicly Visible" T="bool"></MudCheckBox>
@*<MudCheckBox Label="Publicly Visible" T="bool" @bind-Value=Model.IsPublic></MudCheckBox>*@
</MudItem>
<MudItem Style="pr-0">
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="ml-4" OnClick="CancelClicked">Cancel</MudButton>
</MudItem>
<MudItem Style="pl-2">
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="ml-4" OnClick="PublishClicked">Publish</MudButton>
</MudItem>
</MudGrid>
@using System.ComponentModel.DataAnnotations
@inject IDialogService DialogService
@inject NavigationManager NavigationManager;
@inject IArchiveCategoryProvider CategoryProvider;
@code {
private IdentifierTextBox _identifierTextBox = default!;
private ElementReference _formDiv = default!;
private bool _isFormDivVisible = false;
private string _formDivStyle => _isFormDivVisible ? "" : "display: none;";
public List<string> DatesData { get; set; } = [];
public List<ArchiveCategory> Categories { get; set; } = new();
private List<FilePathListing> _filePathListings = new();
private bool _categorySelected = false;
//public List<IdentifierFieldValidationModel> IdentifierFields { get; set; } = [new IdentifierFieldValidationModel() { Name = "Field One", Value = "" }, new IdentifierFieldValidationModel() { Name = "Field Two", Value = "" }, new IdentifierFieldValidationModel() { Name = "Field Three", Value = "" }];
public ArchiveItemValidationModel Model { get; set; } = new();
public bool IsValid { get; set; } = false;
/// <summary>
/// The URI to navigate to if cancel is pressed
/// </summary>
public string? BackLink { get; set; } = "/";
public string? ForwardLink { get; set; } = "/";
private void CancelClicked(MouseEventArgs args)
{
if (BackLink is not null) {
NavigationManager.NavigateTo(BackLink);
}
else
{
throw new ArgumentNullException("No back link provided for the add archive item page.");
}
}
private async Task OnFilesUploaded(List<FilePathListing> args)
{
_filePathListings = args;
StateHasChanged();
await OnChanged();
}
private async Task OnClearFilesClicked()
{
_filePathListings = [];
StateHasChanged();
await OnChanged();
}
private void PublishClicked(MouseEventArgs args)
{
var validationContext = new ValidationContext(Model);
var validationResult = new List<ValidationResult>();
IsValid = Validator.TryValidateObject(Model, validationContext, validationResult);
/*
if (ForwardLink is not null)
{
if (IsValid)
{
NavigationManager.NavigateTo(ForwardLink);
}
else
{
StateHasChanged();
}
}
else
{
throw new ArgumentNullException("No forward link provided for the add archive item page.");
}
// TODO: assign parents to all file path listings
throw new NotImplementedException();
*/
}
async Task OnChanged()
{
var validationContext = new ValidationContext(Model);
var validationResult = new List<ValidationResult>();
IsValid = Validator.TryValidateObject(Model, validationContext, validationResult);
}
async Task OnCategoryChanged()
{
List<ArchiveCategory>? newCategory = await CategoryProvider.GetArchiveCategory(Model.Category);
if (newCategory.Count != 1)
{
throw new ArgumentException(nameof(Model.Category), $"Got {newCategory.Count} rows for category name={Model.Category}");
}
if (newCategory is not null)
{
_identifierTextBox.VerifyFormatCategory = newCategory[0];
_isFormDivVisible = true;
StateHasChanged();
}
if (!_categorySelected)
{
_categorySelected = true;
StateHasChanged();
}
await OnChanged();
}
public async Task OnAddCategoryClicked()
{
var options = new DialogOptions { CloseOnEscapeKey = true, BackdropClick = false };
var dialog = await DialogService.ShowAsync<CategoryCreatorDialog>("Create a Category", options);
var result = await dialog.Result;
if (result is not null && !result.Canceled)
{
await CategoryProvider.CreateCategoryAsync(CategoryValidationModel.ToArchiveCategory((CategoryValidationModel)result.Data));
StateHasChanged();
await OnChanged();
}
}
private async Task<IEnumerable<string>> SearchCategory(string value, CancellationToken cancellationToken)
{
List<ArchiveCategory> categories;
if (string.IsNullOrEmpty(value))
{
categories = new(await CategoryProvider.Top(25) ?? []);
}
else
{
categories = new((await CategoryProvider.Search(value) ?? []));
}
List<string> categoryStrings = [];
foreach (var category in categories)
{
categoryStrings.Add(category.Name);
}
return categoryStrings;
}
}

View File

@@ -1,308 +0,0 @@
@page "/add"
@using OpenArchival.Blazor.Components.CustomComponents;
@using OpenArchival.Blazor.Components.Pages.Administration.Categories
@using OpenArchival.Core
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
<MudText Typo="Typo.h5" Color="Color.Primary">Add an Archive Item</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
@if (!IsValid && _isFormDivVisible)
{
<MudAlert Severity="Severity.Error" Class="mt-4">
All identifier fields must be filled in.
</MudAlert>
}
@* Archive item category *@
<MudGrid Justify="Justify.Center" Class="pt-4">
<MudItem>
<MudAutocomplete T="string" Label="Category" @bind-Value="Model.Category" @bind-Value:after=OnCategoryChanged SearchFunc="SearchCategory" CoerceValue=false CoerceText=false/>
</MudItem>
<MudItem>
<MudFab Color="Color.Primary" StartIcon="@Icons.Material.Filled.Add" OnClick="OnAddCategoryClicked"/>
</MudItem>
</MudGrid>
<div @ref="_formDiv" style="@_formDivStyle">
@* ID Creation *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Archive Item Identifier</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<IdentifierTextBox @ref="_identifierTextBox" IdentifierFields="@Model.IdentifierFields"></IdentifierTextBox>
@* Title *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Archive Item Title</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudTextField Required=true Placeholder="Archive Item Title" T="string" Class="pl-4 pr-4" @bind-Value=Model.Title @bind-Value:after=OnChanged></MudTextField>
@* Description *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Item Description</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudTextField Lines=8 Placeholder="Description" T="string" Class="pl-4 pr-4" @bind-Value=Model.Description @bind-Value:after=OnChanged></MudTextField>
@* Storage Location *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Storage Location</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudAutocomplete T="string" Label="Storage Location" Class="pt-0 mt-0 pl-2 pr-2" @bind-Value=Model.StorageLocation @bind-Value:after=OnChanged CoerceText=false CoerceValue=false></MudAutocomplete>
@* Artifact Type *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Artifact Type</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudAutocomplete T="string" Label="Artifact Type" Class="pt-0 mt-0 pl-2 pr-2" @bind-Value=Model.ArtifactType @bind-Value:after=OnChanged SearchFunc="SearchItemTypes"></MudAutocomplete>
@* Tags *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Tags</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipTagInput @bind-Items=Model.Tags OnChanged="OnChanged" AutocompleteSearchFunc="SearchTags" InputType="ChipTagInput.ChipTagInputType.AutoComplete" Placeholder="Add tags..."></ChipTagInput>
@* Names *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Listed Names</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipTagInput @bind-Items=Model.AssociatedNames OnChanged="OnChanged" AutocompleteSearchFunc="SearchListedNames" InputType="ChipTagInput.ChipTagInputType.AutoComplete" Placeholder="Add names..."></ChipTagInput>
@* Associated Dates *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Associated Dates</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipTagInput @bind-Items=DatesData OnChanged="OnChanged"></ChipTagInput>
@* Defects *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Defects</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipTagInput @bind-Items=Model.Defects OnChanged="OnChanged" AutocompleteSearchFunc="SearchDefects" InputType="ChipTagInput.ChipTagInputType.AutoComplete" Placeholder="Add defects..."></ChipTagInput>
@* Related Artifacts *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Related Artifacts</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipTagInput @bind-Items=Model.RelatedArtifacts OnChanged="OnChanged"></ChipTagInput>
@* Files *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Artifact Documents</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<UploadDropBox></UploadDropBox>
@* Submit Buttons *@
<MudGrid Justify="Justify.FlexEnd" Class="pt-6">
<MudItem>
<MudCheckBox Label="Publicly Visible" T="bool" @bind-Value=Model.IsPublic></MudCheckBox>
</MudItem>
<MudItem>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="ml-4" OnClick="CancelClicked">Cancel</MudButton>
</MudItem>
<MudItem>
<MudButton Color="Color.Primary" Variant="Variant.Filled" Class="ml-4" OnClick="PublishClicked">Publish</MudButton>
</MudItem>
</MudGrid>
</div>
</MudPaper>
@using OpenArchival.Database
@using System.ComponentModel.DataAnnotations
@inject IDialogService DialogService
@inject ICategoryProvider CategoryProvider
@inject IArchiveStorageLocationProvider StorageLocationProvider
@inject IArtifactTypesProvider ArtifactTypesProvider
@inject ITagsProvider TagsProvider;
@inject IArtifactAssociatedNamesProvider AssociatedNamesProvider;
@inject IDefectsProvider DefectsProvider;
@inject NavigationManager NavigationManager;
@code {
private IdentifierTextBox _identifierTextBox = default!;
private ElementReference _formDiv = default!;
private bool _isFormDivVisible = false;
private string _formDivStyle => _isFormDivVisible ? "" : "display: none;";
public List<string> DatesData { get; set; } = [];
public List<Category> Categories { get; set; } = new();
private bool _categorySelected = false;
//public List<IdentifierFieldValidationModel> IdentifierFields { get; set; } = [new IdentifierFieldValidationModel() { Name = "Field One", Value = "" }, new IdentifierFieldValidationModel() { Name = "Field Two", Value = "" }, new IdentifierFieldValidationModel() { Name = "Field Three", Value = "" }];
public ArchiveItemValidationModel Model { get; set; } = new();
public bool IsValid { get; set; } = false;
/// <summary>
/// The URI to navigate to if cancel is pressed
/// </summary>
public string? BackLink { get; set; } = "/";
public string? ForwardLink { get; set; } = "/";
private void CancelClicked(MouseEventArgs args)
{
if (BackLink is not null) {
NavigationManager.NavigateTo(BackLink);
}
else
{
throw new ArgumentNullException("No back link provided for the add archive item page.");
}
}
private void PublishClicked(MouseEventArgs args)
{
var validationContext = new ValidationContext(Model);
var validationResult = new List<ValidationResult>();
IsValid = Validator.TryValidateObject(Model, validationContext, validationResult);
if (ForwardLink is not null)
{
if (IsValid)
{
NavigationManager.NavigateTo(ForwardLink);
}
else
{
StateHasChanged();
}
}
else
{
throw new ArgumentNullException("No forward link provided for the add archive item page.");
}
throw new NotImplementedException();
}
void OnChanged()
{
var validationContext = new ValidationContext(Model);
var validationResult = new List<ValidationResult>();
IsValid = Validator.TryValidateObject(Model, validationContext, validationResult);
}
async Task OnCategoryChanged()
{
Category? newCategory = await CategoryProvider.GetCategoryAsync(Model.Category);
if (newCategory is not null)
{
_identifierTextBox.VerifyFormatCategory = newCategory;
_isFormDivVisible = true;
}
if (!_categorySelected)
{
_categorySelected = true;
StateHasChanged();
}
OnChanged();
}
public async Task OnAddCategoryClicked()
{
var options = new DialogOptions { CloseOnEscapeKey = true, BackdropClick = false };
var dialog = await DialogService.ShowAsync<CategoryCreatorDialog>("Create a Category", options);
var result = await dialog.Result;
if (result is not null && !result.Canceled)
{
StateHasChanged();
}
}
private async Task<IEnumerable<string>> SearchDefects(string value, CancellationToken cancellationToken)
{
List<string> defects;
if (string.IsNullOrEmpty(value))
{
defects = new(await DefectsProvider.TopDefects(25));
}
else
{
defects = new(await DefectsProvider.SearchDefects(value));
}
return defects;
}
private async Task<IEnumerable<string>> SearchListedNames(string value, CancellationToken cancellationToken)
{
List<string> names;
if (string.IsNullOrEmpty(value))
{
names = new(await AssociatedNamesProvider.TopNames(25));
}
else
{
names = new(await AssociatedNamesProvider.SearchNames(value));
}
return names;
}
private async Task<IEnumerable<string>> SearchTags(string value, CancellationToken cancellationToken)
{
List<string> tags;
if (string.IsNullOrEmpty(value))
{
tags = new(await TagsProvider.TopTags(25));
}
else
{
tags = new(await TagsProvider.SearchTags(value));
}
return tags;
}
private async Task<IEnumerable<string>> SearchItemTypes(string value, CancellationToken cancellationToken)
{
List<string> itemTypes;
if (string.IsNullOrEmpty(value))
{
itemTypes = new(await ArtifactTypesProvider.TopTypes(25));
}
else
{
itemTypes = new(await ArtifactTypesProvider.SearchTypes(value));
}
return itemTypes;
}
private async Task<IEnumerable<string>> SearchStorageLocation(string value, CancellationToken cancellationToken)
{
List<string> storageLocations;
if (string.IsNullOrEmpty(value))
{
storageLocations = new(await StorageLocationProvider.TopLocations(25));
}
else
{
storageLocations = new(await StorageLocationProvider.SearchLocations(value));
}
return storageLocations;
}
private async Task<IEnumerable<string>> SearchCategory(string value, CancellationToken cancellationToken)
{
List<Category> categories;
if (string.IsNullOrEmpty(value))
{
categories = new(await CategoryProvider.TopCategories(25));
}
else
{
categories = new(await CategoryProvider.SearchCategories(value));
}
List<string> categoryStrings = [];
foreach (var category in categories)
{
categoryStrings.Add(category.CategoryName);
}
return categoryStrings;
}
}

View File

@@ -0,0 +1,289 @@
@using OpenArchival.Blazor.Components.CustomComponents;
<MudPaper Class="pa-4 ma-2 rounded" Elevation="3">
<h3>@FilePath.OriginalName</h3>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Archive Item Title</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudTextField Required=true Placeholder="Archive Item Title" T="string" Class="pl-4 pr-4" @bind-Value=Model.Title @bind-Value:after=OnInputsChanged></MudTextField>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Item Description</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudTextField Lines=8 Placeholder="Description" T="string" Class="pl-4 pr-4" @bind-Value=Model.Description @bind-Value:after=OnInputsChanged></MudTextField>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Storage Location</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudAutocomplete T="string" Label="Storage Location" Class="pt-0 mt-0 pl-2 pr-2" @bind-Value=Model.StorageLocation @bind-Value:after=OnInputsChanged SearchFunc="SearchStorageLocation" CoerceValue=true></MudAutocomplete>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Artifact Type</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudAutocomplete T="string" Label="Artifact Type" Class="pt-0 mt-0 pl-2 pr-2" @bind-Value=Model.ArtifactType @bind-Value:after=OnInputsChanged SearchFunc="SearchItemTypes" CoerceValue=true></MudAutocomplete>
@* Tags entry *@
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Tags</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipContainer T="string" @ref="@_tagsChipContainer" @bind-Items="Model.Tags">
<InputContent>
<MudAutocomplete
T="string"
OnInternalInputChanged="OnInputsChanged"
SearchFunc="SearchTags"
Value="_tagsInputValue"
ValueChanged="OnTagsInputTextChanged"
OnKeyDown="@(ev => HandleChipContainerEnter<string>(ev, _tagsChipContainer, _tagsInputValue, () => _tagsInputValue = string.Empty))"
CoerceValue=true
Placeholder="Add Tags..."
ShowProgressIndicator="true">
</MudAutocomplete>
</InputContent>
</ChipContainer>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Listed Names</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="pb-2">Enter any names of the people associated with this entry.</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipContainer T="string" @ref=_listedNamesChipContainer>
<InputContent>
<MudAutocomplete
T="string"
SearchFunc="SearchListedNames"
OnInternalInputChanged="OnInputsChanged"
Value="_listedNamesInputValue"
ValueChanged="OnListedNamesTextChanged"
OnKeyDown="@(ev=>HandleChipContainerEnter<string>(ev, _listedNamesChipContainer, _listedNamesInputValue, () => _listedNamesInputValue = string.Empty))"
CoerceValue=true
Placeholder="Add Listed Names..."
ShowProgressIndicator=true>
</MudAutocomplete>
</InputContent>
</ChipContainer>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Associated Dates</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipContainer T="DateTime" @ref="_assocaitedDatesChipContainer" DisplayFunc="date=>date.ToShortDateString()">
<InputContent>
<MudDatePicker @bind-Date=_associatedDateInputValue>
</MudDatePicker>
</InputContent>
<SubmitButton>
<MudButton
Color="Color.Primary"
OnClick="HandleAssociatedDateChipContainerAdd">+</MudButton>
</SubmitButton>
</ChipContainer>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Defects</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipContainer T="string" @ref=_defectsChipContainer>
<InputContent>
<MudAutocomplete
T="string"
SearchFunc="SearchDefects"
OnInternalInputChanged="OnInputsChanged"
Value="_defectsInputValue"
ValueChanged="OnDefectsValueChanged"
OnKeyDown="@(ev=>HandleChipContainerEnter<string>(ev, _defectsChipContainer, _defectsInputValue, () => _defectsInputValue = string.Empty))"
CoerceValue=true
Placeholder="Add Defects..."
ShowProgressIndicator=true>
</MudAutocomplete>
</InputContent>
</ChipContainer>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Related Artifacts</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="pb-2">Tag this entry with the identifier of any other entry to link them.</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<ChipContainer T="ArtifactGrouping" @ref="_assocaitedArtifactsChipContainer" DisplayFunc="artifact => artifact.ArtifactGroupingIdentifier">
<InputContent>
<MudAutocomplete
T="ArtifactGrouping"
OnInternalInputChanged="OnInputsChanged"
Value="_associatedArtifactValue"
ValueChanged="OnAssociatedArtifactChanged"
OnKeyDown="@(EventArgs=>HandleChipContainerEnter<ArtifactGrouping>(EventArgs, _assocaitedArtifactsChipContainer, _associatedArtifactValue, () => _associatedArtifactValue = null))"
CoerceValue="false"
Placeholder="Link artifact groupings..."
ShowProgressIndicator=true>
</MudAutocomplete>
</InputContent>
</ChipContainer>
<MudText Typo="Typo.h6" Color="Color.Primary" Class="pt-4 pb-0">Artifact Text Contents</MudText>
<MudText Typo="Typo.caption" Color="Color.Secondary" Class="pb-2">Input the text transcription of the words on the artifact if applicable to aid the search engine.</MudText>
<MudDivider DividerType="DividerType.Middle"></MudDivider>
<MudTextField T="string" Value=_artifactTextContent ValueChanged="OnArtifactTextContentChanged"></MudTextField>
</MudPaper>
@inject IArtifactDefectProvider DefectsProvider;
@inject IArtifactStorageLocationProvider StorageLocationProvider;
@inject IArchiveEntryTagProvider TagsProvider;
@inject IArtifactTypeProvider TypesProvider;
@inject IListedNameProvider ListedNameProvider;
@code {
[Parameter]
public required FilePathListing FilePath { get; set; }
[Parameter]
public EventCallback OnValueChanged { get; set; }
[Parameter]
public required ArtifactEntryValidationModel Model { get; set; } = new(){StorageLocation="hello", Title="Hello"};
private ChipContainer<string> _tagsChipContainer;
private string _tagsInputValue { get; set; } = "";
private ChipContainer<DateTime> _assocaitedDatesChipContainer;
private DateTime? _associatedDateInputValue { get; set; } = default;
private ChipContainer<string> _listedNamesChipContainer;
private string _listedNamesInputValue { get; set; } = "";
private ChipContainer<string> _defectsChipContainer;
private string _defectsInputValue = "";
private ChipContainer<ArtifactGrouping> _assocaitedArtifactsChipContainer;
private ArtifactGrouping? _associatedArtifactValue = null;
private string _artifactTextContent = "";
public Task OnInputsChanged()
{
return OnValueChanged.InvokeAsync();
}
private Task OnDefectsValueChanged(string text)
{
_defectsInputValue = text;
return OnValueChanged.InvokeAsync();
}
private Task OnTagsInputTextChanged(string text)
{
_tagsInputValue = text;
return OnValueChanged.InvokeAsync();
}
private Task OnListedNamesTextChanged(string text)
{
_listedNamesInputValue = text;
return OnValueChanged.InvokeAsync();
}
private Task OnAssociatedArtifactChanged(ArtifactGrouping grouping)
{
if (grouping is not null)
{
_associatedArtifactValue = grouping;
return OnValueChanged.InvokeAsync();
}
return OnValueChanged.InvokeAsync();
}
private Task OnArtifactTextContentChanged(string value)
{
return OnValueChanged.InvokeAsync();
}
public async Task HandleChipContainerEnter<Type>(KeyboardEventArgs args, ChipContainer<Type> container, Type value, Action resetInputAction)
{
if (args.Key == "Enter")
{
await container.AddItem(value);
resetInputAction?.Invoke();
StateHasChanged();
await OnValueChanged.InvokeAsync();
}
}
public async Task HandleAssociatedDateChipContainerAdd(MouseEventArgs args)
{
if (_associatedDateInputValue is not null)
{
await _assocaitedDatesChipContainer.AddItem((DateTime)_associatedDateInputValue);
_associatedDateInputValue = default;
}
}
private async Task<IEnumerable<string>> SearchDefects(string value, CancellationToken cancellationToken)
{
List<string> defects;
if (string.IsNullOrEmpty(value))
{
defects = new((await DefectsProvider.Top(25) ?? []).Select(prop => prop.Description));
}
else
{
defects = new((await DefectsProvider.Search(value) ?? []).Select(prop => prop.Description));
}
return defects;
}
private async Task<IEnumerable<string>> SearchStorageLocation(string value, CancellationToken cancellationToken)
{
List<string> storageLocations;
if (string.IsNullOrEmpty(value))
{
storageLocations = new((await StorageLocationProvider.Top(25) ?? []).Select(prop => prop.Location));
}
else
{
storageLocations = new((await StorageLocationProvider.Search(value) ?? []).Select(prop => prop.Location));
}
return storageLocations;
}
private async Task<IEnumerable<string>> SearchTags(string value, CancellationToken cancellationToken)
{
List<string> tags;
if (string.IsNullOrEmpty(value))
{
tags = new((await TagsProvider.Top(25) ?? []).Select(prop => prop.Name));
}
else
{
tags = new((await TagsProvider.Search(value) ?? []).Select(prop => prop.Name));
}
return tags;
}
private async Task<IEnumerable<string>> SearchItemTypes(string value, CancellationToken cancellationToken)
{
List<string> itemTypes;
if (string.IsNullOrEmpty(value))
{
itemTypes = new((await TypesProvider.Top(25) ?? []).Select(prop => prop.Name));
}
else
{
itemTypes = new((await TypesProvider.Search(value) ?? []).Select(prop => prop.Name));
}
return itemTypes;
}
private async Task<IEnumerable<string>> SearchListedNames(string value, CancellationToken cancellationToken)
{
List<string> names;
if (string.IsNullOrEmpty(value))
{
names = new((await ListedNameProvider.Top(25) ?? []).Select(prop=>$"{prop.FirstName} {prop.LastName}"));
}
else
{
names = new((await ListedNameProvider.Search(value) ?? []).Select(prop=>$"{prop.FirstName} {prop.LastName}"));
}
return names;
}
}

View File

@@ -17,7 +17,7 @@
<MudItem Class="pt-6">
<MudTextField Label="@field.Name"
@bind-Value="field.Value"
@bind-Value="@field.Value"
@bind-Value:after="OnInputChanged"
DebounceInterval="100"
Required=true/>
@@ -32,8 +32,8 @@
}
</MudGrid>
@using OpenArchival.Database;
@inject ICategoryProvider CategoryProvider;
@using OpenArchival.DataAccess;
@inject IArchiveCategoryProvider CategoryProvider;
@code {
[Parameter]
@@ -50,8 +50,8 @@
[Parameter]
public EventCallback<string> ValueChanged { get; set; }
private Category _verifyFormatCategory;
public Category? VerifyFormatCategory
private ArchiveCategory _verifyFormatCategory;
public ArchiveCategory? VerifyFormatCategory
{
get
{
@@ -63,9 +63,9 @@
{
_identifierFields.Clear();
_verifyFormatCategory = value;
foreach (var field in value.FieldsIterator)
foreach (var field in value.FieldNames)
{
_identifierFields.Add(new IdentifierFieldValidationModel() {Name=field.Key, Value=""});
_identifierFields.Add(new IdentifierFieldValidationModel() {Name=field, Value=""});
}
}
}

View File

@@ -1,5 +1,5 @@
using OpenArchival.Core;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations;
using OpenArchival.DataAccess;
namespace OpenArchival.Blazor;
@@ -34,19 +34,4 @@ public class ArchiveItemValidationModel
public bool IsPublic { get; set; } = true;
public ArchiveItem ToArchiveItem(Category category)
{
return new ArchiveItem() {
ArtifactType = ArtifactType,
Category = category,
Defects = Defects,
Description = Description,
AssociatedDates = AssociatedDates,
ItemTitle = Title,
ListedNames = AssociatedNames,
StorageLocation = StorageLocation,
Tags = Tags,
IsPublic = IsPublic
};
}
}

View File

@@ -0,0 +1,49 @@
namespace OpenArchival.Blazor;
using Microsoft.IdentityModel.Tokens;
using OpenArchival.DataAccess;
using System.ComponentModel.DataAnnotations;
public class ArtifactEntryValidationModel : IValidatableObject
{
[Required(AllowEmptyStrings = false, ErrorMessage = "An artifact numbering must be supplied")]
public string? ArtifactNumber { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "A title must be provided")]
public required string Title { get; set; }
public string? Description { get; set; }
public string? Type { get; set; }
public required string? StorageLocation { get; set; }
public List<string>? Tags { get; set; } = [];
public List<string>? ListedNames { get; set; } = [];
public List<DateTime>? AssociatedDates { get; set; } = [];
public List<string>? Defects { get; set; } = [];
public List<string>? Links { get; set; } = [];
public string? ArtifactType { get; set; }
public List<FilePathListing>? Files { get; set; } = [];
public Dictionary<string, string>? FileTextContent { get; set; } = [];
public IEnumerable<ValidationResult> Validate(ValidationContext context)
{
if (Links.IsNullOrEmpty() && Files.IsNullOrEmpty())
{
yield return new ValidationResult(
"Either uploaded files or add content links",
new[] {nameof(Links), nameof(Files)}
);
}
}
public bool IsPublicallyVisible { get; set; }
}

View File

@@ -0,0 +1,14 @@
using OpenArchival.DataAccess;
namespace OpenArchival.Blazor;
public class ArtifactGroupingValidationModel
{
public required ArchiveCategory Category { get; set; }
public List<string>? IdentifierFieldValues { get; set; }
public List<ArtifactEntryValidationModel>? ArtifactEntries { get; set; }
public bool IsPublicallyVisible { get; set; }
}