got debounced saving working. some of the assignment saving logic is real time

This commit is contained in:
2023-08-11 15:19:15 -06:00
parent ea087faa1a
commit b1d5567902
9 changed files with 170 additions and 130 deletions

View File

@@ -8,7 +8,7 @@ global using CanvasModel;
global using LocalModels; global using LocalModels;
global using Management.Planner; global using Management.Planner;
global using Management.Web.Shared.Components; global using Management.Web.Shared.Components;
global using Management.Web.Shared.Course; global using Management.Web.Shared;
using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Components.Web;
@@ -39,6 +39,7 @@ builder.Services.AddScoped<CanvasService, CanvasService>();
builder.Services.AddScoped<YamlManager>(); builder.Services.AddScoped<YamlManager>();
builder.Services.AddScoped<CoursePlanner>(); builder.Services.AddScoped<CoursePlanner>();
builder.Services.AddScoped<AssignmentEditorContext>();
builder.Services.AddScoped<DragContainer>(); builder.Services.AddScoped<DragContainer>();
var app = builder.Build(); var app = builder.Build();

View File

@@ -4,7 +4,7 @@
@code @code
{ {
protected override void OnInitialized() @* protected override void OnInitialized()
{ {
planner.StateHasChanged += reload; planner.StateHasChanged += reload;
} }
@@ -15,7 +15,7 @@
public void Dispose() public void Dispose()
{ {
planner.StateHasChanged -= reload; planner.StateHasChanged -= reload;
} } *@
[Parameter, EditorRequired] [Parameter, EditorRequired]
@@ -41,7 +41,6 @@
{ {
UseTemplate = Assignment.TemplateId != null && Assignment.TemplateId != ""; UseTemplate = Assignment.TemplateId != null && Assignment.TemplateId != "";
} }
Console.WriteLine(Description)
} }
@@ -77,7 +76,7 @@
} }
: m : m
).ToArray(); ).ToArray();
planner.LocalCourse = planner.LocalCourse with planner.LocalCourse = planner.LocalCourse with
{ {
Modules=updatedModules Modules=updatedModules
@@ -85,41 +84,21 @@
} }
} }
private Timer _debounceTimer;
private void SaveDescription()
{
Console.WriteLine("saving description");
_debounceTimer?.Dispose();
SaveAssignment(Assignment with { Description = currentDescription });
}
private string? currentDescription { get; set; } = null; private string? currentDescription { get; set; } = null;
private void OnInputChanged(ChangeEventArgs e) private void OnInputChanged(ChangeEventArgs e)
{ {
// Dispose of any existing timer SaveAssignment(Assignment with { Description = e.Value?.ToString() ?? "" });
_debounceTimer?.Dispose();
// Create a new timer that waits for 500ms before executing SaveData
_debounceTimer = new Timer(
(_) => SaveDescription(),
null,
500,
Timeout.Infinite
);
} }
} }
<div class="form-check form-switch"> <div class="form-check form-switch">
<input <input
class="form-check-input" class="form-check-input"
type="checkbox" type="checkbox"
role="switch" role="switch"
id="useTemplateForDescription" id="useTemplateForDescription"
@bind="UseTemplate" @bind="UseTemplate"
/> />
<label class="form-check-label" for="useTemplateForDescription"> <label class="form-check-label" for="useTemplateForDescription">
use template for description use template for description

View File

