Skip to content

Commit

Permalink
feat: integrate csv download button on all plotly v2 charts and tables
Browse files Browse the repository at this point in the history
  • Loading branch information
jajjibhai008 committed Aug 19, 2024
1 parent 548d780 commit 404b52f
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 7 deletions.
9 changes: 8 additions & 1 deletion src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const AnalyticsV2Page = () => {
const [activeTab, setActiveTab] = useState('enrollments');
const [granularity, setGranularity] = useState('daily');
const [calculation, setCalculation] = useState('total');
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');

Check warning on line 23 in src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx#L22-L23

Added lines #L22 - L23 were not covered by tests
const dataRefreshDate = '';
const intl = useIntl();

Expand Down Expand Up @@ -52,6 +54,7 @@ const AnalyticsV2Page = () => {
</Form.Label>
<Form.Control
type="date"
onChange={(e) => setStartDate(e.target.value)}

Check warning on line 57 in src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx#L57

Added line #L57 was not covered by tests
/>
</Form.Group>
</div>
Expand All @@ -66,6 +69,7 @@ const AnalyticsV2Page = () => {
</Form.Label>
<Form.Control
type="date"
onChange={(e) => setEndDate(e.target.value)}

Check warning on line 72 in src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/AnalyticsV2Page.jsx#L72

Added line #L72 was not covered by tests
/>
</Form.Group>
</div>
Expand Down Expand Up @@ -227,7 +231,10 @@ const AnalyticsV2Page = () => {
description: 'Title for the skills tab in advance analytics.',
})}
>
<Skills />
<Skills
startDate={startDate}
endDate={endDate}
/>
</Tab>
</Tabs>
</div>
Expand Down
66 changes: 66 additions & 0 deletions src/components/AdvanceAnalyticsV2/DownloadCSV.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import {
Button,
} from '@openedx/paragon';

import PropTypes from 'prop-types';
import { logError } from '@edx/frontend-platform/logging';
import { saveAs } from 'file-saver';
import EnterpriseDataApiService from '../../data/services/EnterpriseDataApiService';

const DownloadCSV = ({
startDate, endDate, chartType, activeTab, granularity, calculation,
}) => {
const [isLoading, setIsLoading] = useState(false);
const downloadCsv = () => {
setIsLoading(true);
const chartUrl = activeTab;
const enterpriseUUID = '9e4ce45148c44c2c86a9bb3ddd138d6b';
EnterpriseDataApiService.fetchPlotlyChartsCSV(enterpriseUUID, chartUrl, {

Check warning on line 19 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L16-L19

Added lines #L16 - L19 were not covered by tests
start_date: startDate,
end_date: endDate,
granularity,
calculation,
chart_type: chartType,
response_type: 'csv',
}).then((response) => {
const contentDisposition = response.headers['content-disposition'];
let filename = 'download.csv'; // Default filename

Check warning on line 28 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L26-L28

Added lines #L26 - L28 were not covered by tests

// Extract the filename from the content-disposition header if it exists
if (contentDisposition && contentDisposition.indexOf('attachment') !== -1) {
const matches = /filename="([^"]+)"/.exec(contentDisposition);

Check warning on line 32 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L32

Added line #L32 was not covered by tests
if (matches != null && matches[1]) {
[, filename] = matches;

Check warning on line 34 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L34

Added line #L34 was not covered by tests
}
}

const blob = new Blob([response.data], { type: 'text/csv' });
saveAs(blob, filename);
setIsLoading(false);
}).catch((error) => {
setIsLoading(false);
logError(error);

Check warning on line 43 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L38-L43

Added lines #L38 - L43 were not covered by tests
});
};
return (
<Button
variant="primary"
className="ml-3"
onClick={() => downloadCsv()}

Check warning on line 50 in src/components/AdvanceAnalyticsV2/DownloadCSV.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/DownloadCSV.jsx#L50

Added line #L50 was not covered by tests
>
{isLoading ? 'loading' : 'Download CSV'}
</Button>
);
};

DownloadCSV.propTypes = {
startDate: PropTypes.string.isRequired,
endDate: PropTypes.string.isRequired,
chartType: PropTypes.string.isRequired,
activeTab: PropTypes.string.isRequired,
granularity: PropTypes.string.isRequired,
calculation: PropTypes.string.isRequired,
};

export default DownloadCSV;
35 changes: 31 additions & 4 deletions src/components/AdvanceAnalyticsV2/Header.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import DownloadCSV from './DownloadCSV';

