Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: populates datatable with subsidies #343

Merged
merged 25 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
e3e7cea
feat: Removes perLearnerEnrollmentLimit
brobro10000 Jun 12, 2023
a8f145c
feat: populates datatable with subsidies
brobro10000 Jun 13, 2023
4666299
feat: Populate datatable
brobro10000 Jun 21, 2023
fa5ff42
fix: PR updates (#346)
adamstankiewicz Jun 22, 2023
6a94221
feat: Updates paragon and @edx/brand packages
brobro10000 Jun 26, 2023
0ab500e
chore: merge
brobro10000 Jun 26, 2023
5f58c03
chore: npm i
brobro10000 Jun 26, 2023
3e0f0b8
chore: Normalized tests to passing state
brobro10000 Jun 26, 2023
5eaebfb
feat: Supports pageCount from subsidy API
brobro10000 Jun 26, 2023
e27f9c7
feat: allow graceful fail if no results returned
brobro10000 Jun 26, 2023
744ef78
feat: Working datatable sort
brobro10000 Jun 27, 2023
5db02c0
feat: Filter by enterprise uuid through basic list
brobro10000 Jun 27, 2023
bdb56fd
feat: filter subsidy uuid and debounce
brobro10000 Jun 27, 2023
e5ed3da
feat: removed unused package, newrelic
brobro10000 Jun 27, 2023
862cd42
fix: Updates financial identifier validation to meet 00k criteria
brobro10000 Jun 27, 2023
bf212f8
feat: provides the length of characters typed for opportunity product
brobro10000 Jun 27, 2023
35e0136
feat: feature flags edit button on datatable
brobro10000 Jun 28, 2023
e57189d
feat: abstraction for greater test coverage
brobro10000 Jun 28, 2023
0eb755e
feat: testing pt 1
brobro10000 Jun 28, 2023
4e119bc
chore: testing 2
brobro10000 Jun 28, 2023
9d2973f
chore: testing 3
brobro10000 Jun 28, 2023
38b040b
chore: testing final
brobro10000 Jun 28, 2023
db1fb40
chore: PR fixes
brobro10000 Jul 11, 2023
4558167
chore: PR fixes 2
brobro10000 Jul 12, 2023
8d81730
chore: PR fixes 2
brobro10000 Jul 13, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ ACCESS_TOKEN_COOKIE_NAME=null
BASE_URL=null
FEATURE_CONFIGURATION_MANAGEMENT=''
FEATURE_CONFIGURATION_ENTERPRISE_PROVISION=''
FEATURE_CONFIGURATION_EDIT_ENTERPRISE_PROVISION=''
CREDENTIALS_BASE_URL=null
CSRF_TOKEN_API_PATH=null
ECOMMERCE_BASE_URL=null
Expand Down
1 change: 1 addition & 0 deletions .env.development
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ ACCESS_TOKEN_COOKIE_NAME='edx-jwt-cookie-header-payload'
BASE_URL='http://localhost:18450'
FEATURE_CONFIGURATION_MANAGEMENT='true'
FEATURE_CONFIGURATION_ENTERPRISE_PROVISION='true'
FEATURE_CONFIGURATION_EDIT_ENTERPRISE_PROVISION='true'
CREDENTIALS_BASE_URL='http://localhost:18150'
CSRF_TOKEN_API_PATH='/csrf/api/v1/token'
ECOMMERCE_BASE_URL='http://localhost:18130'
Expand Down
13,282 changes: 5,208 additions & 8,074 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,10 @@
"url": "https://github.com/openedx/frontend-app-support-tools/issues"
},
"dependencies": {
"@edx/brand": "npm:@edx/brand-edx.org@^1.4.2",
"@edx/brand": "npm:@edx/brand-[email protected]",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to handle "~@edx/brand/paragon/overrides" import for datatable styles

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[inform] Additional context: because this is an open-source repo in the openedx Github organization, the brand-openedx theme should be the default theme installed. Should a consumer want to use the brand-edx.org theme for an MFE, that should be configured outside of committed code. For 2U/edX, the @edx/brand package may be overridden at build+deploy time via configuration (example).

"@edx/frontend-enterprise-utils": "^3.0.0",
"@edx/frontend-platform": "^4.2.0",
"@edx/paragon": "^20.26.0",
"@edx/paragon": "20.45.0",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Upgraded to handle new DjangoShort icon
Screenshot 2023-06-26 at 11 38 34 AM

"@fortawesome/fontawesome-svg-core": "1.2.32",
"@fortawesome/free-brands-svg-icons": "5.15.1",
"@fortawesome/free-regular-svg-icons": "5.15.1",
Expand All @@ -42,7 +42,6 @@
"classnames": "2.2.6",
"lodash.debounce": "4.0.8",
"moment": "2.29.1",
"newrelic": "5.13.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[inform] Context: newrelic is installed, but seemingly unused by this repo. All New Relic related things for MFEs currently comes from @edx/frontend-build and @edx/frontend-platform, without consumers needing to install newrelic themselves.

Having newrelic in package.json causes issues such as:

❯ npm i
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE   package: '[email protected]',
npm WARN EBADENGINE   required: { node: '>=6.0.0 <13.0.0', npm: '>=3.0.0' },
npm WARN EBADENGINE   current: { node: 'v18.16.0', npm: '9.5.1' }
npm WARN EBADENGINE }
npm WARN deprecated [email protected]: This version of the New Relic Node Agent has reached the end of life.

