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

@@ -1,229 +0,0 @@
@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

@@ -1,124 +0,0 @@
@using Markdig
@using Shared.Components.AssignmentForm
@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

@@ -1,61 +0,0 @@
@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

@@ -1,85 +0,0 @@
@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>

View File

@@ -1,82 +0,0 @@
@using Markdig
@code {
[Parameter, EditorRequired]
public LocalQuizQuestion Question { get; set; } = default!;
}
<div class="row justify-content-between text-secondary">
<div class="col">
points: @Question.Points
</div>
<div class="col-auto">
@Question.QuestionType
</div>
</div>
@((MarkupString)Question.HtmlText)
@if(Question.QuestionType == QuestionType.MATCHING)
{
@foreach(var answer in Question.Answers)
{
<div class="mx-3 mb-1 bg-dark px-2 rounded rounded-2 border row">
<div
class="col text-end my-auto p-1"
>
@answer.Text
</div>
<div
class="col my-auto"
>
@answer.MatchedText
</div>
</div>
}
}
else
{
@foreach(var answer in Question.Answers)
{
string answerPreview = answer.HtmlText.StartsWith("<p>")
? answer.HtmlText.Replace("<p>", "<p class='m-0'>")
: answer.HtmlText;
<div class="mx-3 mb-1 bg-dark px-2 rounded rounded-2 d-flex flex-row border">
@if(answer.Correct)
{
<svg
style="width: 1em;"
class="me-1 my-auto"
viewBox="0 0 24 24"
fill="none"
>
<path
d="M4 12.6111L8.92308 17.5L20 6.5"
stroke="var(--bs-success)"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
}
else
{
<div
class="me-1 my-auto"
style="width: 1em;"
>
@if(Question.QuestionType == QuestionType.MULTIPLE_ANSWERS)
{
<span>[ ]</span>
}
</div>
}
<div class="markdownQuizAnswerPreview p-1">
@((MarkupString)answerPreview)
</div>
</div>
}
}

View File

@@ -1,79 +0,0 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
private Modal? modal { get; set; }
private LocalQuiz? testQuiz;
private string? error { get; set; } = null;
private string _quizMarkdownInput { get; set; } = "";
private string quizMarkdownInput
{
get => _quizMarkdownInput;
set
{
_quizMarkdownInput = value;
try
{
var newQuiz = LocalQuiz.ParseMarkdown(_quizMarkdownInput);
error = null;
testQuiz = newQuiz;
quizContext.SaveQuiz(newQuiz);
}
catch (QuizMarkdownParseException e)
{
error = e.Message;
StateHasChanged();
}
}
}
protected override void OnInitialized()
{
reload();
quizContext.StateHasChanged += reload;
}
private void reload()
{
if (quizContext.Quiz != null)
{
if (quizMarkdownInput == "")
{
quizMarkdownInput = quizContext.Quiz.ToMarkdown();
}
this.InvokeAsync(this.StateHasChanged);
}
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
}
<div class="d-flex flex-column h-100">
<div class="d-flex flex-row h-100 p-2">
<div class="row flex-grow-1">
<div class="col-6">
<MonacoTextArea
Value="@quizMarkdownInput"
OnChange="@((v) => quizMarkdownInput = v)"
/>
</div>
<div class="col-6 h-100 overflow-y-auto">
@if (error != null)
{
<p class="text-danger text-truncate">Error: @error</p>
}
@if(testQuiz != null)
{
<QuizPreview Quiz="testQuiz" />
}
</div>
</div>
</div>
</div>

View File

@@ -1,72 +0,0 @@
@using Management.Web.Shared.Components
@inject QuizEditorContext quizContext
@code {
[Parameter, EditorRequired]
public LocalQuiz Quiz { get; set; } = default!;
protected override void OnInitialized()
{
quizContext.StateHasChanged += reload;
}
private void reload()
{
this.InvokeAsync(this.StateHasChanged);
}
public void Dispose()
{
quizContext.StateHasChanged -= reload;
}
}
@if(Quiz != null)
{
<div class="row justify-content-start">
<div class="col-auto" style="min-width: 35em;">
<div class="row">
<div class="col-6 text-end">Name: </div>
<div class="col-6">@Quiz.Name</div>
</div>
<div class="row">
<div class="col-6 text-end">Due At: </div>
<div class="col-6">@Quiz.DueAt</div>
</div>
<div class="row">
<div class="col-6 text-end">Lock At: </div>
<div class="col-6">@Quiz.LockAt</div>
</div>
<div class="row">
<div class="col-6 text-end">Shuffle Answers: </div>
<div class="col-6">@Quiz.ShuffleAnswers</div>
</div>
<div class="row">
<div class="col-6 text-end">Allowed Attempts: </div>
<div class="col-6">@Quiz.AllowedAttempts</div>
</div>
<div class="row">
<div class="col-6 text-end">One question at a time: </div>
<div class="col-6">@Quiz.OneQuestionAtATime</div>
</div>
<div class="row">
<div class="col-6 text-end">Assignment Group: </div>
<div class="col-6">@Quiz.LocalAssignmentGroupName</div>
</div>
</div>
</div>
<div class="p-3" style="white-space: pre-wrap;">@Quiz.Description</div>
@foreach(var question in Quiz.Questions)
{
<div class="bg-dark-subtle mt-1 p-1 ps-2 rounded rounded-2">
<MarkdownQuestionPreview
Question="question"
@key="question"
/>
</div>
}
}