Skip to content

Commit 1aeddf6

Browse files
authored
Able to download the template (#302)
* Able to download the template * Order dataset by is_favorite at first list
1 parent 226550c commit 1aeddf6

File tree

6 files changed

+129
-31
lines changed

6 files changed

+129
-31
lines changed

django_project/frontend/src/app/form.scss

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,23 @@
181181
}
182182
}
183183
}
184+
185+
&.ReferenceLayerInputSelectorWrapper {
186+
.InputControl {
187+
display: flex !important;
188+
flex-direction: row !important;
189+
190+
.MuiTextField-root {
191+
flex-grow: 1;
192+
}
193+
}
194+
195+
.MuiCircularProgress-root {
196+
height: unset !important;
197+
width: unset !important;
198+
margin-right: 0.5rem;
199+
}
200+
}
184201
}
185202

186203
.form-error {

django_project/frontend/src/pages/Admin/Components/Input/ReferenceLayerInput.jsx

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,17 @@ import React, {
2121
useState
2222
} from 'react';
2323
import Grid from '@mui/material/Grid';
24-
import { FormControlLabel, Radio, RadioGroup } from "@mui/material";
24+
import { Button, FormControlLabel, Radio, RadioGroup } from "@mui/material";
2525

2626
import { SelectWithList } from "../../../../components/Input/SelectWithList";
2727
import { GeorepoViewInputSelector } from "../../ModalSelector/InputSelector";
28-
import { axiosGet, GeorepoUrls } from "../../../../utils/georepo";
28+
import {
29+
axiosGet,
30+
fetchFeatureList,
31+
GeorepoUrls
32+
} from "../../../../utils/georepo";
33+
import CircularProgress from "@mui/material/CircularProgress";
34+
import { multiJsonToMultipleSheetsXlsx } from "../../../../utils/main";
2935

3036
const defaultIdType = 'ucode'
3137
const ANY_LEVEL = 'Any Level (Data Driven)'
@@ -53,6 +59,7 @@ export const ReferenceLayerInput = forwardRef(
5359
}));
5460

5561
const [references, setReferences] = useState([])
62+
const [templateDownloading, setTemplateDownloading] = useState(false)
5663

