mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-26 07:38:33 -06:00
added template editor
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="dotenv.net" Version="3.1.2" />
|
||||
<PackageReference Include="Markdig" Version="0.31.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
@page "/"
|
||||
@using CanvasModel.EnrollmentTerms
|
||||
@using Management.Web.Shared.Course
|
||||
@using Management.Web.Shared.Module.Assignment.Templates
|
||||
@using Management.Web.Shared.Semester
|
||||
@using CanvasModel.Courses
|
||||
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
|
||||
@using LocalModels
|
||||
@using Management.Web.Shared.Module.Assignment
|
||||
|
||||
@inject CanvasService canvas
|
||||
@inject CoursePlanner planner
|
||||
@@ -63,13 +65,15 @@ protected override void OnInitialized()
|
||||
|
||||
@if(planner.LocalCourse != null)
|
||||
{
|
||||
<div class="">
|
||||
<div class="mb-3">
|
||||
<button
|
||||
@onclick="@(() => planner.LocalCourse = null)"
|
||||
class="btn btn-primary"
|
||||
>
|
||||
Select New Course
|
||||
</button>
|
||||
<CourseSettings />
|
||||
<AssignmentTemplateManagement />
|
||||
</div>
|
||||
<CourseDetails />
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
|
||||
<div class="modal @modalClass">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-dialog modal-xl" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title text-center w-100">@Title</h4>
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
@code
|
||||
{
|
||||
private bool showEditCourseSettings = false;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
planner.StateHasChanged += reload;
|
||||
@@ -21,22 +20,7 @@
|
||||
planner.StateHasChanged -= reload;
|
||||
}
|
||||
}
|
||||
<br>
|
||||
|
||||
@if(!showEditCourseSettings)
|
||||
{
|
||||
<button class="btn btn-outline-secondary" @onclick="@(() => showEditCourseSettings = true)">Edit Course Settings</button>
|
||||
}
|
||||
else
|
||||
{
|
||||
<CourseSettings />
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
@onclick="@(() => showEditCourseSettings = false)"
|
||||
>
|
||||
Done Editing Course Settings
|
||||
</button>
|
||||
}
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
@code
|
||||
{
|
||||
private Modal modal { get; set; } = default!;
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
planner.StateHasChanged += reload;
|
||||
@@ -25,7 +26,6 @@
|
||||
_selectedTermId = value;
|
||||
if(selectedTerm != null && planner.LocalCourse != null)
|
||||
{
|
||||
System.Console.WriteLine(JsonSerializer.Serialize(selectedTerm));
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
StartDate=selectedTerm.StartAt ?? new DateTime(),
|
||||
@@ -52,82 +52,102 @@
|
||||
}
|
||||
}
|
||||
|
||||
<h5>Select Days Of Week</h5>
|
||||
<div class="row m-3">
|
||||
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
|
||||
{
|
||||
<div class="col">
|
||||
<button
|
||||
class="@(
|
||||
planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false
|
||||
? "btn btn-secondary"
|
||||
: "btn btn-outline-secondary"
|
||||
)"
|
||||
@onclick="() =>
|
||||
{
|
||||
if(planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false)
|
||||
{
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
@onclick="@(() => modal.Show())"
|
||||
>
|
||||
Edit Course Settings
|
||||
</button>
|
||||
|
||||
<Modal @ref="modal">
|
||||
<Title>
|
||||
<h1>Course Settings</h1>
|
||||
</Title>
|
||||
<Body>
|
||||
<h5 class="text-center">Select Days Of Week</h5>
|
||||
<div class="row m-3">
|
||||
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
|
||||
{
|
||||
<div class="col">
|
||||
<button
|
||||
class="@(
|
||||
planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false
|
||||
? "btn btn-secondary"
|
||||
: "btn btn-outline-secondary"
|
||||
)"
|
||||
@onclick="() =>
|
||||
{
|
||||
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Where((d) => d != day)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (planner.LocalCourse != null)
|
||||
{
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
if(planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false)
|
||||
{
|
||||
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Append(day)
|
||||
};
|
||||
}
|
||||
}
|
||||
}"
|
||||
>
|
||||
@day
|
||||
</button>
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Where((d) => d != day)
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (planner.LocalCourse != null)
|
||||
{
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Append(day)
|
||||
};
|
||||
}
|
||||
}
|
||||
}"
|
||||
>
|
||||
@day
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@if(loading)
|
||||
{
|
||||
<Spinner />
|
||||
}
|
||||
@if(loading)
|
||||
{
|
||||
<Spinner />
|
||||
}
|
||||
|
||||
@if (terms != null)
|
||||
{
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<form>
|
||||
<lablel for="termselect">Select Term for Start and End Date:</lablel>
|
||||
<select id="termselect" class="form-select" @bind="selectedTermId">
|
||||
@foreach (var term in terms)
|
||||
{
|
||||
<option value="@term.Id">@term.Name</option>
|
||||
}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@if (terms != null)
|
||||
{
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<form @onsubmit:preventDefault="true">
|
||||
<label for="termselect">Select Term for Start and End Date:</label>
|
||||
<select id="termselect" class="form-select" @bind="selectedTermId">
|
||||
@foreach (var term in terms)
|
||||
{
|
||||
<option value="@term.Id">@term.Name</option>
|
||||
}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
|
||||
@if(planner.LocalCourse != null)
|
||||
{
|
||||
<div class="row justify-content-center m-3 text-center">
|
||||
<div class="col-auto">
|
||||
<div>Default Assignment Due Time</div>
|
||||
<TimePicker
|
||||
Time="planner.LocalCourse.DefaultDueTime"
|
||||
UpdateTime="@((newTime) =>
|
||||
planner.LocalCourse =
|
||||
planner.LocalCourse with
|
||||
{ DefaultDueTime=newTime }
|
||||
)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<br>
|
||||
|
||||
@if(planner.LocalCourse != null)
|
||||
{
|
||||
<div class="row justify-content-center m-3 text-center">
|
||||
<div class="col-auto">
|
||||
<div>Default Assignment Due Time</div>
|
||||
<TimePicker
|
||||
Time="planner.LocalCourse.DefaultDueTime"
|
||||
UpdateTime="@((newTime) =>
|
||||
planner.LocalCourse =
|
||||
planner.LocalCourse with
|
||||
{ DefaultDueTime=newTime }
|
||||
)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</Body>
|
||||
<Footer>
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
@onclick="@(() => modal.Hide())"
|
||||
>
|
||||
Done Editing Course Settings
|
||||
</button>
|
||||
</Footer>
|
||||
</Modal>
|
||||
@@ -148,8 +148,8 @@
|
||||
{
|
||||
<div>Not synced with canvas</div>
|
||||
}
|
||||
<div>
|
||||
Rubric:
|
||||
<div class="text-center">
|
||||
Rubric
|
||||
</div>
|
||||
@foreach(var rubricItem in Assignment.rubric)
|
||||
{
|
||||
@@ -162,6 +162,15 @@
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div>Submission Types:</div>
|
||||
<ul>
|
||||
@foreach(var type in Assignment.submission_types)
|
||||
{
|
||||
<li>
|
||||
@type
|
||||
</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
private string name { get; set; } = String.Empty;
|
||||
private bool lockAtDueDate { get; set; }
|
||||
private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>();
|
||||
private IEnumerable<SubmissionType> submissionTypes { get; set; } = Enumerable.Empty<SubmissionType>();
|
||||
|
||||
protected override void OnParametersSet()
|
||||
{
|
||||
@@ -38,6 +39,7 @@
|
||||
description = Assignment.description;
|
||||
lockAtDueDate = Assignment.lock_at_due_date;
|
||||
rubric = Assignment.rubric;
|
||||
submissionTypes = Assignment.submission_types;
|
||||
}
|
||||
|
||||
private void submitHandler()
|
||||
@@ -53,6 +55,7 @@
|
||||
lock_at_due_date=lockAtDueDate,
|
||||
rubric=rubric,
|
||||
points_possible=totalRubricPoints,
|
||||
submission_types=submissionTypes,
|
||||
};
|
||||
|
||||
if(planner.LocalCourse != null)
|
||||
@@ -128,6 +131,10 @@
|
||||
</label>
|
||||
</div>
|
||||
<RubricEditor Rubric="rubric" SetRubric="updateRubric" />
|
||||
<SubmissionTypeSelector
|
||||
Types="submissionTypes"
|
||||
SetTypes="(newTypes) => submissionTypes = newTypes"
|
||||
/>
|
||||
</form>
|
||||
</Body>
|
||||
<Footer>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
@code
|
||||
{
|
||||
[Parameter, EditorRequired]
|
||||
public IEnumerable<SubmissionType> Types { get; set; } = Enumerable.Empty<SubmissionType>();
|
||||
|
||||
[Parameter, EditorRequired]
|
||||
public Action<IEnumerable<SubmissionType>> SetTypes { get; set; } = (_) => {};
|
||||
private string getLabel(SubmissionType type)
|
||||
{
|
||||
return type.ToString().Replace("_", "") + "switch";
|
||||
}
|
||||
}
|
||||
|
||||
<h5>Submission Types</h5>
|
||||
<div class="row">
|
||||
|
||||
@foreach (var submissionType in (SubmissionType[])Enum.GetValues(typeof(SubmissionType)))
|
||||
{
|
||||
<div class="col-4">
|
||||
<div class="form-check form-switch">
|
||||
<input
|
||||
class="form-check-input"
|
||||
type="checkbox"
|
||||
role="switch"
|
||||
id="@getLabel(submissionType)"
|
||||
checked="@Types.Contains(submissionType)"
|
||||
@onchange="(e) => {
|
||||
var isChecked = (bool)(e.Value ?? false);
|
||||
if(isChecked)
|
||||
SetTypes(Types.Append(submissionType));
|
||||
else
|
||||
SetTypes(Types.Where(t => t != submissionType));
|
||||
}"
|
||||
>
|
||||
<label
|
||||
class="form-check-label"
|
||||
for="@getLabel(submissionType)"
|
||||
>
|
||||
@submissionType
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,122 @@
|
||||
@using Management.Web.Shared.Components
|
||||
|
||||
|
||||
@inject CoursePlanner planner
|
||||
|
||||
@code
|
||||
{
|
||||
private Modal modal { get; set; } = default!;
|
||||
private string newTemplateName { get; set; } = "";
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
planner.StateHasChanged += reload;
|
||||
}
|
||||
private void reload()
|
||||
{
|
||||
this.InvokeAsync(this.StateHasChanged);
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
planner.StateHasChanged -= reload;
|
||||
}
|
||||
|
||||
private string? _selectedTemplateId;
|
||||
private string? selectedTemplateId
|
||||
{
|
||||
get { return _selectedTemplateId; }
|
||||
set { _selectedTemplateId = value; }
|
||||
}
|
||||
|
||||
|
||||
private AssignmentTemplate? selectedTemplate =>
|
||||
planner
|
||||
.LocalCourse?
|
||||
.AssignmentTemplates
|
||||
.FirstOrDefault(t => t.Id == selectedTemplateId);
|
||||
|
||||
private void newTemplate()
|
||||
{
|
||||
if (planner.LocalCourse != null)
|
||||
{
|
||||
var newOne = new AssignmentTemplate()
|
||||
{
|
||||
Id=Guid.NewGuid().ToString(),
|
||||
Name=newTemplateName
|
||||
};
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
AssignmentTemplates = planner.LocalCourse.AssignmentTemplates.Append(newOne)
|
||||
};
|
||||
newTemplateName = "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
@onclick="@(() => modal.Show())"
|
||||
>
|
||||
Manage Assignment Templates
|
||||
</button>
|
||||
|
||||
@if(planner.LocalCourse != null)
|
||||
{
|
||||
<Modal @ref="modal">
|
||||
<Title>
|
||||
<h1>Assignment Templates</h1>
|
||||
</Title>
|
||||
<Body>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<form @onsubmit:preventDefault="true">
|
||||
<label for="termselect">Templates</label>
|
||||
<select id="termselect" class="form-select" @bind="selectedTemplateId">
|
||||
<option></option>
|
||||
@foreach (var template in planner.LocalCourse.AssignmentTemplates)
|
||||
{
|
||||
<option value="@template.Id">@template.Name</option>
|
||||
}
|
||||
</select>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col-auto my-auto">
|
||||
<form
|
||||
@onsubmit:preventDefault="true"
|
||||
@onsubmit="newTemplate"
|
||||
>
|
||||
<label
|
||||
class="form-label"
|
||||
for="newTemplateName"
|
||||
>
|
||||
New Template Name
|
||||
</label>
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
@bind="newTemplateName"
|
||||
@bind:event="oninput"
|
||||
/>
|
||||
<button
|
||||
class="btn btn-outline-primary"
|
||||
>
|
||||
New Template
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@if(selectedTemplate != null)
|
||||
{
|
||||
<TemplateEditor Template="selectedTemplate" />
|
||||
}
|
||||
</Body>
|
||||
<Footer>
|
||||
<button
|
||||
class="btn btn-outline-secondary"
|
||||
@onclick="@(() => modal.Hide())"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</Footer>
|
||||
</Modal>
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
@using Markdig
|
||||
|
||||
@inject CoursePlanner planner
|
||||
|
||||
@code
|
||||
{
|
||||
[Parameter, EditorRequired]
|
||||
public AssignmentTemplate Template { get; set; } = default!;
|
||||
|
||||
string markdownHtml = "";
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
}
|
||||
public string Preview => Markdown.ToHtml(Template.Markdown);
|
||||
|
||||
private void SetName(string newName)
|
||||
{
|
||||
if(planner.LocalCourse != null)
|
||||
{
|
||||
var newTemplates = planner.LocalCourse.AssignmentTemplates.Select(t =>
|
||||
t.Id == Template.Id
|
||||
? t with { Name=newName }
|
||||
: t
|
||||
);
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
AssignmentTemplates=newTemplates
|
||||
};
|
||||
}
|
||||
}
|
||||
private void SetMarkdown(string newMarkdown)
|
||||
{
|
||||
if(planner.LocalCourse != null)
|
||||
{
|
||||
var newTemplates = planner.LocalCourse.AssignmentTemplates.Select(t =>
|
||||
t.Id == Template.Id
|
||||
? t with { Markdown=newMarkdown }
|
||||
: t
|
||||
);
|
||||
planner.LocalCourse = planner.LocalCourse with
|
||||
{
|
||||
AssignmentTemplates=newTemplates
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
<div class="row justify-content-center m-3">
|
||||
<div class="col-6">
|
||||
<input
|
||||
class="form-control"
|
||||
type="text"
|
||||
value="@Template.Name"
|
||||
@oninput="@((e) => {
|
||||
var newValue = (string) (e.Value ?? "");
|
||||
SetName(newValue);
|
||||
})"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-6">
|
||||
<textarea
|
||||
rows="30"
|
||||
class="form-control"
|
||||
value="@Template.Markdown"
|
||||
@oninput="@((e) => {
|
||||
var newValue = (string) (e.Value ?? "");
|
||||
SetMarkdown(newValue);
|
||||
})"
|
||||
/>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
@((MarkupString) Preview)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<br>
|
||||
<h5 class="text-center">Detected Template Variables</h5>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto">
|
||||
<ul>
|
||||
@foreach (var variable in AssignmentTemplate.GetVariables(Template.Markdown))
|
||||
{
|
||||
<li>@variable</li>
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user