18C / Task Bar

// ==UserScript==
// @name        Task Bar
// @namespace   CCAU
// @description Automate course copies
// @match       https://*.instructure.com/courses/*
// @version     0.2.1
// @author      Cappiebara
// @grant       none
// @license     GPL-3.0-or-later
// ==/UserScript==
"use strict";
(() => {
  // out/ccau.js
  function isAdmin() {
    const adminButton = document.querySelector("#global_nav_accounts_link");
    return adminButton ? true : false;
  }
  function getCourseID() {
    return window.location.href.match(/courses\/(\d+)/)?.[1] ?? "NO_COURSE_ID";
  }
  async function isLiveCourse() {
    const response = await fetch("https://se.instructure.com/api/v1/courses/" + getCourseID());
    const data = await response.json();
    if (!data.start_at) {
      return new Promise((resolve) => resolve(false));
    }
    return new Date(data.start_at) < /* @__PURE__ */ new Date();
  }

  // out/task.js
  function getTasks() {
    return TASKS.tasks;
  }
  var TASKS = {
    "tasks": [
      {
        "help": "Click the --> button to start the copy",
        "name": "Begin Course Copy",
        "path": ""
      },
      {
        "help": "If there is any content, don't do the copy",
        "name": "Check for Content",
        "path": "modules"
      },
      {
        "help": "Delete 'Student Introductions' and 'Questions and Answers'",
        "name": "Delete Discussions",
        "path": "discussion_topics"
      },
      {
        "help": "Delete all pages except University Information",
        "name": "Delete Pages",
        "path": "pages"
      },
      {
        "help": "Double check the email to make sure you copy the right course",
        "name": "Copy Content",
        "path": "content_migrations"
      },
      {
        "help": "Copy the current holiday from the SE University Holidays course (select content)",
        "name": "Copy Holiday",
        "path": "content_migrations"
      },
      {
        "help": "Delete any duplicate menu items. The original item is the first one listed",
        "name": "Delete Duplicate Menu Items",
        "path": "settings/configurations#tab-tools"
      },
      {
        "help": "Move the items in the navigation menu to this order:\n\nHome\nAnnouncements\nSyllabus\nModules\nGrades\nSubmit Grades\nPeople\nSE Email\nHenry G. Bennett Library\nTech Support\nTutor.com\nYuJa\nPanorama\nLockdown Browser\nItem Banks\nCredentials\nFollett Discover\n(whatever else happens to be there)\n",
        "name": "Fix Menu Order",
        "path": "settings#tab-navigation"
      },
      {
        "help": "Click the Auto-Move button, then the arrow in the bottom left",
        "name": "Move Content",
        "path": "modules"
      },
      {
        "help": "Click the Remove Empty button, then the arrow in the bottom left",
        "name": "Delete Empty Modules",
        "path": "modules"
      },
      {
        "help": "Click the Add Dates button and wait for them to publish and move into place",
        "name": "Add Date Headers",
        "path": "modules"
      },
      {
        "help": "Delete any GOLD Orientation and the University Information items which are NOT at the bottom of the START HERE module",
        "name": "Delete Old START HERE Items",
        "path": "modules"
      },
      {
        "help": "Move the holiday module into place",
        "name": "Move Holiday",
        "path": "modules"
      },
      {
        "help": "Delete any undeployed GOLD Orientation assignments and empty categories",
        "name": "Delete Old GOLD and Empty Groups",
        "path": "assignments"
      },
      {
        "help": "Use https://k.ngn.tf/8775a to fix broken images; manually fix broken module links",
        "name": "Fix Homepage",
        "path": "wiki"
      },
      {
        "help": "Make sure the dates are correct, especially regarding the holiday-adjacent weeks",
        "name": "Check Assignment Dates",
        "path": "assignments"
      },
      {
        "help": "Check for Blackboard references, as well as getting the grade total / weights",
        "name": "Check Syllabus",
        "path": "assignments/syllabus"
      },
      {
        "help": "Make sure it matches the syllabus",
        "name": "Check Gradebook",
        "path": "gradebook"
      },
      {
        "help": "If any real links are broken, inform the professor",
        "name": "Run Link Validator",
        "path": "link_validator"
      },
      {
        "help": "Ensure that all the steps on the Google Sheet have been followed. If something there isn't covered in the automation, lmk",
        "name": "Check Google Sheet",
        "path": ""
      },
      {
        "help": "Excellent work, 47. The money has been wired to your account",
        "name": "Done",
        "path": ""
      }
    ]
  };

  // out/ui.js
  function addButton(task, fn, label) {
    const slot = document.querySelector(".right-of-crumbs");
    const button = document.createElement("a");
    button.textContent = label;
    button.classList.add("btn");
    button.setAttribute("tabindex", "0");
    button.addEventListener("click", fn, false);
    button.setAttribute("title", task.help);
    slot?.insertAdjacentElement("beforebegin", button);
  }
  function goto(path_) {
    const id = getCourseID();
    const newLoc = `https://se.instructure.com/courses/${id}/${path_}`;
    if (window.location.href === newLoc) {
      window.location.reload();
    } else {
      window.location.href = newLoc;
    }
  }
  function getCurrentTask() {
    const id = getCourseID();
    const taskNum = Number(localStorage.getItem(`ccau_${id}_task`));
    return isNaN(taskNum) ? null : taskNum;
  }
  function setCurrentTask(taskNum) {
    const id = getCourseID();
    localStorage.setItem(`ccau_${id}_task`, taskNum.toString());
  }

  // out/index.js
  async function main() {
    if (!isAdmin()) {
      throw new Error("Only admins can use CCAU");
    }
    if (await isLiveCourse()) {
      throw new Error("CCAU is disabled in live courses");
    }
    const tasks = getTasks();
    const taskNum = getCurrentTask() ?? 0;
    const task = tasks[taskNum];
    const prevNum = Math.max(0, taskNum - 1);
    const prev = tasks[prevNum];
    const nextNum = (taskNum + 1) % tasks.length;
    const next = tasks[nextNum];
    addButton(prev, () => {
      setCurrentTask(prevNum);
      goto(prev.path);
    }, "<--");
    addButton(task, () => {
      alert(task.help);
    }, task.name);
    addButton(next, () => {
      setCurrentTask(nextNum);
      goto(next.path);
    }, "-->");
  }
  main();
})();