Skip to content

Commit 00b2493

Browse files
Add basic footer to loop grid
1 parent 581ee6c commit 00b2493

File tree

2 files changed

+172
-0
lines changed
  • packages/builder/src/components/ComponentOptions/components/Content/Loop/Grid

2 files changed

+172
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import React, { useState, createRef } from 'react'
2+
3+
import { ButtonDropdown, Button,
4+
DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'
5+
import { range } from 'lodash'
6+
7+
import Icon from '../../../../../Icon'
8+
//import FactorialModal from './components/FactorialModal'
9+
import { useArrayContext } from '../../../../../Form/array'
10+
11+
import Uploader from '../../../../../Uploader'
12+
import { saveAs } from 'file-saver'
13+
import { parse, unparse } from 'papaparse'
14+
15+
const exportGrid = (data, columns) => {
16+
const output = unparse({
17+
fields: columns.map(c => c.name),
18+
data
19+
})
20+
21+
return saveAs(
22+
new Blob(
23+
[ output ],
24+
{ type: 'text/csv;charset=utf-8' }
25+
),
26+
'loop.csv'
27+
)
28+
}
29+
30+
export default ({ columns, data }) => {
31+
const [dropdownOpen, setDropdownOpen] = useState(false)
32+
//const factorialModal = createRef()
33+
const { addRow, overwriteAll } = useArrayContext()
34+
35+
return (
36+
<tfoot>
37+
<tr>
38+
<td />
39+
<td colSpan={ columns.length }>
40+
{ /*
41+
<FactorialModal ref={ factorialModal } />
42+
*/ }
43+
<ButtonDropdown
44+
size="sm"
45+
className="w-100"
46+
isOpen={ dropdownOpen }
47+
toggle={ () => setDropdownOpen(!dropdownOpen) }
48+
>
49+
<Button
50+
block size="sm"
51+
outline color="muted"
52+
className="hover-target"
53+
onClick={ () => addRow() }
54+
onMouseUp={
55+
e => e.target.blur()
56+
}
57+
style={{
58+
paddingLeft: '32px', // 6px standard + 24px toggle width
59+
}}
60+
>
61+
<Icon icon="plus" />
62+
</Button>
63+
<DropdownToggle
64+
caret split size="sm"
65+
outline color="muted"
66+
className="hover-target"
67+
style={{
68+
width: '24px',
69+
}}
70+
/>
71+
<DropdownMenu right>
72+
{ /*
73+
<DropdownItem header>Generate</DropdownItem>
74+
<DropdownItem
75+
onClick={ () => factorialModal.current.show().then(result => {
76+
overwriteAll(result.rows, result.columns)
77+
}) }
78+
>
79+
Factorial design
80+
</DropdownItem>
81+
*/ }
82+
<DropdownItem divider />
83+
<DropdownItem header>Repeat</DropdownItem>
84+
<DropdownItem
85+
onClick={ () => {
86+
const n = window.prompt('How many times?')
87+
if (n) {
88+
overwriteAll(
89+
data.flatMap(r => range(n).map(() => r)),
90+
columns,
91+
)
92+
}
93+
} }
94+
>
95+
Each row
96+
</DropdownItem>
97+
<DropdownItem
98+
onClick={ () => {
99+
const n = window.prompt('How many times?')
100+
if (n) {
101+
overwriteAll(
102+
range(n).flatMap(() => data),
103+
columns,
104+
)
105+
}
106+
} }
107+
>
108+
Entire grid
109+
</DropdownItem>
110+
<DropdownItem divider />
111+
<DropdownItem header>CSV / TSV</DropdownItem>
112+
<Uploader
113+
accept="text/csv,text/tab-separated-values,.csv,.tsv"
114+
multiple={ false }
115+
onUpload={
116+
([[content]]) => {
117+
// TODO: Close the dropdown when the file selector
118+
// is shown. This needs some more work to make sure
119+
// that the uploader component isn't removed from the
120+
// page in between
121+
setDropdownOpen(false)
122+
123+
const parseResult = parse(
124+
content.trim(),
125+
{ header: true }
126+
)
127+
128+
if (
129+
// No detected issues
130+
parseResult.errors.length === 0 ||
131+
// Data is present, but no delimiter found
132+
(parseResult.data && parseResult.errors.length === 1 &&
133+
parseResult.errors[0].code === 'UndetectableDelimiter')
134+
) {
135+
overwriteAll(
136+
parseResult.data.map(r => Object.values(r)),
137+
Object.keys(parseResult.data[0])
138+
.map(c => ({ name: c, type: 'string' })),
139+
)
140+
} else {
141+
console.log(
142+
'CSV import found errors: ',
143+
parseResult.errors
144+
)
145+
alert(
146+
'Sorry, I couldn\'t parse that CSV file. ' +
147+
'There seems to be an error. ' +
148+
'Could you check it, please?'
149+
)
150+
}
151+
}
152+
}
153+
>
154+
<div className="dropdown-item">
155+
Import
156+
</div>
157+
</Uploader>
158+
<DropdownItem
159+
onClick={ () => exportGrid(data, columns) }
160+
>
161+
Export
162+
</DropdownItem>
163+
</DropdownMenu>
164+
</ButtonDropdown>
165+
</td>
166+
<td />
167+
</tr>
168+
</tfoot>
169+
)
170+
}

packages/builder/src/components/ComponentOptions/components/Content/Loop/Grid/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { FastField, useFormikContext } from 'formik'
44
import classnames from 'classnames'
55

66
import Header from './header'
7+
import Footer from './footer'
78
import { Table, DefaultRow } from '../../../../../Form/table'
89

910
import './style.css'
@@ -34,6 +35,7 @@ export default () => {
3435
row={ Row }
3536
columns={ columns }
3637
header={ Header }
38+
footer={ Footer }
3739
defaultItem={ Array(columns).fill('') }
3840
className={ classnames({
3941
'table': true,

0 commit comments

Comments
 (0)