Compare commits

...

57 Commits

Author SHA1 Message Date
Brian Smith
4825c3d68c feat: import FooterSlot from component package instead of slot package (#414) 2025-04-24 12:33:01 -04:00
renovate[bot]
4e27a35e10 fix(deps): update dependency @edx/frontend-component-header to v6.4.0 (#415)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-04-23 20:17:57 +00:00
Stanislav Lunyachek
ad0e2af8c8 feat: ORA visual improvements 2025-04-16 16:10:15 +03:30
Brian Smith
d03e7c40d8 feat: upgrade to react 18 (#406) 2025-04-09 15:22:36 -04:00
Régis Behmo
5a7063c123 chore: remove husky 🪓🐶 (#405) 2025-04-09 13:56:30 +00:00
Régis Behmo
9348c4bb4c feat: lighter build by avoiding full lodash import
Incorrect lodash imports are causing MFEs to import the entire lodash
library.
2025-04-03 12:42:31 +03:30
Brian Smith
5c5ff1190b chore(deps): update @openedx dependencies to versions that support React 18 (#399) 2025-03-27 16:17:00 -04:00
Jansen Kantor
7aee8562a8 Merge pull request #390 from openedx/jkantor/conflictError
fix: error code expecting wrong data shape
2025-03-05 14:49:36 -05:00
Jansen Kantor
ebca59a38f Merge branch 'master' into jkantor/conflictError 2025-03-05 14:42:07 -05:00
salman2013
f87d521bc0 chore: update catalog-info file for release data 2025-02-20 19:07:39 +03:30
Stanislav Lunyachek
5280cef554 feat: Add header styles inclusion 2025-02-20 18:19:39 +03:30
Stanislav Lunyachek
08430571ed fix: Fix for the Paragon modal shadow, which prevents clicking on an element on the grading page 2025-02-19 18:45:39 +03:30
Jansen Kantor
3de6821c5d Merge branch 'master' into jkantor/conflictError 2025-01-14 10:45:33 -05:00
Paulo Viadanna
fb06133a27 fix: enable scroll in grading modal 2025-01-14 19:00:42 +03:30
Jansen Kantor
12f1c72b7e Merge branch 'master' into jkantor/conflictError 2025-01-10 14:11:49 -05:00
Jansen Kantor
ca8d08c8a0 fixup! fix: error code expecting wrong data shape 2025-01-10 14:08:32 -05:00
Jansen Kantor
30a4ca17ac fix: error code expecting wrong data shape 2025-01-10 14:07:01 -05:00
Awais Ansari
25d76c0e59 fix: updated notifications preferences url (#389)
* fix: updated notifiations preferences url

* fix: updated test cases
2025-01-10 17:09:14 +05:00
Emad Rad
6527f505f1 chore: npm publish action removed (#366)
We don't push MFEs to the npm registry.
Achieves part of https://github.com/openedx/public-engineering/issues/284
2024-12-18 13:48:18 -05:00
milad-emami
400950cff8 feat: update react-pdf to v7 and fix worker configuration 2024-12-18 13:25:38 +03:30
Adolfo R. Brandes
0219f5cd25 chore: remove extraneous file
Remove a file that was previously added by mistake.
2024-12-06 10:54:46 -03:00
Adolfo R. Brandes
fdcab456e8 fix: broken download tests
Declaring `browserslist` in package.json exposed a bug in the
download.js tests that wasn't causing failures before (but arguably,
should): one can't use arrow functions to mock constructors because
calling `new` on them doesn't work.  See the NOTE under:

https://jestjs.io/docs/es6-class-mocks#-module-factory-function-must-return-a-function
2024-12-06 10:54:46 -03:00
Adolfo R. Brandes
5283e7c7c6 fix: Use browserslist-config
We were installing browserslist-config but not declaring it.  This had
the effect that webpack - and likely others - were not using it.
2024-12-06 10:54:46 -03:00
Dima Alipov
e39533c56a fix: incorrect message for locking 2024-11-30 15:22:18 +03:30
milad-emami
212014fed9 chore: update redux-devtools-extension to @redux-devtools/extension@3.0.0 2024-11-25 12:14:34 +03:30
milad-emami
9600301a62 chore(deps): update dependency redux-mock-store to 1.5.5
Updates redux-mock-store to version 1.5.5 in both package.json and package-lock.json to ensure dependency consistency
2024-11-25 12:08:07 +03:30
Feanil Patel
1d5f64e1db docs: Update catalog-info.yaml
Correct the owner.
2024-11-20 13:14:08 -05:00
milad-emami
f5208c58aa fix: remove fixed height from review modal body
Remove height:100% property from modal body content to prevent content from sticking to bottom of page and allow proper spacing
2024-11-20 17:38:01 +03:30
milad-emami
c15680cb8c fix: prevent radio criterion shrinking and improve alignment
- Add flexShrink: 0 style to prevent radio button compression
- Add align-items-center class for better vertical alignment
2024-11-20 17:36:46 +03:30
Diana Catalina Olarte
76f41439e9 fix: apply getPath to PUBLIC_PATH to allow use with CDN 2024-11-19 16:19:19 +03:30
Feanil Patel
4581cf8698 Merge pull request #371 from CodeWithEmad/chore/catalog-info
chore: owner changed
2024-11-12 09:01:55 -05:00
Emad Rad
95fa32eaaa chore: owner changed 2024-11-09 11:25:09 +03:30
Asad Ali
1f729becbe feat: remove CTA (#347) 2024-11-05 12:00:31 -05:00
Arslan Ashraf
7ad1df8bd0 test: Remove support for Node 18 (#365)
Co-authored-by: Muhammad Anas <muhammad.anas@arbisoft.com>
2024-11-04 13:46:17 -05:00
Asad Ali
c9d0abe968 fix: convert notification banner to text if accounts url is not set (#362)
* fix: convert banner to text if ACCOUNT_SETTINGS_URL is not set

* refactor: refactoring

* refactor: rename notificationsBannerLinkMessage to notificationsBannerPreferencesCenterMessage

* refactor: remove lodash usage

* refactor: remove lodash usage
2024-11-04 12:22:50 -05:00
Brian Smith
91e33748ab feat(deps): update header to 5.6.0 (#363) 2024-10-22 19:19:55 -04:00
Feanil Patel
8809f4cf16 Merge pull request #353 from openedx/feanil/ubuntu_upgrade
build: Switch to ubuntu-latest for builds
2024-09-20 10:28:36 -04:00
Feanil Patel
7482765aa4 build: Switch to ubuntu-latest for builds
This code does not have any dependencies that are specific to any specific
version of ubuntu.  So instead of testing on a specific version and then needing
to do work to keep the versions up-to-date, we switch to the ubuntu-latest
target which should be sufficient for testing purposes.

This work is being done as a part of https://github.com/openedx/platform-roadmap/issues/377

closes https://github.com/openedx/frontend-app-ora-grading/issues/345
2024-09-20 10:28:31 -04:00
Kristin Aoki
7003b6102d Merge pull request #354 from openedx/jkantor/headingMessage
fix: incorrect key breaks page
2024-09-13 09:19:34 -04:00
Jansen Kantor
d608daccb1 Merge branch 'master' into jkantor/headingMessage 2024-09-12 16:03:50 -04:00
Jansen Kantor
2208737a69 fix: incorrect key crashes page 2024-09-12 16:01:02 -04:00
Muhammad Anas
567a020061 build: Upgrade to Node 20 (#349)
* build: Upgrade to Node 20

* refactor: updated package-lock

* refactor: updated the lockfile version workflow
2024-09-06 12:23:49 -04:00
Muhammad Anas
c5d9bfb2f6 test: Add Node 20 to CI matrix (#348)
* test: Add Node 20 to CI matrix

* fix: pinning node 18 verson
2024-09-03 14:30:54 -04:00
Feanil Patel
f433d33f9d Merge pull request #328 from openedx/bilalqamar95/jest-v29-upgrade
feat: updated frontend-build & frontend-platform major versions
2024-08-07 10:01:12 -04:00
Bilal Qamar
c0816e0818 Merge branch 'master' into bilalqamar95/jest-v29-upgrade 2024-07-30 14:12:20 +05:00
Feanil Patel
c83e86bf06 Merge pull request #343 from openedx/feanil/update_maintainer
docs: Make it clear that this is unmaintained.
2024-07-24 10:52:01 -04:00
Feanil Patel
b6f1a9739e docs: Make it clear that this is unmaintained. 2024-07-19 16:06:30 -04:00
Bilal Qamar
f2b6cd4cac Merge branch 'master' into bilalqamar95/jest-v29-upgrade 2024-07-04 16:02:16 +05:00
Adolfo R. Brandes
3092bd3980 build: Update codecov and use token (#342)
Update codecov to the latest version and start using the org-wide token for uploads.

See https://github.com/openedx/wg-frontend/issues/179
2024-06-17 12:14:02 -03:00
Bilal Qamar
20dc736278 refactor: installed jest-environment-jsdom package, updated package-lock 2024-06-03 16:08:02 +05:00
Bilal Qamar
d72beeb2d4 Merge branch 'master' of github.com:openedx/frontend-app-ora-grading into bilalqamar95/jest-v29-upgrade 2024-06-03 16:06:23 +05:00
Brian Smith
64b57df976 feat: use frontend-plugin-framework to provide a FooterSlot 2024-05-23 11:28:25 -03:00
Bilal Qamar
346b371ba2 Merge branch 'master' of github.com:openedx/frontend-app-ora-grading into bilalqamar95/jest-v29-upgrade 2024-05-16 16:04:53 +05:00
Bilal Qamar
650d708a1c refactor: major version upgrade for react-unit-test-utils 2024-05-16 16:04:13 +05:00
Bilal Qamar
b23effdb7f feat: updated frontend-build & frontend-platform major versions 2024-04-24 13:54:40 +05:00
Bilal Qamar
5bcb6fe6f3 refactor: updated snapshots for failing tests 2024-04-15 15:44:02 +05:00
Bilal Qamar
a67f201f4d feat: updated frontend-build major version, bumps jest to v29 2024-04-15 15:43:48 +05:00
69 changed files with 8388 additions and 14487 deletions

View File

@@ -7,7 +7,6 @@ LOGOUT_URL='http://localhost:18000/logout'
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
LOGO_POWERED_BY_OPEN_EDX_URL_SVG=https://edx-cdn.org/v3/stage/open-edx-tag.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'

View File

@@ -7,7 +7,6 @@ LOGOUT_URL='http://localhost:18000/logout'
LOGO_URL=https://edx-cdn.org/v3/default/logo.svg
LOGO_TRADEMARK_URL=https://edx-cdn.org/v3/default/logo-trademark.svg
LOGO_WHITE_URL=https://edx-cdn.org/v3/default/logo-white.svg
LOGO_POWERED_BY_OPEN_EDX_URL_SVG=https://edx-cdn.org/v3/stage/open-edx-tag.svg
FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
REFRESH_ACCESS_TOKEN_ENDPOINT='http://localhost:18000/login_refresh'

View File

@@ -10,17 +10,18 @@ on:
jobs:
tests:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- name: Setup Nodejs
uses: actions/setup-node@v3
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
with:
node-version: 18.15
node-version-file: '.nvmrc'
- name: Install dependencies
run: npm ci
@@ -38,7 +39,10 @@ jobs:
run: npm run build
- name: Run Coverage
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: true
- name: Send failure notification
if: ${{ failure() }}

View File

@@ -10,4 +10,4 @@ on:
jobs:
version-check:
uses: openedx/.github/.github/workflows/lockfile-check.yml@master
uses: openedx/.github/.github/workflows/lockfileversion-check-v3.yml@master

View File

@@ -1,32 +0,0 @@
name: Release CI
on:
push:
tags:
- "*"
jobs:
release:
name: Release
runs-on: ubuntu-20.04
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

View File

@@ -1,4 +0,0 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npm run lint

2
.nvmrc
View File

@@ -1 +1 @@
18.19
20

View File

@@ -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": []
}

View File

@@ -39,6 +39,12 @@ to the `relevant tutor-mfe documentation`_ to get started using it.
.. _relevant tutor-mfe documentation: https://github.com/overhangio/tutor-mfe#mfe-development
Plugins
=======
This MFE can be customized using `Frontend Plugin Framework <https://github.com/openedx/frontend-plugin-framework>`_.
The parts of this MFE that can be customized in that manner are documented `here </src/plugin-slots>`_.
Developing
==========

View File

@@ -13,7 +13,9 @@ metadata:
- url: "https://ora-grading.stage.edx.org"
title: "Stage Site"
icon: "Web"
annotations:
openedx.org/release: "master"
spec:
owner: ~
owner: "user:codewithemad"
type: 'website'
lifecycle: 'production'

View File

@@ -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}

22018
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,9 @@
"type": "git",
"url": "git+https://github.com/edx/frontend-app-ora-grading.git"
},
"browserslist": [
"extends @edx/browserslist-config"
],
"scripts": {
"build": "fedx-scripts webpack",
"i18n_extract": "fedx-scripts formatjs extract",
@@ -13,9 +16,9 @@
"lint-fix": "fedx-scripts eslint --fix --ext .jsx,.js src/",
"semantic-release": "semantic-release",
"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",
"watch-tests": "jest --watch",
"prepare": "husky install"
"watch-tests": "jest --watch"
},
"author": "edX",
"license": "AGPL-3.0",
@@ -25,16 +28,17 @@
},
"dependencies": {
"@edx/brand": "npm:@openedx/brand-openedx@^1.2.2",
"@edx/frontend-component-footer": "13.0.2",
"@edx/frontend-component-header": "5.0.2",
"@edx/frontend-platform": "7.1.0",
"@edx/frontend-component-footer": "^14.6.0",
"@edx/frontend-component-header": "^6.2.0",
"@edx/frontend-platform": "^8.3.1",
"@edx/openedx-atlas": "^0.6.0",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.2.0",
"@openedx/paragon": "21.11.3",
"@openedx/paragon": "^22.16.0",
"@redux-beacon/segment": "^1.1.0",
"@redux-devtools/extension": "3.0.0",
"@reduxjs/toolkit": "^1.6.1",
"@testing-library/user-event": "^14.0.0",
"@zip.js/zip.js": "^2.4.6",
@@ -52,18 +56,17 @@
"moment": "^2.29.3",
"prop-types": "15.8.1",
"query-string": "7.1.3",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-helmet": "^6.1.0",
"react-intl": "6.4.7",
"react-pdf": "^5.5.0",
"react-pdf": "^7.0.0",
"react-redux": "^7.2.9",
"react-router": "6.21.3",
"react-router-dom": "6.21.3",
"react-router-redux": "^5.0.0-alpha.9",
"redux": "4.2.1",
"redux-beacon": "^2.1.0",
"redux-devtools-extension": "2.13.9",
"redux-logger": "3.0.6",
"redux-thunk": "2.4.2",
"regenerator-runtime": "^0.14.0",
@@ -72,22 +75,21 @@
"whatwg-fetch": "^3.6.2"
},
"devDependencies": {
"@edx/browserslist-config": "^1.2.0",
"@edx/react-unit-test-utils": "2.0.0",
"@edx/browserslist-config": "^1.3.0",
"@edx/react-unit-test-utils": "^4.0.0",
"@edx/reactifex": "^2.1.1",
"@openedx/frontend-build": "13.0.28",
"@testing-library/jest-dom": "^6.0.0",
"@testing-library/react": "12.1.5",
"@openedx/frontend-build": "^14.3.3",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.2.0",
"axios-mock-adapter": "^1.20.0",
"fetch-mock": "^9.11.0",
"husky": "^7.0.0",
"identity-obj-proxy": "^3.0.0",
"jest": "29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-expect-message": "^1.0.2",
"react-dev-utils": "^12.0.1",
"react-test-renderer": "^17.0.2",
"react-test-renderer": "^18.3.1",
"reactifex": "1.1.1",
"redux-mock-store": "^1.5.4",
"semantic-release": "^19.0.3"
"redux-mock-store": "^1.5.5"
}
}

View File

@@ -3,13 +3,12 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import Footer from '@edx/frontend-component-footer';
import { FooterSlot } from '@edx/frontend-component-footer';
import { LearningHeader as Header } from '@edx/frontend-component-header';
import { selectors } from 'data/redux';
import DemoWarning from 'containers/DemoWarning';
import CTA from 'containers/CTA';
import NotificationsBanner from 'containers/NotificationsBanner';
import ListView from 'containers/ListView';
@@ -27,12 +26,11 @@ export const App = ({ courseMetadata, isEnabled }) => (
data-testid="header"
/>
{!isEnabled && <DemoWarning />}
<CTA />
<NotificationsBanner />
<main data-testid="main">
<ListView />
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} data-testid="footer" />
<FooterSlot />
</div>
</Router>
);

View File

@@ -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
@import "~@edx/frontend-component-footer/dist/_footer";
@import "~@edx/frontend-component-header/dist/index";
#root {
display: flex;

View File

@@ -15,14 +15,12 @@ jest.mock('data/redux', () => ({
jest.mock('@edx/frontend-component-header', () => ({
LearningHeader: 'Header',
}));
jest.mock('@edx/frontend-component-footer', () => 'Footer');
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'FooterSlot' }));
jest.mock('containers/DemoWarning', () => 'DemoWarning');
jest.mock('containers/CTA', () => 'CTA');
jest.mock('containers/ListView', () => 'ListView');
jest.mock('components/Head', () => 'Head');
const logo = 'fakeLogo.png';
let el;
describe('App router component', () => {
@@ -42,7 +40,6 @@ describe('App router component', () => {
});
describe('component', () => {
beforeEach(() => {
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
el = shallow(<App {...props} />);
});
describe('Router', () => {
@@ -51,9 +48,6 @@ describe('App router component', () => {
expect(el.instance.findByTestId('main')[0].children[0].type).toBe('ListView');
});
});
test('Footer logo drawn from env variable', () => {
expect(el.instance.findByTestId('footer')[0].props.logo).toEqual(logo);
});
test('Header to use courseMetadata props', () => {
const {

View File

@@ -11,17 +11,13 @@ exports[`App router component snapshot: disabled (show demo warning) 1`] = `
data-testid="header"
/>
<DemoWarning />
<CTA />
<NotificationsBanner />
<main
data-testid="main"
>
<ListView />
</main>
<Footer
data-testid="footer"
logo="https://edx-cdn.org/v3/stage/open-edx-tag.svg"
/>
<FooterSlot />
</div>
</BrowserRouter>
`;
@@ -36,17 +32,13 @@ exports[`App router component snapshot: enabled 1`] = `
courseTitle="course-title"
data-testid="header"
/>
<CTA />
<NotificationsBanner />
<main
data-testid="main"
>
<ListView />
</main>
<Footer
data-testid="footer"
logo="https://edx-cdn.org/v3/stage/open-edx-tag.svg"
/>
<FooterSlot />
</div>
</BrowserRouter>
`;

View File

@@ -1,24 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`app registry subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element 1`] = `
<ErrorPage
message="test-error-message"
/>
<React Strict Mode>
<ErrorPage
message="test-error-message"
/>
</React Strict Mode>
`;
exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
<AppProvider
store={
Object {
"dispatch": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
Symbol(Symbol.observable): [Function],
<React Strict Mode>
<AppProvider
store={
{
"dispatch": [Function],
"getState": [Function],
"replaceReducer": [Function],
"subscribe": [Function],
Symbol(Symbol.observable): [Function],
}
}
}
wrapWithRouter={false}
>
<App />
</AppProvider>
wrapWithRouter={false}
>
<App />
</AppProvider>
</React Strict Mode>
`;

View File

@@ -3,7 +3,7 @@
exports[`Error Banner component snapshot 1`] = `
<Alert
actions={
Array [
[
<Button
onClick={[MockFunction action1.onClick]}
variant="outline-primary"

View File

@@ -1,17 +1,15 @@
import React from 'react';
import PropTypes from 'prop-types';
import { pdfjs, Document, Page } from 'react-pdf';
import { Document, Page, pdfjs } from 'react-pdf';
import {
Icon, Form, ActionRow, IconButton,
} from '@openedx/paragon';
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 { rendererHooks } from './pdfHooks';
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.js`;
/**
* <PDFRenderer />

View File

@@ -12,7 +12,7 @@ exports[`PDF Renderer Component snapshots first page, prev is disabled 1`] = `
<div
className="page-wrapper"
style={
Object {
{
"height": 200,
}
}
@@ -80,7 +80,7 @@ exports[`PDF Renderer Component snapshots on last page, next is disabled 1`] = `
<div
className="page-wrapper"
style={
Object {
{
"height": 200,
}
}

View File

@@ -1,16 +1,11 @@
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 { ErrorStatuses } from 'data/constants/requests';
import { StrictDict } from 'utils';
import * as module from './pdfHooks';
pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker;
export const errors = StrictDict({
missingPDF: 'MissingPDFException',
});

View File

@@ -3,7 +3,7 @@
exports[`FileRenderer component snapshot is not loading, with error 1`] = `
<FileCard
file={
Object {
{
"downloadUrl": "file download url",
"name": "filename.txt",
}
@@ -19,7 +19,7 @@ exports[`FileRenderer component snapshot is not loading, with error 1`] = `
exports[`FileRenderer component snapshot isLoading, no Error 1`] = `
<FileCard
file={
Object {
{
"downloadUrl": "file download url",
"name": "filename.txt",
}

View File

@@ -79,7 +79,7 @@ export const renderHooks = ({
message: messages.retryButton,
};
const error = {
headerMessage: errorMessage,
headingMessage: errorMessage,
children: intl.formatMessage(errorMessage),
actions: [errorAction],
};

View File

@@ -55,7 +55,7 @@ describe('FilePreview hooks', () => {
});
describe('error', () => {
it('loads message from current error status, if valid, else from serverError', () => {
expect(hook.error.headerMessage).toEqual(
expect(hook.error.headingMessage).toEqual(
hooks.ERROR_STATUSES[ErrorStatuses.serverError],
);
expect(hook.error.children).toEqual(
@@ -63,7 +63,7 @@ describe('FilePreview hooks', () => {
);
state.mockVal(state.keys.errorStatus, ErrorStatuses.notFound);
hook = hooks.renderHooks({ intl: { formatMessage }, file });
expect(hook.error.headerMessage).toEqual(
expect(hook.error.headingMessage).toEqual(
hooks.ERROR_STATUSES[ErrorStatuses.notFound],
);
expect(hook.error.children).toEqual(

View File

@@ -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();
});
});

View File

@@ -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>
`;

View File

@@ -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;

View File

@@ -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);

View File

@@ -36,12 +36,13 @@ export class RadioCriterion extends React.Component {
<Form.RadioSet name={config.name} value={data}>
{config.options.map((option) => (
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
key={option.name}
value={option.name}
description={intl.formatMessage(messages.optionPoints, { points: option.points })}
onChange={this.onChange}
disabled={!isGrading}
style={{ flexShrink: 0 }}
>
{option.label}
</Form.Radio>

View File

@@ -6,21 +6,31 @@ exports[`Radio Criterion Container snapshot is grading 1`] = `
value="selected radio option"
>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="1 points"
disabled={false}
key="option name"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name"
>
this label
</Form.Radio>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="2 points"
disabled={false}
key="option name 2"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name 2"
>
this label 2
@@ -34,21 +44,31 @@ exports[`Radio Criterion Container snapshot is not grading 1`] = `
value="selected radio option"
>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="1 points"
disabled={true}
key="option name"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name"
>
this label
</Form.Radio>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="2 points"
disabled={true}
key="option name 2"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name 2"
>
this label 2
@@ -62,21 +82,31 @@ exports[`Radio Criterion Container snapshot radio contain invalid response 1`] =
value="selected radio option"
>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="1 points"
disabled={false}
key="option name"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name"
>
this label
</Form.Radio>
<Form.Radio
className="criteria-option"
className="criteria-option align-items-center"
description="2 points"
disabled={false}
key="option name 2"
onChange={[Function]}
style={
{
"flexShrink": 0,
}
}
value="option name 2"
>
this label 2

View File

@@ -25,7 +25,7 @@ exports[`Review Crition Container snapshot 1`] = `
description="criterion option point value display"
id="ora-grading.RadioCriterion.optionPoints"
values={
Object {
{
"points": 1,
}
}
@@ -54,7 +54,7 @@ exports[`Review Crition Container snapshot 1`] = `
description="criterion option point value display"
id="ora-grading.RadioCriterion.optionPoints"
values={
Object {
{
"points": 2,
}
}

View File

@@ -3,7 +3,7 @@
exports[`ListError component component render tests snapshot 1`] = `
<Alert
actions={
Array [
[
<Button
onClick={[MockFunction]}
>
@@ -30,7 +30,7 @@ exports[`ListError component component render tests snapshot 1`] = `
description="Initialization failure alert message line 2"
id="ora-grading.ListView.loadErrorMessage1"
values={
Object {
{
"backToResponses": <Hyperlink
destination="api/openResponse/test-course-id"
>

View File

@@ -11,7 +11,7 @@ exports[`SelectedBulkAction component snapshots 1`] = `
description="Button text to load selected responses for review/grading"
id="ora-grading.ListView.viewSelectedResponses"
values={
Object {
{
"value": 2,
}
}

View File

@@ -9,50 +9,50 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: h
<DataTable
FilterStatusComponent={[MockFunction FilterStatusComponent]}
bulkActions={
Array [
[
<mockConstructor
handleClick={[Function]}
/>,
]
}
columns={
Array [
Object {
[
{
"Header": "Username",
"accessor": "username",
},
Object {
{
"Cell": [Function],
"Header": "Learner submission date",
"accessor": "dateSubmitted",
"disableFilters": true,
},
Object {
{
"Cell": [Function],
"Header": "Grade",
"accessor": "score",
"disableFilters": true,
},
Object {
{
"Cell": [Function],
"Filter": "MultiSelectDropdownFilter",
"Header": "Grading status",
"accessor": "gradingStatus",
"filter": "includesValue",
"filterChoices": Array [
Object {
"filterChoices": [
{
"name": "Ungraded",
"value": "ungraded",
},
Object {
{
"name": "Grading Completed",
"value": "graded",
},
Object {
{
"name": "Currently being graded by someone else",
"value": "locked",
},
Object {
{
"name": "You are currently grading this response",
"value": "in-progress",
},
@@ -61,29 +61,29 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: h
]
}
data={
Array [
Object {
[
{
"dateSubmitted": "2021-12-08 09:06:15.319213+00:00",
"gradingStatus": "ungraded",
"score": Object {
"score": {
"pointsEarned": 1,
"pointsPossible": 10,
},
"username": "username-1",
},
Object {
{
"dateSubmitted": "2021-12-10 18:06:15.319213+00:00",
"gradingStatus": "graded",
"score": Object {
"score": {
"pointsEarned": 2,
"pointsPossible": 10,
},
"username": "username-2",
},
Object {
{
"dateSubmitted": "2021-12-11 07:06:15.319213+00:00",
"gradingStatus": "in-progress",
"score": Object {
"score": {
"pointsEarned": 3,
"pointsPossible": 10,
},
@@ -93,12 +93,12 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: h
}
data-testid="data-table"
defaultColumnValues={
Object {
{
"Filter": "TextFilter",
}
}
initialState={
Object {
{
"pageIndex": 0,
"pageSize": 10,
}
@@ -110,7 +110,7 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: h
itemCount={3}
numBreakoutFilters={2}
tableActions={
Array [
[
<mockConstructor
handleClick={[Function]}
/>,
@@ -131,50 +131,50 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: t
<DataTable
FilterStatusComponent={[MockFunction FilterStatusComponent]}
bulkActions={
Array [
[
<mockConstructor
handleClick={[Function]}
/>,
]
}
columns={
Array [
Object {
[
{
"Header": "Team name",
"accessor": "teamName",
},
Object {
{
"Cell": [Function],
"Header": "Team submission date",
"accessor": "dateSubmitted",
"disableFilters": true,
},
Object {
{
"Cell": [Function],
"Header": "Grade",
"accessor": "score",
"disableFilters": true,
},
Object {
{
"Cell": [Function],
"Filter": "MultiSelectDropdownFilter",
"Header": "Grading status",
"accessor": "gradingStatus",
"filter": "includesValue",
"filterChoices": Array [
Object {
"filterChoices": [
{
"name": "Ungraded",
"value": "ungraded",
},
Object {
{
"name": "Grading Completed",
"value": "graded",
},
Object {
{
"name": "Currently being graded by someone else",
"value": "locked",
},
Object {
{
"name": "You are currently grading this response",
"value": "in-progress",
},
@@ -183,29 +183,29 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: t
]
}
data={
Array [
Object {
[
{
"dateSubmitted": "2021-12-08 09:06:15.319213+00:00",
"gradingStatus": "ungraded",
"score": Object {
"score": {
"pointsEarned": 1,
"pointsPossible": 10,
},
"teamName": "teamName-1",
},
Object {
{
"dateSubmitted": "2021-12-10 18:06:15.319213+00:00",
"gradingStatus": "graded",
"score": Object {
"score": {
"pointsEarned": 2,
"pointsPossible": 10,
},
"teamName": "teamName-2",
},
Object {
{
"dateSubmitted": "2021-12-11 07:06:15.319213+00:00",
"gradingStatus": "in-progress",
"score": Object {
"score": {
"pointsEarned": 3,
"pointsPossible": 10,
},
@@ -215,12 +215,12 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: t
}
data-testid="data-table"
defaultColumnValues={
Object {
{
"Filter": "TextFilter",
}
}
initialState={
Object {
{
"pageIndex": 0,
"pageSize": 10,
}
@@ -232,7 +232,7 @@ exports[`SubmissionsTable component component render tests snapshots snapshot: t
itemCount={3}
numBreakoutFilters={2}
tableActions={
Array [
[
<mockConstructor
handleClick={[Function]}
/>,

View File

@@ -1,10 +1,30 @@
import React from 'react';
import { shallow } from '@edx/react-unit-test-utils';
import { getConfig } from '@edx/frontend-platform';
import { NotificationsBanner } from '.';
jest.mock('@edx/frontend-platform', () => ({
getConfig: jest.fn(),
}));
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 />);
expect(el.snapshot).toMatchSnapshot();
});

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NotificationsBanner component snapshots 1`] = `
exports[`NotificationsBanner component snapshots with ACCOUNT_SETTINGS_URL 1`] = `
<PageBanner
variant="accentB"
>
@@ -11,7 +11,7 @@ exports[`NotificationsBanner component snapshots 1`] = `
id="ora-grading.NotificationsBanner.Message"
/>
<Hyperlink
destination="http://localhost:1997/notifications"
destination="http://localhost:1997/#notifications"
isInline={true}
rel="noopener noreferrer"
showLaunchIcon={false}
@@ -27,3 +27,22 @@ exports[`NotificationsBanner component snapshots 1`] = `
</span>
</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>
`;

View File

@@ -10,16 +10,26 @@ export const NotificationsBanner = () => (
<PageBanner variant="accentB">
<span>
<FormattedMessage {...messages.infoMessage} />
<Hyperlink
isInline
variant="muted"
destination={`${getConfig().ACCOUNT_SETTINGS_URL}/notifications`}
target="_blank"
rel="noopener noreferrer"
showLaunchIcon={false}
>
<FormattedMessage {...messages.notificationsBannerLinkMessage} />
</Hyperlink>
{
(
getConfig().ACCOUNT_SETTINGS_URL === null
|| getConfig().ACCOUNT_SETTINGS_URL === undefined
|| getConfig().ACCOUNT_SETTINGS_URL.trim().length === 0
) ? (
<FormattedMessage {...messages.notificationsBannerPreferencesCenterMessage} />
) : (
<Hyperlink
isInline
variant="muted"
destination={`${getConfig().ACCOUNT_SETTINGS_URL}/#notifications`}
target="_blank"
rel="noopener noreferrer"
showLaunchIcon={false}
>
<FormattedMessage {...messages.notificationsBannerPreferencesCenterMessage} />
</Hyperlink>
)
}
</span>
</PageBanner>
);

View File

@@ -8,7 +8,7 @@ const messages = defineMessages({
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',
},
notificationsBannerLinkMessage: {
notificationsBannerPreferencesCenterMessage: {
id: 'ora-grading.NotificationsBanner.linkMessage',
defaultMessage: 'preferences center.',
description: 'placeholder for the preferences center link',

View File

@@ -3,13 +3,13 @@
exports[`FileDownload component snapshot download is completed 1`] = `
<StatefulButton
disabledStates={
Array [
[
"pending",
"complete",
]
}
icons={
Object {
{
"complete": <Icon
className="fa fa-check"
/>,
@@ -25,7 +25,7 @@ exports[`FileDownload component snapshot download is completed 1`] = `
}
}
labels={
Object {
{
"complete": <FormattedMessage
defaultMessage="Downloaded!"
description="Download files completed state label"
@@ -56,13 +56,13 @@ exports[`FileDownload component snapshot download is completed 1`] = `
exports[`FileDownload component snapshot download is failed 1`] = `
<StatefulButton
disabledStates={
Array [
[
"pending",
"complete",
]
}
icons={
Object {
{
"complete": <Icon
className="fa fa-check"
/>,
@@ -78,7 +78,7 @@ exports[`FileDownload component snapshot download is failed 1`] = `
}
}
labels={
Object {
{
"complete": <FormattedMessage
defaultMessage="Downloaded!"
description="Download files completed state label"
@@ -109,13 +109,13 @@ exports[`FileDownload component snapshot download is failed 1`] = `
exports[`FileDownload component snapshot download is inactive 1`] = `
<StatefulButton
disabledStates={
Array [
[
"pending",
"complete",
]
}
icons={
Object {
{
"complete": <Icon
className="fa fa-check"
/>,
@@ -131,7 +131,7 @@ exports[`FileDownload component snapshot download is inactive 1`] = `
}
}
labels={
Object {
{
"complete": <FormattedMessage
defaultMessage="Downloaded!"
description="Download files completed state label"
@@ -162,13 +162,13 @@ exports[`FileDownload component snapshot download is inactive 1`] = `
exports[`FileDownload component snapshot download is pending 1`] = `
<StatefulButton
disabledStates={
Array [
[
"pending",
"complete",
]
}
icons={
Object {
{
"complete": <Icon
className="fa fa-check"
/>,
@@ -184,7 +184,7 @@ exports[`FileDownload component snapshot download is pending 1`] = `
}
}
labels={
Object {
{
"complete": <FormattedMessage
defaultMessage="Downloaded!"
description="Download files completed state label"

View File

@@ -12,7 +12,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
>
<FileRenderer
file={
Object {
{
"description": "file description 0",
"downloadUrl": "/url-path/fake_file_0.pdf",
"name": "fake_file_0.pdf",
@@ -22,7 +22,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 1",
"downloadUrl": "/url-path/fake_file_1.jpg",
"name": "fake_file_1.jpg",
@@ -32,7 +32,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 2",
"downloadUrl": "/url-path/fake_file_2.jpeg",
"name": "fake_file_2.jpeg",
@@ -42,7 +42,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 3",
"downloadUrl": "/url-path/fake_file_3.png",
"name": "fake_file_3.png",
@@ -52,7 +52,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 4",
"downloadUrl": "/url-path/fake_file_4.bmp",
"name": "fake_file_4.bmp",
@@ -62,7 +62,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 5",
"downloadUrl": "/url-path/fake_file_5.txt",
"name": "fake_file_5.txt",
@@ -72,7 +72,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 6",
"downloadUrl": "/url-path/fake_file_6.gif",
"name": "fake_file_6.gif",
@@ -82,7 +82,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 7",
"downloadUrl": "/url-path/fake_file_7.jfif",
"name": "fake_file_7.jfif",
@@ -92,7 +92,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 8",
"downloadUrl": "/url-path/fake_file_8.pjpeg",
"name": "fake_file_8.pjpeg",
@@ -102,7 +102,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 9",
"downloadUrl": "/url-path/fake_file_9.pjp",
"name": "fake_file_9.pjp",
@@ -112,7 +112,7 @@ exports[`PreviewDisplay component snapshot files render with props 1`] = `
/>
<FileRenderer
file={
Object {
{
"description": "file description 10",
"downloadUrl": "/url-path/fake_file_10.svg",
"name": "fake_file_10.svg",

View File

@@ -53,19 +53,19 @@ exports[`SubmissionFiles component snapshot files existed for props 1`] = `
>
<DataTable
columns={
Array [
Object {
[
{
"Cell": [MockFunction FileNameCell],
"Header": "Name",
"accessor": "name",
},
Object {
{
"Cell": [MockFunction FileExtensionCell],
"Header": "File Extension",
"accessor": "name",
"id": "extension",
},
Object {
{
"Cell": [MockFunction FilePopoverCell],
"Header": "File Metadata",
"accessor": "",
@@ -73,14 +73,14 @@ exports[`SubmissionFiles component snapshot files existed for props 1`] = `
]
}
data={
Array [
Object {
[
{
"description": "description for the file",
"downloadURL": "/valid-url-wink-wink",
"name": "some file name.jpg",
"size": 0,
},
Object {
{
"description": "description for this file",
"downloadURL": "/url-2",
"name": "file number 2.jpg",
@@ -101,14 +101,14 @@ exports[`SubmissionFiles component snapshot files existed for props 1`] = `
<FileDownload
data-testid="file-download"
files={
Array [
Object {
[
{
"description": "description for the file",
"downloadURL": "/valid-url-wink-wink",
"name": "some file name.jpg",
"size": 0,
},
Object {
{
"description": "description for this file",
"downloadURL": "/url-2",
"name": "file number 2.jpg",
@@ -161,19 +161,19 @@ exports[`SubmissionFiles component snapshot files size exceed 1`] = `
>
<DataTable
columns={
Array [
Object {
[
{
"Cell": [MockFunction FileNameCell],
"Header": "Name",
"accessor": "name",
},
Object {
{
"Cell": [MockFunction FileExtensionCell],
"Header": "File Extension",
"accessor": "name",
"id": "extension",
},
Object {
{
"Cell": [MockFunction FilePopoverCell],
"Header": "File Metadata",
"accessor": "",
@@ -181,14 +181,14 @@ exports[`SubmissionFiles component snapshot files size exceed 1`] = `
]
}
data={
Array [
Object {
[
{
"description": "description for the file",
"downloadURL": "/valid-url-wink-wink",
"name": "some file name.jpg",
"size": 1610612737,
},
Object {
{
"description": "description for this file",
"downloadURL": "/url-2",
"name": "file number 2.jpg",

View File

@@ -23,11 +23,11 @@ exports[`ResponseDisplay component snapshot file upload disabled without respons
>
<SubmissionFiles
data-testid="submission-files"
files={Array []}
files={[]}
/>
<PreviewDisplay
data-testid="allow-file-upload"
files={Array []}
files={[]}
/>
</div>
`;
@@ -39,13 +39,13 @@ exports[`ResponseDisplay component snapshot file upload enable with valid respon
<SubmissionFiles
data-testid="submission-files"
files={
Array [
Object {
[
{
"description": "description for the file",
"downloadURL": "/valid-url-wink-wink",
"name": "some file name.jpg",
},
Object {
{
"description": "description for this file",
"downloadURL": "/url-2",
"name": "file number 2.jpg",
@@ -56,13 +56,13 @@ exports[`ResponseDisplay component snapshot file upload enable with valid respon
<PreviewDisplay
data-testid="allow-file-upload"
files={
Array [
Object {
[
{
"description": "description for the file",
"downloadURL": "/valid-url-wink-wink",
"name": "some file name.jpg",
},
Object {
{
"description": "description for this file",
"downloadURL": "/url-2",
"name": "file number 2.jpg",
@@ -89,11 +89,11 @@ exports[`ResponseDisplay component snapshot file upload enable without response
>
<SubmissionFiles
data-testid="submission-files"
files={Array []}
files={[]}
/>
<PreviewDisplay
data-testid="allow-file-upload"
files={Array []}
files={[]}
/>
</div>
`;

View File

@@ -25,7 +25,7 @@ exports[`ReviewActions component component snapshot: do not show rubric 1`] = `
description="Review pane action bar score display"
id="ora-grading.ReviewActions.pointsDisplay"
values={
Object {
{
"pointsEarned": 3,
"pointsPossible": 10,
}
@@ -80,7 +80,7 @@ exports[`ReviewActions component component snapshot: loading 1`] = `
description="Review pane action bar score display"
id="ora-grading.ReviewActions.pointsDisplay"
values={
Object {
{
"pointsEarned": 3,
"pointsPossible": 10,
}

View File

@@ -21,7 +21,7 @@ exports[`SubmissionNavigation component component snapshot: no next submission (
description="Submission navigation location label"
id="ora-grading.ReviewActions.navigationLabel"
values={
Object {
{
"current": 5,
"total": 5,
}
@@ -61,7 +61,7 @@ exports[`SubmissionNavigation component component snapshot: no prev submission (
description="Submission navigation location label"
id="ora-grading.ReviewActions.navigationLabel"
values={
Object {
{
"current": 1,
"total": 5,
}

View File

@@ -16,7 +16,7 @@ import ReviewError from './ReviewError';
*/
export class LockErrors extends React.Component {
get errorProp() {
if (this.props.errorStatus === ErrorStatuses.forbidden) {
if (this.props.errorStatus === ErrorStatuses.conflict) {
return {
heading: messages.errorLockContestedHeading,
message: messages.errorLockContested,

View File

@@ -41,7 +41,7 @@ describe('LockErrors component', () => {
expect(el.snapshot).toMatchSnapshot();
});
test('snapshot: error with conflicted lock', () => {
el = shallow(<LockErrors {...props} errorStatus={ErrorStatuses.forbidden} />);
el = shallow(<LockErrors {...props} errorStatus={ErrorStatuses.conflict} />);
expect(el.snapshot).toMatchSnapshot();
});
});

View File

@@ -5,7 +5,7 @@ exports[`SubmitErrors component snapshots snapshot: no failure 1`] = `null`;
exports[`SubmitErrors component snapshots snapshot: with valid error, loads from hook 1`] = `
<ReviewError
actions={
Object {
{
"cancel": "hooks.reviewActions.cancel",
"confirm": "hooks.reviewActions.confirm",
}

View File

@@ -3,17 +3,17 @@
exports[`DownloadErrors component component snapshots failed: show error 1`] = `
<ReviewError
actions={
Object {
"cancel": Object {
"message": Object {
{
"cancel": {
"message": {
"defaultMessage": "Dismiss",
"description": "Dismiss error action button text",
"id": "ora-grading.ReviewModal.dismiss",
},
"onClick": [Function],
},
"confirm": Object {
"message": Object {
"confirm": {
"message": {
"defaultMessage": "Retry download",
"description": "Failed download retry button text",
"id": "ora-grading.ReviewModal.errorRetryDownload",
@@ -23,7 +23,7 @@ exports[`DownloadErrors component component snapshots failed: show error 1`] = `
}
}
headingMessage={
Object {
{
"defaultMessage": "Couldn't download files",
"id": "ora-grading.ReviewModal.errorDownloadFailed",
}

View File

@@ -3,7 +3,7 @@
exports[`LockErrors component component snapshots no failure 1`] = `
<ReviewError
headingMessage={
Object {
{
"defaultMessage": "Invalid request. Please check your input.",
"description": "Error lock request for missing params",
"id": "ora-grading.ReviewModal.errorLockBadRequestHeading",
@@ -22,7 +22,7 @@ exports[`LockErrors component component snapshots no failure 1`] = `
exports[`LockErrors component component snapshots snapshot: error with bad request 1`] = `
<ReviewError
headingMessage={
Object {
{
"defaultMessage": "Invalid request. Please check your input.",
"description": "Error lock request for missing params",
"id": "ora-grading.ReviewModal.errorLockBadRequestHeading",
@@ -41,7 +41,7 @@ exports[`LockErrors component component snapshots snapshot: error with bad reque
exports[`LockErrors component component snapshots snapshot: error with conflicted lock 1`] = `
<ReviewError
headingMessage={
Object {
{
"defaultMessage": "The lock owned by another user",
"description": "Error lock by someone else",
"id": "ora-grading.ReviewModal.errorLockContestedHeading",

View File

@@ -3,7 +3,7 @@
exports[`ReviewError component component snapshots cancel and confirm 1`] = `
<Alert
actions={
Array [
[
<Button
onClick={[MockFunction this.props.cancel.onClick]}
variant="outline-primary"
@@ -43,7 +43,7 @@ exports[`ReviewError component component snapshots cancel and confirm 1`] = `
exports[`ReviewError component component snapshots cancel only 1`] = `
<Alert
actions={
Array [
[
<Button
onClick={[MockFunction this.props.cancel.onClick]}
variant="outline-primary"
@@ -75,7 +75,7 @@ exports[`ReviewError component component snapshots cancel only 1`] = `
exports[`ReviewError component component snapshots confirm only 1`] = `
<Alert
actions={
Array [
[
<Button
onClick={[MockFunction this.props.confirm.onClick]}
>
@@ -105,7 +105,7 @@ exports[`ReviewError component component snapshots confirm only 1`] = `
exports[`ReviewError component component snapshots no actions 1`] = `
<Alert
actions={Array []}
actions={[]}
className=""
variant="danger"
>

View File

@@ -2,14 +2,11 @@
.review-modal-body {
background-color: $gray-300 !important;
overflow: auto !important;
padding: inherit;
& > div.pgn__modal-body-content {
& > div.pgn__modal-body-content .row {
height: 100%;
.row {
height: 100%;
}
}
.content-block {
@@ -40,4 +37,4 @@
width: 100%;
}
}
}
}

View File

@@ -37,7 +37,7 @@ exports[`ReviewModal component component snapshots loading 1`] = `
<ReviewContent />
<LoadingMessage
message={
Object {
{
"defaultMessage": "Loading response",
"description": "loading text for submission response review screen",
"id": "ora-grading.ReviewModal.loadingResponse",

View File

@@ -19,15 +19,19 @@
}
}
.criteria-option {
display: flex;
width: 100%;
> div {
display: inline;
display: flex;
align-items: flex-start;
justify-content: space-between;
width: 100%;
.pgn__form-label {
display: inline-flex;
padding-right: 10px;
}
.pgn__form-control-description {
float: right;
white-space: nowrap;
}
}
}
@@ -42,6 +46,10 @@
.help-popover-option {
margin-bottom: map-get($spacers, 1);
}
.popover-body {
max-height: 100vh;
overflow-y: auto !important;
}
}
@@ -80,4 +88,4 @@
.grading-rubric-card {
margin-left: 0 !important;
}
}
}

View File

@@ -70,7 +70,7 @@ exports[`Rubric Container snapshot: show footer 1`] = `
>
<StatefulButton
labels={
Object {
{
"complete": "Grade Submitted",
"default": "Submit grade",
"pending": "Submitting grade",

View File

@@ -1,4 +1,5 @@
import { getConfig } from '@edx/frontend-platform';
import { getConfig, getPath } from '@edx/frontend-platform';
export const routePath = () => `${getConfig().PUBLIC_PATH}:courseId`;
export const locationId = () => decodeURIComponent(window.location.pathname).replace(getConfig().PUBLIC_PATH, '');
const publicPath = getPath(getConfig().PUBLIC_PATH);
export const routePath = () => `${publicPath}:courseId`;
export const locationId = () => decodeURIComponent(window.location.pathname).replace(publicPath, '');

View File

@@ -6,6 +6,7 @@ jest.unmock('./app');
jest.mock('@edx/frontend-platform', () => {
const PUBLIC_PATH = '/test-public-path/';
return {
...jest.requireActual('@edx/frontend-platform'),
getConfig: () => ({ PUBLIC_PATH }),
PUBLIC_PATH,
};

View File

@@ -182,11 +182,11 @@ const grading = createSlice({
const gradeData = {
...state.gradeData,
...(payload && { [submissionUUID]: payload.submissionStatus.gradeData }),
...(payload && { [submissionUUID]: payload.gradeData }),
};
const { gradeStatus } = payload ? payload.submissionStatus : state.current;
const lockStatus = payload ? payload.submissionStatus.lockStatus : lockStatuses.unlocked;
const { gradeStatus } = payload || state.current;
const lockStatus = payload ? payload.lockStatus : lockStatuses.unlocked;
return {
...state,

View File

@@ -250,7 +250,7 @@ describe('app reducer', () => {
});
describe('stopGrading', () => {
let output;
const args = { submissionStatus: { gradeData: testData, lockStatus, gradeStatus } };
const args = { gradeData: testData, lockStatus, gradeStatus };
describe('resulting state', () => {
test('gradingData: deletes current data', () => {
output = reducer(testState, actions.stopGrading());

View File

@@ -1,4 +1,4 @@
import _ from 'lodash';
import sortBy from 'lodash/sortBy';
import { createSelector } from 'reselect';
import { StrictDict } from 'utils';
@@ -22,7 +22,7 @@ export const listData = createSelector(
const gradingStatus = (lockStatus === lockStatuses.unlocked ? gradeStatus : lockStatus);
return { gradingStatus, ...rest };
});
return _.sortBy(
return sortBy(
submissionList,
['submissionDate'],
);

View File

@@ -6,9 +6,9 @@ import { RequestKeys } from 'data/constants/requests';
import api from 'data/services/lms/api';
import * as download from './download';
const mockBlobWriter = jest.fn().mockName('BlobWriter');
const mockTextReader = jest.fn().mockName('TextReader');
const mockBlobReader = jest.fn().mockName('BlobReader');
const mockBlobWriter = jest.fn();
const mockTextReader = jest.fn();
const mockBlobReader = jest.fn();
const mockZipAdd = jest.fn();
const mockZipClose = jest.fn();
@@ -21,9 +21,9 @@ jest.mock('@zip.js/zip.js', () => {
close: mockZipClose.mockImplementation(() => Promise.resolve(files)),
files,
})),
BlobWriter: () => mockBlobWriter,
TextReader: () => mockTextReader,
BlobReader: () => mockBlobReader,
BlobWriter: function _() { return mockBlobWriter; },
TextReader: function _() { return mockTextReader; },
BlobReader: function _() { return mockBlobReader; },
};
});

View File

@@ -1,6 +1,6 @@
import * as redux from 'redux';
import thunkMiddleware from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction';
import { composeWithDevTools } from '@redux-devtools/extension';
import { createLogger } from 'redux-logger';
import apiTestUtils from 'data/services/lms/fakeData/testUtils';

View File

@@ -1,6 +1,6 @@
import { applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension/logOnlyInProduction';
import { composeWithDevTools } from '@redux-devtools/extension';
import { createLogger } from 'redux-logger';
import rootReducer, { actions, selectors } from 'data/redux';
@@ -22,7 +22,7 @@ jest.mock('redux', () => ({
applyMiddleware: (...middleware) => ({ applied: middleware }),
createStore: (reducer, middleware) => ({ reducer, middleware }),
}));
jest.mock('redux-devtools-extension/logOnlyInProduction', () => ({
jest.mock('@redux-devtools/extension', () => ({
composeWithDevTools: (middleware) => ({ withDevTools: middleware }),
}));

View File

@@ -2,8 +2,8 @@
import 'core-js/stable';
import 'regenerator-runtime/runtime';
import React from 'react';
import ReactDOM from 'react-dom';
import React, { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
import store from 'data/store';
@@ -20,18 +20,24 @@ import messages from './i18n';
import App from './App';
subscribe(APP_READY, () => {
ReactDOM.render(
<AppProvider store={store} wrapWithRouter={false}>
<App />
</AppProvider>,
document.getElementById('root'),
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<AppProvider store={store} wrapWithRouter={false}>
<App />
</AppProvider>
</StrictMode>,
);
});
subscribe(APP_INIT_ERROR, (error) => {
ReactDOM.render(
<ErrorPage message={error.message} />,
document.getElementById('root'),
const root = createRoot(document.getElementById('root'));
root.render(
<StrictMode>
<ErrorPage message={error.message} />
</StrictMode>,
);
});

View File

@@ -1,5 +1,3 @@
import { render } from 'react-dom';
import {
APP_INIT_ERROR,
APP_READY,
@@ -11,8 +9,24 @@ import {
import messages from './i18n';
import * as app from '.';
jest.mock('react-dom', () => ({
render: jest.fn(),
// These need to be var not let so they get hoisted
// 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', () => ({
@@ -39,7 +53,7 @@ describe('app registry', () => {
let getElement;
beforeEach(() => {
render.mockClear();
mockRender.mockClear();
getElement = window.document.getElementById;
window.document.getElementById = jest.fn(id => ({ id }));
});
@@ -51,18 +65,16 @@ describe('app registry', () => {
const callArgs = subscribe.mock.calls[0];
expect(callArgs[0]).toEqual(APP_READY);
callArgs[1]();
const [rendered, target] = render.mock.calls[0];
const [rendered] = mockRender.mock.calls[0];
expect(rendered).toMatchSnapshot();
expect(target).toEqual(document.getElementById('root'));
});
test('subscribe: APP_INIT_ERROR. snapshot: displays an ErrorPage to root element', () => {
const callArgs = subscribe.mock.calls[1];
expect(callArgs[0]).toEqual(APP_INIT_ERROR);
const error = { message: 'test-error-message' };
callArgs[1](error);
const [rendered, target] = render.mock.calls[0];
const [rendered] = mockRender.mock.calls[0];
expect(rendered).toMatchSnapshot();
expect(target).toEqual(document.getElementById('root'));
});
test('initialize is called with footerMessages and requireAuthenticatedUser', () => {
expect(initialize).toHaveBeenCalledTimes(1);

View File

@@ -0,0 +1,53 @@
# Footer Slot
### Slot ID: `org.openedx.frontend.layout.footer.v1`
### Slot ID Aliases
* `footer_slot`
## Description
This slot is used to replace/modify/hide the footer.
The implementation of the `FooterSlot` component lives in [the `frontend-component-footer` repository](https://github.com/openedx/frontend-component-footer/).
## Example
The following `env.config.jsx` will replace the default footer.
![Screenshot of Default Footer](./images/default_footer.png)
with a simple custom footer
![Screenshot of Custom Footer](./images/custom_footer.png)
```jsx
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
const config = {
pluginSlots: {
'org.openedx.frontend.layout.footer.v1': {
plugins: [
{
// Hide the default footer
op: PLUGIN_OPERATIONS.Hide,
widgetId: 'default_contents',
},
{
// Insert a custom footer
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'custom_footer',
type: DIRECT_PLUGIN,
RenderWidget: () => (
<h1 style={{textAlign: 'center'}}>🦶</h1>
),
},
},
]
}
},
}
export default config;
```

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -0,0 +1,3 @@
# `frontend-app-ora-grading` Plugin Slots
* [`org.openedx.frontend.layout.footer.v1`](./FooterSlot/)