Compare commits

..

12 Commits

Author SHA1 Message Date
jszewczulak
4b2e46e387 feat: lint fix 2023-05-11 09:33:03 -04:00
jszewczulak
7ce1808b0a feat: added lightning.js 2023-05-11 09:33:03 -04:00
jszewczulak
e62cc3d135 feat: added logic to render feedback widget in PROD only 2023-05-11 09:33:03 -04:00
jszewczulak
c7a3cc0341 feat: added logic to render feedback widget in PROD only 2023-05-11 09:33:00 -04:00
jszewczulak
113f66783a feat: added new property 2023-05-11 09:30:47 -04:00
jszewczulak
19230c4506 feat: added "Get Feedback" widget 2023-05-11 09:30:47 -04:00
Omar Al-Ithawi
ae1702d182 feat: use atlas in make pull_translations (#325)
Changes
-------
 - Bump frontend-platform to bring `intl-imports.js` script
 - Move all i18n imports into `src/i18n/index.js` so `intl-imports.js` can
   override it with latest translations
 - Add `atlas` into `make pull_translations` when `OPENEDX_ATLAS_PULL`
   environment variable is set.
 - Refactored i18n utils into own file to avoid overwriting them by
   atlas

Refs: [FC-0012 project](https://openedx.atlassian.net/l/cp/XGS0iCcQ) implementing Translation Infrastructure OEP-58.
2023-05-09 10:32:40 -04:00
Peter Kulko
67789481fb chore: use openedx brand as a default theme (#327) 2023-05-04 21:22:46 +03:00
Jansen Kantor
543cd623e1 feat: add column for full name for masters students (#321)
* feat: add column for full name for masters students

* refactor: move masters asterisk out of messages file

* refactor: simpletext -> text

* refactor: asterisk const
2023-04-28 13:04:31 -04:00
dependabot[bot]
ba31b713e2 build(deps): bump webpack from 5.75.0 to 5.79.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.75.0 to 5.79.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.75.0...v5.79.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-04-28 10:42:41 -04:00
jansenk
84fe2c6628 chore: update browserslist DB 2023-04-28 10:34:43 -04:00
Leangseu Kim
b87447b543 fix: file input handler 2023-04-26 15:32:02 -04:00
32 changed files with 26611 additions and 2746 deletions

1
.env
View File

@@ -32,3 +32,4 @@ ENTERPRISE_MARKETING_UTM_CAMPAIGN=''
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM=''
APP_ID=''
MFE_CONFIG_API_URL=''
DISPLAY_FEEDBACK_WIDGET='true'

View File

@@ -39,3 +39,4 @@ ENTERPRISE_MARKETING_UTM_CAMPAIGN='example.com Referral'
ENTERPRISE_MARKETING_FOOTER_UTM_MEDIUM='Footer'
APP_ID=''
MFE_CONFIG_API_URL=''
DISPLAY_FEEDBACK_WIDGET='false'

View File

@@ -3,3 +3,4 @@ dist/
node_modules/
src/postcss.config.js
src/segment.js
src/lightning.js

View File

@@ -11,18 +11,22 @@ on:
jobs:
test:
runs-on: ubuntu-20.04
strategy:
matrix:
node: [16]
npm: [8.5.x]
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
uses: actions/checkout@v2
- name: Setup Nodejs
uses: actions/setup-node@v3
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VER }}
node-version: ${{ matrix.node }}
- name: Install npm 8.5.x
run: npm install -g npm@${{ matrix.npm }}
- name: Install dependencies
run: npm ci

View File

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

View File

@@ -15,13 +15,10 @@ jobs:
with:
fetch-depth: 0
- name: Setup Nodejs Env
run: echo "NODE_VER=`cat .nvmrc`" >> $GITHUB_ENV
- name: Setup Node.js
uses: actions/setup-node@v1
with:
node-version: ${{ env.NODE_VER }}
node-version: 12
- name: Install dependencies
run: npm ci

1
.nvmrc
View File

@@ -1 +0,0 @@
18.15

View File

@@ -4,6 +4,7 @@ npm-install-%: ## install specified % npm package
export TRANSIFEX_RESOURCE = frontend-app-gradebook
transifex_langs = "ar,de,es_419,fa_IR,fr,fr_CA,hi,it,pt,ru,uk,zh_CN"
intl_imports = ./node_modules/.bin/intl-imports.js
transifex_utils = ./node_modules/.bin/transifex-utils.js
i18n = ./src/i18n
transifex_input = $(i18n)/transifex_input.json
@@ -54,9 +55,23 @@ push_translations:
# Pushing comments to Transifex...
./node_modules/@edx/reactifex/bash_scripts/put_comments_v3.sh
ifeq ($(OPENEDX_ATLAS_PULL),)
# Pulls translations from Transifex.
pull_translations:
tx pull -t -f --mode reviewed --languages=$(transifex_langs)
else
# Experimental: OEP-58 Pulls translations using atlas
pull_translations:
rm -rf src/i18n/messages
mkdir src/i18n/messages
cd src/i18n/messages \
&& atlas pull --filter=$(transifex_langs) \
translations/frontend-component-footer/src/i18n/messages:frontend-component-footer \
translations/frontend-component-header/src/i18n/messages:frontend-component-header \
translations/frontend-app-gradebook/src/i18n/messages:frontend-app-gradebook
$(intl_imports) frontend-component-header frontend-component-footer frontend-app-gradebook
endif
# This target is used by CI.
validate-no-uncommitted-package-lock-changes:

28904
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@edx/frontend-app-gradebook",
"version": "1.6.1",
"version": "1.6.2",
"description": "edx editable gradebook-ui to manipulate grade overrides on subsections",
"repository": {
"type": "git",
@@ -28,10 +28,10 @@
"extends @edx/browserslist-config"
],
"dependencies": {
"@edx/brand": "npm:@edx/brand-edx.org@^1.3.2",
"@edx/frontend-component-footer": "^11.1.1",
"@edx/frontend-component-header": "^3.1.1",
"@edx/frontend-platform": "2.5.0",
"@edx/brand": "npm:@edx/brand-openedx@^1.2.0",
"@edx/frontend-component-footer": "^12.0.0",
"@edx/frontend-component-header": "^4.0.0",
"@edx/frontend-platform": "^4.2.0",
"@edx/paragon": "^19.25.4",
"@edx/reactifex": "^2.1.1",
"@fortawesome/fontawesome-svg-core": "^1.2.25",
@@ -47,12 +47,11 @@
"enzyme-to-json": "^3.6.2",
"font-awesome": "4.7.0",
"history": "4.10.1",
"prop-types": "15.7.2",
"prop-types": "15.8.1",
"query-string": "6.13.0",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-helmet": "^6.1.0",
"react-intl": "^2.9.0",
"react-redux": "^7.1.1",
"react-router": "5.2.0",
"react-router-dom": "5.2.0",
@@ -68,7 +67,7 @@
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
"@edx/frontend-build": "12.8.27",
"@edx/frontend-build": "^12.4.15",
"@testing-library/react": "^12.1.0",
"axios": "0.21.2",
"axios-mock-adapter": "^1.17.0",

View File

@@ -7,7 +7,7 @@ import { Form } from '@edx/paragon';
import selectors from 'data/selectors';
import actions from 'data/actions';
import { getLocalizedSlash } from 'i18n';
import { getLocalizedSlash } from 'i18n/utils';
/**
* <AdjustedGradeInput />

View File

@@ -29,16 +29,16 @@ Username.propTypes = {
};
/**
* Fields.Email
* Simple label field for email value.
* @param {string} email - email for display
* Fields.Text
* Simple label field for text value.
* @param {string} value - value for display
*/
const Email = ({ email }) => <span className="wrap-text-in-cell">{email}</span>;
Email.propTypes = {
email: PropTypes.string.isRequired,
const Text = ({ value }) => (<span className="wrap-text-in-cell">{value}</span>);
Text.propTypes = {
value: PropTypes.string.isRequired,
};
export default StrictDict({
Email,
Text,
Username,
});

View File

@@ -41,13 +41,13 @@ describe('Gradebook Table Fields', () => {
});
});
describe('Email', () => {
const email = 'myTag@place.com';
describe('Text', () => {
const value = 'myTag@place.com';
test('snapshot', () => {
expect(shallow(<Fields.Email email={email} />)).toMatchSnapshot();
expect(shallow(<Fields.Text value={value} />)).toMatchSnapshot();
});
test('wraps entry email', () => {
expect(shallow(<Fields.Email email={email} />).text()).toEqual(email);
test('wraps entry value', () => {
expect(shallow(<Fields.Text value={value} />).text()).toEqual(value);
});
});
});

View File

@@ -45,6 +45,13 @@ const TotalGradeLabelReplacement = () => (
</div>
);
/**
* Asterisk to display next to heading labels that are only used for masters students
*/
const mastersOnlyFieldAsterisk = (
<span className="font-weight-normal">*</span>
);
/**
* <UsernameLabelReplacement />
* Username column header. Lists that Student Key is possibly available
@@ -56,11 +63,24 @@ const UsernameLabelReplacement = () => (
</div>
<div className="font-weight-normal student-key">
<FormattedMessage {...messages.studentKeyLabel} />
{ mastersOnlyFieldAsterisk }
</div>
</div>
);
/**
* <MastersOnlyLabelReplacement {message}>
* Column header for fields that are only available for masters students
*/
const MastersOnlyLabelReplacement = (message) => (
<div>
<FormattedMessage {...message} />
{ mastersOnlyFieldAsterisk }
</div>
);
export default StrictDict({
TotalGradeLabelReplacement,
UsernameLabelReplacement,
MastersOnlyLabelReplacement,
});

View File

@@ -9,6 +9,7 @@ import LabelReplacements from './LabelReplacements';
const {
TotalGradeLabelReplacement,
UsernameLabelReplacement,
MastersOnlyLabelReplacement,
} = LabelReplacements;
jest.mock('@edx/paragon', () => ({
@@ -35,6 +36,16 @@ describe('LabelReplacements', () => {
expect(shallow(<UsernameLabelReplacement />)).toMatchSnapshot();
});
});
describe('MastersOnlyLabelReplacement', () => {
test('snapshot', () => {
const message = {
id: 'id',
defaultMessage: 'defaultMessAge',
description: 'desCripTion',
};
expect(shallow(<MastersOnlyLabelReplacement {...message} />)).toMatchSnapshot();
});
});
});
describe('snapshot', () => {

View File

@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Gradebook Table Fields Email snapshot 1`] = `
exports[`Gradebook Table Fields Text snapshot 1`] = `
<span
className="wrap-text-in-cell"
>

View File

@@ -1,5 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`LabelReplacements MastersOnlyLabelReplacement snapshot 1`] = `
<div>
<FormattedMessage
defaultMessage="defaultMessAge"
description="desCripTion"
id="id"
/>
<span
className="font-weight-normal"
>
*
</span>
</div>
`;
exports[`LabelReplacements TotalGradeLabelReplacement displays overlay tooltip 1`] = `
<Tooltip
id="course-grade-tooltip"
@@ -73,10 +88,15 @@ exports[`LabelReplacements UsernameLabelReplacement snapshot 1`] = `
className="font-weight-normal student-key"
>
<FormattedMessage
defaultMessage="Student Key*"
defaultMessage="Student Key"
description="Gradebook table Student Key label"
id="gradebook.GradesView.table.labels.studentKey"
/>
<span
className="font-weight-normal"
>
*
</span>
</div>
</div>
`;

View File

@@ -13,8 +13,16 @@ exports[`GradebookTable component snapshot - fields1 and 2 between email and tot
"accessor": "Username",
},
Object {
"Header": <FormattedMessage
defaultMessage="Email*"
"Header": <MastersOnlyLabelReplacement
defaultMessage="Full Name"
description="Gradebook table full name column header"
id="gradebook.GradesView.table.headings.fullName"
/>,
"accessor": "Full Name",
},
Object {
"Header": <MastersOnlyLabelReplacement
defaultMessage="Email"
description="Gradebook table email column header"
id="gradebook.GradesView.table.headings.email"
/>,

View File

@@ -4,11 +4,11 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { DataTable } from '@edx/paragon';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import selectors from 'data/selectors';
import { Headings } from 'data/constants/grades';
import { getLocalizedPercentSign } from 'i18n';
import { getLocalizedPercentSign } from 'i18n/utils';
import messages from './messages';
import Fields from './Fields';
@@ -38,7 +38,9 @@ export class GradebookTable extends React.Component {
} else if (heading === Headings.username) {
label = <LabelReplacements.UsernameLabelReplacement />;
} else if (heading === Headings.email) {
label = <FormattedMessage {...messages.emailHeading} />;
label = <LabelReplacements.MastersOnlyLabelReplacement {...messages.emailHeading} />;
} else if (heading === Headings.fullName) {
label = <LabelReplacements.MastersOnlyLabelReplacement {...messages.fullNameHeading} />;
} else {
label = heading;
}
@@ -49,7 +51,8 @@ export class GradebookTable extends React.Component {
[Headings.username]: (
<Fields.Username username={entry.username} userKey={entry.external_user_key} />
),
[Headings.email]: (<Fields.Email email={entry.email} />),
[Headings.fullName]: (<Fields.Text value={entry.full_name} />),
[Headings.email]: (<Fields.Text value={entry.email} />),
[Headings.totalGrade]: `${roundGrade(entry.percent * 100)}${getLocalizedPercentSign()}`,
...entry.section_breakdown.reduce((acc, subsection) => ({
...acc,

View File

@@ -1,9 +1,14 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
fullNameHeading: {
id: 'gradebook.GradesView.table.headings.fullName',
defaultMessage: 'Full Name',
description: 'Gradebook table full name column header',
},
emailHeading: {
id: 'gradebook.GradesView.table.headings.email',
defaultMessage: 'Email*',
defaultMessage: 'Email',
description: 'Gradebook table email column header',
},
totalGradeHeading: {
@@ -18,7 +23,7 @@ const messages = defineMessages({
},
studentKeyLabel: {
id: 'gradebook.GradesView.table.labels.studentKey',
defaultMessage: 'Student Key*',
defaultMessage: 'Student Key',
description: 'Gradebook table Student Key label',
},
usernameLabel: {

View File

@@ -2,7 +2,6 @@ import React from 'react';
import { shallow } from 'enzyme';
import { DataTable } from '@edx/paragon';
import { FormattedMessage } from '@edx/frontend-platform/i18n';
import selectors from 'data/selectors';
import { Headings } from 'data/constants/grades';
@@ -22,7 +21,7 @@ jest.mock('./Fields', () => ({
__esModule: true,
default: {
Username: () => 'Fields.Username',
Email: () => 'Fields.Email',
Text: () => 'Fields.Text',
},
}));
jest.mock('./LabelReplacements', () => ({
@@ -30,6 +29,7 @@ jest.mock('./LabelReplacements', () => ({
default: {
TotalGradeLabelReplacement: () => 'TotalGradeLabelReplacement',
UsernameLabelReplacement: () => 'UsernameLabelReplacement',
MastersOnlyLabelReplacement: () => 'MastersOnlyLabelReplacement',
},
}));
jest.mock('./GradeButton', () => 'GradeButton');
@@ -75,6 +75,7 @@ describe('GradebookTable', () => {
],
headings: [
Headings.username,
Headings.fullName,
Headings.email,
fields.field1,
fields.field2,
@@ -104,17 +105,22 @@ describe('GradebookTable', () => {
expect(heading.accessor).toEqual(Headings.username);
expect(heading.Header.type).toEqual(LabelReplacements.UsernameLabelReplacement);
});
test('email sets key and Header from header', () => {
test('full name sets key and Header from header', () => {
const heading = headings[1];
expect(heading.accessor).toEqual(Headings.fullName);
expect(heading.Header).toEqual(<LabelReplacements.MastersOnlyLabelReplacement {...messages.fullNameHeading} />);
});
test('email sets key and Header from header', () => {
const heading = headings[2];
expect(heading.accessor).toEqual(Headings.email);
expect(heading.Header).toEqual(<FormattedMessage {...messages.emailHeading} />);
expect(heading.Header).toEqual(<LabelReplacements.MastersOnlyLabelReplacement {...messages.emailHeading} />);
});
test('subsections set key and Header from header', () => {
expect(headings[2]).toEqual({ accessor: fields.field1, Header: fields.field1 });
expect(headings[3]).toEqual({ accessor: fields.field2, Header: fields.field2 });
expect(headings[3]).toEqual({ accessor: fields.field1, Header: fields.field1 });
expect(headings[4]).toEqual({ accessor: fields.field2, Header: fields.field2 });
});
test('totalGrade sets key and replaces Header with component', () => {
const heading = headings[4];
const heading = headings[5];
expect(heading.accessor).toEqual(Headings.totalGrade);
expect(heading.Header.type).toEqual(LabelReplacements.TotalGradeLabelReplacement);
});
@@ -139,10 +145,15 @@ describe('GradebookTable', () => {
userKey: entry.external_user_key,
});
});
test('email set to Email Field', () => {
test('fullName set to Text Field', () => {
const field = row[Headings.fullName];
expect(field.type).toEqual(Fields.Text);
expect(field.props).toEqual({ value: entry.full_name });
});
test('email set to Text Field', () => {
const field = row[Headings.email];
expect(field.type).toEqual(Fields.Email);
expect(field.props).toEqual({ email: entry.email });
expect(field.type).toEqual(Fields.Text);
expect(field.props).toEqual({ value: entry.email });
});
test('totalGrade set to rounded percent grade * 100', () => {
expect(

View File

@@ -6,11 +6,10 @@ export const useImportButtonData = () => {
const submitImportGradesButtonData = thunkActions.grades.useSubmitImportGradesButtonData();
const fileInputRef = useRef();
const hasFile = fileInputRef.current && fileInputRef.current.files[0];
const handleClickImportGrades = () => hasFile && fileInputRef.current.click();
const handleClickImportGrades = () => fileInputRef.current?.click();
const handleFileInputChange = () => {
if (hasFile) {
if (fileInputRef.current?.files[0]) {
const clearInput = () => {
fileInputRef.current.value = null;
};

View File

@@ -3,6 +3,7 @@ import { StrictDict } from 'utils';
const EMAIL_HEADING = 'Email';
const TOTAL_COURSE_GRADE_HEADING = 'Total Grade (%)';
const USERNAME_HEADING = 'Username';
const FULL_NAME_HEADING = 'Full Name';
const GradeFormats = StrictDict({
absolute: 'absolute',
@@ -10,15 +11,17 @@ const GradeFormats = StrictDict({
});
const Headings = StrictDict({
email: 'Email',
totalGrade: 'Total Grade (%)',
username: 'Username',
email: EMAIL_HEADING,
totalGrade: TOTAL_COURSE_GRADE_HEADING,
username: USERNAME_HEADING,
fullName: FULL_NAME_HEADING,
});
export {
EMAIL_HEADING,
TOTAL_COURSE_GRADE_HEADING,
USERNAME_HEADING,
FULL_NAME_HEADING,
GradeFormats,
Headings,
};

View File

@@ -3,7 +3,7 @@ import { StrictDict } from 'utils';
import { Headings, GradeFormats } from 'data/constants/grades';
import { formatDateForDisplay } from 'data/actions/utils';
import { getLocalizedSlash } from 'i18n';
import { getLocalizedSlash } from 'i18n/utils';
import simpleSelectorFactory from '../utils';
import * as module from './grades';
@@ -105,12 +105,17 @@ export const headingMapper = (category, label = 'All') => {
} else {
filter = filters.byLabel;
}
const { username, email, totalGrade } = Headings;
const {
username,
fullName,
email,
totalGrade,
} = Headings;
const filteredLabels = (entry) => entry.filter(filter).map(s => s.label);
return (entry) => (
entry
? [username, email, ...filteredLabels(entry), totalGrade]
? [username, fullName, email, ...filteredLabels(entry), totalGrade]
: []
);
};

View File

@@ -1,4 +1,9 @@
import { EMAIL_HEADING, TOTAL_COURSE_GRADE_HEADING, USERNAME_HEADING } from '../constants/grades';
import {
EMAIL_HEADING,
FULL_NAME_HEADING,
TOTAL_COURSE_GRADE_HEADING,
USERNAME_HEADING,
} from '../constants/grades';
import { formatDateForDisplay } from '../actions/utils';
import * as selectors from './grades';
import exportedSelectors from './grades';
@@ -179,6 +184,7 @@ describe('grades selectors', () => {
describe('headingMapper', () => {
const expectedHeaders = (subsectionLabels) => ([
USERNAME_HEADING,
FULL_NAME_HEADING,
EMAIL_HEADING,
...subsectionLabels,
TOTAL_COURSE_GRADE_HEADING,

View File

@@ -1,4 +1,6 @@
import { getLocale, isRtl } from '@edx/frontend-platform/i18n';
import { messages as footerMessages } from '@edx/frontend-component-footer';
import { messages as headerMessages } from '@edx/frontend-component-header';
import arMessages from './messages/ar.json';
import deMessages from './messages/de.json';
import es419Messages from './messages/es_419.json';
@@ -13,7 +15,7 @@ import ukMessages from './messages/uk.json';
import zhcnMessages from './messages/zh_CN.json';
// no need to import en messages-- they are in the defaultMessage field
const messages = {
const appMessages = {
ar: arMessages,
'es-419': es419Messages,
'fa-ir': faIRMessages,
@@ -28,25 +30,8 @@ const messages = {
uk: ukMessages,
};
export const getLocalizedSlash = () => {
// For fractional grades
// if we are in a LTR language, we want to use a forward slash.
// If we are in a RTL language, we want to use a backslash instead
if (isRtl(getLocale())) {
return '\\';
}
return '/';
};
export const getLocalizedPercentSign = () => {
// LTR languages put the percent to the right of a number.
// RTL languages put the percent sign to the left of the number.
// We can place a non-printing unicode right-to-left marker next to the percent
// sign to make it print to the left of the number if we are currently in a LTR language
if (isRtl(getLocale())) {
return '\u200f%';
}
return '%';
};
export default messages;
export default [
footerMessages,
headerMessages,
appMessages,
];

22
src/i18n/utils.js Normal file
View File

@@ -0,0 +1,22 @@
import { getLocale, isRtl } from '@edx/frontend-platform/i18n';
export const getLocalizedSlash = () => {
// For fractional grades
// if we are in a LTR language, we want to use a forward slash.
// If we are in a RTL language, we want to use a backslash instead
if (isRtl(getLocale())) {
return '\\';
}
return '/';
};
export const getLocalizedPercentSign = () => {
// LTR languages put the percent to the right of a number.
// RTL languages put the percent sign to the left of the number.
// We can place a non-printing unicode right-to-left marker next to the percent
// sign to make it print to the left of the number if we are currently in a LTR language
if (isRtl(getLocale())) {
return '\u200f%';
}
return '%';
};

View File

@@ -1,5 +1,5 @@
import { isRtl } from '@edx/frontend-platform/i18n';
import { getLocalizedSlash, getLocalizedPercentSign } from './index';
import { getLocalizedSlash, getLocalizedPercentSign } from './utils';
jest.mock('@edx/frontend-platform/i18n', () => ({
isRtl: jest.fn(),

View File

@@ -10,13 +10,13 @@ import {
mergeConfig,
subscribe,
} from '@edx/frontend-platform';
import { messages as headerMessages } from '@edx/frontend-component-header';
import { messages as footerMessages } from '@edx/frontend-component-footer';
import lightning from './lightning';
import appMessages from './i18n';
import messages from './i18n';
import App from './App';
subscribe(APP_READY, () => {
lightning();
ReactDOM.render(<App />, document.getElementById('root'));
});
@@ -37,10 +37,6 @@ initialize({
});
},
},
messages: [
appMessages,
headerMessages,
footerMessages,
],
messages,
requireAuthenticatedUser: true,
});

View File

@@ -7,10 +7,8 @@ import {
mergeConfig,
subscribe,
} from '@edx/frontend-platform';
import { messages as headerMessages } from '@edx/frontend-component-header';
import { messages as footerMessages } from '@edx/frontend-component-footer';
import appMessages from './i18n';
import messages from './i18n';
import App from './App';
import '.';
@@ -23,12 +21,6 @@ jest.mock('@edx/frontend-platform', () => ({
mergeConfig: jest.fn(),
subscribe: jest.fn(),
}));
jest.mock('@edx/frontend-component-header', () => ({
messages: ['some', 'messages'],
}));
jest.mock('@edx/frontend-component-footer', () => ({
messages: ['some', 'messages'],
}));
jest.mock('./App', () => 'App');
describe('app registry', () => {
@@ -50,7 +42,7 @@ describe('app registry', () => {
});
test('initialize is called with requireAuthenticatedUser, messages, and a config handler', () => {
expect(initialize).toHaveBeenCalledWith({
messages: [appMessages, headerMessages, footerMessages],
messages,
requireAuthenticatedUser: true,
handlers: {
config: expect.any(Function),

131
src/lightning.js Normal file
View File

@@ -0,0 +1,131 @@
module.exports = () => {
if (process.env.DISPLAY_FEEDBACK_WIDGET === "true") {
window.lightningjs ||
(function (n) {
var e = "lightningjs";
function t(e, t) {
var r, i, a, o, d, c;
return (
t && (t += (/\?/.test(t) ? "&" : "?") + "lv=1"),
n[e] ||
((r = window),
(i = document),
(a = e),
(o = i.location.protocol),
(d = "load"),
(c = 0),
(function () {
n[a] = function () {
var t = arguments,
i = this,
o = ++c,
d = (i && i != r && i.id) || 0;
function s() {
return (s.id = o), n[a].apply(s, arguments);
}
return (
(e.s = e.s || []).push([o, d, t]),
(s.then = function (n, t, r) {
var i = (e.fh[o] = e.fh[o] || []),
a = (e.eh[o] = e.eh[o] || []),
d = (e.ph[o] = e.ph[o] || []);
return n && i.push(n), t && a.push(t), r && d.push(r), s;
}),
s
);
};
var e = (n[a]._ = {});
function s() {
e.P(d), (e.w = 1), n[a]("_load");
}
(e.fh = {}),
(e.eh = {}),
(e.ph = {}),
(e.l = t
? t.replace(/^\/\//, ("https:" == o ? o : "http:") + "//")
: t),
(e.p = { 0: +new Date() }),
(e.P = function (n) {
e.p[n] = new Date() - e.p[0];
}),
e.w && s(),
r.addEventListener
? r.addEventListener(d, s, !1)
: r.attachEvent("onload", s);
var l = function () {
function n() {
return [
"<!DOCTYPE ",
o,
"><",
o,
"><head></head><",
t,
"><",
r,
' src="',
e.l,
'"></',
r,
"></",
t,
"></",
o,
">",
].join("");
}
var t = "body",
r = "script",
o = "html",
d = i[t];
if (!d) return setTimeout(l, 100);
e.P(1);
var c,
s = i.createElement("div"),
h = s.appendChild(i.createElement("div")),
u = i.createElement("iframe");
(s.style.display = "none"),
(d.insertBefore(s, d.firstChild).id = "lightningjs-" + a),
(u.frameBorder = "0"),
(u.id = "lightningjs-frame-" + a),
/MSIE[ ]+6/.test(navigator.userAgent) &&
(u.src = "javascript:false"),
(u.allowTransparency = "true"),
h.appendChild(u);
try {
u.contentWindow.document.open();
} catch (n) {
(e.domain = i.domain),
(c =
"javascript:var d=document.open();d.domain='" +
i.domain +
"';"),
(u.src = c + "void(0);");
}
try {
var p = u.contentWindow.document;
p.write(n()), p.close();
} catch (e) {
u.src =
c +
'd.write("' +
n().replace(/"/g, String.fromCharCode(92) + '"') +
'");d.close();';
}
e.P(2);
};
e.l && l();
})()),
(n[e].lv = "1"),
n[e]
);
}
var r = (window.lightningjs = t(e));
(r.require = t), (r.modules = n);
})({});
window.usabilla_live = lightningjs.require(
"usabilla_live",
"//w.usabilla.com/a13a22d8ea20.js"
);
}
};

View File

@@ -32,6 +32,13 @@ jest.mock('@edx/frontend-platform/i18n', () => {
};
});
jest.mock('@edx/frontend-component-header', () => ({
messages: ['some', 'messages'],
}));
jest.mock('@edx/frontend-component-footer', () => ({
messages: ['some', 'messages'],
}));
jest.mock('@edx/paragon', () => jest.requireActual('testUtils').mockNestedComponents({
Alert: 'Alert',
ActionRow: 'ActionRow',