Skip to content

Commit ff7491e

Browse files
author
dushimsam
committed
feat(UI): Import CSV-license file PAGE
Signed-off-by: dushimsam <[email protected]>
1 parent cf11dae commit ff7491e

File tree

9 files changed

+238
-4
lines changed

9 files changed

+238
-4
lines changed

src/Routes.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ const DeleteUser = React.lazy(() => import("pages/Admin/Users/Delete"));
9595
const AddUser = React.lazy(() => import("pages/Admin/Users/Add"));
9696
const EditUser = React.lazy(() => import("pages/Admin/Users/Edit"));
9797
const AddLicense = React.lazy(() => import("pages/Admin/License/Create"));
98+
const ImportLicense = React.lazy(() => import("pages/Admin/License/Import"));
9899
const SelectLicense = React.lazy(() =>
99100
import("pages/Admin/License/SelectLicense")
100101
);
@@ -302,6 +303,11 @@ const Routes = () => {
302303
path={routes.admin.license.selectLicense}
303304
component={SelectLicense}
304305
/>
306+
<AdminLayout
307+
exact
308+
path={routes.admin.license.import}
309+
component={ImportLicense}
310+
/>
305311
<AdminLayout
306312
exact
307313
path={routes.admin.users.delete}

src/api/licenses.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,3 +67,23 @@ export const createCandidateLicenseApi = ({
6767
},
6868
});
6969
};
70+
71+
export const importLicenseCsvApi = (fileInput, delimiter, enclosure) => {
72+
const url = endpoints.license.importCsv();
73+
const formdata = new FormData();
74+
75+
if (fileInput) {
76+
formdata.append("file_input", fileInput);
77+
formdata.append("delimiter", delimiter);
78+
formdata.append("enclosure", enclosure);
79+
}
80+
return sendRequest({
81+
url,
82+
method: "POST",
83+
isMultipart: true,
84+
headers: {
85+
Authorization: getToken(),
86+
},
87+
body: formdata,
88+
});
89+
};

src/api/licenses.test.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616
import sendRequest from "api/sendRequest";
1717
import endpoints from "constants/endpoints";
1818
import { getToken } from "shared/authHelper";
19-
import { createCandidateLicenseApi, getAllLicenseApi } from "api/licenses";
19+
import {
20+
createCandidateLicenseApi,
21+
getAllLicenseApi,
22+
importLicenseCsvApi,
23+
} from "api/licenses";
2024

2125
jest.mock("api/sendRequest");
2226

