From 1234c4ff2852a35997c7fe1d1bd41d3038e45940 Mon Sep 17 00:00:00 2001 From: Thomas Sparks <69657545+thsparks@users.noreply.github.com> Date: Tue, 30 Apr 2024 16:35:58 -0700 Subject: [PATCH 1/9] Reorder catalogs co copilot and "block used count times" are at the top. (#9992) --- common-docs/teachertool/catalog-shared.json | 40 +++++++++---------- .../src/transforms/loadCatalogAsync.ts | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/common-docs/teachertool/catalog-shared.json b/common-docs/teachertool/catalog-shared.json index 0b33bb96a1d9..922e2a0558a8 100644 --- a/common-docs/teachertool/catalog-shared.json +++ b/common-docs/teachertool/catalog-shared.json @@ -1,5 +1,25 @@ { "criteria": [ + { + "id": "59AAC5BA-B0B3-4389-AA90-1E767EFA8563", + "use": "block_used_n_times", + "template": "${Block} used ${count} times", + "description": "This block was used the specified number of times in your project.", + "docPath": "/teachertool", + "params": [ + { + "name": "block", + "type": "block", + "paths": ["checks[0].blockCounts[0].blockId"] + }, + { + "name": "count", + "type": "number", + "default": 1, + "paths": ["checks[0].blockCounts[0].count"] + } + ] + }, { "id": "D21D76A2-D9FD-4F9B-B0AC-973CB870EA78", "use": "variable_set", @@ -32,26 +52,6 @@ } ] }, - { - "id": "59AAC5BA-B0B3-4389-AA90-1E767EFA8563", - "use": "block_used_n_times", - "template": "${Block} used ${count} times", - "description": "This block was used the specified number of times in your project.", - "docPath": "/teachertool", - "params": [ - { - "name": "block", - "type": "block", - "paths": ["checks[0].blockCounts[0].blockId"] - }, - { - "name": "count", - "type": "number", - "default": 1, - "paths": ["checks[0].blockCounts[0].count"] - } - ] - }, { "id": "B8987394-1531-4C71-8661-BE4086CE0C6E", "use": "n_loops", diff --git a/teachertool/src/transforms/loadCatalogAsync.ts b/teachertool/src/transforms/loadCatalogAsync.ts index 0deca85961ad..876704bde6f1 100644 --- a/teachertool/src/transforms/loadCatalogAsync.ts +++ b/teachertool/src/transforms/loadCatalogAsync.ts @@ -4,8 +4,8 @@ import * as Actions from "../state/actions"; import { CatalogCriteria } from "../types/criteria"; const prodFiles = [ - "/teachertool/catalog.json", // target-specific catalog "/teachertool/catalog-shared.json", // shared across all targets + "/teachertool/catalog.json", // target-specific catalog ]; export async function loadCatalogAsync() { From 2648b4f164ad8899a8554bfaac5536a238299cd8 Mon Sep 17 00:00:00 2001 From: Thomas Sparks <69657545+thsparks@users.noreply.github.com> Date: Wed, 1 May 2024 15:01:53 -0700 Subject: [PATCH 2/9] Teacher Tool: Remove rubric name from header bar (#9995) --- teachertool/src/components/HeaderBar.tsx | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/teachertool/src/components/HeaderBar.tsx b/teachertool/src/components/HeaderBar.tsx index 34b78efc7492..96e88aae8c7a 100644 --- a/teachertool/src/components/HeaderBar.tsx +++ b/teachertool/src/components/HeaderBar.tsx @@ -74,15 +74,6 @@ export const HeaderBar: React.FC = () => { ); }; - const getRubricName = (): JSX.Element | null => { - const rubricName = getSafeRubricName(teacherTool); - return rubricName ? ( -
- {rubricName} -
- ) : null; - }; - const onHomeClicked = () => { pxt.tickEvent(Ticks.HomeLink); @@ -103,7 +94,6 @@ export const HeaderBar: React.FC = () => {
{getOrganizationLogo()} {getTargetLogo()} - {getRubricName()}
From 5390637376fd90e0bc95b8cf068166a6d20e7c79 Mon Sep 17 00:00:00 2001 From: Galen Nickel Date: Wed, 1 May 2024 17:42:34 -0700 Subject: [PATCH 3/9] Make a troubelshooting page for tutorial authoring (#9990) * make a troublshooting page for tutorial authoring * add a link in the main tutorial writing page * comment additions, thanks * oops, need spaces in name? * collapsed repo/var name form --- docs/writing-docs/tutorials.md | 1 + docs/writing-docs/tutorials/resources.md | 51 ++++++++++++++++++- .../writing-docs/tutorials/troubleshooting.md | 50 ++++++++++++++++++ 3 files changed, 101 insertions(+), 1 deletion(-) create mode 100644 docs/writing-docs/tutorials/troubleshooting.md diff --git a/docs/writing-docs/tutorials.md b/docs/writing-docs/tutorials.md index 88c84cf7c4e9..f2033e25cc12 100644 --- a/docs/writing-docs/tutorials.md +++ b/docs/writing-docs/tutorials.md @@ -26,3 +26,4 @@ You can write, edit, and test a tutorial with the online [**Tutorial Tool**](htt * [Multi-language](/writing-docs/tutorials/multi-lang) - Tutorials for both Blocks and Code * [Adding Resources](/writing-docs/tutorials/resources) - Including a resource section in a tutorial * [Publish](/writing-docs/tutorials/publish) - How to publish a tutorial +* [Troubleshoot](/writing-docs/tutorials/troubleshooting) - Troubleshooting problems with a tutorial diff --git a/docs/writing-docs/tutorials/resources.md b/docs/writing-docs/tutorials/resources.md index 6cb7d5c41710..0be11b205d92 100644 --- a/docs/writing-docs/tutorials/resources.md +++ b/docs/writing-docs/tutorials/resources.md @@ -138,10 +138,59 @@ The asset block might look something like the following example. ``` ```` -If you need to modify the assets for the tutoral, reopen and edit the project saved in the `.txt.mkcd` file. +If you need to modify the assets for the tutorial, reopen and edit the project saved in the `.txt.mkcd` file. You can simply drag the file into the editor, make your changes, and download it again. Open the project file in a text editor, copy the new asset data, and replace the contents of your tutorial's ```` ```assetjson ```` block with it. The assets are shown as the initial view in a tutorial by using the [@preferredEditor](/writing-docs/tutorials/control-options#preferred-editor-view) option. This option causes the tutorial to open with the Asset Editor rather than showing the editor for Blocks or Code. + +## Creating asset packs + +### ~ alert + +#### MackeCode Arcade only + +Asset packs only work with MakeCode Arcade. + +### ~ + +Asset packs are resource projects that are separate from a tutorial file. They contain images, animations, tilemaps, and other resources for use in a tutorial. An asset pack can help reduce the size of a tutorial when it's using many resources or very large resources. You may place some or all your tutorial resources into an asset pack project. + +Here are the instructions for creating an asset pack: + +1. Create a new project. The name of this project will end up being the namespace of the asset pack you create, so make sure to rename it to a valid javascript variable name (no spaces, only letters, underscores, and numbers). For example, `my_asset_pack`. +2. Switch to the **Assets** tab. +3. Create a new image (or other asset item). Copy the image text your tutorial and paste it into image space in the editor for the new asset. +4. Give the asset a name in the bottom right of the image editor. This name will be the name you reference in your code, so make sure it’s a valid javascript variable name. For example, `background1`. +5. Close the image editor and switch to the **JavaScript** tab. +6. On the left, in the file explorer underneath the simulator, open up pxt.json +7. Click "Edit settings as text". +8. Underneath the line that says "description", paste in this line:
`"assetPack": true`
+9. In the file explorer, switch back to main.ts. +10. Turn this project into a GitHub repo using the GitHub button in the bottom toolbar (for example, my_github_username/my_asset_pack). + +Now that you have an asset pack, you can include it in your tutorial just like you would an extension. Add an annotation like this at the bottom of your markdown file: + +```` +```package +my_asset_pack=github:my_github_username/my_asset_pack +``` +```` + +**Important**: Make sure that the name on the left hand side of the "=" matches the name of your extension from Step 1. However, if the asset pack's repository name contains "-" such as `github:my_github_username/my-asset-pack`, the name on the left of the "=" should remove the "-" characters such that `my-asset-pack` becomes `myassetpack`. + +Now, instead of including the background image in your code snippets, you can reference it like so: + +```` +```blocks +scene.setBackgroundImage(my_asset_pack.background1) +``` +```` + +For more details on how to create an asset pack for your tutorial, watch this helpful video: + +https://youtu.be/ikz15E24F2k + +If you have other assets you want to include, you can insert them into the pack in the same manner. \ No newline at end of file diff --git a/docs/writing-docs/tutorials/troubleshooting.md b/docs/writing-docs/tutorials/troubleshooting.md new file mode 100644 index 000000000000..3ae97a10a1e0 --- /dev/null +++ b/docs/writing-docs/tutorials/troubleshooting.md @@ -0,0 +1,50 @@ +# Troubleshooting + +If your tutorial is not behaving properly or you receive an error message, you can check some of these common trouble situations to help resolve the problem with your custom tutorial. + +### ~ hint + +#### Tutorial format or content problems + +If MakeCode can't load your tutorial, you will likely see the message: + +``` +Please check your internet connection and check the tutorial is valid +``` + +This may indicate that your tutorial has a problem with it's content or it can't be located at the path you provided. + +### ~ + +## Tutorial file is too large + +Tutorial markdown files are required to be less than **128K** bytes. + +### Asset packs in MakeCode Arcade + +There can be several images and/or very large images within the asset sections or instructions of a tutorial markdown file. Often these will make the tutorial file size exceed the 128K byte limit. You can reduce the size of the tutorial file by moving the images into a separate asset pack. See the instructions in the [resources](/writing-docs/tutorials/resources) page for creating an [asset pack](/writing-docs/tutorials/resources#creating-asset-packs). + +## Tutorial game screen just shows activity spinner + +If activity indicator on the game screen in the tutorial seems to just spin and never load, there's probably an error. Start by opening the JavaScript console and try to re-run the tutorial. It should give you an idea of what's causing it to not work. + +## Kind types aren't working in MakeCode Arcade + +If you added a "kind" and MakeCode generated the code for you, it won't work correctly in the tutorial. You need to add `//% isKind` before each declaration. + +The kind that was declared in your tutorial code, such as: + +```typescript +namespace SpriteKind { + export const Veggies = SpriteKind.create() +} +``` + +You should add `//% isKind` to the declaration: + +```typescript +namespace SpriteKind { + //% isKind + export const Veggies = SpriteKind.create() +} +``` From 387ee3a0959a0b211e78ca773b8cfee8ce6c1018 Mon Sep 17 00:00:00 2001 From: Thomas Sparks <69657545+thsparks@users.noreply.github.com> Date: Fri, 3 May 2024 15:25:16 -0700 Subject: [PATCH 4/9] Teacher Tool: Variable Usage Validator (#9994) This adds a new validator which can check if variables are both defined and used. The key difference between this and "block-exist" checks for variable_set and variable_get is that we can ensure the names match, and we can ensure it's checking for multiple variables (so variable_get isn't just called X number of times on the same variable, even if variable_set defines X unique variables, and so on...). You can optionally filter by name, but we don't expose this currently in any criteria. You can also used nested validation to ensure a variable is set to something specific (like pick random), but again, we don't have any criteria that currently use this. --- common-docs/teachertool/catalog-shared.json | 32 +++++------ .../teachertool/validator-plans-shared.json | 44 ++++----------- localtypings/validatorPlan.d.ts | 6 ++ pxteditor/code-validation/runValidatorPlan.ts | 20 +++++++ .../code-validation/validateVariableUsage.ts | 55 +++++++++++++++++++ 5 files changed, 109 insertions(+), 48 deletions(-) create mode 100644 pxteditor/code-validation/validateVariableUsage.ts diff --git a/common-docs/teachertool/catalog-shared.json b/common-docs/teachertool/catalog-shared.json index 922e2a0558a8..883162e77ca0 100644 --- a/common-docs/teachertool/catalog-shared.json +++ b/common-docs/teachertool/catalog-shared.json @@ -20,22 +20,6 @@ } ] }, - { - "id": "D21D76A2-D9FD-4F9B-B0AC-973CB870EA78", - "use": "variable_set", - "template": "At least one custom variable is set", - "docPath": "/teachertool", - "description": "At least one user-defined variable is set to a value.", - "maxCount": 1 - }, - { - "id": "0173898D-8A48-4266-AAB9-CE934471A734", - "use": "variable_accessed", - "template": "At least one variable is accessed", - "docPath": "/teachertool", - "description": "At least one variable's value is read.", - "maxCount": 1 - }, { "id": "7AE7EA2A-3AC8-42DC-89DB-65E3AE157156", "use": "block_comment_used", @@ -83,6 +67,22 @@ "default": 1 } ] + }, + { + "id": "0DFA44C8-3CA5-4C77-946E-AF09F6C03879", + "use": "variable_usage", + "template": "Uses at least ${count} variables", + "docPath": "/teachertool", + "description": "The program creates and uses at least this many user-defined variables.", + "maxCount": 1, + "params": [ + { + "name": "count", + "type": "number", + "paths": ["checks[0].count"], + "default": 1 + } + ] } ] } diff --git a/common-docs/teachertool/validator-plans-shared.json b/common-docs/teachertool/validator-plans-shared.json index ecfb58877648..09fa4551c12d 100644 --- a/common-docs/teachertool/validator-plans-shared.json +++ b/common-docs/teachertool/validator-plans-shared.json @@ -86,38 +86,6 @@ } ] }, - { - ".desc": "A variable's value is set", - "name": "variable_set", - "threshold": 1, - "checks": [ - { - "validator": "blocksExist", - "blockCounts": [ - { - "blockId": "variables_set", - "count": 1 - } - ] - } - ] - }, - { - ".desc": "A variable's value is used", - "name": "variable_accessed", - "threshold": 1, - "checks": [ - { - "validator": "blocksExist", - "blockCounts": [ - { - "blockId": "variables_get", - "count": 1 - } - ] - } - ] - }, { ".desc": "A parameter's value is used", "name": "parameter_variable_accessed", @@ -301,6 +269,18 @@ "count": 0 } ] + }, + { + ".desc": "Variable creation & usage validation, with optional name filtering", + "name": "variable_usage", + "threshold": 1, + "checks": [ + { + "validator": "variableUsage", + "count": 0, + "name": "" + } + ] } ] } diff --git a/localtypings/validatorPlan.d.ts b/localtypings/validatorPlan.d.ts index 439e94fef223..13ec08c14972 100644 --- a/localtypings/validatorPlan.d.ts +++ b/localtypings/validatorPlan.d.ts @@ -40,6 +40,12 @@ declare namespace pxt.blocks { count: number; } + export interface VariableUsageValidatorCheck extends ValidatorCheckBase { + validator: "variableUsage"; + count: number; + name?: string; + } + export interface EvaluationResult { result?: boolean; notes?: string; diff --git a/pxteditor/code-validation/runValidatorPlan.ts b/pxteditor/code-validation/runValidatorPlan.ts index 3a96867a1de7..1022341fd0c9 100644 --- a/pxteditor/code-validation/runValidatorPlan.ts +++ b/pxteditor/code-validation/runValidatorPlan.ts @@ -8,6 +8,7 @@ import { validateBlocksInSetExist } from "./validateBlocksInSetExist"; import { validateBlockCommentsExist } from "./validateCommentsExist"; import { validateSpecificBlockCommentsExist } from "./validateSpecificBlockCommentsExist"; import { getNestedChildBlocks } from "./getNestedChildBlocks"; +import { validateVariableUsage } from "./validateVariableUsage"; export function runValidatorPlan(usedBlocks: Blockly.Block[], plan: pxt.blocks.ValidatorPlan, planLib: pxt.blocks.ValidatorPlan[]): boolean { const startTime = Date.now(); @@ -32,6 +33,9 @@ export function runValidatorPlan(usedBlocks: Blockly.Block[], plan: pxt.blocks.V case "blockFieldValueExists": [successfulBlocks, checkPassed] = [...runBlockFieldValueExistsValidation(usedBlocks, check as pxt.blocks.BlockFieldValueExistsCheck)]; break; + case "variableUsage": + [successfulBlocks, checkPassed] = [...runVariableUsageValidation(usedBlocks, check as pxt.blocks.VariableUsageValidatorCheck)]; + break; default: pxt.debug(`Unrecognized validator: ${check.validator}`); checkPassed = false; @@ -104,3 +108,19 @@ function runBlockFieldValueExistsValidation(usedBlocks: Blockly.Block[], inputs: }); return [blockResults.successfulBlocks, blockResults.passed]; } + +function runVariableUsageValidation(usedBlocks: Blockly.Block[], inputs: pxt.blocks.VariableUsageValidatorCheck): [Blockly.Block[], boolean] { + const blockResults = validateVariableUsage({ + usedBlocks, + count: inputs.count, + name: inputs.name + }); + + // Flatten the map of passing variable definition blocks + const passingVarDefinitions: Blockly.Block[] = []; + for (const blocks of blockResults.passingVarDefinitions.values()) { + passingVarDefinitions.push(...blocks); + } + + return [passingVarDefinitions, blockResults.passed]; +} diff --git a/pxteditor/code-validation/validateVariableUsage.ts b/pxteditor/code-validation/validateVariableUsage.ts new file mode 100644 index 000000000000..97c023f41597 --- /dev/null +++ b/pxteditor/code-validation/validateVariableUsage.ts @@ -0,0 +1,55 @@ +/// +import * as Blockly from "blockly"; + +// Validates that variables are created and used within the workspace. +// Name is optional. If undefined or empty, all variable names are permitted. +// Returns the definition blocks for variables that passed the check. +export function validateVariableUsage({ + usedBlocks, + count, + name, +}: { + usedBlocks: Blockly.Block[]; + count: number; + name?: String; +}): { + passingVarDefinitions: Map; + passed: boolean; +} { + const varDefinitionBlocks: Map = new Map(); + const usedVars: Set = new Set(); + + for (const block of usedBlocks) { + if (!block.isEnabled()) { + continue; + } + + const varsUsed = block.getVarModels(); + for (const varModel of varsUsed ?? []) { + const varName = varModel.name; + if (!name || varName === name) { + if (block.type === "variables_set" || block.type === "variables_change") { + // Variable created + if (!varDefinitionBlocks.has(varName)) { + varDefinitionBlocks.set(varName, []); + } + varDefinitionBlocks.get(varName).push(block); + } else { + // Variable used + usedVars.add(varName); + } + } + } + } + + // Var passes check if it is both used and defined. + // We return the definition blocks to allow for recursively checking how the var was set. + const passingVarDefinitions = new Map(); + for (const [varName, definitionBlocks] of varDefinitionBlocks) { + if (usedVars.has(varName)) { + passingVarDefinitions.set(varName, definitionBlocks); + } + } + + return { passingVarDefinitions, passed: passingVarDefinitions.size >= count }; +} From ffec97e94b197f02df49a1c1e73115cd7e5d39e2 Mon Sep 17 00:00:00 2001 From: Thomas Sparks <69657545+thsparks@users.noreply.github.com> Date: Fri, 3 May 2024 15:25:46 -0700 Subject: [PATCH 5/9] Teacher Tool: Refactor Rubric to Checklist (#9996) This changes all "Rubric" references to "Checklist". Originally I was just going to change the public-facing strings, but I thought if I did that, we'd likely end up forever chasing down places where we accidentally put Rubric instead of Checklist in a public-facing place, and taking the time to refactor everything reduces the likelihood of that happening...and better to do it now than to wait until the codebase is even bigger. I also changed "MakeCode Project Insights" to "MakeCode Code Evaluation" I only found one place (the toolbar action menu dropdown) where styles had to be updated to account for the longer string size, but feel free to play with the upload target and see if you can spot anymore. --- teachertool/src/App.tsx | 8 +-- ...Display.tsx => ActiveChecklistDisplay.tsx} | 20 +++--- teachertool/src/components/CatalogOverlay.tsx | 8 +-- .../src/components/ChecklistPreview.tsx | 23 +++++++ ...icWorkspace.tsx => ChecklistWorkspace.tsx} | 64 +++++++++--------- teachertool/src/components/CriteriaTable.tsx | 8 +-- .../src/components/DragAndDropFileSurface.tsx | 2 +- .../src/components/EvalResultDisplay.tsx | 4 +- teachertool/src/components/HeaderBar.tsx | 1 - teachertool/src/components/HomeScreen.tsx | 56 ++++++++-------- ...bricModal.tsx => ImportChecklistModal.tsx} | 22 +++---- teachertool/src/components/MainPanel.tsx | 4 +- teachertool/src/components/PrintButton.tsx | 4 +- teachertool/src/components/RubricPreview.tsx | 23 ------- ...css => ActiveChecklistDisplay.module.scss} | 6 +- ...dule.scss => ChecklistPreview.module.scss} | 6 +- ...le.scss => ChecklistWorkspace.module.scss} | 34 +++++----- .../styling/EvalResultDisplay.module.scss | 2 +- .../components/styling/HeaderBar.module.scss | 13 ---- .../components/styling/HomeScreen.module.scss | 8 +-- ....scss => ImportChecklistModal.module.scss} | 6 +- .../components/styling/Toolbar.module.scss | 1 + teachertool/src/constants.ts | 31 +++++---- teachertool/src/services/fileSystemService.ts | 28 ++++---- teachertool/src/services/storageService.ts | 66 +++++++++---------- teachertool/src/state/actions.ts | 18 ++--- teachertool/src/state/helpers.ts | 18 ++--- teachertool/src/state/reducer.ts | 8 +-- teachertool/src/state/state.ts | 8 +-- ...aToRubric.ts => addCriteriaToChecklist.ts} | 14 ++-- .../transforms/getChecklistFromFileAsync.ts | 20 ++++++ .../src/transforms/getRubricFromFileAsync.ts | 20 ------ .../src/transforms/loadChecklistAsync.ts | 25 +++++++ teachertool/src/transforms/loadRubricAsync.ts | 25 ------- ...bric.ts => removeCriteriaFromChecklist.ts} | 12 ++-- .../transforms/replaceActiveChecklistAsync.ts | 23 +++++++ .../transforms/replaceActiveRubricAsync.ts | 23 ------- .../src/transforms/resetChecklistAsync.ts | 12 ++++ .../src/transforms/resetRubricAsync.ts | 12 ---- .../src/transforms/runEvaluateAsync.ts | 4 +- .../{setRubric.ts => setChecklist.ts} | 8 +-- .../src/transforms/setChecklistName.ts | 18 +++++ .../transforms/setEvalResultsToNotStarted.ts | 10 +-- .../src/transforms/setParameterValue.ts | 8 +-- teachertool/src/transforms/setRubricName.ts | 18 ----- .../tryLoadLastActiveChecklistAsync.ts | 24 +++++++ .../tryLoadLastActiveRubricAsync.ts | 24 ------- .../transforms/updateStoredChecklistAsync.ts | 15 +++++ .../src/transforms/updateStoredRubric.ts | 15 ----- .../src/types/{rubric.ts => checklist.ts} | 2 +- teachertool/src/types/criteria.ts | 4 +- teachertool/src/types/errorCode.ts | 4 +- teachertool/src/types/index.ts | 12 ++-- teachertool/src/types/modalOptions.ts | 6 +- teachertool/src/utils/index.ts | 10 +-- 55 files changed, 429 insertions(+), 439 deletions(-) rename teachertool/src/components/{ActiveRubricDisplay.tsx => ActiveChecklistDisplay.tsx} (53%) create mode 100644 teachertool/src/components/ChecklistPreview.tsx rename teachertool/src/components/{RubricWorkspace.tsx => ChecklistWorkspace.tsx} (68%) rename teachertool/src/components/{ImportRubricModal.tsx => ImportChecklistModal.tsx} (54%) delete mode 100644 teachertool/src/components/RubricPreview.tsx rename teachertool/src/components/styling/{ActiveRubricDisplay.module.scss => ActiveChecklistDisplay.module.scss} (89%) rename teachertool/src/components/styling/{RubricPreview.module.scss => ChecklistPreview.module.scss} (90%) rename teachertool/src/components/styling/{RubricWorkspace.module.scss => ChecklistWorkspace.module.scss} (95%) rename teachertool/src/components/styling/{ImportRubricModal.module.scss => ImportChecklistModal.module.scss} (83%) rename teachertool/src/transforms/{addCriteriaToRubric.ts => addCriteriaToChecklist.ts} (81%) create mode 100644 teachertool/src/transforms/getChecklistFromFileAsync.ts delete mode 100644 teachertool/src/transforms/getRubricFromFileAsync.ts create mode 100644 teachertool/src/transforms/loadChecklistAsync.ts delete mode 100644 teachertool/src/transforms/loadRubricAsync.ts rename teachertool/src/transforms/{removeCriteriaFromRubric.ts => removeCriteriaFromChecklist.ts} (57%) create mode 100644 teachertool/src/transforms/replaceActiveChecklistAsync.ts delete mode 100644 teachertool/src/transforms/replaceActiveRubricAsync.ts create mode 100644 teachertool/src/transforms/resetChecklistAsync.ts delete mode 100644 teachertool/src/transforms/resetRubricAsync.ts rename teachertool/src/transforms/{setRubric.ts => setChecklist.ts} (60%) create mode 100644 teachertool/src/transforms/setChecklistName.ts delete mode 100644 teachertool/src/transforms/setRubricName.ts create mode 100644 teachertool/src/transforms/tryLoadLastActiveChecklistAsync.ts delete mode 100644 teachertool/src/transforms/tryLoadLastActiveRubricAsync.ts create mode 100644 teachertool/src/transforms/updateStoredChecklistAsync.ts delete mode 100644 teachertool/src/transforms/updateStoredRubric.ts rename teachertool/src/types/{rubric.ts => checklist.ts} (77%) diff --git a/teachertool/src/App.tsx b/teachertool/src/App.tsx index 13a9b3bf4391..ad3e94198a98 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 362913185ee7..5c91d03bcc2e 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 d3eeb93afc24..f01a244aaf56 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 000000000000..a94ad2d96d70 --- /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 107cea484ec8..5b11b5f1dc15 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 02dd95f69fb9..6b8024f03b00 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 a1060fd1a484..2e89bcf5b7cb 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 62c95edf495c..6d20772996f9 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 96e88aae8c7a..06ef158d6d33 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 c0ebebccd2b1..6d345ebcfc66 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 0bc07ae187dd..ff8ee21c1b76 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 aef72e4d91d4..3cc41a4bd951 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 f4eb24c43d13..1c73685d5958 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 8041bfaabd40..000000000000 --- 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 02fa6e85508f..56079f550bda 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 8702dcf9064c..592b3d6ad209 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 29fb1b18f501..710817042945 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 9fd5b941d14a..bf1ba2248630 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 94a31aa2739f..dad4820419d5 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 f14b72564f15..0804be70159d 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 219bf22eb4c0..66d3613b34c2 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 ffe69ef88ff4..36ac645f75b3 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 4cf131add02f..ea7a9f264721 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 585b602f8f7e..ea8f25066f6f 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 33162c2fbf10..34f729e20937 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 cd3cc472f9e1..de4ba151fe7a 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 c69062de4f5f..61e14759e06e 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 d260aa14a8ab..40f487050a89 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 4a74375f8634..8b66df5b31e3 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 48ae4a540682..995ae2fff781 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 000000000000..d9471ff44a51 --- /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 d833e4c16968..000000000000 --- 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 000000000000..a0e22fb0c363 --- /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 2380c9adf3bd..000000000000 --- 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 31c662f1978e..2b7365bfd18c 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 000000000000..5de6de34eedc --- /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 216af0781708..000000000000 --- 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 000000000000..b5aa3f0c6002 --- /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 3bf786caa5a7..000000000000 --- 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 7988fe223214..69870de5140a 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 347dbf2e10a9..1b2ff797d330 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 000000000000..60c295c5484c --- /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 fd982aeea8fe..916cc12ce16d 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 2fa79ecd9b38..05aa572f3a6c 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 c18bf9e0387d..000000000000 --- 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 000000000000..d8dff736e437 --- /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 8fe4f661af68..000000000000 --- 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 000000000000..9eacee2c4a64 --- /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 c2bdf1f92a53..000000000000 --- 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 073ca325c7d0..d34cce738ce7 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 5c07b2b3204a..97f9ac6e68cb 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 9a339ea83e9e..f122a6b22bcc 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 b16bb1e5849c..2383b34e089b 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 a33331ef1047..086bf6f60f4a 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 ee7000281e79..670f49c49d1a 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 { From 978c9bde7e6d8d982527abdba7ba60bec1c92d59 Mon Sep 17 00:00:00 2001 From: Thomas Sparks <69657545+thsparks@users.noreply.github.com> Date: Mon, 6 May 2024 10:04:12 -0700 Subject: [PATCH 6/9] Add a check for the number 0 (which is for checking score set to 0) (#10004) This adds a validator plan to check for the number 0 block, which is useful if we want to ensure 0 was passed in as a parameter (used by microsoft/pxt-microbit#5644 to check for setting lives to 0 specifically, which produces output when non-zero values do not) --- common-docs/teachertool/validator-plans-shared.json | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/common-docs/teachertool/validator-plans-shared.json b/common-docs/teachertool/validator-plans-shared.json index 09fa4551c12d..681c7812ae04 100644 --- a/common-docs/teachertool/validator-plans-shared.json +++ b/common-docs/teachertool/validator-plans-shared.json @@ -281,6 +281,19 @@ "name": "" } ] + }, + { + ".desc": "The zero number block is present.", + "name": "number_zero", + "threshold": 1, + "checks": [ + { + "validator": "blockFieldValueExists", + "fieldType": "NUM", + "fieldValue": 0, + "blockType": "math_number" + } + ] } ] } From 456665210365e54228b5f2d8d73b66542d12208d Mon Sep 17 00:00:00 2001 From: thsparks Date: Mon, 6 May 2024 12:36:37 -0700 Subject: [PATCH 7/9] 10.0.21 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 5582d159a3a4..f1634593851e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "pxt-core", - "version": "10.0.20", + "version": "10.0.21", "description": "Microsoft MakeCode provides Blocks / JavaScript / Python tools and editors", "keywords": [ "TypeScript", From 1b0949c4b38f670bf0025ef0f528897c31fc4213 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Mon, 6 May 2024 16:51:11 -0700 Subject: [PATCH 8/9] Add partner telemetry flag (#10005) --- docfiles/pxtweb/cookieCompliance.ts | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docfiles/pxtweb/cookieCompliance.ts b/docfiles/pxtweb/cookieCompliance.ts index 28d4c4bdf126..d2da3badfbed 100644 --- a/docfiles/pxtweb/cookieCompliance.ts +++ b/docfiles/pxtweb/cookieCompliance.ts @@ -9,6 +9,7 @@ namespace pxt { let analyticsLoaded = false; let interactiveConsent = false; let isProduction = false; + let partnerName: string; class TelemetryQueue { private q: [A, B, C][] = []; @@ -185,6 +186,16 @@ namespace pxt { } export function initializeAppInsightsInternal(includeCookie = false) { + try { + const params = new URLSearchParams(window.location.search); + if (params.has("partner")) { + partnerName = params.get("partner"); + } + } + catch (e) { + console.warn("Could not parse search string", e); + } + // loadAppInsights is defined in docfiles/tracking.html const loadAI = (window as any).loadAppInsights; if (loadAI) { @@ -221,6 +232,10 @@ namespace pxt { telemetryItem.properties["target"] = pxtConfig.targetId; telemetryItem.properties["stage"] = (pxtConfig.relprefix || "/--").replace(/[^a-z]/ig, '') + if (partnerName) { + telemetryItem.properties["partner"] = partnerName; + } + const userAgent = navigator.userAgent.toLowerCase(); const electronRegexResult = /\belectron\/(\d+\.\d+\.\d+.*?)(?: |$)/i.exec(userAgent); // Example navigator.userAgent: "Mozilla/5.0 Chrome/61.0.3163.100 Electron/2.0.0 Safari/537.36" if (electronRegexResult) { From c48ddb08a97e7f6eb846a790c611c3d103faf75c Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Wed, 8 May 2024 10:01:01 -0700 Subject: [PATCH 9/9] fix help link in monaco flyout (#10008) --- webapp/src/monacoFlyout.tsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/webapp/src/monacoFlyout.tsx b/webapp/src/monacoFlyout.tsx index 474ec8451902..5f7d6a595b08 100644 --- a/webapp/src/monacoFlyout.tsx +++ b/webapp/src/monacoFlyout.tsx @@ -6,6 +6,7 @@ import * as workspace from "./workspace"; import * as data from "./data"; import * as auth from "./auth"; import { HELP_IMAGE_URI } from "../../pxteditor"; +import * as pxtblockly from "../../pxtblocks"; import ISettingsProps = pxt.editor.ISettingsProps; @@ -353,7 +354,11 @@ export class MonacoFlyout extends data.Component { + pxtblockly.external.openHelpUrl(helpUrl); + }; const qName = this.getQName(block) || this.getSnippetName(block); const selected = qName == this.state.selectedBlock; @@ -385,9 +390,11 @@ export class MonacoFlyout extends data.Component{description}
{snippet ? snippet : `${qName}(${params ? params.map(p => `${p.name}`).join(", ") : ""})`} - {helpUrl && - - } + {helpUrl && + + + + }
{params &&
{params.map((p, i) => {