restructured components so that there are more components in the pages

This commit is contained in:
2024-01-11 17:28:14 -07:00
parent 4fb5d9a25d
commit 5666d3dc85
22 changed files with 110 additions and 85 deletions

View File

@@ -0,0 +1,229 @@
@using Management.Web.Shared.Components
@using Management.Web.Shared.Components.Forms
@using CanvasModel.Assignments
@inject CoursePlanner planner
@inject CanvasService canvas
@inject NavigationManager Navigation
@inject AssignmentEditorContext assignmentContext
@code {
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
name = assignmentContext.Assignment.Name;
}
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private void OnHide()
{
assignmentContext.Assignment = null;
name = "";
}
private string name { get; set; } = String.Empty;
private bool addingAssignmentToCanvas = false;
private bool deletingAssignmentFromCanvas = false;
private bool showHelp = false;
private void toggleHelp() => showHelp = !showHelp;
private void submitHandler()
{
if (assignmentContext.Assignment != null)
{
var newAssignment = assignmentContext.Assignment with
{
Name = name,
};
assignmentContext.SaveAssignment(newAssignment);
}
assignmentContext.Assignment = null;
}
private async Task HandleDelete()
{
if (planner.LocalCourse != null && assignmentContext.Assignment != null)
{
var assignment = assignmentContext.Assignment;
var currentModule = planner
.LocalCourse
.Modules
.First(m =>
m.Assignments.Contains(assignment)
) ?? throw new Exception("handling assignment delete, could not find module");
var newModules = planner.LocalCourse.Modules.Select(m =>
m.Name == currentModule.Name
? m with
{
Assignments = m.Assignments.Where(a => a != assignment).ToArray()
}
: m
)
.ToArray();
planner.LocalCourse = planner.LocalCourse with
{
Modules = newModules
};
if (assignmentInCanvas != null && planner.LocalCourse.Settings.CanvasId != null)
{
ulong courseId = planner.LocalCourse.Settings.CanvasId ?? throw new Exception("cannot delete if no course id");
await canvas.Assignments.Delete(courseId, assignmentInCanvas.Id, assignment.Name);
}
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name);
}
}
private void handleNameChange(ChangeEventArgs e)
{
if (assignmentContext.Assignment != null)
{
var newAssignment = assignmentContext.Assignment with { Name = e.Value?.ToString() ?? "" };
assignmentContext.SaveAssignment(newAssignment);
}
}
private void setAssignmentGroup(LocalAssignmentGroup? group)
{
if (assignmentContext.Assignment == null)
return;
var newAssignment = assignmentContext.Assignment with
{
LocalAssignmentGroupName = group?.Name
};
assignmentContext.SaveAssignment(newAssignment);
}
private LocalAssignmentGroup? selectedAssignmentGroup =>
planner
.LocalCourse?
.Settings
.AssignmentGroups
.FirstOrDefault(g => g.Name == assignmentContext.Assignment?.LocalAssignmentGroupName);
private async Task addToCanvas()
{
addingAssignmentToCanvas = true;
await assignmentContext.AddAssignmentToCanvas();
await planner.LoadCanvasData();
addingAssignmentToCanvas = false;
}
private async Task updateInCanvas()
{
if(assignmentInCanvas != null)
{
addingAssignmentToCanvas = true;
await assignmentContext.UpdateInCanvas(assignmentInCanvas.Id);
await planner.LoadCanvasData();
addingAssignmentToCanvas = false;
}
}
private CanvasAssignment? assignmentInCanvas =>
planner.CanvasAssignments?.FirstOrDefault(a => a.Name == assignmentContext.Assignment?.Name);
private string canvasAssignmentUrl =>
$"https://snow.instructure.com/courses/{planner.LocalCourse?.Settings.CanvasId}/assignments/{assignmentInCanvas?.Id}";
private async Task deleteFromCanvas()
{
if (assignmentInCanvas == null
|| planner?.LocalCourse?.Settings.CanvasId == null
|| assignmentContext.Assignment == null
)
return;
deletingAssignmentFromCanvas = true;
await canvas.Assignments.Delete(
(ulong)planner.LocalCourse.Settings.CanvasId,
assignmentInCanvas.Id,
assignmentContext.Assignment.Name
);
await planner.LoadCanvasData();
deletingAssignmentFromCanvas = false;
StateHasChanged();
}
}
<div class="d-flex flex-column p-2 h-100 w-100" style="height: 100%;" >
<div>
@assignmentContext.Assignment?.Name
</div>
<section class="flex-grow-1 p-1 border rounded-4 bg-dark-subtle" style="min-height: 0;">
@if (assignmentContext.Assignment != null)
{
<AssignmentMarkdownEditor ShowHelp=@showHelp />
}
</section>
<div class="d-flex justify-content-end p-3">
@if (addingAssignmentToCanvas || deletingAssignmentFromCanvas)
{
<div>
<Spinner />
</div>
}
<button class="btn btn-outline-secondary mx-3" @onclick=toggleHelp>
Toggle Help
</button>
<ConfirmationModal Label="Delete" Class="btn btn-danger" OnConfirmAsync="HandleDelete" />
<button
class="btn btn-outline-secondary mx-3"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
@onclick="addToCanvas"
>
Add To Canvas
</button>
@if (assignmentInCanvas != null)
{
<a
class="btn btn-outline-secondary me-1"
href="@canvasAssignmentUrl"
target="_blank"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
>
View in Canvas
</a>
<button
class="btn btn-outline-secondary mx-3"
disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
@onclick="updateInCanvas"
>
Update In Canvas
</button>
<ConfirmationModal
Disabled="@(addingAssignmentToCanvas || deletingAssignmentFromCanvas)"
Label="Delete from Canvas"
Class="btn btn-outline-danger mx-3"
OnConfirmAsync="deleteFromCanvas"
/>
}
<button class="btn btn-primary mx-2" @onclick="@(() => {
assignmentContext.Assignment = null;
Navigation.NavigateTo("/course/" + planner.LocalCourse?.Settings.Name);
})">
Done
</button>
</div>
</div>

