Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
482f7b3
advanced search with filter over muliple columns
sbamin Mar 2, 2026
c5c56cd
✨ 🔎 add advanced search panel to Rows tab
sbamin Mar 2, 2026
b5edcd9
update version
sbamin Mar 3, 2026
25a9c28
offset table when search is expanded
sbamin Mar 3, 2026
e08aec2
regex operators
sbamin Mar 3, 2026
1e4d9fd
always keep first operator
sbamin Mar 3, 2026
c65b21f
Merge pull request #1 from sbamin/main
sbamin Mar 3, 2026
432fbdf
🛠️ fixed IN, BETWEEN, and NULL operators
sbamin Mar 5, 2026
ee7516b
chore: ignore .worktrees/ directory
sbamin Apr 1, 2026
98c489f
feat: add aggregate panel HTML skeleton
sbamin Apr 1, 2026
a59a5f7
feat: add aggregate panel CSS
sbamin Apr 1, 2026
75fc8f2
feat: add aggregateActive flag, buildGroupBySection, and aggregate pa…
sbamin Apr 1, 2026
261af06
feat: add buildAggregateRow and aggregate expression event handlers
sbamin Apr 1, 2026
f2d06d5
feat: add getAggregateAliases, buildHavingRow, updateHavingAliasDropd…
sbamin Apr 1, 2026
5b129e8
feat: add buildAggregateSelectClause, buildGroupByClause, buildHaving…
sbamin Apr 1, 2026
e507a6b
feat: add applyAggregate, resetAggregate, and aggregate panel button …
sbamin Apr 1, 2026
71aeb8e
feat: wire aggregate mode into showTableContent, buildFullQuery, tabl…
sbamin Apr 1, 2026
dc31cae
fix: update stale buildFullQuery comment to reflect aggregate delegation
sbamin Apr 1, 2026
ddab2df
fix: address final review issues — HAVING escaping, sort/edit guards,…
sbamin Apr 1, 2026
5c8f30a
fix: repair Show Query toggle, move query display outside panels, add…
sbamin Apr 1, 2026
3f04262
docs: add GROUP BY dropdown design spec
sbamin Apr 2, 2026
55e4457
docs: add GROUP BY dropdown implementation plan
sbamin Apr 2, 2026
3c17b58
feat: replace GROUP BY checkbox grid with multi-select element
sbamin Apr 2, 2026
2729751
fix: add aria-label and aria-describedby to GROUP BY select
sbamin Apr 2, 2026
b69d0cc
feat: swap GROUP BY grid CSS for multi-select styles
sbamin Apr 2, 2026
b3b8bd4
feat: rewrite buildGroupBySection to populate select options
sbamin Apr 2, 2026
e4ab7ff
feat: update buildGroupByClause to read from multi-select
sbamin Apr 2, 2026
9fb6961
feat: update buildAggregateSelectClause to read from multi-select
sbamin Apr 2, 2026
b7a7a7d
feat: update resetAggregate to deselect multi-select instead of rebui…
sbamin Apr 2, 2026
cbf80bd
fix: update buildGroupBySection to populate multi-select options
sbamin Apr 2, 2026
7b2e648
Merge branch 'feature/group-by-dropdown' into local
sbamin Apr 2, 2026
ae192dd
fix: prevent query tab freeze on unexpected API response and modal close
sbamin Apr 2, 2026
ee12731
docs: add HAVING row remove button design spec
sbamin Apr 2, 2026
54716b8
docs: add HAVING row remove button implementation plan
sbamin Apr 2, 2026
32d635f
feat: add remove button to first HAVING row
sbamin Apr 2, 2026
c105c29
fix: promote new first HAVING row after first-row deletion
sbamin Apr 2, 2026
369630d
fix: use full aggregate expression in HAVING clause instead of alias
sbamin Apr 2, 2026
96740bb
feat: add cautionary note in nav bar for Advanced/Aggregate filters
sbamin Apr 2, 2026
6db67ef
docs: add ORDER BY + LIMIT design spec for Advanced and Aggregate panels
sbamin Apr 2, 2026
1aa8861
docs: add ORDER BY + LIMIT implementation plan
sbamin Apr 2, 2026
3c3feae
GO build inst for mac
sbamin Apr 7, 2026
db4fc27
pre-hook push - prevent local push
sbamin Apr 7, 2026
25040a5
🐞 ☑️ Run Query buttons unclickable after Rows tab — root cause and fix
sbamin May 17, 2026
428d926
update with DOM bugfix, unable to click query button
sbamin May 17, 2026
06d309a
add --banner arg for a banner on bookmarks page
sbamin May 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions .claude/memory/2026-04-02-group-by-dropdown-design.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Group By Dropdown Design

**Date:** 2026-04-02
**Feature:** Replace GROUP BY checkbox grid with native multi-select dropdown

## Context

