Skip to content

Commit 3de5b7a

Browse files
committed
Create UI and API for exporting to CSV
1 parent 9456a3c commit 3de5b7a

File tree

2 files changed

+43
-3
lines changed

2 files changed

+43
-3
lines changed

web-ui/src/api/skillcategory.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { resolve } from "./api.js";
22

33
const skillCategoryUrl = "/services/skills/categories";
44
const skillCategorySkillUrl = "/services/skills/category-skills";
5+
const skillRecordsUrl = "/services/skills/records";
56

67
export const createSkillCategory = async (skillCategory, cookie) => {
78
return resolve({
@@ -82,4 +83,12 @@ export const deleteSkillCategorySkill = async (categoryId, skillId, cookie) => {
8283
},
8384
headers: { "X-CSRF-Header": cookie }
8485
});
86+
}
87+
88+
export const getSkillsCsv = async (cookie) => {
89+
return resolve({
90+
url: `${skillRecordsUrl}/csv`,
91+
responseType: "blob",
92+
headers: { "X-CSRF-Header": cookie, "Accept": "text/csv" }
93+
});
8594
}

web-ui/src/pages/SkillCategoriesPage.jsx

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@ import { styled } from '@mui/material/styles';
33

44
import { AppContext } from "../context/AppContext";
55

6+
import fileDownload from 'js-file-download';
7+
68
import {
79
Button,
810
DialogActions,
911
DialogContent,
1012
DialogContentText,
11-
DialogTitle,
12-
TextField,
13+
DialogTitle, IconButton,
14+
TextField, Tooltip,
1315
Typography
1416
} from "@mui/material";
1517
import SkillCategoryCard from "../components/skill-category-card/SkillCategoryCard";
@@ -19,14 +21,15 @@ import {selectCsrfToken, selectOrderedSkills} from "../context/selectors";
1921
import {
2022
createSkillCategory,
2123
deleteSkillCategory,
22-
getSkillCategories
24+
getSkillCategories, getSkillsCsv
2325
} from "../api/skillcategory";
2426
import SkillCategoryNewDialog from "../components/skill-category-new-dialog/SkillCategoryNewDialog";
2527
import {UPDATE_TOAST} from "../context/actions";
2628
import Dialog from "@mui/material/Dialog";
2729
import InputAdornment from "@mui/material/InputAdornment";
2830
import {Search} from "@mui/icons-material";
2931
import Autocomplete from "@mui/material/Autocomplete";
32+
import DownloadIcon from "@mui/icons-material/FileDownload";
3033

3134
const PREFIX = 'SkillCategoriesPage';
3235
const classes = {
@@ -110,6 +113,29 @@ const SkillCategoriesPage = () => {
110113
}
111114
}
112115

116+
const downloadSkills = useCallback(async () => {
117+
let res = await getSkillsCsv(csrf);
118+
if (!res.error && res.payload.data) {
119+
fileDownload(res.payload.data, "skill_records.csv");
120+
dispatch({
121+
type: UPDATE_TOAST,
122+
payload: {
123+
severity: "success",
124+
toast: "Skills successfully exported"
125+
}
126+
});
127+
} else {
128+
dispatch({
129+
type: UPDATE_TOAST,
130+
payload: {
131+
severity: "error",
132+
toast: "Failed to export skills"
133+
}
134+
});
135+
}
136+
137+
}, [csrf, dispatch]);
138+
113139
const getFilteredCategories = useCallback(() => {
114140
if (skillCategories) {
115141
return skillCategories.filter(category => {
@@ -136,6 +162,11 @@ const SkillCategoriesPage = () => {
136162
<div className="skill-categories-header">
137163
<Typography variant="h4">Skill Categories</Typography>
138164
<div className="skill-categories-actions">
165+
<Tooltip title="Download Skills" arrow>
166+
<IconButton onClick={downloadSkills}>
167+
<DownloadIcon/>
168+
</IconButton>
169+
</Tooltip>
139170
<TextField
140171
style={{ minWidth: "200px" }}
141172
label="Search"

0 commit comments

Comments
 (0)