View File

@@ -0,0 +1,67 @@
@page "/course/{CourseName}/assignment/{AssignmentName}"
@using CanvasModel.EnrollmentTerms
@using CanvasModel.Courses
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@using LocalModels
@using Management.Web.Shared.Module.Assignment
@using Management.Web.Shared.Components
@inject FileStorageManager fileStorageManager
@inject CanvasService canvas
@inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@inject ILogger<AssignmentFormPage> logger
@code {
[Parameter]
public string? CourseName { get; set; } = default!;
[Parameter]
public string? AssignmentName { get; set; } = default!;
private bool loading { get; set; } = true;
protected override async Task OnInitializedAsync()
{
if (loading)
{
loading = false;
logger.LogInformation($"loading assignment {CourseName} {AssignmentName}");
if (planner.LocalCourse == null)
{
var courses = await fileStorageManager.LoadSavedCourses();
planner.LocalCourse = courses.First(c => c.Settings.Name == CourseName);
logger.LogInformation($"set course to '{planner.LocalCourse?.Settings.Name}'");
}
if (assignmentContext.Assignment == null)
{
var assignment = planner
.LocalCourse?
.Modules
.SelectMany(m => m.Assignments)
.FirstOrDefault(a => a.Name == AssignmentName);
assignmentContext.Assignment = assignment;
logger.LogInformation($"set assignment to '{assignmentContext.Assignment?.Name}'");
}
await planner.LoadCanvasData();
base.OnInitialized();
StateHasChanged();
}
}
}
<PageTitle>@CourseName - @AssignmentName</PageTitle>
<div style="height: 100vh;" class="m-0 p-1 d-flex flex-row">
@if (loading)
{
<Spinner />
}
@if (planner.LocalCourse != null && assignmentContext.Assignment != null)
{
<AssignmentForm />
}
</div>

View File

