Add button to sheet and shift selector
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
let sortColumn = $state<keyof RowData | null>(null);
|
let sortColumn = $state<keyof RowData | null>(null);
|
||||||
let sortDirection = $state<'asc' | 'desc'>('asc');
|
let sortDirection = $state<'asc' | 'desc'>('asc');
|
||||||
|
let lastCheckedId: string | null = $state(null);
|
||||||
|
|
||||||
const ROW_LIMIT = 200;
|
const ROW_LIMIT = 200;
|
||||||
|
|
||||||
@@ -85,20 +86,52 @@
|
|||||||
} finally {
|
} finally {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
}
|
}
|
||||||
} // Run on component mount
|
}
|
||||||
|
|
||||||
|
function handleRowClick(event: MouseEvent, clickedId: string) {
|
||||||
|
const clickedRow = rows.find((r) => r.id === clickedId);
|
||||||
|
if (!clickedRow || !clickedRow._valid) return;
|
||||||
|
|
||||||
|
// Handle shift-clicking for range selection
|
||||||
|
if (event.shiftKey && lastCheckedId) {
|
||||||
|
const lastIndex = displayData.findIndex((r) => r.id === lastCheckedId);
|
||||||
|
const currentIndex = displayData.findIndex((r) => r.id === clickedId);
|
||||||
|
|
||||||
|
if (lastIndex !== -1 && currentIndex !== -1) {
|
||||||
|
const start = Math.min(lastIndex, currentIndex);
|
||||||
|
const end = Math.max(lastIndex, currentIndex);
|
||||||
|
const isChecked = !clickedRow._checked; // The state to apply to the range
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
const rowToSelect = displayData[i];
|
||||||
|
if (rowToSelect && rowToSelect._valid) {
|
||||||
|
// Prevent checking more than the limit
|
||||||
|
if (isChecked && selectedCount >= ROW_LIMIT && !rowToSelect._checked) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
rowToSelect._checked = isChecked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Normal click, just toggle the state
|
||||||
|
if (!clickedRow._checked && selectedCount >= ROW_LIMIT) {
|
||||||
|
// Do not allow checking more than the limit
|
||||||
|
} else {
|
||||||
|
clickedRow._checked = !clickedRow._checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the last checked ID for the next shift-click
|
||||||
|
lastCheckedId = clickedId;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run on component mount
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
ensureToken();
|
ensureToken();
|
||||||
fetchAndProcessData();
|
fetchAndProcessData();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Function to toggle a single row's checked state
|
|
||||||
function toggleRow(id: string) {
|
|
||||||
const row = rows.find((r) => r.id === id);
|
|
||||||
if (row && row._valid) {
|
|
||||||
row._checked = !row._checked;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Function to toggle select-all: selects first 200 eligible items in current view
|
// Function to toggle select-all: selects first 200 eligible items in current view
|
||||||
function toggleSelectAll(event: Event) {
|
function toggleSelectAll(event: Event) {
|
||||||
const target = event.target as HTMLInputElement;
|
const target = event.target as HTMLInputElement;
|
||||||
@@ -169,56 +202,62 @@
|
|||||||
<div>
|
<div>
|
||||||
<h2 class="mb-2 text-xl font-semibold text-gray-900">Filter and Select Rows</h2>
|
<h2 class="mb-2 text-xl font-semibold text-gray-900">Filter and Select Rows</h2>
|
||||||
<p class="text-sm text-gray-700">
|
<p class="text-sm text-gray-700">
|
||||||
Review your data and select which rows to include. Select a batch of max 200 items by using the top checkbox.
|
Review your data and select which rows to include. Select a batch of max 200 items by using
|
||||||
|
the top checkbox.
|
||||||
</p>
|
</p>
|
||||||
<p class="text-sm text-gray-700">
|
<p class="mt-1 text-sm text-gray-700">
|
||||||
|
Tip: Hold <kbd
|
||||||
|
class="rounded-md border border-gray-400 bg-gray-200 px-1.5 py-0.5 text-xs font-semibold"
|
||||||
|
>Shift</kbd
|
||||||
|
> and click two checkboxes to select a range of rows.
|
||||||
|
</p>
|
||||||
|
<p class="mt-1 text-sm text-gray-700">
|
||||||
Already printed or invalid data is marked in the status column.
|
Already printed or invalid data is marked in the status column.
|
||||||
</p>
|
</p>
|
||||||
{#if $selectedSheet?.id}
|
|
||||||
<p class="mt-1 text-sm text-gray-500">
|
|
||||||
Need to make changes?
|
|
||||||
<a
|
|
||||||
href={`https://docs.google.com/spreadsheets/d/${$selectedSheet.id}/edit`}
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
class="text-blue-600 underline hover:text-blue-800"
|
|
||||||
>
|
|
||||||
Open the spreadsheet
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
<button
|
<div class="flex flex-col space-y-2">
|
||||||
onclick={fetchAndProcessData}
|
{#if $selectedSheet?.id}
|
||||||
class="inline-flex items-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-wait disabled:opacity-50"
|
<a
|
||||||
disabled={isLoading}
|
href={`https://docs.google.com/spreadsheets/d/${$selectedSheet.id}/edit`}
|
||||||
>
|
target="_blank"
|
||||||
{#if isLoading}
|
rel="noopener noreferrer"
|
||||||
<svg
|
class="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"
|
||||||
class="-ml-1 mr-2 h-5 w-5 animate-spin text-gray-500"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
fill="none"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
>
|
||||||
<circle
|
Open Sheet
|
||||||
class="opacity-25"
|
</a>
|
||||||
cx="12"
|
|
||||||
cy="12"
|
|
||||||
r="10"
|
|
||||||
stroke="currentColor"
|
|
||||||
stroke-width="4"
|
|
||||||
></circle>
|
|
||||||
<path
|
|
||||||
class="opacity-75"
|
|
||||||
fill="currentColor"
|
|
||||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
||||||
></path>
|
|
||||||
</svg>
|
|
||||||
Refreshing...
|
|
||||||
{:else}
|
|
||||||
Refresh Data
|
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
<button
|
||||||
|
onclick={fetchAndProcessData}
|
||||||
|
class="inline-flex items-center justify-center rounded-md border border-gray-300 bg-white px-4 py-2 text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:cursor-wait disabled:opacity-50"
|
||||||
|
disabled={isLoading}
|
||||||
|
>
|
||||||
|
{#if isLoading}
|
||||||
|
<svg
|
||||||
|
class="-ml-1 mr-2 h-5 w-5 animate-spin text-gray-500"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
>
|
||||||
|
<circle
|
||||||
|
class="opacity-25"
|
||||||
|
cx="12"
|
||||||
|
cy="12"
|
||||||
|
r="10"
|
||||||
|
stroke="currentColor"
|
||||||
|
stroke-width="4"
|
||||||
|
></circle>
|
||||||
|
<path
|
||||||
|
class="opacity-75"
|
||||||
|
fill="currentColor"
|
||||||
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
Refreshing...
|
||||||
|
{:else}
|
||||||
|
Refresh Data
|
||||||
|
{/if}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
@@ -313,7 +352,7 @@
|
|||||||
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed disabled:bg-gray-200"
|
class="h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500 disabled:cursor-not-allowed disabled:bg-gray-200"
|
||||||
checked={row._checked}
|
checked={row._checked}
|
||||||
disabled={!row._valid || (selectedCount >= ROW_LIMIT && !row._checked)}
|
disabled={!row._valid || (selectedCount >= ROW_LIMIT && !row._checked)}
|
||||||
onchange={() => toggleRow(row.id)}
|
onclick={(e) => handleRowClick(e, row.id)}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-4 py-3 text-sm">{row._rowIndex}</td>
|
<td class="whitespace-nowrap px-4 py-3 text-sm">{row._rowIndex}</td>
|
||||||
|
|||||||
Reference in New Issue
Block a user