Compare commits
35 Commits
open-relea
...
release/te
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4825c3d68c | ||
|
|
4e27a35e10 | ||
|
|
ad0e2af8c8 | ||
|
|
d03e7c40d8 | ||
|
|
5a7063c123 | ||
|
|
9348c4bb4c | ||
|
|
5c5ff1190b | ||
|
|
7aee8562a8 | ||
|
|
ebca59a38f | ||
|
|
f87d521bc0 | ||
|
|
5280cef554 | ||
|
|
08430571ed | ||
|
|
3de6821c5d | ||
|
|
fb06133a27 | ||
|
|
12f1c72b7e | ||
|
|
ca8d08c8a0 | ||
|
|
30a4ca17ac | ||
|
|
25d76c0e59 | ||
|
|
6527f505f1 | ||
|
|
400950cff8 | ||
|
|
0219f5cd25 | ||
|
|
fdcab456e8 | ||
|
|
5283e7c7c6 | ||
|
|
e39533c56a | ||
|
|
212014fed9 | ||
|
|
9600301a62 | ||
|
|
1d5f64e1db | ||
|
|
f5208c58aa | ||
|
|
c15680cb8c | ||
|
|
76f41439e9 | ||
|
|
4581cf8698 | ||
|
|
95fa32eaaa | ||
|
|
1f729becbe | ||
|
|
7ad1df8bd0 | ||
|
|
c9d0abe968 |
5
.github/workflows/ci.yml
vendored
5
.github/workflows/ci.yml
vendored
@@ -11,9 +11,6 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
node: [18.15, 20]
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
@@ -24,7 +21,7 @@ jobs:
|
|||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
# Because of node 18 bug (https://github.com/nodejs/node/issues/47563), Pinning node version 18.15 until the next release of node
|
# Because of node 18 bug (https://github.com/nodejs/node/issues/47563), Pinning node version 18.15 until the next release of node
|
||||||
with:
|
with:
|
||||||
node-version: ${{ matrix.node }}
|
node-version-file: '.nvmrc'
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
run: npm ci
|
run: npm ci
|
||||||
|
|||||||
32
.github/workflows/npm-publish.yml
vendored
32
.github/workflows/npm-publish.yml
vendored
@@ -1,32 +0,0 @@
|
|||||||
name: Release CI
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- "*"
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
release:
|
|
||||||
name: Release
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v2
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
|
|
||||||
- name: Setup Node.js
|
|
||||||
uses: actions/setup-node@v2
|
|
||||||
with:
|
|
||||||
node-version: 12
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: npm ci
|
|
||||||
|
|
||||||
- name: Create Build
|
|
||||||
run: npm run build
|
|
||||||
|
|
||||||
- name: Release Package
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.SEMANTIC_RELEASE_GITHUB_TOKEN }}
|
|
||||||
NPM_TOKEN: ${{ secrets.SEMANTIC_RELEASE_NPM_TOKEN }}
|
|
||||||
run: npm semantic-release
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
. "$(dirname "$0")/_/husky.sh"
|
|
||||||
|
|
||||||
npm run lint
|
|
||||||
27
.releaserc
27
.releaserc
@@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"branch": "master",
|
|
||||||
"tagFormat": "v${version}",
|
|
||||||
"verifyConditions": [
|
|
||||||
"@semantic-release/npm",
|
|
||||||
{
|
|
||||||
"path": "@semantic-release/github",
|
|
||||||
"assets": {
|
|
||||||
"path": "dist/*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"analyzeCommits": "@semantic-release/commit-analyzer",
|
|
||||||
"generateNotes": "@semantic-release/release-notes-generator",
|
|
||||||
"prepare": "@semantic-release/npm",
|
|
||||||
"publish": [
|
|
||||||
"@semantic-release/npm",
|
|
||||||
{
|
|
||||||
"path": "@semantic-release/github",
|
|
||||||
"assets": {
|
|
||||||
"path": "dist/*"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"success": [],
|
|
||||||
"fail": []
|
|
||||||
}
|
|
||||||
@@ -13,7 +13,9 @@ metadata:
|
|||||||
- url: "https://ora-grading.stage.edx.org"
|
- url: "https://ora-grading.stage.edx.org"
|
||||||
title: "Stage Site"
|
title: "Stage Site"
|
||||||
icon: "Web"
|
icon: "Web"
|
||||||
|
annotations:
|
||||||
|
openedx.org/release: "master"
|
||||||
spec:
|
spec:
|
||||||
owner: "group:openedx-unmaintained"
|
owner: "user:codewithemad"
|
||||||
type: 'website'
|
type: 'website'
|
||||||
lifecycle: 'production'
|
lifecycle: 'production'
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
# This file describes this Open edX repo, as described in OEP-2:
|
|
||||||
# http://open-edx-proposals.readthedocs.io/en/latest/oeps/oep-0002.html#specification
|
|
||||||
|
|
||||||
tags:
|
|
||||||
- frontend-app
|
|
||||||
- masters
|
|
||||||
oeps:
|
|
||||||
oep-2: true # Repository metadata
|
|
||||||
openedx-release: {ref: master}
|
|
||||||
14049
package-lock.json
generated
14049
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
39
package.json
39
package.json
@@ -6,6 +6,9 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/edx/frontend-app-ora-grading.git"
|
"url": "git+https://github.com/edx/frontend-app-ora-grading.git"
|
||||||
},
|
},
|
||||||
|
"browserslist": [
|
||||||
|
"extends @edx/browserslist-config"
|
||||||
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "fedx-scripts webpack",
|
"build": "fedx-scripts webpack",
|
||||||
"i18n_extract": "fedx-scripts formatjs extract",
|
"i18n_extract": "fedx-scripts formatjs extract",
|
||||||
@@ -13,9 +16,9 @@
|
|||||||
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
|
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
|
||||||
"semantic-release": "semantic-release",
|
"semantic-release": "semantic-release",
|
||||||
"start": "fedx-scripts webpack-dev-server --progress",
|
"start": "fedx-scripts webpack-dev-server --progress",
|
||||||
|
"dev": "PUBLIC_PATH=/ora-grading/ MFE_CONFIG_API_URL='http://localhost:8000/api/mfe_config/v1' fedx-scripts webpack-dev-server --progress --host apps.local.openedx.io",
|
||||||
"test": "TZ=GMT fedx-scripts jest --coverage --passWithNoTests",
|
"test": "TZ=GMT fedx-scripts jest --coverage --passWithNoTests",
|
||||||
"watch-tests": "jest --watch",
|
"watch-tests": "jest --watch"
|
||||||
"prepare": "husky install"
|
|
||||||
},
|
},
|
||||||
"author": "edX",
|
"author": "edX",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
@@ -25,16 +28,17 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
|
||||||
"@edx/frontend-component-header": "^5.6.0",
|
"@edx/frontend-component-footer": "^14.6.0",
|
||||||
"@edx/frontend-platform": "8.0.0",
|
"@edx/frontend-component-header": "^6.2.0",
|
||||||
|
"@edx/frontend-platform": "^8.3.1",
|
||||||
"@edx/openedx-atlas": "^0.6.0",
|
"@edx/openedx-atlas": "^0.6.0",
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
"@fortawesome/fontawesome-svg-core": "^1.2.36",
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
"@fortawesome/free-solid-svg-icons": "^5.15.4",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@openedx/frontend-slot-footer": "^1.0.2",
|
"@openedx/paragon": "^22.16.0",
|
||||||
"@openedx/paragon": "21.11.3",
|
|
||||||
"@redux-beacon/segment": "^1.1.0",
|
"@redux-beacon/segment": "^1.1.0",
|
||||||
|
"@redux-devtools/extension": "3.0.0",
|
||||||
"@reduxjs/toolkit": "^1.6.1",
|
"@reduxjs/toolkit": "^1.6.1",
|
||||||
"@testing-library/user-event": "^14.0.0",
|
"@testing-library/user-event": "^14.0.0",
|
||||||
"@zip.js/zip.js": "^2.4.6",
|
"@zip.js/zip.js": "^2.4.6",
|
||||||
@@ -52,18 +56,17 @@
|
|||||||
"moment": "^2.29.3",
|
"moment": "^2.29.3",
|
||||||
"prop-types": "15.8.1",
|
"prop-types": "15.8.1",
|
||||||
"query-string": "7.1.3",
|
"query-string": "7.1.3",
|
||||||
"react": "^17.0.2",
|
"react": "^18.3.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.3.1",
|
||||||
"react-helmet": "^6.1.0",
|
"react-helmet": "^6.1.0",
|
||||||
"react-intl": "6.4.7",
|
"react-intl": "6.4.7",
|
||||||
"react-pdf": "^5.5.0",
|
"react-pdf": "^7.0.0",
|
||||||
"react-redux": "^7.2.9",
|
"react-redux": "^7.2.9",
|
||||||
"react-router": "6.21.3",
|
"react-router": "6.21.3",
|
||||||
"react-router-dom": "6.21.3",
|
"react-router-dom": "6.21.3",
|
||||||
"react-router-redux": "^5.0.0-alpha.9",
|
"react-router-redux": "^5.0.0-alpha.9",
|
||||||
"redux": "4.2.1",
|
"redux": "4.2.1",
|
||||||
"redux-beacon": "^2.1.0",
|
"redux-beacon": "^2.1.0",
|
||||||
"redux-devtools-extension": "2.13.9",
|
|
||||||
"redux-logger": "3.0.6",
|
"redux-logger": "3.0.6",
|
||||||
"redux-thunk": "2.4.2",
|
"redux-thunk": "2.4.2",
|
||||||
"regenerator-runtime": "^0.14.0",
|
"regenerator-runtime": "^0.14.0",
|
||||||
@@ -72,23 +75,21 @@
|
|||||||
"whatwg-fetch": "^3.6.2"
|
"whatwg-fetch": "^3.6.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@edx/browserslist-config": "^1.2.0",
|
"@edx/browserslist-config": "^1.3.0",
|
||||||
"@edx/react-unit-test-utils": "3.0.0",
|
"@edx/react-unit-test-utils": "^4.0.0",
|
||||||
"@edx/reactifex": "^2.1.1",
|
"@edx/reactifex": "^2.1.1",
|
||||||
"@openedx/frontend-build": "14.0.3",
|
"@openedx/frontend-build": "^14.3.3",
|
||||||
"@testing-library/jest-dom": "^6.0.0",
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
"@testing-library/react": "12.1.5",
|
"@testing-library/react": "^16.2.0",
|
||||||
"axios-mock-adapter": "^1.20.0",
|
"axios-mock-adapter": "^1.20.0",
|
||||||
"fetch-mock": "^9.11.0",
|
"fetch-mock": "^9.11.0",
|
||||||
"husky": "^7.0.0",
|
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "29.7.0",
|
"jest": "29.7.0",
|
||||||
"jest-environment-jsdom": "^29.7.0",
|
"jest-environment-jsdom": "^29.7.0",
|
||||||
"jest-expect-message": "^1.0.2",
|
"jest-expect-message": "^1.0.2",
|
||||||
"react-dev-utils": "^12.0.1",
|
"react-dev-utils": "^12.0.1",
|
||||||
"react-test-renderer": "^17.0.2",
|
"react-test-renderer": "^18.3.1",
|
||||||
"reactifex": "1.1.1",
|
"reactifex": "1.1.1",
|
||||||
"redux-mock-store": "^1.5.4",
|
"redux-mock-store": "^1.5.5"
|
||||||
"semantic-release": "^19.0.3"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import PropTypes from 'prop-types';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { BrowserRouter as Router } from 'react-router-dom';
|
import { BrowserRouter as Router } from 'react-router-dom';
|
||||||
|
|
||||||
import FooterSlot from '@openedx/frontend-slot-footer';
|
import { FooterSlot } from '@edx/frontend-component-footer';
|
||||||
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
import { LearningHeader as Header } from '@edx/frontend-component-header';
|
||||||
|
|
||||||
import { selectors } from 'data/redux';
|
import { selectors } from 'data/redux';
|
||||||
|
|
||||||
import DemoWarning from 'containers/DemoWarning';
|
import DemoWarning from 'containers/DemoWarning';
|
||||||
import CTA from 'containers/CTA';
|
|
||||||
import NotificationsBanner from 'containers/NotificationsBanner';
|
import NotificationsBanner from 'containers/NotificationsBanner';
|
||||||
import ListView from 'containers/ListView';
|
import ListView from 'containers/ListView';
|
||||||
|
|
||||||
@@ -27,7 +26,6 @@ export const App = ({ courseMetadata, isEnabled }) => (
|
|||||||
data-testid="header"
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
{!isEnabled && <DemoWarning />}
|
{!isEnabled && <DemoWarning />}
|
||||||
<CTA />
|
|
||||||
<NotificationsBanner />
|
<NotificationsBanner />
|
||||||
<main data-testid="main">
|
<main data-testid="main">
|
||||||
<ListView />
|
<ListView />
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ $fa-font-path: "~font-awesome/fonts";
|
|||||||
$input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.0.0 to work
|
$input-focus-box-shadow: $input-box-shadow; // hack to get upgrade to paragon 4.0.0 to work
|
||||||
|
|
||||||
@import "~@edx/frontend-component-footer/dist/_footer";
|
@import "~@edx/frontend-component-footer/dist/_footer";
|
||||||
|
@import "~@edx/frontend-component-header/dist/index";
|
||||||
|
|
||||||
#root {
|
#root {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -15,10 +15,9 @@ jest.mock('data/redux', () => ({
|
|||||||
jest.mock('@edx/frontend-component-header', () => ({
|
jest.mock('@edx/frontend-component-header', () => ({
|
||||||
LearningHeader: 'Header',
|
LearningHeader: 'Header',
|
||||||
}));
|
}));
|
||||||
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'Footer' }));
|
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'FooterSlot' }));
|
||||||
|
|
||||||
jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
jest.mock('containers/DemoWarning', () => 'DemoWarning');
|
||||||
jest.mock('containers/CTA', () => 'CTA');
|
|
||||||
jest.mock('containers/ListView', () => 'ListView');
|
jest.mock('containers/ListView', () => 'ListView');
|
||||||
jest.mock('components/Head', () => 'Head');
|
jest.mock('components/Head', () => 'Head');
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ exports[`App router component snapshot: disabled (show demo warning) 1`] = `
|
|||||||
data-testid="header"
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
<DemoWarning />
|
<DemoWarning />
|
||||||
<CTA />
|
|
||||||
<NotificationsBanner />
|
<NotificationsBanner />
|
||||||
<main
|
<main
|
||||||
data-testid="main"
|
data-testid="main"
|
||||||
@@ -33,7 +32,6 @@ exports[`App router component snapshot: enabled 1`] = `
|
|||||||
courseTitle="course-title"
|
courseTitle="course-title"
|
||||||
data-testid="header"
|
data-testid="header"
|
||||||
/>
|
/>
|
||||||
<CTA />
|
|
||||||
<NotificationsBanner />
|
<NotificationsBanner />
|
||||||
<main
|
<main
|
||||||
data-testid="main"
|
data-testid="main"
|
||||||
|
|||||||
@@ -1,24 +1,28 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
|
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
|
||||||
<ErrorPage
|
<React Strict Mode>
|
||||||
message="test-error-message"
|
<ErrorPage
|
||||||
/>
|
message="test-error-message"
|
||||||
|
/>
|
||||||
|
</React Strict Mode>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
||||||
<AppProvider
|
<React Strict Mode>
|
||||||
store={
|
<AppProvider
|
||||||
{
|
store={
|
||||||
"dispatch": [Function],
|
{
|
||||||
"getState": [Function],
|
"dispatch": [Function],
|
||||||
"replaceReducer": [Function],
|
"getState": [Function],
|
||||||
"subscribe": [Function],
|
"replaceReducer": [Function],
|
||||||
Symbol(Symbol.observable): [Function],
|
"subscribe": [Function],
|
||||||
|
Symbol(Symbol.observable): [Function],
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
wrapWithRouter={false}
|
||||||
wrapWithRouter={false}
|
>
|
||||||
>
|
<App />
|
||||||
<App />
|
</AppProvider>
|
||||||
</AppProvider>
|
</React Strict Mode>
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,17 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
import { Document, Page, pdfjs } from 'react-pdf';
|
||||||
import { pdfjs, Document, Page } from 'react-pdf';
|
|
||||||
import {
|
import {
|
||||||
Icon, Form, ActionRow, IconButton,
|
Icon, Form, ActionRow, IconButton,
|
||||||
} from '@openedx/paragon';
|
} from '@openedx/paragon';
|
||||||
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
import { ChevronLeft, ChevronRight } from '@openedx/paragon/icons';
|
||||||
import pdfjsWorker from 'react-pdf/dist/esm/pdf.worker.entry';
|
|
||||||
|
|
||||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
import { rendererHooks } from './pdfHooks';
|
import { rendererHooks } from './pdfHooks';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <PDFRenderer />
|
* <PDFRenderer />
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
import { useState, useRef } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
|
|
||||||
import { pdfjs } from 'react-pdf';
|
|
||||||
import pdfjsWorker from 'react-pdf/dist/esm/pdf.worker.entry';
|
|
||||||
|
|
||||||
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
import 'react-pdf/dist/esm/Page/AnnotationLayer.css';
|
||||||
|
|
||||||
import { ErrorStatuses } from 'data/constants/requests';
|
import { ErrorStatuses } from 'data/constants/requests';
|
||||||
import { StrictDict } from 'utils';
|
import { StrictDict } from 'utils';
|
||||||
import * as module from './pdfHooks';
|
import * as module from './pdfHooks';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
|
|
||||||
|
|
||||||
export const errors = StrictDict({
|
export const errors = StrictDict({
|
||||||
missingPDF: 'MissingPDFException',
|
missingPDF: 'MissingPDFException',
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { shallow } from '@edx/react-unit-test-utils';
|
|
||||||
|
|
||||||
import { CTA } from '.';
|
|
||||||
|
|
||||||
describe('CTA component', () => {
|
|
||||||
test('snapshots', () => {
|
|
||||||
const el = shallow(<CTA hide />);
|
|
||||||
expect(el.snapshot).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`CTA component snapshots 1`] = `
|
|
||||||
<PageBanner>
|
|
||||||
<span>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Thanks for using the new ORA staff grading experience. "
|
|
||||||
description="Thank user for using ora and ask for feed back"
|
|
||||||
id="ora-grading.CTA.feedbackMessage"
|
|
||||||
/>
|
|
||||||
<Hyperlink
|
|
||||||
destination="https://docs.google.com/forms/d/1Hu1rgJcCHl5_EtDb5Up3hiZ40sSUtkZQfRHJ3fWOvfQ/edit"
|
|
||||||
isInline={true}
|
|
||||||
showLaunchIcon={false}
|
|
||||||
target="_blank"
|
|
||||||
variant="muted"
|
|
||||||
>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage="Provide some feedback"
|
|
||||||
description="placeholder for the feedback anchor link"
|
|
||||||
id="ora-grading.CTA.linkMessage"
|
|
||||||
/>
|
|
||||||
</Hyperlink>
|
|
||||||
<FormattedMessage
|
|
||||||
defaultMessage=" and let us know what you think!"
|
|
||||||
description="inform user to provide feedback"
|
|
||||||
id="ora-grading.CTA.letUsKnowMessage"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</PageBanner>
|
|
||||||
`;
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { FormattedMessage } from '@edx/frontend-platform/i18n';
|
|
||||||
import { PageBanner, Hyperlink } from '@openedx/paragon';
|
|
||||||
|
|
||||||
import messages from './messages';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <CTA />
|
|
||||||
*/
|
|
||||||
export const CTA = () => (
|
|
||||||
<PageBanner>
|
|
||||||
<span>
|
|
||||||
<FormattedMessage {...messages.ctaFeedbackMessage} />
|
|
||||||
<Hyperlink
|
|
||||||
isInline
|
|
||||||
variant="muted"
|
|
||||||
destination="https://docs.google.com/forms/d/1Hu1rgJcCHl5_EtDb5Up3hiZ40sSUtkZQfRHJ3fWOvfQ/edit"
|
|
||||||
target="_blank"
|
|
||||||
showLaunchIcon={false}
|
|
||||||
>
|
|
||||||
<FormattedMessage {...messages.ctaLinkMessage} />
|
|
||||||
</Hyperlink>
|
|
||||||
<FormattedMessage {...messages.ctaLetUsKnowMessage} />
|
|
||||||
</span>
|
|
||||||
</PageBanner>
|
|
||||||
);
|
|
||||||
|
|
||||||
export default CTA;
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
/* eslint-disable quotes */
|
|
||||||
import { defineMessages } from '@edx/frontend-platform/i18n';
|
|
||||||
import { StrictDict } from 'utils';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
ctaFeedbackMessage: {
|
|
||||||
id: 'ora-grading.CTA.feedbackMessage',
|
|
||||||
defaultMessage: 'Thanks for using the new ORA staff grading experience. ',
|
|
||||||
description: 'Thank user for using ora and ask for feed back',
|
|
||||||
},
|
|
||||||
ctaLinkMessage: {
|
|
||||||
id: 'ora-grading.CTA.linkMessage',
|
|
||||||
defaultMessage: 'Provide some feedback',
|
|
||||||
description: 'placeholder for the feedback anchor link',
|
|
||||||
},
|
|
||||||
ctaLetUsKnowMessage: {
|
|
||||||
id: 'ora-grading.CTA.letUsKnowMessage',
|
|
||||||
defaultMessage: ' and let us know what you think!',
|
|
||||||
description: 'inform user to provide feedback',
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default StrictDict(messages);
|
|
||||||
@@ -36,12 +36,13 @@ export class RadioCriterion extends React.Component {
|
|||||||
<Form.RadioSet name={config.name} value={data}>
|
<Form.RadioSet name={config.name} value={data}>
|
||||||
{config.options.map((option) => (
|
{config.options.map((option) => (
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
key={option.name}
|
key={option.name}
|
||||||
value={option.name}
|
value={option.name}
|
||||||
description={intl.formatMessage(messages.optionPoints, { points: option.points })}
|
description={intl.formatMessage(messages.optionPoints, { points: option.points })}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
disabled={!isGrading}
|
disabled={!isGrading}
|
||||||
|
style={{ flexShrink: 0 }}
|
||||||
>
|
>
|
||||||
{option.label}
|
{option.label}
|
||||||
</Form.Radio>
|
</Form.Radio>
|
||||||
|
|||||||
@@ -6,21 +6,31 @@ exports[`Radio Criterion Container snapshot is grading 1`] = `
|
|||||||
value="selected radio option"
|
value="selected radio option"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="1 points"
|
description="1 points"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
key="option name"
|
key="option name"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name"
|
value="option name"
|
||||||
>
|
>
|
||||||
this label
|
this label
|
||||||
</Form.Radio>
|
</Form.Radio>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="2 points"
|
description="2 points"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name 2"
|
value="option name 2"
|
||||||
>
|
>
|
||||||
this label 2
|
this label 2
|
||||||
@@ -34,21 +44,31 @@ exports[`Radio Criterion Container snapshot is not grading 1`] = `
|
|||||||
value="selected radio option"
|
value="selected radio option"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="1 points"
|
description="1 points"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
key="option name"
|
key="option name"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name"
|
value="option name"
|
||||||
>
|
>
|
||||||
this label
|
this label
|
||||||
</Form.Radio>
|
</Form.Radio>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="2 points"
|
description="2 points"
|
||||||
disabled={true}
|
disabled={true}
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name 2"
|
value="option name 2"
|
||||||
>
|
>
|
||||||
this label 2
|
this label 2
|
||||||
@@ -62,21 +82,31 @@ exports[`Radio Criterion Container snapshot radio contain invalid response 1`] =
|
|||||||
value="selected radio option"
|
value="selected radio option"
|
||||||
>
|
>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="1 points"
|
description="1 points"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
key="option name"
|
key="option name"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name"
|
value="option name"
|
||||||
>
|
>
|
||||||
this label
|
this label
|
||||||
</Form.Radio>
|
</Form.Radio>
|
||||||
<Form.Radio
|
<Form.Radio
|
||||||
className="criteria-option"
|
className="criteria-option align-items-center"
|
||||||
description="2 points"
|
description="2 points"
|
||||||
disabled={false}
|
disabled={false}
|
||||||
key="option name 2"
|
key="option name 2"
|
||||||
onChange={[Function]}
|
onChange={[Function]}
|
||||||
|
style={
|
||||||
|
{
|
||||||
|
"flexShrink": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
value="option name 2"
|
value="option name 2"
|
||||||
>
|
>
|
||||||
this label 2
|
this label 2
|
||||||
|
|||||||
@@ -1,10 +1,30 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from '@edx/react-unit-test-utils';
|
import { shallow } from '@edx/react-unit-test-utils';
|
||||||
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
|
|
||||||
import { NotificationsBanner } from '.';
|
import { NotificationsBanner } from '.';
|
||||||
|
|
||||||
|
jest.mock('@edx/frontend-platform', () => ({
|
||||||
|
getConfig: jest.fn(),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('NotificationsBanner component', () => {
|
describe('NotificationsBanner component', () => {
|
||||||
test('snapshots', () => {
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('snapshots with empty ACCOUNT_SETTINGS_URL', () => {
|
||||||
|
getConfig.mockReturnValue({
|
||||||
|
ACCOUNT_SETTINGS_URL: '',
|
||||||
|
});
|
||||||
|
const el = shallow(<NotificationsBanner hide />);
|
||||||
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('snapshots with ACCOUNT_SETTINGS_URL', () => {
|
||||||
|
getConfig.mockReturnValue({
|
||||||
|
ACCOUNT_SETTINGS_URL: 'http://localhost:1997',
|
||||||
|
});
|
||||||
const el = shallow(<NotificationsBanner hide />);
|
const el = shallow(<NotificationsBanner hide />);
|
||||||
expect(el.snapshot).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`NotificationsBanner component snapshots 1`] = `
|
exports[`NotificationsBanner component snapshots with ACCOUNT_SETTINGS_URL 1`] = `
|
||||||
<PageBanner
|
<PageBanner
|
||||||
variant="accentB"
|
variant="accentB"
|
||||||
>
|
>
|
||||||
@@ -11,7 +11,7 @@ exports[`NotificationsBanner component snapshots 1`] = `
|
|||||||
id="ora-grading.NotificationsBanner.Message"
|
id="ora-grading.NotificationsBanner.Message"
|
||||||
/>
|
/>
|
||||||
<Hyperlink
|
<Hyperlink
|
||||||
destination="http://localhost:1997/notifications"
|
destination="http://localhost:1997/#notifications"
|
||||||
isInline={true}
|
isInline={true}
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
showLaunchIcon={false}
|
showLaunchIcon={false}
|
||||||
@@ -27,3 +27,22 @@ exports[`NotificationsBanner component snapshots 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</PageBanner>
|
</PageBanner>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`NotificationsBanner component snapshots with empty ACCOUNT_SETTINGS_URL 1`] = `
|
||||||
|
<PageBanner
|
||||||
|
variant="accentB"
|
||||||
|
>
|
||||||
|
<span>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="You can now enable notifications for ORA assignments that require staff grading, from the "
|
||||||
|
description="user info message that user can enable notifications for ORA assignments"
|
||||||
|
id="ora-grading.NotificationsBanner.Message"
|
||||||
|
/>
|
||||||
|
<FormattedMessage
|
||||||
|
defaultMessage="preferences center."
|
||||||
|
description="placeholder for the preferences center link"
|
||||||
|
id="ora-grading.NotificationsBanner.linkMessage"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</PageBanner>
|
||||||
|
`;
|
||||||
|
|||||||
@@ -10,16 +10,26 @@ export const NotificationsBanner = () => (
|
|||||||
<PageBanner variant="accentB">
|
<PageBanner variant="accentB">
|
||||||
<span>
|
<span>
|
||||||
<FormattedMessage {...messages.infoMessage} />
|
<FormattedMessage {...messages.infoMessage} />
|
||||||
<Hyperlink
|
{
|
||||||
isInline
|
(
|
||||||
variant="muted"
|
getConfig().ACCOUNT_SETTINGS_URL === null
|
||||||
destination={`${getConfig().ACCOUNT_SETTINGS_URL}/notifications`}
|
|| getConfig().ACCOUNT_SETTINGS_URL === undefined
|
||||||
target="_blank"
|
|| getConfig().ACCOUNT_SETTINGS_URL.trim().length === 0
|
||||||
rel="noopener noreferrer"
|
) ? (
|
||||||
showLaunchIcon={false}
|
<FormattedMessage {...messages.notificationsBannerPreferencesCenterMessage} />
|
||||||
>
|
) : (
|
||||||
<FormattedMessage {...messages.notificationsBannerLinkMessage} />
|
<Hyperlink
|
||||||
</Hyperlink>
|
isInline
|
||||||
|
variant="muted"
|
||||||
|
destination={`${getConfig().ACCOUNT_SETTINGS_URL}/#notifications`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
showLaunchIcon={false}
|
||||||
|
>
|
||||||
|
<FormattedMessage {...messages.notificationsBannerPreferencesCenterMessage} />
|
||||||
|
</Hyperlink>
|
||||||
|
)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</PageBanner>
|
</PageBanner>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const messages = defineMessages({
|
|||||||
defaultMessage: 'You can now enable notifications for ORA assignments that require staff grading, from the ',
|
defaultMessage: 'You can now enable notifications for ORA assignments that require staff grading, from the ',
|
||||||
description: 'user info message that user can enable notifications for ORA assignments',
|
description: 'user info message that user can enable notifications for ORA assignments',
|
||||||
},
|
},
|
||||||
notificationsBannerLinkMessage: {
|
notificationsBannerPreferencesCenterMessage: {
|
||||||
id: 'ora-grading.NotificationsBanner.linkMessage',
|
id: 'ora-grading.NotificationsBanner.linkMessage',
|
||||||
defaultMessage: 'preferences center.',
|
defaultMessage: 'preferences center.',
|
||||||
description: 'placeholder for the preferences center link',
|
description: 'placeholder for the preferences center link',
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import ReviewError from './ReviewError';
|
|||||||
*/
|
*/
|
||||||
export class LockErrors extends React.Component {
|
export class LockErrors extends React.Component {
|
||||||
get errorProp() {
|
get errorProp() {
|
||||||
if (this.props.errorStatus === ErrorStatuses.forbidden) {
|
if (this.props.errorStatus === ErrorStatuses.conflict) {
|
||||||
return {
|
return {
|
||||||
heading: messages.errorLockContestedHeading,
|
heading: messages.errorLockContestedHeading,
|
||||||
message: messages.errorLockContested,
|
message: messages.errorLockContested,
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ describe('LockErrors component', () => {
|
|||||||
expect(el.snapshot).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
test('snapshot: error with conflicted lock', () => {
|
test('snapshot: error with conflicted lock', () => {
|
||||||
el = shallow(<LockErrors {...props} errorStatus={ErrorStatuses.forbidden} />);
|
el = shallow(<LockErrors {...props} errorStatus={ErrorStatuses.conflict} />);
|
||||||
expect(el.snapshot).toMatchSnapshot();
|
expect(el.snapshot).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,14 +2,11 @@
|
|||||||
|
|
||||||
.review-modal-body {
|
.review-modal-body {
|
||||||
background-color: $gray-300 !important;
|
background-color: $gray-300 !important;
|
||||||
|
overflow: auto !important;
|
||||||
padding: inherit;
|
padding: inherit;
|
||||||
|
|
||||||
& > div.pgn__modal-body-content {
|
& > div.pgn__modal-body-content .row {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
.row {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-block {
|
.content-block {
|
||||||
@@ -40,4 +37,4 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,15 +19,19 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.criteria-option {
|
.criteria-option {
|
||||||
|
display: flex;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
> div {
|
> div {
|
||||||
display: inline;
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
.pgn__form-label {
|
.pgn__form-label {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
.pgn__form-control-description {
|
.pgn__form-control-description {
|
||||||
float: right;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +46,10 @@
|
|||||||
.help-popover-option {
|
.help-popover-option {
|
||||||
margin-bottom: map-get($spacers, 1);
|
margin-bottom: map-get($spacers, 1);
|
||||||
}
|
}
|
||||||
|
.popover-body {
|
||||||
|
max-height: 100vh;
|
||||||
|
overflow-y: auto !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -80,4 +88,4 @@
|
|||||||
.grading-rubric-card {
|
.grading-rubric-card {
|
||||||
margin-left: 0 !important;
|
margin-left: 0 !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig, getPath } from '@edx/frontend-platform';
|
||||||
|
|
||||||
export const routePath = () => `${getConfig().PUBLIC_PATH}:courseId`;
|
const publicPath = getPath(getConfig().PUBLIC_PATH);
|
||||||
export const locationId = () => decodeURIComponent(window.location.pathname).replace(getConfig().PUBLIC_PATH, '');
|
export const routePath = () => `${publicPath}:courseId`;
|
||||||
|
export const locationId = () => decodeURIComponent(window.location.pathname).replace(publicPath, '');
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ jest.unmock('./app');
|
|||||||
jest.mock('@edx/frontend-platform', () => {
|
jest.mock('@edx/frontend-platform', () => {
|
||||||
const PUBLIC_PATH = '/test-public-path/';
|
const PUBLIC_PATH = '/test-public-path/';
|
||||||
return {
|
return {
|
||||||
|
...jest.requireActual('@edx/frontend-platform'),
|
||||||
getConfig: () => ({ PUBLIC_PATH }),
|
getConfig: () => ({ PUBLIC_PATH }),
|
||||||
PUBLIC_PATH,
|
PUBLIC_PATH,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -182,11 +182,11 @@ const grading = createSlice({
|
|||||||
|
|
||||||
const gradeData = {
|
const gradeData = {
|
||||||
...state.gradeData,
|
...state.gradeData,
|
||||||
...(payload && { [submissionUUID]: payload.submissionStatus.gradeData }),
|
...(payload && { [submissionUUID]: payload.gradeData }),
|
||||||
};
|
};
|
||||||
|
|
||||||
const { gradeStatus } = payload ? payload.submissionStatus : state.current;
|
const { gradeStatus } = payload || state.current;
|
||||||
const lockStatus = payload ? payload.submissionStatus.lockStatus : lockStatuses.unlocked;
|
const lockStatus = payload ? payload.lockStatus : lockStatuses.unlocked;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -250,7 +250,7 @@ describe('app reducer', () => {
|
|||||||
});
|
});
|
||||||
describe('stopGrading', () => {
|
describe('stopGrading', () => {
|
||||||
let output;
|
let output;
|
||||||
const args = { submissionStatus: { gradeData: testData, lockStatus, gradeStatus } };
|
const args = { gradeData: testData, lockStatus, gradeStatus };
|
||||||
describe('resulting state', () => {
|
describe('resulting state', () => {
|
||||||
test('gradingData: deletes current data', () => {
|
test('gradingData: deletes current data', () => {
|
||||||
output = reducer(testState, actions.stopGrading());
|
output = reducer(testState, actions.stopGrading());
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import _ from 'lodash';
|
import sortBy from 'lodash/sortBy';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
|
||||||
import { StrictDict } from 'utils';
|
import { StrictDict } from 'utils';
|
||||||
@@ -22,7 +22,7 @@ export const listData = createSelector(
|
|||||||
const gradingStatus = (lockStatus === lockStatuses.unlocked ? gradeStatus : lockStatus);
|
const gradingStatus = (lockStatus === lockStatuses.unlocked ? gradeStatus : lockStatus);
|
||||||
return { gradingStatus, ...rest };
|
return { gradingStatus, ...rest };
|
||||||
});
|
});
|
||||||
return _.sortBy(
|
return sortBy(
|
||||||
submissionList,
|
submissionList,
|
||||||
['submissionDate'],
|
['submissionDate'],
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { RequestKeys } from 'data/constants/requests';
|
|||||||
import api from 'data/services/lms/api';
|
import api from 'data/services/lms/api';
|
||||||
import * as download from './download';
|
import * as download from './download';
|
||||||
|
|
||||||
const mockBlobWriter = jest.fn().mockName('BlobWriter');
|
const mockBlobWriter = jest.fn();
|
||||||
const mockTextReader = jest.fn().mockName('TextReader');
|
const mockTextReader = jest.fn();
|
||||||
const mockBlobReader = jest.fn().mockName('BlobReader');
|
const mockBlobReader = jest.fn();
|
||||||
|
|
||||||
const mockZipAdd = jest.fn();
|
const mockZipAdd = jest.fn();
|
||||||
const mockZipClose = jest.fn();
|
const mockZipClose = jest.fn();
|
||||||
@@ -21,9 +21,9 @@ jest.mock('@zip.js/zip.js', () => {
|
|||||||
close: mockZipClose.mockImplementation(() => Promise.resolve(files)),
|
close: mockZipClose.mockImplementation(() => Promise.resolve(files)),
|
||||||
files,
|
files,
|
||||||
})),
|
})),
|
||||||
BlobWriter: () => mockBlobWriter,
|
BlobWriter: function _() { return mockBlobWriter; },
|
||||||
TextReader: () => mockTextReader,
|
TextReader: function _() { return mockTextReader; },
|
||||||
BlobReader: () => mockBlobReader,
|
BlobReader: function _() { return mockBlobReader; },
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import * as redux from 'redux';
|
import * as redux from 'redux';
|
||||||
import thunkMiddleware from 'redux-thunk';
|
import thunkMiddleware from 'redux-thunk';
|
||||||
import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction';
|
import { composeWithDevTools } from '@redux-devtools/extension';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
|
|
||||||
import apiTestUtils from 'data/services/lms/fakeData/testUtils';
|
import apiTestUtils from 'data/services/lms/fakeData/testUtils';
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { applyMiddleware } from 'redux';
|
import { applyMiddleware } from 'redux';
|
||||||
import thunkMiddleware from 'redux-thunk';
|
import thunkMiddleware from 'redux-thunk';
|
||||||
import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction';
|
import { composeWithDevTools } from '@redux-devtools/extension';
|
||||||
import { createLogger } from 'redux-logger';
|
import { createLogger } from 'redux-logger';
|
||||||
|
|
||||||
import rootReducer, { actions, selectors } from 'data/redux';
|
import rootReducer, { actions, selectors } from 'data/redux';
|
||||||
@@ -22,7 +22,7 @@ jest.mock('redux', () => ({
|
|||||||
applyMiddleware: (...middleware) => ({ applied: middleware }),
|
applyMiddleware: (...middleware) => ({ applied: middleware }),
|
||||||
createStore: (reducer, middleware) => ({ reducer, middleware }),
|
createStore: (reducer, middleware) => ({ reducer, middleware }),
|
||||||
}));
|
}));
|
||||||
jest.mock('redux-devtools-extension/logOnlyInProduction', () => ({
|
jest.mock('@redux-devtools/extension', () => ({
|
||||||
composeWithDevTools: (middleware) => ({ withDevTools: middleware }),
|
composeWithDevTools: (middleware) => ({ withDevTools: middleware }),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
import 'core-js/stable';
|
import 'core-js/stable';
|
||||||
import 'regenerator-runtime/runtime';
|
import 'regenerator-runtime/runtime';
|
||||||
|
|
||||||
import React from 'react';
|
import React, { StrictMode } from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import { createRoot } from 'react-dom/client';
|
||||||
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
|
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
|
||||||
|
|
||||||
import store from 'data/store';
|
import store from 'data/store';
|
||||||
@@ -20,18 +20,24 @@ import messages from './i18n';
|
|||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
subscribe(APP_READY, () => {
|
subscribe(APP_READY, () => {
|
||||||
ReactDOM.render(
|
const root = createRoot(document.getElementById('root'));
|
||||||
<AppProvider store={store} wrapWithRouter={false}>
|
|
||||||
<App />
|
root.render(
|
||||||
</AppProvider>,
|
<StrictMode>
|
||||||
document.getElementById('root'),
|
<AppProvider store={store} wrapWithRouter={false}>
|
||||||
|
<App />
|
||||||
|
</AppProvider>
|
||||||
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
subscribe(APP_INIT_ERROR, (error) => {
|
subscribe(APP_INIT_ERROR, (error) => {
|
||||||
ReactDOM.render(
|
const root = createRoot(document.getElementById('root'));
|
||||||
<ErrorPage message={error.message} />,
|
|
||||||
document.getElementById('root'),
|
root.render(
|
||||||
|
<StrictMode>
|
||||||
|
<ErrorPage message={error.message} />
|
||||||
|
</StrictMode>,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import { render } from 'react-dom';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
APP_INIT_ERROR,
|
APP_INIT_ERROR,
|
||||||
APP_READY,
|
APP_READY,
|
||||||
@@ -11,8 +9,24 @@ import {
|
|||||||
import messages from './i18n';
|
import messages from './i18n';
|
||||||
import * as app from '.';
|
import * as app from '.';
|
||||||
|
|
||||||
jest.mock('react-dom', () => ({
|
// These need to be var not let so they get hoisted
|
||||||
render: jest.fn(),
|
// and can be used by jest.mock (which is also hoisted)
|
||||||
|
var mockRender; // eslint-disable-line no-var
|
||||||
|
var mockCreateRoot; // eslint-disable-line no-var
|
||||||
|
jest.mock('react-dom/client', () => {
|
||||||
|
mockRender = jest.fn();
|
||||||
|
mockCreateRoot = jest.fn(() => ({
|
||||||
|
render: mockRender,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return ({
|
||||||
|
createRoot: mockCreateRoot,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.mock('react', () => ({
|
||||||
|
...jest.requireActual('react'),
|
||||||
|
StrictMode: 'React Strict Mode',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('@edx/frontend-component-footer', () => ({
|
jest.mock('@edx/frontend-component-footer', () => ({
|
||||||
@@ -39,7 +53,7 @@ describe('app registry', () => {
|
|||||||
let getElement;
|
let getElement;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
render.mockClear();
|
mockRender.mockClear();
|
||||||
getElement = window.document.getElementById;
|
getElement = window.document.getElementById;
|
||||||
window.document.getElementById = jest.fn(id => ({ id }));
|
window.document.getElementById = jest.fn(id => ({ id }));
|
||||||
});
|
});
|
||||||
@@ -51,18 +65,16 @@ describe('app registry', () => {
|
|||||||
const callArgs = subscribe.mock.calls[0];
|
const callArgs = subscribe.mock.calls[0];
|
||||||
expect(callArgs[0]).toEqual(APP_READY);
|
expect(callArgs[0]).toEqual(APP_READY);
|
||||||
callArgs[1]();
|
callArgs[1]();
|
||||||
const [rendered, target] = render.mock.calls[0];
|
const [rendered] = mockRender.mock.calls[0];
|
||||||
expect(rendered).toMatchSnapshot();
|
expect(rendered).toMatchSnapshot();
|
||||||
expect(target).toEqual(document.getElementById('root'));
|
|
||||||
});
|
});
|
||||||
test('subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element', () => {
|
test('subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element', () => {
|
||||||
const callArgs = subscribe.mock.calls[1];
|
const callArgs = subscribe.mock.calls[1];
|
||||||
expect(callArgs[0]).toEqual(APP_INIT_ERROR);
|
expect(callArgs[0]).toEqual(APP_INIT_ERROR);
|
||||||
const error = { message: 'test-error-message' };
|
const error = { message: 'test-error-message' };
|
||||||
callArgs[1](error);
|
callArgs[1](error);
|
||||||
const [rendered, target] = render.mock.calls[0];
|
const [rendered] = mockRender.mock.calls[0];
|
||||||
expect(rendered).toMatchSnapshot();
|
expect(rendered).toMatchSnapshot();
|
||||||
expect(target).toEqual(document.getElementById('root'));
|
|
||||||
});
|
});
|
||||||
test('initialize is called with footerMessages and requireAuthenticatedUser', () => {
|
test('initialize is called with footerMessages and requireAuthenticatedUser', () => {
|
||||||
expect(initialize).toHaveBeenCalledTimes(1);
|
expect(initialize).toHaveBeenCalledTimes(1);
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
# Footer Slot
|
# Footer Slot
|
||||||
|
|
||||||
### Slot ID: `footer_slot`
|
### Slot ID: `org.openedx.frontend.layout.footer.v1`
|
||||||
|
|
||||||
|
### Slot ID Aliases
|
||||||
|
* `footer_slot`
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
This slot is used to replace/modify/hide the footer.
|
This slot is used to replace/modify/hide the footer.
|
||||||
|
|
||||||
The implementation of the `FooterSlot` component lives in [the `frontend-slot-footer` repository](https://github.com/openedx/frontend-slot-footer/).
|
The implementation of the `FooterSlot` component lives in [the `frontend-component-footer` repository](https://github.com/openedx/frontend-component-footer/).
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-frame
|
|||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
pluginSlots: {
|
pluginSlots: {
|
||||||
footer_slot: {
|
'org.openedx.frontend.layout.footer.v1': {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
// Hide the default footer
|
// Hide the default footer
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
# `frontend-app-ora-grading` Plugin Slots
|
# `frontend-app-ora-grading` Plugin Slots
|
||||||
|
|
||||||
* [`footer_slot`](./FooterSlot/)
|
* [`org.openedx.frontend.layout.footer.v1`](./FooterSlot/)
|
||||||
|
|||||||
Reference in New Issue
Block a user