generated from cording12/next-fast-turbo
-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(desktop): quick-ask panel with prompt picker and paste-back #1031
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
0f846cd
track frontmost app on shortcut trigger
CREDO23 0abbfbf
save clipboard contents on shortcut trigger
CREDO23 6597649
add REPLACE_TEXT IPC channel
CREDO23 f931b4c
expose replaceText in preload
CREDO23 6e74f46
add replaceText type to ElectronAPI
CREDO23 5bb4f5c
implement replace handler with clipboard swap and paste-back
CREDO23 2adffcc
add paste-back button to assistant action bar
CREDO23 bc16c03
check accessibility permission before paste-back
CREDO23 2f08d40
destroy panel on dismiss, remove activate to preserve selection
CREDO23 1133a36
extract keyboard module with macOS and Windows support
CREDO23 f931f08
rename keyboard to platform module, add getSelectedText
CREDO23 2a8f393
add quick-ask action type definition
CREDO23 d48f6aa
add quick-ask page with default action menu
CREDO23 98e12dd
load /quick-ask page in panel
CREDO23 06f02fb
navigate directly to chat with search space id
CREDO23 6c59b3e
auto-submit quick-ask prompt from URL param
CREDO23 cc9cb39
show paste-back button only for transform actions
CREDO23 59e0579
simplify action menu to plain buttons, remove old quickAskText from t…
CREDO23 8d60fc7
remove searchSpacesAtom from quick-ask, forward params via dashboard
CREDO23 af2129e
move quick-ask page into dashboard route for auth context
CREDO23 f9a6e64
fix: don't clear pendingText on read to survive auth remount
CREDO23 151d6a8
use sessionStorage for quickAskMode to survive route changes
CREDO23 f36e5f8
redesign action menu: grid layout, search, Ask SurfSense, fix action …
CREDO23 9f13da3
fix Ask SurfSense: pre-fill with initialText and cursor positioning
CREDO23 58ac17f
fix: move quickAskMode to IPC to prevent sessionStorage leak between …
CREDO23 cb6f456
add / action trigger to InlineMentionEditor
CREDO23 3be0988
add ActionPicker component for / command trigger
CREDO23 c2644aa
wire / action picker in Composer with keyboard navigation
CREDO23 407059c
add action chip in composer with prompt prepend at send time
CREDO23 041401a
add custom quick-ask actions: model, migration, schemas, CRUD routes
CREDO23 1137424
restore custom actions API service and wire to ActionPicker
CREDO23 a6ccb7a
rename quick-ask-actions to prompts across backend and frontend
CREDO23 03ca4f1
add My Prompts settings tab and create prompt button in picker
CREDO23 6df9eea
desktop: clipboard auto-insert with prompt picker, remove old session…
CREDO23 cfddfa5
fix: harden quick-ask panel, prompt handling, and clipboard UX
CREDO23 b8a1d1f
Merge remote-tracking branch 'upstream/dev' into electon-desktop
CREDO23 726fec7
fix: renumber prompts migration to 110 to follow upstream folders mig…
CREDO23 ab3c636
Merge remote-tracking branch 'upstream/dev' into electon-desktop
CREDO23 3363c71
fix: renumber prompts migration to 111 to follow upstream OneDrive mi…
CREDO23 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
50 changes: 50 additions & 0 deletions
50
surfsense_backend/alembic/versions/111_add_prompts_table.py
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @CREDO23 It should be no 111 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| """add prompts table | ||
|
|
||
| Revision ID: 111 | ||
| Revises: 110 | ||
| """ | ||
|
|
||
| from collections.abc import Sequence | ||
|
|
||
| import sqlalchemy as sa | ||
|
|
||
| from alembic import op | ||
|
|
||
| revision: str = "111" | ||
| down_revision: str | None = "110" | ||
| branch_labels: str | Sequence[str] | None = None | ||
| depends_on: str | Sequence[str] | None = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| conn = op.get_bind() | ||
|
|
||
| result = conn.execute( | ||
| sa.text("SELECT 1 FROM pg_type WHERE typname = 'prompt_mode'") | ||
| ) | ||
| if not result.fetchone(): | ||
| op.execute("CREATE TYPE prompt_mode AS ENUM ('transform', 'explore')") | ||
|
|
||
| result = conn.execute( | ||
| sa.text("SELECT 1 FROM information_schema.tables WHERE table_name = 'prompts'") | ||
| ) | ||
| if not result.fetchone(): | ||
| op.execute(""" | ||
| CREATE TABLE prompts ( | ||
| id SERIAL PRIMARY KEY, | ||
| user_id UUID NOT NULL REFERENCES "user"(id) ON DELETE CASCADE, | ||
| search_space_id INTEGER REFERENCES searchspaces(id) ON DELETE CASCADE, | ||
| name VARCHAR(200) NOT NULL, | ||
| prompt TEXT NOT NULL, | ||
| mode prompt_mode NOT NULL, | ||
| icon VARCHAR(50), | ||
| created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now() | ||
| ) | ||
| """) | ||
| op.execute("CREATE INDEX ix_prompts_user_id ON prompts (user_id)") | ||
| op.execute("CREATE INDEX ix_prompts_search_space_id ON prompts (search_space_id)") | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| op.execute("DROP TABLE IF EXISTS prompts") | ||
| op.execute("DROP TYPE IF EXISTS prompt_mode") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| from fastapi import APIRouter, Depends, HTTPException | ||
| from sqlalchemy import select | ||
| from sqlalchemy.ext.asyncio import AsyncSession | ||
|
|
||
| from app.db import Prompt, User, get_async_session | ||
| from app.schemas.prompts import ( | ||
| PromptCreate, | ||
| PromptRead, | ||
| PromptUpdate, | ||
| ) | ||
| from app.users import current_active_user | ||
|
|
||
| router = APIRouter(tags=["Prompts"]) | ||
|
|
||
|
|
||
| @router.get("/prompts", response_model=list[PromptRead]) | ||
| async def list_prompts( | ||
| search_space_id: int | None = None, | ||
| session: AsyncSession = Depends(get_async_session), | ||
| user: User = Depends(current_active_user), | ||
| ): | ||
| query = select(Prompt).where(Prompt.user_id == user.id) | ||
| if search_space_id is not None: | ||
| query = query.where(Prompt.search_space_id == search_space_id) | ||
| query = query.order_by(Prompt.created_at.desc()) | ||
| result = await session.execute(query) | ||
| return result.scalars().all() | ||
|
|
||
|
|
||
| @router.post("/prompts", response_model=PromptRead) | ||
| async def create_prompt( | ||
| body: PromptCreate, | ||
| session: AsyncSession = Depends(get_async_session), | ||
| user: User = Depends(current_active_user), | ||
| ): | ||
| prompt = Prompt( | ||
| user_id=user.id, | ||
| search_space_id=body.search_space_id, | ||
| name=body.name, | ||
| prompt=body.prompt, | ||
| mode=body.mode, | ||
| icon=body.icon, | ||
| ) | ||
| session.add(prompt) | ||
| await session.commit() | ||
| await session.refresh(prompt) | ||
| return prompt | ||
|
|
||
|
|
||
| @router.put("/prompts/{prompt_id}", response_model=PromptRead) | ||
| async def update_prompt( | ||
| prompt_id: int, | ||
| body: PromptUpdate, | ||
| session: AsyncSession = Depends(get_async_session), | ||
| user: User = Depends(current_active_user), | ||
| ): | ||
| result = await session.execute( | ||
| select(Prompt).where( | ||
| Prompt.id == prompt_id, | ||
| Prompt.user_id == user.id, | ||
| ) | ||
| ) | ||
| prompt = result.scalar_one_or_none() | ||
| if not prompt: | ||
| raise HTTPException(status_code=404, detail="Prompt not found") | ||
|
|
||
| for field, value in body.model_dump(exclude_unset=True).items(): | ||
| setattr(prompt, field, value) | ||
|
|
||
| session.add(prompt) | ||
| await session.commit() | ||
| await session.refresh(prompt) | ||
| return prompt | ||
|
|
||
|
|
||
| @router.delete("/prompts/{prompt_id}") | ||
| async def delete_prompt( | ||
| prompt_id: int, | ||
| session: AsyncSession = Depends(get_async_session), | ||
| user: User = Depends(current_active_user), | ||
| ): | ||
| result = await session.execute( | ||
| select(Prompt).where( | ||
| Prompt.id == prompt_id, | ||
| Prompt.user_id == user.id, | ||
| ) | ||
| ) | ||
| prompt = result.scalar_one_or_none() | ||
| if not prompt: | ||
| raise HTTPException(status_code=404, detail="Prompt not found") | ||
|
|
||
| await session.delete(prompt) | ||
| await session.commit() | ||
| return {"success": True} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| from datetime import datetime | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
|
|
||
| class PromptCreate(BaseModel): | ||
| name: str = Field(..., min_length=1, max_length=200) | ||
| prompt: str = Field(..., min_length=1) | ||
| mode: str = Field(..., pattern="^(transform|explore)$") | ||
| icon: str | None = Field(None, max_length=50) | ||
| search_space_id: int | None = None | ||
|
|
||
|
|
||
| class PromptUpdate(BaseModel): | ||
| name: str | None = Field(None, min_length=1, max_length=200) | ||
| prompt: str | None = Field(None, min_length=1) | ||
| mode: str | None = Field(None, pattern="^(transform|explore)$") | ||
| icon: str | None = Field(None, max_length=50) | ||
|
|
||
|
|
||
| class PromptRead(BaseModel): | ||
| id: int | ||
| name: str | ||
| prompt: str | ||
| mode: str | ||
| icon: str | None | ||
| search_space_id: int | None | ||
| created_at: datetime | ||
|
|
||
| class Config: | ||
| from_attributes = True |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { execSync } from 'child_process'; | ||
| import { systemPreferences } from 'electron'; | ||
|
|
||
| export function getFrontmostApp(): string { | ||
| try { | ||
| if (process.platform === 'darwin') { | ||
| return execSync( | ||
| 'osascript -e \'tell application "System Events" to get name of first application process whose frontmost is true\'' | ||
| ).toString().trim(); | ||
| } | ||
| if (process.platform === 'win32') { | ||
| return execSync( | ||
| 'powershell -command "Add-Type \'using System; using System.Runtime.InteropServices; public class W { [DllImport(\\\"user32.dll\\\")] public static extern IntPtr GetForegroundWindow(); }\'; (Get-Process | Where-Object { $_.MainWindowHandle -eq [W]::GetForegroundWindow() }).ProcessName"' | ||
| ).toString().trim(); | ||
| } | ||
| } catch { | ||
| return ''; | ||
| } | ||
| return ''; | ||
| } | ||
|
|
||
| export function getSelectedText(): string { | ||
| try { | ||
| if (process.platform === 'darwin') { | ||
| return execSync( | ||
| 'osascript -e \'tell application "System Events" to get value of attribute "AXSelectedText" of focused UI element of first application process whose frontmost is true\'' | ||
| ).toString().trim(); | ||
| } | ||
| // Windows: no reliable accessibility API for selected text across apps | ||
| } catch { | ||
| return ''; | ||
| } | ||
| return ''; | ||
| } | ||
|
|
||
| export function simulateCopy(): void { | ||
| if (process.platform === 'darwin') { | ||
| execSync('osascript -e \'tell application "System Events" to keystroke "c" using command down\''); | ||
| } else if (process.platform === 'win32') { | ||
| execSync('powershell -command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait(\'^c\')"'); | ||
| } | ||
| } | ||
|
|
||
| export function simulatePaste(): void { | ||
| if (process.platform === 'darwin') { | ||
| execSync('osascript -e \'tell application "System Events" to keystroke "v" using command down\''); | ||
| } else if (process.platform === 'win32') { | ||
| execSync('powershell -command "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait(\'^v\')"'); | ||
| } | ||
| } | ||
|
|
||
| export function checkAccessibilityPermission(): boolean { | ||
| if (process.platform !== 'darwin') return true; | ||
| return systemPreferences.isTrustedAccessibilityClient(true); | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.