5764
let referenceLayer = references?.find(row => {
5865
return row.identifier === data?.reference_layer
@@ -109,6 +116,39 @@ export const ReferenceLayerInput = forwardRef(
109116
}, [references]
110117
)
111118

119+
// Create download data
120+
useEffect(
121+
() => {
122+
if (templateDownloading) {
123+
(
124+
async () => {
125+
const templateData = {}
126+
let levels = referenceLayer.dataset_levels;
127+
if (data.admin_level_type === BY_VALUE) {
128+
levels = levels.filter(level => parseInt(data.admin_level_value) === level.level)
129+
}
130+
for (const level of levels) {
131+
let geometryData = await fetchFeatureList(level.url)
132+
templateData[level.name] = geometryData.map(data => {
133+
return Object.assign({}, {
134+
GeographyCode: data.ucode,
135+
GeographyName: data.name,
136+
Value: "",
137+
ExtraName1: "",
138+
ExtraName2: ""
139+
}, data.ext_codes)
140+
})
141+
}
142+
multiJsonToMultipleSheetsXlsx(
143+
templateData, 'template.xlsx'
144+
)
145+
setTemplateDownloading(false);
146+
}
147+
)()
148+
}
149+
}, [templateDownloading]
150+
)
151+
112152
/**
113153
* Return default level
114154
* @param {Array} levels
@@ -180,7 +220,7 @@ export const ReferenceLayerInput = forwardRef(
180220
return (
181221
<Grid container spacing={2}>
182222
<Grid item xs={6}>
183-
<div className="BasicFormSection">
223+
<div className="BasicFormSection ReferenceLayerInputSelectorWrapper">
184224
<label className="form-label required" htmlFor="group">
185225
Reference Layer
186226
</label>
@@ -199,6 +239,20 @@ export const ReferenceLayerInput = forwardRef(
199239
}}
200240
isMultiple={false}
201241
showSelected={false}
242+
otherContent={
243+
<Button
244+
variant="primary"
245+
disabled={!referenceLayer || templateDownloading}
246+
onClick={() => {
247+
setTemplateDownloading(true)
248+
}}
249+
>
250+
{
251+
templateDownloading ? <>
252+
<CircularProgress/>Downloading</> : 'Template'
253+
}
254+
</Button>
255+
}
202256
/>
203257
</div>
204258
</Grid>

django_project/frontend/src/pages/Admin/ModalSelector/GeorepoView.jsx

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const columns = [
4141
* @param {Boolean} isMultiple Is data returned multiple object.
4242
* @param {Boolean} showSelected Is Showing selected data.
4343
* @param {array} filter List of id of data that will be used to filter data.
44+
* @param {React.Component} otherContent other content to be rendered.
4445
* */
4546
export default function GeorepoViewSelector(
4647
{
@@ -50,7 +51,8 @@ export default function GeorepoViewSelector(
5051
selectedDataChanged,
5152
isMultiple = true,
5253
showSelected = true,
53-
filter = false
54+
filter = false,
55+
otherContent = null
5456
}
5557
) {
5658

@@ -121,28 +123,31 @@ export default function GeorepoViewSelector(
121123
usedInputData = usedInputData.filter(data => newFilter.includes(data.identifier))
122124
}
123125

124-
return <ModalSelector
125-
title={"View(s)"}
126-
inputData={usedInputData}
127-
columns={columns}
128-
open={open}
129-
setOpen={setOpen}
130-
selectedData={selectedData}
131-
selectedDataChanged={selectedDataChanged}
132-
defaultSorting={[{ field: 'name', sort: 'asc' }]}
133-
isMultiple={isMultiple}
134-
showSelected={showSelected}
135-
beforeChildren={
136-
<FormControl className='InputControl'>
137-
<SelectWithList
138-
placeholder={references ? 'Select dataset' : 'Loading'}
139-
list={references}
140-
value={reference}
141-
onChange={evt => {
142-
setReference(evt.value)
143-
}}
144-
/>
145-
</FormControl>
146-
}
147-
/>
126+
return <>
127+
<ModalSelector
128+
title={"View(s)"}
129+
inputData={usedInputData}
130+
columns={columns}
131+
open={open}
132+
setOpen={setOpen}
133+
selectedData={selectedData}
134+
selectedDataChanged={selectedDataChanged}
135+
defaultSorting={[{ field: 'name', sort: 'asc' }]}
136+
isMultiple={isMultiple}
137+
showSelected={showSelected}
138+
beforeChildren={
139+
<FormControl className='InputControl'>
140+
<SelectWithList
141+
placeholder={references ? 'Select dataset' : 'Loading'}
142+
list={references}
143+
value={reference}
144+
onChange={evt => {
145+
setReference(evt.value)
146+
}}
147+
/>
148+
</FormControl>
149+
}
150+
/>
151+
{otherContent ? otherContent : null}
152+
</>
148153
}

django_project/frontend/src/pages/Admin/ModalSelector/InputSelector/index.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,9 +155,12 @@ export function ContextLayerInputSelector(
155155
* @param {function} setData When the value changed.
156156
* @param {Boolean} isMultiple Is data returned multiple object.
157157
* @param {Boolean} showSelected Is Showing selected data.
158+
* @param {React.Component} otherContent other content to be rendered.
158159
*/
159160
export function GeorepoViewInputSelector(
160-
{ data, setData, isMultiple, showSelected }
161+
{
162+
data, setData, isMultiple, showSelected, otherContent = null
163+
}
161164
) {
162165
return <ModalInputSelector
163166
placeholder={'Select view ' + (isMultiple ? '(s)' : '')}
@@ -167,6 +170,6 @@ export function GeorepoViewInputSelector(
167170
showSelected={showSelected}
168171
hideLabel={true}
169172
>
170-
<GeorepoViewSelector/>
173+
<GeorepoViewSelector otherContent={otherContent}/>
171174
</ModalInputSelector>
172175
}

django_project/frontend/src/utils/georepo.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export const fetchReferenceLayerList = async function () {
6363
data.map(row => {
6464
row.identifier = row.uuid
6565
})
66-
return data
66+
return [].concat(data.filter(row => row.is_favorite), data.filter(row => !row.is_favorite));
6767
}
6868

6969
/**

django_project/frontend/src/utils/main.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,25 @@ export function jsonToXlsx(data, filename, sheetName = "Sheet 1") {
254254
XLSX.writeFile(workbook, filename);
255255
}
256256

257+
/**
258+
* Multiple json to multiple sheet
259+
* @param {Array} data Array of object.
260+
* @param {string} filename Filename of json
261+
*/
262+
export function multiJsonToMultipleSheetsXlsx(data, filename) {
263+
const workbook = XLSX.utils.book_new();
264+
for (const [sheetName, sheetData] of Object.entries(data)) {
265+
const worksheet = XLSX.utils.json_to_sheet(sheetData);
266+
if (sheetData[0]) {
267+
worksheet["!cols"] = Object.keys(sheetData[0]).map(key => {
268+
return { wch: sheetData.reduce((w, r) => Math.max(w, r[key]?.length), 10) }
269+
});
270+
}
271+
XLSX.utils.book_append_sheet(workbook, worksheet, sheetName);
272+
}
273+
XLSX.writeFile(workbook, filename);
274+
}
275+
257276
/** Return now date in UTC */
258277
export function nowUTC(secondZero = false) {
259278
const date = new Date();

0 commit comments

Comments
 (0)