MRB webassembly

This commit is contained in:
Chase Tucker
2024-05-13 14:33:27 -07:00
parent ba8d92ea01
commit 9b7e3ef897
109 changed files with 11731 additions and 1024 deletions

View File

@ -0,0 +1,69 @@
@inject ISnackbar snackbar
<MudDialog>
<DialogContent>
<MudPaper Class="p-2">
<MudForm @bind-Errors="@errors">
<MudTextField T="string"
Label="Comments"
Required="true"
RequiredError="You must provide a comment"
@bind-Value="@comments"
@bind-Text="@comments"
Immediate="true"
AutoGrow
AutoFocus/>
</MudForm>
</MudPaper>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m1-auto"
OnClick=SubmitComments>
@if (processing) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Ok</MudText>
}
</MudButton>
<MudButton Variant="Variant.Filled"
Class="grey text-black m1-auto"
OnClick=Cancel>
Cancel
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
public string comments { get; set; } = "";
private string[] errors = { };
private bool processing = false;
protected override void OnParametersSet() {
comments = string.Empty;
}
private void SubmitComments() {
processing = true;
try {
if (string.IsNullOrWhiteSpace(comments) || comments.Length < 5)
throw new Exception("Comments must be at least five characters long");
MudDialog.Close(DialogResult.Ok(comments));
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
processing = false;
}
private void Cancel() {
MudDialog.Close(DialogResult.Cancel());
}
}

View File

@ -0,0 +1,115 @@
@inject ISnackbar snackbar
@inject IMRBService mrbService
@inject MesaFabApprovalAuthStateProvider authStateProvider
<MudDialog>
<DialogContent>
<MudPaper Class="p-2">
<MudForm @bind-Errors="@errors">
<MudTextField T="string"
Label="Comments"
Required="true"
RequiredError="You must provide a comment"
@bind-Value="@comments"
@bind-Text="@comments"
Immediate="true"
AutoGrow
AutoFocus/>
<MudFileUpload T="IReadOnlyList<IBrowserFile>" OnFilesChanged="AddAttachments">
<ActivatorContent>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
style="margin: auto;"
StartIcon="@Icons.Material.Filled.AttachFile">
@if (attachmentUploadInProcess) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Upload Supporting Document</MudText>
}
</MudButton>
</ActivatorContent>
</MudFileUpload>
</MudForm>
</MudPaper>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m1-auto"
OnClick=SubmitComments>
@if (processing) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Ok</MudText>
}
</MudButton>
<MudButton Variant="Variant.Filled"
Class="grey text-black m1-auto"
OnClick=Cancel>
Cancel
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
public string comments { get; set; } = "";
[Parameter]
public int actionId { get; set; } = 0;
private string[] errors = { };
private bool processing = false;
private bool attachmentUploadInProcess = false;
protected override void OnParametersSet() {
comments = string.Empty;
}
private void SubmitComments() {
processing = true;
try {
if (string.IsNullOrWhiteSpace(comments) || comments.Length < 5)
throw new Exception("Comments must be at least five characters long");
MudDialog.Close(DialogResult.Ok(comments));
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
processing = false;
}
private void Cancel() {
MudDialog.Close(DialogResult.Cancel());
}
private async Task AddAttachments(InputFileChangeEventArgs args) {
attachmentUploadInProcess = true;
try {
if (actionId <= 0)
throw new Exception($"{actionId} is not a valid MRB action ID");
IReadOnlyList<IBrowserFile> attachments = args.GetMultipleFiles();
if (authStateProvider.CurrentUser is not null) {
await mrbService.UploadActionAttachments(attachments, actionId);
await mrbService.GetAllActionAttachmentsForMRB(actionId, true);
attachmentUploadInProcess = false;
snackbar.Add("Attachments successfully uploaded", Severity.Success);
StateHasChanged();
}
} catch (Exception ex) {
attachmentUploadInProcess = false;
snackbar.Add($"Unable to upload attachments, because {ex.Message}", Severity.Error);
}
}
}

View File

@ -0,0 +1,261 @@
@inject IMRBService mrbService
@inject ISnackbar snackbar
@inject ICustomerService customerService
<MudDialog>
<DialogContent>
<MudPaper Class="p-2">
<MudForm @bind-Errors="@errors">
<MudSelect T="string"
Label="Action"
Required="true"
RequiredError="You must select an action!"
@bind-Value="@mrbAction.Action"
Text="@mrbAction.Action">
<MudSelectItem Value="@("Block")" />
<MudSelectItem Value="@("Convert")" />
<MudSelectItem Value="@("Recall")" />
<MudSelectItem Value="@("Scrap")" />
<MudSelectItem Value="@("Unblock")" />
<MudSelectItem Value="@("Waiver")" />
</MudSelect>
@if (mrbAction.Action.Equals("Convert")) {
<MudTextField @bind-Value="@mrbAction.ConvertFrom"
Label="Convert From"
Required
RequiredError="Conversion value required!"
Text="@mrbAction.ConvertFrom" />
<MudTextField @bind-Value="@mrbAction.ConvertTo"
Label="Convert To"
Required
RequiredError="Conversion value required!"
Text="@mrbAction.ConvertTo" />
}
<MudSelect T="string"
Label="Affected Customer"
Required
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=mrbAction.Customer
Text="@mrbAction.Customer">
@foreach (string customer in customerNames) {
<MudSelectItem Value="@(customer)" />
}
</MudSelect>
<MudTextField T="int"
InputType="@InputType.Number"
Label="Qty"
Required="true"
RequiredError="You must supply a quantity!"
@bind-Value=mrbAction.Quantity
Text="@mrbAction.Quantity.ToString()" />
<MudAutocomplete T="string"
Label="Part Number"
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=mrbAction.PartNumber
Text="@mrbAction.PartNumber"
SearchFunc="@PartNumberSearch"
ResetValueOnEmptyText
CoerceText />
<MudAutocomplete T="string"
Label="Batch Number / Lot Number"
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=mrbAction.LotNumber
Text="@mrbAction.LotNumber"
SearchFunc="@LotNumberSearch"
ResetValueOnEmptyText
CoerceText />
@if (mrbAction.Action.Equals("Scrap")) {
<MudSelect T="string"
Label="Justification"
Required
RequiredError="Justification required!"
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=mrbAction.Justification
Text="@mrbAction.Justification">
<MudSelectItem Value="@("Obsolete")" />
<MudSelectItem Value="@("Aged Material")" />
<MudSelectItem Value="@("Out of Specification")" />
</MudSelect>
}
</MudForm>
</MudPaper>
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m1-auto"
OnClick=SaveMRBAction>
@if (processingSave) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Save</MudText>
}
</MudButton>
@if (mrbAction is not null && mrbAction.ActionID > 0) {
<MudButton Variant="Variant.Filled"
Color="Color.Secondary"
Disabled="@(mrbAction is null || (mrbAction is not null && mrbAction.ActionID <= 0))"
Class="m1-auto"
OnClick=DeleteMRBAction>
@if (processingDelete) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Delete</MudText>
}
</MudButton>
}
<MudButton Variant="Variant.Filled"
Class="grey text-black m1-auto"
OnClick=Cancel>
Cancel
</MudButton>
</DialogActions>
</MudDialog>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
public MRBAction mrbAction { get; set; }
private IEnumerable<MRBAction>? actions = null;
private MRBAction lastAction = null;
private IEnumerable<string> customerNames = new List<string>();
private bool isVisible { get; set; }
private string[] errors = { };
private bool processingSave = false;
private bool processingDelete = false;
protected override async Task OnParametersSetAsync() {
isVisible = true;
if (mrbAction is null) {
snackbar.Add("MRB action cannot be null", Severity.Warning);
MudDialog.Cancel();
} else {
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, false)).OrderByDescending(a => a.ActionID);
if (actions is not null && actions.Count() > 0) {
if (string.IsNullOrWhiteSpace(mrbAction.LotNumber))
mrbAction.LotNumber = actions.First().LotNumber;
if (string.IsNullOrWhiteSpace(mrbAction.PartNumber))
mrbAction.PartNumber = actions.First().PartNumber;
}
}
if (customerNames is null || customerNames.Count() <= 0)
customerNames = await customerService.GetAllCustomerNames();
StateHasChanged();
}
private bool FormIsValid() {
bool actionIsValid = mrbAction.Action.Equals("Block") || mrbAction.Action.Equals("Convert") ||
mrbAction.Action.Equals("Other") || mrbAction.Action.Equals("Recall") || mrbAction.Action.Equals("Scrap") ||
mrbAction.Action.Equals("Unblock") || mrbAction.Action.Equals("Waiver");
actionIsValid = actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Customer) &&
!string.IsNullOrWhiteSpace(mrbAction.PartNumber) &&
!string.IsNullOrWhiteSpace(mrbAction.LotNumber);
if (mrbAction.Action.Equals("Scrap"))
return actionIsValid && !string.IsNullOrWhiteSpace(mrbAction.Justification);
return actionIsValid;
}
private async void SaveMRBAction() {
processingSave = true;
try {
if (!FormIsValid()) throw new Exception("You must complete the form before saving!");
if (mrbAction.MRBNumber > 0) {
if (mrbAction.ActionID <= 0) {
await mrbService.CreateMRBAction(mrbAction);
snackbar.Add("MRB action created", Severity.Success);
} else {
await mrbService.UpdateMRBAction(mrbAction);
snackbar.Add("MRB action updated", Severity.Success);
}
actions = (await mrbService.GetMRBActionsForMRB(mrbAction.MRBNumber, true)).OrderByDescending(a => a.ActionID);
} else {
snackbar.Add("MRB action saved", Severity.Success);
}
StateHasChanged();
MudDialog.Close(DialogResult.Ok(mrbAction));
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
processingSave = false;
}
private async void DeleteMRBAction() {
processingDelete = true;
try {
if (mrbAction is null) throw new Exception("MRB action cannot be null!");
if (mrbAction.ActionID <= 0)
throw new Exception("You cannot delete an action before creating it!");
if (mrbAction.MRBNumber <= 0)
throw new Exception("Invalid MRB number!");
await mrbService.DeleteMRBAction(mrbAction);
snackbar.Add("MRB action successfully deleted", Severity.Success);
StateHasChanged();
MudDialog.Close(DialogResult.Ok<MRBAction>(null));
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
processingDelete = false;
}
private void Cancel() {
MudDialog.Cancel();
}
private async Task<IEnumerable<string>> PartNumberSearch(string value, CancellationToken token) {
if (actions is null) return new List<string> { value };
if (string.IsNullOrWhiteSpace(value)) return new string[0];
HashSet<string> partNumbers = new();
partNumbers.Add(value);
foreach (MRBAction action in actions) {
if (action.PartNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase))
partNumbers.Add(action.PartNumber);
}
return partNumbers;
}
private async Task<IEnumerable<string>> LotNumberSearch(string value, CancellationToken token) {
if (actions is null) return new List<string> { value };
if (string.IsNullOrWhiteSpace(value)) return new string[0];
HashSet<string> lotNumbers = new();
lotNumbers.Add(value);
foreach (MRBAction action in actions) {
if (action.LotNumber.Contains(value, StringComparison.InvariantCultureIgnoreCase))
lotNumbers.Add(action.LotNumber);
}
return lotNumbers;
}
}