@@ -2,32 +2,30 @@
@inject CoursePlanner planner @inject CoursePlanner planner
@inject CanvasService canvas @inject CanvasService canvas
@inject AssignmentEditorContext assignmentContext
@code { @code {
protected override void OnInitialized() protected override void OnInitialized()
{ {
planner.StateHasChanged += reload; assignmentContext.StateHasChanged += reload;
} }
private void reload() private void reload()
{ {
if (assignmentContext.Assignment != null)
{
AssignmentModal?.Show();
name = assignmentContext.Assignment.Name;
lockAtDueDate = assignmentContext.Assignment.LockAtDueDate;
rubric = assignmentContext.Assignment.Rubric;
submissionTypes = assignmentContext.Assignment.SubmissionTypes;
}
this.InvokeAsync(this.StateHasChanged); this.InvokeAsync(this.StateHasChanged);
} }
public void Dispose() public void Dispose()
{ {
planner.StateHasChanged -= reload; assignmentContext.StateHasChanged -= reload;
} }
[Parameter]
[EditorRequired]
public LocalAssignment Assignment
{
get;
set;
} = default!;
[Parameter]
[EditorRequired]
public bool Show { get; set; }
[Parameter] [Parameter]
public Action OnHide { get; set; } = () => { }; public Action OnHide { get; set; } = () => { };
@@ -37,26 +35,16 @@
private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>(); private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>();
private IEnumerable<string> submissionTypes { get; set; } = Enumerable.Empty<string>(); private IEnumerable<string> submissionTypes { get; set; } = Enumerable.Empty<string>();
protected override void OnParametersSet()
{
if (Show)
{
AssignmentModal?.Show();
}
name = Assignment.Name;
lockAtDueDate = Assignment.LockAtDueDate;
rubric = Assignment.Rubric;
submissionTypes = Assignment.SubmissionTypes;
}
private void submitHandler() private void submitHandler()
{ {
var totalRubricPoints = rubric if(assignmentContext.Assignment != null)
.Where(r => !r.Label.Contains(RubricItem.extraCredit)) {
.Select(s => s.Points) var totalRubricPoints = rubric
.Sum(); .Where(r => !r.Label.Contains(RubricItem.extraCredit))
.Select(s => s.Points)
.Sum();
var newAssignment = Assignment with var newAssignment = assignmentContext.Assignment with
{ {
Name = name, Name = name,
LockAtDueDate = lockAtDueDate, LockAtDueDate = lockAtDueDate,
@@ -65,34 +53,36 @@
SubmissionTypes = submissionTypes, SubmissionTypes = submissionTypes,
}; };
if (planner.LocalCourse != null) if (planner.LocalCourse != null)
{ {
var currentModule = planner var currentModule = planner
.LocalCourse .LocalCourse
.Modules .Modules
.First(m => .First(m =>
m.Assignments m.Assignments
.Select(a => a.Id) .Select(a => a.Id)
.Contains(Assignment.Id) .Contains(newAssignment.Id)
) ?? throw new Exception("could not find current module in assignment form"); ) ?? throw new Exception("could not find current module in assignment form");
var updatedModules = planner.LocalCourse.Modules.Select(m => var updatedModules = planner.LocalCourse.Modules.Select(m =>
m.Name == currentModule.Name m.Name == currentModule.Name
? currentModule with ? currentModule with
{ {
Assignments = currentModule.Assignments.Select(a => Assignments = currentModule.Assignments.Select(a =>
a.Id == newAssignment.Id a.Id == newAssignment.Id
? newAssignment ? newAssignment
: a : a
).ToArray() ).ToArray()
} }
: m : m
).ToArray(); ).ToArray();
planner.LocalCourse = planner.LocalCourse with planner.LocalCourse = planner.LocalCourse with
{ {
Modules = updatedModules Modules = updatedModules
}; };
}
AssignmentModal?.Hide();
assignmentContext.Assignment = null;
} }
AssignmentModal?.Hide();
} }
private void updateRubric(IEnumerable<RubricItem> newRubric) private void updateRubric(IEnumerable<RubricItem> newRubric)
@@ -108,16 +98,17 @@
private async Task HandleDelete() private async Task HandleDelete()
{ {
if (planner.LocalCourse != null) if (planner.LocalCourse != null && assignmentContext.Assignment != null)
{ {
var assignment = Assignment; var assignment = assignmentContext.Assignment;
var currentModule = planner var currentModule = planner
.LocalCourse .LocalCourse
.Modules .Modules
.First(m => .First(m =>
m.Assignments m.Assignments
.Select(a => a.Id) .Select(a => a.Id)
.Contains(Assignment.Id) .Contains(assignment.Id)
) ?? throw new Exception("handling assignment delete, could not find module"); ) ?? throw new Exception("handling assignment delete, could not find module");
var newModules = planner.LocalCourse.Modules.Select(m => var newModules = planner.LocalCourse.Modules.Select(m =>
m.Name == currentModule.Name m.Name == currentModule.Name
@@ -143,34 +134,40 @@
<Modal @ref="AssignmentModal" OnHide="@(() => OnHide())"> <Modal @ref="AssignmentModal" OnHide="@(() => OnHide())">
<Title> <Title>
@Assignment.Name @assignmentContext.Assignment?.Name
</Title> </Title>
<Body> <Body>
<form @onsubmit:preventDefault="true" @onsubmit="submitHandler"> @if(assignmentContext.Assignment != null)
<div class="m-1"> {
<label class="form-label"> <form @onsubmit:preventDefault="true">
Name <div class="m-1">
</label> <label class="form-label">
<input class="form-control" @bind="name" /> Name
</div> </label>
<div class="m-1"> <input class="form-control" @bind="name" />
<AssignmentDescriptionEditor @key="Assignment" Assignment="Assignment" /> </div>
</div> <div class="m-1">
<AssignmentDescriptionEditor Assignment="assignmentContext.Assignment" />
</div>
<div class="form-check m-1"> <div class="form-check m-1">
<input class="form-check-input" id="lockAtDueDate" type="checkbox" /> <input class="form-check-input" id="lockAtDueDate" type="checkbox" />
<label class="form-check-label" for="lockAtDueDate" @bind="lockAtDueDate"> <label class="form-check-label" for="lockAtDueDate" @bind="lockAtDueDate">
Lock At Due Date Lock At Due Date
</label> </label>
</div> </div>
<RubricEditor Rubric="rubric" SetRubric="updateRubric" /> <RubricEditor Rubric="rubric" SetRubric="updateRubric" />
<SubmissionTypeSelector Types="submissionTypes" SetTypes="SetTypes" /> <SubmissionTypeSelector Types="submissionTypes" SetTypes="SetTypes" />
</form> </form>
}
</Body> </Body>
<Footer> <Footer>
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirmAsync="HandleDelete" /> <ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirmAsync="HandleDelete" />
<button class="btn btn-primary" @onclick="@(() => AssignmentModal?.Hide())"> <button class="btn btn-primary" @onclick="@(() => {
AssignmentModal?.Hide();
assignmentContext.Assignment = null;
})">
Save Save
</button> </button>
</Footer> </Footer>

View File

@@ -18,6 +18,7 @@
private bool showBackdrop = false; private bool showBackdrop = false;
public void Show() public void Show()
{ {
modalClass = "show-modal"; modalClass = "show-modal";
showBackdrop = true; showBackdrop = true;
OnShow(); OnShow();

View File

@@ -2,6 +2,7 @@
@using CanvasModel.EnrollmentTerms @using CanvasModel.EnrollmentTerms
@using Management.Web.Shared.Module @using Management.Web.Shared.Module
@using Management.Web.Shared.Semester @using Management.Web.Shared.Semester
@using Management.Web.Shared.Components.AssignmentForm
@inject CanvasService canvas @inject CanvasService canvas
@inject CoursePlanner planner @inject CoursePlanner planner
@@ -55,4 +56,6 @@
<div class="col-4 overflow-y-auto" style="max-height: 95vh;"> <div class="col-4 overflow-y-auto" style="max-height: 95vh;">
<Modules /> <Modules />
</div> </div>
</div> </div>
<AssignmentForm />

View File

@@ -3,6 +3,7 @@
@inject DragContainer dragContainer @inject DragContainer dragContainer
@inject CoursePlanner planner @inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code { @code {
[Parameter] [Parameter]
@@ -128,7 +129,7 @@
draggable="true" draggable="true"
@ondragstart="HandleDragStart" @ondragstart="HandleDragStart"
@ondragend="HandleDragEnd" @ondragend="HandleDragEnd"
@onclick="@(() => showUpdateForm = true)" @onclick="@(() => assignmentContext.Assignment = Assignment)"
role="button" role="button"
> >
<div class="card"> <div class="card">
@@ -249,9 +250,3 @@
</div> </div>
</div> </div>
</div> </div>
<AssignmentForm
Assignment="Assignment"
Show="showUpdateForm"
OnHide="@(() => showUpdateForm = false)"
/>

View File

@@ -2,6 +2,7 @@
@inject DragContainer dragContainer @inject DragContainer dragContainer
@inject CoursePlanner planner @inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code { @code {
[Parameter] [Parameter]
@@ -14,12 +15,12 @@
private void reload() private void reload()
{ {
this.InvokeAsync(this.StateHasChanged); this.InvokeAsync(this.StateHasChanged);
@* Console.WriteLine("on initialized " + showUpdateForm + " " + Assignment.Name); *@
} }
public void Dispose() public void Dispose()
{ {
planner.StateHasChanged -= reload; planner.StateHasChanged -= reload;
} }
private bool showUpdateForm = false;
private void dropOnDate(DateTime dropDate) private void dropOnDate(DateTime dropDate)
{ {
@@ -114,14 +115,8 @@
draggable="true" draggable="true"
@ondragstart="HandleDragStart" @ondragstart="HandleDragStart"
@ondragend="HandleDragEnd" @ondragend="HandleDragEnd"
@onclick="@(() => showUpdateForm = true)" @onclick="@(() => assignmentContext.Assignment = Assignment)"
role="button" role="button"
> >
@Assignment.Name @Assignment.Name
</div> </div>
<AssignmentForm
Assignment="Assignment"
Show="showUpdateForm"
OnHide="@(() => showUpdateForm = false)"
/>

View File

@@ -0,0 +1,52 @@
using LocalModels;
using Management.Planner;
public class AssignmentEditorContext
{
public event Action? StateHasChanged;
private CoursePlanner planner { get; }
public AssignmentEditorContext(CoursePlanner planner)
{
this.planner = planner;
}
private LocalAssignment? _assignment;
public LocalAssignment? Assignment
{
get { return _assignment; }
set
{
_assignment = value;
StateHasChanged?.Invoke();
}
}
public void SaveAssignment(LocalAssignment newAssignment)
{
if (planner.LocalCourse != null)
{
Console.WriteLine(newAssignment.Description);
var currentModule =
planner.LocalCourse.Modules.First(
m => m.Assignments.Select(a => a.Id).Contains(newAssignment.Id)
) ?? throw new Exception("could not find current module in assignment description form");
var updatedModules = planner.LocalCourse.Modules
.Select(
m =>
m.Name == currentModule.Name
? currentModule with
{
Assignments = currentModule.Assignments
.Select(a => a.Id == newAssignment.Id ? newAssignment : a)
.ToArray()
}
: m
)
.ToArray();
planner.LocalCourse = planner.LocalCourse with { Modules = updatedModules };
}
}
}

View File

@@ -21,6 +21,8 @@ public class CoursePlanner
this.canvas = canvas; this.canvas = canvas;
} }
private Timer _debounceTimer;
private int _debounceInterval = 1000;
private LocalCourse? _localCourse { get; set; } private LocalCourse? _localCourse { get; set; }
public LocalCourse? LocalCourse public LocalCourse? LocalCourse
{ {
@@ -36,15 +38,30 @@ public class CoursePlanner
var verifiedCourse = value.GeneralCourseCleanup(); var verifiedCourse = value.GeneralCourseCleanup();
// ignore initial load of course _debounceTimer?.Dispose();
if (_localCourse != null) _debounceTimer = new Timer(
{ (_) => saveCourseToFile(),
yamlManager.SaveCourse(verifiedCourse); null,
} _debounceInterval,
Timeout.Infinite
);
_localCourse = verifiedCourse; _localCourse = verifiedCourse;
StateHasChanged?.Invoke(); StateHasChanged?.Invoke();
} }
} }
private void saveCourseToFile()
{
_debounceTimer?.Dispose();
// ignore initial load of course
if (LocalCourse != null)
{
Console.WriteLine("Saving file");
yamlManager.SaveCourse(LocalCourse);
}
}
public event Action? StateHasChanged; public event Action? StateHasChanged;
public IEnumerable<CanvasAssignment>? CanvasAssignments { get; internal set; } public IEnumerable<CanvasAssignment>? CanvasAssignments { get; internal set; }