@@ -54,6 +58,7 @@ describe("licenses", () => {
5458
const licenseUrl = "licenseUrl";
5559
const mergeRequest = "mergeRequest";
5660
const url = endpoints.admin.license.createCandidateLicense();
61+
sendRequest.mockImplementation(() => true);
5762

5863
expect(
5964
createCandidateLicenseApi({
@@ -85,3 +90,32 @@ describe("licenses", () => {
8590
);
8691
});
8792
});
93+
94+
test("importLicenseCsvApi", () => {
95+
const url = endpoints.license.importCsv();
96+
const expectedBody = new FormData();
97+
const delimiter = "shortName";
98+
const enclosure = "fullName";
99+
const fileInput = "fileInput";
100+
101+
expectedBody.append("file_input", fileInput);
102+
expectedBody.append("delimiter", delimiter);
103+
expectedBody.append("enclosure", enclosure);
104+
105+
sendRequest.mockImplementation(() => true);
106+
107+
expect(importLicenseCsvApi(fileInput, delimiter, enclosure)).toBe(
108+
sendRequest({})
109+
);
110+
expect(sendRequest).toHaveBeenCalledWith(
111+
expect.objectContaining({
112+
url,
113+
method: "POST",
114+
isMultipart: true,
115+
headers: {
116+
Authorization: getToken(),
117+
},
118+
body: expectedBody,
119+
})
120+
);
121+
});

src/components/Header/index.jsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,12 @@ const Header = () => {
312312
>
313313
CSV Export
314314
</NavDropdown.Item>
315+
<NavDropdown.Item
316+
as={Link}
317+
to={routes.admin.license.import}
318+
>
319+
CSV Import
320+
</NavDropdown.Item>
315321
<NavDropdown.Item
316322
as={Link}
317323
to={routes.admin.license.selectLicense}

src/constants/constants.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ export const initialMessageSearch = {
104104
text: "",
105105
};
106106

107+
// constants used in Import License component
108+
export const initialImportCsvLicense = {
109+
fileInput: null,
110+
delimiter: ",",
111+
enclosure: '"',
112+
};
113+
107114
// constants used in Upload/file component
108115
export const initialStateFile = {
109116
folderId: 1,

src/constants/endpoints.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,8 @@ const endpoints = {
8585
license: {
8686
get: () => `${apiUrl}/license`,
8787
createCandidateLicense: () => `${apiUrl}/license`,
88-
},
88+
importCsv: () => `${apiUrl}/license/import-csv`,
89+
},
8990
info: {
9091
info: () => `${apiUrl}/info`,
9192
health: () => `${apiUrl}/health`,

src/constants/routes.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ const routes = {
7777
create: "/admin/license/create",
7878
selectLicense: "/admin/selectLicense",
7979
licenseCSV: "/licenseCSV/fossology-license-export.csv",
80+
import: "/admin/license/import",
8081
},
8182
mantainance: "/admin/mantainance",
8283
},
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
Copyright (C) 2022 Samuel Dushimimana ([email protected])
3+
4+
SPDX-License-Identifier: GPL-2.0
5+
6+
This program is free software; you can redistribute it and/or
7+
modify it under the terms of the GNU General Public License
8+
version 2 as published by the Free Software Foundation.
9+
This program is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License along
15+
with this program; if not, write to the Free Software Foundation, Inc.,
16+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17+
*/
18+
19+
import React, { useState } from "react";
20+
21+
// Title
22+
import Title from "components/Title";
23+
import { initialImportCsvLicense, initialMessage } from "constants/constants";
24+
import { Alert, Button, InputContainer, Spinner } from "components/Widgets";
25+
import { importLicenseCsv } from "services/licenses";
26+
27+
const ImportLicense = () => {
28+
// Data required for importing the csv file
29+
const [uploadFileData, setUploadFileData] = useState(initialImportCsvLicense);
30+
// State Variables for handling Error Boundaries
31+
const [loading, setLoading] = useState(false);
32+
const [showMessage, setShowMessage] = useState(false);
33+
const [message, setMessage] = useState(initialMessage);
34+
35+
const handleChange = (e) => {
36+
if (e.target.type === "fileInput") {
37+
setUploadFileData({
38+
...uploadFileData,
39+
[e.target.name]: e.target.files[0],
40+
});
41+
} else {
42+
setUploadFileData({
43+
...uploadFileData,
44+
[e.target.name]: e.target.value,
45+
});
46+
}
47+
};
48+
49+
const handleSubmit = async (e) => {
50+
e.preventDefault();
51+
try {
52+
setLoading(true);
53+
const { data } = await importLicenseCsv(uploadFileData);
54+
setMessage({
55+
type: "success",
56+
text: data.message,
57+
});
58+
setUploadFileData(initialImportCsvLicense);
59+
} catch (error) {
60+
setMessage({
61+
type: "danger",
62+
text: error.message,
63+
});
64+
} finally {
65+
setLoading(false);
66+
setShowMessage(true);
67+
}
68+
};
69+
return (
70+
<>
71+
<Title title="Admin Obligation CSV Import" />
72+
<div className="main-container my-3">
73+
<div className="row">
74+
<div className="col-lg-8 col-md-12 col-sm-12 col-12">
75+
{showMessage && (
76+
<Alert
77+
type={message.type}
78+
setShow={setShowMessage}
79+
message={message.text}
80+
/>
81+
)}
82+
<h1 className="font-size-main-heading">
83+
Admin Obligation CSV Import
84+
</h1>
85+
</div>
86+
<div className="col-lg-8 col-md-12 col-sm-12 col-12">
87+
<p>
88+
This option permits uploading a CSV file from your computer to
89+
Your FOSSology server has imposed a maximum upload file size of
90+
700Mbytes.
91+
</p>
92+
</div>
93+
<div className="col-lg-8 col-md-12 col-sm-12 col-12">
94+
<span>Select the CSV-file to upload:</span>
95+
<InputContainer
96+
type="file"
97+
name="fileInput"
98+
id="upload-file-input"
99+
onChange={(e) => handleChange(e)}
100+
/>
101+
</div>
102+
<div className="col-lg-8 col-md-12 col-sm-12 col-12">
103+
<div>
104+
<InputContainer
105+
type="text"
106+
name="name"
107+
id="delimiter"
108+
onChange={handleChange}
109+
value={uploadFileData.delimiter}
110+
>
111+
Delimiter:
112+
</InputContainer>
113+
</div>
114+
115+
<div>
116+
<InputContainer
117+
type="text"
118+
name="name"
119+
id="admin-group-add-name"
120+
onChange={handleChange}
121+
placeholder="Group name"
122+
value={uploadFileData.enclosure}
123+
>
124+
Enclosure:
125+
</InputContainer>
126+
</div>
127+
</div>
128+
<div className="col-lg-8 col-md-12 col-sm-12 col-12">
129+
<Button type="submit" onClick={handleSubmit} className="mt-4">
130+
{loading ? (
131+
<Spinner
132+
as="span"
133+
animation="border"
134+
size="sm"
135+
role="status"
136+
aria-hidden="true"
137+
/>
138+
) : (
139+
"Add"
140+
)}
141+
</Button>
142+
</div>
143+
</div>
144+
</div>
145+
</>
146+
);
147+
};
148+
149+
export default ImportLicense;

src/services/licenses.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright (C) 2021 Shruti Agarwal ([email protected]), Aman Dwivedi ([email protected])
2+
Copyright (C) 2021 Shruti Agarwal ([email protected]), Aman Dwivedi ([email protected]) , Samuel Dushimimana ([email protected])
33
44
SPDX-License-Identifier: GPL-2.0
55
@@ -16,7 +16,11 @@
1616
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
1717
*/
1818

19-
import { getAllLicenseApi, createCandidateLicenseApi } from "api/licenses";
19+
import {
20+
getAllLicenseApi,
21+
createCandidateLicenseApi,
22+
importLicenseCsvApi,
23+
} from "api/licenses";
2024

2125
// Fetching the licenses with their kind i.e (candidate, main, all)
2226
export const getAllLicense = (licenseData) => {
@@ -30,3 +34,9 @@ export const createCandidateLicense = (licenseData) => {
3034
return res;
3135
});
3236
};
37+
38+
export const importLicenseCsv = ({ fileInput, delimiter, enclosure }) => {
39+
return importLicenseCsvApi(fileInput, delimiter, enclosure).then((res) => {
40+
return res;
41+
});
42+
};

0 commit comments

Comments
 (0)