View File

@ -0,0 +1,111 @@
@inject IApprovalService approvalService
@inject ISnackbar snackbar
@inject MesaFabApprovalAuthStateProvider authStateProvider
<MudDialog>
<DialogContent>
@if (availableApprovers is not null) {
<MudPaper Class="p-2">
<MudSelect T="User"
Label="Select a User"
Required
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=selectedUser
Text="@(selectedUser is null ? "" : selectedUser.GetFullName())">
@foreach (User user in availableApprovers) {
<MudSelectItem Value="@user">
@user.GetFullName()
</MudSelectItem>
}
</MudSelect>
</MudPaper>
}
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m1-auto"
OnClick=Submit>
<MudText>Submit</MudText>
</MudButton>
<MudButton Variant="Variant.Filled"
Color="Color.Secondary"
Class="m1-auto"
OnClick=Cancel>
<MudText>Cancel</MudText>
</MudButton>
</DialogActions>
</MudDialog>
<MudOverlay Visible=processing DarkBackground="true" AutoClose="false">
<MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" />
</MudOverlay>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
public User selectedUser { get; set; }
private bool processing = false;
private HashSet<User> availableApprovers = new();
protected override async Task OnInitializedAsync() {
try {
processing = true;
string roleName = "QA_PRE_APPROVAL";
string subRoleName = "QA_PRE_APPROVAL";
IEnumerable<User> qaApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName);
foreach (User approver in qaApprovers)
availableApprovers.Add(approver);
roleName = "MRB Approver";
subRoleName = "MRBApprover";
IEnumerable<User> mrbApprovers = await GetApprovalGroupMembersForRoleAndSubRole(roleName, subRoleName);
foreach (User approver in mrbApprovers)
availableApprovers.Add(approver);
selectedUser = availableApprovers.First();
processing = false;
} catch (Exception ex) {
processing = false;
snackbar.Add($"Unable to get all approvers, because {ex.Message}", Severity.Error);
}
}
private void Submit() {
MudDialog.Close(DialogResult.Ok(selectedUser));
}
private void Cancel() {
MudDialog.Close(DialogResult.Cancel());
}
private async Task<IEnumerable<User>> GetApprovalGroupMembersForRoleAndSubRole(string roleName, string subRoleName) {
HashSet<User> members = new();
int roleId = await approvalService.GetRoleIdForRoleName(roleName);
if (roleId <= 0) throw new Exception($"could not find {roleName} role ID");
IEnumerable<SubRole> subRoles = await approvalService.GetSubRolesForSubRoleName(subRoleName, roleId);
foreach (SubRole subRole in subRoles) {
IEnumerable<User> subRoleMembers = await approvalService.GetApprovalGroupMembers(subRole.SubRoleID);
foreach (User member in subRoleMembers) {
members.Add(member);
}
}
return members;
}
}

