Skip to content

Refine WebUI Sidebar and config source add#33

Merged
JaredforReal merged 2 commits into
mainfrom
refine
May 2, 2026
Merged

Refine WebUI Sidebar and config source add#33
JaredforReal merged 2 commits into
mainfrom
refine

Conversation

@JaredforReal
Copy link
Copy Markdown
Owner

No description provided.

Signed-off-by: JaredforReal <w13431838023@gmail.com>
Signed-off-by: JaredforReal <w13431838023@gmail.com>
Copilot AI review requested due to automatic review settings May 2, 2026 21:23
@JaredforReal JaredforReal changed the title Refine Refine WebUI Sidebar and config source add May 2, 2026
@JaredforReal JaredforReal merged commit 24d2778 into main May 2, 2026
5 checks passed
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refines WebUI source handling by introducing human-friendly source names, adding source_id_prefix-based filtering for GitHub repos, and improving the config “Form” editor with schema-driven source defaults/fields. It also updates backend unread counting to be group-based and adjusts default grouping for several adaptors.

Changes:

  • Add computed name fields for sources/groups and update the UI to display/use them.
  • Add source_id_prefix (and multi-prefix) filtering to envelope queries, and wire it through the API + frontend.
  • Enhance the config Form editor with schema-driven fields/defaults and switch Config editor default mode to “form”.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
