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,64 @@
@page "/redirect"
@attribute [AllowAnonymous]
@inject MesaFabApprovalAuthStateProvider authStateProvider
@inject IAuthenticationService authService
@inject IUserService userService
@inject ISnackbar snackbar
@inject MesaFabApprovalAuthStateProvider authStateProvider
@inject NavigationManager navigationManager
@code {
private string? _jwt;
private string? _refreshToken;
private string? _redirectPath;
protected override async Task OnParametersSetAsync() {
try {
Uri uri = navigationManager.ToAbsoluteUri(navigationManager.Uri);
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("jwt", out var jwt)) {
_jwt = System.Net.WebUtility.UrlDecode(jwt);
}
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("refreshToken", out var refreshToken)) {
_refreshToken = System.Net.WebUtility.UrlDecode(refreshToken);
}
if (QueryHelpers.ParseQuery(uri.Query).TryGetValue("redirectPath", out var redirectPath)) {
_redirectPath = System.Net.WebUtility.UrlDecode(redirectPath);
}
if (!string.IsNullOrWhiteSpace(_jwt) && !string.IsNullOrWhiteSpace(_refreshToken)) {
await authService.SetTokens(_jwt, _refreshToken);
ClaimsPrincipal principal = authService.GetClaimsPrincipalFromJwt(_jwt);
string loginId = userService.GetLoginIdFromClaimsPrincipal(principal);
await authService.SetLoginId(loginId);
await authService.SetTokens(_jwt, _refreshToken);
User? user = await userService.GetUserByLoginId(loginId);
await authService.SetCurrentUser(user);
await authStateProvider.StateHasChanged(principal);
}
if (authStateProvider.CurrentUser is not null && !string.IsNullOrWhiteSpace(_redirectPath)) {
navigationManager.NavigateTo(_redirectPath);
} else {
await authStateProvider.Logout();
if (!string.IsNullOrWhiteSpace(_redirectPath)) {
navigationManager.NavigateTo($"login/{_redirectPath}");
} else {
navigationManager.NavigateTo("login");
}
}
} catch (Exception ex) {
snackbar.Add($"Redirect failed, because {ex.Message}", Severity.Error);
navigationManager.NavigateTo("login");
}
}
}

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());
}
}

View File