The aggregate panel's GROUP BY section currently renders a flat grid of checkboxes (one per column), injected by `buildGroupBySection()`. This design scales poorly for tables with many columns and lacks a clear affordance for multi-selection.

## Goal

Replace the checkbox grid with a native `<select multiple>` element. Selection alone is required — column ordering is not.

## Design

### HTML (`static/index.html`)

Replace the `#agg_group_by_grid` div with a `<select multiple>` and a hint label inside the existing `.agg-section`:

```html
<div class="agg-section">
<div class="agg-section-header">GROUP BY</div>
<select id="agg_group_by_select" multiple class="form-control agg-group-by-select"></select>
<div class="agg-group-by-hint">Hold Ctrl / Cmd to select multiple columns</div>
</div>
```

### JS (`static/js/app.js`)

**`buildGroupBySection()`** — populate `<option>` elements instead of checkbox labels:

```js
function buildGroupBySection() {
var sel = $("#agg_group_by_select");
sel.empty();
$("#pagination select.column option").each(function() {
var val = $(this).val();
if (!val) return;
sel.append($("<option>", { value: val, text: val }));
});
}
```

**`buildGroupByClause()`** — read `.val()` on the multi-select (returns array or null):

```js
function buildGroupByClause() {
var cols = $("#agg_group_by_select").val() || [];
if (cols.length === 0) return null;
return "GROUP BY " + cols.map(function(c) { return '"' + c + '"'; }).join(", ");
}
```

**`buildAggregateSelectClause()`** — iterate `.val()` instead of `.agg-group-col:checked`:

```js
var cols = $("#agg_group_by_select").val() || [];
cols.forEach(function(c) { parts.push('"' + c + '"'); });
```

**`resetAggregate()`** — deselect all: `$("#agg_group_by_select").val([]);`

### CSS (`static/css/app.css`)

Remove `.agg-group-by-grid` and `.agg-group-by-grid label` rules. Add:

```css
.agg-group-by-select {
height: 90px;
font-size: 12px;
}
.agg-group-by-hint {
font-size: 11px;
color: #aaa;
margin-top: 3px;
}
```

## Scope

- 4 JS functions modified: `buildGroupBySection`, `buildGroupByClause`, `buildAggregateSelectClause`, `resetAggregate`
- 1 HTML block replaced: `#agg_group_by_grid` → `#agg_group_by_select`
- 2 CSS rules removed, 2 added
- No changes to `buildAggregateQuery`, HAVING logic, or aggregate expression logic
- No new dependencies
287 changes: 287 additions & 0 deletions .claude/memory/2026-04-02-group-by-dropdown-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
# Group By Dropdown Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Replace the GROUP BY checkbox grid in the aggregate panel with a native `<select multiple>` dropdown.

**Architecture:** Three files change in concert — HTML swaps the container element, JS updates four functions to read from the select instead of checkboxes, CSS removes the old grid rules and adds two new rules for the select and hint. No new dependencies; no other logic is touched.

**Tech Stack:** jQuery, Bootstrap 3, plain HTML/CSS. No JS test framework exists for the frontend — verification is via Go build success and manual browser inspection.

---

### Task 1: Replace GROUP BY HTML

**Files:**
- Modify: `static/index.html:156-158`

- [ ] **Step 1: Replace the checkbox grid div with a `<select multiple>` and hint**

In `static/index.html`, replace lines 156-158:

```html
<div id="agg_group_by_grid" class="agg-group-by-grid">
<!-- Group-by checkboxes injected by buildGroupBySection() -->
</div>
```

with:

```html
<select id="agg_group_by_select" multiple class="form-control agg-group-by-select"></select>
<div class="agg-group-by-hint">Hold Ctrl / Cmd to select multiple columns</div>
```

- [ ] **Step 2: Commit**

```bash
git add static/index.html
git commit -S -m "feat: replace GROUP BY checkbox grid with multi-select element"
```

---

### Task 2: Update CSS

**Files:**
- Modify: `static/css/app.css:1140-1154`

- [ ] **Step 1: Remove old grid rules and add new select rules**

In `static/css/app.css`, replace lines 1140-1154:

```css
.agg-group-by-grid {
display: flex;
flex-wrap: wrap;
gap: 6px 16px;
}

.agg-group-by-grid label {
display: flex;
align-items: center;
gap: 4px;
font-size: 12px;
font-weight: normal;
margin: 0;
cursor: pointer;
}
```

with:

```css
.agg-group-by-select {
height: 90px;
font-size: 12px;
}

.agg-group-by-hint {
font-size: 11px;
color: #aaa;
margin-top: 3px;
}
```

- [ ] **Step 2: Commit**

```bash
git add static/css/app.css
git commit -S -m "feat: swap GROUP BY grid CSS for multi-select styles"
```

---

### Task 3: Update `buildGroupBySection()`

**Files:**
- Modify: `static/js/app.js:1181-1192`

