-
Notifications
You must be signed in to change notification settings - Fork 0
feat: read-only / watch mode for admin #17
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
base: main
Are you sure you want to change the base?
Conversation
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
…oncerns Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
… support, a watch address input, and modified the components to support a read-only state. The next step would be to modify the child components (`WalletEntriesCard`, `ContractControlCard`, and `CreatorFacetCard`) to accept and handle the `readOnly` prop. Would you like me to help you update those components? Typically, this would involve: 1. Adding `readOnly?: boolean` to the component props 2. Disabling buttons when `readOnly` is true 3. Adding tooltips to explain why buttons are disabled Would you like me to show you how to modify those components? Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
…eatorFacetCard components. Could you please add those files to the chat so I can update them? Specifically, I'd like to see: - `ui/src/components/ContractControlCard.tsx` - `ui/src/components/CreatorFacetCard.tsx` Could you share those files? USER: I added these files to the chat: ui/src/components/ContractControlCard.tsx ui/src/components/CreatorFacetCard.tsx Let me know if there are others we should add. A: ui/src/components/ContractControlCard.tsx ```tsx <<<<<<< SEARCH interface ContractControlCardProps { contractAddress: string; contractName: string; onCreateInstance: (instanceName: string) => void; } ======= interface ContractControlCardProps { contractAddress: string; contractName: string; onCreateInstance: (instanceName: string) => void; readOnly?: boolean; } >>>>>>> REPLACE ``` ui/src/components/ContractControlCard.tsx ```tsx <<<<<<< SEARCH const ContractControlCard: React.FC<ContractControlCardProps> = ({ contractAddress, contractName, onCreateInstance, }) => { ======= const ContractControlCard: React.FC<ContractControlCardProps> = ({ contractAddress, contractName, onCreateInstance, readOnly = false, }) => { >>>>>>> REPLACE ``` ui/src/components/ContractControlCard.tsx ```tsx <<<<<<< SEARCH <input type="text" value={instanceName} onChange={(e) => setInstanceName(e.target.value)} placeholder="Instance name..." style={{ flex: 1, padding: '0.5rem', border: '1px solid #ccc', borderRadius: '4px', fontSize: '1em' }} /> ======= <input type="text" value={instanceName} onChange={(e) => setInstanceName(e.target.value)} placeholder="Instance name..." disabled={readOnly} style={{ flex: 1, padding: '0.5rem', border: '1px solid #ccc', borderRadius: '4px', fontSize: '1em', backgroundColor: readOnly ? '#f0f0f0' : 'white', color: readOnly ? '#666' : 'black' }} /> >>>>>>> REPLACE ``` ui/src/components/ContractControlCard.tsx ```tsx <<<<<<< SEARCH <button onClick={() => onCreateInstance(instanceName)} disabled={!instanceName.trim()} style={{ padding: '0.5rem 1rem', backgroundColor: !instanceName.trim() ? '#ccc' : '#6f42c1', color: 'white', border: 'none', borderRadius: '4px', cursor: !instanceName.trim() ? 'not-allowed' : 'pointer', fontSize: '1em' }} > Create Instance </button> ======= <button onClick={() => onCreateInstance(instanceName)} disabled={!instanceName.trim() || readOnly} title={readOnly ? 'Connect wallet to create instances' : ''} style={{ padding: '0.5rem 1rem', backgroundColor: (!instanceName.trim() || readOnly) ? '#ccc' : '#6f42c1', color: 'white', border: 'none', borderRadius: '4px', cursor: (!instanceName.trim() || readOnly) ? 'not-allowed' : 'pointer', fontSize: '1em' }} > Create Instance </button> >>>>>>> REPLACE ``` ui/src/components/CreatorFacetCard.tsx ```tsx <<<<<<< SEARCH interface CreatorFacetCardProps { contractAddress: string; contractName: string; onCreateFacet: (facetName: string) => void; } ======= interface CreatorFacetCardProps { contractAddress: string; contractName: string; onCreateFacet: (facetName: string) => void; readOnly?: boolean; } >>>>>>> REPLACE ``` ui/src/components/CreatorFacetCard.tsx ```tsx <<<<<<< SEARCH const CreatorFacetCard: React.FC<CreatorFacetCardProps> = ({ contractAddress, contractName, onCreateFacet, }) => { ======= const CreatorFacetCard: React.FC<CreatorFacetCardProps> = ({ contractAddress, contractName, onCreateFacet, readOnly = false, }) => { >>>>>>> REPLACE ``` ui/src/components/CreatorFacetCard.tsx ```tsx <<<<<<< SEARCH <input type="text" value={facetName} onChange={(e) => setFacetName(e.target.value)} placeholder="Facet name..." style={{ flex: 1, padding: '0.5rem', border: '1px solid #ccc', borderRadius: '4px', fontSize: '1em' }} /> ======= <input type="text" value={facetName} onChange={(e) => setFacetName(e.target.value)} placeholder="Facet name..." disabled={readOnly} style={{ flex: 1, padding: '0.5rem', border: '1px solid #ccc', borderRadius: '4px', fontSize: '1em', backgroundColor: readOnly ? '#f0f0f0' : 'white', color: readOnly ? '#666' : 'black' }} /> >>>>>>> REPLACE ``` ui/src/components/CreatorFacetCard.tsx ```tsx <<<<<<< SEARCH <button onClick={() => onCreateFacet(facetName)} disabled={!facetName.trim()} style={{ padding: '0.5rem 1rem', backgroundColor: !facetName.trim() ? '#ccc' : '#6f42c1', color: 'white', border: 'none', borderRadius: '4px', cursor: !facetName.trim() ? 'not-allowed' : 'pointer', fontSize: '1em' }} > Create Facet </button> ======= <button onClick={() => onCreateFacet(facetName)} disabled={!facetName.trim() || readOnly} title={readOnly ? 'Connect wallet to create facets' : ''} style={{ padding: '0.5rem 1rem', backgroundColor: (!facetName.trim() || readOnly) ? '#ccc' : '#6f42c1', color: 'white', border: 'none', borderRadius: '4px', cursor: (!facetName.trim() || readOnly) ? 'not-allowed' : 'pointer', fontSize: '1em' }} > Create Facet </button> >>>>>>> REPLACE ``` Now I'll need to update the `Admin.tsx` to pass the `readOnly` prop to these components. Would you like me to show those changes? Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
…riesCard Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
Co-authored-by: aider (anthropic/claude-sonnet-4-20250514) <[email protected]>
✅ Deploy Preview for ymax0 ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this 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 introduces a read-only/watch mode for the admin interface, allowing users to view wallet state and transaction history without connecting a wallet or using private keys. The implementation includes service layer refactoring, UI updates for watch mode functionality, and environment-specific default addresses.
Key Changes
- Added watch-only mode with address input and default addresses for devnet/mainnet
- Refactored contract operations into a dedicated
ContractService
class - Extracted wallet-related functionality into reusable service functions
Reviewed Changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
File | Description |
---|---|
ui/src/services/walletService.ts | New service containing invitation redemption logic |
ui/src/services/contractService.ts | New service class for contract operations (terminate, upgrade, etc.) |
ui/src/components/WalletEntriesCard.tsx | Added watch mode UI with connection section and read-only states |
ui/src/components/InvitationItem.tsx | Added read-only prop support with disabled styling |
ui/src/components/Admin.tsx | Major refactoring to support watch mode using custom hooks and service classes |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
const fetchTransactions = async () => { | ||
if (!walletAddress) return; | ||
|
||
const url = `${endpoints.API}/cosmos/tx/v1beta1/txs?query=message.sender='${walletAddress}'&order_by=ORDER_BY_DESC&limit=${transactionLimit}`; |
Copilot
AI
Sep 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The query parameter should be events
instead of query
based on the original code and Cosmos SDK API. This change may cause the transaction fetching to fail.
const url = `${endpoints.API}/cosmos/tx/v1beta1/txs?query=message.sender='${walletAddress}'&order_by=ORDER_BY_DESC&limit=${transactionLimit}`; | |
const url = `${endpoints.API}/cosmos/tx/v1beta1/txs?events=message.sender='${walletAddress}'&order_by=ORDER_BY_DESC&limit=${transactionLimit}`; |
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot this was a fix, necessary to restore the TransactionHistory component to working order.
The Agoric chain has been upgrade from Cosmos SDK 0.47 to 0.50; perhaps that made this change necessary. Can you find docs to confirm, please?
); | ||
|
||
}, [wallet, purses, watcherRef.current]); | ||
}, [effectiveAddress, watcherRef.current, handleInvocationCompletion, fetchTransactions]); |
Copilot
AI
Sep 24, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The dependency array includes handleInvocationCompletion
and fetchTransactions
which are functions defined in custom hooks. This will cause the effect to re-run on every render since these functions are recreated each time.
Copilot uses AI. Check for mistakes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot would this explain why the thing is going into an infinite loop, re-fetching the transactions and re-displaying them?
In order to be able to see stuff like when we last did an
installAndStart
on mainnet without using the private key, I asked a bot to add a watch mode:VIBE CODING NOTE: I didn't even look at the code other than watching it scroll by. watch-mode-aider-chat.md is a transcript.
main
/code
prompts:events
toquery
in the [query in the] TransactionHistory componentagoric10utru593dspjwfewcgdak8lvp9tkz0xttvcnxv
and mainnet toagoric1e80twfutmrm3wrk3fysjcnef4j82mq8dn6nmcq
?