mirror of
https://github.com/alexmickelson/canvasManagement.git
synced 2026-03-25 23:28:33 -06:00
added template editor
This commit is contained in:
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="dotenv.net" Version="3.1.2" />
|
<PackageReference Include="dotenv.net" Version="3.1.2" />
|
||||||
|
<PackageReference Include="Markdig" Version="0.31.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
@page "/"
|
@page "/"
|
||||||
@using CanvasModel.EnrollmentTerms
|
@using CanvasModel.EnrollmentTerms
|
||||||
@using Management.Web.Shared.Course
|
@using Management.Web.Shared.Course
|
||||||
|
@using Management.Web.Shared.Module.Assignment.Templates
|
||||||
@using Management.Web.Shared.Semester
|
@using Management.Web.Shared.Semester
|
||||||
@using CanvasModel.Courses
|
@using CanvasModel.Courses
|
||||||
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
|
@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
|
||||||
@using LocalModels
|
@using LocalModels
|
||||||
|
@using Management.Web.Shared.Module.Assignment
|
||||||
|
|
||||||
@inject CanvasService canvas
|
@inject CanvasService canvas
|
||||||
@inject CoursePlanner planner
|
@inject CoursePlanner planner
|
||||||
@@ -63,13 +65,15 @@ protected override void OnInitialized()
|
|||||||
|
|
||||||
@if(planner.LocalCourse != null)
|
@if(planner.LocalCourse != null)
|
||||||
{
|
{
|
||||||
<div class="">
|
<div class="mb-3">
|
||||||
<button
|
<button
|
||||||
@onclick="@(() => planner.LocalCourse = null)"
|
@onclick="@(() => planner.LocalCourse = null)"
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
>
|
>
|
||||||
Select New Course
|
Select New Course
|
||||||
</button>
|
</button>
|
||||||
|
<CourseSettings />
|
||||||
|
<AssignmentTemplateManagement />
|
||||||
</div>
|
</div>
|
||||||
<CourseDetails />
|
<CourseDetails />
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div class="modal @modalClass">
|
<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-content">
|
||||||
<div class="modal-header">
|
<div class="modal-header">
|
||||||
<h4 class="modal-title text-center w-100">@Title</h4>
|
<h4 class="modal-title text-center w-100">@Title</h4>
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
private bool showEditCourseSettings = false;
|
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
planner.StateHasChanged += reload;
|
planner.StateHasChanged += reload;
|
||||||
@@ -21,22 +20,7 @@
|
|||||||
planner.StateHasChanged -= reload;
|
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">
|
<div class="row">
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
@code
|
@code
|
||||||
{
|
{
|
||||||
|
private Modal modal { get; set; } = default!;
|
||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
planner.StateHasChanged += reload;
|
planner.StateHasChanged += reload;
|
||||||
@@ -25,7 +26,6 @@
|
|||||||
_selectedTermId = value;
|
_selectedTermId = value;
|
||||||
if(selectedTerm != null && planner.LocalCourse != null)
|
if(selectedTerm != null && planner.LocalCourse != null)
|
||||||
{
|
{
|
||||||
System.Console.WriteLine(JsonSerializer.Serialize(selectedTerm));
|
|
||||||
planner.LocalCourse = planner.LocalCourse with
|
planner.LocalCourse = planner.LocalCourse with
|
||||||
{
|
{
|
||||||
StartDate=selectedTerm.StartAt ?? new DateTime(),
|
StartDate=selectedTerm.StartAt ?? new DateTime(),
|
||||||
@@ -52,82 +52,102 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
<h5>Select Days Of Week</h5>
|
<button
|
||||||
<div class="row m-3">
|
class="btn btn-outline-secondary"
|
||||||
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
|
@onclick="@(() => modal.Show())"
|
||||||
{
|
>
|
||||||
<div class="col">
|
Edit Course Settings
|
||||||
<button
|
</button>
|
||||||
class="@(
|
|
||||||
planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false
|
<Modal @ref="modal">
|
||||||
? "btn btn-secondary"
|
<Title>
|
||||||
: "btn btn-outline-secondary"
|
<h1>Course Settings</h1>
|
||||||
)"
|
</Title>
|
||||||
@onclick="() =>
|
<Body>
|
||||||
{
|
<h5 class="text-center">Select Days Of Week</h5>
|
||||||
if(planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false)
|
<div class="row m-3">
|
||||||
{
|
@foreach (DayOfWeek day in (DayOfWeek[])Enum.GetValues(typeof(DayOfWeek)))
|
||||||
planner.LocalCourse = planner.LocalCourse with
|
{
|
||||||
|
<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)
|
if(planner.LocalCourse?.DaysOfWeek.Contains(day) ?? false)
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (planner.LocalCourse != null)
|
|
||||||
{
|
|
||||||
planner.LocalCourse = planner.LocalCourse with
|
|
||||||
{
|
{
|
||||||
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Append(day)
|
planner.LocalCourse = planner.LocalCourse with
|
||||||
};
|
{
|
||||||
}
|
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Where((d) => d != day)
|
||||||
}
|
};
|
||||||
}"
|
}
|
||||||
>
|
else
|
||||||
@day
|
{
|
||||||
</button>
|
if (planner.LocalCourse != null)
|
||||||
|
{
|
||||||
|
planner.LocalCourse = planner.LocalCourse with
|
||||||
|
{
|
||||||
|
DaysOfWeek = planner.LocalCourse.DaysOfWeek.Append(day)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
@day
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@if(loading)
|
@if(loading)
|
||||||
{
|
{
|
||||||
<Spinner />
|
<Spinner />
|
||||||
}
|
}
|
||||||
|
|
||||||
@if (terms != null)
|
@if (terms != null)
|
||||||
{
|
{
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<form>
|
<form @onsubmit:preventDefault="true">
|
||||||
<lablel for="termselect">Select Term for Start and End Date:</lablel>
|
<label for="termselect">Select Term for Start and End Date:</label>
|
||||||
<select id="termselect" class="form-select" @bind="selectedTermId">
|
<select id="termselect" class="form-select" @bind="selectedTermId">
|
||||||
@foreach (var term in terms)
|
@foreach (var term in terms)
|
||||||
{
|
{
|
||||||
<option value="@term.Id">@term.Name</option>
|
<option value="@term.Id">@term.Name</option>
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@if(planner.LocalCourse != null)
|
@if(planner.LocalCourse != null)
|
||||||
{
|
{
|
||||||
<div class="row justify-content-center m-3 text-center">
|
<div class="row justify-content-center m-3 text-center">
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<div>Default Assignment Due Time</div>
|
<div>Default Assignment Due Time</div>
|
||||||
<TimePicker
|
<TimePicker
|
||||||
Time="planner.LocalCourse.DefaultDueTime"
|
Time="planner.LocalCourse.DefaultDueTime"
|
||||||
UpdateTime="@((newTime) =>
|
UpdateTime="@((newTime) =>
|
||||||
planner.LocalCourse =
|
planner.LocalCourse =
|
||||||
planner.LocalCourse with
|
planner.LocalCourse with
|
||||||
{ DefaultDueTime=newTime }
|
{ DefaultDueTime=newTime }
|
||||||
)"
|
)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
</Body>
|
||||||
<br>
|
<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>Not synced with canvas</div>
|
||||||
}
|
}
|
||||||
<div>
|
<div class="text-center">
|
||||||
Rubric:
|
Rubric
|
||||||
</div>
|
</div>
|
||||||
@foreach(var rubricItem in Assignment.rubric)
|
@foreach(var rubricItem in Assignment.rubric)
|
||||||
{
|
{
|
||||||
@@ -162,6 +162,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
<div>Submission Types:</div>
|
||||||
|
<ul>
|
||||||
|
@foreach(var type in Assignment.submission_types)
|
||||||
|
{
|
||||||
|
<li>
|
||||||
|
@type
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
private string name { get; set; } = String.Empty;
|
private string name { get; set; } = String.Empty;
|
||||||
private bool lockAtDueDate { get; set; }
|
private bool lockAtDueDate { get; set; }
|
||||||
private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>();
|
private IEnumerable<RubricItem> rubric { get; set; } = Enumerable.Empty<RubricItem>();
|
||||||
|
private IEnumerable<SubmissionType> submissionTypes { get; set; } = Enumerable.Empty<SubmissionType>();
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
@@ -38,6 +39,7 @@
|
|||||||
description = Assignment.description;
|
description = Assignment.description;
|
||||||
lockAtDueDate = Assignment.lock_at_due_date;
|
lockAtDueDate = Assignment.lock_at_due_date;
|
||||||
rubric = Assignment.rubric;
|
rubric = Assignment.rubric;
|
||||||
|
submissionTypes = Assignment.submission_types;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void submitHandler()
|
private void submitHandler()
|
||||||
@@ -53,6 +55,7 @@
|
|||||||
lock_at_due_date=lockAtDueDate,
|
lock_at_due_date=lockAtDueDate,
|
||||||
rubric=rubric,
|
rubric=rubric,
|
||||||
points_possible=totalRubricPoints,
|
points_possible=totalRubricPoints,
|
||||||
|
submission_types=submissionTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
if(planner.LocalCourse != null)
|
if(planner.LocalCourse != null)
|
||||||
@@ -128,6 +131,10 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<RubricEditor Rubric="rubric" SetRubric="updateRubric" />
|
<RubricEditor Rubric="rubric" SetRubric="updateRubric" />
|
||||||
|
<SubmissionTypeSelector
|
||||||
|
Types="submissionTypes"
|
||||||
|
SetTypes="(newTypes) => submissionTypes = newTypes"
|
||||||
|
/>
|
||||||
</form>
|
</form>
|
||||||
</Body>
|
</Body>
|
||||||
<Footer>
|
<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>
|
||||||
18
Management/Models/Local/AssignmentTemplate.cs
Normal file
18
Management/Models/Local/AssignmentTemplate.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace LocalModels;
|
||||||
|
|
||||||
|
public record AssignmentTemplate
|
||||||
|
{
|
||||||
|
public string Id { get; set; } = String.Empty;
|
||||||
|
public string Name { get; set; } = String.Empty;
|
||||||
|
public string Markdown { get; set; } = String.Empty;
|
||||||
|
|
||||||
|
public static IEnumerable<string> GetVariables(string markdown)
|
||||||
|
{
|
||||||
|
string pattern = "{{(.*?)}}";
|
||||||
|
MatchCollection matches = Regex.Matches(markdown, pattern);
|
||||||
|
|
||||||
|
return matches.Select(match => match.Groups[1].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,16 +8,16 @@ public record RubricItem
|
|||||||
|
|
||||||
public enum SubmissionType
|
public enum SubmissionType
|
||||||
{
|
{
|
||||||
|
online_text_entry,
|
||||||
|
online_upload,
|
||||||
online_quiz,
|
online_quiz,
|
||||||
none,
|
|
||||||
on_paper,
|
on_paper,
|
||||||
discussion_topic,
|
discussion_topic,
|
||||||
external_tool,
|
external_tool,
|
||||||
online_upload,
|
|
||||||
online_text_entry,
|
|
||||||
online_url,
|
online_url,
|
||||||
media_recording,
|
media_recording,
|
||||||
student_annotation,
|
student_annotation,
|
||||||
|
none,
|
||||||
}
|
}
|
||||||
|
|
||||||
public record LocalAssignment
|
public record LocalAssignment
|
||||||
@@ -9,6 +9,8 @@ public record LocalCourse
|
|||||||
public DateTime StartDate { get; init; }
|
public DateTime StartDate { get; init; }
|
||||||
public DateTime EndDate { get; init; }
|
public DateTime EndDate { get; init; }
|
||||||
public SimpleTimeOnly DefaultDueTime { get; init; } = new SimpleTimeOnly();
|
public SimpleTimeOnly DefaultDueTime { get; init; } = new SimpleTimeOnly();
|
||||||
|
public IEnumerable<AssignmentTemplate> AssignmentTemplates { get; init; } =
|
||||||
|
Enumerable.Empty<AssignmentTemplate>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public record SimpleTimeOnly
|
public record SimpleTimeOnly
|
||||||
|
|||||||
35
tmp.json
Normal file
35
tmp.json
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"id": 753,
|
||||||
|
"name": "Summer 2023",
|
||||||
|
"sis_term_id": null,
|
||||||
|
"sis_import_id": null,
|
||||||
|
"start_at": "2023-05-10T06:00:00Z",
|
||||||
|
"end_at": "2023-07-29T05:59:59Z",
|
||||||
|
"grading_period_group_id": null,
|
||||||
|
"workflow_state": "active",
|
||||||
|
"overrides": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 751,
|
||||||
|
"name": "Fall 2023",
|
||||||
|
"sis_term_id": null,
|
||||||
|
"sis_import_id": null,
|
||||||
|
"start_at": "2023-08-21T06:00:00Z",
|
||||||
|
"end_at": "2023-12-15T06:59:59Z",
|
||||||
|
"grading_period_group_id": null,
|
||||||
|
"workflow_state": "active",
|
||||||
|
"overrides": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 773,
|
||||||
|
"name": "Spring 2024",
|
||||||
|
"sis_term_id": null,
|
||||||
|
"sis_import_id": null,
|
||||||
|
"start_at": "2024-01-02T00:00:00Z",
|
||||||
|
"end_at": "2024-04-26T00:00:00Z",
|
||||||
|
"grading_period_group_id": null,
|
||||||
|
"workflow_state": "active",
|
||||||
|
"overrides": null
|
||||||
|
}
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user