- [ ] **Step 1: Rewrite to populate `<option>` elements**

In `static/js/app.js`, replace lines 1181-1192:

```js
function buildGroupBySection() {
var grid = $("#agg_group_by_grid");
grid.empty();
$("#pagination select.column option").each(function() {
var val = $(this).val();
if (!val) return;
var label = $("<label>");
var cb = $("<input>", { type: "checkbox", class: "agg-group-col", value: val });
label.append(cb).append(" " + val);
grid.append(label);
});
}
```

with:

```js
function buildGroupBySection() {
var sel = $("#agg_group_by_select");
sel.empty();
$("#pagination select.column option").each(function() {
var val = $(this).val();
if (!val) return;
sel.append($("<option>", { value: val, text: val }));
});
}
```

- [ ] **Step 2: Commit**

```bash
git add static/js/app.js
git commit -S -m "feat: rewrite buildGroupBySection to populate select options"
```

---

### Task 4: Update `buildGroupByClause()`

**Files:**
- Modify: `static/js/app.js:1321-1328`

- [ ] **Step 1: Read from multi-select `.val()` instead of checked checkboxes**

In `static/js/app.js`, replace lines 1321-1328:

```js
function buildGroupByClause() {
var cols = [];
$(".agg-group-col:checked").each(function() {
cols.push('"' + $(this).val() + '"');
});
if (cols.length === 0) return null;
return "GROUP BY " + cols.join(", ");
}
```

with:

```js
function buildGroupByClause() {
var cols = $("#agg_group_by_select").val() || [];
if (cols.length === 0) return null;
return "GROUP BY " + cols.map(function(c) { return '"' + c + '"'; }).join(", ");
}
```

- [ ] **Step 2: Commit**

```bash
git add static/js/app.js
git commit -S -m "feat: update buildGroupByClause to read from multi-select"
```

---

### Task 5: Update `buildAggregateSelectClause()`

**Files:**
- Modify: `static/js/app.js:1298-1302`

- [ ] **Step 1: Replace `.agg-group-col:checked` iteration with `.val()` array**

In `static/js/app.js`, replace lines 1298-1302:

```js
function buildAggregateSelectClause() {
var parts = [];
$(".agg-group-col:checked").each(function() {
parts.push('"' + $(this).val() + '"');
});
```

with:

```js
function buildAggregateSelectClause() {
var parts = [];
var cols = $("#agg_group_by_select").val() || [];
cols.forEach(function(c) { parts.push('"' + c + '"'); });
```

- [ ] **Step 2: Commit**

```bash
git add static/js/app.js
git commit -S -m "feat: update buildAggregateSelectClause to read from multi-select"
```

---

### Task 6: Update `resetAggregate()`

**Files:**
- Modify: `static/js/app.js:1493`

- [ ] **Step 1: Replace `buildGroupBySection()` call with deselect-all**

In `static/js/app.js`, replace line 1493:

```js
buildGroupBySection();
```

with:

```js
$("#agg_group_by_select").val([]);
```

The full function after the change:

```js
function resetAggregate() {
aggregateActive = false;
$("#agg_active_badge").hide();
$("#agg_group_by_select").val([]);
$("#agg_expr_rows").empty();
$("#agg_having_rows").empty();
$("#aggregate_panel").hide();
$("#aggregate-toggle").removeClass("agg-open");
$("#pagination").removeClass("agg-panel-open");
adjustOutputTop();
}
```

- [ ] **Step 2: Commit**

```bash
git add static/js/app.js
git commit -S -m "feat: update resetAggregate to deselect multi-select instead of rebuilding"
```

---

### Task 7: Build and verify

- [ ] **Step 1: Build the binary**

```bash
GOROOT=/opt/homebrew/Cellar/go/1.26.1/libexec GOPROXY=https://proxy.golang.org,direct GONOSUMDB='*' GOOS=linux GOARCH=amd64 go build -o ./bin/pgweb_linux_amd64
```

Expected: exits 0, no output.

- [ ] **Step 2: Run Go tests**

```bash
GOROOT=/opt/homebrew/Cellar/go/1.26.1/libexec go test ./... 2>&1 | grep -v "^?"
```

Expected: all packages pass except `pkg/client` (requires a live PostgreSQL connection — pre-existing infrastructure failure, not related to this change).

- [ ] **Step 3: Manual smoke check**

Start the server locally and open a table:
1. Click **Aggregate** button — GROUP BY section shows a `<select>` populated with column names
2. Select one column (single-click) → click **Apply** → results group correctly
3. Select multiple columns (Ctrl+click) → click **Apply** → GROUP BY clause includes all selected columns
4. Click **Show Query** → SQL reflects selected columns in GROUP BY
5. Click **Clear** → select has no selection, aggregate mode deactivates

- [ ] **Step 4: Invoke `superpowers:finishing-a-development-branch`**
Loading