@@ -0,0 +1,124 @@
@using Markdig
@using Management.Web.Shared.Components
@inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code
{
[Parameter, EditorRequired]
public bool ShowHelp { get; set; } = false;
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
if(rawText == string.Empty)
{
rawText = assignmentContext.Assignment.ToMarkdown();
this.InvokeAsync(this.StateHasChanged);
}
}
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private string rawText { get; set; } = string.Empty;
private string? error = null;
public bool? UseTemplate { get; set; } = null;
public string? TemplateId { get; set; }
private void handleChange(string newRawAssignment)
{
rawText = newRawAssignment;
if (newRawAssignment != string.Empty)
{
try
{
var parsed = LocalAssignment.ParseMarkdown(newRawAssignment);
error = null;
assignmentContext.SaveAssignment(parsed);
}
catch(AssignmentMarkdownParseException e)
{
error = e.Message;
}
catch(RubricMarkdownParseException e)
{
error = e.Message;
}
finally
{
StateHasChanged();
}
}
StateHasChanged();
}
private MarkupString preview { get => (MarkupString)Markdown.ToHtml(assignmentContext?.Assignment?.Description ?? ""); }
private string HelpText()
{
var groupNames = string.Join("\n- " , planner.LocalCourse?.Settings.AssignmentGroups.Select(g => g.Name) ?? []);
return $@"
SubmissionTypes:
- {AssignmentSubmissionType.ONLINE_TEXT_ENTRY}
- {AssignmentSubmissionType.ONLINE_UPLOAD}
- {AssignmentSubmissionType.DISCUSSION_TOPIC}
Assignment Group Names:
- {groupNames}
";
}
}
<div class="d-flex w-100 h-100 flex-row">
@if(ShowHelp)
{
<div class=" rounded rounded-3 bg-black" >
<pre class=" me-3 pe-5 ps-3 rounded rounded-3">
@HelpText()
</pre>
</div>
}
@if(assignmentContext.Assignment != null && planner.LocalCourse != null)
{
<div class="row h-100 w-100">
<div class="col-6">
<MonacoTextArea Value=@rawText OnChange=@handleChange />
</div>
<div class="col-6 overflow-y-auto h-100" >
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
<div>Due At: @assignmentContext.Assignment.DueAt</div>
<div>Lock At: @assignmentContext.Assignment.LockAt</div>
<div>Assignment Group Name @assignmentContext.Assignment.LocalAssignmentGroupName</div>
<div>Submission Types</div>
<ul>
@foreach(var t in assignmentContext.Assignment.SubmissionTypes)
{
<li>@t</li>
}
</ul>
<hr>
<div>
@(preview)
</div>
<hr>
<RubricDisplay />
</div>
</div>
}
</div>

View File

@@ -0,0 +1,61 @@
@using Management.Web.Shared.Components
@inject CoursePlanner planner
@inject AssignmentEditorContext assignmentContext
@code
{
private string? error { get; set; } = null;
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private int requiredPoints => assignmentContext?.Assignment?.Rubric.Where(r => !r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
private int extraCreditPoints => assignmentContext?.Assignment?.Rubric.Where(r => r.IsExtraCredit).Select(r => r.Points).Sum() ?? 0;
}
@if(assignmentContext != null)
{
<div class="row">
<h4 class="text-center">Rubric</h4>
</div>
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
<div class="row border-bottom">
<div class="col-6 text-end">Label</div>
<div class="col-3 text-center">Points</div>
<div class="col-3 text-center">Extra Credit</div>
</div>
@foreach (var item in assignmentContext?.Assignment?.Rubric ?? [])
{
<div class="row border-bottom">
<div class="col-6 text-end">@item.Label</div>
<div class="col-3 text-center">@item.Points</div>
<div class="col-3 text-center">@item.IsExtraCredit</div>
</div>
}
<div class="text-end">
<div>
Required Points: @requiredPoints
</div>
<div>
Extra Credit Points @extraCreditPoints
</div>
</div>
}

View File

@@ -0,0 +1,85 @@
@using System.Reflection
@inject AssignmentEditorContext assignmentContext
@code
{
protected override void OnInitialized()
{
assignmentContext.StateHasChanged += reload;
reload();
}
private void reload()
{
if (assignmentContext.Assignment != null)
{
types = assignmentContext.Assignment.SubmissionTypes;
}
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
assignmentContext.StateHasChanged -= reload;
}
private IEnumerable<string> types { get; set; } = Enumerable.Empty<string>();
private string getLabel(string type)
{
return type.ToString().Replace("_", "") + "switch";
}
private bool discussionIsSelected
{
get => types.FirstOrDefault(
t => t == AssignmentSubmissionType.DISCUSSION_TOPIC
) != null;
}
private void saveTypes(IEnumerable<string> newTypes)
{
if(assignmentContext.Assignment != null)
{
types = newTypes;
assignmentContext.SaveAssignment(assignmentContext.Assignment with
{
SubmissionTypes = types
});
}
}
}
<h5>Submission Types</h5>
<div class="row" @key="types">
@foreach (var submissionType in AssignmentSubmissionType.AllTypes)
{
var isDiscussion = submissionType == AssignmentSubmissionType.DISCUSSION_TOPIC;
var allowedToBeChecked = !discussionIsSelected || isDiscussion;
<div class="col-3">
<div class="form-check form-switch">
<input
class="form-check-input"
type="checkbox"
role="switch"
id="@getLabel(submissionType)"
checked="@(types.Contains(submissionType) && allowedToBeChecked)"
@onchange="(e) => {
var isChecked = (bool)(e.Value ?? false);
if(isChecked)
saveTypes(types.Append(submissionType));
else
saveTypes(types.Where(t => t != submissionType));
}"
disabled="@(discussionIsSelected && !isDiscussion)"
>
<label
class="form-check-label"
for="@getLabel(submissionType)"
>
@submissionType
</label>
</div>
</div>
}
</div>