const Header = ({ title, subtitle }) => (
<div className="analytics-header">
<h2 className="analytics-header-title">{title}</h2>
{subtitle && <p className="analytics-header-subtitle">{subtitle}</p>}
const Header = ({
title, subtitle, startDate, endDate, isDownloadCSV, activeTab, granularity, calculation, chartType,
}) => (
<div className="analytics-header d-flex justify-content-between">
<div>
<h2 className="analytics-header-title">{title}</h2>
{subtitle && <p className="analytics-header-subtitle">{subtitle}</p>}
</div>
{isDownloadCSV && (
<div className="mr-2">
<DownloadCSV
startDate={startDate}
endDate={endDate}
activeTab={activeTab}
granularity={granularity}
calculation={calculation}
chartType={chartType}
/>
</div>
)}
</div>
);

Header.defaultProps = {
subtitle: undefined,
isDownloadCSV: false,
granularity: 'day',
calculation: 'count',
};

Header.propTypes = {
title: PropTypes.string.isRequired,
subtitle: PropTypes.string,
isDownloadCSV: PropTypes.bool,
startDate: PropTypes.string.isRequired,
endDate: PropTypes.string.isRequired,
activeTab: PropTypes.string.isRequired,
chartType: PropTypes.string.isRequired,
granularity: PropTypes.string,
calculation: PropTypes.string,
};

export default Header;
16 changes: 16 additions & 0 deletions src/components/AdvanceAnalyticsV2/data/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const advancedAnalyticsV2QueryKeys = {
chartCSV: (enterpriseId, chartName) => [...advancedAnalyticsV2QueryKeys.all, 'chartCSV', enterpriseId, chartName],

Check warning on line 2 in src/components/AdvanceAnalyticsV2/data/constants.js

View check run for this annotation

Codecov / codecov/patch

src/components/AdvanceAnalyticsV2/data/constants.js#L2

Added line #L2 was not covered by tests
};

export const chartTypes = {
BUBBLE: 'bubble',
TOP_SKILLS_ENROLLMENT: 'top_skills_enrollment',
TOP_SKILLS_COMPLETION: 'top_skills_completion',
COMPLETIONS_OVER_TIME: 'completions_over_time',
TOP_COURSES_BY_COMPLETIONS: 'top_courses_by_completions',
TOP_SUBJECTS_BY_COMPLETIONS: 'top_subjects_by_completions',
};

export const ANALYTICS_TABS = {
SKILLS: 'skills',
};
11 changes: 10 additions & 1 deletion src/components/AdvanceAnalyticsV2/tabs/Enrollments.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import React from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import EmptyChart from '../charts/EmptyChart';
import Header from '../Header';

const Enrollments = () => {
const Enrollments = ({ startDate, endDate }) => {
const intl = useIntl();

return (
Expand All @@ -20,6 +21,9 @@ const Enrollments = () => {
defaultMessage: 'See audit and certificate track enrollments over time.',
description: 'Subtitle for the enrollments over time chart.',
})}
isDownloadCSV
startDate={startDate}
endDate={endDate}
/>
<EmptyChart />
</div>
Expand Down Expand Up @@ -72,4 +76,9 @@ const Enrollments = () => {
);
};

Enrollments.propTypes = {
startDate: PropTypes.string.isRequired,
endDate: PropTypes.string.isRequired,
};

export default Enrollments;
14 changes: 13 additions & 1 deletion src/components/AdvanceAnalyticsV2/tabs/Skills.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import React from 'react';
import { useIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import Header from '../Header';
import EmptyChart from '../charts/EmptyChart';
import { ANALYTICS_TABS, chartTypes } from '../data/constants';

const Skills = () => {
const Skills = ({ startDate, endDate }) => {
const intl = useIntl();

return (
Expand All @@ -20,6 +22,11 @@ const Skills = () => {
defaultMessage: 'See the top skills that are the most in demand in your organization, based on enrollments and completions.',
description: 'Subtitle for the top skills chart.',
})}
startDate={startDate}
endDate={endDate}
activeTab={ANALYTICS_TABS.SKILLS}
chartType={chartTypes.BUBBLE}
isDownloadCSV
/>
<EmptyChart />
</div>
Expand Down Expand Up @@ -53,4 +60,9 @@ const Skills = () => {
);
};

Skills.propTypes = {
startDate: PropTypes.string.isRequired,
endDate: PropTypes.string.isRequired,
};

export default Skills;
7 changes: 7 additions & 0 deletions src/data/services/EnterpriseDataApiService.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ class EnterpriseDataApiService {

static enterpriseAdminBaseUrl = `${configuration.DATA_API_BASE_URL}/enterprise/api/v1/admin/`;

static enterpriseAdminAnalyticsV2BaseUrl = `${configuration.DATA_API_BASE_URL}/enterprise/api/v1/admin/analytics/`;

static getEnterpriseUUID(enterpriseId) {
const { enableDemoData } = store.getState().portalConfiguration;
return enableDemoData ? configuration.DEMO_ENTEPRISE_UUID : enterpriseId;
Expand Down Expand Up @@ -142,6 +144,11 @@ class EnterpriseDataApiService {
const url = `${EnterpriseDataApiService.enterpriseAdminBaseUrl}insights/${enterpriseUUID}`;
return EnterpriseDataApiService.apiClient().get(url);
}

static fetchPlotlyChartsCSV(enterpriseId, chartUrl, options) {
const url = `${EnterpriseDataApiService.enterpriseAdminAnalyticsV2BaseUrl}${enterpriseId}/${chartUrl}/stats?${new URLSearchParams(options).toString()}`;
return EnterpriseDataApiService.apiClient().get(url);

Check warning on line 150 in src/data/services/EnterpriseDataApiService.js

View check run for this annotation

Codecov / codecov/patch

src/data/services/EnterpriseDataApiService.js#L148-L150

Added lines #L148 - L150 were not covered by tests
}
}

export default EnterpriseDataApiService;

0 comments on commit 404b52f

Please sign in to comment.