Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
0372fd7
"Claude PR Assistant workflow"
ChingEnLin May 11, 2026
8f3648c
"Claude Code Review workflow"
ChingEnLin May 11, 2026
bb2a75f
Merge pull request #29 from ChingEnLin/add-claude-github-actions-1778…
ChingEnLin May 11, 2026
b945405
refactor: update Claude Code Review workflow to trigger on issue comm…
ChingEnLin May 11, 2026
169074a
feat: add HubPage and refactor navigation structure
ChingEnLin May 12, 2026
8bc2338
feat: add support for preselected account navigation in QueryGenerato…
ChingEnLin May 12, 2026
bccd212
feat: enhance ShareQueryDialog and ShortcutCheatsheet components with…
ChingEnLin May 13, 2026
4aeed9e
feat: enhance Data Explorer and Query Generator with session manageme…
ChingEnLin May 13, 2026
6a7d31f
feat: refactor query execution logic and enhance saved query handling
ChingEnLin May 13, 2026
e72e0eb
feat: add DESIGN_HANDBOOK.md to .gitignore
ChingEnLin May 14, 2026
fb15a31
feat: implement AnalyticsPageWrapper for session management and routing
ChingEnLin May 14, 2026
53795d4
feat: enhance UI components and add command palette functionality
ChingEnLin May 14, 2026
7684762
feat: rework LoginPage UI with enhanced design and functionality
ChingEnLin May 14, 2026
0ccefaa
feat: remove 'Audit Log' from AppSidebar and HubPage navigation
ChingEnLin May 14, 2026
0510ba8
feat: pass initialCollection state when navigating from CommandPalette
ChingEnLin May 14, 2026
706bb77
feat: update database engine badges to reflect availability status
ChingEnLin May 14, 2026
fc3d144
feat: enhance QueryDisplay and DataExplorer components with filter st…
ChingEnLin May 14, 2026
092b491
feat: refactor AppSidebar and DataExplorerPageWrapper for improved st…
ChingEnLin May 14, 2026
8305dfb
fix: apply black formatting to react_agent_service.py
ChingEnLin May 14, 2026
a9a4e0f
Merge pull request #30 from ChingEnLin/feat/ui_rework
ChingEnLin May 14, 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
38 changes: 38 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Claude Code Review

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]

jobs:
claude-review:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude review')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude review'))

runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code Review
id: claude-review
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
plugin_marketplaces: 'https://github.com/anthropics/claude-code.git'
plugins: 'code-review@claude-code-plugins'
prompt: '/code-review:code-review ${{ github.repository }}/pull/${{ github.event.pull_request.number }}'
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options

50 changes: 50 additions & 0 deletions .github/workflows/claude.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: read
issues: read
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@v1
with:
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}

# This is an optional setting that allows Claude to read CI results on PRs
additional_permissions: |
actions: read

# Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
# prompt: 'Update the pull request description to include a summary of changes.'

# Optional: Add claude_args to customize behavior and configuration
# See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md
# or https://code.claude.com/docs/en/cli-reference for available options
# claude_args: '--allowed-tools Bash(gh pr *)'

6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,9 @@ deployment_note.txt

# Temporary files
development_plans.txt

# claude files
CLAUDE.md
.claude/settings.local.json
HANDOFF.md
DESIGN_HANDBOOK.md
24 changes: 19 additions & 5 deletions backend/routes/audit.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from fastapi import APIRouter, Header, Body, HTTPException
from pydantic import BaseModel
from typing import List, Dict, Any, Optional
from services.audit_service import process_audit_question
from services.audit_service import process_audit_question, get_recent_activity
from services.gemini_service import VisualizationConfig
from services.user_queries_service import get_user_id_from_token

router = APIRouter()

Expand All @@ -18,16 +19,29 @@ class AuditQueryResponse(BaseModel):
visualization: Optional[VisualizationConfig] = None


class RecentActivityItem(BaseModel):
database_name: str
collection_name: str
operation: str
document_id: str
user_email: str
timestamp_utc: str


@router.post("/query", response_model=AuditQueryResponse)
def query_audit_log(
body: AuditQueryRequest = Body(...), authorization: str = Header(...)
):
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid token format")

# We might want to validate the token here even if we don't use it for the pg connection directly yet
# user_token = authorization.replace("Bearer ", "")
# access_token = exchange_token_obo(user_token)

response = process_audit_question(body.question)
return AuditQueryResponse(**response)


@router.get("/recent", response_model=List[RecentActivityItem])
def recent_activity(authorization: str = Header(...), limit: int = 10):
if not authorization.startswith("Bearer "):
raise HTTPException(status_code=401, detail="Invalid token format")
user_email = get_user_id_from_token(authorization.replace("Bearer ", ""))
return get_recent_activity(user_email=user_email, limit=min(limit, 50))
32 changes: 31 additions & 1 deletion backend/services/audit_service.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Dict, Any
from typing import Dict, Any, List
from services.pg_connection import get_connection
from services.gemini_service import generate_audit_sql, summarize_audit_results

Expand Down Expand Up @@ -36,6 +36,36 @@ def execute_audit_query(sql_query: str) -> list:
return [{"error": str(e)}]


def get_recent_activity(user_email: str, limit: int = 10) -> List[Dict[str, Any]]:
"""Returns the most recent write_audit_log rows for a specific user."""
try:
conn = get_connection()
cur = conn.cursor()
cur.execute(
"""
SELECT user_email, operation, database_name, collection_name, document_id, timestamp_utc
FROM write_audit_log
WHERE user_email = %s
ORDER BY timestamp_utc DESC
LIMIT %s
""",
(user_email, limit),
)
columns = [desc[0] for desc in cur.description]
rows = []
for row in cur.fetchall():
item = dict(zip(columns, row))
if hasattr(item.get("timestamp_utc"), "isoformat"):
item["timestamp_utc"] = item["timestamp_utc"].isoformat()
rows.append(item)
cur.close()
conn.close()
return rows
except Exception as e:
print(f"Error fetching recent activity: {e}")
return []


def process_audit_question(question: str) -> Dict[str, Any]:
"""
Orchestrates the process of answering a user's audit question:
Expand Down
1 change: 0 additions & 1 deletion backend/services/react_agent_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
from services.gemini_service import extract_python_code
from services.mongo_service import execute_mongo_query, transform_mongo_result


WRITE_METHODS = {
"insert_one",
"insert_many",
Expand Down
Loading
Loading