Skip to content

Commit

Permalink
Add React App for Teacher Tool
Browse files Browse the repository at this point in the history
This has been largerly just copy/paste from Kiosk with a few substitutions from multiplayer and skillmap.
  • Loading branch information
thsparks committed Dec 8, 2023
1 parent f2a5482 commit 4f63eaf
Show file tree
Hide file tree
Showing 38 changed files with 32,247 additions and 7 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ webapp/public/skillmap.html
webapp/public/authcode.html
webapp/public/multiplayer.html
webapp/public/kiosk.html
webapp/public/teachertool.html
localtypings/blockly.d.ts
node_modules
*.sw?
Expand Down
13 changes: 10 additions & 3 deletions cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ function pxtFileList(pref: string) {
.concat(nodeutil.allFiles(pref + "built/web/authcode", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/multiplayer", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/kiosk", { maxDepth: 4 }))
.concat(nodeutil.allFiles(pref + "built/web/teachertool", { maxDepth: 4 }))
}

function semverCmp(a: string, b: string) {
Expand Down Expand Up @@ -458,7 +459,8 @@ function ciAsync() {
.then(() => crowdin.execCrowdinAsync("upload", "built/skillmap-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/authcode-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/multiplayer-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/kiosk-strings.json"));
.then(() => crowdin.execCrowdinAsync("upload", "built/kiosk-strings.json"))
.then(() => crowdin.execCrowdinAsync("upload", "built/teachertool-strings.json"));
if (uploadApiStrings)
p = p.then(() => crowdin.execCrowdinAsync("upload", "built/strings.json"))
if (uploadDocs || uploadApiStrings)
Expand Down Expand Up @@ -1049,6 +1051,7 @@ function uploadCoreAsync(opts: UploadOptions) {
"authcodeUrl": opts.localDir + "authcode.html",
"multiplayerUrl": opts.localDir + "multiplayer.html",
"kioskUrl": opts.localDir + "kiosk.html",
"teachertoolUrl": opts.localDir + "teachertool.html",
"isStatic": true,
}
const targetImageLocalPaths = targetImagePaths.map(k =>
Expand Down Expand Up @@ -1102,6 +1105,7 @@ function uploadCoreAsync(opts: UploadOptions) {
"authcode.html",
"multiplayer.html",
"kiosk.html",
"teachertool.html",
]

// expandHtml is manually called on these files before upload
Expand All @@ -1112,6 +1116,7 @@ function uploadCoreAsync(opts: UploadOptions) {
"authcode.html",
"multiplayer.html",
"kiosk.html",
"teachertool.html",
]

nodeutil.mkdirP("built/uploadrepl")
Expand Down Expand Up @@ -2041,7 +2046,8 @@ async function buildSemanticUIAsync(parsed?: commandParser.ParsedCommand) {
await Promise.all([
generateReactCommonCss("skillmap"),
generateReactCommonCss("authcode"),
generateReactCommonCss("multiplayer")
generateReactCommonCss("multiplayer"),
generateReactCommonCss("teachertool")
]);

// Run postcss with autoprefixer and rtlcss
Expand Down Expand Up @@ -2070,7 +2076,8 @@ async function buildSemanticUIAsync(parsed?: commandParser.ParsedCommand) {
"blockly.css",
"react-common-skillmap.css",
"react-common-authcode.css",
"react-common-multiplayer.css"
"react-common-multiplayer.css",
"react-common-teachertool.css"
];

for (const cssFile of files) {
Expand Down
3 changes: 2 additions & 1 deletion cli/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ let serveOptions: ServeOptions;

const webappNames = [
"kiosk",
"multiplayer"
"multiplayer",
"teachertool"
// TODO: Add other webapp names here: "skillmap", "authcode"
];

Expand Down
38 changes: 36 additions & 2 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,10 @@ function updateKioskStrings() {
return buildStrings("built/kiosk-strings.json", ["kiosk/src"], true);
}

function updateTeacherToolStrings() {
return buildStrings("built/teachertool-strings.json", ["teachertool/src"], true);
}

// TODO: Copied from Jakefile; should be async
function buildStrings(out, rootPaths, recursive) {
let errCnt = 0;
Expand Down Expand Up @@ -687,6 +691,33 @@ const copyKioskHtml = () => rimraf("webapp/public/kiosk.html")

const kiosk = gulp.series(cleanKiosk, buildKiosk, gulp.series(copyKioskCss, copyKioskJs, copyKioskHtml));

/********************************************************
Teacher Tool
*********************************************************/

const teacherToolRoot = "teachertool";
const teacherToolOut = "built/web/teachertool";

const cleanTeacherTool = () => rimraf(teacherToolOut);

const npmBuildTeacherTool = () => exec("npm run build", true, { cwd: teacherToolRoot });

const buildTeacherTool = async () => await npmBuildTeacherTool();

const copyTeacherToolCss = () => gulp.src(`${teacherToolRoot}/build/static/css/*`)
.pipe(gulp.dest(`${teacherToolOut}/css`));

const copyTeacherToolJs = () => gulp.src(`${teacherToolRoot}/build/static/js/*`)
.pipe(gulp.dest(`${teacherToolOut}/js`));

const copyTeacherToolHtml = () => rimraf("webapp/public/teachertool.html")
.then(() => gulp.src(`${teacherToolRoot}/build/index.html`)
.pipe(replace(/="\/static\//g, `="/blb/teachertool/`))
.pipe(concat("teachertool.html"))
.pipe(gulp.dest("webapp/public")));

const teacherTool = gulp.series(cleanTeacherTool, buildTeacherTool, gulp.series(copyTeacherToolCss, copyTeacherToolJs, copyTeacherToolHtml));

/********************************************************
Webapp build wrappers
*********************************************************/
Expand All @@ -700,12 +731,13 @@ const maybeUpdateWebappStrings = () => {
updateAuthcodeStrings,
updateMultiplayerStrings,
updateKioskStrings,
updateTeacherToolStrings,
);
};

const maybeBuildWebapps = () => {
if (!shouldBuildWebapps()) return noop;
return gulp.parallel(skillmap, authcode, multiplayer, kiosk);
return gulp.parallel(skillmap, authcode, multiplayer, kiosk, teacherTool);
}

/********************************************************
Expand All @@ -715,7 +747,7 @@ const maybeBuildWebapps = () => {
const lintWithEslint = () => Promise.all(
["cli", "pxtblocks", "pxteditor", "pxtlib", "pxtcompiler",
"pxtpy", "pxtrunner", "pxtsim", "webapp",
"docfiles/pxtweb", "skillmap", "authcode", "multiplayer"/*, "kiosk"*/, "docs/static/streamer"].map(dirname =>
"docfiles/pxtweb", "skillmap", "authcode", "multiplayer"/*, "kiosk"*/, "teachertool", "docs/static/streamer"].map(dirname =>
exec(`node node_modules/eslint/bin/eslint.js -c .eslintrc.js --ext .ts,.tsx ./${dirname}/`, true)))
.then(() => console.log("linted"))
const lint = lintWithEslint
Expand Down Expand Up @@ -863,6 +895,8 @@ exports.skillmap = skillmap;
exports.authcode = authcode;
exports.multiplayer = multiplayer;
exports.kiosk = kiosk;
exports.teacherTool = teacherTool;
exports.tt = teacherTool;
exports.icons = buildSVGIcons;
exports.testhelpers = testhelpers;
exports.testpxteditor = testpxteditor;
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
"built/web/multiplayer/js/*.js",
"built/web/kiosk/css/*.css",
"built/web/kiosk/js/*.js",
"built/web/teachertool/css/*.css",
"built/web/teachertool/js/*.js",
"pxtcompiler/ext-typescript/lib/lib.d.ts",
"pxtcompiler/ext-typescript/lib/typescript.js",
"pxtcompiler/ext-typescript/lib/typescriptServices.d.ts",
Expand Down Expand Up @@ -164,6 +166,6 @@
"test:lang": "gulp testlang",
"update": "gulp update",
"watch-streamer": "cd docs/static/streamer && tsc -t es6 --watch",
"prepare": "cd skillmap && npm install && cd .. && cd authcode && npm install && cd .. && cd multiplayer && npm install && cd .. && cd kiosk && npm install && cd .."
"prepare": "cd skillmap && npm install && cd .. && cd authcode && npm install && cd .. && cd multiplayer && npm install && cd .. && cd kiosk && npm install && cd teachertool && npm install && cd .."
}
}
1 change: 1 addition & 0 deletions pxtlib/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ namespace pxt {
authcodeUrl?: string; // "/beta---authcode"
multiplayerUrl?: string; // "/beta---multiplayer"
kioskUrl?: string; // "/beta---kiosk"
teachertoolUrl?: string; // "/beta---teachertool"
isStatic?: boolean;
verprefix?: string; // "v1"
}
Expand Down
10 changes: 10 additions & 0 deletions react-common/styles/react-common-teachertool-core.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* This file is the same as react-common-teachertool.less except it doesn't import any
* variables from the target. This is used for pxt-core's css build
*/

// Import variables from pxt-core
@import "themes/default/globals/site.variables";
@import "themes/pxt/globals/site.variables";

@import "react-common.less";
12 changes: 12 additions & 0 deletions react-common/styles/react-common-teachertool.less
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/**
* Used for building react-common-teachertool.css
*/

// Import variables from pxt-core
@import "themes/default/globals/site.variables";
@import "themes/pxt/globals/site.variables";

// Import the variables from the target
@import "site/globals/site.variables";

@import "react-common.less";
3 changes: 3 additions & 0 deletions teachertool/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DISABLE_ESLINT_PLUGIN=true
GENERATE_SOURCEMAP=false
BROWSER=none
6 changes: 6 additions & 0 deletions teachertool/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
"parserOptions": {
"project": "teachertool/tsconfig.json",
},
"ignorePatterns": ["tests/**/*.spec.ts", "public/**/*", "build/**/*"]
}
4 changes: 4 additions & 0 deletions teachertool/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.vscode
build
!package-lock.json
src/Fonts.css
5 changes: 5 additions & 0 deletions teachertool/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"arrowParens": "avoid",
"semi": true,
"tabWidth": 4
}
35 changes: 35 additions & 0 deletions teachertool/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Teacher Tool

## config.json settings

|Key|Purpose|
|---------------------------------|-|
|Volume | Volume for sounds within the page|

## Localhost testing

To test the Teacher Tool locally:

1. Ensure your pxt repo is up to date and has been built recently.
2. In a command shell, in the `pxt` repo, cd into the `teachertool` folder and start the Teacher Tool dev server: `npm run start`. This will *not* open a browser window.
3. In another command shell, in the `pxt-arcade` repo, start the Arcade dev server: `pxt serve --rebundle`. This will open the Arcade webapp in a browser.

Requests to the `/teachertool` endpoint will be routed to the Teacher Tool dev server.

Debug and step through Teacher Tool code using the browser dev tools (F12 to open).


## Test in staging environment

1. In the pxt repo, run `gulp` to ensure production teacher tool is built.
2. In a browser, go to `https://staging.pxt.io/oauth/gettoken`. This should return a url with an auth token embedded. Copy the entire url value to your clipboard.
- It should look something like `https://staging.pxt.io/?access_token=X.XXXXXXXX`
- If you get access denied, contact your manager to help you.
3. In a command shell, set environment variable `PXT_ACCESS_TOKEN` with the copied value.
4. In the same shell, in the pxt-arcade repo, run `pxt uploadtrg --rebundle`. This should return a url to your private build.
- It should look something like `https://arcade.staging.pxt.io/app/XXXXXX-XXXXX`
- Paste in a browser and append "/teachertool". This should take you to your teacher tool build in staging.

## Test in production environment

Follow the "Test in staging environment" instructions, but get your auth token from `https://makecode.com/oauth/gettoken`.
41 changes: 41 additions & 0 deletions teachertool/config-overrides.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const { aliasWebpack } = require("react-app-alias-ex");
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");

module.exports = function (config, env) {
const isEnvProduction = env === "production";
const aliasFn = aliasWebpack({});
config = {
...aliasFn(config),
plugins: [
...config.plugins.filter((p) => !(p instanceof HtmlWebpackPlugin)),
new NodePolyfillPlugin(),
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: "./public/index.html",
},
isEnvProduction
? {
minify: {
removeComments: false,
collapseWhitespace: false,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
],
};
return config;
};
Loading

0 comments on commit 4f63eaf

Please sign in to comment.