@ -0,0 +1,248 @@
@page "/"
@page "/Dashboard"
@inject IConfiguration Configuration
@inject MesaFabApprovalAuthStateProvider stateProvider
@inject IApprovalService approvalService
@inject IMemoryCache cache
@inject NavigationManager navigationManager
@inject ISnackbar snackbar
@inject IMRBService mrbService
@inject IECNService ecnService
@inject ICAService caService
@inject IJSRuntime jsRuntime
<PageTitle>Dashboard</PageTitle>
<MudPaper Class="p-2 m-2">
<MudText Typo="Typo.h3" Align="Align.Center">Dashboard</MudText>
</MudPaper>
<MudPaper Class="p-2 m-2">
<MudTabs Class="p-2" Rounded Centered Color="Color.Info" MinimumTabWidth="50%">
<MudTabPanel Text="My Active Approvals" Style="min-width:50%; text-align: center;">
@if (stateProvider.CurrentUser is not null && approvalList is not null && !myApprovalsProcessing) {
<MudPaper Outlined="true"
Class="p-2 m-2 d-flex flex-column justify-center">
<MudText Typo="Typo.h4" Align="Align.Center">My Active Approvals</MudText>
<MudDivider DividerType="DividerType.Middle" Class="my-2" />
<MudTable Items="@approvalList"
Class="m-2"
Striped
SortLabel="Sort by">
<HeaderContent>
<MudTh>
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.IssueID)">
Issue ID
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.SubRoleCategoryItem)">
Role
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<Approval,object>(x=>x.AssignedDate)">
Assigned Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<Approval,object>(x=>x.Step)">
Step
</MudTableSortLabel>
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Issue ID">
@if (context.IssueID > 0) {
<MudLink OnClick="@(() => FollowLink(context.IssueID))">@context.IssueID</MudLink>
}
</MudTd>
<MudTd DataLabel="Role">@context.SubRoleCategoryItem</MudTd>
<MudTd DataLabel="Assigned Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.AssignedDate)</MudTd>
<MudTd DataLabel="Step">@context.Step</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
</MudPaper>
} else {
<MudOverlay Visible DarkBackground="true" AutoClose="false">
<MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText>
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
</MudOverlay>
}
</MudTabPanel>
<MudTabPanel Text="My MRBs" Style="min-width:50%; text-align: center;">
@if (stateProvider.CurrentUser is not null && myMRBs is not null && !myMrbsProcessing) {
<MudPaper Outlined="true"
Class="p-2 m-2 d-flex flex-column justify-center">
<MudText Typo="Typo.h4" Align="Align.Center">My MRBs</MudText>
<MudDivider DividerType="DividerType.Middle" Class="my-2" />
<MudTable Items="@myMRBs"
Class="m-2"
Striped
SortLabel="Sort by"
Filter="new Func<MRB, bool>(FilterFuncForMRBTable)">
<ToolBarContent>
<MudSpacer />
<MudTextField @bind-Value="mrbSearchString"
Placeholder="Search"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="mt-0" />
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<MRB,object>(x=>x.MRBNumber)">
MRB#
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.Title)">
Title
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.SubmittedDate)">
Submitted Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)">
Approval Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CancelDate)">
Cancel Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)">
Completed Date
</MudTableSortLabel>
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="MRB#">
<MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink>
</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd>
<MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd>
<MudTd DataLabel="Cancel Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CancelDate)</MudTd>
<MudTd DataLabel="Completed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
</MudPaper>
} else {
<MudOverlay Visible DarkBackground="true" AutoClose="false">
<MudText Align="Align.Center" Typo="Typo.h3">Processing</MudText>
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
</MudOverlay>
}
</MudTabPanel>
</MudTabs>
</MudPaper>
@code {
private IEnumerable<Approval> approvalList = new List<Approval>();
private IEnumerable<MRB> myMRBs = new List<MRB>();
private IEnumerable<int> ecnNumbers = new HashSet<int>();
private IEnumerable<int> caNumbers = new HashSet<int>();
private IEnumerable<int> mrbNumbers = new HashSet<int>();
private bool myApprovalsProcessing = false;
private bool myMrbsProcessing = false;
private string mrbSearchString = "";
protected async override Task OnParametersSetAsync() {
try {
if (stateProvider.CurrentUser is not null) {
myApprovalsProcessing = true;
approvalList = (await approvalService.GetApprovalsForUserId(stateProvider.CurrentUser.UserID, true))
.Where(a => a.CompletedDate > DateTime.Now && a.ItemStatus == 0)
.ToList()
.OrderByDescending(x => x.AssignedDate);
myApprovalsProcessing = false;
myMrbsProcessing = true;
myMRBs = (await mrbService.GetAllMRBs(false)).Where(m => m.OriginatorID == stateProvider.CurrentUser.UserID)
.ToList()
.OrderByDescending(x => x.SubmittedDate);
myMrbsProcessing = false;
}
} catch (Exception ex) {
myMrbsProcessing = false;
snackbar.Add($"Unable to load the dashboard, because {ex.Message}", Severity.Error);
}
}
private async Task FollowLink(int issueId) {
HashSet<Task> tasks = new();
bool isEcn = false;
bool isCa = false;
bool isMrb = false;
if (ecnNumbers.Contains(issueId))
isEcn = true;
if (caNumbers.Contains(issueId))
isCa = true;
if (mrbNumbers.Contains(issueId))
isMrb = true;
if (!isEcn && !isCa && !isMrb) {
Task<bool> isEcnTask = ecnService.ECNNumberIsValid(issueId);
tasks.Add(isEcnTask);
Task<bool> isCaTask = caService.CANumberIsValid(issueId);
tasks.Add(isCaTask);
Task<bool> isMrbTask = mrbService.NumberIsValid(issueId);
tasks.Add(isMrbTask);
await Task.WhenAll(tasks);
if (isEcnTask.Result) {
isEcn = true;
} else if (isCaTask.Result) {
isCa = true;
} else if (isMrbTask.Result) {
isMrb = true;
}
}
if (isEcn) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/ECN/Edit?IssueID={issueId}", "");
if (isCa) await GoToExternal($"{Configuration["OldFabApprovalUrl"]}/CorrectiveAction/Edit?IssueID={issueId}", "");
if (isMrb) GoTo($"mrb/{issueId}");
}
private void GoTo(string page) {
cache.Set("redirectUrl", page);
navigationManager.NavigateTo("/" + page);
}
private async Task GoToExternal(string url, string content) {
IJSObjectReference windowModule = await jsRuntime.InvokeAsync<IJSObjectReference>("import", "./js/OpenInNewWindow.js");
await windowModule.InvokeAsync<object>("OpenInNewWindow", url, content);
}
private bool FilterFuncForMRBTable(MRB mrb) => MRBFilterFunc(mrb, mrbSearchString);
private bool MRBFilterFunc(MRB mrb, string searchString) {
if (string.IsNullOrWhiteSpace(searchString))
return true;
if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
return true;
if (mrb.MRBNumber.ToString().Contains(searchString.Trim()))
return true;
return false;
}
}

