Compare commits

...

16 Commits

Author SHA1 Message Date
Brian Smith
e08dc1ddc3 feat(deps): update header to 5.6.0 (#409) 2024-10-22 19:19:22 -04:00
Feanil Patel
3d2dd5006a Merge pull request #403 from openedx/feanil/ubuntu_upgrade
build: Switch to ubuntu-latest for builds
2024-09-20 10:27:51 -04:00
Bilal Qamar
694b1a75fc build: Upgrade to Node 20 (#406) 2024-09-19 17:50:39 -04:00
Feanil Patel
eff1ac0900 Merge branch 'master' into feanil/ubuntu_upgrade 2024-09-13 09:35:09 -04:00
Bilal Qamar
918463de91 test: Add Node 20 to CI matrix (#404) 2024-09-11 13:29:47 -04:00
Feanil Patel
a2d119aa43 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-gradebook/issues/401
2024-09-09 10:00:30 -04:00
Bilal Qamar
ccb7865100 feat: updated frontend-build & frontend-platform major versions (#374)
* feat: bumped frontend-platform to v6

* chore: bumped jest to v29

* fix: updated snapshots for failing tests

* refactor: updated frontend-build, updated snapshots

* feat: updated build and platform major versions, along with edx packages

* refactor: updated index.test to resolve failing test

* refactor: major version upgrade for react-unit-test-utils

* refactor: updated package-lock
2024-08-02 16:35:00 +05:00
Adolfo R. Brandes
997d205ac6 build: Update codecov and use token (#398)
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:03:01 -03:00
Adolfo R. Brandes
13433e969f Merge pull request #310 from raccoongang/lunyachek/fix/edit-grades-modal-rows-counter-olive
fix: Fix rows counter in the Edit Grade modal window
2024-05-30 14:13:07 -03:00
Farhaan Bukhsh
c21a81eb55 Merge pull request #393 from openedx/farhaan/add-catalog-file
chore: Adds catalog-info.yml for the project
2024-05-23 13:27:14 +05:30
Farhaan Bukhsh
9675a6e9a9 chore: Adds catalog-info.yml for the project
Signed-off-by: Farhaan Bukhsh <farhaan@opencraft.com>
2024-05-23 12:19:51 +05:30
Adolfo R. Brandes
d9a0a11936 Merge pull request #391 from brian-smith-tcril/footer-slot
feat: use frontend-plugin-framework to provide a FooterSlot
2024-05-17 13:10:25 -03:00
Brian Smith
13a19a274c feat: use frontend-plugin-framework to provide a FooterSlot 2024-05-17 10:49:02 -04:00
Feanil Patel
f4edf956bb Merge pull request #392 from salman2013/salman/Add-renovate-json-file
Add renovate configuration file
2024-05-15 12:05:41 -04:00
salman2013
c3c328fddb chore: add renovate configuration file 2024-05-15 15:23:02 +05:00
Stanislav Lunyachek
18cede45a6 fix: Fix rows counter in the Edit Grade modal window 2024-04-18 23:34:33 +03:00
35 changed files with 4113 additions and 5042 deletions

View File

@@ -7,7 +7,6 @@ LOGOUT_URL='http://localhost:18000/login'
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'

33
.github/renovate.json vendored Normal file
View File

@@ -0,0 +1,33 @@
{
"extends": [
"config:base",
"schedule:weekly",
":automergeLinters",
":automergeMinor",
":automergeTesters",
":enableVulnerabilityAlerts",
":rebaseStalePrs",
":semanticCommits",
":updateNotScheduled"
],
"packageRules": [
{
"matchDepTypes": [
"devDependencies"
],
"matchUpdateTypes": [
"lockFileMaintenance",
"minor",
"patch",
"pin"
],
"automerge": true
},
{
"matchPackagePatterns": ["@edx", "@openedx"],
"matchUpdateTypes": ["minor", "patch"],
"automerge": true
}
],
"timezone": "America/New_York"
}

View File

@@ -10,19 +10,19 @@ on:
jobs:
test:
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
strategy:
matrix:
node: [18, 20]
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
with:
node-version: ${{ env.NODE_VER }}
node-version: ${{ matrix.node }}
- name: Install dependencies
run: npm ci
@@ -43,7 +43,10 @@ jobs:
run: npm run build
- name: Run Coverage
uses: codecov/codecov-action@v2
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

@@ -7,7 +7,7 @@ on:
jobs:
release:
name: Release
runs-on: ubuntu-20.04
runs-on: ubuntu-latest
steps:
- name: Checkout

2
.nvmrc
View File

@@ -1 +1 @@
18.15
20

View File

@@ -108,6 +108,11 @@ check the ``enabled`` and ``enabled for all courses`` boxes.
numbers for grades. If your gradebook isn't accepting your changes, or the changes aren't resulting in sane,
recalculated grade values, verify you've set all flags correctly.
## 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).
## Running tests
1. Assuming that you're operating in the context of the edX devstack,

13
catalog-info.yaml Normal file
View File

@@ -0,0 +1,13 @@
# This file records information about this repo. Its use is described in OEP-55:
# https://open-edx-proposals.readthedocs.io/en/latest/processes/oep-0055-proc-project-maintainers.html
apiVersion: backstage.io/v1alpha1
kind: Component
metadata:
name: "frontend-app-gradebook"
description: "The frontend (MFE) for Open edX Gradebook"
annotations:
openedx.org/arch-interest-groups: ""
spec:
owner: user:farhaanbukhsh
type: 'website'
lifecycle: 'experimental'

8860
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -29,11 +29,12 @@
],
"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-header": "^5.6.0",
"@edx/frontend-platform": "8.0.0",
"@edx/openedx-atlas": "^0.6.0",
"@edx/react-unit-test-utils": "^2.0.0",
"@edx/react-unit-test-utils": "^3.0.0",
"@openedx/frontend-plugin-framework": "^1.2.1",
"@openedx/frontend-slot-footer": "^1.0.2",
"@openedx/paragon": "^22.1.1",
"@edx/reactifex": "^2.1.1",
"@fortawesome/fontawesome-svg-core": "^1.2.25",
@@ -67,7 +68,7 @@
},
"devDependencies": {
"@edx/browserslist-config": "^1.1.1",
"@openedx/frontend-build": "^13.0.28",
"@openedx/frontend-build": "14.0.3",
"@testing-library/react": "12.1.5",
"axios": "0.21.2",
"axios-mock-adapter": "^1.17.0",
@@ -75,7 +76,7 @@
"fetch-mock": "^6.5.2",
"husky": "2.7.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^26.6.3",
"jest": "^29.7.0",
"react-dev-utils": "^12.0.1",
"react-test-renderer": "17.0.2",
"reactifex": "1.1.1",

View File

@@ -3,7 +3,7 @@ import { Route, Routes } from 'react-router-dom';
import { AppProvider } from '@edx/frontend-platform/react';
import Footer from '@edx/frontend-component-footer';
import FooterSlot from '@openedx/frontend-slot-footer';
import Header from '@edx/frontend-component-header';
import store from 'data/store';
@@ -24,7 +24,7 @@ const App = () => (
/>
</Routes>
</main>
<Footer logo={process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG} />
<FooterSlot />
</div>
</AppProvider>
);

View File

@@ -3,8 +3,6 @@ import { shallow } from '@edx/react-unit-test-utils';
import { Route } from 'react-router-dom';
import Footer from '@edx/frontend-component-footer';
import store from 'data/store';
import GradebookPage from 'containers/GradebookPage';
@@ -18,13 +16,12 @@ jest.mock('react-router-dom', () => ({
jest.mock('@edx/frontend-platform/react', () => ({
AppProvider: () => 'AppProvider',
}));
jest.mock('@edx/frontend-component-footer', () => 'Footer');
jest.mock('@edx/frontend-component-footer', () => ({ FooterSlot: 'Footer' }));
jest.mock('data/store', () => 'testStore');
jest.mock('containers/GradebookPage', () => 'GradebookPage');
jest.mock('@edx/frontend-component-header', () => 'Header');
jest.mock('./head/Head', () => 'Head');
const logo = 'fakeLogo.png';
let el;
let secondChild;
@@ -34,7 +31,6 @@ describe('App router component', () => {
});
describe('component', () => {
beforeEach(() => {
process.env.LOGO_POWERED_BY_OPEN_EDX_URL_SVG = logo;
el = shallow(<App />);
secondChild = el.instance.children;
});
@@ -63,8 +59,5 @@ describe('App router component', () => {
expect(secondChild[1].findByType(Route)[0].props.element.type).toEqual(GradebookPage);
});
});
test('Footer logo drawn from env variable', () => {
expect(secondChild[1].findByType(Footer)[0].props.logo).toEqual(logo);
});
});
});

View File

@@ -15,7 +15,7 @@ exports[`App router component snapshot 1`] = `
/>
</Routes>
</main>
<Footer />
<FooterSlot />
</div>
</AppProvider>
`;

View File

@@ -1,8 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`HistoryTable component snapshot history table data (from bulkManagementHistory.map(this.formatHistoryRow) snapshot: maps resultsSummay to ResultsSummary, wraps filename and user, forwards the rest 1`] = `
Array [
Object {
[
{
"filename": <span
className="wrap-text-in-cell"
>
@@ -20,7 +20,7 @@ Array [
Eifel
</span>,
},
Object {
{
"filename": <span
className="wrap-text-in-cell"
>
@@ -45,26 +45,26 @@ exports[`HistoryTable component snapshot snapshot - loads formatted table 1`] =
<DataTable
className="table-striped"
columns={
Array [
Object {
[
{
"Header": "Gradebook",
"accessor": "filename",
"columnSortable": false,
"width": "col-5",
},
Object {
{
"Header": "Download Summary",
"accessor": "resultsSummary",
"columnSortable": false,
"width": "col",
},
Object {
{
"Header": "Who",
"accessor": "user",
"columnSortable": false,
"width": "col-1",
},
Object {
{
"Header": "When",
"accessor": "timeUploaded",
"columnSortable": false,
@@ -73,8 +73,8 @@ exports[`HistoryTable component snapshot snapshot - loads formatted table 1`] =
]
}
data={
Array [
Object {
[
{
"filename": <span
className="wrap-text-in-cell"
>
@@ -92,7 +92,7 @@ exports[`HistoryTable component snapshot snapshot - loads formatted table 1`] =
Eifel
</span>,
},
Object {
{
"filename": <span
className="wrap-text-in-cell"
>

View File

@@ -4,8 +4,8 @@ exports[`ResultsSummary component snapshot - safe hyperlink with bulkGradesUrl w
<Hyperlink
destination="www.edx.org"
href={
Object {
"url": Object {
{
"url": {
"rowId": 42,
},
}

View File

@@ -10,7 +10,7 @@ exports[`AssignmentFilter component render snapshot 1`] = `
label="Assignment"
onChange={[MockFunction]}
options={
Array [
[
<option
value=""
>

View File

@@ -10,7 +10,7 @@ exports[`AssignmentFilterType component render snapshot 1`] = `
label="Assignment Types"
onChange={[MockFunction]}
options={
Array [
[
<option
value=""
>

View File

@@ -7,7 +7,7 @@ exports[`StudentGroupsFilter component render snapshot 1`] = `
label="Tracks"
onChange={[MockFunction]}
options={
Array [
[
<option
value="Track-All"
>
@@ -43,7 +43,7 @@ exports[`StudentGroupsFilter component render snapshot 1`] = `
label="Cohorts"
onChange={[MockFunction]}
options={
Array [
[
<option
value="Cohort-All"
>

View File

@@ -6,7 +6,7 @@ exports[`BulkManagementControls render snapshot - show - network and import butt
>
<NetworkButton
label={
Object {
{
"defaultMessage": "Download Grades",
"description": "A labeled button that allows an admin user to download course grades all at once (in bulk).",
"id": "gradebook.GradesView.BulkManagementControls.bulkManagementLabel",

View File

@@ -4,22 +4,22 @@ exports[`OverrideTable component render snapshot 1`] = `
<DataTable
columns="test-columns"
data={
Array [
Object {
[
{
"test": "data",
},
Object {
{
"andOther": "test-data",
},
Object {
{
"adjustedGrade": <AdjustedGradeInput />,
"date": Object {
"date": {
"formatted": 2000-01-01T00:00:00.000Z,
},
"reason": <ReasonInput />,
},
]
}
itemCount={2}
itemCount={3}
/>
`;

View File

@@ -20,18 +20,20 @@ export const OverrideTable = () => {
if (hide) { return null; }
const tableData = [
...data,
{
adjustedGrade: <AdjustedGradeInput />,
date: formatDateForDisplay(new Date()),
reason: <ReasonInput />,
},
];
return (
<DataTable
columns={columns}
data={[
...data,
{
adjustedGrade: <AdjustedGradeInput />,
date: formatDateForDisplay(new Date()),
reason: <ReasonInput />,
},
]}
itemCount={data.length}
data={tableData}
itemCount={tableData.length}
/>
);
};

View File

@@ -19,8 +19,8 @@ exports[`FilterBadge render do not hide value snapshot 1`] = `
aria-label="close"
className="btn-info"
onClick={
Object {
"handleClose": Array [
{
"handleClose": [
"some",
"filters",
],
@@ -55,8 +55,8 @@ exports[`FilterBadge render hide Value snapshot 1`] = `
aria-label="close"
className="btn-info"
onClick={
Object {
"handleClose": Array [
{
"handleClose": [
"some",
"filters",
],

View File

@@ -3,14 +3,14 @@
exports[`FilteredUsersLabel component render snapshot 1`] = `
<format-message-function
message={
Object {
{
"defaultMessage": "Showing {filteredUsers} of {totalUsers} total learners",
"description": "Users visibility label",
"id": "gradebook.GradesTab.usersVisibilityLabel",
}
}
values={
Object {
{
"filteredUsers": <BoldText
text={100}
/>,

View File

@@ -28,32 +28,32 @@ exports[`Gradebook Table Fields Username with external_user_key snapshot 1`] = `
`;
exports[`Gradebook Table Fields Username with external_user_key wraps external user key and username 1`] = `
Object {
"children": Array [
Object {
"children": Array [
Object {
"children": Array [
{
"children": [
{
"children": [
{
"children": [
"MyNameFromHere",
],
"props": Object {},
"props": {},
"type": "div",
},
Object {
"children": Array [
{
"children": [
"My name from another land",
],
"props": Object {
"props": {
"className": "student-key",
},
"type": "div",
},
],
"props": Object {},
"props": {},
"type": "div",
},
],
"props": Object {
"props": {
"className": "wrap-text-in-cell",
},
"type": "span",

View File

@@ -32,7 +32,7 @@ exports[`LabelReplacements TotalGradeLabelReplacement snapshot 1`] = `
}
placement="left"
trigger={
Array [
[
"hover",
"focus",
]
@@ -84,7 +84,7 @@ exports[`snapshot left to right overlay placement 1`] = `
}
placement="right"
trigger={
Array [
[
"hover",
"focus",
]
@@ -118,7 +118,7 @@ exports[`snapshot right to left overlay placement 1`] = `
}
placement="left"
trigger={
Array [
[
"hover",
"focus",
]

View File

@@ -7,13 +7,13 @@ exports[`GradebookTable snapshot 1`] = `
<DataTable
RowStatusComponent={[MockFunction hooks.nullMethod]}
columns={
Array [
[
"some",
"columns",
]
}
data={
Array [
[
"some",
"data",
]

View File

@@ -41,7 +41,7 @@ exports[`ImportGradesButton component render snapshot 1`] = `
className="import-grades-btn"
import={true}
label={
Object {
{
"defaultMessage": "Import Grades",
"description": "A labeled button to import grades in the BulkManagement Tab File Upload Form",
"id": "gradebook.GradesView.importGradesBtnText",

View File

@@ -17,7 +17,7 @@ exports[`InterventionsReport component output snapshot 1`] = `
</div>
<NetworkButton
label={
Object {
{
"defaultMessage": "Download Interventions",
"description": "The labeled button to download the Intervention report from the Grades View",
"id": "gradebook.GradesView.InterventionsReport.downloadBtn",

View File

@@ -4,7 +4,7 @@ exports[`PageButtons component render snapshot 1`] = `
<div
className="d-flex justify-content-center"
style={
Object {
{
"paddingBottom": "20px",
}
}
@@ -13,7 +13,7 @@ exports[`PageButtons component render snapshot 1`] = `
disabled="prev-disabled"
onClick={[MockFunction hooks.prev.onClick]}
style={
Object {
{
"margin": "20px",
}
}
@@ -25,7 +25,7 @@ exports[`PageButtons component render snapshot 1`] = `
disabled="next-disabled"
onClick={[MockFunction hooks.next.onClick]}
style={
Object {
{
"margin": "20px",
}
}

View File

@@ -4,12 +4,12 @@ exports[`NetworkButton component snapshots snapshot 1`] = `
<StatefulButton
className="ml-2 test-class"
disabledStates={
Array [
[
"pending",
]
}
icons={
Object {
{
"default": <Icon
className="fa mr-2 fa-download"
/>,
@@ -19,7 +19,7 @@ exports[`NetworkButton component snapshots snapshot 1`] = `
}
}
labels={
Object {
{
"default": <FormattedMessage
defaultMessage="test button label"
description="test button label description"

View File

@@ -87,15 +87,16 @@ describe('root selectors', () => {
});
});
describe('if neither/only 1 are default values', () => {
beforeEach(() => {
filterConstants.filterConfig[filterName] = testConfig;
config = selectors.root.filterBadgeConfig(testState, filterName);
});
describe.each([
['neither', () => false],
['only filter1', (v) => v === filters[0]],
['only filter2', (v) => v === filters[1]],
], '%1 is default', (label, isDefaultFn) => {
beforeEach(() => {
filterConstants.filterConfig[filterName] = testConfig;
config = selectors.root.filterBadgeConfig(testState, filterName);
});
it('returns isDefault: false, string value, and remaining filterConfig', () => {
selectors.filters.isDefault.mockImplementation(isDefaultFn);
const { filterOrder, ...rest } = testConfig;

View File

@@ -0,0 +1,50 @@
# Footer Slot
### Slot ID: `footer_slot`
## Description
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/).
## 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: {
footer_slot: {
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: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,3 @@
# `frontend-app-gradebook` Plugin Slots
* [`footer_slot`](./FooterSlot/)