juxscript 1.1.192 → 1.1.194
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/components/dataframe.d.ts.map +1 -1
- package/lib/components/dataframe.js +112 -34
- package/lib/components/dataframe.ts +126 -34
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"dataframe.d.ts","sourceRoot":"","sources":["dataframe.ts"],"names":[],"mappings":"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"}
|
|
@@ -360,8 +360,8 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
360
360
|
this._table.columns(columnDefs).rows(this._df.toRows());
|
|
361
361
|
}
|
|
362
362
|
const isMalformed = this._detectMalformedData(this._df);
|
|
363
|
-
if (isMalformed && this.
|
|
364
|
-
this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols (Data may
|
|
363
|
+
if (isMalformed && this._rawFileData) {
|
|
364
|
+
this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols (Data may need reformatting)`, 'warning');
|
|
365
365
|
requestAnimationFrame(() => {
|
|
366
366
|
const statusEl = document.getElementById(`${this._id}-status`);
|
|
367
367
|
if (statusEl) {
|
|
@@ -376,12 +376,13 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
376
376
|
}
|
|
377
377
|
else {
|
|
378
378
|
this._updateStatus(`${sourceName} — ${this._df.height} rows × ${this._df.width} cols`, 'success');
|
|
379
|
-
if
|
|
379
|
+
// Always show settings button if we have raw file data
|
|
380
|
+
if (this._rawFileData) {
|
|
380
381
|
requestAnimationFrame(() => {
|
|
381
382
|
const statusEl = document.getElementById(`${this._id}-status`);
|
|
382
383
|
if (statusEl) {
|
|
383
384
|
const settingsBtn = document.createElement('button');
|
|
384
|
-
settingsBtn.textContent = 'Settings';
|
|
385
|
+
settingsBtn.textContent = 'Import Settings';
|
|
385
386
|
settingsBtn.className = 'jux-button jux-button-sm jux-button-ghost';
|
|
386
387
|
settingsBtn.style.marginLeft = '0.5rem';
|
|
387
388
|
settingsBtn.addEventListener('click', () => this._showReshapeModal());
|
|
@@ -485,15 +486,12 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
485
486
|
max="50"
|
|
486
487
|
style="width: 100%;"
|
|
487
488
|
/>
|
|
488
|
-
<div class="jux-reshape-hint">
|
|
489
|
-
<strong>Detected issue:</strong> The current header row appears to contain metadata or empty values.
|
|
490
|
-
Row ${suggestedRow} looks like it contains the actual column headers.
|
|
491
|
-
Adjust the value above and check the preview below. The Row column shows the index for each row.
|
|
489
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint">
|
|
492
490
|
</div>
|
|
493
491
|
</div>
|
|
494
492
|
<div class="jux-reshape-preview-container">
|
|
495
493
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">
|
|
496
|
-
Preview
|
|
494
|
+
Preview
|
|
497
495
|
</div>
|
|
498
496
|
<div id="${this._id}-preview" class="jux-reshape-preview"></div>
|
|
499
497
|
</div>
|
|
@@ -526,7 +524,6 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
526
524
|
this._renderMultiSheet(sheets, this._rawFileData.file.name);
|
|
527
525
|
}
|
|
528
526
|
else {
|
|
529
|
-
this._showReshapeWarning = false;
|
|
530
527
|
this._setDataFrame(sheets[sheetNames[0]], this._rawFileData.file.name);
|
|
531
528
|
}
|
|
532
529
|
this._reshapeModal.closeModal();
|
|
@@ -542,29 +539,70 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
542
539
|
await new Promise(resolve => requestAnimationFrame(resolve));
|
|
543
540
|
const headerRowInput = document.getElementById(`${this._id}-header-row`);
|
|
544
541
|
const previewDiv = document.getElementById(`${this._id}-preview`);
|
|
542
|
+
const hintDiv = document.getElementById(`${this._id}-reshape-hint`);
|
|
543
|
+
const updateHint = (headerRow) => {
|
|
544
|
+
if (!hintDiv)
|
|
545
|
+
return;
|
|
546
|
+
hintDiv.innerHTML = headerRow > 0
|
|
547
|
+
? `Row <strong>${headerRow}</strong> will be used as column headers. ` +
|
|
548
|
+
`The <strong>${headerRow}</strong> row${headerRow > 1 ? 's' : ''} above will be skipped.`
|
|
549
|
+
: `Row <strong>0</strong> (first row) will be used as column headers.`;
|
|
550
|
+
};
|
|
545
551
|
const updatePreview = async () => {
|
|
546
552
|
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
553
|
+
updateHint(headerRow);
|
|
547
554
|
try {
|
|
548
|
-
|
|
555
|
+
// First, get raw data (headerRow=0) to show skipped rows
|
|
556
|
+
const rawSheets = await this._driver.streamFileMultiSheet(this._rawFileData.file, {
|
|
557
|
+
headerRow: 0,
|
|
558
|
+
maxSheetSize: headerRow + 15
|
|
559
|
+
});
|
|
560
|
+
const rawSheet = Object.values(rawSheets)[0];
|
|
561
|
+
// Then, get parsed data with the chosen header row
|
|
562
|
+
const parsedSheets = await this._driver.streamFileMultiSheet(this._rawFileData.file, {
|
|
549
563
|
headerRow,
|
|
550
|
-
maxSheetSize: headerRow +
|
|
564
|
+
maxSheetSize: headerRow + 15
|
|
551
565
|
});
|
|
552
|
-
const
|
|
553
|
-
if (!
|
|
566
|
+
const parsedSheet = Object.values(parsedSheets)[0];
|
|
567
|
+
if (!rawSheet && !parsedSheet) {
|
|
554
568
|
if (previewDiv)
|
|
555
569
|
previewDiv.textContent = 'No data found';
|
|
556
570
|
return;
|
|
557
571
|
}
|
|
558
|
-
const
|
|
559
|
-
const
|
|
560
|
-
const
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
const
|
|
564
|
-
|
|
565
|
-
|
|
572
|
+
const colWidth = 22;
|
|
573
|
+
const idxWidth = 6;
|
|
574
|
+
const lines = [];
|
|
575
|
+
// Show skipped rows (rows before the header)
|
|
576
|
+
if (rawSheet && headerRow > 0) {
|
|
577
|
+
const rawRows = rawSheet.toRows();
|
|
578
|
+
// Row 0 in raw parse is the raw header, rows after are data
|
|
579
|
+
// Show raw header as row 0
|
|
580
|
+
const rawCols = rawSheet.columns;
|
|
581
|
+
lines.push(`${'Idx'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`);
|
|
582
|
+
const skippedCount = Math.min(headerRow - 1, rawRows.length);
|
|
583
|
+
for (let i = 0; i < skippedCount; i++) {
|
|
584
|
+
const row = rawRows[i];
|
|
585
|
+
const rowIdx = String(i + 1).padEnd(idxWidth);
|
|
586
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
587
|
+
lines.push(`${rowIdx}${cols}`);
|
|
588
|
+
}
|
|
589
|
+
// Separator: everything above is skipped
|
|
590
|
+
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
591
|
+
}
|
|
592
|
+
// Show header row and data rows from parsed result
|
|
593
|
+
if (parsedSheet) {
|
|
594
|
+
const headerLine = `${'▶'.padEnd(idxWidth)}${parsedSheet.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`;
|
|
595
|
+
lines.push(headerLine);
|
|
596
|
+
lines.push('═'.repeat(Math.min(headerLine.length, 140)));
|
|
597
|
+
const dataRows = parsedSheet.toRows().slice(0, 8);
|
|
598
|
+
dataRows.forEach((row, i) => {
|
|
599
|
+
const rowIdx = String(headerRow + 1 + i).padEnd(idxWidth);
|
|
600
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
601
|
+
lines.push(`${rowIdx}${cols}`);
|
|
602
|
+
});
|
|
603
|
+
}
|
|
566
604
|
if (previewDiv) {
|
|
567
|
-
previewDiv.textContent =
|
|
605
|
+
previewDiv.textContent = lines.join('\n');
|
|
568
606
|
}
|
|
569
607
|
}
|
|
570
608
|
catch (err) {
|
|
@@ -605,7 +643,8 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
605
643
|
<label style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Skip Rows Before Header</label>
|
|
606
644
|
<input type="number" id="${this._id}-skip-rows" class="jux-input-element" value="0" min="0" max="50" style="width: 100%;" />
|
|
607
645
|
</div>
|
|
608
|
-
<div class="jux-reshape-
|
|
646
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint"></div>
|
|
647
|
+
<div class="jux-reshape-preview-container" style="margin-top: 1rem;">
|
|
609
648
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">Preview</div>
|
|
610
649
|
<div id="${this._id}-preview" class="jux-reshape-preview"></div>
|
|
611
650
|
</div>
|
|
@@ -640,7 +679,6 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
640
679
|
hasHeader: true
|
|
641
680
|
});
|
|
642
681
|
await this._driver.store(this._rawFileData.file.name, df, { source: this._rawFileData.file.name });
|
|
643
|
-
this._showReshapeWarning = false;
|
|
644
682
|
this._setDataFrame(df, this._rawFileData.file.name);
|
|
645
683
|
this._reshapeModal.closeModal();
|
|
646
684
|
}
|
|
@@ -657,6 +695,7 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
657
695
|
const headerRowInput = document.getElementById(`${this._id}-header-row`);
|
|
658
696
|
const skipRowsInput = document.getElementById(`${this._id}-skip-rows`);
|
|
659
697
|
const previewDiv = document.getElementById(`${this._id}-preview`);
|
|
698
|
+
const hintDiv = document.getElementById(`${this._id}-reshape-hint`);
|
|
660
699
|
if (this._rawFileData?.text) {
|
|
661
700
|
const detected = this._driver._detectDelimiter(this._rawFileData.text);
|
|
662
701
|
if (delimiterSelect)
|
|
@@ -665,30 +704,69 @@ export class DataFrameComponent extends BaseComponent {
|
|
|
665
704
|
if (headerRowInput)
|
|
666
705
|
headerRowInput.value = String(detectedHeaderRow);
|
|
667
706
|
}
|
|
707
|
+
const updateHint = () => {
|
|
708
|
+
if (!hintDiv)
|
|
709
|
+
return;
|
|
710
|
+
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
711
|
+
const skipRows = parseInt(skipRowsInput?.value) || 0;
|
|
712
|
+
const totalSkipped = headerRow + skipRows;
|
|
713
|
+
hintDiv.innerHTML = totalSkipped > 0
|
|
714
|
+
? `Row <strong>${headerRow + skipRows}</strong> will be used as column headers. ` +
|
|
715
|
+
`<strong>${totalSkipped}</strong> row${totalSkipped > 1 ? 's' : ''} above will be skipped.`
|
|
716
|
+
: `Row <strong>0</strong> (first row) will be used as column headers.`;
|
|
717
|
+
};
|
|
668
718
|
const updatePreview = () => {
|
|
669
719
|
if (!this._rawFileData?.text)
|
|
670
720
|
return;
|
|
671
721
|
const delim = delimiterSelect?.value || ',';
|
|
672
722
|
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
673
723
|
const skipRows = parseInt(skipRowsInput?.value) || 0;
|
|
724
|
+
updateHint();
|
|
674
725
|
try {
|
|
726
|
+
const colWidth = 22;
|
|
727
|
+
const idxWidth = 6;
|
|
728
|
+
const lines = [];
|
|
729
|
+
const totalOffset = headerRow + skipRows;
|
|
730
|
+
// Parse raw (no header offset) to show skipped rows
|
|
731
|
+
if (totalOffset > 0) {
|
|
732
|
+
const rawDf = this._driver.parseCSV(this._rawFileData.text, {
|
|
733
|
+
delimiter: delim,
|
|
734
|
+
headerRow: 0,
|
|
735
|
+
skipRows: 0,
|
|
736
|
+
hasHeader: true,
|
|
737
|
+
maxRows: totalOffset + 1
|
|
738
|
+
});
|
|
739
|
+
const rawCols = rawDf.columns;
|
|
740
|
+
lines.push(`${'Idx'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`);
|
|
741
|
+
const rawRows = rawDf.toRows();
|
|
742
|
+
const skippedCount = Math.min(totalOffset - 1, rawRows.length);
|
|
743
|
+
for (let i = 0; i < skippedCount; i++) {
|
|
744
|
+
const row = rawRows[i];
|
|
745
|
+
const rowIdx = String(i + 1).padEnd(idxWidth);
|
|
746
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
747
|
+
lines.push(`${rowIdx}${cols}`);
|
|
748
|
+
}
|
|
749
|
+
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
750
|
+
}
|
|
751
|
+
// Parse with actual settings for header + data rows
|
|
675
752
|
const df = this._driver.parseCSV(this._rawFileData.text, {
|
|
676
753
|
delimiter: delim,
|
|
677
754
|
headerRow,
|
|
678
755
|
skipRows,
|
|
679
756
|
hasHeader: true,
|
|
680
|
-
maxRows:
|
|
757
|
+
maxRows: 8
|
|
681
758
|
});
|
|
759
|
+
const headerLine = `${'▶'.padEnd(idxWidth)}${df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`;
|
|
760
|
+
lines.push(headerLine);
|
|
761
|
+
lines.push('═'.repeat(Math.min(headerLine.length, 140)));
|
|
682
762
|
const dataRows = df.toRows();
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
return `${rowIdx}${cols}`;
|
|
689
|
-
}).join('\n');
|
|
763
|
+
dataRows.forEach((row, i) => {
|
|
764
|
+
const rowIdx = String(totalOffset + 1 + i).padEnd(idxWidth);
|
|
765
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
766
|
+
lines.push(`${rowIdx}${cols}`);
|
|
767
|
+
});
|
|
690
768
|
if (previewDiv) {
|
|
691
|
-
previewDiv.textContent =
|
|
769
|
+
previewDiv.textContent = lines.join('\n');
|
|
692
770
|
}
|
|
693
771
|
}
|
|
694
772
|
catch (err) {
|
|
@@ -452,9 +452,9 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
452
452
|
|
|
453
453
|
const isMalformed = this._detectMalformedData(this._df!);
|
|
454
454
|
|
|
455
|
-
if (isMalformed && this.
|
|
455
|
+
if (isMalformed && this._rawFileData) {
|
|
456
456
|
this._updateStatus(
|
|
457
|
-
`${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols (Data may
|
|
457
|
+
`${sourceName} — ${this._df!.height} rows × ${this._df!.width} cols (Data may need reformatting)`,
|
|
458
458
|
'warning'
|
|
459
459
|
);
|
|
460
460
|
|
|
@@ -475,12 +475,13 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
475
475
|
'success'
|
|
476
476
|
);
|
|
477
477
|
|
|
478
|
-
if
|
|
478
|
+
// Always show settings button if we have raw file data
|
|
479
|
+
if (this._rawFileData) {
|
|
479
480
|
requestAnimationFrame(() => {
|
|
480
481
|
const statusEl = document.getElementById(`${this._id}-status`);
|
|
481
482
|
if (statusEl) {
|
|
482
483
|
const settingsBtn = document.createElement('button');
|
|
483
|
-
settingsBtn.textContent = 'Settings';
|
|
484
|
+
settingsBtn.textContent = 'Import Settings';
|
|
484
485
|
settingsBtn.className = 'jux-button jux-button-sm jux-button-ghost';
|
|
485
486
|
settingsBtn.style.marginLeft = '0.5rem';
|
|
486
487
|
settingsBtn.addEventListener('click', () => this._showReshapeModal());
|
|
@@ -603,15 +604,12 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
603
604
|
max="50"
|
|
604
605
|
style="width: 100%;"
|
|
605
606
|
/>
|
|
606
|
-
<div class="jux-reshape-hint">
|
|
607
|
-
<strong>Detected issue:</strong> The current header row appears to contain metadata or empty values.
|
|
608
|
-
Row ${suggestedRow} looks like it contains the actual column headers.
|
|
609
|
-
Adjust the value above and check the preview below. The Row column shows the index for each row.
|
|
607
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint">
|
|
610
608
|
</div>
|
|
611
609
|
</div>
|
|
612
610
|
<div class="jux-reshape-preview-container">
|
|
613
611
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">
|
|
614
|
-
Preview
|
|
612
|
+
Preview
|
|
615
613
|
</div>
|
|
616
614
|
<div id="${this._id}-preview" class="jux-reshape-preview"></div>
|
|
617
615
|
</div>
|
|
@@ -648,7 +646,6 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
648
646
|
if (sheetNames.length > 1) {
|
|
649
647
|
this._renderMultiSheet(sheets, this._rawFileData!.file.name);
|
|
650
648
|
} else {
|
|
651
|
-
this._showReshapeWarning = false;
|
|
652
649
|
this._setDataFrame(sheets[sheetNames[0]], this._rawFileData!.file.name);
|
|
653
650
|
}
|
|
654
651
|
|
|
@@ -667,32 +664,80 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
667
664
|
|
|
668
665
|
const headerRowInput = document.getElementById(`${this._id}-header-row`) as HTMLInputElement;
|
|
669
666
|
const previewDiv = document.getElementById(`${this._id}-preview`)!;
|
|
667
|
+
const hintDiv = document.getElementById(`${this._id}-reshape-hint`)!;
|
|
668
|
+
|
|
669
|
+
const updateHint = (headerRow: number) => {
|
|
670
|
+
if (!hintDiv) return;
|
|
671
|
+
hintDiv.innerHTML = headerRow > 0
|
|
672
|
+
? `Row <strong>${headerRow}</strong> will be used as column headers. ` +
|
|
673
|
+
`The <strong>${headerRow}</strong> row${headerRow > 1 ? 's' : ''} above will be skipped.`
|
|
674
|
+
: `Row <strong>0</strong> (first row) will be used as column headers.`;
|
|
675
|
+
};
|
|
670
676
|
|
|
671
677
|
const updatePreview = async () => {
|
|
672
678
|
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
679
|
+
updateHint(headerRow);
|
|
680
|
+
|
|
673
681
|
try {
|
|
674
|
-
|
|
682
|
+
// First, get raw data (headerRow=0) to show skipped rows
|
|
683
|
+
const rawSheets = await this._driver.streamFileMultiSheet(this._rawFileData!.file, {
|
|
684
|
+
headerRow: 0,
|
|
685
|
+
maxSheetSize: headerRow + 15
|
|
686
|
+
});
|
|
687
|
+
const rawSheet = Object.values(rawSheets)[0];
|
|
688
|
+
|
|
689
|
+
// Then, get parsed data with the chosen header row
|
|
690
|
+
const parsedSheets = await this._driver.streamFileMultiSheet(this._rawFileData!.file, {
|
|
675
691
|
headerRow,
|
|
676
|
-
maxSheetSize: headerRow +
|
|
692
|
+
maxSheetSize: headerRow + 15
|
|
677
693
|
});
|
|
694
|
+
const parsedSheet = Object.values(parsedSheets)[0];
|
|
678
695
|
|
|
679
|
-
|
|
680
|
-
if (!firstSheet) {
|
|
696
|
+
if (!rawSheet && !parsedSheet) {
|
|
681
697
|
if (previewDiv) previewDiv.textContent = 'No data found';
|
|
682
698
|
return;
|
|
683
699
|
}
|
|
684
700
|
|
|
685
|
-
const
|
|
686
|
-
const
|
|
687
|
-
const
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
701
|
+
const colWidth = 22;
|
|
702
|
+
const idxWidth = 6;
|
|
703
|
+
const lines: string[] = [];
|
|
704
|
+
|
|
705
|
+
// Show skipped rows (rows before the header)
|
|
706
|
+
if (rawSheet && headerRow > 0) {
|
|
707
|
+
const rawRows = rawSheet.toRows();
|
|
708
|
+
// Row 0 in raw parse is the raw header, rows after are data
|
|
709
|
+
// Show raw header as row 0
|
|
710
|
+
const rawCols = rawSheet.columns;
|
|
711
|
+
lines.push(`${'Idx'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`);
|
|
712
|
+
|
|
713
|
+
const skippedCount = Math.min(headerRow - 1, rawRows.length);
|
|
714
|
+
for (let i = 0; i < skippedCount; i++) {
|
|
715
|
+
const row = rawRows[i];
|
|
716
|
+
const rowIdx = String(i + 1).padEnd(idxWidth);
|
|
717
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
718
|
+
lines.push(`${rowIdx}${cols}`);
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// Separator: everything above is skipped
|
|
722
|
+
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Show header row and data rows from parsed result
|
|
726
|
+
if (parsedSheet) {
|
|
727
|
+
const headerLine = `${'▶'.padEnd(idxWidth)}${parsedSheet.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`;
|
|
728
|
+
lines.push(headerLine);
|
|
729
|
+
lines.push('═'.repeat(Math.min(headerLine.length, 140)));
|
|
730
|
+
|
|
731
|
+
const dataRows = parsedSheet.toRows().slice(0, 8);
|
|
732
|
+
dataRows.forEach((row, i) => {
|
|
733
|
+
const rowIdx = String(headerRow + 1 + i).padEnd(idxWidth);
|
|
734
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
735
|
+
lines.push(`${rowIdx}${cols}`);
|
|
736
|
+
});
|
|
737
|
+
}
|
|
693
738
|
|
|
694
739
|
if (previewDiv) {
|
|
695
|
-
previewDiv.textContent =
|
|
740
|
+
previewDiv.textContent = lines.join('\n');
|
|
696
741
|
}
|
|
697
742
|
} catch (err: any) {
|
|
698
743
|
if (previewDiv) previewDiv.textContent = `Error: ${err.message}`;
|
|
@@ -735,7 +780,8 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
735
780
|
<label style="display: block; font-weight: 600; margin-bottom: 0.5rem;">Skip Rows Before Header</label>
|
|
736
781
|
<input type="number" id="${this._id}-skip-rows" class="jux-input-element" value="0" min="0" max="50" style="width: 100%;" />
|
|
737
782
|
</div>
|
|
738
|
-
<div class="jux-reshape-
|
|
783
|
+
<div id="${this._id}-reshape-hint" class="jux-reshape-hint"></div>
|
|
784
|
+
<div class="jux-reshape-preview-container" style="margin-top: 1rem;">
|
|
739
785
|
<div style="font-weight: 600; margin-bottom: 0.5rem; color: hsl(var(--foreground));">Preview</div>
|
|
740
786
|
<div id="${this._id}-preview" class="jux-reshape-preview"></div>
|
|
741
787
|
</div>
|
|
@@ -775,7 +821,6 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
775
821
|
});
|
|
776
822
|
|
|
777
823
|
await this._driver.store(this._rawFileData.file.name, df, { source: this._rawFileData.file.name });
|
|
778
|
-
this._showReshapeWarning = false;
|
|
779
824
|
this._setDataFrame(df, this._rawFileData.file.name);
|
|
780
825
|
|
|
781
826
|
this._reshapeModal!.closeModal();
|
|
@@ -794,6 +839,7 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
794
839
|
const headerRowInput = document.getElementById(`${this._id}-header-row`) as HTMLInputElement;
|
|
795
840
|
const skipRowsInput = document.getElementById(`${this._id}-skip-rows`) as HTMLInputElement;
|
|
796
841
|
const previewDiv = document.getElementById(`${this._id}-preview`)!;
|
|
842
|
+
const hintDiv = document.getElementById(`${this._id}-reshape-hint`)!;
|
|
797
843
|
|
|
798
844
|
if (this._rawFileData?.text) {
|
|
799
845
|
const detected = (this._driver as any)._detectDelimiter(this._rawFileData.text);
|
|
@@ -803,6 +849,17 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
803
849
|
if (headerRowInput) headerRowInput.value = String(detectedHeaderRow);
|
|
804
850
|
}
|
|
805
851
|
|
|
852
|
+
const updateHint = () => {
|
|
853
|
+
if (!hintDiv) return;
|
|
854
|
+
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
855
|
+
const skipRows = parseInt(skipRowsInput?.value) || 0;
|
|
856
|
+
const totalSkipped = headerRow + skipRows;
|
|
857
|
+
hintDiv.innerHTML = totalSkipped > 0
|
|
858
|
+
? `Row <strong>${headerRow + skipRows}</strong> will be used as column headers. ` +
|
|
859
|
+
`<strong>${totalSkipped}</strong> row${totalSkipped > 1 ? 's' : ''} above will be skipped.`
|
|
860
|
+
: `Row <strong>0</strong> (first row) will be used as column headers.`;
|
|
861
|
+
};
|
|
862
|
+
|
|
806
863
|
const updatePreview = () => {
|
|
807
864
|
if (!this._rawFileData?.text) return;
|
|
808
865
|
|
|
@@ -810,26 +867,61 @@ export class DataFrameComponent extends BaseComponent<DataFrameState> {
|
|
|
810
867
|
const headerRow = parseInt(headerRowInput?.value) || 0;
|
|
811
868
|
const skipRows = parseInt(skipRowsInput?.value) || 0;
|
|
812
869
|
|
|
870
|
+
updateHint();
|
|
871
|
+
|
|
813
872
|
try {
|
|
873
|
+
const colWidth = 22;
|
|
874
|
+
const idxWidth = 6;
|
|
875
|
+
const lines: string[] = [];
|
|
876
|
+
const totalOffset = headerRow + skipRows;
|
|
877
|
+
|
|
878
|
+
// Parse raw (no header offset) to show skipped rows
|
|
879
|
+
if (totalOffset > 0) {
|
|
880
|
+
const rawDf = this._driver.parseCSV(this._rawFileData.text, {
|
|
881
|
+
delimiter: delim,
|
|
882
|
+
headerRow: 0,
|
|
883
|
+
skipRows: 0,
|
|
884
|
+
hasHeader: true,
|
|
885
|
+
maxRows: totalOffset + 1
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
const rawCols = rawDf.columns;
|
|
889
|
+
lines.push(`${'Idx'.padEnd(idxWidth)}${rawCols.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`);
|
|
890
|
+
|
|
891
|
+
const rawRows = rawDf.toRows();
|
|
892
|
+
const skippedCount = Math.min(totalOffset - 1, rawRows.length);
|
|
893
|
+
for (let i = 0; i < skippedCount; i++) {
|
|
894
|
+
const row = rawRows[i];
|
|
895
|
+
const rowIdx = String(i + 1).padEnd(idxWidth);
|
|
896
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
897
|
+
lines.push(`${rowIdx}${cols}`);
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
lines.push(`${'─'.repeat(6)}${'── skipped '.padEnd(colWidth * Math.min(rawCols.length, 5), '─')}`);
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
// Parse with actual settings for header + data rows
|
|
814
904
|
const df = this._driver.parseCSV(this._rawFileData.text, {
|
|
815
905
|
delimiter: delim,
|
|
816
906
|
headerRow,
|
|
817
907
|
skipRows,
|
|
818
908
|
hasHeader: true,
|
|
819
|
-
maxRows:
|
|
909
|
+
maxRows: 8
|
|
820
910
|
});
|
|
821
911
|
|
|
912
|
+
const headerLine = `${'▶'.padEnd(idxWidth)}${df.columns.map(c => String(c).substring(0, colWidth - 2).padEnd(colWidth)).join('| ')}`;
|
|
913
|
+
lines.push(headerLine);
|
|
914
|
+
lines.push('═'.repeat(Math.min(headerLine.length, 140)));
|
|
915
|
+
|
|
822
916
|
const dataRows = df.toRows();
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
return `${rowIdx}${cols}`;
|
|
829
|
-
}).join('\n');
|
|
917
|
+
dataRows.forEach((row, i) => {
|
|
918
|
+
const rowIdx = String(totalOffset + 1 + i).padEnd(idxWidth);
|
|
919
|
+
const cols = Object.values(row).map(v => String(v ?? '').substring(0, colWidth - 2).padEnd(colWidth)).join('| ');
|
|
920
|
+
lines.push(`${rowIdx}${cols}`);
|
|
921
|
+
});
|
|
830
922
|
|
|
831
923
|
if (previewDiv) {
|
|
832
|
-
previewDiv.textContent =
|
|
924
|
+
previewDiv.textContent = lines.join('\n');
|
|
833
925
|
}
|
|
834
926
|
} catch (err: any) {
|
|
835
927
|
if (previewDiv) previewDiv.textContent = `Error: ${err.message}`;
|