Avinashnalla7 commited on
Commit
0981ffd
·
verified ·
1 Parent(s): 884f006

Update src/App.jsx

Browse files
Files changed (1) hide show
  1. src/App.jsx +86 -9
src/App.jsx CHANGED
@@ -158,14 +158,14 @@ function isTableField(field) {
158
  const API_BASE = import.meta.env.VITE_API_BASE || "http://localhost:8000";
159
 
160
  export default function App() {
161
- // PDF comes from pdf_id in URL
162
  const [pdfId, setPdfId] = useState(null);
163
  const [pdfUrl, setPdfUrl] = useState(null);
164
  const [pdfName, setPdfName] = useState(null);
165
 
166
- // NEW: template id comes from URL OR manual input
167
  const [templateId, setTemplateId] = useState("");
168
- // NEW: template metadata so the exported config matches the registry template format
169
  const [templateName, setTemplateName] = useState("");
170
  const [templateVersion, setTemplateVersion] = useState(1);
171
  const [matchKeywordsAny, setMatchKeywordsAny] = useState("");
@@ -193,6 +193,9 @@ export default function App() {
193
  const dragStartRef = useRef(null);
194
  const overlayRef = useRef(null);
195
 
 
 
 
196
  const [showPreview, setShowPreview] = useState(true);
197
 
198
  const [sendStatus, setSendStatus] = useState({ state: "idle", msg: "" }); // idle|sending|ok|err
@@ -228,14 +231,22 @@ export default function App() {
228
 
229
  // Spacebar handling for pan
230
  useEffect(() => {
 
 
 
 
 
 
231
  function onKeyDown(e) {
232
  if (e.code === "Space") {
 
233
  e.preventDefault();
234
  setSpaceDown(true);
235
  }
236
  }
237
  function onKeyUp(e) {
238
  if (e.code === "Space") {
 
239
  e.preventDefault();
240
  setSpaceDown(false);
241
  setIsPanning(false);
@@ -254,15 +265,12 @@ export default function App() {
254
  useEffect(() => {
255
  const sp = new URLSearchParams(window.location.search);
256
 
257
- console.log("URL", window.location.href);
258
- console.log("query", Object.fromEntries(sp.entries()));
259
  const id = sp.get("pdf_id") || sp.get("id") || sp.get("pdfId") || sp.get("pdf");
260
  setPdfId(id || null);
261
 
262
  const tid = sp.get("template_id");
263
  setTemplateId((tid || "").trim());
264
 
265
- // Optional metadata via URL
266
  const tname = sp.get("template_name");
267
  if (tname) setTemplateName(tname.trim());
268
 
@@ -305,6 +313,53 @@ export default function App() {
305
  };
306
  }, []);
307
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  const selectedField = useMemo(
309
  () => FIELDS.find((f) => f.fieldId === selectedFieldId),
310
  [selectedFieldId]
@@ -633,7 +688,7 @@ export default function App() {
633
 
634
  async function saveConfig() {
635
  if (!pdfId) {
636
- setSendStatus({ state: "err", msg: "Missing pdf_id in URL." });
637
  return;
638
  }
639
  const tid = (templateId || "").trim();
@@ -709,11 +764,33 @@ export default function App() {
709
  </div>
710
  {!pdfId && (
711
  <div style={{ marginTop: 10, fontSize: 12, color: "#ffb4b4" }}>
712
- Missing <b>pdf_id</b>. Open this page using the pipeline link from the email.
713
  </div>
714
  )}
715
  </div>
716
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
717
  {/* Template ID */}
718
  <div style={{ marginBottom: 14 }}>
719
  <div style={UI.label}>Template ID (required)</div>
@@ -1049,7 +1126,7 @@ export default function App() {
1049
  <div style={{ color: "#999", lineHeight: 1.4 }}>
1050
  No PDF loaded.
1051
  <br />
1052
- Open using pipeline link:
1053
  <br />
1054
  <code style={{ color: "#ddd" }}>...?pdf_id=xxxx&template_id=T1_...</code>
1055
  </div>
 
158
  const API_BASE = import.meta.env.VITE_API_BASE || "http://localhost:8000";
159
 
160
  export default function App() {
161
+ // PDF comes from pdf_id in URL OR a local upload
162
  const [pdfId, setPdfId] = useState(null);
163
  const [pdfUrl, setPdfUrl] = useState(null);
164
  const [pdfName, setPdfName] = useState(null);
165
 
166
+ // template id comes from URL OR manual input
167
  const [templateId, setTemplateId] = useState("");
168
+ // template metadata so the exported config matches the registry template format
169
  const [templateName, setTemplateName] = useState("");
170
  const [templateVersion, setTemplateVersion] = useState(1);
171
  const [matchKeywordsAny, setMatchKeywordsAny] = useState("");
 
193
  const dragStartRef = useRef(null);
194
  const overlayRef = useRef(null);
195
 
196
+ const fileInputRef = useRef(null);
197
+ const localUrlRef = useRef(null);
198
+
199
  const [showPreview, setShowPreview] = useState(true);
200
 
201
  const [sendStatus, setSendStatus] = useState({ state: "idle", msg: "" }); // idle|sending|ok|err
 
231
 
232
  // Spacebar handling for pan
233
  useEffect(() => {
234
+ // Don't hijack the spacebar while the user is typing in a field.
235
+ function isTypingTarget(e) {
236
+ const t = e.target;
237
+ const tag = t && t.tagName ? t.tagName.toLowerCase() : "";
238
+ return tag === "input" || tag === "textarea" || tag === "select" || (t && t.isContentEditable);
239
+ }
240
  function onKeyDown(e) {
241
  if (e.code === "Space") {
242
+ if (isTypingTarget(e)) return; // allow typing spaces in inputs
243
  e.preventDefault();
244
  setSpaceDown(true);
245
  }
246
  }
247
  function onKeyUp(e) {
248
  if (e.code === "Space") {
249
+ if (isTypingTarget(e)) return;
250
  e.preventDefault();
251
  setSpaceDown(false);
252
  setIsPanning(false);
 
265
  useEffect(() => {
266
  const sp = new URLSearchParams(window.location.search);
267
 
 
 
268
  const id = sp.get("pdf_id") || sp.get("id") || sp.get("pdfId") || sp.get("pdf");
269
  setPdfId(id || null);
270
 
271
  const tid = sp.get("template_id");
272
  setTemplateId((tid || "").trim());
273
 
 
274
  const tname = sp.get("template_name");
275
  if (tname) setTemplateName(tname.trim());
276
 
 
313
  };
314
  }, []);
315
 
316
+ // ---- Load a local PDF directly (no email link / no pdf_id needed) ----
317
+ async function onPickLocalPdf(e) {
318
+ const file = e.target.files && e.target.files[0];
319
+ if (!file) return;
320
+
321
+ // revoke previous local URL
322
+ if (localUrlRef.current) {
323
+ try { URL.revokeObjectURL(localUrlRef.current); } catch (_) {}
324
+ localUrlRef.current = null;
325
+ }
326
+
327
+ const objectUrl = URL.createObjectURL(file);
328
+ localUrlRef.current = objectUrl;
329
+
330
+ // show it + reset view/measurements
331
+ setPdfUrl(objectUrl);
332
+ setPdfName(file.name);
333
+ setPageSize({ w: 0, h: 0 });
334
+ setScale(1);
335
+ setPan({ x: 0, y: 0 });
336
+
337
+ // give it an id so Save Config / form_id work
338
+ const localId = `local_${Date.now()}`;
339
+ setPdfId(localId);
340
+
341
+ setSendStatus({ state: "ok", msg: `Loaded ${file.name}. (Download Template JSON works offline.)` });
342
+
343
+ // best-effort: also upload to the API so "Save Config" can attach the PDF server-side.
344
+ try {
345
+ const fd = new FormData();
346
+ fd.append("file", file, file.name);
347
+ fd.append("pdf_name", file.name);
348
+ const resp = await fetch(`${API_BASE}/api/pdf/${encodeURIComponent(localId)}`, {
349
+ method: "POST",
350
+ body: fd,
351
+ });
352
+ if (resp.ok) {
353
+ setSendStatus({ state: "ok", msg: `Loaded ${file.name} and uploaded to API as ${localId}.` });
354
+ }
355
+ } catch (_) {
356
+ // offline / CORS — local preview + Download still work fine
357
+ }
358
+
359
+ // allow re-selecting the same file later
360
+ if (fileInputRef.current) fileInputRef.current.value = "";
361
+ }
362
+
363
  const selectedField = useMemo(
364
  () => FIELDS.find((f) => f.fieldId === selectedFieldId),
365
  [selectedFieldId]
 
688
 
689
  async function saveConfig() {
690
  if (!pdfId) {
691
+ setSendStatus({ state: "err", msg: "Missing pdf_id. Upload a PDF or open via the pipeline link." });
692
  return;
693
  }
694
  const tid = (templateId || "").trim();
 
764
  </div>
765
  {!pdfId && (
766
  <div style={{ marginTop: 10, fontSize: 12, color: "#ffb4b4" }}>
767
+ No PDF yet. Upload one below, or open this page using the pipeline link from the email.
768
  </div>
769
  )}
770
  </div>
771
 
772
+ {/* Upload a local PDF directly */}
773
+ <div style={{ marginBottom: 14 }}>
774
+ <div style={UI.label}>Upload PDF (no link needed)</div>
775
+ <input
776
+ ref={fileInputRef}
777
+ type="file"
778
+ accept="application/pdf,.pdf"
779
+ onChange={onPickLocalPdf}
780
+ style={{ display: "none" }}
781
+ />
782
+ <button
783
+ type="button"
784
+ onClick={() => fileInputRef.current && fileInputRef.current.click()}
785
+ style={{ ...UI.btnBase, ...UI.blue }}
786
+ >
787
+ Upload PDF
788
+ </button>
789
+ <div style={{ fontSize: 12, color: UI.subtle, marginTop: 6 }}>
790
+ Loads a PDF from your computer to train on. No email link required.
791
+ </div>
792
+ </div>
793
+
794
  {/* Template ID */}
795
  <div style={{ marginBottom: 14 }}>
796
  <div style={UI.label}>Template ID (required)</div>
 
1126
  <div style={{ color: "#999", lineHeight: 1.4 }}>
1127
  No PDF loaded.
1128
  <br />
1129
+ Click <b>Upload PDF</b> on the left, or open using a pipeline link:
1130
  <br />
1131
  <code style={{ color: "#ddd" }}>...?pdf_id=xxxx&template_id=T1_...</code>
1132
  </div>