View File

@ -0,0 +1,8 @@
@attribute [AllowAnonymous]
@inject NavigationManager Navigation
@code {
protected override void OnInitialized() {
Navigation.NavigateTo("login");
}
}

View File

@ -0,0 +1,74 @@
@inject IUserService userService
@inject ISnackbar snackbar
@inject MesaFabApprovalAuthStateProvider authStateProvider
<MudDialog>
<DialogContent>
@if (allUsers is not null) {
<MudPaper Class="p-2">
<MudSelect T="User"
Label="Select a User"
Required
Variant="Variant.Outlined"
AnchorOrigin="Origin.BottomCenter"
@bind-Value=selectedUser
Text="@(selectedUser is null ? "" : selectedUser.GetFullName())">
@foreach (User user in allUsers) {
<MudSelectItem Value="@user">
@user.GetFullName()
</MudSelectItem>
}
</MudSelect>
</MudPaper>
}
</DialogContent>
<DialogActions>
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m1-auto"
OnClick=Submit>
<MudText>Submit</MudText>
</MudButton>
<MudButton Variant="Variant.Filled"
Color="Color.Secondary"
Class="m1-auto"
OnClick=Cancel>
<MudText>Cancel</MudText>
</MudButton>
</DialogActions>
</MudDialog>
<MudOverlay Visible=processing DarkBackground="true" AutoClose="false">
<MudProgressCircular Color="Color.Info" Size="Size.Medium" Indeterminate="true" />
</MudOverlay>
@code {
[CascadingParameter] MudDialogInstance MudDialog { get; set; }
[Parameter]
public User selectedUser { get; set; }
private bool processing = false;
private IEnumerable<User> allUsers = new List<User>();
protected override async Task OnInitializedAsync() {
try {
processing = true;
selectedUser = authStateProvider.CurrentUser;
allUsers = await userService.GetAllActiveUsers();
processing = false;
} catch (Exception ex) {
processing = false;
snackbar.Add($"Unable to get all users, because {ex.Message}", Severity.Error);
}
}
private void Submit() {
MudDialog.Close(DialogResult.Ok(selectedUser));
}
private void Cancel() {
MudDialog.Close(DialogResult.Cancel());
}
}