Skip to content

Commit 5612078

Browse files
committed
feat: add drag and drop output
Closes #21
1 parent b979bd8 commit 5612078

File tree

6 files changed

+70
-17
lines changed

6 files changed

+70
-17
lines changed

.vscode/settings.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111
"cSpell.words": [
1212
"agrc",
1313
"apos",
14+
"draganddrop",
1415
"Dropzone",
1516
"fulladd",
17+
"heroicons",
1618
"loglevel",
1719
"noreferrer",
1820
"relocator",

src/assets/draganddrop.png

4.8 KB
Loading

src/pages/Geocoding.jsx

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,32 @@
11
import React, { useState, useEffect, useRef } from 'react';
22
import { Link } from 'react-router-dom';
33
import humanizeDuration from 'humanize-duration';
4+
import { DocumentTextIcon } from '@heroicons/react/outline';
45
import { useGeocodeContext } from '../components/GeocodeContext.js';
56

67
const percentFormatter = new Intl.NumberFormat('en-US', { style: 'percent' });
78

89
export default function Geocoding() {
9-
const [status, setStatus] = useState({
10+
const [stats, setStats] = useState({
1011
rowsProcessed: 0,
1112
totalRows: 0,
1213
activeMatchRate: 0,
1314
averageScore: 0,
15+
status: 'idle',
1416
});
1517
const startTime = useRef(new Date());
1618
const abortController = useRef(new AbortController());
1719
const geocodeContext = useGeocodeContext()[0];
20+
const draggable = useRef(null);
21+
22+
const onDragStart = (event) => {
23+
event.preventDefault();
24+
window.ugrc.startDrag('ugrc_geocode_results.csv');
25+
};
1826

1927
useEffect(() => {
2028
window.ugrc.onGeocodingUpdate((_, data) => {
21-
setStatus(data);
29+
setStats(data);
2230
});
2331

2432
window.ugrc.geocode({
@@ -29,10 +37,10 @@ export default function Geocoding() {
2937
});
3038
}, [geocodeContext]);
3139

32-
const progress = status.rowsProcessed / status.totalRows || 0;
40+
const progress = stats.rowsProcessed / stats.totalRows || 0;
3341
const elapsedTime = new Date().getTime() - startTime.current.getTime();
34-
const timePerRow = elapsedTime / status.rowsProcessed;
35-
const estimatedTimeRemaining = timePerRow * (status.totalRows - status.rowsProcessed);
42+
const timePerRow = elapsedTime / stats.rowsProcessed;
43+
const estimatedTimeRemaining = timePerRow * (stats.totalRows - stats.rowsProcessed);
3644

3745
const cancel = () => {
3846
window.ugrc.cancelGeocode();
@@ -51,21 +59,21 @@ export default function Geocoding() {
5159
<dl>
5260
<div className="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
5361
<dt className="font-medium text-gray-500">Rows processed</dt>
54-
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{status.rowsProcessed}</dd>
62+
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{stats.rowsProcessed}</dd>
5563
</div>
5664
<div className="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
5765
<dt className="font-medium text-gray-500">Total Rows</dt>
58-
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{status.totalRows}</dd>
66+
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{stats.totalRows}</dd>
5967
</div>
6068
<div className="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
6169
<dt className="font-medium text-gray-500">Active match rate</dt>
6270
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">
63-
{percentFormatter.format(status.activeMatchRate)}
71+
{percentFormatter.format(stats.activeMatchRate)}
6472
</dd>
6573
</div>
6674
<div className="px-4 py-5 bg-white sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
6775
<dt className="font-medium text-gray-500">Average match score</dt>
68-
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{status.averageScore}</dd>
76+
<dd className="mt-1 text-gray-900 sm:mt-0 sm:col-span-2">{stats.averageScore}</dd>
6977
</div>
7078
<div className="px-4 py-5 bg-gray-50 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
7179
<dt className="font-medium text-gray-500">Time elapsed</dt>
@@ -80,14 +88,28 @@ export default function Geocoding() {
8088
</dd>
8189
</div>
8290
</dl>
91+
{stats.status === 'complete' && (
92+
<div
93+
className="p-12 mx-auto text-center bg-gray-100 border rounded-lg shadow cursor-grab"
94+
ref={draggable}
95+
draggable={true}
96+
onDragStart={onDragStart}
97+
>
98+
<p>Drag and drop this file to save the results.</p>
99+
<DocumentTextIcon className="w-32 mx-auto" />
100+
<span className="mx-auto font-mono text-sm">ugrc_geocode_results.csv</span>
101+
</div>
102+
)}
83103
</section>
84-
<button
85-
type="button"
86-
onClick={cancel}
87-
disabled={status.rowsProcessed > 0 && status.totalRows === status.rowsProcessed}
88-
>
89-
Cancel
90-
</button>
104+
{stats.status === 'running' ? (
105+
<button
106+
type="button"
107+
onClick={cancel}
108+
disabled={stats.rowsProcessed > 0 && stats.totalRows === stats.rowsProcessed}
109+
>
110+
Cancel
111+
</button>
112+
) : null}
91113
</article>
92114
);
93115
}

src/services/csv.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,12 @@ export const cancelGeocode = () => {
6868
cancelled = true;
6969
};
7070

71+
const output = 'ugrc_geocode_results.csv';
7172
export const geocode = async (event, { filePath, fields, apiKey }) => {
7273
cancelled = false;
7374
const parser = fs.createReadStream(filePath).pipe(parse({ columns: true, skipEmptyLines: true }));
7475
const columns = await getFields(filePath);
75-
const writer = fs.createWriteStream(path.join(app.getPath('userData'), 'output.csv'));
76+
const writer = fs.createWriteStream(path.join(app.getPath('userData'), output));
7677
const stringifier = stringify({ columns: [...columns, 'x', 'y', 'score', 'match_address'], header: true });
7778
stringifier.pipe(writer);
7879

@@ -84,8 +85,17 @@ export const geocode = async (event, { filePath, fields, apiKey }) => {
8485

8586
for await (const record of parser) {
8687
if (cancelled) {
88+
event.reply('onGeocodingUpdate', {
89+
totalRows,
90+
rowsProcessed,
91+
averageScore: Math.round(totalScore / (rowsProcessed - failures)),
92+
activeMatchRate: (rowsProcessed - failures) / rowsProcessed,
93+
status: 'cancelled',
94+
});
95+
8796
return;
8897
}
98+
8999
const newRecord = { ...record, x: null, y: null, score: 0, match_address: null };
90100

91101
const street = cleanseStreet(record[fields.street]);
@@ -141,12 +151,21 @@ export const geocode = async (event, { filePath, fields, apiKey }) => {
141151
rowsProcessed,
142152
averageScore: Math.round(totalScore / (rowsProcessed - failures)),
143153
activeMatchRate: (rowsProcessed - failures) / rowsProcessed,
154+
status: 'running',
144155
});
145156

146157
await coolYourJets();
147158
}
148159

149160
stringifier.end();
161+
162+
event.reply('onGeocodingUpdate', {
163+
totalRows,
164+
rowsProcessed,
165+
averageScore: Math.round(totalScore / (rowsProcessed - failures)),
166+
activeMatchRate: (rowsProcessed - failures) / rowsProcessed,
167+
status: 'complete',
168+
});
150169
};
151170

152171
ipcMain.handle('getFieldsFromFile', (_, content) => {
@@ -161,3 +180,9 @@ ipcMain.on('geocode', (event, content) => {
161180
ipcMain.on('cancelGeocode', () => {
162181
return cancelGeocode();
163182
});
183+
ipcMain.on('ondragstart', (event) => {
184+
event.sender.startDrag({
185+
file: path.join(app.getPath('userData'), output),
186+
icon: path.join(process.cwd(), 'src', 'assets', 'draganddrop.png'),
187+
});
188+
});

src/services/preload.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ contextBridge.exposeInMainWorld('ugrc', {
88
onGeocodingUpdate: (event, arg) => ipcRenderer.on('onGeocodingUpdate', event, arg),
99
geocode: (content) => ipcRenderer.send('geocode', content),
1010
cancelGeocode: (content) => ipcRenderer.send('cancelGeocode', content),
11+
startDrag: (content) => ipcRenderer.send('ondragstart', content),
1112
});

tailwind.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ module.exports = {
44
darkMode: false, // or 'media' or 'class'
55
theme: {
66
extend: {},
7+
cursor: {
8+
grab: 'grab',
9+
},
710
},
811
variants: {
912
extend: {},

0 commit comments

Comments
 (0)