"prop-types": "15.7.2",
"react": "16.14.0",
"react-dom": "16.14.0",
Expand Down
22 changes: 1 addition & 21 deletions src/Configuration/Provisioning/Dashboard.jsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,19 @@
import React, { useEffect, useState } from 'react';

import { Icon, IconButton } from '@edx/paragon';
import { EditOutline } from '@edx/paragon/icons';
import { useHistory } from 'react-router';
import { v4 as uuidv4 } from 'uuid';

import DashboardHeader from './DashboardHeader';
import DashboardDatatable from './DashboardDatatable';
import DashboardToast from './DashboardToast';

import DashboardDatatable from './DashboardDatatable';
import { toastText } from './data/constants';
import { useDashboardContext } from './data/hooks';

// TODO: Create a new item header, search box and datatable
const Dashboard = () => {
const { hydrateEnterpriseSubsidies } = useDashboardContext();
const history = useHistory();
const { location } = history;
const { state: locationState } = location;
const [toasts, setToasts] = useState([]);

const editLearnerCreditPlan = (uuid) => {
// TODO: Navigate to the edit page for the selected learner credit plan based on UUID
history.push(`/enterprise-configuration/learner-credit/${uuid}/edit`);
};

const editAction = (onIconInteraction) => (
<IconButton
src={EditOutline}
iconAs={Icon}
onClick={onIconInteraction}
/>
);

useEffect(() => {
if (locationState?.planSuccessfullyCreated) {
setToasts((prevState) => [...prevState, {
Expand All @@ -43,7 +24,6 @@ const Dashboard = () => {
delete newState.planSuccessfullyCreated;
history.replace({ ...location, state: newState });
}
hydrateEnterpriseSubsidies(25, editAction, editLearnerCreditPlan);
}, [toastText.successfulPlanCreation, history, location, locationState]);

return (
Expand Down
2 changes: 1 addition & 1 deletion src/Configuration/Provisioning/DashboardContext.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { createContext } from 'use-context-selector';
export const DashboardContext = createContext(null);
const DashboardContextProvider = ({ children }) => {
const contextValue = useState({
enterpriseSubsidies: [],
enterpriseSubsidies: { results: [] },
});

return (
Expand Down
69 changes: 0 additions & 69 deletions src/Configuration/Provisioning/DashboardDatatable.jsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import {
brobro10000 marked this conversation as resolved.
Show resolved Hide resolved
DataTable,
TextFilter,
} from '@edx/paragon';
import React, {
useCallback, useMemo, useState,
} from 'react';
import { useContextSelector } from 'use-context-selector';
import debounce from 'lodash.debounce';
import { logError } from '@edx/frontend-platform/logging';
import { DashboardContext } from '../DashboardContext';
import { MAX_PAGE_SIZE } from '../data/constants';
import { useDashboardContext } from '../data/hooks';
import DashboardTableActions from './DashboardTableActions';
import DashboardTableBadges from './DashboardTableBadges';
import { filterDatatableData, sortDatatableData, transformDatatableDate } from '../data/utils';

const DashboardDatatable = () => {
const { enterpriseSubsidies } = useContextSelector(DashboardContext, v => v[0]);
const { hydrateEnterpriseSubsidies } = useDashboardContext();
const [isLoading, setIsLoading] = useState(true);

// Implementation due to filterText value displaying accessor value customerName as opposed to Customer Name
const filterStatus = (rest) => <DataTable.FilterStatus showFilteredFields={false} {...rest} />;

const fetchData = useCallback(async (datatableProps) => {
setIsLoading(true);
try {
await hydrateEnterpriseSubsidies({
pageIndex: datatableProps.pageIndex + 1,
sortBy: sortDatatableData(datatableProps),
filterBy: filterDatatableData(datatableProps),
});
} catch (e) {
logError(e);
} finally {
setIsLoading(false);
}
}, [hydrateEnterpriseSubsidies]);

const debouncedFetchData = useMemo(() => debounce(
fetchData,
300,
{
leading: false,
},
), [fetchData]);

return (
<section className="mt-5">
<DataTable
isLoading={isLoading}
isPaginated
manualPagination
isSortable
manualSortBy
isFilterable
manualFilters
defaultColumnValues={{ Filter: TextFilter }}
pageCount={enterpriseSubsidies.pageCount || 0}
initialState={{
pageSize: MAX_PAGE_SIZE,
pageIndex: 0,
}}
itemCount={enterpriseSubsidies?.count || 0}
data={enterpriseSubsidies.results}
fetchData={debouncedFetchData}
FilterStatusComponent={filterStatus}
columns={[
{
Header: 'Plan ID',
accessor: 'uuid',
},
{
Header: 'Plan name',
accessor: 'title',
},
{
Header: 'Plan Status',
accessor: 'isActive',
disableFilters: true,
Cell: DashboardTableBadges,
},
{
Header: 'Customer name',
accessor: 'enterpriseCustomerName',
disableSortBy: true,
},
{
Header: 'Start date',
accessor: 'activeDatetime',
disableFilters: true,
Cell: ({ row }) => transformDatatableDate(row.values.activeDatetime),
},
{
Header: 'End date',
accessor: 'expirationDatetime',
disableFilters: true,
Cell: ({ row }) => transformDatatableDate(row.values.expirationDatetime),
},
{
Header: '',
accessor: 'actions',
disableFilters: true,
disableSortBy: true,
Cell: DashboardTableActions,
},
]}
/>
</section>
);
};

export default DashboardDatatable;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import {
IconButton,
Icon,
Hyperlink,
} from '@edx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { useHistory } from 'react-router';
import {
EditOutline,
DjangoShort,
} from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import ROUTES from '../../../data/constants/routes';

const DashboardTableActions = ({ row }) => {
const rowUuid = row.values.uuid;
const { DJANGO_ADMIN_SUBSIDY_BASE_URL } = getConfig();
const history = useHistory();
const { HOME } = ROUTES.CONFIGURATION.SUB_DIRECTORY.PROVISIONING;
return [
getConfig().FEATURE_CONFIGURATION_EDIT_ENTERPRISE_PROVISION && (
brobro10000 marked this conversation as resolved.
Show resolved Hide resolved
<IconButton
key="edit-icon"
size="sm"
src={EditOutline}
iconAs={Icon}
onClick={() => history.push(`${HOME}/${rowUuid}/edit`)}
alt="Edit Subsidy Icon Button"
data-testid={`Edit-${rowUuid}`}
/>
),
<Hyperlink
key="django-icon"
destination={`${DJANGO_ADMIN_SUBSIDY_BASE_URL}/admin/subsidy/subsidy/?uuid=${rowUuid}`}
target="_blank"
showLaunchIcon={false}
data-testid="django-admin-link"
>
<IconButton
size="sm"
src={DjangoShort}
iconAs={Icon}
alt="Django Admin Icon Button"
data-testid={`Django-Admin-Page-${rowUuid}`}
/>
</Hyperlink>,
];
};

DashboardTableActions.propTypes = {
row: PropTypes.shape({
values: PropTypes.shape({
uuid: PropTypes.string,
}),
}).isRequired,
};

export default DashboardTableActions;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import {
Badge,
} from '@edx/paragon';
import PropTypes from 'prop-types';

const DashboardTableBadges = ({ row }) => {
const { isActive } = row.values;
return (
<Badge
variant={isActive ? 'success' : 'danger'}
>
{isActive ? 'Active' : 'Inactive'}
</Badge>
);
};

DashboardTableBadges.propTypes = {
row: PropTypes.shape({
values: PropTypes.shape({
isActive: PropTypes.bool,
}),
}).isRequired,
};

export default DashboardTableBadges;
3 changes: 3 additions & 0 deletions src/Configuration/Provisioning/DashboardDatatable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import DashboardDatatable from './DashboardDatatable';

export default DashboardDatatable;
Loading