diff --git a/teachertool/src/App.tsx b/teachertool/src/App.tsx index 13a9b3bf439..ad3e94198a9 100644 --- a/teachertool/src/App.tsx +++ b/teachertool/src/App.tsx @@ -11,8 +11,8 @@ import { Toasts } from "./components/Toasts"; import { showToast } from "./transforms/showToast"; import { loadCatalogAsync } from "./transforms/loadCatalogAsync"; import { loadValidatorPlansAsync } from "./transforms/loadValidatorPlansAsync"; -import { tryLoadLastActiveRubricAsync } from "./transforms/tryLoadLastActiveRubricAsync"; -import { ImportRubricModal } from "./components/ImportRubricModal"; +import { tryLoadLastActiveChecklistAsync } from "./transforms/tryLoadLastActiveChecklistAsync"; +import { ImportChecklistModal } from "./components/ImportChecklistModal"; import { ConfirmationModal } from "./components/ConfirmationModal"; import { BlockPickerModal } from "./components/BlockPickerModal"; import { ScreenReaderAnnouncer } from "./components/ScreenReaderAnnouncer"; @@ -33,7 +33,7 @@ export const App = () => { // Load catalog and validator plans into state. await loadCatalogAsync(); await loadValidatorPlansAsync(); - await tryLoadLastActiveRubricAsync(); + await tryLoadLastActiveChecklistAsync(); // Test notification showToast({ @@ -57,7 +57,7 @@ export const App = () => { <> - + diff --git a/teachertool/src/components/ActiveRubricDisplay.tsx b/teachertool/src/components/ActiveChecklistDisplay.tsx similarity index 53% rename from teachertool/src/components/ActiveRubricDisplay.tsx rename to teachertool/src/components/ActiveChecklistDisplay.tsx index 362913185ee..5c91d03bcc2 100644 --- a/teachertool/src/components/ActiveRubricDisplay.tsx +++ b/teachertool/src/components/ActiveChecklistDisplay.tsx @@ -1,28 +1,28 @@ import { useContext } from "react"; import { Strings } from "../constants"; import { AppStateContext } from "../state/appStateContext"; -import { setRubricName } from "../transforms/setRubricName"; +import { setChecklistName } from "../transforms/setChecklistName"; import { DebouncedInput } from "./DebouncedInput"; import { AddCriteriaButton } from "./AddCriteriaButton"; -import css from "./styling/ActiveRubricDisplay.module.scss"; +import css from "./styling/ActiveChecklistDisplay.module.scss"; import React from "react"; import { CriteriaTable } from "./CriteriaTable"; -interface ActiveRubricDisplayProps {} -export const ActiveRubricDisplay: React.FC = ({}) => { +interface ActiveChecklistDisplayProps {} +export const ActiveChecklistDisplay: React.FC = ({}) => { const { state: teacherTool } = useContext(AppStateContext); return ( -
-
+
+
diff --git a/teachertool/src/components/CatalogOverlay.tsx b/teachertool/src/components/CatalogOverlay.tsx index d3eeb93afc2..f01a244aaf5 100644 --- a/teachertool/src/components/CatalogOverlay.tsx +++ b/teachertool/src/components/CatalogOverlay.tsx @@ -1,6 +1,6 @@ import { useContext, useMemo, useState } from "react"; import { AppStateContext } from "../state/appStateContext"; -import { addCriteriaToRubric } from "../transforms/addCriteriaToRubric"; +import { addCriteriaToChecklist } from "../transforms/addCriteriaToChecklist"; import { CatalogCriteria } from "../types/criteria"; import { getCatalogCriteria } from "../state/helpers"; import { ReadOnlyCriteriaDisplay } from "./ReadonlyCriteriaDisplay"; @@ -75,7 +75,7 @@ const CatalogList: React.FC = () => { const criteria = useMemo( () => getCatalogCriteria(teacherTool), - [teacherTool.catalog, teacherTool.rubric] + [teacherTool.catalog, teacherTool.checklist] ); function updateRecentlyAddedValue(id: string, value: NodeJS.Timeout | undefined) { @@ -91,7 +91,7 @@ const CatalogList: React.FC = () => { } function onItemClicked(c: CatalogCriteria) { - addCriteriaToRubric([c.id]); + addCriteriaToChecklist([c.id]); // Set a timeout to remove the recently added indicator // and save it in the state. @@ -109,7 +109,7 @@ const CatalogList: React.FC = () => { return (
{criteria.map(c => { - const existingInstanceCount = teacherTool.rubric.criteria.filter( + const existingInstanceCount = teacherTool.checklist.criteria.filter( i => i.catalogCriteriaId === c.id ).length; const isMaxed = c.maxCount !== undefined && existingInstanceCount >= c.maxCount; diff --git a/teachertool/src/components/ChecklistPreview.tsx b/teachertool/src/components/ChecklistPreview.tsx new file mode 100644 index 00000000000..a94ad2d96d7 --- /dev/null +++ b/teachertool/src/components/ChecklistPreview.tsx @@ -0,0 +1,23 @@ +import { getCatalogCriteriaWithId } from "../state/helpers"; +import { Checklist } from "../types/checklist"; +import css from "./styling/ChecklistPreview.module.scss"; + +export interface IChecklistPreviewProps { + checklist: Checklist; +} + +export const ChecklistPreview: React.FC = ({ checklist }) => { + return ( +
+
{checklist.name}
+ {checklist.criteria.map((c, i) => { + const template = getCatalogCriteriaWithId(c.catalogCriteriaId)?.template; + return template ? ( +
+ {template} +
+ ) : null; + })} +
+ ); +}; diff --git a/teachertool/src/components/RubricWorkspace.tsx b/teachertool/src/components/ChecklistWorkspace.tsx similarity index 68% rename from teachertool/src/components/RubricWorkspace.tsx rename to teachertool/src/components/ChecklistWorkspace.tsx index 107cea484ec..5b11b5f1dc1 100644 --- a/teachertool/src/components/RubricWorkspace.tsx +++ b/teachertool/src/components/ChecklistWorkspace.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import css from "./styling/RubricWorkspace.module.scss"; +import css from "./styling/ChecklistWorkspace.module.scss"; import { useContext, useRef } from "react"; import { AppStateContext, stateAndDispatch } from "../state/appStateContext"; import { Toolbar } from "./Toolbar"; @@ -7,33 +7,33 @@ import { TabGroup, TabButton } from "./TabGroup"; import { TabPanel } from "./TabPanel"; import { HomeScreen } from "./HomeScreen"; import { EvalResultDisplay } from "./EvalResultDisplay"; -import { ActiveRubricDisplay } from "./ActiveRubricDisplay"; +import { ActiveChecklistDisplay } from "./ActiveChecklistDisplay"; import { MenuItem } from "react-common/components/controls/MenuDropdown"; import { TabName } from "../types"; import { runEvaluateAsync } from "../transforms/runEvaluateAsync"; -import { writeRubricToFile } from "../services/fileSystemService"; +import { writeChecklistToFile } from "../services/fileSystemService"; import { showModal } from "../transforms/showModal"; import { isProjectLoaded } from "../state/helpers"; import { setAutorun } from "../transforms/setAutorun"; import { Strings, Ticks } from "../constants"; -import { resetRubricAsync } from "../transforms/resetRubricAsync"; +import { resetChecklistAsync } from "../transforms/resetChecklistAsync"; import { PrintButton } from "./PrintButton"; -import { ImportRubricOptions } from "../types/modalOptions"; +import { ImportChecklistOptions } from "../types/modalOptions"; -function handleImportRubricClicked() { - pxt.tickEvent(Ticks.ImportRubric); - showModal({ modal: "import-rubric" } as ImportRubricOptions); +function handleImportChecklistClicked() { + pxt.tickEvent(Ticks.ImportChecklist); + showModal({ modal: "import-checklist" } as ImportChecklistOptions); } -function handleExportRubricClicked() { - pxt.tickEvent(Ticks.ExportRubric); +function handleExportChecklistClicked() { + pxt.tickEvent(Ticks.ExportChecklist); const { state: teacherTool } = stateAndDispatch(); - writeRubricToFile(teacherTool.rubric); + writeChecklistToFile(teacherTool.checklist); } -async function handleNewRubricClickedAsync() { - pxt.tickEvent(Ticks.NewRubric); - await resetRubricAsync(); +async function handleNewChecklistClickedAsync() { + pxt.tickEvent(Ticks.NewChecklist); + await resetChecklistAsync(); } async function handleEvaluateClickedAsync() { @@ -46,8 +46,8 @@ const WorkspaceTabButtons: React.FC = () => { return ( - {lf("Home")} - {lf("Rubric")} + {Strings.Home} + {Strings.Checklist} {lf("Results")} @@ -65,8 +65,8 @@ const WorkspaceTabPanels: React.FC = ({ resultsRef }) = - - + + @@ -79,25 +79,25 @@ function getActionMenuItems(tab: TabName): MenuItem[] { const items: MenuItem[] = []; switch (tab) { case "home": - case "rubric": + case "checklist": items.push( { - title: Strings.NewRubric, - label: Strings.NewRubric, - ariaLabel: Strings.NewRubric, - onClick: handleNewRubricClickedAsync, + title: Strings.NewChecklist, + label: Strings.NewChecklist, + ariaLabel: Strings.NewChecklist, + onClick: handleNewChecklistClickedAsync, }, { - title: Strings.ImportRubric, - label: Strings.ImportRubric, - ariaLabel: Strings.ImportRubric, - onClick: handleImportRubricClicked, + title: Strings.ImportChecklist, + label: Strings.ImportChecklist, + ariaLabel: Strings.ImportChecklist, + onClick: handleImportChecklistClicked, }, { - title: Strings.ExportRubric, - label: Strings.ExportRubric, - ariaLabel: Strings.ExportRubric, - onClick: handleExportRubricClicked, + title: Strings.ExportChecklist, + label: Strings.ExportChecklist, + ariaLabel: Strings.ExportChecklist, + onClick: handleExportChecklistClicked, } ); break; @@ -143,7 +143,7 @@ const WorkspaceToolbarButtons: React.FC = ({ resul ); }; -export const RubricWorkspace: React.FC = () => { +export const ChecklistWorkspace: React.FC = () => { const resultsRef = useRef(null); return (
diff --git a/teachertool/src/components/CriteriaTable.tsx b/teachertool/src/components/CriteriaTable.tsx index 02dd95f69fb..6b8024f03b0 100644 --- a/teachertool/src/components/CriteriaTable.tsx +++ b/teachertool/src/components/CriteriaTable.tsx @@ -2,7 +2,7 @@ import { useContext } from "react"; import { Strings } from "../constants"; import { AppStateContext } from "../state/appStateContext"; import { getCatalogCriteriaWithId } from "../state/helpers"; -import { removeCriteriaFromRubric } from "../transforms/removeCriteriaFromRubric"; +import { removeCriteriaFromChecklist } from "../transforms/removeCriteriaFromChecklist"; import { CriteriaInstance } from "../types/criteria"; import { classList } from "react-common/components/util"; import { Button } from "react-common/components/controls/Button"; @@ -39,7 +39,7 @@ const CriteriaInstanceRow: React.FC = ({ criteriaI className={css["delete-criteria-button"]} title={Strings.Remove} ariaLabel={Strings.Remove} - onClick={() => removeCriteriaFromRubric(criteriaInstance)} + onClick={() => removeCriteriaFromChecklist(criteriaInstance)} />
@@ -50,7 +50,7 @@ interface CriteriaTableProps {} const CriteriaTableControl: React.FC = ({}) => { const { state: teacherTool } = useContext(AppStateContext); - return teacherTool.rubric.criteria?.length > 0 ? ( + return teacherTool.checklist.criteria?.length > 0 ? (
@@ -67,7 +67,7 @@ const CriteriaTableControl: React.FC = ({}) => {
- {teacherTool.rubric.criteria.map(criteriaInstance => { + {teacherTool.checklist.criteria.map(criteriaInstance => { return ( ); diff --git a/teachertool/src/components/DragAndDropFileSurface.tsx b/teachertool/src/components/DragAndDropFileSurface.tsx index a1060fd1a48..2e89bcf5b7c 100644 --- a/teachertool/src/components/DragAndDropFileSurface.tsx +++ b/teachertool/src/components/DragAndDropFileSurface.tsx @@ -85,7 +85,7 @@ export const DragAndDropFileSurface: React.FC = ({ ref={fileInputRef} className="hidden" onChange={handleFileFromBrowse} - aria-label={Strings.SelectRubricFile} + aria-label={Strings.SelectChecklistFile} accept=".json" />
diff --git a/teachertool/src/components/EvalResultDisplay.tsx b/teachertool/src/components/EvalResultDisplay.tsx index 62c95edf495..6d20772996f 100644 --- a/teachertool/src/components/EvalResultDisplay.tsx +++ b/teachertool/src/components/EvalResultDisplay.tsx @@ -11,8 +11,8 @@ const ResultsHeader: React.FC = () => { return (
-
-

{teacherTool.rubric.name}

+
+

{teacherTool.checklist.name}

diff --git a/teachertool/src/components/HeaderBar.tsx b/teachertool/src/components/HeaderBar.tsx index 96e88aae8c7..06ef158d6d3 100644 --- a/teachertool/src/components/HeaderBar.tsx +++ b/teachertool/src/components/HeaderBar.tsx @@ -4,7 +4,6 @@ import css from "./styling/HeaderBar.module.scss"; import { Button } from "react-common/components/controls/Button"; import { MenuBar } from "react-common/components/controls/MenuBar"; import { AppStateContext } from "../state/appStateContext"; -import { getSafeRubricName } from "../state/helpers"; import { Ticks } from "../constants"; interface HeaderBarProps {} diff --git a/teachertool/src/components/HomeScreen.tsx b/teachertool/src/components/HomeScreen.tsx index c0ebebccd2b..6d345ebcfc6 100644 --- a/teachertool/src/components/HomeScreen.tsx +++ b/teachertool/src/components/HomeScreen.tsx @@ -9,23 +9,23 @@ import { Link } from "react-common/components/controls/Link"; import { Button } from "react-common/components/controls/Button"; import { classList } from "react-common/components/util"; import { showModal } from "../transforms/showModal"; -import { resetRubricAsync } from "../transforms/resetRubricAsync"; -import { loadRubricAsync } from "../transforms/loadRubricAsync"; +import { resetChecklistAsync } from "../transforms/resetChecklistAsync"; +import { loadChecklistAsync } from "../transforms/loadChecklistAsync"; import { Constants, Strings, Ticks } from "../constants"; import { Swiper, SwiperSlide } from "swiper/react"; import { Mousewheel, Navigation } from "swiper"; import { AppStateContext } from "../state/appStateContext"; -import { CarouselCardSet, RequestStatus, CarouselRubricResourceCard, CardType } from "../types"; +import { CarouselCardSet, RequestStatus } from "../types"; import { useJsonDocRequest } from "../hooks/useJsonDocRequest"; -import { isRubricResourceCard } from "../utils"; -import { ImportRubricOptions } from "../types/modalOptions"; +import { isChecklistResourceCard } from "../utils"; +import { ImportChecklistOptions } from "../types/modalOptions"; const Welcome: React.FC = () => { return (
-

{lf("Welcome to MakeCode Project Insights!")}

+

{lf("Welcome to MakeCode Code Evaluation!")}

- {lf("This tool is designed to help you evaluate student projects using a rubric.")}{" "} + {lf("This tool is designed to help you evaluate student projects using an automated checklist.")}{" "} {lf("Learn More.")} @@ -80,21 +80,21 @@ const LoadingCard: React.FC = ({ delay }) => { ); }; -interface RubricResourceCardProps { +interface ChecklistResourceCardProps { cardTitle: string; imageUrl: string; - rubricUrl: string; + checklistUrl: string; } -const RubricResourceCard: React.FC = ({ cardTitle, imageUrl, rubricUrl }) => { +const ChecklistResourceCard: React.FC = ({ cardTitle, imageUrl, checklistUrl }) => { const onCardClickedAsync = async () => { - pxt.tickEvent(Ticks.LoadRubric, { rubricUrl }); - await loadRubricAsync(rubricUrl); + pxt.tickEvent(Ticks.LoadChecklist, { checklistUrl }); + await loadChecklistAsync(checklistUrl); }; return (

@@ -201,8 +201,8 @@ const CardCarousel: React.FC = ({ title, cardsUrl }) => { {fetchStatus === "success" && ( {cardSet?.cards.map((card, index) => { - if (isRubricResourceCard(card)) { - return ; + if (isChecklistResourceCard(card)) { + return ; } else { return ; } diff --git a/teachertool/src/components/ImportRubricModal.tsx b/teachertool/src/components/ImportChecklistModal.tsx similarity index 54% rename from teachertool/src/components/ImportRubricModal.tsx rename to teachertool/src/components/ImportChecklistModal.tsx index 0bc07ae187d..ff8ee21c1b7 100644 --- a/teachertool/src/components/ImportRubricModal.tsx +++ b/teachertool/src/components/ImportChecklistModal.tsx @@ -2,15 +2,15 @@ import { useContext, useState } from "react"; import { AppStateContext } from "../state/appStateContext"; import { Modal } from "react-common/components/controls/Modal"; import { hideModal } from "../transforms/hideModal"; -import { getRubricFromFileAsync } from "../transforms/getRubricFromFileAsync"; +import { getChecklistFromFileAsync } from "../transforms/getChecklistFromFileAsync"; import { DragAndDropFileSurface } from "./DragAndDropFileSurface"; import { Strings } from "../constants"; -import css from "./styling/ImportRubricModal.module.scss"; -import { replaceActiveRubricAsync } from "../transforms/replaceActiveRubricAsync"; +import css from "./styling/ImportChecklistModal.module.scss"; +import { replaceActiveChecklistAsync } from "../transforms/replaceActiveChecklistAsync"; export interface IProps {} -export const ImportRubricModal: React.FC = () => { +export const ImportChecklistModal: React.FC = () => { const { state: teacherTool } = useContext(AppStateContext); const [errorMessage, setErrorMessage] = useState(undefined); @@ -20,19 +20,19 @@ export const ImportRubricModal: React.FC = () => { } async function handleFileDroppedAsync(file: File) { - const parsedRubric = await getRubricFromFileAsync(file, false /* allow partial */); - if (!parsedRubric) { - setErrorMessage(Strings.InvalidRubricFile); + const parsedChecklist = await getChecklistFromFileAsync(file, false /* allow partial */); + if (!parsedChecklist) { + setErrorMessage(Strings.InvalidChecklistFile); } else { setErrorMessage(undefined); closeModal(); - replaceActiveRubricAsync(parsedRubric); + replaceActiveChecklistAsync(parsedChecklist); } } - return teacherTool.modalOptions?.modal === "import-rubric" ? ( - -
+ return teacherTool.modalOptions?.modal === "import-checklist" ? ( + +
diff --git a/teachertool/src/components/MainPanel.tsx b/teachertool/src/components/MainPanel.tsx index aef72e4d91d..3cc41a4bd95 100644 --- a/teachertool/src/components/MainPanel.tsx +++ b/teachertool/src/components/MainPanel.tsx @@ -1,7 +1,7 @@ import * as React from "react"; import css from "./styling/MainPanel.module.scss"; import { SplitPane } from "./SplitPane"; -import { RubricWorkspace } from "./RubricWorkspace"; +import { ChecklistWorkspace } from "./ChecklistWorkspace"; import { ProjectWorkspace } from "./ProjectWorkspace"; import { getLastSplitPosition, setLastSplitPosition } from "../services/storageService"; @@ -22,7 +22,7 @@ export const MainPanel: React.FC = () => { defaultSize={defaultSize} startingSize={lastSavedSplitPosition} primary={"left"} - left={} + left={} right={} leftMinSize="5rem" rightMinSize="5rem" diff --git a/teachertool/src/components/PrintButton.tsx b/teachertool/src/components/PrintButton.tsx index f4eb24c43d1..1c73685d595 100644 --- a/teachertool/src/components/PrintButton.tsx +++ b/teachertool/src/components/PrintButton.tsx @@ -5,7 +5,7 @@ import { stateAndDispatch } from "../state"; import { showToast } from "../state/actions"; import { makeToast } from "../utils"; import { Strings } from "../constants"; -import { getSafeRubricName } from "../state/helpers"; +import { getSafeChecklistName } from "../state/helpers"; interface PrintButtonProps { printRef: React.RefObject; @@ -16,7 +16,7 @@ export const PrintButton: React.FC = ({ printRef }) => { const handlePrint = useReactToPrint({ content: () => printRef.current, onPrintError: () => showToast(makeToast("error", lf("Unable to print evaluation results"), 2000)), - documentTitle: `${pxt.Util.sanitizeFileName(getSafeRubricName(teacherTool)!)} - ${pxt.Util.sanitizeFileName( + documentTitle: `${pxt.Util.sanitizeFileName(getSafeChecklistName(teacherTool)!)} - ${pxt.Util.sanitizeFileName( teacherTool.projectMetadata?.name || Strings.UntitledProject )}`, }); diff --git a/teachertool/src/components/RubricPreview.tsx b/teachertool/src/components/RubricPreview.tsx deleted file mode 100644 index 8041bfaabd4..00000000000 --- a/teachertool/src/components/RubricPreview.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { getCatalogCriteriaWithId } from "../state/helpers"; -import { Rubric } from "../types/rubric"; -import css from "./styling/RubricPreview.module.scss"; - -export interface IRubricPreviewProps { - rubric: Rubric; -} - -export const RubricPreview: React.FC = ({ rubric }) => { - return ( -
-
{rubric.name}
- {rubric.criteria.map((c, i) => { - const template = getCatalogCriteriaWithId(c.catalogCriteriaId)?.template; - return template ? ( -
- {template} -
- ) : null; - })} -
- ); -}; diff --git a/teachertool/src/components/styling/ActiveRubricDisplay.module.scss b/teachertool/src/components/styling/ActiveChecklistDisplay.module.scss similarity index 89% rename from teachertool/src/components/styling/ActiveRubricDisplay.module.scss rename to teachertool/src/components/styling/ActiveChecklistDisplay.module.scss index 02fa6e85508..56079f550bd 100644 --- a/teachertool/src/components/styling/ActiveRubricDisplay.module.scss +++ b/teachertool/src/components/styling/ActiveChecklistDisplay.module.scss @@ -1,9 +1,9 @@ -.rubric-display { +.checklist-display { display: flex; flex-direction: column; margin: 0 1rem 1rem 1rem; - .rubric-name-input-container { + .checklist-name-input-container { // Designed to mirror share-link-input layout. display: flex; flex-direction: row; @@ -15,7 +15,7 @@ padding-top: 1px; } - .rubric-name-input { + .checklist-name-input { display: flex; flex-direction: row; width: 100%; diff --git a/teachertool/src/components/styling/RubricPreview.module.scss b/teachertool/src/components/styling/ChecklistPreview.module.scss similarity index 90% rename from teachertool/src/components/styling/RubricPreview.module.scss rename to teachertool/src/components/styling/ChecklistPreview.module.scss index 8702dcf9064..592b3d6ad20 100644 --- a/teachertool/src/components/styling/RubricPreview.module.scss +++ b/teachertool/src/components/styling/ChecklistPreview.module.scss @@ -4,7 +4,7 @@ align-items: flex-start; justify-content: flex-start; - .rubric-header { + .checklist-header { width: 100%; font-weight: bold; margin-bottom: 0.1rem; @@ -12,7 +12,7 @@ padding: 0.2rem 0.5rem; } - .rubric-criteria { + .checklist-criteria { width: 100%; padding: 0.2rem 0.5rem; border-bottom: 1px solid var(--pxt-content-accent); @@ -21,4 +21,4 @@ border-bottom: none; } } -} \ No newline at end of file +} diff --git a/teachertool/src/components/styling/RubricWorkspace.module.scss b/teachertool/src/components/styling/ChecklistWorkspace.module.scss similarity index 95% rename from teachertool/src/components/styling/RubricWorkspace.module.scss rename to teachertool/src/components/styling/ChecklistWorkspace.module.scss index 29fb1b18f50..71081704294 100644 --- a/teachertool/src/components/styling/RubricWorkspace.module.scss +++ b/teachertool/src/components/styling/ChecklistWorkspace.module.scss @@ -1,17 +1,17 @@ -.panel { - width: 100%; - height: 100%; - display: flex; - flex-direction: column; - overflow: hidden; - background-color: var(--pxt-page-background); - color: var(--pxt-page-foreground); - - div[class*="tt-tabgroup"] { - height: 100%; - } - - div[class*="tt-tabview"] { - flex: 1 1 0%; - } -} +.panel { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + background-color: var(--pxt-page-background); + color: var(--pxt-page-foreground); + + div[class*="tt-tabgroup"] { + height: 100%; + } + + div[class*="tt-tabview"] { + flex: 1 1 0%; + } +} diff --git a/teachertool/src/components/styling/EvalResultDisplay.module.scss b/teachertool/src/components/styling/EvalResultDisplay.module.scss index 9fd5b941d14..bf1ba224863 100644 --- a/teachertool/src/components/styling/EvalResultDisplay.module.scss +++ b/teachertool/src/components/styling/EvalResultDisplay.module.scss @@ -80,7 +80,7 @@ border-bottom: solid 1px var(--pxt-content-accent); // height: 2.625rem; - .rubric-name { + .checklist-name { h2 { font-size: 1.5rem; font-weight: 500; diff --git a/teachertool/src/components/styling/HeaderBar.module.scss b/teachertool/src/components/styling/HeaderBar.module.scss index 94a31aa2739..dad4820419d 100644 --- a/teachertool/src/components/styling/HeaderBar.module.scss +++ b/teachertool/src/components/styling/HeaderBar.module.scss @@ -41,17 +41,4 @@ margin: 0 1rem; } } - - .rubric-name { - display: flex; - align-items: center; - &:before { - height: 1.5rem; - border-left: 2px solid var(--pxt-headerbar-foreground); - content: " "; - } - span { - margin: 0 1rem; - } - } } diff --git a/teachertool/src/components/styling/HomeScreen.module.scss b/teachertool/src/components/styling/HomeScreen.module.scss index f14b72564f1..0804be70159 100644 --- a/teachertool/src/components/styling/HomeScreen.module.scss +++ b/teachertool/src/components/styling/HomeScreen.module.scss @@ -89,7 +89,7 @@ div.page { } } - &.newRubric { + &.newChecklist { background-color: var(--pxt-button-primary-background); color: var(--pxt-button-primary-foreground); @@ -97,7 +97,7 @@ div.page { outline-color: var(--pxt-button-primary-foreground); } } - &.importRubric { + &.importChecklist { background-color: var(--pxt-headerbar-background); color: var(--pxt-button-primary-foreground); @@ -126,13 +126,13 @@ div.page { animation-delay: 0.3s; } } - &.rubricResource { + &.checklistResource { background-size: 100% 100%; background-repeat: no-repeat; grid-area: 1 / 1 / 2 / 5; border: 1px solid var(--pxt-content-background); - .rubricResourceCardTitle { + .checklistResourceCardTitle { background-color: rgba(228, 231, 241, 0.9); color: var(--pxt-page-foreground); } diff --git a/teachertool/src/components/styling/ImportRubricModal.module.scss b/teachertool/src/components/styling/ImportChecklistModal.module.scss similarity index 83% rename from teachertool/src/components/styling/ImportRubricModal.module.scss rename to teachertool/src/components/styling/ImportChecklistModal.module.scss index 219bf22eb4c..66d3613b34c 100644 --- a/teachertool/src/components/styling/ImportRubricModal.module.scss +++ b/teachertool/src/components/styling/ImportChecklistModal.module.scss @@ -1,15 +1,15 @@ -.import-rubric-modal { +.import-checklist-modal { div[class*="common-modal-body"] { background-color: var(--pxt-content-background); justify-content: center; } - .import-rubric { + .import-checklist { display: flex; flex-direction: column; gap: 0.5rem; - .rubric-preview-container { + .checklist-preview-container { max-height: 50vh; overflow-y: auto; border: 2px solid var(--pxt-content-foreground); diff --git a/teachertool/src/components/styling/Toolbar.module.scss b/teachertool/src/components/styling/Toolbar.module.scss index ffe69ef88ff..36ac645f75b 100644 --- a/teachertool/src/components/styling/Toolbar.module.scss +++ b/teachertool/src/components/styling/Toolbar.module.scss @@ -88,6 +88,7 @@ border-radius: 0.25rem; padding: 0.25rem 0; box-shadow: 0 0.5rem 0.5rem 0 #00000020; + width: 8.5rem !important; } ul { diff --git a/teachertool/src/constants.ts b/teachertool/src/constants.ts index 4cf131add02..ea7a9f26472 100644 --- a/teachertool/src/constants.ts +++ b/teachertool/src/constants.ts @@ -1,25 +1,25 @@ export namespace Strings { - export const ErrorLoadingRubricMsg = lf("That wasn't a valid rubric."); - export const ConfirmReplaceRubricMsg = lf("This will replace your current rubric. Continue?"); + export const ErrorLoadingChecklistMsg = lf("That wasn't a valid checklist."); + export const ConfirmReplaceChecklistMsg = lf("This will replace your current checklist. Continue?"); export const UntitledProject = lf("Untitled Project"); - export const UntitledRubric = lf("Untitled Rubric"); - export const NewRubric = lf("New Rubric"); - export const ImportRubric = lf("Import Rubric"); - export const ExportRubric = lf("Export Rubric"); + export const UntitledChecklist = lf("Untitled Checklist"); + export const NewChecklist = lf("New Checklist"); + export const ImportChecklist = lf("Import Checklist"); + export const ExportChecklist = lf("Export Checklist"); export const Remove = lf("Remove"); export const Criteria = lf("Criteria"); export const Name = lf("Name"); - export const RubricName = lf("Rubric Name"); + export const ChecklistName = lf("Checklist Name"); export const AddCriteria = lf("Add Criteria"); export const Actions = lf("Actions"); export const AutoRun = lf("auto-run"); - export const AutoRunDescription = lf("Automatically re-evaluate when the rubric or project changes"); + export const AutoRunDescription = lf("Automatically re-evaluate when the checklist or project changes"); export const AddNotes = lf("Add Notes"); export const DragAndDrop = lf("Drag & Drop"); export const ReleaseToUpload = lf("Release to Upload"); export const Browse = lf("Browse"); - export const SelectRubricFile = lf("Select Rubric File"); - export const InvalidRubricFile = lf("Invalid Rubric File"); + export const SelectChecklistFile = lf("Select Checklist File"); + export const InvalidChecklistFile = lf("Invalid Checklist File"); export const Cancel = lf("Cancel"); export const SelectBlock = lf("Select Block"); export const ValueRequired = lf("Value Required"); @@ -30,6 +30,9 @@ export namespace Strings { export const Max = lf("Max"); export const AddToChecklist = lf("Add to Checklist"); export const SelectCriteriaDescription = lf("Select the criteria you'd like to include"); + export const Checklist = lf("Checklist"); + export const Home = lf("Home"); + export const CreateEmptyChecklist = lf("Create Empty Checklist"); } export namespace Ticks { @@ -38,10 +41,10 @@ export namespace Ticks { export const BrandLink = "teachertool.brandlink"; export const OrgLink = "teachertool.orglink"; export const Error = "teachertool.error"; - export const NewRubric = "teachertool.newrubric"; - export const ImportRubric = "teachertool.importrubric"; - export const ExportRubric = "teachertool.exportrubric"; - export const LoadRubric = "teachertool.loadrubric"; + export const NewChecklist = "teachertool.newchecklist"; + export const ImportChecklist = "teachertool.importchecklist"; + export const ExportChecklist = "teachertool.exportchecklist"; + export const LoadChecklist = "teachertool.loadchecklist"; export const Evaluate = "teachertool.evaluate"; export const Autorun = "teachertool.autorun"; export const AddCriteria = "teachertool.addcriteria"; diff --git a/teachertool/src/services/fileSystemService.ts b/teachertool/src/services/fileSystemService.ts index 585b602f8f7..ea8f25066f6 100644 --- a/teachertool/src/services/fileSystemService.ts +++ b/teachertool/src/services/fileSystemService.ts @@ -1,33 +1,33 @@ import { logError } from "../services/loggingService"; import { ErrorCode } from "../types/errorCode"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; -// Serializes the active rubric and writes it to a file. +// Serializes the active checklist and writes it to a file. // Returns true if the file was written successfully, false otherwise. -export function writeRubricToFile(rubric: Rubric): boolean { - const sanitizedName = rubric.name ? pxt.Util.sanitizeFileName(rubric.name) : ""; - const fileName = `${sanitizedName ? sanitizedName : lf("unnamed-rubric")}.json`; +export function writeChecklistToFile(checklist: Checklist): boolean { + const sanitizedName = checklist.name ? pxt.Util.sanitizeFileName(checklist.name) : ""; + const fileName = `${sanitizedName ? sanitizedName : lf("unnamed-checklist")}.json`; // Write content to the given path on disk. - const rubricJson = JSON.stringify(rubric, null, 4); + const checklistJson = JSON.stringify(checklist, null, 4); try { - pxt.BrowserUtils.browserDownloadText(rubricJson, fileName); + pxt.BrowserUtils.browserDownloadText(checklistJson, fileName); return true; } catch (error) { - logError(ErrorCode.unableToExportRubric, error); + logError(ErrorCode.unableToExportChecklist, error); return false; } } -export async function loadRubricFromFileAsync(file: File): Promise { - let rubric: Rubric | undefined = undefined; +export async function loadChecklistFromFileAsync(file: File): Promise { + let checklist: Checklist | undefined = undefined; try { - const rubricJson = await pxt.Util.fileReadAsTextAsync(file); - rubric = JSON.parse(rubricJson) as Rubric; + const checklistJson = await pxt.Util.fileReadAsTextAsync(file); + checklist = JSON.parse(checklistJson) as Checklist; } catch (error) { - logError(ErrorCode.unableToReadRubricFile, error); + logError(ErrorCode.unableToReadChecklistFile, error); } - return rubric; + return checklist; } diff --git a/teachertool/src/services/storageService.ts b/teachertool/src/services/storageService.ts index 33162c2fbf1..34f729e2093 100644 --- a/teachertool/src/services/storageService.ts +++ b/teachertool/src/services/storageService.ts @@ -1,7 +1,7 @@ import { openDB, IDBPDatabase } from "idb"; import { ErrorCode } from "../types/errorCode"; import { logError } from "./loggingService"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; // ---------------------------------- // Local Storage (for simple key -> value mappings of small data) @@ -9,7 +9,7 @@ import { Rubric } from "../types/rubric"; const KEY_PREFIX = "teachertool"; const AUTORUN_KEY = [KEY_PREFIX, "autorun"].join("/"); -const LAST_ACTIVE_RUBRIC_KEY = [KEY_PREFIX, "lastActiveRubric"].join("/"); +const LAST_ACTIVE_CHECKLIST_KEY = [KEY_PREFIX, "lastActiveChecklist"].join("/"); const SPLIT_POSITION_KEY = [KEY_PREFIX, "splitPosition"].join("/"); function getValue(key: string, defaultValue?: string): string | undefined { @@ -29,8 +29,8 @@ function delValue(key: string) { // ---------------------------------- const teacherToolDbName = "makecode-project-insights"; -const dbVersion = 1; -const rubricsStoreName = "rubrics"; +const dbVersion = 2; +const checklistsStoreName = "checklists"; class TeacherToolDb { db: IDBPDatabase | undefined; @@ -39,7 +39,7 @@ class TeacherToolDb { if (this.db) return; this.db = await openDB(teacherToolDbName, dbVersion, { upgrade(db) { - db.createObjectStore(rubricsStoreName, { keyPath: "name" }); + db.createObjectStore(checklistsStoreName, { keyPath: "name" }); }, }); } @@ -82,16 +82,16 @@ class TeacherToolDb { } } - public getRubric(name: string): Promise { - return this.getAsync(rubricsStoreName, name); + public getChecklist(name: string): Promise { + return this.getAsync(checklistsStoreName, name); } - public saveRubric(rubric: Rubric): Promise { - return this.setAsync(rubricsStoreName, rubric); + public saveChecklist(checklist: Checklist): Promise { + return this.setAsync(checklistsStoreName, checklist); } - public deleteRubric(name: string): Promise { - return this.deleteAsync(rubricsStoreName, name); + public deleteChecklist(name: string): Promise { + return this.deleteAsync(checklistsStoreName, name); } } @@ -101,14 +101,14 @@ const getDb = (async () => { return db; })(); -async function saveRubricToIndexedDbAsync(rubric: Rubric) { +async function saveChecklistToIndexedDbAsync(checklist: Checklist) { const db = await getDb; - await db.saveRubric(rubric); + await db.saveChecklist(checklist); } -async function deleteRubricFromIndexedDbAsync(name: string) { +async function deleteChecklistFromIndexedDbAsync(name: string) { const db = await getDb; - await db.deleteRubric(name); + await db.deleteChecklist(name); } // ---------------------------------- @@ -132,18 +132,18 @@ export function setAutorun(autorun: boolean) { } } -export function getLastActiveRubricName(): string { +export function getLastActiveChecklistName(): string { try { - return getValue(LAST_ACTIVE_RUBRIC_KEY) ?? ""; + return getValue(LAST_ACTIVE_CHECKLIST_KEY) ?? ""; } catch (e) { logError(ErrorCode.localStorageReadError, e); return ""; } } -export function setLastActiveRubricName(name: string) { +export function setLastActiveChecklistName(name: string) { try { - setValue(LAST_ACTIVE_RUBRIC_KEY, name); + setValue(LAST_ACTIVE_CHECKLIST_KEY, name); } catch (e) { logError(ErrorCode.localStorageWriteError, e); } @@ -166,29 +166,29 @@ export function setLastSplitPosition(position: string) { } } -export async function getRubric(name: string): Promise { +export async function getChecklist(name: string): Promise { const db = await getDb; - let rubric: Rubric | undefined = undefined; - rubric = await db.getRubric(name); + let checklist: Checklist | undefined = undefined; + checklist = await db.getChecklist(name); - return rubric; + return checklist; } -export async function getLastActiveRubricAsync(): Promise { - const lastActiveRubricName = getLastActiveRubricName(); - return await getRubric(lastActiveRubricName); +export async function getLastActiveChecklistAsync(): Promise { + const lastActiveChecklistName = getLastActiveChecklistName(); + return await getChecklist(lastActiveChecklistName); } -export async function saveRubricAsync(rubric: Rubric) { - await saveRubricToIndexedDbAsync(rubric); - setLastActiveRubricName(rubric.name); +export async function saveChecklistAsync(checklist: Checklist) { + await saveChecklistToIndexedDbAsync(checklist); + setLastActiveChecklistName(checklist.name); } -export async function deleteRubricAsync(name: string) { - await deleteRubricFromIndexedDbAsync(name); +export async function deleteChecklistAsync(name: string) { + await deleteChecklistFromIndexedDbAsync(name); - if (getLastActiveRubricName() === name) { - setLastActiveRubricName(""); + if (getLastActiveChecklistName() === name) { + setLastActiveChecklistName(""); } } diff --git a/teachertool/src/state/actions.ts b/teachertool/src/state/actions.ts index cd3cc472f9e..de4ba151fe7 100644 --- a/teachertool/src/state/actions.ts +++ b/teachertool/src/state/actions.ts @@ -1,7 +1,7 @@ import { ToastWithId, TabName, ProjectData } from "../types"; import { CatalogCriteria, CriteriaResult } from "../types/criteria"; import { ModalOptions } from "../types/modalOptions"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; // Changes to app state are performed by dispatching actions to the reducer type ActionBase = { @@ -56,9 +56,9 @@ type SetCatalogOpen = ActionBase & { open: boolean; }; -type SetRubric = ActionBase & { - type: "SET_RUBRIC"; - rubric: Rubric; +type SetChecklist = ActionBase & { + type: "SET_CHECKLIST"; + checklist: Checklist; }; type ShowModal = ActionBase & { @@ -126,7 +126,7 @@ export type Action = | SetTargetConfig | SetCatalog | SetCatalogOpen - | SetRubric + | SetChecklist | ShowModal | HideModal | SetValidatorPlans @@ -184,9 +184,9 @@ const setCatalogOpen = (open: boolean): SetCatalogOpen => ({ open, }); -const setRubric = (rubric: Rubric): SetRubric => ({ - type: "SET_RUBRIC", - rubric, +const setChecklist = (checklist: Checklist): SetChecklist => ({ + type: "SET_CHECKLIST", + checklist, }); const showModal = (modalOptions: ModalOptions): ShowModal => ({ @@ -250,7 +250,7 @@ export { setTargetConfig, setCatalog, setCatalogOpen, - setRubric, + setChecklist, showModal, hideModal, setValidatorPlans, diff --git a/teachertool/src/state/helpers.ts b/teachertool/src/state/helpers.ts index c69062de4f5..61e14759e06 100644 --- a/teachertool/src/state/helpers.ts +++ b/teachertool/src/state/helpers.ts @@ -1,7 +1,7 @@ import { logError } from "../services/loggingService"; import { CatalogCriteria, CriteriaInstance } from "../types/criteria"; import { ErrorCode } from "../types/errorCode"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; import { stateAndDispatch } from "./appStateContext"; import { AppState } from "./state"; import { Strings } from "../constants"; @@ -12,7 +12,7 @@ export function getCatalogCriteriaWithId(id: string): CatalogCriteria | undefine } export function getCriteriaInstanceWithId(state: AppState, id: string): CriteriaInstance | undefined { - return state.rubric.criteria.find(c => c.instanceId === id); + return state.checklist.criteria.find(c => c.instanceId === id); } export function getParameterValue(state: AppState, instanceId: string, paramName: string): string | undefined { @@ -34,18 +34,18 @@ export function verifyCriteriaInstanceIntegrity(instance: CriteriaInstance) { } } -export function verifyRubricIntegrity(rubric: Rubric): { +export function verifyChecklistIntegrity(checklist: Checklist): { valid: boolean; validCriteria: CriteriaInstance[]; invalidCriteria: CriteriaInstance[]; } { - if (!rubric || !rubric.criteria) { + if (!checklist || !checklist.criteria) { return { valid: false, validCriteria: [], invalidCriteria: [] }; } const validCriteria: CriteriaInstance[] = []; const invalidCriteria: CriteriaInstance[] = []; - for (const criteria of rubric.criteria) { + for (const criteria of checklist.criteria) { try { verifyCriteriaInstanceIntegrity(criteria); validCriteria.push(criteria); @@ -61,8 +61,8 @@ export function isProjectLoaded(state: AppState): boolean { return !!state.projectMetadata; } -export function isRubricLoaded(state: AppState): boolean { - return !!(state.rubric.criteria.length || state.rubric.name); +export function isChecklistLoaded(state: AppState): boolean { + return !!(state.checklist.criteria.length || state.checklist.name); } export function getSafeProjectName(state: AppState): string | undefined { @@ -71,8 +71,8 @@ export function getSafeProjectName(state: AppState): string | undefined { } } -export function getSafeRubricName(state: AppState): string | undefined { - return state.rubric.name || Strings.UntitledRubric; +export function getSafeChecklistName(state: AppState): string | undefined { + return state.checklist.name || Strings.UntitledChecklist; } export function getCatalogCriteria(state: AppState): CatalogCriteria[] { diff --git a/teachertool/src/state/reducer.ts b/teachertool/src/state/reducer.ts index d260aa14a8a..40f487050a8 100644 --- a/teachertool/src/state/reducer.ts +++ b/teachertool/src/state/reducer.ts @@ -1,6 +1,6 @@ import { AppState } from "./state"; import { Action } from "./actions"; -import { updateStoredRubricAsync } from "../transforms/updateStoredRubric"; +import { updateStoredChecklistAsync } from "../transforms/updateStoredChecklistAsync"; // The reducer's job is to apply state changes by creating a copy of the existing state with the change applied. // The reducer must not create side effects. E.g. do not dispatch a state change from within the reducer. @@ -82,11 +82,11 @@ export default function reducer(state: AppState, action: Action): AppState { catalogOpen: action.open, }; } - case "SET_RUBRIC": { - /*await*/ updateStoredRubricAsync(state.rubric, action.rubric); // fire and forget, we don't need to wait for this to finish. + case "SET_CHECKLIST": { + /*await*/ updateStoredChecklistAsync(state.checklist, action.checklist); // fire and forget, we don't need to wait for this to finish. return { ...state, - rubric: action.rubric, + checklist: action.checklist, }; } case "SHOW_MODAL": { diff --git a/teachertool/src/state/state.ts b/teachertool/src/state/state.ts index 4a74375f863..8b66df5b31e 100644 --- a/teachertool/src/state/state.ts +++ b/teachertool/src/state/state.ts @@ -1,8 +1,8 @@ import { ToastWithId, TabName, ProjectData } from "../types"; import { CatalogCriteria, CriteriaResult } from "../types/criteria"; import { ModalOptions } from "../types/modalOptions"; -import { Rubric } from "../types/rubric"; -import { makeRubric } from "../utils"; +import { Checklist } from "../types/checklist"; +import { makeChecklist as makeChecklist } from "../utils"; export type AppState = { targetConfig?: pxt.TargetConfig; @@ -10,7 +10,7 @@ export type AppState = { evalResults: pxt.Map; // Criteria Instance Id -> Result projectMetadata: ProjectData | undefined; catalog: CatalogCriteria[] | undefined; - rubric: Rubric; + checklist: Checklist; activeTab: TabName; validatorPlans: pxt.blocks.ValidatorPlan[] | undefined; autorun: boolean; @@ -30,7 +30,7 @@ export const initialAppState: AppState = { evalResults: {}, projectMetadata: undefined, catalog: undefined, - rubric: makeRubric(), + checklist: makeChecklist(), activeTab: "home", validatorPlans: undefined, autorun: false, diff --git a/teachertool/src/transforms/addCriteriaToRubric.ts b/teachertool/src/transforms/addCriteriaToChecklist.ts similarity index 81% rename from teachertool/src/transforms/addCriteriaToRubric.ts rename to teachertool/src/transforms/addCriteriaToChecklist.ts index 48ae4a54068..995ae2fff78 100644 --- a/teachertool/src/transforms/addCriteriaToRubric.ts +++ b/teachertool/src/transforms/addCriteriaToChecklist.ts @@ -4,16 +4,16 @@ import { logDebug, logError } from "../services/loggingService"; import { CriteriaInstance, CriteriaParameterValue } from "../types/criteria"; import { nanoid } from "nanoid"; import { ErrorCode } from "../types/errorCode"; -import { setRubric } from "./setRubric"; +import { setChecklist } from "./setChecklist"; import { Ticks } from "../constants"; -export function addCriteriaToRubric(catalogCriteriaIds: string[]) { +export function addCriteriaToChecklist(catalogCriteriaIds: string[]) { const { state: teacherTool, dispatch } = stateAndDispatch(); // Create instances for each of the catalog criteria. - const newRubric = { - ...teacherTool.rubric, - criteria: [...(teacherTool.rubric.criteria ?? [])], + const newChecklist = { + ...teacherTool.checklist, + criteria: [...(teacherTool.checklist.criteria ?? [])], }; for (const catalogCriteriaId of catalogCriteriaIds) { @@ -42,10 +42,10 @@ export function addCriteriaToRubric(catalogCriteriaIds: string[]) { params, } as CriteriaInstance; - newRubric.criteria.push(criteriaInstance); + newChecklist.criteria.push(criteriaInstance); } - setRubric(newRubric); + setChecklist(newChecklist); pxt.tickEvent(Ticks.AddCriteria, { ids: JSON.stringify(catalogCriteriaIds), diff --git a/teachertool/src/transforms/getChecklistFromFileAsync.ts b/teachertool/src/transforms/getChecklistFromFileAsync.ts new file mode 100644 index 00000000000..d9471ff44a5 --- /dev/null +++ b/teachertool/src/transforms/getChecklistFromFileAsync.ts @@ -0,0 +1,20 @@ +import { logDebug } from "../services/loggingService"; +import { loadChecklistFromFileAsync } from "../services/fileSystemService"; +import { verifyChecklistIntegrity } from "../state/helpers"; +import { Checklist } from "../types/checklist"; + +export async function getChecklistFromFileAsync(file: File, allowPartial: boolean): Promise { + let checklist = await loadChecklistFromFileAsync(file); + + if (checklist) { + logDebug("Loading checklist from file...", { file, checklist }); + + const checklistVerificationResult = verifyChecklistIntegrity(checklist); + + if (!checklistVerificationResult.valid) { + checklist = allowPartial ? { ...checklist, criteria: checklistVerificationResult.validCriteria } : undefined; + } + } + + return checklist; +} diff --git a/teachertool/src/transforms/getRubricFromFileAsync.ts b/teachertool/src/transforms/getRubricFromFileAsync.ts deleted file mode 100644 index d833e4c1696..00000000000 --- a/teachertool/src/transforms/getRubricFromFileAsync.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { logDebug, logError } from "../services/loggingService"; -import { loadRubricFromFileAsync } from "../services/fileSystemService"; -import { verifyRubricIntegrity } from "../state/helpers"; -import { Rubric } from "../types/rubric"; - -export async function getRubricFromFileAsync(file: File, allowPartial: boolean): Promise { - let rubric = await loadRubricFromFileAsync(file); - - if (rubric) { - logDebug("Loading rubric from file...", { file, rubric }); - - const rubricVerificationResult = verifyRubricIntegrity(rubric); - - if (!rubricVerificationResult.valid) { - rubric = allowPartial ? { ...rubric, criteria: rubricVerificationResult.validCriteria } : undefined; - } - } - - return rubric; -} diff --git a/teachertool/src/transforms/loadChecklistAsync.ts b/teachertool/src/transforms/loadChecklistAsync.ts new file mode 100644 index 00000000000..a0e22fb0c36 --- /dev/null +++ b/teachertool/src/transforms/loadChecklistAsync.ts @@ -0,0 +1,25 @@ +import { Strings } from "../constants"; +import { fetchJsonDocAsync } from "../services/backendRequests"; +import { verifyChecklistIntegrity } from "../state/helpers"; +import { Checklist } from "../types/checklist"; +import { makeToast } from "../utils"; +import { replaceActiveChecklistAsync } from "./replaceActiveChecklistAsync"; +import { showToast } from "./showToast"; + +export async function loadChecklistAsync(checklistUrl: string) { + const json = await fetchJsonDocAsync(checklistUrl); + + if (!json) { + showToast(makeToast("error", Strings.ErrorLoadingChecklistMsg)); + return; + } + + const { valid } = verifyChecklistIntegrity(json); + + if (!valid) { + showToast(makeToast("error", Strings.ErrorLoadingChecklistMsg)); + return; + } + + await replaceActiveChecklistAsync(json); +} diff --git a/teachertool/src/transforms/loadRubricAsync.ts b/teachertool/src/transforms/loadRubricAsync.ts deleted file mode 100644 index 2380c9adf3b..00000000000 --- a/teachertool/src/transforms/loadRubricAsync.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { Strings } from "../constants"; -import { fetchJsonDocAsync } from "../services/backendRequests"; -import { verifyRubricIntegrity } from "../state/helpers"; -import { Rubric } from "../types/rubric"; -import { makeToast } from "../utils"; -import { replaceActiveRubricAsync } from "./replaceActiveRubricAsync"; -import { showToast } from "./showToast"; - -export async function loadRubricAsync(rubricUrl: string) { - const json = await fetchJsonDocAsync(rubricUrl); - - if (!json) { - showToast(makeToast("error", Strings.ErrorLoadingRubricMsg)); - return; - } - - const { valid } = verifyRubricIntegrity(json); - - if (!valid) { - showToast(makeToast("error", Strings.ErrorLoadingRubricMsg)); - return; - } - - await replaceActiveRubricAsync(json); -} diff --git a/teachertool/src/transforms/removeCriteriaFromRubric.ts b/teachertool/src/transforms/removeCriteriaFromChecklist.ts similarity index 57% rename from teachertool/src/transforms/removeCriteriaFromRubric.ts rename to teachertool/src/transforms/removeCriteriaFromChecklist.ts index 31c662f1978..2b7365bfd18 100644 --- a/teachertool/src/transforms/removeCriteriaFromRubric.ts +++ b/teachertool/src/transforms/removeCriteriaFromChecklist.ts @@ -1,20 +1,20 @@ import { stateAndDispatch } from "../state"; import { logDebug } from "../services/loggingService"; import { CriteriaInstance } from "../types/criteria"; -import { setRubric } from "./setRubric"; +import { setChecklist } from "./setChecklist"; import { Ticks } from "../constants"; -export function removeCriteriaFromRubric(instance: CriteriaInstance) { +export function removeCriteriaFromChecklist(instance: CriteriaInstance) { const { state: teacherTool, dispatch } = stateAndDispatch(); logDebug(`Removing criteria with id: ${instance.instanceId}`); - const newRubric = { - ...teacherTool.rubric, - criteria: teacherTool.rubric.criteria.filter(c => c.instanceId !== instance.instanceId), + const newChecklist = { + ...teacherTool.checklist, + criteria: teacherTool.checklist.criteria.filter(c => c.instanceId !== instance.instanceId), }; - setRubric(newRubric); + setChecklist(newChecklist); pxt.tickEvent(Ticks.RemoveCriteria, { catalogCriteriaId: instance.catalogCriteriaId }); } diff --git a/teachertool/src/transforms/replaceActiveChecklistAsync.ts b/teachertool/src/transforms/replaceActiveChecklistAsync.ts new file mode 100644 index 00000000000..5de6de34eed --- /dev/null +++ b/teachertool/src/transforms/replaceActiveChecklistAsync.ts @@ -0,0 +1,23 @@ +import { Strings } from "../constants"; +import { stateAndDispatch } from "../state"; +import { isChecklistLoaded } from "../state/helpers"; +import { Checklist } from "../types/checklist"; +import { confirmAsync } from "./confirmAsync"; +import { setActiveTab } from "./setActiveTab"; +import { setChecklist } from "./setChecklist"; + +export async function replaceActiveChecklistAsync(newChecklist: Checklist): Promise { + const { state: teacherTool } = stateAndDispatch(); + + const title = + !newChecklist.name && !newChecklist.criteria?.length + ? Strings.CreateEmptyChecklist + : lf("Import '{0}'?", newChecklist.name ? newChecklist.name : Strings.UntitledChecklist); + if (isChecklistLoaded(teacherTool) && !(await confirmAsync(title, Strings.ConfirmReplaceChecklistMsg))) { + return false; + } + + setChecklist(newChecklist); + setActiveTab("checklist"); + return true; +} diff --git a/teachertool/src/transforms/replaceActiveRubricAsync.ts b/teachertool/src/transforms/replaceActiveRubricAsync.ts deleted file mode 100644 index 216af078170..00000000000 --- a/teachertool/src/transforms/replaceActiveRubricAsync.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Strings } from "../constants"; -import { stateAndDispatch } from "../state"; -import { isRubricLoaded } from "../state/helpers"; -import { Rubric } from "../types/rubric"; -import { confirmAsync } from "./confirmAsync"; -import { setActiveTab } from "./setActiveTab"; -import { setRubric } from "./setRubric"; - -export async function replaceActiveRubricAsync(newRubric: Rubric): Promise { - const { state: teacherTool } = stateAndDispatch(); - - const title = - !newRubric.name && !newRubric.criteria?.length - ? lf("Create Empty Rubric") - : lf("Import '{0}'?", newRubric.name ? newRubric.name : Strings.UntitledRubric); - if (isRubricLoaded(teacherTool) && !(await confirmAsync(title, Strings.ConfirmReplaceRubricMsg))) { - return false; - } - - setRubric(newRubric); - setActiveTab("rubric"); - return true; -} diff --git a/teachertool/src/transforms/resetChecklistAsync.ts b/teachertool/src/transforms/resetChecklistAsync.ts new file mode 100644 index 00000000000..b5aa3f0c600 --- /dev/null +++ b/teachertool/src/transforms/resetChecklistAsync.ts @@ -0,0 +1,12 @@ +import { stateAndDispatch } from "../state"; +import * as Actions from "../state/actions"; +import { makeChecklist } from "../utils"; +import { replaceActiveChecklistAsync } from "./replaceActiveChecklistAsync"; + +export async function resetChecklistAsync() { + const { dispatch } = stateAndDispatch(); + + if (await replaceActiveChecklistAsync(makeChecklist())) { + dispatch(Actions.clearAllEvalResults()); + } +} diff --git a/teachertool/src/transforms/resetRubricAsync.ts b/teachertool/src/transforms/resetRubricAsync.ts deleted file mode 100644 index 3bf786caa5a..00000000000 --- a/teachertool/src/transforms/resetRubricAsync.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { stateAndDispatch } from "../state"; -import * as Actions from "../state/actions"; -import { makeRubric } from "../utils"; -import { replaceActiveRubricAsync } from "./replaceActiveRubricAsync"; - -export async function resetRubricAsync() { - const { dispatch } = stateAndDispatch(); - - if (await replaceActiveRubricAsync(makeRubric())) { - dispatch(Actions.clearAllEvalResults()); - } -} diff --git a/teachertool/src/transforms/runEvaluateAsync.ts b/teachertool/src/transforms/runEvaluateAsync.ts index 7988fe22321..69870de5140 100644 --- a/teachertool/src/transforms/runEvaluateAsync.ts +++ b/teachertool/src/transforms/runEvaluateAsync.ts @@ -88,7 +88,7 @@ export async function runEvaluateAsync(fromUserInteraction: boolean) { // EvalRequest promises will resolve to true if evaluation completed successfully (regarless of pass/fail). // They will only resolve to false if evaluation was unable to complete. - const evalRequests = teacherTool.rubric.criteria.map( + const evalRequests = teacherTool.checklist.criteria.map( criteriaInstance => new Promise(async resolve => { const existingOutcome = teacherTool.evalResults[criteriaInstance.instanceId]?.result; @@ -149,7 +149,7 @@ export async function runEvaluateAsync(fromUserInteraction: boolean) { const results = await Promise.all(evalRequests); if (fromUserInteraction) { const errorCount = results.filter(r => !r).length; - if (errorCount === teacherTool.rubric.criteria.length) { + if (errorCount === teacherTool.checklist.criteria.length) { showToast(makeToast("error", lf("Unable to run evaluation"))); } else if (errorCount > 0) { showToast(makeToast("error", lf("Unable to evaluate some criteria"))); diff --git a/teachertool/src/transforms/setRubric.ts b/teachertool/src/transforms/setChecklist.ts similarity index 60% rename from teachertool/src/transforms/setRubric.ts rename to teachertool/src/transforms/setChecklist.ts index 347dbf2e10a..1b2ff797d33 100644 --- a/teachertool/src/transforms/setRubric.ts +++ b/teachertool/src/transforms/setChecklist.ts @@ -1,12 +1,12 @@ import { stateAndDispatch } from "../state"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; import * as Actions from "../state/actions"; import * as AutorunService from "../services/autorunService"; import { setEvalResultsToNotStarted } from "./setEvalResultsToNotStarted"; -export function setRubric(rubric: Rubric) { +export function setChecklist(checklist: Checklist) { const { dispatch } = stateAndDispatch(); - dispatch(Actions.setRubric(rubric)); - setEvalResultsToNotStarted({ rubric }); + dispatch(Actions.setChecklist(checklist)); + setEvalResultsToNotStarted({ checklist }); AutorunService.poke(); } diff --git a/teachertool/src/transforms/setChecklistName.ts b/teachertool/src/transforms/setChecklistName.ts new file mode 100644 index 00000000000..60c295c5484 --- /dev/null +++ b/teachertool/src/transforms/setChecklistName.ts @@ -0,0 +1,18 @@ +import { stateAndDispatch } from "../state"; +import { setChecklist } from "./setChecklist"; + +export function setChecklistName(name: string) { + const { state: teacherTool } = stateAndDispatch(); + + const oldName = teacherTool.checklist.name; + + if (oldName === name) { + return; + } + + const newChecklist = { + ...teacherTool.checklist, + name, + }; + setChecklist(newChecklist); +} diff --git a/teachertool/src/transforms/setEvalResultsToNotStarted.ts b/teachertool/src/transforms/setEvalResultsToNotStarted.ts index fd982aeea8f..916cc12ce16 100644 --- a/teachertool/src/transforms/setEvalResultsToNotStarted.ts +++ b/teachertool/src/transforms/setEvalResultsToNotStarted.ts @@ -1,19 +1,19 @@ import { stateAndDispatch } from "../state"; import { EvaluationStatus, CriteriaResult } from "../types/criteria"; -import { Rubric } from "../types/rubric"; +import { Checklist } from "../types/checklist"; import * as Actions from "../state/actions"; export function setEvalResultsToNotStarted({ overwriteExistingEntries, - rubric, + checklist, }: { overwriteExistingEntries?: boolean; - rubric?: Rubric; + checklist?: Checklist; }): void { const { state: teachertool, dispatch } = stateAndDispatch(); let allEvalResults: pxt.Map = {}; - const usedRubric = rubric || teachertool.rubric; - for (const criteria of usedRubric.criteria) { + const usedChecklist = checklist || teachertool.checklist; + for (const criteria of usedChecklist.criteria) { const instanceId = criteria.instanceId; if (!teachertool.evalResults[instanceId] || overwriteExistingEntries) { allEvalResults[instanceId] = { result: EvaluationStatus.NotStarted }; diff --git a/teachertool/src/transforms/setParameterValue.ts b/teachertool/src/transforms/setParameterValue.ts index 2fa79ecd9b3..05aa572f3a6 100644 --- a/teachertool/src/transforms/setParameterValue.ts +++ b/teachertool/src/transforms/setParameterValue.ts @@ -4,7 +4,7 @@ import { getCriteriaInstanceWithId } from "../state/helpers"; import { EvaluationStatus } from "../types/criteria"; import { ErrorCode } from "../types/errorCode"; import { setEvalResultOutcome } from "./setEvalResultOutcome"; -import { setRubric } from "./setRubric"; +import { setChecklist } from "./setChecklist"; export function setParameterValue(instanceId: string, paramName: string, newValue: any) { const { state: teacherTool } = stateAndDispatch(); @@ -30,11 +30,11 @@ export function setParameterValue(instanceId: string, paramName: string, newValu ...oldCriteriaInstance, params: oldCriteriaInstance.params?.map(p => (p.name === paramName ? newParam : p)), }; - const newInstanceSet = teacherTool.rubric.criteria.map(c => + const newInstanceSet = teacherTool.checklist.criteria.map(c => c.instanceId === instanceId ? newCriteriaInstance : c ); - const newRubric = { ...teacherTool.rubric, criteria: newInstanceSet }; + const newChecklist = { ...teacherTool.checklist, criteria: newInstanceSet }; - setRubric(newRubric); + setChecklist(newChecklist); setEvalResultOutcome(instanceId, EvaluationStatus.NotStarted); } diff --git a/teachertool/src/transforms/setRubricName.ts b/teachertool/src/transforms/setRubricName.ts deleted file mode 100644 index c18bf9e0387..00000000000 --- a/teachertool/src/transforms/setRubricName.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { stateAndDispatch } from "../state"; -import { setRubric } from "./setRubric"; - -export function setRubricName(name: string) { - const { state: teacherTool } = stateAndDispatch(); - - const oldName = teacherTool.rubric.name; - - if (oldName === name) { - return; - } - - const newRubric = { - ...teacherTool.rubric, - name, - }; - setRubric(newRubric); -} diff --git a/teachertool/src/transforms/tryLoadLastActiveChecklistAsync.ts b/teachertool/src/transforms/tryLoadLastActiveChecklistAsync.ts new file mode 100644 index 00000000000..d8dff736e43 --- /dev/null +++ b/teachertool/src/transforms/tryLoadLastActiveChecklistAsync.ts @@ -0,0 +1,24 @@ +import { getLastActiveChecklistAsync } from "../services/storageService"; +import { logDebug } from "../services/loggingService"; +import { showToast } from "./showToast"; +import { makeToast } from "../utils"; +import { setChecklist } from "./setChecklist"; +import { verifyChecklistIntegrity } from "../state/helpers"; + +export async function tryLoadLastActiveChecklistAsync() { + const lastActiveChecklist = await getLastActiveChecklistAsync(); + + if (lastActiveChecklist) { + logDebug("Loading last active checklist...", lastActiveChecklist); + + const checklistVerificationResult = verifyChecklistIntegrity(lastActiveChecklist); + + if (!checklistVerificationResult.valid) { + showToast(makeToast("error", lf("Some criteria could not be loaded."))); + } + + setChecklist({ ...lastActiveChecklist, criteria: checklistVerificationResult.validCriteria }); + } else { + logDebug(`No last active checklist to load.`); + } +} diff --git a/teachertool/src/transforms/tryLoadLastActiveRubricAsync.ts b/teachertool/src/transforms/tryLoadLastActiveRubricAsync.ts deleted file mode 100644 index 8fe4f661af6..00000000000 --- a/teachertool/src/transforms/tryLoadLastActiveRubricAsync.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { getLastActiveRubricAsync } from "../services/storageService"; -import { logDebug } from "../services/loggingService"; -import { showToast } from "./showToast"; -import { makeToast } from "../utils"; -import { setRubric } from "./setRubric"; -import { verifyRubricIntegrity } from "../state/helpers"; - -export async function tryLoadLastActiveRubricAsync() { - const lastActiveRubric = await getLastActiveRubricAsync(); - - if (lastActiveRubric) { - logDebug("Loading last active rubric...", lastActiveRubric); - - const rubricVerificationResult = verifyRubricIntegrity(lastActiveRubric); - - if (!rubricVerificationResult.valid) { - showToast(makeToast("error", lf("Some criteria could not be loaded."))); - } - - setRubric({ ...lastActiveRubric, criteria: rubricVerificationResult.validCriteria }); - } else { - logDebug(`No last active rubric to load.`); - } -} diff --git a/teachertool/src/transforms/updateStoredChecklistAsync.ts b/teachertool/src/transforms/updateStoredChecklistAsync.ts new file mode 100644 index 00000000000..9eacee2c4a6 --- /dev/null +++ b/teachertool/src/transforms/updateStoredChecklistAsync.ts @@ -0,0 +1,15 @@ +import { deleteChecklistAsync, saveChecklistAsync } from "../services/storageService"; +import { Checklist } from "../types/checklist"; + +export async function updateStoredChecklistAsync(oldChecklist: Checklist | undefined, newChecklist: Checklist | undefined) { + const renamed = oldChecklist && newChecklist && oldChecklist?.name !== newChecklist.name; + const deleted = oldChecklist && !newChecklist; + + if (newChecklist) { + await saveChecklistAsync(newChecklist); + } + + if (renamed || deleted) { + await deleteChecklistAsync(oldChecklist.name); + } +} diff --git a/teachertool/src/transforms/updateStoredRubric.ts b/teachertool/src/transforms/updateStoredRubric.ts deleted file mode 100644 index c2bdf1f92a5..00000000000 --- a/teachertool/src/transforms/updateStoredRubric.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { deleteRubricAsync, saveRubricAsync } from "../services/storageService"; -import { Rubric } from "../types/rubric"; - -export async function updateStoredRubricAsync(oldRubric: Rubric | undefined, newRubric: Rubric | undefined) { - const renamed = oldRubric && newRubric && oldRubric?.name !== newRubric.name; - const deleted = oldRubric && !newRubric; - - if (newRubric) { - await saveRubricAsync(newRubric); - } - - if (renamed || deleted) { - await deleteRubricAsync(oldRubric.name); - } -} diff --git a/teachertool/src/types/rubric.ts b/teachertool/src/types/checklist.ts similarity index 77% rename from teachertool/src/types/rubric.ts rename to teachertool/src/types/checklist.ts index 073ca325c7d..d34cce738ce 100644 --- a/teachertool/src/types/rubric.ts +++ b/teachertool/src/types/checklist.ts @@ -1,6 +1,6 @@ import { CriteriaInstance } from "./criteria"; -export interface Rubric { +export interface Checklist { name: string; criteria: CriteriaInstance[]; } diff --git a/teachertool/src/types/criteria.ts b/teachertool/src/types/criteria.ts index 5c07b2b3204..97f9ac6e68c 100644 --- a/teachertool/src/types/criteria.ts +++ b/teachertool/src/types/criteria.ts @@ -1,4 +1,4 @@ -// A criteria defined in the catalog of all possible criteria for the user to choose from when creating a rubric. +// A criteria defined in the catalog of all possible criteria for the user to choose from when creating a checklist. export interface CatalogCriteria { id: string; // A unique id (GUID) for the catalog criteria use: string; // Refers to the validator plan this criteria relies upon @@ -10,7 +10,7 @@ export interface CatalogCriteria { maxCount?: number; // The maximum number of instances allowed for this criteria within a single checklist. Unlimited if undefined. } -// An instance of a criteria in a rubric. +// An instance of a criteria in a checklist. export interface CriteriaInstance { catalogCriteriaId: string; instanceId: string; diff --git a/teachertool/src/types/errorCode.ts b/teachertool/src/types/errorCode.ts index 9a339ea83e9..f122a6b22bc 100644 --- a/teachertool/src/types/errorCode.ts +++ b/teachertool/src/types/errorCode.ts @@ -13,8 +13,8 @@ export enum ErrorCode { unableToSetIndexedDbRecord = "unableToSetIndexedDbRecord", unableToDeleteIndexedDbRecord = "unableToDeleteIndexedDbRecord", unableToLoadCriteriaInstance = "unableToLoadCriteriaInstance", - unableToExportRubric = "unableToExportRubric", - unableToReadRubricFile = "unableToReadRubricFile", + unableToExportChecklist = "unableToExportChecklist", + unableToReadChecklistFile = "unableToReadChecklistFile", localStorageReadError = "localStorageReadError", localStorageWriteError = "localStorageWriteError", missingCriteriaInstance = "missingCriteriaInstance", diff --git a/teachertool/src/types/index.ts b/teachertool/src/types/index.ts index b16bb1e5849..2383b34e089 100644 --- a/teachertool/src/types/index.ts +++ b/teachertool/src/types/index.ts @@ -21,20 +21,20 @@ export type ToastWithId = Toast & { id: string; }; -export type TabName = "home" | "rubric" | "results"; +export type TabName = "home" | "checklist" | "results"; -export type CardType = "rubric-resource"; +export type CardType = "checklist-resource"; -// Rubric Card types that can be appear in the carousel +// Checklist Card types that can be appear in the carousel export type CarouselCard = { cardType: CardType; }; -export type CarouselRubricResourceCard = CarouselCard & { - cardType: "rubric-resource"; +export type CarouselChecklistResourceCard = CarouselCard & { + cardType: "checklist-resource"; cardTitle: string; imageUrl: string; - rubricUrl: string; + checklistUrl: string; }; export type CarouselCardSet = { diff --git a/teachertool/src/types/modalOptions.ts b/teachertool/src/types/modalOptions.ts index a33331ef104..086bf6f60f4 100644 --- a/teachertool/src/types/modalOptions.ts +++ b/teachertool/src/types/modalOptions.ts @@ -12,8 +12,8 @@ export type BlockPickerOptions = { paramName: string; }; -export type ImportRubricOptions = { - modal: "import-rubric"; +export type ImportChecklistOptions = { + modal: "import-checklist"; }; -export type ModalOptions = ImportRubricOptions | ConfirmationModalOptions | BlockPickerOptions; +export type ModalOptions = ImportChecklistOptions | ConfirmationModalOptions | BlockPickerOptions; diff --git a/teachertool/src/utils/index.ts b/teachertool/src/utils/index.ts index ee7000281e7..670f49c49d1 100644 --- a/teachertool/src/utils/index.ts +++ b/teachertool/src/utils/index.ts @@ -1,6 +1,6 @@ import { nanoid } from "nanoid"; -import { CarouselRubricResourceCard, CriteriaTemplateSegment, ToastType, ToastWithId } from "../types"; -import { Rubric } from "../types/rubric"; +import { CarouselChecklistResourceCard, CriteriaTemplateSegment, ToastType, ToastWithId } from "../types"; +import { Checklist } from "../types/checklist"; import { classList } from "react-common/components/util"; import { CatalogCriteria } from "../types/criteria"; @@ -30,15 +30,15 @@ export function classes(css: { [name: string]: string }, ...names: string[]) { return classList(...names.map(n => css[n])); } -export function makeRubric(): Rubric { +export function makeChecklist(): Checklist { return { name: "", criteria: [], }; } -export const isRubricResourceCard = (card: any): card is CarouselRubricResourceCard => { - return typeof card === "object" && card.cardType === "rubric-resource"; +export const isChecklistResourceCard = (card: any): card is CarouselChecklistResourceCard => { + return typeof card === "object" && card.cardType === "checklist-resource"; }; export function getProjectLink(inputText: string): string {