View File

@ -0,0 +1,113 @@
@page "/login"
@page "/login/{redirectUrl}"
@page "/login/{redirectUrl}/{redirectUrlSub}"
@attribute [AllowAnonymous]
@inject MesaFabApprovalAuthStateProvider authStateProvider
@inject NavigationManager navManager
@inject ISnackbar snackbar
<MudPaper Class="p-2 m-2">
<MudText Typo="Typo.h3" Align="Align.Center">Login</MudText>
</MudPaper>
<MudPaper Class="p-2 m-2">
<MudForm @bind-IsValid="@success" @bind-Errors="@errors">
<MudTextField T="string"
Label="Windows Username"
Required="true"
RequiredError="Username is required!"
Variant="Variant.Outlined"
@bind-Value=username
Class="m-1"
Immediate="true"
AutoFocus
OnKeyDown=SubmitIfEnter />
<MudTextField T="string"
Label="Windows Password"
Required="true"
RequiredError="Password is required!"
Variant="Variant.Outlined"
@bind-Value=password
InputType="InputType.Password"
Class="m-1"
Immediate="true"
OnKeyDown=SubmitIfEnter />
<MudButton
Variant="Variant.Filled"
Color="Color.Tertiary"
Disabled="@(!success)"
Class="m-1"
OnClick=SubmitLogin >
@if (processing) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Log In</MudText>
}
</MudButton>
<MudDivider />
@* <MudButton
Variant="Variant.Filled"
Color="Color.Tertiary"
Class="m-1"
OnClick="LoginLocal" >
@if (processingLocal) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Log In (SSO)</MudText>
}
</MudButton> *@
</MudForm>
</MudPaper>
@code {
[Parameter]
public string? redirectUrl { get; set; }
[Parameter]
public string? redirectUrlSub { get; set; }
private bool success;
private bool processing = false;
private bool processingLocal = false;
private string[] errors = { };
private string? username;
private string? password;
private async Task SubmitLogin() {
processing = true;
if (string.IsNullOrWhiteSpace(username)) snackbar.Add("Username is required!", Severity.Error);
else if (string.IsNullOrWhiteSpace(password)) snackbar.Add("Password is required!", Severity.Error);
else {
await authStateProvider.LoginAsync(username, password);
if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) {
navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}");
} else if (!string.IsNullOrWhiteSpace(redirectUrl)) {
navManager.NavigateTo(redirectUrl);
} else {
navManager.NavigateTo("dashboard");
}
}
processing = false;
}
private async Task SubmitIfEnter(KeyboardEventArgs e) {
if (e.Key == "Enter" && success) {
SubmitLogin();
}
}
private async Task LoginLocal() {
processingLocal = true;
await authStateProvider.LoginLocal();
if (!string.IsNullOrWhiteSpace(redirectUrl) && !string.IsNullOrWhiteSpace(redirectUrlSub)) {
navManager.NavigateTo($"{redirectUrl}/{redirectUrlSub}");
} else if (!string.IsNullOrWhiteSpace(redirectUrl)) {
navManager.NavigateTo(redirectUrl);
} else {
navManager.NavigateTo("dashboard");
}
processingLocal = false;
}
}

