refactor: fix crisp app expiration time and checks#1126
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. 2 Skipped Deployments
|
WalkthroughRemoved per-call messageHash from proof flows and SDK/types; replaced the WebAssembly worker with an SDK worker; switched poll end detection to on-chain block-timestamp checks; removed several unused UI components and utilities; introduced dynamic chain selection and related wagmi/Web3Provider/App changes. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20–30 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
28-68: Race condition: ConcurrentgenerateProofcalls will conflict.Setting
workerRef.current!.onmessageinsidegenerateProofcreates a critical race condition. IfgenerateProofis called multiple times before the first completes, each new call overwrites the previousonmessagehandler, causing earlier promises to hang indefinitely and their loading states to never clear.Additionally, if the component unmounts during proof generation, the promise never resolves or rejects, causing a memory leak.
🔎 Suggested fix using message IDs to handle concurrent calls:
export const useSDKWorkerHook = () => { const { showToast } = useNotificationAlertContext() const [isLoading, setIsLoading] = useState<boolean>(false) const workerRef = useRef<Worker | null>(null) + const pendingRequests = useRef<Map<string, { resolve: (value: string | undefined) => void; reject: (error: Error) => void }>>(new Map()) useEffect(() => { const newWorker = new Worker(new URL('libs/crispSDKWorker.js', import.meta.url), { type: 'module', }) workerRef.current = newWorker + + newWorker.onmessage = (event) => { + const { type, success, encodedProof, error, requestId } = event.data + + if (type === 'generate_proof') { + const pending = pendingRequests.current.get(requestId) + if (pending) { + pendingRequests.current.delete(requestId) + setIsLoading(pendingRequests.current.size > 0) + + if (success) { + pending.resolve(encodedProof) + } else { + showToast({ + type: 'danger', + message: error, + }) + handleGenericError('generateProof', new Error(error)) + pending.reject(new Error(error)) + } + } + } + } return () => { + pendingRequests.current.clear() newWorker.terminate() } }, []) const generateProof = async ( voteId: bigint, publicKey: Uint8Array, address: string, signature: string, previousCiphertext?: Uint8Array, ): Promise<string | undefined> => { if (!workerRef.current) { console.error('Worker not initialized') return } return new Promise<string | undefined>((resolve, reject) => { + const requestId = crypto.randomUUID() + pendingRequests.current.set(requestId, { resolve, reject }) setIsLoading(true) workerRef.current!.postMessage({ type: 'generate_proof', - data: { voteId, publicKey, address, signature, previousCiphertext }, + data: { voteId, publicKey, address, signature, previousCiphertext, requestId }, }) - - workerRef.current!.onmessage = async (event) => { - const { type, success, encodedProof, error } = event.data - - if (type === 'generate_proof') { - if (success) { - resolve(encodedProof) - } else { - showToast({ - type: 'danger', - message: error, - }) - - handleGenericError('generateProof', new Error(error)) - - reject(new Error(error)) - } - - setIsLoading(false) - } - } }) } return { isLoading, generateProof, } }Note: This also requires updating
libs/crispSDKWorker.jsto echo back therequestIdin responses.
🧹 Nitpick comments (5)
examples/CRISP/server/.env.example (1)
23-26: Verify the timing configuration relationship and document units.The reduced values align with the PR's goal to fix expiration times. However:
Relationship verification needed: E3_WINDOW_SIZE (30) defines the activation window, while E3_DURATION (40) defines the input submission interval. Please confirm that having the duration exceed the window size is the intended behavior.
Missing unit specification: The comments don't specify units for these values. Based on the test file using milliseconds (30000ms), these appear to be in seconds, but this should be explicitly documented in the comments to prevent confusion.
🔎 Suggested documentation improvement
# E3 Config -# Defines the time window during which an e3 can be activated +# Defines the time window (in seconds) during which an e3 can be activated E3_WINDOW_SIZE=30 -# Defines the time interval during which users can submit their inputs +# Defines the time interval (in seconds) during which users can submit their inputs # After this interval, the computation phase starts automatically E3_DURATION=40Note: The static analysis tool suggests reordering these keys, but this is a minor stylistic preference and can be safely ignored.
examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx (1)
35-46: Add error handling for blockchain queries.The async block fetch has no error handling. If
client.getBlock()fails (e.g., network issues), the error will be uncaught and could cause issues.🔎 Apply this diff to add error handling:
useEffect(() => { ;(async () => { if (!client) return if (!roundState) return - const block = await client.getBlock() - - if (block.timestamp > roundState.expiration) { - setIsEnded(true) - } + try { + const block = await client.getBlock() + + if (block.timestamp > roundState.expiration) { + setIsEnded(true) + } else { + setIsEnded(false) + } + } catch (error) { + console.error('Failed to fetch block for poll status:', error) + } })() }, [roundState, client])examples/CRISP/client/src/providers/Web3Provider.tsx (2)
22-26: Consider transport configuration alignment.The
chainsarray contains only[getChain()](either hardhat or sepolia), buttransportsdefines mappings for bothanvil.idandsepolia.id. While this doesn't cause runtime errors, it means one transport is unused.🔎 Consider simplifying to match the single-chain approach:
+ const chain = getChain() chains: [getChain()], transports: { - [anvil.id]: http(anvil.rpcUrls.default.http[0]), - [sepolia.id]: http(sepolia.rpcUrls.default.http[0]), + [chain.id]: http(chain.rpcUrls.default.http[0]), },Alternatively, if multi-chain support is planned, include both chains:
- chains: [getChain()], + chains: [anvil, sepolia],
33-35: Improve chain switcher documentation.The comment is helpful but could be more actionable. Consider adding a reference to where the switcher should be implemented or a code example.
🔎 Suggested improvement:
-// NOTE: ConnectKit doesn't ship a drop-in chain switcher UI. This just sets the initial chain. -// For a user-facing switcher, implement a small component that calls wagmi's `useSwitchChain`. +// NOTE: ConnectKit doesn't provide a built-in chain switcher UI. This sets the initial chain only. +// For a user-facing switcher, see App.tsx for an example using wagmi's `useSwitchChain` hook. const options = { initialChainId: getChain().id }Based on learnings, the user prefers manual network switching over automatic detection.
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
43-43: Consider removing non-null assertions for cleaner code.The non-null assertion operator
!is used onworkerRef.currentafter the guard check at line 35. While technically safe, this pattern could be improved by extracting the worker reference to a local variable.🔎 Optional refactor to eliminate non-null assertions:
const generateProof = async ( voteId: bigint, publicKey: Uint8Array, address: string, signature: string, previousCiphertext?: Uint8Array, ): Promise<string | undefined> => { - if (!workerRef.current) { + const worker = workerRef.current + if (!worker) { console.error('Worker not initialized') return } return new Promise<string | undefined>((resolve, reject) => { setIsLoading(true) - workerRef.current!.postMessage({ + worker.postMessage({ type: 'generate_proof', data: { voteId, publicKey, address, signature, previousCiphertext }, }) - workerRef.current!.onmessage = async (event) => { + worker.onmessage = async (event) => { const { type, success, encodedProof, error } = event.data if (type === 'generate_proof') { if (success) { resolve(encodedProof) } else { showToast({ type: 'danger', message: error, }) handleGenericError('generateProof', new Error(error)) reject(new Error(error)) } setIsLoading(false) } } }) }Also applies to: 48-48
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (12)
examples/CRISP/client/src/assets/icons/arrowRight.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/calendarCheck.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/caretCircle.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/check.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/close.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/enclaveLogo.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/fingerprint.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/fingerprintWhite.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/logout.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/notebook.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/paper.svgis excluded by!**/*.svgexamples/CRISP/client/src/assets/icons/paperPurple.svgis excluded by!**/*.svg
📒 Files selected for processing (25)
examples/CRISP/client/libs/crispSDKWorker.js(1 hunks)examples/CRISP/client/src/App.tsx(2 hunks)examples/CRISP/client/src/components/Cards/PollCard.tsx(2 hunks)examples/CRISP/client/src/components/CodeTextDisplay.tsx(0 hunks)examples/CRISP/client/src/components/Modal.tsx(0 hunks)examples/CRISP/client/src/context/voteManagement/VoteManagement.context.tsx(3 hunks)examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts(0 hunks)examples/CRISP/client/src/globals.css(0 hunks)examples/CRISP/client/src/hooks/generic/useLocalStorage.tsx(0 hunks)examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx(3 hunks)examples/CRISP/client/src/hooks/voting/useVoteCasting.ts(4 hunks)examples/CRISP/client/src/model/vote.model.ts(0 hunks)examples/CRISP/client/src/pages/About/About.tsx(0 hunks)examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx(3 hunks)examples/CRISP/client/src/providers/Web3Provider.tsx(1 hunks)examples/CRISP/client/src/utils/handle-generic-error.ts(0 hunks)examples/CRISP/client/src/utils/methods.ts(2 hunks)examples/CRISP/client/src/utils/network.ts(0 hunks)examples/CRISP/client/src/utils/proof-encoding.ts(0 hunks)examples/CRISP/client/src/utils/whitepaper.ts(0 hunks)examples/CRISP/packages/crisp-sdk/src/types.ts(1 hunks)examples/CRISP/packages/crisp-sdk/src/utils.ts(1 hunks)examples/CRISP/packages/crisp-sdk/tests/vote.test.ts(0 hunks)examples/CRISP/server/.env.example(1 hunks)examples/CRISP/test/crisp.spec.ts(2 hunks)
💤 Files with no reviewable changes (12)
- examples/CRISP/client/src/utils/proof-encoding.ts
- examples/CRISP/client/src/context/voteManagement/VoteManagement.types.ts
- examples/CRISP/client/src/model/vote.model.ts
- examples/CRISP/client/src/components/Modal.tsx
- examples/CRISP/client/src/components/CodeTextDisplay.tsx
- examples/CRISP/client/src/utils/whitepaper.ts
- examples/CRISP/packages/crisp-sdk/tests/vote.test.ts
- examples/CRISP/client/src/hooks/generic/useLocalStorage.tsx
- examples/CRISP/client/src/globals.css
- examples/CRISP/client/src/utils/handle-generic-error.ts
- examples/CRISP/client/src/utils/network.ts
- examples/CRISP/client/src/pages/About/About.tsx
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-10T17:29:41.338Z
Learnt from: cedoor
Repo: gnosisguild/enclave PR: 832
File: templates/default/client/src/pages/components/Navbar.tsx:12-26
Timestamp: 2025-10-10T17:29:41.338Z
Learning: In the Enclave project, the user prefers using ConnectKit's `initialChainId` configuration combined with a manual NetworkSwitchButton for network switching, rather than implementing automatic network detection and switching on wallet connection.
Applied to files:
examples/CRISP/client/src/providers/Web3Provider.tsx
🧬 Code graph analysis (6)
examples/CRISP/packages/crisp-sdk/src/utils.ts (2)
examples/CRISP/packages/crisp-sdk/src/index.ts (2)
getAddressFromSignature(10-10)SIGNATURE_MESSAGE_HASH(9-9)examples/CRISP/packages/crisp-sdk/src/constants.ts (1)
SIGNATURE_MESSAGE_HASH(32-32)
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (4)
examples/CRISP/client/src/context/NotificationAlert/NotificationAlert.context.tsx (1)
useNotificationAlertContext(88-88)examples/CRISP/client/libs/crispSDKWorker.js (1)
event(10-10)examples/CRISP/client/src/utils/handle-generic-error.ts (1)
handleGenericError(7-9)crates/events/src/eventbus.rs (1)
error(73-77)
examples/CRISP/client/src/components/Cards/PollCard.tsx (2)
examples/CRISP/client/src/model/poll.model.ts (2)
PollResult(14-20)PollOption(7-12)examples/CRISP/client/src/context/voteManagement/VoteManagement.context.tsx (1)
useVoteManagementContext(242-242)
examples/CRISP/client/src/context/voteManagement/VoteManagement.context.tsx (1)
examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (1)
useSDKWorkerHook(11-75)
examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (4)
examples/CRISP/client/src/model/poll.model.ts (1)
Poll(32-36)examples/CRISP/packages/crisp-sdk/src/vote.ts (1)
generateProof(167-176)packages/enclave-sdk/src/index.ts (1)
generateProof(69-69)examples/CRISP/packages/crisp-sdk/src/constants.ts (1)
SIGNATURE_MESSAGE(31-31)
examples/CRISP/client/src/providers/Web3Provider.tsx (1)
examples/CRISP/client/src/utils/methods.ts (1)
getChain(26-28)
🪛 dotenv-linter (4.0.0)
examples/CRISP/server/.env.example
[warning] 26-26: [UnorderedKey] The E3_DURATION key should go before the E3_WINDOW_SIZE key
(UnorderedKey)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Build & Push Image
- GitHub Check: build_sdk
- GitHub Check: integration_prebuild
- GitHub Check: build_crisp_sdk
- GitHub Check: rust_integration
- GitHub Check: build_enclave_cli
- GitHub Check: build_ciphernode_image
- GitHub Check: rust_unit
- GitHub Check: test_net
🔇 Additional comments (22)
examples/CRISP/test/crisp.spec.ts (2)
47-47: Consider adding buffer time to the activation timeout.The reduced timeout from 60s to 30s aligns with the E3_WINDOW_SIZE configuration change. However, with a 30-second activation window and exactly 30 seconds of wait time, there's no buffer for processing overhead, network latency, or CI environment slowness. This could lead to flaky test failures.
Consider adding a small buffer (e.g., 35000ms or 40000ms) to account for realistic execution delays while still keeping tests reasonably fast.
113-113: Test wait time reduction looks reasonable.The reduction from 150s to 60s is appropriate given the E3_DURATION configuration change from 60 to 40 seconds. The 60-second wait provides a 20-second buffer beyond the 40-second duration, which should be sufficient for computation and result processing.
However, monitor for any flakiness in CI environments where execution may be slower than local development.
examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx (4)
7-7: LGTM!The new imports are correctly added to support the blockchain-based poll end detection.
Also applies to: 18-18
28-29: LGTM with a note on state management.The hook and state initialization look correct. Note that
isEndedpersists acrossroundStatechanges, which appears intentional since the useEffect will recalculate it whenroundStateupdates.
95-95: LGTM!The conditional rendering logic based on
isEndedstate is correctly implemented throughout the component for displaying poll status, countdown timer, and voting buttons.Also applies to: 113-113, 131-131, 138-138
42-42: No changes needed. The comparison is correct.Both
block.timestamp(from Ethereum) androundState.expirationare in seconds. TheconvertVoteStateLiteutility function confirms this by multiplyingexpirationby 1000 when converting to a JavaScript Date, which is the standard conversion from seconds to milliseconds.Likely an incorrect or invalid review comment.
examples/CRISP/client/src/components/Cards/PollCard.tsx (3)
12-14: LGTM: Clean transition to blockchain-based timestamp checking.The import changes appropriately reflect the shift from a synchronous utility function to wagmi's public client for blockchain timestamp verification.
41-41: LGTM: Dependency array properly manages interval cleanup.Including
isActivein the dependency array ensures the interval is cleaned up when the poll ends. WhenisActivebecomesfalse, the effect re-runs, the cleanup function clears the old interval, and the guard at line 27 prevents a new interval from being set.
27-35: Verify type compatibility betweenblock.timestampandendTime.The comparison at line 32 mixes types:
block.timestampisbigint(from viem'sgetBlock()), whileendTimeisnumber(from the PollResult interface). Consider converting to a consistent type:if (Number(block.timestamp) >= endTime) { setIsActive(false) }Or alternatively:
if (block.timestamp >= BigInt(endTime)) { setIsActive(false) }examples/CRISP/client/src/hooks/voting/useVoteCasting.ts (3)
16-16: LGTM: Centralized signature message.The import of
SIGNATURE_MESSAGEfrom the SDK centralizes the signing message, improving consistency across the codebase.
113-113: Fixed signature message replaces dynamic approach.Using the constant
SIGNATURE_MESSAGEreplaces the previous per-round dynamic message hash. This change simplifies the signing flow and ensures consistency.
70-73: Simplified proof generation signature with smart message defaults.The
messageHashparameter is made optional and defaults toSIGNATURE_MESSAGE_HASH, simplifying the public API. The function now relies on the SDK's fixedSIGNATURE_MESSAGEconstant for address recovery, eliminating the need for callers to manage the signature message separately.Verification confirmed:
- Backend signature verification correctly uses fixed
SIGNATURE_MESSAGE_HASHfor address recovery (verified in contract tests)- Client code correctly relies on the SDK's default by signing with
SIGNATURE_MESSAGEand omittingmessageHash- Type definition shows
messageHash?: 0x${string}with fallback toSIGNATURE_MESSAGE_HASHingetAddressFromSignatureexamples/CRISP/client/libs/crispSDKWorker.js (1)
14-35: LGTM: Worker aligned with messageHash removal.The worker correctly omits
messageHashfrom the data payload and thegenerateVoteProofcall, consistent with the SDK refactor that makes messageHash optional and defaults toSIGNATURE_MESSAGE_HASH.examples/CRISP/packages/crisp-sdk/src/types.ts (1)
198-198: LGTM: Type reflects optional messageHash.Making
messageHashoptional inVoteProofInputsaligns with the runtime behavior where the SDK now defaults toSIGNATURE_MESSAGE_HASHwhen not provided. This change is backward-compatible.examples/CRISP/client/src/utils/methods.ts (2)
26-28: LGTM: Clean chain selection helper.The
getChain()function provides a clear DEV vs. production chain selection. The implementation is straightforward and leverages Viem's chain definitions.
9-10: Poll-end utilities successfully removed.Verification confirms
hasPollEndedandhasPollEndedByTimestampare not referenced anywhere in the codebase. The removal is complete with no remaining dependencies.examples/CRISP/client/src/context/voteManagement/VoteManagement.context.tsx (2)
9-9: LGTM: SDK worker replaces WebAssembly hook.The refactor from
useWebAssemblyHooktouseSDKWorkerHookmodernizes the proof generation flow while maintaining the same API surface (generateProof, loading state).
62-62: Consistent loading state renaming.The rename from
wasmLoadingtoworkerLoadingaccurately reflects the underlying implementation change and is applied consistently across all references.Also applies to: 170-174
examples/CRISP/packages/crisp-sdk/src/utils.ts (1)
120-124: LGTM: Optional messageHash with sensible fallback.Making
messageHashoptional and defaulting toSIGNATURE_MESSAGE_HASHsupports both the new fixed-message flow and any legacy code that might still pass explicit message hashes. This is a backward-compatible change.examples/CRISP/client/src/hooks/voting/useSDKWorker.tsx (3)
7-7: LGTM! Appropriate use ofuseReffor Worker instance.Using
useRefinstead ofuseStatefor the Worker instance is the correct approach, as Worker mutations shouldn't trigger component re-renders.Also applies to: 14-14
11-11: LGTM! Hook renamed to reflect SDK worker integration.The rename from
useWebAssemblyHooktouseSDKWorkerHookaccurately reflects the refactoring to SDK-based worker integration.
17-26: LGTM! Worker initialization and cleanup properly implemented.The worker script path has been updated to
crispSDKWorker.js, and the cleanup logic properly terminates the worker on component unmount.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
examples/CRISP/server/.env.example(1 hunks)examples/CRISP/test/crisp.spec.ts(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- examples/CRISP/server/.env.example
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
- GitHub Check: build_sdk
- GitHub Check: build_e3_support_dev
- GitHub Check: integration_prebuild
- GitHub Check: build_enclave_cli
- GitHub Check: build_crisp_sdk
- GitHub Check: rust_unit
- GitHub Check: rust_integration
- GitHub Check: test_net
- GitHub Check: build_ciphernode_image
- GitHub Check: Build & Push Image
🔇 Additional comments (1)
examples/CRISP/test/crisp.spec.ts (1)
47-47: Verify the reduced timeout is sufficient across environments.The
maxWaitMshas been halved from 60s to 30s. While this aligns with the server-sideE3_WINDOW_SIZEreduction (40→30), ensure this timeout is adequate for all test environments (local, CI, different hardware configurations) to avoid introducing flakiness.Consider running the test suite multiple times across different environments to confirm the 30s timeout remains reliable. If timing varies significantly, you may want to add a small buffer to the timeout.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
examples/CRISP/client/src/App.tsx (1)
31-48: Fix the incomplete dependency array (still unresolved from previous review).The previous review identified that this
useEffectusesinitialLoadandswitchChainbut has an empty dependency array. This issue remains unresolved. The effect now also usesshowToastandhandleGenericError, which should be included in the dependencies or properly memoized.🔎 Apply this diff to fix the dependency array:
})() - }, []) + }, [initialLoad, switchChain, showToast])Note: Ensure
initialLoad,switchChain, andshowToastare stable (memoized withuseCallbackin their respective contexts) to prevent infinite re-renders.
🧹 Nitpick comments (1)
examples/CRISP/client/src/App.tsx (1)
38-46: Consider more granular error handling for different failure scenarios.The current error handling treats all failures equally with a persistent error toast. However,
switchChaincan fail for benign reasons (e.g., user rejection), which shouldn't display a persistent "Failed to initialize" message. Consider distinguishing between critical failures (initialLoad) and optional failures (switchChain).🔎 Suggested approach for more nuanced error handling:
try { await initialLoad() - + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error) + handleGenericError('App initial load', error instanceof Error ? error : new Error(errorMessage)) + showToast({ + type: 'danger', + message: 'Failed to initialize application. Please refresh the page.', + persistent: true, + }) + return + } + + try { const chain = getChain() switchChain({ chainId: chain.id }) } catch (error) { - const errorMessage = error instanceof Error ? error.message : String(error) - handleGenericError('App initial load', error instanceof Error ? error : new Error(errorMessage)) + // Chain switch failure is less critical (e.g., user rejection) + console.warn('Chain switch failed:', error) showToast({ - type: 'danger', - message: 'Failed to initialize application. Please refresh the page.', - persistent: true, + type: 'warning', + message: 'Failed to switch network. You may need to switch manually.', + persistent: false, }) }This separates critical initialization failures from optional chain-switching failures.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
examples/CRISP/client/src/App.tsx(2 hunks)examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx(3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx (1)
examples/CRISP/client/src/model/poll.model.ts (1)
Poll(32-36)
🔇 Additional comments (1)
examples/CRISP/client/src/pages/Landing/components/DailyPoll.tsx (1)
92-99: Great fix for the Tailwind dynamic class generation issue!The previous review correctly flagged that template literal interpolation (e.g.,
`border-${color}-600`) doesn't work with Tailwind's JIT compiler. You've properly addressed this by using complete conditional class names with a ternary operator, ensuring all required classes are generated in the final CSS bundle.
• removed dead code
• fixed the calculations related to E3 execution completion and app component updates
• reduced the waiting time of e2e tests by several minutes
• minor changes
Fixes #1125
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
Chores
✏️ Tip: You can customize this high-level summary in your review settings.