Missing Assignments Observer
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
New endpoint humans so let's get cooking.
GET /api/v1/users/:user_id/missing_submissions
This endpoint is what I have been needing for some time in K-12. In fact I have had to bake it myself with a now retired c# LTI application that provided the parents with the same information.
proof of concept:
. Enough chat here is the code:
function missingSubmissionsObserver() {
const checkIfNull = async selector => {
while (document.querySelector(selector) === null) {
await new Promise(resolve => requestAnimationFrame(resolve));
}
return document.querySelector(selector);
};
checkIfNull(".recent-activity-header").then(() => {
if (ENV.current_user_roles.includes("observer")) {
const observeePage = document.querySelector(".recent-activity-header");
const fetchObservees = `/api/v1/users/self/observees?per_page=30`;
const options = {
credentials: "same-origin",
headers: { accept: "application/json" },
timeout: 5000
};
let observees;
let dataCollection = [];
let missingSubmissionsContainer;
let observeesListContainer;
const borderStyle =`border-bottom: 1px solid #005299;padding-left:8px;`;
const tableClasses = [`ic-Table`, `ic-Table--condensed`];
const filteringConfig = {
'l8 sub after': `2020-08-01T01:01:01Z`, //ISO or function
'locked for a user': false, //bool
'omit from final grade': false, //bool
'display points possible if greater or equal to': 0, //num
'submittable':`&filter[]=submittable` //either `&filter[]=submittable` || ``
};
//------------------------------------------------------------------
const nextURL = linkTxt => {
if (linkTxt) {
let links = linkTxt.split(",");
let nextRegEx = new RegExp('^<(.*)>; rel="next"$');
for (let i = 0; i < links.length; i++) {
let matches = nextRegEx.exec(links[i]);
if (matches && matches[1]) {
//return right away
//console.log(matches[1]);
return matches[1];
}
}
} else {
return false;
}
};
//--------------------------------------------------------------------
const fetchObserveesID = async () => {
const response = await fetch(fetchObservees, options);
const info = await response.json();
let rsp = {
data: info,
ok: response.ok,
headers: response.headers
};
observees = rsp.data;
};
fetchObserveesID().then(async () => {
observeePage.insertAdjacentHTML( 'beforebegin',
`
<h2 id="being-observed">Students Being Observed</h2>
<a href="/grades" class="Button">View Grades</a>
<div class="gameLoader pacMan"></div>
<br>
<h5>Click a name below to see missing submissions</h5>
<div class="observees-list-container"></div>
<div class="missing-submissions-container"></div>
`
)
;
observeesListContainer = document.querySelector(
".observees-list-container"
);
missingSubmissionsContainer = document.querySelector(
".missing-submissions-container"
);
//LOOP
observees.forEach(kid => {
let missingListItem = document.createElement("li"); //create li
let classesToAddOB = [`Button`]; //add more classes
missingListItem.classList.add(...classesToAddOB);
missingListItem.textContent = `${kid.name}`; //replace
missingListItem.addEventListener(
"click",
async () =>
await addMissingSub(kid.id).then(async () => {
scrubMissingSubs(kid.name);
}),
{ once: true }
);
observeesListContainer.appendChild(missingListItem);
});
});
missingSubmissionsObserver()
NOTES:
The custom loading animation the pacMan, but you can easily replace with the canvas native loader.
/*
_ __ __ _ ___ _ __ ___ __ _ _ __
| '_ \ / _` |/ __| '_ ` _ \ / _` | '_ \
| |_) | (_| | (__| | | | | | (_| | | | |
| .__/ \__,_|\___|_| |_| |_|\__,_|_| |_|
| |
|_|
*/
.gameLoader {
width: 15px;
height: 15px;
position: relative;
display: inline-block;
margin-left: 7px;
}
.gameLoader::before,
.gameLoader::after {
content: "";
position: absolute;
}
.pacMan {
border-radius: 50%;
width: 4px;
height: 4px;
-webkit-animation-name: pacmanDot;
animation-name: pacmanDot;
-webkit-transform: translateX(14px);
transform: translateX(14px);
}
.pacMan::before,
.pacMan::after {
border-radius: 50%;
border: 14px solid #005299;
border-right-color: transparent;
top: -12px;
left: -24px;
}
.pacMan,
.pacMan::before,
.pacMan::after {
-webkit-animation-duration: 0.5s;
animation-duration: 0.5s;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
animation-play-state: var(--playState, paused);
}
.pacMan::before {
-webkit-animation-name: upperJaw;
animation-name: upperJaw;
}
.pacMan::after {
-webkit-animation-name: lowerJaw;
animation-name: lowerJaw;
}
@-webkit-keyframes pacmanDot {
0%,
50% {
background: #008000;
}
51%,
100% {
background: none;
}
0%,
100% {
-webkit-transform: translateX(19px);
transform: translateX(19px);
}
50% {
-webkit-transform: translateX(12px);
transform: translateX(12px);
}
}
@keyframes pacmanDot {
0%,
50% {
background: #008000;
}
51%,
100% {
background: none;
}
0%,
100% {
-webkit-transform: translateX(19px);
transform: translateX(19px);
}
50% {
-webkit-transform: translateX(12px);
transform: translateX(12px);
}
}
@-webkit-keyframes upperJaw {
50% {
-webkit-transform: rotate(50deg) translate(2px, -2px);
transform: rotate(50deg) translate(2px, -2px);
}
}
@keyframes upperJaw {
50% {
-webkit-transform: rotate(50deg) translate(2px, -2px);
transform: rotate(50deg) translate(2px, -2px);
}
}
@-webkit-keyframes lowerJaw {
50% {
-webkit-transform: rotate(-50deg) translate(2px, 2px);
transform: rotate(-50deg) translate(2px, 2px);
}
}
@keyframes lowerJaw {
50% {
-webkit-transform: rotate(-50deg) translate(2px, 2px);
transform: rotate(-50deg) translate(2px, 2px);
}
}
- there is a bit more filtering that is available for the grades displayed it is commented out under the ``` dataCollection ``` filter
- I don't like my appendChild process but it is easier to read that way vs. me extraping and throwing into convoluted functions so I have to force myself to get use to seeing such an eyesore (easier to troubleshoot incase I abandoned ship). But I probably will anyway it hurts my soul...
Edit: 2020-02-15T15:58:38Z implemented proposed changes @r_carroll the var is filteringConfig