View File

@ -0,0 +1,119 @@
@page "/mrb/all"
@using System.Globalization
@inject IMRBService mrbService
@inject ISnackbar snackbar
@inject IMemoryCache cache
@inject NavigationManager navigationManager
<PageTitle>MRB</PageTitle>
<MudPaper Class="p-2 m-2">
<MudText Typo="Typo.h3" Align="Align.Center">MRB List</MudText>
</MudPaper>
@if (allMrbs is not null && allMrbs.Count() > 0) {
<MudTable Items="@allMrbs"
Class="m-2"
Striped="true"
Filter="new Func<MRB,bool>(FilterFuncForTable)"
SortLabel="Sort By"
Hover="true">
<ToolBarContent>
<MudSpacer />
<MudTextField @bind-Value="searchString"
Placeholder="Search"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="mt-0" />
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<MRB,object>(x=>x.MRBNumber)">
MRB#
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.Title)">
Title
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.OriginatorName)">
Originator
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.SubmittedDate)">
Submitted Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.ApprovalDate)">
Approval Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<MRB,object>(x=>x.CloseDate)">
Closed Date
</MudTableSortLabel>
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="MRB#">
<MudLink OnClick="@(() => GoTo($"mrb/{context.MRBNumber}"))">@context.MRBNumber</MudLink>
</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Originator">@context.OriginatorName</MudTd>
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.SubmittedDate)</MudTd>
<MudTd DataLabel="Approval Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ApprovalDate)</MudTd>
<MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.CloseDate)</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
}
<MudOverlay @bind-Visible=inProcess DarkBackground="true" AutoClose="false">
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
</MudOverlay>
@code {
private bool inProcess = false;
private string searchString = "";
private IEnumerable<MRB> allMrbs = new List<MRB>();
protected override async Task OnParametersSetAsync() {
inProcess = true;
try {
if (mrbService is null) {
throw new Exception("MRB service not injected!");
} else {
allMrbs = await mrbService.GetAllMRBs(false);
}
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
inProcess = false;
}
private bool FilterFuncForTable(MRB mrb) => FilterFunc(mrb, searchString);
private bool FilterFunc(MRB mrb, string searchString) {
if (string.IsNullOrWhiteSpace(searchString))
return true;
if (mrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
return true;
if (mrb.OriginatorName.ToLower().Contains(searchString.Trim().ToLower()))
return true;
if (mrb.MRBNumber.ToString().Contains(searchString.Trim()))
return true;
return false;
}
private void GoTo(string page) {
cache.Set("redirectUrl", page);
navigationManager.NavigateTo(page);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,119 @@
@page "/pcrb/all"
@using System.Globalization
@inject IPCRBService pcrbService
@inject ISnackbar snackbar
@inject IMemoryCache cache
@inject NavigationManager navigationManager
<PageTitle>PCRB</PageTitle>
<MudPaper Class="p-2 m-2">
<MudText Typo="Typo.h3" Align="Align.Center">PCRB List</MudText>
</MudPaper>
@if (allPCRBs is not null && allPCRBs.Count() > 0) {
<MudTable Items="@allPCRBs"
Class="m-2"
Striped="true"
Filter="new Func<PCRB,bool>(FilterFuncForTable)"
SortLabel="Sort By"
Hover="true">
<ToolBarContent>
<MudSpacer />
<MudTextField @bind-Value="searchString"
Placeholder="Search"
Adornment="Adornment.Start"
AdornmentIcon="@Icons.Material.Filled.Search"
IconSize="Size.Medium"
Class="mt-0" />
</ToolBarContent>
<HeaderContent>
<MudTh>
<MudTableSortLabel InitialDirection="SortDirection.Descending" SortBy="new Func<PCRB,object>(x=>x.PlanNumber)">
Plan#
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.Title)">
Title
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.OwnerName)">
Owner
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.InsertTimeStamp)">
Submitted Date
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.LastUpdateDate)">
Last Updated
</MudTableSortLabel>
</MudTh>
<MudTh>
<MudTableSortLabel SortBy="new Func<PCRB,object>(x=>x.ClosedDate)">
Closed Date
</MudTableSortLabel>
</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Plan#">
<MudLink OnClick="@(() => GoTo($"pcrb/{context.PlanNumber.ToString()}"))">@context.PlanNumber</MudLink>
</MudTd>
<MudTd DataLabel="Title">@context.Title</MudTd>
<MudTd DataLabel="Owner">@context.OwnerName</MudTd>
<MudTd DataLabel="Submitted Date">@DateTimeUtilities.GetDateAsStringMinDefault(context.InsertTimeStamp)</MudTd>
<MudTd DataLabel="Last Updated">@DateTimeUtilities.GetDateAsStringMinDefault(context.LastUpdateDate)</MudTd>
<MudTd DataLabel="Closed Date">@DateTimeUtilities.GetDateAsStringMaxDefault(context.ClosedDate)</MudTd>
</RowTemplate>
<PagerContent>
<MudTablePager />
</PagerContent>
</MudTable>
}
<MudOverlay @bind-Visible=inProcess DarkBackground="true" AutoClose="false">
<MudProgressCircular Color="Color.Info" Size="Size.Large" Indeterminate="true" />
</MudOverlay>
@code {
private bool inProcess = false;
private string searchString = "";
private IEnumerable<PCRB> allPCRBs = new List<PCRB>();
protected override async Task OnParametersSetAsync() {
inProcess = true;
try {
if (pcrbService is null) {
throw new Exception("PCRB service not injected!");
} else {
allPCRBs = await pcrbService.GetAllPCRBs(false);
}
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
inProcess = false;
}
private bool FilterFuncForTable(PCRB pcrb) => FilterFunc(pcrb, searchString);
private bool FilterFunc(PCRB pcrb, string searchString) {
if (string.IsNullOrWhiteSpace(searchString))
return true;
if (pcrb.Title.ToLower().Contains(searchString.Trim().ToLower()))
return true;
if (pcrb.OwnerName.ToLower().Contains(searchString.Trim().ToLower()))
return true;
if (pcrb.PlanNumber.ToString().Contains(searchString.Trim()))
return true;
return false;
}
private void GoTo(string page) {
cache.Set("redirectUrl", page);
navigationManager.NavigateTo(page);
}
}

View File

@ -0,0 +1,263 @@
@page "/pcrb/{planNumber}"
@page "/pcrb/new"
@using System.Text
@inject ISnackbar snackbar
@inject IPCRBService pcrbService
@inject IUserService userService
@inject IMemoryCache cache
@inject NavigationManager navigationManager
@inject MesaFabApprovalAuthStateProvider authStateProvider
<PageTitle>PCRB @planNumber</PageTitle>
<MudPaper Class="p-2 m-2 d-flex flex-row justify-content-between">
<MudIconButton Icon="@Icons.Material.Filled.ChevronLeft"
Variant="Variant.Outlined"
Color="Color.Dark"
OnClick="@ReturnToAllPcrbs"
Size="Size.Large" />
<MudText Typo="Typo.h3" Align="Align.Center">PCRB @planNumber</MudText>
<MudPaper Height="100%" Width="0.1%" Square="true" />
</MudPaper>
@if (pcrb is not null) {
<MudTimeline Class="mt-2 pt-2" TimelineOrientation="TimelineOrientation.Horizontal"
TimelinePosition="TimelinePosition.Bottom">
@for (int i = 0; i < PCRB.Stages.Length; i++) {
Color color;
if (pcrb.CurrentStep > i || pcrb.CurrentStep == (PCRB.Stages.Length - 1)) {
color = Color.Success;
} else if (pcrb.CurrentStep == i) {
color = Color.Info;
} else {
color = Color.Dark;
}
string stageName = PCRB.Stages[i];
<MudTimelineItem Color="@color" Variant="Variant.Filled">
<MudText Align="Align.Center" Color="@color">@stageName</MudText>
</MudTimelineItem>
}
</MudTimeline>
bool pcrbIsSubmitted = pcrb.InsertTimeStamp > DateTimeUtilities.MIN_DT;
bool userIsOriginator = pcrb.OwnerID == authStateProvider.CurrentUser?.UserID;
bool userIsAdmin = authStateProvider.CurrentUser is null ? false : authStateProvider.CurrentUser.IsAdmin;
<MudPaper Outlined="true"
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-center"
Elevation="10">
@if (!pcrbIsSubmitted && !string.IsNullOrWhiteSpace(pcrb.Title)) {
<MudButton Variant="Variant.Filled"
Color="Color.Tertiary"
OnClick=SavePCRB>
@if (saveInProcess) {
<MudProgressCircular Class="m-1" Size="Size.Small" Indeterminate="true" />
<MudText>Processing</MudText>
} else {
<MudText>Save</MudText>
}
</MudButton>
}
</MudPaper>
@if (!pcrbIsSubmitted && GetIncompleteFields().Count() > 0) {
IEnumerable<string> incompleteFields = GetIncompleteFields();
StringBuilder errorBuilder = new();
errorBuilder.Append($"Incomplete fields: {incompleteFields.First()}");
for (int i = 1; i < incompleteFields.Count(); i++) {
errorBuilder.Append($", {incompleteFields.ElementAt(i)}");
}
<MudPaper Outlined Class="p-2 m-2">
<MudText Align="Align.Center" Color="Color.Secondary" Typo="Typo.h6">
@errorBuilder.ToString()
</MudText>
</MudPaper>
}
<MudPaper Outlined="true"
Class="p-2 m-2 d-flex flex-wrap gap-3 justify-content-center align-content-start"
Elevation="10">
<MudTextField @bind-Value=pcrb.PlanNumber
Text="@pcrb.PlanNumber.ToString()"
T="int"
Disabled="true"
Label="Plan#"
Required
Variant="Variant.Outlined" />
<MudTextField @bind-Value=pcrb.Title
Text="@pcrb.Title"
Disabled="@(pcrbIsSubmitted)"
T="string"
AutoGrow
AutoFocus
Immediate
Clearable
Required
Variant="Variant.Outlined"
Label="Title" />
<MudSelect T="User"
Label="Originator"
Variant="Variant.Outlined"
Required
Clearable
AnchorOrigin="Origin.BottomCenter"
ToStringFunc="@UserToNameConverter"
Disabled=@(pcrbIsSubmitted)
@bind-Value=@selectedOwner>
@foreach (User user in allActiveUsers.OrderBy(u => u.LastName)) {
<MudSelectItem T="User" Value="@(user)" />
}
</MudSelect>
<MudSelect T="string"
Variant="Variant.Outlined"
Required
Clearable
AnchorOrigin="Origin.BottomCenter"
Disabled="@pcrbIsSubmitted"
@bind-Value="@pcrb.ChangeLevel"
Text="@pcrb.ChangeLevel"
Label="Change Level">
<MudSelectItem Value="@("Global")" />
<MudSelectItem Value="@("Other Site + Mesa")" />
<MudSelectItem Value="@("Mesa")" />
</MudSelect>
<MudCheckBox Disabled="@pcrbIsSubmitted"
Color="Color.Tertiary"
@bind-Value=pcrb.IsITAR
Label="Export Controlled"
LabelPosition="LabelPosition.Start" />
<MudTextField Disabled="true"
T="string"
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.InsertTimeStamp)"
Label="Submit Date"
Variant="Variant.Outlined" />
<MudTextField Disabled="true"
T="string"
Value="@DateTimeUtilities.GetDateAsStringMinDefault(pcrb.LastUpdateDate)"
Label="Last Update"
Variant="Variant.Outlined" />
<MudTextField @bind-Value=pcrb.ChangeDescription
Text="@pcrb.ChangeDescription"
Disabled="@(pcrbIsSubmitted)"
T="string"
AutoGrow
Immediate
Clearable
Required
Variant="Variant.Outlined"
Label="Description" />
<MudTextField @bind-Value=pcrb.ReasonForChange
Text="@pcrb.ReasonForChange"
Disabled="@(pcrbIsSubmitted)"
T="string"
AutoGrow
Immediate
Clearable
Required
Variant="Variant.Outlined"
Label="Reason For Change" />
</MudPaper>
}
@code {
[Parameter]
public string planNumber { get; set; } = "";
private int planNumberInt = 0;
private PCRB pcrb = null;
private IEnumerable<User> allActiveUsers = new List<User>();
private User selectedOwner = null;
private bool processing = false;
private bool saveInProcess = false;
protected override async Task OnParametersSetAsync() {
processing = true;
try {
allActiveUsers = await userService.GetAllActiveUsers();
if (!string.IsNullOrWhiteSpace(planNumber) && Int32.TryParse(planNumber, out planNumberInt)) {
pcrb = await pcrbService.GetPCRBByPlanNumber(planNumberInt, false);
if (pcrb.OwnerID > 0) selectedOwner = await userService.GetUserByUserId(pcrb.OwnerID);
} else {
int ownerID = 0;
string ownerName = string.Empty;
if (authStateProvider.CurrentUser is not null) {
selectedOwner = authStateProvider.CurrentUser;
ownerID = authStateProvider.CurrentUser.UserID;
ownerName = authStateProvider.CurrentUser.GetFullName();
}
pcrb = new() {
OwnerID = ownerID,
OwnerName = ownerName,
CurrentStep = 0
};
}
} catch (Exception ex) {
snackbar.Add(ex.Message, Severity.Error);
}
processing = false;
}
private Func<User, string> UserToNameConverter = u => u is null ? string.Empty : u.GetFullName();
private void ReturnToAllPcrbs() {
cache.Set("redirectUrl", $"pcrb/all");
navigationManager.NavigateTo("pcrb/all");
}
private IEnumerable<string> GetIncompleteFields() {
List<string> incompleteFields = new();
if (string.IsNullOrWhiteSpace(pcrb.Title))
incompleteFields.Add("Title");
if (selectedOwner is null || pcrb.OwnerID <= 0 || string.IsNullOrWhiteSpace(pcrb.OwnerName))
incompleteFields.Add("Originator");
if (string.IsNullOrWhiteSpace(pcrb.ChangeLevel))
incompleteFields.Add("Change Level");
if (string.IsNullOrWhiteSpace(pcrb.ChangeDescription))
incompleteFields.Add("Description");
if (string.IsNullOrWhiteSpace(pcrb.ReasonForChange))
incompleteFields.Add("Reason For Change");
return incompleteFields;
}
private async void SavePCRB() {
saveInProcess = true;
try {
if (pcrb is null) throw new Exception("PCRB cannot be null");
int initialPlanNumber = pcrb.PlanNumber;
pcrb.OwnerID = selectedOwner.UserID;
pcrb.OwnerName = selectedOwner.GetFullName();
if (initialPlanNumber <= 0) {
await pcrbService.CreateNewPCRB(pcrb);
} else {
await pcrbService.UpdatePCRB(pcrb);
}
pcrb = await pcrbService.GetPCRBByTitle(pcrb.Title, true);
cache.Set("redirectUrl", $"pcrb/{pcrb.PlanNumber}");
saveInProcess = false;
StateHasChanged();
snackbar.Add($"PCRB {pcrb.PlanNumber} successfully saved", Severity.Success);
if (initialPlanNumber <= 0)
navigationManager.NavigateTo($"pcrb/{pcrb.PlanNumber}");
} catch (Exception ex) {
saveInProcess = false;
snackbar.Add($"Unable to save PCRB, because {ex.Message}", Severity.Error);
}
}
}