tests/test_webui.py Adds a test asserting /api/sources includes computed name.
loom/webui/frontend/tsconfig.tsbuildinfo Updates TS incremental build metadata (likely a generated artifact).
loom/webui/frontend/src/pages/config/ConfigFormEditor.tsx Adds schema-driven source defaults/fields and “Add source kind” selection.
loom/webui/frontend/src/pages/config/ConfigEditor.tsx Switches default editor mode to “form”.
loom/webui/frontend/src/lib/types.ts Extends frontend types to include Source.name and optional name for group sources.
loom/webui/frontend/src/lib/api.ts Adds source_id_prefix query param wiring for listing envelopes.
loom/webui/frontend/src/components/Sidebar.tsx Adds sourceIdPrefix state/handlers and per-repo GitHub filtering from the sidebar.
loom/webui/frontend/src/components/SettingsPopover.tsx Changes default-source selection options to use/display name.
loom/state/store.py Adds group-based unread counts, prefix filtering, and a GitHub group migration on init.
loom/daemon.py Sets default groups for GitHub/RSS/arXiv sources based on source identity.
loom/core/mailbox.py Plumbs source_id_prefix through to the store query.
loom/api_server.py Adds source_id_prefix param, group→prefix resolution for GitHub, and name/unread computation updates.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +61 to +62
<option key={s.name || s.kind} value={s.name || s.kind}>
{s.name || s.kind}
Comment thread loom/state/store.py
Comment on lines +217 to +234
async def get_unread_counts_by_group(self) -> dict[str, int]:
"""Return {group: count} for pending/in_review envelopes."""
async with self._session() as session:
stmt = (
select(EnvelopeRow.group, func.count(EnvelopeRow.id))
.where(
EnvelopeRow.status.in_(
[
str(EnvelopeStatus.PENDING),
str(EnvelopeStatus.IN_REVIEW),
]
)
)
.where(EnvelopeRow.group != "")
.group_by(EnvelopeRow.group)
)
result = await session.execute(stmt)
return {row[0]: row[1] for row in result.all()}
Comment thread loom/api_server.py
if kind == "github" and "owner" in src and "repo" in src:
prefixes.append(f"{src['owner']}/{src['repo']}")
if prefixes:
envelopes = await ctx.store.query_envelopes(
Comment thread loom/daemon.py
Comment on lines +228 to +232
categories=cats,
keywords=src.get("keywords", []),
poll_interval=src.get("poll_interval", 3600),
max_results=src.get("max_results", 50),
group=src.get("group", ""),
group=src.get("group") or default_group,
Comment on lines +364 to +369
onClick={() => {
const sel = document.getElementById("source-kind-select") as HTMLSelectElement
const kind = sel?.value ?? "github"
const defaults = sourceDefaults(kind)
const next = [...config.sources, defaults]
update({ ...config, sources: next })
Comment thread loom/api_server.py
Comment on lines +238 to +261
group_counts = await ctx.store.get_unread_counts_by_group()
result = []
for src in ctx.config.sources:
kind = src.get("kind", "unknown")
entry = dict(src)
entry.setdefault("mode", "active")
entry["unread"] = counts.get(kind, 0)

# Compute display name from source-specific fields
if kind == "github" and "owner" in src and "repo" in src:
entry["name"] = f"{src['owner']}/{src['repo']}"
elif kind == "rss" and "url" in src:
from urllib.parse import urlparse

entry["name"] = urlparse(src["url"]).hostname or src["url"]
elif kind == "arxiv":
cats = src.get("categories", [])
entry["name"] = ", ".join(cats) if cats else src.get("query", kind)[:60]
else:
entry["name"] = kind

# Unread count: use explicit group if set, else match by name
# (daemon auto-assigns name as group on envelopes)
group_key = entry.get("group") or entry.get("name", kind)
entry["unread"] = group_counts.get(group_key, 0)
Comment thread loom/state/store.py
Comment on lines +126 to +132
# Migrate: reset GitHub envelope groups to source_id-derived value
# (undoes any stale backfill from previous daemon runs)
await conn.execute(
text(
'UPDATE envelopes SET "group" = '
"substr(source_id, 1, instr(source_id, '#') - 1) "
"WHERE source = 'github' AND source_id LIKE '%#%'"
@@ -1 +1 @@
{"root":["./src/app.tsx","./src/main.tsx","./src/components/actionspanel.tsx","./src/components/column.tsx","./src/components/detailpanel.tsx","./src/components/envelopecard.tsx","./src/components/envelopedetail.tsx","./src/components/kanbanboard.tsx","./src/components/label.tsx","./src/components/settingspopover.tsx","./src/components/sidebar.tsx","./src/components/statusbar.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/dialog.tsx","./src/components/ui/popover.tsx","./src/components/ui/scroll-area.tsx","./src/components/ui/separator.tsx","./src/components/ui/tooltip.tsx","./src/lib/api.ts","./src/lib/policies.ts","./src/lib/prompts.ts","./src/lib/settings.ts","./src/lib/types.ts","./src/lib/utils.ts","./src/pages/settingspage.tsx","./src/pages/policies/policiespanel.tsx","./src/pages/policies/policyeditor.tsx","./src/pages/policies/policyformeditor.tsx","./src/pages/policies/policyyamleditor.tsx","./src/pages/policies/rulecard.tsx","./src/pages/prompts/prompteditor.tsx","./src/pages/prompts/promptspanel.tsx"],"version":"5.9.3"}
{"root":["./src/app.tsx","./src/main.tsx","./src/components/actionspanel.tsx","./src/components/column.tsx","./src/components/detailpanel.tsx","./src/components/envelopecard.tsx","./src/components/envelopedetail.tsx","./src/components/kanbanboard.tsx","./src/components/label.tsx","./src/components/settingspopover.tsx","./src/components/sidebar.tsx","./src/components/statusbar.tsx","./src/components/ui/badge.tsx","./src/components/ui/button.tsx","./src/components/ui/dialog.tsx","./src/components/ui/popover.tsx","./src/components/ui/scroll-area.tsx","./src/components/ui/separator.tsx","./src/components/ui/tooltip.tsx","./src/lib/api.ts","./src/lib/config.ts","./src/lib/policies.ts","./src/lib/prompts.ts","./src/lib/settings.ts","./src/lib/types.ts","./src/lib/utils.ts","./src/pages/settingspage.tsx","./src/pages/config/configeditor.tsx","./src/pages/config/configformeditor.tsx","./src/pages/config/configpanel.tsx","./src/pages/config/configyamleditor.tsx","./src/pages/policies/policiespanel.tsx","./src/pages/policies/policyeditor.tsx","./src/pages/policies/policyformeditor.tsx","./src/pages/policies/policyyamleditor.tsx","./src/pages/policies/rulecard.tsx","./src/pages/prompts/prompteditor.tsx","./src/pages/prompts/promptspanel.tsx"],"version":"5.9.3"}
Comment thread tests/test_webui.py
Comment on lines +146 to +147
body = client.get("/api/sources").json()
assert len(body) == 2
@JaredforReal JaredforReal deleted the refine branch May 2, 2026 23:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants